##// END OF EJS Templates
status: support revsets with --change
Patrick Mezard -
r15578:db0e277b default
parent child Browse files
Show More
@@ -1,5701 +1,5701 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import match as matchmod
16 import match as matchmod
17 import merge as mergemod
17 import merge as mergemod
18 import minirst, revset, fileset
18 import minirst, revset, fileset
19 import dagparser, context, simplemerge
19 import dagparser, context, simplemerge
20 import random, setdiscovery, treediscovery, dagutil
20 import random, setdiscovery, treediscovery, dagutil
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 ] + templateopts
101 ] + templateopts
102
102
103 diffopts = [
103 diffopts = [
104 ('a', 'text', None, _('treat all files as text')),
104 ('a', 'text', None, _('treat all files as text')),
105 ('g', 'git', None, _('use git extended diff format')),
105 ('g', 'git', None, _('use git extended diff format')),
106 ('', 'nodates', None, _('omit dates from diff headers'))
106 ('', 'nodates', None, _('omit dates from diff headers'))
107 ]
107 ]
108
108
109 diffwsopts = [
109 diffwsopts = [
110 ('w', 'ignore-all-space', None,
110 ('w', 'ignore-all-space', None,
111 _('ignore white space when comparing lines')),
111 _('ignore white space when comparing lines')),
112 ('b', 'ignore-space-change', None,
112 ('b', 'ignore-space-change', None,
113 _('ignore changes in the amount of white space')),
113 _('ignore changes in the amount of white space')),
114 ('B', 'ignore-blank-lines', None,
114 ('B', 'ignore-blank-lines', None,
115 _('ignore changes whose lines are all blank')),
115 _('ignore changes whose lines are all blank')),
116 ]
116 ]
117
117
118 diffopts2 = [
118 diffopts2 = [
119 ('p', 'show-function', None, _('show which function each change is in')),
119 ('p', 'show-function', None, _('show which function each change is in')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
120 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ] + diffwsopts + [
121 ] + diffwsopts + [
122 ('U', 'unified', '',
122 ('U', 'unified', '',
123 _('number of lines of context to show'), _('NUM')),
123 _('number of lines of context to show'), _('NUM')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ]
125 ]
126
126
127 mergetoolopts = [
127 mergetoolopts = [
128 ('t', 'tool', '', _('specify merge tool')),
128 ('t', 'tool', '', _('specify merge tool')),
129 ]
129 ]
130
130
131 similarityopts = [
131 similarityopts = [
132 ('s', 'similarity', '',
132 ('s', 'similarity', '',
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
133 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 ]
134 ]
135
135
136 subrepoopts = [
136 subrepoopts = [
137 ('S', 'subrepos', None,
137 ('S', 'subrepos', None,
138 _('recurse into subrepositories'))
138 _('recurse into subrepositories'))
139 ]
139 ]
140
140
141 # Commands start here, listed alphabetically
141 # Commands start here, listed alphabetically
142
142
143 @command('^add',
143 @command('^add',
144 walkopts + subrepoopts + dryrunopts,
144 walkopts + subrepoopts + dryrunopts,
145 _('[OPTION]... [FILE]...'))
145 _('[OPTION]... [FILE]...'))
146 def add(ui, repo, *pats, **opts):
146 def add(ui, repo, *pats, **opts):
147 """add the specified files on the next commit
147 """add the specified files on the next commit
148
148
149 Schedule files to be version controlled and added to the
149 Schedule files to be version controlled and added to the
150 repository.
150 repository.
151
151
152 The files will be added to the repository at the next commit. To
152 The files will be added to the repository at the next commit. To
153 undo an add before that, see :hg:`forget`.
153 undo an add before that, see :hg:`forget`.
154
154
155 If no names are given, add all files to the repository.
155 If no names are given, add all files to the repository.
156
156
157 .. container:: verbose
157 .. container:: verbose
158
158
159 An example showing how new (unknown) files are added
159 An example showing how new (unknown) files are added
160 automatically by :hg:`add`::
160 automatically by :hg:`add`::
161
161
162 $ ls
162 $ ls
163 foo.c
163 foo.c
164 $ hg status
164 $ hg status
165 ? foo.c
165 ? foo.c
166 $ hg add
166 $ hg add
167 adding foo.c
167 adding foo.c
168 $ hg status
168 $ hg status
169 A foo.c
169 A foo.c
170
170
171 Returns 0 if all files are successfully added.
171 Returns 0 if all files are successfully added.
172 """
172 """
173
173
174 m = scmutil.match(repo[None], pats, opts)
174 m = scmutil.match(repo[None], pats, opts)
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
175 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 opts.get('subrepos'), prefix="")
176 opts.get('subrepos'), prefix="")
177 return rejected and 1 or 0
177 return rejected and 1 or 0
178
178
179 @command('addremove',
179 @command('addremove',
180 similarityopts + walkopts + dryrunopts,
180 similarityopts + walkopts + dryrunopts,
181 _('[OPTION]... [FILE]...'))
181 _('[OPTION]... [FILE]...'))
182 def addremove(ui, repo, *pats, **opts):
182 def addremove(ui, repo, *pats, **opts):
183 """add all new files, delete all missing files
183 """add all new files, delete all missing files
184
184
185 Add all new files and remove all missing files from the
185 Add all new files and remove all missing files from the
186 repository.
186 repository.
187
187
188 New files are ignored if they match any of the patterns in
188 New files are ignored if they match any of the patterns in
189 ``.hgignore``. As with add, these changes take effect at the next
189 ``.hgignore``. As with add, these changes take effect at the next
190 commit.
190 commit.
191
191
192 Use the -s/--similarity option to detect renamed files. With a
192 Use the -s/--similarity option to detect renamed files. With a
193 parameter greater than 0, this compares every removed file with
193 parameter greater than 0, this compares every removed file with
194 every added file and records those similar enough as renames. This
194 every added file and records those similar enough as renames. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. Detecting renamed files this way
196 be identical) as its parameter. Detecting renamed files this way
197 can be expensive. After using this option, :hg:`status -C` can be
197 can be expensive. After using this option, :hg:`status -C` can be
198 used to check which files were identified as moved or renamed.
198 used to check which files were identified as moved or renamed.
199
199
200 Returns 0 if all files are successfully added.
200 Returns 0 if all files are successfully added.
201 """
201 """
202 try:
202 try:
203 sim = float(opts.get('similarity') or 100)
203 sim = float(opts.get('similarity') or 100)
204 except ValueError:
204 except ValueError:
205 raise util.Abort(_('similarity must be a number'))
205 raise util.Abort(_('similarity must be a number'))
206 if sim < 0 or sim > 100:
206 if sim < 0 or sim > 100:
207 raise util.Abort(_('similarity must be between 0 and 100'))
207 raise util.Abort(_('similarity must be between 0 and 100'))
208 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
208 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
209
209
210 @command('^annotate|blame',
210 @command('^annotate|blame',
211 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
211 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
212 ('', 'follow', None,
212 ('', 'follow', None,
213 _('follow copies/renames and list the filename (DEPRECATED)')),
213 _('follow copies/renames and list the filename (DEPRECATED)')),
214 ('', 'no-follow', None, _("don't follow copies and renames")),
214 ('', 'no-follow', None, _("don't follow copies and renames")),
215 ('a', 'text', None, _('treat all files as text')),
215 ('a', 'text', None, _('treat all files as text')),
216 ('u', 'user', None, _('list the author (long with -v)')),
216 ('u', 'user', None, _('list the author (long with -v)')),
217 ('f', 'file', None, _('list the filename')),
217 ('f', 'file', None, _('list the filename')),
218 ('d', 'date', None, _('list the date (short with -q)')),
218 ('d', 'date', None, _('list the date (short with -q)')),
219 ('n', 'number', None, _('list the revision number (default)')),
219 ('n', 'number', None, _('list the revision number (default)')),
220 ('c', 'changeset', None, _('list the changeset')),
220 ('c', 'changeset', None, _('list the changeset')),
221 ('l', 'line-number', None, _('show line number at the first appearance'))
221 ('l', 'line-number', None, _('show line number at the first appearance'))
222 ] + diffwsopts + walkopts,
222 ] + diffwsopts + walkopts,
223 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
223 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
224 def annotate(ui, repo, *pats, **opts):
224 def annotate(ui, repo, *pats, **opts):
225 """show changeset information by line for each file
225 """show changeset information by line for each file
226
226
227 List changes in files, showing the revision id responsible for
227 List changes in files, showing the revision id responsible for
228 each line
228 each line
229
229
230 This command is useful for discovering when a change was made and
230 This command is useful for discovering when a change was made and
231 by whom.
231 by whom.
232
232
233 Without the -a/--text option, annotate will avoid processing files
233 Without the -a/--text option, annotate will avoid processing files
234 it detects as binary. With -a, annotate will annotate the file
234 it detects as binary. With -a, annotate will annotate the file
235 anyway, although the results will probably be neither useful
235 anyway, although the results will probably be neither useful
236 nor desirable.
236 nor desirable.
237
237
238 Returns 0 on success.
238 Returns 0 on success.
239 """
239 """
240 if opts.get('follow'):
240 if opts.get('follow'):
241 # --follow is deprecated and now just an alias for -f/--file
241 # --follow is deprecated and now just an alias for -f/--file
242 # to mimic the behavior of Mercurial before version 1.5
242 # to mimic the behavior of Mercurial before version 1.5
243 opts['file'] = True
243 opts['file'] = True
244
244
245 datefunc = ui.quiet and util.shortdate or util.datestr
245 datefunc = ui.quiet and util.shortdate or util.datestr
246 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
246 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
247
247
248 if not pats:
248 if not pats:
249 raise util.Abort(_('at least one filename or pattern is required'))
249 raise util.Abort(_('at least one filename or pattern is required'))
250
250
251 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
251 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
252 ('number', ' ', lambda x: str(x[0].rev())),
252 ('number', ' ', lambda x: str(x[0].rev())),
253 ('changeset', ' ', lambda x: short(x[0].node())),
253 ('changeset', ' ', lambda x: short(x[0].node())),
254 ('date', ' ', getdate),
254 ('date', ' ', getdate),
255 ('file', ' ', lambda x: x[0].path()),
255 ('file', ' ', lambda x: x[0].path()),
256 ('line_number', ':', lambda x: str(x[1])),
256 ('line_number', ':', lambda x: str(x[1])),
257 ]
257 ]
258
258
259 if (not opts.get('user') and not opts.get('changeset')
259 if (not opts.get('user') and not opts.get('changeset')
260 and not opts.get('date') and not opts.get('file')):
260 and not opts.get('date') and not opts.get('file')):
261 opts['number'] = True
261 opts['number'] = True
262
262
263 linenumber = opts.get('line_number') is not None
263 linenumber = opts.get('line_number') is not None
264 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
264 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
265 raise util.Abort(_('at least one of -n/-c is required for -l'))
265 raise util.Abort(_('at least one of -n/-c is required for -l'))
266
266
267 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
267 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
268 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
268 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
269
269
270 def bad(x, y):
270 def bad(x, y):
271 raise util.Abort("%s: %s" % (x, y))
271 raise util.Abort("%s: %s" % (x, y))
272
272
273 ctx = scmutil.revsingle(repo, opts.get('rev'))
273 ctx = scmutil.revsingle(repo, opts.get('rev'))
274 m = scmutil.match(ctx, pats, opts)
274 m = scmutil.match(ctx, pats, opts)
275 m.bad = bad
275 m.bad = bad
276 follow = not opts.get('no_follow')
276 follow = not opts.get('no_follow')
277 diffopts = patch.diffopts(ui, opts, section='annotate')
277 diffopts = patch.diffopts(ui, opts, section='annotate')
278 for abs in ctx.walk(m):
278 for abs in ctx.walk(m):
279 fctx = ctx[abs]
279 fctx = ctx[abs]
280 if not opts.get('text') and util.binary(fctx.data()):
280 if not opts.get('text') and util.binary(fctx.data()):
281 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
281 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
282 continue
282 continue
283
283
284 lines = fctx.annotate(follow=follow, linenumber=linenumber,
284 lines = fctx.annotate(follow=follow, linenumber=linenumber,
285 diffopts=diffopts)
285 diffopts=diffopts)
286 pieces = []
286 pieces = []
287
287
288 for f, sep in funcmap:
288 for f, sep in funcmap:
289 l = [f(n) for n, dummy in lines]
289 l = [f(n) for n, dummy in lines]
290 if l:
290 if l:
291 sized = [(x, encoding.colwidth(x)) for x in l]
291 sized = [(x, encoding.colwidth(x)) for x in l]
292 ml = max([w for x, w in sized])
292 ml = max([w for x, w in sized])
293 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
293 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
294 for x, w in sized])
294 for x, w in sized])
295
295
296 if pieces:
296 if pieces:
297 for p, l in zip(zip(*pieces), lines):
297 for p, l in zip(zip(*pieces), lines):
298 ui.write("%s: %s" % ("".join(p), l[1]))
298 ui.write("%s: %s" % ("".join(p), l[1]))
299
299
300 @command('archive',
300 @command('archive',
301 [('', 'no-decode', None, _('do not pass files through decoders')),
301 [('', 'no-decode', None, _('do not pass files through decoders')),
302 ('p', 'prefix', '', _('directory prefix for files in archive'),
302 ('p', 'prefix', '', _('directory prefix for files in archive'),
303 _('PREFIX')),
303 _('PREFIX')),
304 ('r', 'rev', '', _('revision to distribute'), _('REV')),
304 ('r', 'rev', '', _('revision to distribute'), _('REV')),
305 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
305 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
306 ] + subrepoopts + walkopts,
306 ] + subrepoopts + walkopts,
307 _('[OPTION]... DEST'))
307 _('[OPTION]... DEST'))
308 def archive(ui, repo, dest, **opts):
308 def archive(ui, repo, dest, **opts):
309 '''create an unversioned archive of a repository revision
309 '''create an unversioned archive of a repository revision
310
310
311 By default, the revision used is the parent of the working
311 By default, the revision used is the parent of the working
312 directory; use -r/--rev to specify a different revision.
312 directory; use -r/--rev to specify a different revision.
313
313
314 The archive type is automatically detected based on file
314 The archive type is automatically detected based on file
315 extension (or override using -t/--type).
315 extension (or override using -t/--type).
316
316
317 .. container:: verbose
317 .. container:: verbose
318
318
319 Examples:
319 Examples:
320
320
321 - create a zip file containing the 1.0 release::
321 - create a zip file containing the 1.0 release::
322
322
323 hg archive -r 1.0 project-1.0.zip
323 hg archive -r 1.0 project-1.0.zip
324
324
325 - create a tarball excluding .hg files::
325 - create a tarball excluding .hg files::
326
326
327 hg archive project.tar.gz -X ".hg*"
327 hg archive project.tar.gz -X ".hg*"
328
328
329 Valid types are:
329 Valid types are:
330
330
331 :``files``: a directory full of files (default)
331 :``files``: a directory full of files (default)
332 :``tar``: tar archive, uncompressed
332 :``tar``: tar archive, uncompressed
333 :``tbz2``: tar archive, compressed using bzip2
333 :``tbz2``: tar archive, compressed using bzip2
334 :``tgz``: tar archive, compressed using gzip
334 :``tgz``: tar archive, compressed using gzip
335 :``uzip``: zip archive, uncompressed
335 :``uzip``: zip archive, uncompressed
336 :``zip``: zip archive, compressed using deflate
336 :``zip``: zip archive, compressed using deflate
337
337
338 The exact name of the destination archive or directory is given
338 The exact name of the destination archive or directory is given
339 using a format string; see :hg:`help export` for details.
339 using a format string; see :hg:`help export` for details.
340
340
341 Each member added to an archive file has a directory prefix
341 Each member added to an archive file has a directory prefix
342 prepended. Use -p/--prefix to specify a format string for the
342 prepended. Use -p/--prefix to specify a format string for the
343 prefix. The default is the basename of the archive, with suffixes
343 prefix. The default is the basename of the archive, with suffixes
344 removed.
344 removed.
345
345
346 Returns 0 on success.
346 Returns 0 on success.
347 '''
347 '''
348
348
349 ctx = scmutil.revsingle(repo, opts.get('rev'))
349 ctx = scmutil.revsingle(repo, opts.get('rev'))
350 if not ctx:
350 if not ctx:
351 raise util.Abort(_('no working directory: please specify a revision'))
351 raise util.Abort(_('no working directory: please specify a revision'))
352 node = ctx.node()
352 node = ctx.node()
353 dest = cmdutil.makefilename(repo, dest, node)
353 dest = cmdutil.makefilename(repo, dest, node)
354 if os.path.realpath(dest) == repo.root:
354 if os.path.realpath(dest) == repo.root:
355 raise util.Abort(_('repository root cannot be destination'))
355 raise util.Abort(_('repository root cannot be destination'))
356
356
357 kind = opts.get('type') or archival.guesskind(dest) or 'files'
357 kind = opts.get('type') or archival.guesskind(dest) or 'files'
358 prefix = opts.get('prefix')
358 prefix = opts.get('prefix')
359
359
360 if dest == '-':
360 if dest == '-':
361 if kind == 'files':
361 if kind == 'files':
362 raise util.Abort(_('cannot archive plain files to stdout'))
362 raise util.Abort(_('cannot archive plain files to stdout'))
363 dest = cmdutil.makefileobj(repo, dest)
363 dest = cmdutil.makefileobj(repo, dest)
364 if not prefix:
364 if not prefix:
365 prefix = os.path.basename(repo.root) + '-%h'
365 prefix = os.path.basename(repo.root) + '-%h'
366
366
367 prefix = cmdutil.makefilename(repo, prefix, node)
367 prefix = cmdutil.makefilename(repo, prefix, node)
368 matchfn = scmutil.match(ctx, [], opts)
368 matchfn = scmutil.match(ctx, [], opts)
369 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
369 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
370 matchfn, prefix, subrepos=opts.get('subrepos'))
370 matchfn, prefix, subrepos=opts.get('subrepos'))
371
371
372 @command('backout',
372 @command('backout',
373 [('', 'merge', None, _('merge with old dirstate parent after backout')),
373 [('', 'merge', None, _('merge with old dirstate parent after backout')),
374 ('', 'parent', '',
374 ('', 'parent', '',
375 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
375 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
376 ('r', 'rev', '', _('revision to backout'), _('REV')),
376 ('r', 'rev', '', _('revision to backout'), _('REV')),
377 ] + mergetoolopts + walkopts + commitopts + commitopts2,
377 ] + mergetoolopts + walkopts + commitopts + commitopts2,
378 _('[OPTION]... [-r] REV'))
378 _('[OPTION]... [-r] REV'))
379 def backout(ui, repo, node=None, rev=None, **opts):
379 def backout(ui, repo, node=None, rev=None, **opts):
380 '''reverse effect of earlier changeset
380 '''reverse effect of earlier changeset
381
381
382 Prepare a new changeset with the effect of REV undone in the
382 Prepare a new changeset with the effect of REV undone in the
383 current working directory.
383 current working directory.
384
384
385 If REV is the parent of the working directory, then this new changeset
385 If REV is the parent of the working directory, then this new changeset
386 is committed automatically. Otherwise, hg needs to merge the
386 is committed automatically. Otherwise, hg needs to merge the
387 changes and the merged result is left uncommitted.
387 changes and the merged result is left uncommitted.
388
388
389 .. note::
389 .. note::
390 backout cannot be used to fix either an unwanted or
390 backout cannot be used to fix either an unwanted or
391 incorrect merge.
391 incorrect merge.
392
392
393 .. container:: verbose
393 .. container:: verbose
394
394
395 By default, the pending changeset will have one parent,
395 By default, the pending changeset will have one parent,
396 maintaining a linear history. With --merge, the pending
396 maintaining a linear history. With --merge, the pending
397 changeset will instead have two parents: the old parent of the
397 changeset will instead have two parents: the old parent of the
398 working directory and a new child of REV that simply undoes REV.
398 working directory and a new child of REV that simply undoes REV.
399
399
400 Before version 1.7, the behavior without --merge was equivalent
400 Before version 1.7, the behavior without --merge was equivalent
401 to specifying --merge followed by :hg:`update --clean .` to
401 to specifying --merge followed by :hg:`update --clean .` to
402 cancel the merge and leave the child of REV as a head to be
402 cancel the merge and leave the child of REV as a head to be
403 merged separately.
403 merged separately.
404
404
405 See :hg:`help dates` for a list of formats valid for -d/--date.
405 See :hg:`help dates` for a list of formats valid for -d/--date.
406
406
407 Returns 0 on success.
407 Returns 0 on success.
408 '''
408 '''
409 if rev and node:
409 if rev and node:
410 raise util.Abort(_("please specify just one revision"))
410 raise util.Abort(_("please specify just one revision"))
411
411
412 if not rev:
412 if not rev:
413 rev = node
413 rev = node
414
414
415 if not rev:
415 if not rev:
416 raise util.Abort(_("please specify a revision to backout"))
416 raise util.Abort(_("please specify a revision to backout"))
417
417
418 date = opts.get('date')
418 date = opts.get('date')
419 if date:
419 if date:
420 opts['date'] = util.parsedate(date)
420 opts['date'] = util.parsedate(date)
421
421
422 cmdutil.bailifchanged(repo)
422 cmdutil.bailifchanged(repo)
423 node = scmutil.revsingle(repo, rev).node()
423 node = scmutil.revsingle(repo, rev).node()
424
424
425 op1, op2 = repo.dirstate.parents()
425 op1, op2 = repo.dirstate.parents()
426 a = repo.changelog.ancestor(op1, node)
426 a = repo.changelog.ancestor(op1, node)
427 if a != node:
427 if a != node:
428 raise util.Abort(_('cannot backout change on a different branch'))
428 raise util.Abort(_('cannot backout change on a different branch'))
429
429
430 p1, p2 = repo.changelog.parents(node)
430 p1, p2 = repo.changelog.parents(node)
431 if p1 == nullid:
431 if p1 == nullid:
432 raise util.Abort(_('cannot backout a change with no parents'))
432 raise util.Abort(_('cannot backout a change with no parents'))
433 if p2 != nullid:
433 if p2 != nullid:
434 if not opts.get('parent'):
434 if not opts.get('parent'):
435 raise util.Abort(_('cannot backout a merge changeset'))
435 raise util.Abort(_('cannot backout a merge changeset'))
436 p = repo.lookup(opts['parent'])
436 p = repo.lookup(opts['parent'])
437 if p not in (p1, p2):
437 if p not in (p1, p2):
438 raise util.Abort(_('%s is not a parent of %s') %
438 raise util.Abort(_('%s is not a parent of %s') %
439 (short(p), short(node)))
439 (short(p), short(node)))
440 parent = p
440 parent = p
441 else:
441 else:
442 if opts.get('parent'):
442 if opts.get('parent'):
443 raise util.Abort(_('cannot use --parent on non-merge changeset'))
443 raise util.Abort(_('cannot use --parent on non-merge changeset'))
444 parent = p1
444 parent = p1
445
445
446 # the backout should appear on the same branch
446 # the backout should appear on the same branch
447 branch = repo.dirstate.branch()
447 branch = repo.dirstate.branch()
448 hg.clean(repo, node, show_stats=False)
448 hg.clean(repo, node, show_stats=False)
449 repo.dirstate.setbranch(branch)
449 repo.dirstate.setbranch(branch)
450 revert_opts = opts.copy()
450 revert_opts = opts.copy()
451 revert_opts['date'] = None
451 revert_opts['date'] = None
452 revert_opts['all'] = True
452 revert_opts['all'] = True
453 revert_opts['rev'] = hex(parent)
453 revert_opts['rev'] = hex(parent)
454 revert_opts['no_backup'] = None
454 revert_opts['no_backup'] = None
455 revert(ui, repo, **revert_opts)
455 revert(ui, repo, **revert_opts)
456 if not opts.get('merge') and op1 != node:
456 if not opts.get('merge') and op1 != node:
457 try:
457 try:
458 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
458 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
459 return hg.update(repo, op1)
459 return hg.update(repo, op1)
460 finally:
460 finally:
461 ui.setconfig('ui', 'forcemerge', '')
461 ui.setconfig('ui', 'forcemerge', '')
462
462
463 commit_opts = opts.copy()
463 commit_opts = opts.copy()
464 commit_opts['addremove'] = False
464 commit_opts['addremove'] = False
465 if not commit_opts['message'] and not commit_opts['logfile']:
465 if not commit_opts['message'] and not commit_opts['logfile']:
466 # we don't translate commit messages
466 # we don't translate commit messages
467 commit_opts['message'] = "Backed out changeset %s" % short(node)
467 commit_opts['message'] = "Backed out changeset %s" % short(node)
468 commit_opts['force_editor'] = True
468 commit_opts['force_editor'] = True
469 commit(ui, repo, **commit_opts)
469 commit(ui, repo, **commit_opts)
470 def nice(node):
470 def nice(node):
471 return '%d:%s' % (repo.changelog.rev(node), short(node))
471 return '%d:%s' % (repo.changelog.rev(node), short(node))
472 ui.status(_('changeset %s backs out changeset %s\n') %
472 ui.status(_('changeset %s backs out changeset %s\n') %
473 (nice(repo.changelog.tip()), nice(node)))
473 (nice(repo.changelog.tip()), nice(node)))
474 if opts.get('merge') and op1 != node:
474 if opts.get('merge') and op1 != node:
475 hg.clean(repo, op1, show_stats=False)
475 hg.clean(repo, op1, show_stats=False)
476 ui.status(_('merging with changeset %s\n')
476 ui.status(_('merging with changeset %s\n')
477 % nice(repo.changelog.tip()))
477 % nice(repo.changelog.tip()))
478 try:
478 try:
479 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
479 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
480 return hg.merge(repo, hex(repo.changelog.tip()))
480 return hg.merge(repo, hex(repo.changelog.tip()))
481 finally:
481 finally:
482 ui.setconfig('ui', 'forcemerge', '')
482 ui.setconfig('ui', 'forcemerge', '')
483 return 0
483 return 0
484
484
485 @command('bisect',
485 @command('bisect',
486 [('r', 'reset', False, _('reset bisect state')),
486 [('r', 'reset', False, _('reset bisect state')),
487 ('g', 'good', False, _('mark changeset good')),
487 ('g', 'good', False, _('mark changeset good')),
488 ('b', 'bad', False, _('mark changeset bad')),
488 ('b', 'bad', False, _('mark changeset bad')),
489 ('s', 'skip', False, _('skip testing changeset')),
489 ('s', 'skip', False, _('skip testing changeset')),
490 ('e', 'extend', False, _('extend the bisect range')),
490 ('e', 'extend', False, _('extend the bisect range')),
491 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
491 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
492 ('U', 'noupdate', False, _('do not update to target'))],
492 ('U', 'noupdate', False, _('do not update to target'))],
493 _("[-gbsr] [-U] [-c CMD] [REV]"))
493 _("[-gbsr] [-U] [-c CMD] [REV]"))
494 def bisect(ui, repo, rev=None, extra=None, command=None,
494 def bisect(ui, repo, rev=None, extra=None, command=None,
495 reset=None, good=None, bad=None, skip=None, extend=None,
495 reset=None, good=None, bad=None, skip=None, extend=None,
496 noupdate=None):
496 noupdate=None):
497 """subdivision search of changesets
497 """subdivision search of changesets
498
498
499 This command helps to find changesets which introduce problems. To
499 This command helps to find changesets which introduce problems. To
500 use, mark the earliest changeset you know exhibits the problem as
500 use, mark the earliest changeset you know exhibits the problem as
501 bad, then mark the latest changeset which is free from the problem
501 bad, then mark the latest changeset which is free from the problem
502 as good. Bisect will update your working directory to a revision
502 as good. Bisect will update your working directory to a revision
503 for testing (unless the -U/--noupdate option is specified). Once
503 for testing (unless the -U/--noupdate option is specified). Once
504 you have performed tests, mark the working directory as good or
504 you have performed tests, mark the working directory as good or
505 bad, and bisect will either update to another candidate changeset
505 bad, and bisect will either update to another candidate changeset
506 or announce that it has found the bad revision.
506 or announce that it has found the bad revision.
507
507
508 As a shortcut, you can also use the revision argument to mark a
508 As a shortcut, you can also use the revision argument to mark a
509 revision as good or bad without checking it out first.
509 revision as good or bad without checking it out first.
510
510
511 If you supply a command, it will be used for automatic bisection.
511 If you supply a command, it will be used for automatic bisection.
512 Its exit status will be used to mark revisions as good or bad:
512 Its exit status will be used to mark revisions as good or bad:
513 status 0 means good, 125 means to skip the revision, 127
513 status 0 means good, 125 means to skip the revision, 127
514 (command not found) will abort the bisection, and any other
514 (command not found) will abort the bisection, and any other
515 non-zero exit status means the revision is bad.
515 non-zero exit status means the revision is bad.
516
516
517 .. container:: verbose
517 .. container:: verbose
518
518
519 Some examples:
519 Some examples:
520
520
521 - start a bisection with known bad revision 12, and good revision 34::
521 - start a bisection with known bad revision 12, and good revision 34::
522
522
523 hg bisect --bad 34
523 hg bisect --bad 34
524 hg bisect --good 12
524 hg bisect --good 12
525
525
526 - advance the current bisection by marking current revision as good or
526 - advance the current bisection by marking current revision as good or
527 bad::
527 bad::
528
528
529 hg bisect --good
529 hg bisect --good
530 hg bisect --bad
530 hg bisect --bad
531
531
532 - mark the current revision, or a known revision, to be skipped (eg. if
532 - mark the current revision, or a known revision, to be skipped (eg. if
533 that revision is not usable because of another issue)::
533 that revision is not usable because of another issue)::
534
534
535 hg bisect --skip
535 hg bisect --skip
536 hg bisect --skip 23
536 hg bisect --skip 23
537
537
538 - forget the current bisection::
538 - forget the current bisection::
539
539
540 hg bisect --reset
540 hg bisect --reset
541
541
542 - use 'make && make tests' to automatically find the first broken
542 - use 'make && make tests' to automatically find the first broken
543 revision::
543 revision::
544
544
545 hg bisect --reset
545 hg bisect --reset
546 hg bisect --bad 34
546 hg bisect --bad 34
547 hg bisect --good 12
547 hg bisect --good 12
548 hg bisect --command 'make && make tests'
548 hg bisect --command 'make && make tests'
549
549
550 - see all changesets whose states are already known in the current
550 - see all changesets whose states are already known in the current
551 bisection::
551 bisection::
552
552
553 hg log -r "bisect(pruned)"
553 hg log -r "bisect(pruned)"
554
554
555 - see all changesets that took part in the current bisection::
555 - see all changesets that took part in the current bisection::
556
556
557 hg log -r "bisect(range)"
557 hg log -r "bisect(range)"
558
558
559 - with the graphlog extension, you can even get a nice graph::
559 - with the graphlog extension, you can even get a nice graph::
560
560
561 hg log --graph -r "bisect(range)"
561 hg log --graph -r "bisect(range)"
562
562
563 See :hg:`help revsets` for more about the `bisect()` keyword.
563 See :hg:`help revsets` for more about the `bisect()` keyword.
564
564
565 Returns 0 on success.
565 Returns 0 on success.
566 """
566 """
567 def extendbisectrange(nodes, good):
567 def extendbisectrange(nodes, good):
568 # bisect is incomplete when it ends on a merge node and
568 # bisect is incomplete when it ends on a merge node and
569 # one of the parent was not checked.
569 # one of the parent was not checked.
570 parents = repo[nodes[0]].parents()
570 parents = repo[nodes[0]].parents()
571 if len(parents) > 1:
571 if len(parents) > 1:
572 side = good and state['bad'] or state['good']
572 side = good and state['bad'] or state['good']
573 num = len(set(i.node() for i in parents) & set(side))
573 num = len(set(i.node() for i in parents) & set(side))
574 if num == 1:
574 if num == 1:
575 return parents[0].ancestor(parents[1])
575 return parents[0].ancestor(parents[1])
576 return None
576 return None
577
577
578 def print_result(nodes, good):
578 def print_result(nodes, good):
579 displayer = cmdutil.show_changeset(ui, repo, {})
579 displayer = cmdutil.show_changeset(ui, repo, {})
580 if len(nodes) == 1:
580 if len(nodes) == 1:
581 # narrowed it down to a single revision
581 # narrowed it down to a single revision
582 if good:
582 if good:
583 ui.write(_("The first good revision is:\n"))
583 ui.write(_("The first good revision is:\n"))
584 else:
584 else:
585 ui.write(_("The first bad revision is:\n"))
585 ui.write(_("The first bad revision is:\n"))
586 displayer.show(repo[nodes[0]])
586 displayer.show(repo[nodes[0]])
587 extendnode = extendbisectrange(nodes, good)
587 extendnode = extendbisectrange(nodes, good)
588 if extendnode is not None:
588 if extendnode is not None:
589 ui.write(_('Not all ancestors of this changeset have been'
589 ui.write(_('Not all ancestors of this changeset have been'
590 ' checked.\nUse bisect --extend to continue the '
590 ' checked.\nUse bisect --extend to continue the '
591 'bisection from\nthe common ancestor, %s.\n')
591 'bisection from\nthe common ancestor, %s.\n')
592 % extendnode)
592 % extendnode)
593 else:
593 else:
594 # multiple possible revisions
594 # multiple possible revisions
595 if good:
595 if good:
596 ui.write(_("Due to skipped revisions, the first "
596 ui.write(_("Due to skipped revisions, the first "
597 "good revision could be any of:\n"))
597 "good revision could be any of:\n"))
598 else:
598 else:
599 ui.write(_("Due to skipped revisions, the first "
599 ui.write(_("Due to skipped revisions, the first "
600 "bad revision could be any of:\n"))
600 "bad revision could be any of:\n"))
601 for n in nodes:
601 for n in nodes:
602 displayer.show(repo[n])
602 displayer.show(repo[n])
603 displayer.close()
603 displayer.close()
604
604
605 def check_state(state, interactive=True):
605 def check_state(state, interactive=True):
606 if not state['good'] or not state['bad']:
606 if not state['good'] or not state['bad']:
607 if (good or bad or skip or reset) and interactive:
607 if (good or bad or skip or reset) and interactive:
608 return
608 return
609 if not state['good']:
609 if not state['good']:
610 raise util.Abort(_('cannot bisect (no known good revisions)'))
610 raise util.Abort(_('cannot bisect (no known good revisions)'))
611 else:
611 else:
612 raise util.Abort(_('cannot bisect (no known bad revisions)'))
612 raise util.Abort(_('cannot bisect (no known bad revisions)'))
613 return True
613 return True
614
614
615 # backward compatibility
615 # backward compatibility
616 if rev in "good bad reset init".split():
616 if rev in "good bad reset init".split():
617 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
617 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
618 cmd, rev, extra = rev, extra, None
618 cmd, rev, extra = rev, extra, None
619 if cmd == "good":
619 if cmd == "good":
620 good = True
620 good = True
621 elif cmd == "bad":
621 elif cmd == "bad":
622 bad = True
622 bad = True
623 else:
623 else:
624 reset = True
624 reset = True
625 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
625 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
626 raise util.Abort(_('incompatible arguments'))
626 raise util.Abort(_('incompatible arguments'))
627
627
628 if reset:
628 if reset:
629 p = repo.join("bisect.state")
629 p = repo.join("bisect.state")
630 if os.path.exists(p):
630 if os.path.exists(p):
631 os.unlink(p)
631 os.unlink(p)
632 return
632 return
633
633
634 state = hbisect.load_state(repo)
634 state = hbisect.load_state(repo)
635
635
636 if command:
636 if command:
637 changesets = 1
637 changesets = 1
638 try:
638 try:
639 while changesets:
639 while changesets:
640 # update state
640 # update state
641 status = util.system(command, out=ui.fout)
641 status = util.system(command, out=ui.fout)
642 if status == 125:
642 if status == 125:
643 transition = "skip"
643 transition = "skip"
644 elif status == 0:
644 elif status == 0:
645 transition = "good"
645 transition = "good"
646 # status < 0 means process was killed
646 # status < 0 means process was killed
647 elif status == 127:
647 elif status == 127:
648 raise util.Abort(_("failed to execute %s") % command)
648 raise util.Abort(_("failed to execute %s") % command)
649 elif status < 0:
649 elif status < 0:
650 raise util.Abort(_("%s killed") % command)
650 raise util.Abort(_("%s killed") % command)
651 else:
651 else:
652 transition = "bad"
652 transition = "bad"
653 ctx = scmutil.revsingle(repo, rev)
653 ctx = scmutil.revsingle(repo, rev)
654 rev = None # clear for future iterations
654 rev = None # clear for future iterations
655 state[transition].append(ctx.node())
655 state[transition].append(ctx.node())
656 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
656 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
657 check_state(state, interactive=False)
657 check_state(state, interactive=False)
658 # bisect
658 # bisect
659 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
659 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
660 # update to next check
660 # update to next check
661 cmdutil.bailifchanged(repo)
661 cmdutil.bailifchanged(repo)
662 hg.clean(repo, nodes[0], show_stats=False)
662 hg.clean(repo, nodes[0], show_stats=False)
663 finally:
663 finally:
664 hbisect.save_state(repo, state)
664 hbisect.save_state(repo, state)
665 print_result(nodes, good)
665 print_result(nodes, good)
666 return
666 return
667
667
668 # update state
668 # update state
669
669
670 if rev:
670 if rev:
671 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
671 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
672 else:
672 else:
673 nodes = [repo.lookup('.')]
673 nodes = [repo.lookup('.')]
674
674
675 if good or bad or skip:
675 if good or bad or skip:
676 if good:
676 if good:
677 state['good'] += nodes
677 state['good'] += nodes
678 elif bad:
678 elif bad:
679 state['bad'] += nodes
679 state['bad'] += nodes
680 elif skip:
680 elif skip:
681 state['skip'] += nodes
681 state['skip'] += nodes
682 hbisect.save_state(repo, state)
682 hbisect.save_state(repo, state)
683
683
684 if not check_state(state):
684 if not check_state(state):
685 return
685 return
686
686
687 # actually bisect
687 # actually bisect
688 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
688 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
689 if extend:
689 if extend:
690 if not changesets:
690 if not changesets:
691 extendnode = extendbisectrange(nodes, good)
691 extendnode = extendbisectrange(nodes, good)
692 if extendnode is not None:
692 if extendnode is not None:
693 ui.write(_("Extending search to changeset %d:%s\n"
693 ui.write(_("Extending search to changeset %d:%s\n"
694 % (extendnode.rev(), extendnode)))
694 % (extendnode.rev(), extendnode)))
695 if noupdate:
695 if noupdate:
696 return
696 return
697 cmdutil.bailifchanged(repo)
697 cmdutil.bailifchanged(repo)
698 return hg.clean(repo, extendnode.node())
698 return hg.clean(repo, extendnode.node())
699 raise util.Abort(_("nothing to extend"))
699 raise util.Abort(_("nothing to extend"))
700
700
701 if changesets == 0:
701 if changesets == 0:
702 print_result(nodes, good)
702 print_result(nodes, good)
703 else:
703 else:
704 assert len(nodes) == 1 # only a single node can be tested next
704 assert len(nodes) == 1 # only a single node can be tested next
705 node = nodes[0]
705 node = nodes[0]
706 # compute the approximate number of remaining tests
706 # compute the approximate number of remaining tests
707 tests, size = 0, 2
707 tests, size = 0, 2
708 while size <= changesets:
708 while size <= changesets:
709 tests, size = tests + 1, size * 2
709 tests, size = tests + 1, size * 2
710 rev = repo.changelog.rev(node)
710 rev = repo.changelog.rev(node)
711 ui.write(_("Testing changeset %d:%s "
711 ui.write(_("Testing changeset %d:%s "
712 "(%d changesets remaining, ~%d tests)\n")
712 "(%d changesets remaining, ~%d tests)\n")
713 % (rev, short(node), changesets, tests))
713 % (rev, short(node), changesets, tests))
714 if not noupdate:
714 if not noupdate:
715 cmdutil.bailifchanged(repo)
715 cmdutil.bailifchanged(repo)
716 return hg.clean(repo, node)
716 return hg.clean(repo, node)
717
717
718 @command('bookmarks',
718 @command('bookmarks',
719 [('f', 'force', False, _('force')),
719 [('f', 'force', False, _('force')),
720 ('r', 'rev', '', _('revision'), _('REV')),
720 ('r', 'rev', '', _('revision'), _('REV')),
721 ('d', 'delete', False, _('delete a given bookmark')),
721 ('d', 'delete', False, _('delete a given bookmark')),
722 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
722 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
723 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
723 ('i', 'inactive', False, _('do not mark a new bookmark active'))],
724 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
724 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
725 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
725 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
726 rename=None, inactive=False):
726 rename=None, inactive=False):
727 '''track a line of development with movable markers
727 '''track a line of development with movable markers
728
728
729 Bookmarks are pointers to certain commits that move when
729 Bookmarks are pointers to certain commits that move when
730 committing. Bookmarks are local. They can be renamed, copied and
730 committing. Bookmarks are local. They can be renamed, copied and
731 deleted. It is possible to use bookmark names in :hg:`merge` and
731 deleted. It is possible to use bookmark names in :hg:`merge` and
732 :hg:`update` to merge and update respectively to a given bookmark.
732 :hg:`update` to merge and update respectively to a given bookmark.
733
733
734 You can use :hg:`bookmark NAME` to set a bookmark on the working
734 You can use :hg:`bookmark NAME` to set a bookmark on the working
735 directory's parent revision with the given name. If you specify
735 directory's parent revision with the given name. If you specify
736 a revision using -r REV (where REV may be an existing bookmark),
736 a revision using -r REV (where REV may be an existing bookmark),
737 the bookmark is assigned to that revision.
737 the bookmark is assigned to that revision.
738
738
739 Bookmarks can be pushed and pulled between repositories (see :hg:`help
739 Bookmarks can be pushed and pulled between repositories (see :hg:`help
740 push` and :hg:`help pull`). This requires both the local and remote
740 push` and :hg:`help pull`). This requires both the local and remote
741 repositories to support bookmarks. For versions prior to 1.8, this means
741 repositories to support bookmarks. For versions prior to 1.8, this means
742 the bookmarks extension must be enabled.
742 the bookmarks extension must be enabled.
743 '''
743 '''
744 hexfn = ui.debugflag and hex or short
744 hexfn = ui.debugflag and hex or short
745 marks = repo._bookmarks
745 marks = repo._bookmarks
746 cur = repo.changectx('.').node()
746 cur = repo.changectx('.').node()
747
747
748 if delete:
748 if delete:
749 if mark is None:
749 if mark is None:
750 raise util.Abort(_("bookmark name required"))
750 raise util.Abort(_("bookmark name required"))
751 if mark not in marks:
751 if mark not in marks:
752 raise util.Abort(_("bookmark '%s' does not exist") % mark)
752 raise util.Abort(_("bookmark '%s' does not exist") % mark)
753 if mark == repo._bookmarkcurrent:
753 if mark == repo._bookmarkcurrent:
754 bookmarks.setcurrent(repo, None)
754 bookmarks.setcurrent(repo, None)
755 del marks[mark]
755 del marks[mark]
756 bookmarks.write(repo)
756 bookmarks.write(repo)
757 return
757 return
758
758
759 if rename:
759 if rename:
760 if rename not in marks:
760 if rename not in marks:
761 raise util.Abort(_("bookmark '%s' does not exist") % rename)
761 raise util.Abort(_("bookmark '%s' does not exist") % rename)
762 if mark in marks and not force:
762 if mark in marks and not force:
763 raise util.Abort(_("bookmark '%s' already exists "
763 raise util.Abort(_("bookmark '%s' already exists "
764 "(use -f to force)") % mark)
764 "(use -f to force)") % mark)
765 if mark is None:
765 if mark is None:
766 raise util.Abort(_("new bookmark name required"))
766 raise util.Abort(_("new bookmark name required"))
767 marks[mark] = marks[rename]
767 marks[mark] = marks[rename]
768 if repo._bookmarkcurrent == rename and not inactive:
768 if repo._bookmarkcurrent == rename and not inactive:
769 bookmarks.setcurrent(repo, mark)
769 bookmarks.setcurrent(repo, mark)
770 del marks[rename]
770 del marks[rename]
771 bookmarks.write(repo)
771 bookmarks.write(repo)
772 return
772 return
773
773
774 if mark is not None:
774 if mark is not None:
775 if "\n" in mark:
775 if "\n" in mark:
776 raise util.Abort(_("bookmark name cannot contain newlines"))
776 raise util.Abort(_("bookmark name cannot contain newlines"))
777 mark = mark.strip()
777 mark = mark.strip()
778 if not mark:
778 if not mark:
779 raise util.Abort(_("bookmark names cannot consist entirely of "
779 raise util.Abort(_("bookmark names cannot consist entirely of "
780 "whitespace"))
780 "whitespace"))
781 if inactive and mark == repo._bookmarkcurrent:
781 if inactive and mark == repo._bookmarkcurrent:
782 bookmarks.setcurrent(repo, None)
782 bookmarks.setcurrent(repo, None)
783 return
783 return
784 if mark in marks and not force:
784 if mark in marks and not force:
785 raise util.Abort(_("bookmark '%s' already exists "
785 raise util.Abort(_("bookmark '%s' already exists "
786 "(use -f to force)") % mark)
786 "(use -f to force)") % mark)
787 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
787 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
788 and not force):
788 and not force):
789 raise util.Abort(
789 raise util.Abort(
790 _("a bookmark cannot have the name of an existing branch"))
790 _("a bookmark cannot have the name of an existing branch"))
791 if rev:
791 if rev:
792 marks[mark] = repo.lookup(rev)
792 marks[mark] = repo.lookup(rev)
793 else:
793 else:
794 marks[mark] = cur
794 marks[mark] = cur
795 if not inactive and cur == marks[mark]:
795 if not inactive and cur == marks[mark]:
796 bookmarks.setcurrent(repo, mark)
796 bookmarks.setcurrent(repo, mark)
797 bookmarks.write(repo)
797 bookmarks.write(repo)
798 return
798 return
799
799
800 if mark is None:
800 if mark is None:
801 if rev:
801 if rev:
802 raise util.Abort(_("bookmark name required"))
802 raise util.Abort(_("bookmark name required"))
803 if len(marks) == 0:
803 if len(marks) == 0:
804 ui.status(_("no bookmarks set\n"))
804 ui.status(_("no bookmarks set\n"))
805 else:
805 else:
806 for bmark, n in sorted(marks.iteritems()):
806 for bmark, n in sorted(marks.iteritems()):
807 current = repo._bookmarkcurrent
807 current = repo._bookmarkcurrent
808 if bmark == current and n == cur:
808 if bmark == current and n == cur:
809 prefix, label = '*', 'bookmarks.current'
809 prefix, label = '*', 'bookmarks.current'
810 else:
810 else:
811 prefix, label = ' ', ''
811 prefix, label = ' ', ''
812
812
813 if ui.quiet:
813 if ui.quiet:
814 ui.write("%s\n" % bmark, label=label)
814 ui.write("%s\n" % bmark, label=label)
815 else:
815 else:
816 ui.write(" %s %-25s %d:%s\n" % (
816 ui.write(" %s %-25s %d:%s\n" % (
817 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
817 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
818 label=label)
818 label=label)
819 return
819 return
820
820
821 @command('branch',
821 @command('branch',
822 [('f', 'force', None,
822 [('f', 'force', None,
823 _('set branch name even if it shadows an existing branch')),
823 _('set branch name even if it shadows an existing branch')),
824 ('C', 'clean', None, _('reset branch name to parent branch name'))],
824 ('C', 'clean', None, _('reset branch name to parent branch name'))],
825 _('[-fC] [NAME]'))
825 _('[-fC] [NAME]'))
826 def branch(ui, repo, label=None, **opts):
826 def branch(ui, repo, label=None, **opts):
827 """set or show the current branch name
827 """set or show the current branch name
828
828
829 With no argument, show the current branch name. With one argument,
829 With no argument, show the current branch name. With one argument,
830 set the working directory branch name (the branch will not exist
830 set the working directory branch name (the branch will not exist
831 in the repository until the next commit). Standard practice
831 in the repository until the next commit). Standard practice
832 recommends that primary development take place on the 'default'
832 recommends that primary development take place on the 'default'
833 branch.
833 branch.
834
834
835 Unless -f/--force is specified, branch will not let you set a
835 Unless -f/--force is specified, branch will not let you set a
836 branch name that already exists, even if it's inactive.
836 branch name that already exists, even if it's inactive.
837
837
838 Use -C/--clean to reset the working directory branch to that of
838 Use -C/--clean to reset the working directory branch to that of
839 the parent of the working directory, negating a previous branch
839 the parent of the working directory, negating a previous branch
840 change.
840 change.
841
841
842 Use the command :hg:`update` to switch to an existing branch. Use
842 Use the command :hg:`update` to switch to an existing branch. Use
843 :hg:`commit --close-branch` to mark this branch as closed.
843 :hg:`commit --close-branch` to mark this branch as closed.
844
844
845 .. note::
845 .. note::
846 Branch names are permanent. Use :hg:`bookmark` to create a
846 Branch names are permanent. Use :hg:`bookmark` to create a
847 light-weight bookmark instead. See :hg:`help glossary` for more
847 light-weight bookmark instead. See :hg:`help glossary` for more
848 information about named branches and bookmarks.
848 information about named branches and bookmarks.
849
849
850 Returns 0 on success.
850 Returns 0 on success.
851 """
851 """
852
852
853 if opts.get('clean'):
853 if opts.get('clean'):
854 label = repo[None].p1().branch()
854 label = repo[None].p1().branch()
855 repo.dirstate.setbranch(label)
855 repo.dirstate.setbranch(label)
856 ui.status(_('reset working directory to branch %s\n') % label)
856 ui.status(_('reset working directory to branch %s\n') % label)
857 elif label:
857 elif label:
858 if not opts.get('force') and label in repo.branchtags():
858 if not opts.get('force') and label in repo.branchtags():
859 if label not in [p.branch() for p in repo.parents()]:
859 if label not in [p.branch() for p in repo.parents()]:
860 raise util.Abort(_('a branch of the same name already exists'),
860 raise util.Abort(_('a branch of the same name already exists'),
861 # i18n: "it" refers to an existing branch
861 # i18n: "it" refers to an existing branch
862 hint=_("use 'hg update' to switch to it"))
862 hint=_("use 'hg update' to switch to it"))
863 repo.dirstate.setbranch(label)
863 repo.dirstate.setbranch(label)
864 ui.status(_('marked working directory as branch %s\n') % label)
864 ui.status(_('marked working directory as branch %s\n') % label)
865 else:
865 else:
866 ui.write("%s\n" % repo.dirstate.branch())
866 ui.write("%s\n" % repo.dirstate.branch())
867
867
868 @command('branches',
868 @command('branches',
869 [('a', 'active', False, _('show only branches that have unmerged heads')),
869 [('a', 'active', False, _('show only branches that have unmerged heads')),
870 ('c', 'closed', False, _('show normal and closed branches'))],
870 ('c', 'closed', False, _('show normal and closed branches'))],
871 _('[-ac]'))
871 _('[-ac]'))
872 def branches(ui, repo, active=False, closed=False):
872 def branches(ui, repo, active=False, closed=False):
873 """list repository named branches
873 """list repository named branches
874
874
875 List the repository's named branches, indicating which ones are
875 List the repository's named branches, indicating which ones are
876 inactive. If -c/--closed is specified, also list branches which have
876 inactive. If -c/--closed is specified, also list branches which have
877 been marked closed (see :hg:`commit --close-branch`).
877 been marked closed (see :hg:`commit --close-branch`).
878
878
879 If -a/--active is specified, only show active branches. A branch
879 If -a/--active is specified, only show active branches. A branch
880 is considered active if it contains repository heads.
880 is considered active if it contains repository heads.
881
881
882 Use the command :hg:`update` to switch to an existing branch.
882 Use the command :hg:`update` to switch to an existing branch.
883
883
884 Returns 0.
884 Returns 0.
885 """
885 """
886
886
887 hexfunc = ui.debugflag and hex or short
887 hexfunc = ui.debugflag and hex or short
888 activebranches = [repo[n].branch() for n in repo.heads()]
888 activebranches = [repo[n].branch() for n in repo.heads()]
889 def testactive(tag, node):
889 def testactive(tag, node):
890 realhead = tag in activebranches
890 realhead = tag in activebranches
891 open = node in repo.branchheads(tag, closed=False)
891 open = node in repo.branchheads(tag, closed=False)
892 return realhead and open
892 return realhead and open
893 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
893 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
894 for tag, node in repo.branchtags().items()],
894 for tag, node in repo.branchtags().items()],
895 reverse=True)
895 reverse=True)
896
896
897 for isactive, node, tag in branches:
897 for isactive, node, tag in branches:
898 if (not active) or isactive:
898 if (not active) or isactive:
899 if ui.quiet:
899 if ui.quiet:
900 ui.write("%s\n" % tag)
900 ui.write("%s\n" % tag)
901 else:
901 else:
902 hn = repo.lookup(node)
902 hn = repo.lookup(node)
903 if isactive:
903 if isactive:
904 label = 'branches.active'
904 label = 'branches.active'
905 notice = ''
905 notice = ''
906 elif hn not in repo.branchheads(tag, closed=False):
906 elif hn not in repo.branchheads(tag, closed=False):
907 if not closed:
907 if not closed:
908 continue
908 continue
909 label = 'branches.closed'
909 label = 'branches.closed'
910 notice = _(' (closed)')
910 notice = _(' (closed)')
911 else:
911 else:
912 label = 'branches.inactive'
912 label = 'branches.inactive'
913 notice = _(' (inactive)')
913 notice = _(' (inactive)')
914 if tag == repo.dirstate.branch():
914 if tag == repo.dirstate.branch():
915 label = 'branches.current'
915 label = 'branches.current'
916 rev = str(node).rjust(31 - encoding.colwidth(tag))
916 rev = str(node).rjust(31 - encoding.colwidth(tag))
917 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
917 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
918 tag = ui.label(tag, label)
918 tag = ui.label(tag, label)
919 ui.write("%s %s%s\n" % (tag, rev, notice))
919 ui.write("%s %s%s\n" % (tag, rev, notice))
920
920
921 @command('bundle',
921 @command('bundle',
922 [('f', 'force', None, _('run even when the destination is unrelated')),
922 [('f', 'force', None, _('run even when the destination is unrelated')),
923 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
923 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
924 _('REV')),
924 _('REV')),
925 ('b', 'branch', [], _('a specific branch you would like to bundle'),
925 ('b', 'branch', [], _('a specific branch you would like to bundle'),
926 _('BRANCH')),
926 _('BRANCH')),
927 ('', 'base', [],
927 ('', 'base', [],
928 _('a base changeset assumed to be available at the destination'),
928 _('a base changeset assumed to be available at the destination'),
929 _('REV')),
929 _('REV')),
930 ('a', 'all', None, _('bundle all changesets in the repository')),
930 ('a', 'all', None, _('bundle all changesets in the repository')),
931 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
931 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
932 ] + remoteopts,
932 ] + remoteopts,
933 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
933 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
934 def bundle(ui, repo, fname, dest=None, **opts):
934 def bundle(ui, repo, fname, dest=None, **opts):
935 """create a changegroup file
935 """create a changegroup file
936
936
937 Generate a compressed changegroup file collecting changesets not
937 Generate a compressed changegroup file collecting changesets not
938 known to be in another repository.
938 known to be in another repository.
939
939
940 If you omit the destination repository, then hg assumes the
940 If you omit the destination repository, then hg assumes the
941 destination will have all the nodes you specify with --base
941 destination will have all the nodes you specify with --base
942 parameters. To create a bundle containing all changesets, use
942 parameters. To create a bundle containing all changesets, use
943 -a/--all (or --base null).
943 -a/--all (or --base null).
944
944
945 You can change compression method with the -t/--type option.
945 You can change compression method with the -t/--type option.
946 The available compression methods are: none, bzip2, and
946 The available compression methods are: none, bzip2, and
947 gzip (by default, bundles are compressed using bzip2).
947 gzip (by default, bundles are compressed using bzip2).
948
948
949 The bundle file can then be transferred using conventional means
949 The bundle file can then be transferred using conventional means
950 and applied to another repository with the unbundle or pull
950 and applied to another repository with the unbundle or pull
951 command. This is useful when direct push and pull are not
951 command. This is useful when direct push and pull are not
952 available or when exporting an entire repository is undesirable.
952 available or when exporting an entire repository is undesirable.
953
953
954 Applying bundles preserves all changeset contents including
954 Applying bundles preserves all changeset contents including
955 permissions, copy/rename information, and revision history.
955 permissions, copy/rename information, and revision history.
956
956
957 Returns 0 on success, 1 if no changes found.
957 Returns 0 on success, 1 if no changes found.
958 """
958 """
959 revs = None
959 revs = None
960 if 'rev' in opts:
960 if 'rev' in opts:
961 revs = scmutil.revrange(repo, opts['rev'])
961 revs = scmutil.revrange(repo, opts['rev'])
962
962
963 if opts.get('all'):
963 if opts.get('all'):
964 base = ['null']
964 base = ['null']
965 else:
965 else:
966 base = scmutil.revrange(repo, opts.get('base'))
966 base = scmutil.revrange(repo, opts.get('base'))
967 if base:
967 if base:
968 if dest:
968 if dest:
969 raise util.Abort(_("--base is incompatible with specifying "
969 raise util.Abort(_("--base is incompatible with specifying "
970 "a destination"))
970 "a destination"))
971 common = [repo.lookup(rev) for rev in base]
971 common = [repo.lookup(rev) for rev in base]
972 heads = revs and map(repo.lookup, revs) or revs
972 heads = revs and map(repo.lookup, revs) or revs
973 else:
973 else:
974 dest = ui.expandpath(dest or 'default-push', dest or 'default')
974 dest = ui.expandpath(dest or 'default-push', dest or 'default')
975 dest, branches = hg.parseurl(dest, opts.get('branch'))
975 dest, branches = hg.parseurl(dest, opts.get('branch'))
976 other = hg.peer(repo, opts, dest)
976 other = hg.peer(repo, opts, dest)
977 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
977 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
978 heads = revs and map(repo.lookup, revs) or revs
978 heads = revs and map(repo.lookup, revs) or revs
979 common, outheads = discovery.findcommonoutgoing(repo, other,
979 common, outheads = discovery.findcommonoutgoing(repo, other,
980 onlyheads=heads,
980 onlyheads=heads,
981 force=opts.get('force'))
981 force=opts.get('force'))
982
982
983 cg = repo.getbundle('bundle', common=common, heads=heads)
983 cg = repo.getbundle('bundle', common=common, heads=heads)
984 if not cg:
984 if not cg:
985 ui.status(_("no changes found\n"))
985 ui.status(_("no changes found\n"))
986 return 1
986 return 1
987
987
988 bundletype = opts.get('type', 'bzip2').lower()
988 bundletype = opts.get('type', 'bzip2').lower()
989 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
989 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
990 bundletype = btypes.get(bundletype)
990 bundletype = btypes.get(bundletype)
991 if bundletype not in changegroup.bundletypes:
991 if bundletype not in changegroup.bundletypes:
992 raise util.Abort(_('unknown bundle type specified with --type'))
992 raise util.Abort(_('unknown bundle type specified with --type'))
993
993
994 changegroup.writebundle(cg, fname, bundletype)
994 changegroup.writebundle(cg, fname, bundletype)
995
995
996 @command('cat',
996 @command('cat',
997 [('o', 'output', '',
997 [('o', 'output', '',
998 _('print output to file with formatted name'), _('FORMAT')),
998 _('print output to file with formatted name'), _('FORMAT')),
999 ('r', 'rev', '', _('print the given revision'), _('REV')),
999 ('r', 'rev', '', _('print the given revision'), _('REV')),
1000 ('', 'decode', None, _('apply any matching decode filter')),
1000 ('', 'decode', None, _('apply any matching decode filter')),
1001 ] + walkopts,
1001 ] + walkopts,
1002 _('[OPTION]... FILE...'))
1002 _('[OPTION]... FILE...'))
1003 def cat(ui, repo, file1, *pats, **opts):
1003 def cat(ui, repo, file1, *pats, **opts):
1004 """output the current or given revision of files
1004 """output the current or given revision of files
1005
1005
1006 Print the specified files as they were at the given revision. If
1006 Print the specified files as they were at the given revision. If
1007 no revision is given, the parent of the working directory is used,
1007 no revision is given, the parent of the working directory is used,
1008 or tip if no revision is checked out.
1008 or tip if no revision is checked out.
1009
1009
1010 Output may be to a file, in which case the name of the file is
1010 Output may be to a file, in which case the name of the file is
1011 given using a format string. The formatting rules are the same as
1011 given using a format string. The formatting rules are the same as
1012 for the export command, with the following additions:
1012 for the export command, with the following additions:
1013
1013
1014 :``%s``: basename of file being printed
1014 :``%s``: basename of file being printed
1015 :``%d``: dirname of file being printed, or '.' if in repository root
1015 :``%d``: dirname of file being printed, or '.' if in repository root
1016 :``%p``: root-relative path name of file being printed
1016 :``%p``: root-relative path name of file being printed
1017
1017
1018 Returns 0 on success.
1018 Returns 0 on success.
1019 """
1019 """
1020 ctx = scmutil.revsingle(repo, opts.get('rev'))
1020 ctx = scmutil.revsingle(repo, opts.get('rev'))
1021 err = 1
1021 err = 1
1022 m = scmutil.match(ctx, (file1,) + pats, opts)
1022 m = scmutil.match(ctx, (file1,) + pats, opts)
1023 for abs in ctx.walk(m):
1023 for abs in ctx.walk(m):
1024 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1024 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1025 pathname=abs)
1025 pathname=abs)
1026 data = ctx[abs].data()
1026 data = ctx[abs].data()
1027 if opts.get('decode'):
1027 if opts.get('decode'):
1028 data = repo.wwritedata(abs, data)
1028 data = repo.wwritedata(abs, data)
1029 fp.write(data)
1029 fp.write(data)
1030 fp.close()
1030 fp.close()
1031 err = 0
1031 err = 0
1032 return err
1032 return err
1033
1033
1034 @command('^clone',
1034 @command('^clone',
1035 [('U', 'noupdate', None,
1035 [('U', 'noupdate', None,
1036 _('the clone will include an empty working copy (only a repository)')),
1036 _('the clone will include an empty working copy (only a repository)')),
1037 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1037 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1038 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1038 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1039 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1039 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1040 ('', 'pull', None, _('use pull protocol to copy metadata')),
1040 ('', 'pull', None, _('use pull protocol to copy metadata')),
1041 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1041 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1042 ] + remoteopts,
1042 ] + remoteopts,
1043 _('[OPTION]... SOURCE [DEST]'))
1043 _('[OPTION]... SOURCE [DEST]'))
1044 def clone(ui, source, dest=None, **opts):
1044 def clone(ui, source, dest=None, **opts):
1045 """make a copy of an existing repository
1045 """make a copy of an existing repository
1046
1046
1047 Create a copy of an existing repository in a new directory.
1047 Create a copy of an existing repository in a new directory.
1048
1048
1049 If no destination directory name is specified, it defaults to the
1049 If no destination directory name is specified, it defaults to the
1050 basename of the source.
1050 basename of the source.
1051
1051
1052 The location of the source is added to the new repository's
1052 The location of the source is added to the new repository's
1053 ``.hg/hgrc`` file, as the default to be used for future pulls.
1053 ``.hg/hgrc`` file, as the default to be used for future pulls.
1054
1054
1055 Only local paths and ``ssh://`` URLs are supported as
1055 Only local paths and ``ssh://`` URLs are supported as
1056 destinations. For ``ssh://`` destinations, no working directory or
1056 destinations. For ``ssh://`` destinations, no working directory or
1057 ``.hg/hgrc`` will be created on the remote side.
1057 ``.hg/hgrc`` will be created on the remote side.
1058
1058
1059 To pull only a subset of changesets, specify one or more revisions
1059 To pull only a subset of changesets, specify one or more revisions
1060 identifiers with -r/--rev or branches with -b/--branch. The
1060 identifiers with -r/--rev or branches with -b/--branch. The
1061 resulting clone will contain only the specified changesets and
1061 resulting clone will contain only the specified changesets and
1062 their ancestors. These options (or 'clone src#rev dest') imply
1062 their ancestors. These options (or 'clone src#rev dest') imply
1063 --pull, even for local source repositories. Note that specifying a
1063 --pull, even for local source repositories. Note that specifying a
1064 tag will include the tagged changeset but not the changeset
1064 tag will include the tagged changeset but not the changeset
1065 containing the tag.
1065 containing the tag.
1066
1066
1067 To check out a particular version, use -u/--update, or
1067 To check out a particular version, use -u/--update, or
1068 -U/--noupdate to create a clone with no working directory.
1068 -U/--noupdate to create a clone with no working directory.
1069
1069
1070 .. container:: verbose
1070 .. container:: verbose
1071
1071
1072 For efficiency, hardlinks are used for cloning whenever the
1072 For efficiency, hardlinks are used for cloning whenever the
1073 source and destination are on the same filesystem (note this
1073 source and destination are on the same filesystem (note this
1074 applies only to the repository data, not to the working
1074 applies only to the repository data, not to the working
1075 directory). Some filesystems, such as AFS, implement hardlinking
1075 directory). Some filesystems, such as AFS, implement hardlinking
1076 incorrectly, but do not report errors. In these cases, use the
1076 incorrectly, but do not report errors. In these cases, use the
1077 --pull option to avoid hardlinking.
1077 --pull option to avoid hardlinking.
1078
1078
1079 In some cases, you can clone repositories and the working
1079 In some cases, you can clone repositories and the working
1080 directory using full hardlinks with ::
1080 directory using full hardlinks with ::
1081
1081
1082 $ cp -al REPO REPOCLONE
1082 $ cp -al REPO REPOCLONE
1083
1083
1084 This is the fastest way to clone, but it is not always safe. The
1084 This is the fastest way to clone, but it is not always safe. The
1085 operation is not atomic (making sure REPO is not modified during
1085 operation is not atomic (making sure REPO is not modified during
1086 the operation is up to you) and you have to make sure your
1086 the operation is up to you) and you have to make sure your
1087 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1087 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1088 so). Also, this is not compatible with certain extensions that
1088 so). Also, this is not compatible with certain extensions that
1089 place their metadata under the .hg directory, such as mq.
1089 place their metadata under the .hg directory, such as mq.
1090
1090
1091 Mercurial will update the working directory to the first applicable
1091 Mercurial will update the working directory to the first applicable
1092 revision from this list:
1092 revision from this list:
1093
1093
1094 a) null if -U or the source repository has no changesets
1094 a) null if -U or the source repository has no changesets
1095 b) if -u . and the source repository is local, the first parent of
1095 b) if -u . and the source repository is local, the first parent of
1096 the source repository's working directory
1096 the source repository's working directory
1097 c) the changeset specified with -u (if a branch name, this means the
1097 c) the changeset specified with -u (if a branch name, this means the
1098 latest head of that branch)
1098 latest head of that branch)
1099 d) the changeset specified with -r
1099 d) the changeset specified with -r
1100 e) the tipmost head specified with -b
1100 e) the tipmost head specified with -b
1101 f) the tipmost head specified with the url#branch source syntax
1101 f) the tipmost head specified with the url#branch source syntax
1102 g) the tipmost head of the default branch
1102 g) the tipmost head of the default branch
1103 h) tip
1103 h) tip
1104
1104
1105 Examples:
1105 Examples:
1106
1106
1107 - clone a remote repository to a new directory named hg/::
1107 - clone a remote repository to a new directory named hg/::
1108
1108
1109 hg clone http://selenic.com/hg
1109 hg clone http://selenic.com/hg
1110
1110
1111 - create a lightweight local clone::
1111 - create a lightweight local clone::
1112
1112
1113 hg clone project/ project-feature/
1113 hg clone project/ project-feature/
1114
1114
1115 - clone from an absolute path on an ssh server (note double-slash)::
1115 - clone from an absolute path on an ssh server (note double-slash)::
1116
1116
1117 hg clone ssh://user@server//home/projects/alpha/
1117 hg clone ssh://user@server//home/projects/alpha/
1118
1118
1119 - do a high-speed clone over a LAN while checking out a
1119 - do a high-speed clone over a LAN while checking out a
1120 specified version::
1120 specified version::
1121
1121
1122 hg clone --uncompressed http://server/repo -u 1.5
1122 hg clone --uncompressed http://server/repo -u 1.5
1123
1123
1124 - create a repository without changesets after a particular revision::
1124 - create a repository without changesets after a particular revision::
1125
1125
1126 hg clone -r 04e544 experimental/ good/
1126 hg clone -r 04e544 experimental/ good/
1127
1127
1128 - clone (and track) a particular named branch::
1128 - clone (and track) a particular named branch::
1129
1129
1130 hg clone http://selenic.com/hg#stable
1130 hg clone http://selenic.com/hg#stable
1131
1131
1132 See :hg:`help urls` for details on specifying URLs.
1132 See :hg:`help urls` for details on specifying URLs.
1133
1133
1134 Returns 0 on success.
1134 Returns 0 on success.
1135 """
1135 """
1136 if opts.get('noupdate') and opts.get('updaterev'):
1136 if opts.get('noupdate') and opts.get('updaterev'):
1137 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1137 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1138
1138
1139 r = hg.clone(ui, opts, source, dest,
1139 r = hg.clone(ui, opts, source, dest,
1140 pull=opts.get('pull'),
1140 pull=opts.get('pull'),
1141 stream=opts.get('uncompressed'),
1141 stream=opts.get('uncompressed'),
1142 rev=opts.get('rev'),
1142 rev=opts.get('rev'),
1143 update=opts.get('updaterev') or not opts.get('noupdate'),
1143 update=opts.get('updaterev') or not opts.get('noupdate'),
1144 branch=opts.get('branch'))
1144 branch=opts.get('branch'))
1145
1145
1146 return r is None
1146 return r is None
1147
1147
1148 @command('^commit|ci',
1148 @command('^commit|ci',
1149 [('A', 'addremove', None,
1149 [('A', 'addremove', None,
1150 _('mark new/missing files as added/removed before committing')),
1150 _('mark new/missing files as added/removed before committing')),
1151 ('', 'close-branch', None,
1151 ('', 'close-branch', None,
1152 _('mark a branch as closed, hiding it from the branch list')),
1152 _('mark a branch as closed, hiding it from the branch list')),
1153 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1153 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1154 _('[OPTION]... [FILE]...'))
1154 _('[OPTION]... [FILE]...'))
1155 def commit(ui, repo, *pats, **opts):
1155 def commit(ui, repo, *pats, **opts):
1156 """commit the specified files or all outstanding changes
1156 """commit the specified files or all outstanding changes
1157
1157
1158 Commit changes to the given files into the repository. Unlike a
1158 Commit changes to the given files into the repository. Unlike a
1159 centralized SCM, this operation is a local operation. See
1159 centralized SCM, this operation is a local operation. See
1160 :hg:`push` for a way to actively distribute your changes.
1160 :hg:`push` for a way to actively distribute your changes.
1161
1161
1162 If a list of files is omitted, all changes reported by :hg:`status`
1162 If a list of files is omitted, all changes reported by :hg:`status`
1163 will be committed.
1163 will be committed.
1164
1164
1165 If you are committing the result of a merge, do not provide any
1165 If you are committing the result of a merge, do not provide any
1166 filenames or -I/-X filters.
1166 filenames or -I/-X filters.
1167
1167
1168 If no commit message is specified, Mercurial starts your
1168 If no commit message is specified, Mercurial starts your
1169 configured editor where you can enter a message. In case your
1169 configured editor where you can enter a message. In case your
1170 commit fails, you will find a backup of your message in
1170 commit fails, you will find a backup of your message in
1171 ``.hg/last-message.txt``.
1171 ``.hg/last-message.txt``.
1172
1172
1173 See :hg:`help dates` for a list of formats valid for -d/--date.
1173 See :hg:`help dates` for a list of formats valid for -d/--date.
1174
1174
1175 Returns 0 on success, 1 if nothing changed.
1175 Returns 0 on success, 1 if nothing changed.
1176 """
1176 """
1177 if opts.get('subrepos'):
1177 if opts.get('subrepos'):
1178 # Let --subrepos on the command line overide config setting.
1178 # Let --subrepos on the command line overide config setting.
1179 ui.setconfig('ui', 'commitsubrepos', True)
1179 ui.setconfig('ui', 'commitsubrepos', True)
1180
1180
1181 extra = {}
1181 extra = {}
1182 if opts.get('close_branch'):
1182 if opts.get('close_branch'):
1183 if repo['.'].node() not in repo.branchheads():
1183 if repo['.'].node() not in repo.branchheads():
1184 # The topo heads set is included in the branch heads set of the
1184 # The topo heads set is included in the branch heads set of the
1185 # current branch, so it's sufficient to test branchheads
1185 # current branch, so it's sufficient to test branchheads
1186 raise util.Abort(_('can only close branch heads'))
1186 raise util.Abort(_('can only close branch heads'))
1187 extra['close'] = 1
1187 extra['close'] = 1
1188 e = cmdutil.commiteditor
1188 e = cmdutil.commiteditor
1189 if opts.get('force_editor'):
1189 if opts.get('force_editor'):
1190 e = cmdutil.commitforceeditor
1190 e = cmdutil.commitforceeditor
1191
1191
1192 def commitfunc(ui, repo, message, match, opts):
1192 def commitfunc(ui, repo, message, match, opts):
1193 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1193 return repo.commit(message, opts.get('user'), opts.get('date'), match,
1194 editor=e, extra=extra)
1194 editor=e, extra=extra)
1195
1195
1196 branch = repo[None].branch()
1196 branch = repo[None].branch()
1197 bheads = repo.branchheads(branch)
1197 bheads = repo.branchheads(branch)
1198
1198
1199 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1199 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1200 if not node:
1200 if not node:
1201 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1201 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1202 if stat[3]:
1202 if stat[3]:
1203 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1203 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
1204 % len(stat[3]))
1204 % len(stat[3]))
1205 else:
1205 else:
1206 ui.status(_("nothing changed\n"))
1206 ui.status(_("nothing changed\n"))
1207 return 1
1207 return 1
1208
1208
1209 ctx = repo[node]
1209 ctx = repo[node]
1210 parents = ctx.parents()
1210 parents = ctx.parents()
1211
1211
1212 if (bheads and node not in bheads and not
1212 if (bheads and node not in bheads and not
1213 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1213 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1214 ui.status(_('created new head\n'))
1214 ui.status(_('created new head\n'))
1215 # The message is not printed for initial roots. For the other
1215 # The message is not printed for initial roots. For the other
1216 # changesets, it is printed in the following situations:
1216 # changesets, it is printed in the following situations:
1217 #
1217 #
1218 # Par column: for the 2 parents with ...
1218 # Par column: for the 2 parents with ...
1219 # N: null or no parent
1219 # N: null or no parent
1220 # B: parent is on another named branch
1220 # B: parent is on another named branch
1221 # C: parent is a regular non head changeset
1221 # C: parent is a regular non head changeset
1222 # H: parent was a branch head of the current branch
1222 # H: parent was a branch head of the current branch
1223 # Msg column: whether we print "created new head" message
1223 # Msg column: whether we print "created new head" message
1224 # In the following, it is assumed that there already exists some
1224 # In the following, it is assumed that there already exists some
1225 # initial branch heads of the current branch, otherwise nothing is
1225 # initial branch heads of the current branch, otherwise nothing is
1226 # printed anyway.
1226 # printed anyway.
1227 #
1227 #
1228 # Par Msg Comment
1228 # Par Msg Comment
1229 # NN y additional topo root
1229 # NN y additional topo root
1230 #
1230 #
1231 # BN y additional branch root
1231 # BN y additional branch root
1232 # CN y additional topo head
1232 # CN y additional topo head
1233 # HN n usual case
1233 # HN n usual case
1234 #
1234 #
1235 # BB y weird additional branch root
1235 # BB y weird additional branch root
1236 # CB y branch merge
1236 # CB y branch merge
1237 # HB n merge with named branch
1237 # HB n merge with named branch
1238 #
1238 #
1239 # CC y additional head from merge
1239 # CC y additional head from merge
1240 # CH n merge with a head
1240 # CH n merge with a head
1241 #
1241 #
1242 # HH n head merge: head count decreases
1242 # HH n head merge: head count decreases
1243
1243
1244 if not opts.get('close_branch'):
1244 if not opts.get('close_branch'):
1245 for r in parents:
1245 for r in parents:
1246 if r.extra().get('close') and r.branch() == branch:
1246 if r.extra().get('close') and r.branch() == branch:
1247 ui.status(_('reopening closed branch head %d\n') % r)
1247 ui.status(_('reopening closed branch head %d\n') % r)
1248
1248
1249 if ui.debugflag:
1249 if ui.debugflag:
1250 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1250 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1251 elif ui.verbose:
1251 elif ui.verbose:
1252 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1252 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1253
1253
1254 @command('copy|cp',
1254 @command('copy|cp',
1255 [('A', 'after', None, _('record a copy that has already occurred')),
1255 [('A', 'after', None, _('record a copy that has already occurred')),
1256 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1256 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1257 ] + walkopts + dryrunopts,
1257 ] + walkopts + dryrunopts,
1258 _('[OPTION]... [SOURCE]... DEST'))
1258 _('[OPTION]... [SOURCE]... DEST'))
1259 def copy(ui, repo, *pats, **opts):
1259 def copy(ui, repo, *pats, **opts):
1260 """mark files as copied for the next commit
1260 """mark files as copied for the next commit
1261
1261
1262 Mark dest as having copies of source files. If dest is a
1262 Mark dest as having copies of source files. If dest is a
1263 directory, copies are put in that directory. If dest is a file,
1263 directory, copies are put in that directory. If dest is a file,
1264 the source must be a single file.
1264 the source must be a single file.
1265
1265
1266 By default, this command copies the contents of files as they
1266 By default, this command copies the contents of files as they
1267 exist in the working directory. If invoked with -A/--after, the
1267 exist in the working directory. If invoked with -A/--after, the
1268 operation is recorded, but no copying is performed.
1268 operation is recorded, but no copying is performed.
1269
1269
1270 This command takes effect with the next commit. To undo a copy
1270 This command takes effect with the next commit. To undo a copy
1271 before that, see :hg:`revert`.
1271 before that, see :hg:`revert`.
1272
1272
1273 Returns 0 on success, 1 if errors are encountered.
1273 Returns 0 on success, 1 if errors are encountered.
1274 """
1274 """
1275 wlock = repo.wlock(False)
1275 wlock = repo.wlock(False)
1276 try:
1276 try:
1277 return cmdutil.copy(ui, repo, pats, opts)
1277 return cmdutil.copy(ui, repo, pats, opts)
1278 finally:
1278 finally:
1279 wlock.release()
1279 wlock.release()
1280
1280
1281 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1281 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1282 def debugancestor(ui, repo, *args):
1282 def debugancestor(ui, repo, *args):
1283 """find the ancestor revision of two revisions in a given index"""
1283 """find the ancestor revision of two revisions in a given index"""
1284 if len(args) == 3:
1284 if len(args) == 3:
1285 index, rev1, rev2 = args
1285 index, rev1, rev2 = args
1286 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1286 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1287 lookup = r.lookup
1287 lookup = r.lookup
1288 elif len(args) == 2:
1288 elif len(args) == 2:
1289 if not repo:
1289 if not repo:
1290 raise util.Abort(_("there is no Mercurial repository here "
1290 raise util.Abort(_("there is no Mercurial repository here "
1291 "(.hg not found)"))
1291 "(.hg not found)"))
1292 rev1, rev2 = args
1292 rev1, rev2 = args
1293 r = repo.changelog
1293 r = repo.changelog
1294 lookup = repo.lookup
1294 lookup = repo.lookup
1295 else:
1295 else:
1296 raise util.Abort(_('either two or three arguments required'))
1296 raise util.Abort(_('either two or three arguments required'))
1297 a = r.ancestor(lookup(rev1), lookup(rev2))
1297 a = r.ancestor(lookup(rev1), lookup(rev2))
1298 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1298 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1299
1299
1300 @command('debugbuilddag',
1300 @command('debugbuilddag',
1301 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1301 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1302 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1302 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1303 ('n', 'new-file', None, _('add new file at each rev'))],
1303 ('n', 'new-file', None, _('add new file at each rev'))],
1304 _('[OPTION]... [TEXT]'))
1304 _('[OPTION]... [TEXT]'))
1305 def debugbuilddag(ui, repo, text=None,
1305 def debugbuilddag(ui, repo, text=None,
1306 mergeable_file=False,
1306 mergeable_file=False,
1307 overwritten_file=False,
1307 overwritten_file=False,
1308 new_file=False):
1308 new_file=False):
1309 """builds a repo with a given DAG from scratch in the current empty repo
1309 """builds a repo with a given DAG from scratch in the current empty repo
1310
1310
1311 The description of the DAG is read from stdin if not given on the
1311 The description of the DAG is read from stdin if not given on the
1312 command line.
1312 command line.
1313
1313
1314 Elements:
1314 Elements:
1315
1315
1316 - "+n" is a linear run of n nodes based on the current default parent
1316 - "+n" is a linear run of n nodes based on the current default parent
1317 - "." is a single node based on the current default parent
1317 - "." is a single node based on the current default parent
1318 - "$" resets the default parent to null (implied at the start);
1318 - "$" resets the default parent to null (implied at the start);
1319 otherwise the default parent is always the last node created
1319 otherwise the default parent is always the last node created
1320 - "<p" sets the default parent to the backref p
1320 - "<p" sets the default parent to the backref p
1321 - "*p" is a fork at parent p, which is a backref
1321 - "*p" is a fork at parent p, which is a backref
1322 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1322 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1323 - "/p2" is a merge of the preceding node and p2
1323 - "/p2" is a merge of the preceding node and p2
1324 - ":tag" defines a local tag for the preceding node
1324 - ":tag" defines a local tag for the preceding node
1325 - "@branch" sets the named branch for subsequent nodes
1325 - "@branch" sets the named branch for subsequent nodes
1326 - "#...\\n" is a comment up to the end of the line
1326 - "#...\\n" is a comment up to the end of the line
1327
1327
1328 Whitespace between the above elements is ignored.
1328 Whitespace between the above elements is ignored.
1329
1329
1330 A backref is either
1330 A backref is either
1331
1331
1332 - a number n, which references the node curr-n, where curr is the current
1332 - a number n, which references the node curr-n, where curr is the current
1333 node, or
1333 node, or
1334 - the name of a local tag you placed earlier using ":tag", or
1334 - the name of a local tag you placed earlier using ":tag", or
1335 - empty to denote the default parent.
1335 - empty to denote the default parent.
1336
1336
1337 All string valued-elements are either strictly alphanumeric, or must
1337 All string valued-elements are either strictly alphanumeric, or must
1338 be enclosed in double quotes ("..."), with "\\" as escape character.
1338 be enclosed in double quotes ("..."), with "\\" as escape character.
1339 """
1339 """
1340
1340
1341 if text is None:
1341 if text is None:
1342 ui.status(_("reading DAG from stdin\n"))
1342 ui.status(_("reading DAG from stdin\n"))
1343 text = ui.fin.read()
1343 text = ui.fin.read()
1344
1344
1345 cl = repo.changelog
1345 cl = repo.changelog
1346 if len(cl) > 0:
1346 if len(cl) > 0:
1347 raise util.Abort(_('repository is not empty'))
1347 raise util.Abort(_('repository is not empty'))
1348
1348
1349 # determine number of revs in DAG
1349 # determine number of revs in DAG
1350 total = 0
1350 total = 0
1351 for type, data in dagparser.parsedag(text):
1351 for type, data in dagparser.parsedag(text):
1352 if type == 'n':
1352 if type == 'n':
1353 total += 1
1353 total += 1
1354
1354
1355 if mergeable_file:
1355 if mergeable_file:
1356 linesperrev = 2
1356 linesperrev = 2
1357 # make a file with k lines per rev
1357 # make a file with k lines per rev
1358 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1358 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1359 initialmergedlines.append("")
1359 initialmergedlines.append("")
1360
1360
1361 tags = []
1361 tags = []
1362
1362
1363 tr = repo.transaction("builddag")
1363 tr = repo.transaction("builddag")
1364 try:
1364 try:
1365
1365
1366 at = -1
1366 at = -1
1367 atbranch = 'default'
1367 atbranch = 'default'
1368 nodeids = []
1368 nodeids = []
1369 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1369 ui.progress(_('building'), 0, unit=_('revisions'), total=total)
1370 for type, data in dagparser.parsedag(text):
1370 for type, data in dagparser.parsedag(text):
1371 if type == 'n':
1371 if type == 'n':
1372 ui.note('node %s\n' % str(data))
1372 ui.note('node %s\n' % str(data))
1373 id, ps = data
1373 id, ps = data
1374
1374
1375 files = []
1375 files = []
1376 fctxs = {}
1376 fctxs = {}
1377
1377
1378 p2 = None
1378 p2 = None
1379 if mergeable_file:
1379 if mergeable_file:
1380 fn = "mf"
1380 fn = "mf"
1381 p1 = repo[ps[0]]
1381 p1 = repo[ps[0]]
1382 if len(ps) > 1:
1382 if len(ps) > 1:
1383 p2 = repo[ps[1]]
1383 p2 = repo[ps[1]]
1384 pa = p1.ancestor(p2)
1384 pa = p1.ancestor(p2)
1385 base, local, other = [x[fn].data() for x in pa, p1, p2]
1385 base, local, other = [x[fn].data() for x in pa, p1, p2]
1386 m3 = simplemerge.Merge3Text(base, local, other)
1386 m3 = simplemerge.Merge3Text(base, local, other)
1387 ml = [l.strip() for l in m3.merge_lines()]
1387 ml = [l.strip() for l in m3.merge_lines()]
1388 ml.append("")
1388 ml.append("")
1389 elif at > 0:
1389 elif at > 0:
1390 ml = p1[fn].data().split("\n")
1390 ml = p1[fn].data().split("\n")
1391 else:
1391 else:
1392 ml = initialmergedlines
1392 ml = initialmergedlines
1393 ml[id * linesperrev] += " r%i" % id
1393 ml[id * linesperrev] += " r%i" % id
1394 mergedtext = "\n".join(ml)
1394 mergedtext = "\n".join(ml)
1395 files.append(fn)
1395 files.append(fn)
1396 fctxs[fn] = context.memfilectx(fn, mergedtext)
1396 fctxs[fn] = context.memfilectx(fn, mergedtext)
1397
1397
1398 if overwritten_file:
1398 if overwritten_file:
1399 fn = "of"
1399 fn = "of"
1400 files.append(fn)
1400 files.append(fn)
1401 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1401 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1402
1402
1403 if new_file:
1403 if new_file:
1404 fn = "nf%i" % id
1404 fn = "nf%i" % id
1405 files.append(fn)
1405 files.append(fn)
1406 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1406 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1407 if len(ps) > 1:
1407 if len(ps) > 1:
1408 if not p2:
1408 if not p2:
1409 p2 = repo[ps[1]]
1409 p2 = repo[ps[1]]
1410 for fn in p2:
1410 for fn in p2:
1411 if fn.startswith("nf"):
1411 if fn.startswith("nf"):
1412 files.append(fn)
1412 files.append(fn)
1413 fctxs[fn] = p2[fn]
1413 fctxs[fn] = p2[fn]
1414
1414
1415 def fctxfn(repo, cx, path):
1415 def fctxfn(repo, cx, path):
1416 return fctxs.get(path)
1416 return fctxs.get(path)
1417
1417
1418 if len(ps) == 0 or ps[0] < 0:
1418 if len(ps) == 0 or ps[0] < 0:
1419 pars = [None, None]
1419 pars = [None, None]
1420 elif len(ps) == 1:
1420 elif len(ps) == 1:
1421 pars = [nodeids[ps[0]], None]
1421 pars = [nodeids[ps[0]], None]
1422 else:
1422 else:
1423 pars = [nodeids[p] for p in ps]
1423 pars = [nodeids[p] for p in ps]
1424 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1424 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1425 date=(id, 0),
1425 date=(id, 0),
1426 user="debugbuilddag",
1426 user="debugbuilddag",
1427 extra={'branch': atbranch})
1427 extra={'branch': atbranch})
1428 nodeid = repo.commitctx(cx)
1428 nodeid = repo.commitctx(cx)
1429 nodeids.append(nodeid)
1429 nodeids.append(nodeid)
1430 at = id
1430 at = id
1431 elif type == 'l':
1431 elif type == 'l':
1432 id, name = data
1432 id, name = data
1433 ui.note('tag %s\n' % name)
1433 ui.note('tag %s\n' % name)
1434 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1434 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1435 elif type == 'a':
1435 elif type == 'a':
1436 ui.note('branch %s\n' % data)
1436 ui.note('branch %s\n' % data)
1437 atbranch = data
1437 atbranch = data
1438 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1438 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1439 tr.close()
1439 tr.close()
1440 finally:
1440 finally:
1441 ui.progress(_('building'), None)
1441 ui.progress(_('building'), None)
1442 tr.release()
1442 tr.release()
1443
1443
1444 if tags:
1444 if tags:
1445 repo.opener.write("localtags", "".join(tags))
1445 repo.opener.write("localtags", "".join(tags))
1446
1446
1447 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1447 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1448 def debugbundle(ui, bundlepath, all=None, **opts):
1448 def debugbundle(ui, bundlepath, all=None, **opts):
1449 """lists the contents of a bundle"""
1449 """lists the contents of a bundle"""
1450 f = url.open(ui, bundlepath)
1450 f = url.open(ui, bundlepath)
1451 try:
1451 try:
1452 gen = changegroup.readbundle(f, bundlepath)
1452 gen = changegroup.readbundle(f, bundlepath)
1453 if all:
1453 if all:
1454 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1454 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1455
1455
1456 def showchunks(named):
1456 def showchunks(named):
1457 ui.write("\n%s\n" % named)
1457 ui.write("\n%s\n" % named)
1458 chain = None
1458 chain = None
1459 while True:
1459 while True:
1460 chunkdata = gen.deltachunk(chain)
1460 chunkdata = gen.deltachunk(chain)
1461 if not chunkdata:
1461 if not chunkdata:
1462 break
1462 break
1463 node = chunkdata['node']
1463 node = chunkdata['node']
1464 p1 = chunkdata['p1']
1464 p1 = chunkdata['p1']
1465 p2 = chunkdata['p2']
1465 p2 = chunkdata['p2']
1466 cs = chunkdata['cs']
1466 cs = chunkdata['cs']
1467 deltabase = chunkdata['deltabase']
1467 deltabase = chunkdata['deltabase']
1468 delta = chunkdata['delta']
1468 delta = chunkdata['delta']
1469 ui.write("%s %s %s %s %s %s\n" %
1469 ui.write("%s %s %s %s %s %s\n" %
1470 (hex(node), hex(p1), hex(p2),
1470 (hex(node), hex(p1), hex(p2),
1471 hex(cs), hex(deltabase), len(delta)))
1471 hex(cs), hex(deltabase), len(delta)))
1472 chain = node
1472 chain = node
1473
1473
1474 chunkdata = gen.changelogheader()
1474 chunkdata = gen.changelogheader()
1475 showchunks("changelog")
1475 showchunks("changelog")
1476 chunkdata = gen.manifestheader()
1476 chunkdata = gen.manifestheader()
1477 showchunks("manifest")
1477 showchunks("manifest")
1478 while True:
1478 while True:
1479 chunkdata = gen.filelogheader()
1479 chunkdata = gen.filelogheader()
1480 if not chunkdata:
1480 if not chunkdata:
1481 break
1481 break
1482 fname = chunkdata['filename']
1482 fname = chunkdata['filename']
1483 showchunks(fname)
1483 showchunks(fname)
1484 else:
1484 else:
1485 chunkdata = gen.changelogheader()
1485 chunkdata = gen.changelogheader()
1486 chain = None
1486 chain = None
1487 while True:
1487 while True:
1488 chunkdata = gen.deltachunk(chain)
1488 chunkdata = gen.deltachunk(chain)
1489 if not chunkdata:
1489 if not chunkdata:
1490 break
1490 break
1491 node = chunkdata['node']
1491 node = chunkdata['node']
1492 ui.write("%s\n" % hex(node))
1492 ui.write("%s\n" % hex(node))
1493 chain = node
1493 chain = node
1494 finally:
1494 finally:
1495 f.close()
1495 f.close()
1496
1496
1497 @command('debugcheckstate', [], '')
1497 @command('debugcheckstate', [], '')
1498 def debugcheckstate(ui, repo):
1498 def debugcheckstate(ui, repo):
1499 """validate the correctness of the current dirstate"""
1499 """validate the correctness of the current dirstate"""
1500 parent1, parent2 = repo.dirstate.parents()
1500 parent1, parent2 = repo.dirstate.parents()
1501 m1 = repo[parent1].manifest()
1501 m1 = repo[parent1].manifest()
1502 m2 = repo[parent2].manifest()
1502 m2 = repo[parent2].manifest()
1503 errors = 0
1503 errors = 0
1504 for f in repo.dirstate:
1504 for f in repo.dirstate:
1505 state = repo.dirstate[f]
1505 state = repo.dirstate[f]
1506 if state in "nr" and f not in m1:
1506 if state in "nr" and f not in m1:
1507 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1507 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1508 errors += 1
1508 errors += 1
1509 if state in "a" and f in m1:
1509 if state in "a" and f in m1:
1510 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1510 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1511 errors += 1
1511 errors += 1
1512 if state in "m" and f not in m1 and f not in m2:
1512 if state in "m" and f not in m1 and f not in m2:
1513 ui.warn(_("%s in state %s, but not in either manifest\n") %
1513 ui.warn(_("%s in state %s, but not in either manifest\n") %
1514 (f, state))
1514 (f, state))
1515 errors += 1
1515 errors += 1
1516 for f in m1:
1516 for f in m1:
1517 state = repo.dirstate[f]
1517 state = repo.dirstate[f]
1518 if state not in "nrm":
1518 if state not in "nrm":
1519 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1519 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1520 errors += 1
1520 errors += 1
1521 if errors:
1521 if errors:
1522 error = _(".hg/dirstate inconsistent with current parent's manifest")
1522 error = _(".hg/dirstate inconsistent with current parent's manifest")
1523 raise util.Abort(error)
1523 raise util.Abort(error)
1524
1524
1525 @command('debugcommands', [], _('[COMMAND]'))
1525 @command('debugcommands', [], _('[COMMAND]'))
1526 def debugcommands(ui, cmd='', *args):
1526 def debugcommands(ui, cmd='', *args):
1527 """list all available commands and options"""
1527 """list all available commands and options"""
1528 for cmd, vals in sorted(table.iteritems()):
1528 for cmd, vals in sorted(table.iteritems()):
1529 cmd = cmd.split('|')[0].strip('^')
1529 cmd = cmd.split('|')[0].strip('^')
1530 opts = ', '.join([i[1] for i in vals[1]])
1530 opts = ', '.join([i[1] for i in vals[1]])
1531 ui.write('%s: %s\n' % (cmd, opts))
1531 ui.write('%s: %s\n' % (cmd, opts))
1532
1532
1533 @command('debugcomplete',
1533 @command('debugcomplete',
1534 [('o', 'options', None, _('show the command options'))],
1534 [('o', 'options', None, _('show the command options'))],
1535 _('[-o] CMD'))
1535 _('[-o] CMD'))
1536 def debugcomplete(ui, cmd='', **opts):
1536 def debugcomplete(ui, cmd='', **opts):
1537 """returns the completion list associated with the given command"""
1537 """returns the completion list associated with the given command"""
1538
1538
1539 if opts.get('options'):
1539 if opts.get('options'):
1540 options = []
1540 options = []
1541 otables = [globalopts]
1541 otables = [globalopts]
1542 if cmd:
1542 if cmd:
1543 aliases, entry = cmdutil.findcmd(cmd, table, False)
1543 aliases, entry = cmdutil.findcmd(cmd, table, False)
1544 otables.append(entry[1])
1544 otables.append(entry[1])
1545 for t in otables:
1545 for t in otables:
1546 for o in t:
1546 for o in t:
1547 if "(DEPRECATED)" in o[3]:
1547 if "(DEPRECATED)" in o[3]:
1548 continue
1548 continue
1549 if o[0]:
1549 if o[0]:
1550 options.append('-%s' % o[0])
1550 options.append('-%s' % o[0])
1551 options.append('--%s' % o[1])
1551 options.append('--%s' % o[1])
1552 ui.write("%s\n" % "\n".join(options))
1552 ui.write("%s\n" % "\n".join(options))
1553 return
1553 return
1554
1554
1555 cmdlist = cmdutil.findpossible(cmd, table)
1555 cmdlist = cmdutil.findpossible(cmd, table)
1556 if ui.verbose:
1556 if ui.verbose:
1557 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1557 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1558 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1558 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1559
1559
1560 @command('debugdag',
1560 @command('debugdag',
1561 [('t', 'tags', None, _('use tags as labels')),
1561 [('t', 'tags', None, _('use tags as labels')),
1562 ('b', 'branches', None, _('annotate with branch names')),
1562 ('b', 'branches', None, _('annotate with branch names')),
1563 ('', 'dots', None, _('use dots for runs')),
1563 ('', 'dots', None, _('use dots for runs')),
1564 ('s', 'spaces', None, _('separate elements by spaces'))],
1564 ('s', 'spaces', None, _('separate elements by spaces'))],
1565 _('[OPTION]... [FILE [REV]...]'))
1565 _('[OPTION]... [FILE [REV]...]'))
1566 def debugdag(ui, repo, file_=None, *revs, **opts):
1566 def debugdag(ui, repo, file_=None, *revs, **opts):
1567 """format the changelog or an index DAG as a concise textual description
1567 """format the changelog or an index DAG as a concise textual description
1568
1568
1569 If you pass a revlog index, the revlog's DAG is emitted. If you list
1569 If you pass a revlog index, the revlog's DAG is emitted. If you list
1570 revision numbers, they get labelled in the output as rN.
1570 revision numbers, they get labelled in the output as rN.
1571
1571
1572 Otherwise, the changelog DAG of the current repo is emitted.
1572 Otherwise, the changelog DAG of the current repo is emitted.
1573 """
1573 """
1574 spaces = opts.get('spaces')
1574 spaces = opts.get('spaces')
1575 dots = opts.get('dots')
1575 dots = opts.get('dots')
1576 if file_:
1576 if file_:
1577 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1577 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1578 revs = set((int(r) for r in revs))
1578 revs = set((int(r) for r in revs))
1579 def events():
1579 def events():
1580 for r in rlog:
1580 for r in rlog:
1581 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1581 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1582 if r in revs:
1582 if r in revs:
1583 yield 'l', (r, "r%i" % r)
1583 yield 'l', (r, "r%i" % r)
1584 elif repo:
1584 elif repo:
1585 cl = repo.changelog
1585 cl = repo.changelog
1586 tags = opts.get('tags')
1586 tags = opts.get('tags')
1587 branches = opts.get('branches')
1587 branches = opts.get('branches')
1588 if tags:
1588 if tags:
1589 labels = {}
1589 labels = {}
1590 for l, n in repo.tags().items():
1590 for l, n in repo.tags().items():
1591 labels.setdefault(cl.rev(n), []).append(l)
1591 labels.setdefault(cl.rev(n), []).append(l)
1592 def events():
1592 def events():
1593 b = "default"
1593 b = "default"
1594 for r in cl:
1594 for r in cl:
1595 if branches:
1595 if branches:
1596 newb = cl.read(cl.node(r))[5]['branch']
1596 newb = cl.read(cl.node(r))[5]['branch']
1597 if newb != b:
1597 if newb != b:
1598 yield 'a', newb
1598 yield 'a', newb
1599 b = newb
1599 b = newb
1600 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1600 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1601 if tags:
1601 if tags:
1602 ls = labels.get(r)
1602 ls = labels.get(r)
1603 if ls:
1603 if ls:
1604 for l in ls:
1604 for l in ls:
1605 yield 'l', (r, l)
1605 yield 'l', (r, l)
1606 else:
1606 else:
1607 raise util.Abort(_('need repo for changelog dag'))
1607 raise util.Abort(_('need repo for changelog dag'))
1608
1608
1609 for line in dagparser.dagtextlines(events(),
1609 for line in dagparser.dagtextlines(events(),
1610 addspaces=spaces,
1610 addspaces=spaces,
1611 wraplabels=True,
1611 wraplabels=True,
1612 wrapannotations=True,
1612 wrapannotations=True,
1613 wrapnonlinear=dots,
1613 wrapnonlinear=dots,
1614 usedots=dots,
1614 usedots=dots,
1615 maxlinewidth=70):
1615 maxlinewidth=70):
1616 ui.write(line)
1616 ui.write(line)
1617 ui.write("\n")
1617 ui.write("\n")
1618
1618
1619 @command('debugdata',
1619 @command('debugdata',
1620 [('c', 'changelog', False, _('open changelog')),
1620 [('c', 'changelog', False, _('open changelog')),
1621 ('m', 'manifest', False, _('open manifest'))],
1621 ('m', 'manifest', False, _('open manifest'))],
1622 _('-c|-m|FILE REV'))
1622 _('-c|-m|FILE REV'))
1623 def debugdata(ui, repo, file_, rev = None, **opts):
1623 def debugdata(ui, repo, file_, rev = None, **opts):
1624 """dump the contents of a data file revision"""
1624 """dump the contents of a data file revision"""
1625 if opts.get('changelog') or opts.get('manifest'):
1625 if opts.get('changelog') or opts.get('manifest'):
1626 file_, rev = None, file_
1626 file_, rev = None, file_
1627 elif rev is None:
1627 elif rev is None:
1628 raise error.CommandError('debugdata', _('invalid arguments'))
1628 raise error.CommandError('debugdata', _('invalid arguments'))
1629 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1629 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1630 try:
1630 try:
1631 ui.write(r.revision(r.lookup(rev)))
1631 ui.write(r.revision(r.lookup(rev)))
1632 except KeyError:
1632 except KeyError:
1633 raise util.Abort(_('invalid revision identifier %s') % rev)
1633 raise util.Abort(_('invalid revision identifier %s') % rev)
1634
1634
1635 @command('debugdate',
1635 @command('debugdate',
1636 [('e', 'extended', None, _('try extended date formats'))],
1636 [('e', 'extended', None, _('try extended date formats'))],
1637 _('[-e] DATE [RANGE]'))
1637 _('[-e] DATE [RANGE]'))
1638 def debugdate(ui, date, range=None, **opts):
1638 def debugdate(ui, date, range=None, **opts):
1639 """parse and display a date"""
1639 """parse and display a date"""
1640 if opts["extended"]:
1640 if opts["extended"]:
1641 d = util.parsedate(date, util.extendeddateformats)
1641 d = util.parsedate(date, util.extendeddateformats)
1642 else:
1642 else:
1643 d = util.parsedate(date)
1643 d = util.parsedate(date)
1644 ui.write("internal: %s %s\n" % d)
1644 ui.write("internal: %s %s\n" % d)
1645 ui.write("standard: %s\n" % util.datestr(d))
1645 ui.write("standard: %s\n" % util.datestr(d))
1646 if range:
1646 if range:
1647 m = util.matchdate(range)
1647 m = util.matchdate(range)
1648 ui.write("match: %s\n" % m(d[0]))
1648 ui.write("match: %s\n" % m(d[0]))
1649
1649
1650 @command('debugdiscovery',
1650 @command('debugdiscovery',
1651 [('', 'old', None, _('use old-style discovery')),
1651 [('', 'old', None, _('use old-style discovery')),
1652 ('', 'nonheads', None,
1652 ('', 'nonheads', None,
1653 _('use old-style discovery with non-heads included')),
1653 _('use old-style discovery with non-heads included')),
1654 ] + remoteopts,
1654 ] + remoteopts,
1655 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1655 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1656 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1656 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1657 """runs the changeset discovery protocol in isolation"""
1657 """runs the changeset discovery protocol in isolation"""
1658 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1658 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
1659 remote = hg.peer(repo, opts, remoteurl)
1659 remote = hg.peer(repo, opts, remoteurl)
1660 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1660 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1661
1661
1662 # make sure tests are repeatable
1662 # make sure tests are repeatable
1663 random.seed(12323)
1663 random.seed(12323)
1664
1664
1665 def doit(localheads, remoteheads):
1665 def doit(localheads, remoteheads):
1666 if opts.get('old'):
1666 if opts.get('old'):
1667 if localheads:
1667 if localheads:
1668 raise util.Abort('cannot use localheads with old style discovery')
1668 raise util.Abort('cannot use localheads with old style discovery')
1669 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1669 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1670 force=True)
1670 force=True)
1671 common = set(common)
1671 common = set(common)
1672 if not opts.get('nonheads'):
1672 if not opts.get('nonheads'):
1673 ui.write("unpruned common: %s\n" % " ".join([short(n)
1673 ui.write("unpruned common: %s\n" % " ".join([short(n)
1674 for n in common]))
1674 for n in common]))
1675 dag = dagutil.revlogdag(repo.changelog)
1675 dag = dagutil.revlogdag(repo.changelog)
1676 all = dag.ancestorset(dag.internalizeall(common))
1676 all = dag.ancestorset(dag.internalizeall(common))
1677 common = dag.externalizeall(dag.headsetofconnecteds(all))
1677 common = dag.externalizeall(dag.headsetofconnecteds(all))
1678 else:
1678 else:
1679 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1679 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1680 common = set(common)
1680 common = set(common)
1681 rheads = set(hds)
1681 rheads = set(hds)
1682 lheads = set(repo.heads())
1682 lheads = set(repo.heads())
1683 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1683 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1684 if lheads <= common:
1684 if lheads <= common:
1685 ui.write("local is subset\n")
1685 ui.write("local is subset\n")
1686 elif rheads <= common:
1686 elif rheads <= common:
1687 ui.write("remote is subset\n")
1687 ui.write("remote is subset\n")
1688
1688
1689 serverlogs = opts.get('serverlog')
1689 serverlogs = opts.get('serverlog')
1690 if serverlogs:
1690 if serverlogs:
1691 for filename in serverlogs:
1691 for filename in serverlogs:
1692 logfile = open(filename, 'r')
1692 logfile = open(filename, 'r')
1693 try:
1693 try:
1694 line = logfile.readline()
1694 line = logfile.readline()
1695 while line:
1695 while line:
1696 parts = line.strip().split(';')
1696 parts = line.strip().split(';')
1697 op = parts[1]
1697 op = parts[1]
1698 if op == 'cg':
1698 if op == 'cg':
1699 pass
1699 pass
1700 elif op == 'cgss':
1700 elif op == 'cgss':
1701 doit(parts[2].split(' '), parts[3].split(' '))
1701 doit(parts[2].split(' '), parts[3].split(' '))
1702 elif op == 'unb':
1702 elif op == 'unb':
1703 doit(parts[3].split(' '), parts[2].split(' '))
1703 doit(parts[3].split(' '), parts[2].split(' '))
1704 line = logfile.readline()
1704 line = logfile.readline()
1705 finally:
1705 finally:
1706 logfile.close()
1706 logfile.close()
1707
1707
1708 else:
1708 else:
1709 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1709 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1710 opts.get('remote_head'))
1710 opts.get('remote_head'))
1711 localrevs = opts.get('local_head')
1711 localrevs = opts.get('local_head')
1712 doit(localrevs, remoterevs)
1712 doit(localrevs, remoterevs)
1713
1713
1714 @command('debugfileset', [], ('REVSPEC'))
1714 @command('debugfileset', [], ('REVSPEC'))
1715 def debugfileset(ui, repo, expr):
1715 def debugfileset(ui, repo, expr):
1716 '''parse and apply a fileset specification'''
1716 '''parse and apply a fileset specification'''
1717 if ui.verbose:
1717 if ui.verbose:
1718 tree = fileset.parse(expr)[0]
1718 tree = fileset.parse(expr)[0]
1719 ui.note(tree, "\n")
1719 ui.note(tree, "\n")
1720
1720
1721 for f in fileset.getfileset(repo[None], expr):
1721 for f in fileset.getfileset(repo[None], expr):
1722 ui.write("%s\n" % f)
1722 ui.write("%s\n" % f)
1723
1723
1724 @command('debugfsinfo', [], _('[PATH]'))
1724 @command('debugfsinfo', [], _('[PATH]'))
1725 def debugfsinfo(ui, path = "."):
1725 def debugfsinfo(ui, path = "."):
1726 """show information detected about current filesystem"""
1726 """show information detected about current filesystem"""
1727 util.writefile('.debugfsinfo', '')
1727 util.writefile('.debugfsinfo', '')
1728 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1728 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1729 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1729 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1730 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1730 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1731 and 'yes' or 'no'))
1731 and 'yes' or 'no'))
1732 os.unlink('.debugfsinfo')
1732 os.unlink('.debugfsinfo')
1733
1733
1734 @command('debuggetbundle',
1734 @command('debuggetbundle',
1735 [('H', 'head', [], _('id of head node'), _('ID')),
1735 [('H', 'head', [], _('id of head node'), _('ID')),
1736 ('C', 'common', [], _('id of common node'), _('ID')),
1736 ('C', 'common', [], _('id of common node'), _('ID')),
1737 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1737 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1738 _('REPO FILE [-H|-C ID]...'))
1738 _('REPO FILE [-H|-C ID]...'))
1739 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1739 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1740 """retrieves a bundle from a repo
1740 """retrieves a bundle from a repo
1741
1741
1742 Every ID must be a full-length hex node id string. Saves the bundle to the
1742 Every ID must be a full-length hex node id string. Saves the bundle to the
1743 given file.
1743 given file.
1744 """
1744 """
1745 repo = hg.peer(ui, opts, repopath)
1745 repo = hg.peer(ui, opts, repopath)
1746 if not repo.capable('getbundle'):
1746 if not repo.capable('getbundle'):
1747 raise util.Abort("getbundle() not supported by target repository")
1747 raise util.Abort("getbundle() not supported by target repository")
1748 args = {}
1748 args = {}
1749 if common:
1749 if common:
1750 args['common'] = [bin(s) for s in common]
1750 args['common'] = [bin(s) for s in common]
1751 if head:
1751 if head:
1752 args['heads'] = [bin(s) for s in head]
1752 args['heads'] = [bin(s) for s in head]
1753 bundle = repo.getbundle('debug', **args)
1753 bundle = repo.getbundle('debug', **args)
1754
1754
1755 bundletype = opts.get('type', 'bzip2').lower()
1755 bundletype = opts.get('type', 'bzip2').lower()
1756 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1756 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1757 bundletype = btypes.get(bundletype)
1757 bundletype = btypes.get(bundletype)
1758 if bundletype not in changegroup.bundletypes:
1758 if bundletype not in changegroup.bundletypes:
1759 raise util.Abort(_('unknown bundle type specified with --type'))
1759 raise util.Abort(_('unknown bundle type specified with --type'))
1760 changegroup.writebundle(bundle, bundlepath, bundletype)
1760 changegroup.writebundle(bundle, bundlepath, bundletype)
1761
1761
1762 @command('debugignore', [], '')
1762 @command('debugignore', [], '')
1763 def debugignore(ui, repo, *values, **opts):
1763 def debugignore(ui, repo, *values, **opts):
1764 """display the combined ignore pattern"""
1764 """display the combined ignore pattern"""
1765 ignore = repo.dirstate._ignore
1765 ignore = repo.dirstate._ignore
1766 includepat = getattr(ignore, 'includepat', None)
1766 includepat = getattr(ignore, 'includepat', None)
1767 if includepat is not None:
1767 if includepat is not None:
1768 ui.write("%s\n" % includepat)
1768 ui.write("%s\n" % includepat)
1769 else:
1769 else:
1770 raise util.Abort(_("no ignore patterns found"))
1770 raise util.Abort(_("no ignore patterns found"))
1771
1771
1772 @command('debugindex',
1772 @command('debugindex',
1773 [('c', 'changelog', False, _('open changelog')),
1773 [('c', 'changelog', False, _('open changelog')),
1774 ('m', 'manifest', False, _('open manifest')),
1774 ('m', 'manifest', False, _('open manifest')),
1775 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1775 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1776 _('[-f FORMAT] -c|-m|FILE'))
1776 _('[-f FORMAT] -c|-m|FILE'))
1777 def debugindex(ui, repo, file_ = None, **opts):
1777 def debugindex(ui, repo, file_ = None, **opts):
1778 """dump the contents of an index file"""
1778 """dump the contents of an index file"""
1779 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1779 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1780 format = opts.get('format', 0)
1780 format = opts.get('format', 0)
1781 if format not in (0, 1):
1781 if format not in (0, 1):
1782 raise util.Abort(_("unknown format %d") % format)
1782 raise util.Abort(_("unknown format %d") % format)
1783
1783
1784 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1784 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1785 if generaldelta:
1785 if generaldelta:
1786 basehdr = ' delta'
1786 basehdr = ' delta'
1787 else:
1787 else:
1788 basehdr = ' base'
1788 basehdr = ' base'
1789
1789
1790 if format == 0:
1790 if format == 0:
1791 ui.write(" rev offset length " + basehdr + " linkrev"
1791 ui.write(" rev offset length " + basehdr + " linkrev"
1792 " nodeid p1 p2\n")
1792 " nodeid p1 p2\n")
1793 elif format == 1:
1793 elif format == 1:
1794 ui.write(" rev flag offset length"
1794 ui.write(" rev flag offset length"
1795 " size " + basehdr + " link p1 p2 nodeid\n")
1795 " size " + basehdr + " link p1 p2 nodeid\n")
1796
1796
1797 for i in r:
1797 for i in r:
1798 node = r.node(i)
1798 node = r.node(i)
1799 if generaldelta:
1799 if generaldelta:
1800 base = r.deltaparent(i)
1800 base = r.deltaparent(i)
1801 else:
1801 else:
1802 base = r.chainbase(i)
1802 base = r.chainbase(i)
1803 if format == 0:
1803 if format == 0:
1804 try:
1804 try:
1805 pp = r.parents(node)
1805 pp = r.parents(node)
1806 except:
1806 except:
1807 pp = [nullid, nullid]
1807 pp = [nullid, nullid]
1808 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1808 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1809 i, r.start(i), r.length(i), base, r.linkrev(i),
1809 i, r.start(i), r.length(i), base, r.linkrev(i),
1810 short(node), short(pp[0]), short(pp[1])))
1810 short(node), short(pp[0]), short(pp[1])))
1811 elif format == 1:
1811 elif format == 1:
1812 pr = r.parentrevs(i)
1812 pr = r.parentrevs(i)
1813 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1813 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1814 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1814 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1815 base, r.linkrev(i), pr[0], pr[1], short(node)))
1815 base, r.linkrev(i), pr[0], pr[1], short(node)))
1816
1816
1817 @command('debugindexdot', [], _('FILE'))
1817 @command('debugindexdot', [], _('FILE'))
1818 def debugindexdot(ui, repo, file_):
1818 def debugindexdot(ui, repo, file_):
1819 """dump an index DAG as a graphviz dot file"""
1819 """dump an index DAG as a graphviz dot file"""
1820 r = None
1820 r = None
1821 if repo:
1821 if repo:
1822 filelog = repo.file(file_)
1822 filelog = repo.file(file_)
1823 if len(filelog):
1823 if len(filelog):
1824 r = filelog
1824 r = filelog
1825 if not r:
1825 if not r:
1826 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1826 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1827 ui.write("digraph G {\n")
1827 ui.write("digraph G {\n")
1828 for i in r:
1828 for i in r:
1829 node = r.node(i)
1829 node = r.node(i)
1830 pp = r.parents(node)
1830 pp = r.parents(node)
1831 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1831 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1832 if pp[1] != nullid:
1832 if pp[1] != nullid:
1833 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1833 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1834 ui.write("}\n")
1834 ui.write("}\n")
1835
1835
1836 @command('debuginstall', [], '')
1836 @command('debuginstall', [], '')
1837 def debuginstall(ui):
1837 def debuginstall(ui):
1838 '''test Mercurial installation
1838 '''test Mercurial installation
1839
1839
1840 Returns 0 on success.
1840 Returns 0 on success.
1841 '''
1841 '''
1842
1842
1843 def writetemp(contents):
1843 def writetemp(contents):
1844 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1844 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1845 f = os.fdopen(fd, "wb")
1845 f = os.fdopen(fd, "wb")
1846 f.write(contents)
1846 f.write(contents)
1847 f.close()
1847 f.close()
1848 return name
1848 return name
1849
1849
1850 problems = 0
1850 problems = 0
1851
1851
1852 # encoding
1852 # encoding
1853 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1853 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1854 try:
1854 try:
1855 encoding.fromlocal("test")
1855 encoding.fromlocal("test")
1856 except util.Abort, inst:
1856 except util.Abort, inst:
1857 ui.write(" %s\n" % inst)
1857 ui.write(" %s\n" % inst)
1858 ui.write(_(" (check that your locale is properly set)\n"))
1858 ui.write(_(" (check that your locale is properly set)\n"))
1859 problems += 1
1859 problems += 1
1860
1860
1861 # compiled modules
1861 # compiled modules
1862 ui.status(_("Checking installed modules (%s)...\n")
1862 ui.status(_("Checking installed modules (%s)...\n")
1863 % os.path.dirname(__file__))
1863 % os.path.dirname(__file__))
1864 try:
1864 try:
1865 import bdiff, mpatch, base85, osutil
1865 import bdiff, mpatch, base85, osutil
1866 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1866 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1867 except Exception, inst:
1867 except Exception, inst:
1868 ui.write(" %s\n" % inst)
1868 ui.write(" %s\n" % inst)
1869 ui.write(_(" One or more extensions could not be found"))
1869 ui.write(_(" One or more extensions could not be found"))
1870 ui.write(_(" (check that you compiled the extensions)\n"))
1870 ui.write(_(" (check that you compiled the extensions)\n"))
1871 problems += 1
1871 problems += 1
1872
1872
1873 # templates
1873 # templates
1874 import templater
1874 import templater
1875 p = templater.templatepath()
1875 p = templater.templatepath()
1876 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1876 ui.status(_("Checking templates (%s)...\n") % ' '.join(p))
1877 try:
1877 try:
1878 templater.templater(templater.templatepath("map-cmdline.default"))
1878 templater.templater(templater.templatepath("map-cmdline.default"))
1879 except Exception, inst:
1879 except Exception, inst:
1880 ui.write(" %s\n" % inst)
1880 ui.write(" %s\n" % inst)
1881 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1881 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1882 problems += 1
1882 problems += 1
1883
1883
1884 # editor
1884 # editor
1885 ui.status(_("Checking commit editor...\n"))
1885 ui.status(_("Checking commit editor...\n"))
1886 editor = ui.geteditor()
1886 editor = ui.geteditor()
1887 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1887 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
1888 if not cmdpath:
1888 if not cmdpath:
1889 if editor == 'vi':
1889 if editor == 'vi':
1890 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1890 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1891 ui.write(_(" (specify a commit editor in your configuration"
1891 ui.write(_(" (specify a commit editor in your configuration"
1892 " file)\n"))
1892 " file)\n"))
1893 else:
1893 else:
1894 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1894 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1895 ui.write(_(" (specify a commit editor in your configuration"
1895 ui.write(_(" (specify a commit editor in your configuration"
1896 " file)\n"))
1896 " file)\n"))
1897 problems += 1
1897 problems += 1
1898
1898
1899 # check username
1899 # check username
1900 ui.status(_("Checking username...\n"))
1900 ui.status(_("Checking username...\n"))
1901 try:
1901 try:
1902 ui.username()
1902 ui.username()
1903 except util.Abort, e:
1903 except util.Abort, e:
1904 ui.write(" %s\n" % e)
1904 ui.write(" %s\n" % e)
1905 ui.write(_(" (specify a username in your configuration file)\n"))
1905 ui.write(_(" (specify a username in your configuration file)\n"))
1906 problems += 1
1906 problems += 1
1907
1907
1908 if not problems:
1908 if not problems:
1909 ui.status(_("No problems detected\n"))
1909 ui.status(_("No problems detected\n"))
1910 else:
1910 else:
1911 ui.write(_("%s problems detected,"
1911 ui.write(_("%s problems detected,"
1912 " please check your install!\n") % problems)
1912 " please check your install!\n") % problems)
1913
1913
1914 return problems
1914 return problems
1915
1915
1916 @command('debugknown', [], _('REPO ID...'))
1916 @command('debugknown', [], _('REPO ID...'))
1917 def debugknown(ui, repopath, *ids, **opts):
1917 def debugknown(ui, repopath, *ids, **opts):
1918 """test whether node ids are known to a repo
1918 """test whether node ids are known to a repo
1919
1919
1920 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1920 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1921 indicating unknown/known.
1921 indicating unknown/known.
1922 """
1922 """
1923 repo = hg.peer(ui, opts, repopath)
1923 repo = hg.peer(ui, opts, repopath)
1924 if not repo.capable('known'):
1924 if not repo.capable('known'):
1925 raise util.Abort("known() not supported by target repository")
1925 raise util.Abort("known() not supported by target repository")
1926 flags = repo.known([bin(s) for s in ids])
1926 flags = repo.known([bin(s) for s in ids])
1927 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1927 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1928
1928
1929 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1929 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
1930 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1930 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1931 '''access the pushkey key/value protocol
1931 '''access the pushkey key/value protocol
1932
1932
1933 With two args, list the keys in the given namespace.
1933 With two args, list the keys in the given namespace.
1934
1934
1935 With five args, set a key to new if it currently is set to old.
1935 With five args, set a key to new if it currently is set to old.
1936 Reports success or failure.
1936 Reports success or failure.
1937 '''
1937 '''
1938
1938
1939 target = hg.peer(ui, {}, repopath)
1939 target = hg.peer(ui, {}, repopath)
1940 if keyinfo:
1940 if keyinfo:
1941 key, old, new = keyinfo
1941 key, old, new = keyinfo
1942 r = target.pushkey(namespace, key, old, new)
1942 r = target.pushkey(namespace, key, old, new)
1943 ui.status(str(r) + '\n')
1943 ui.status(str(r) + '\n')
1944 return not r
1944 return not r
1945 else:
1945 else:
1946 for k, v in target.listkeys(namespace).iteritems():
1946 for k, v in target.listkeys(namespace).iteritems():
1947 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1947 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1948 v.encode('string-escape')))
1948 v.encode('string-escape')))
1949
1949
1950 @command('debugrebuildstate',
1950 @command('debugrebuildstate',
1951 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1951 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
1952 _('[-r REV] [REV]'))
1952 _('[-r REV] [REV]'))
1953 def debugrebuildstate(ui, repo, rev="tip"):
1953 def debugrebuildstate(ui, repo, rev="tip"):
1954 """rebuild the dirstate as it would look like for the given revision"""
1954 """rebuild the dirstate as it would look like for the given revision"""
1955 ctx = scmutil.revsingle(repo, rev)
1955 ctx = scmutil.revsingle(repo, rev)
1956 wlock = repo.wlock()
1956 wlock = repo.wlock()
1957 try:
1957 try:
1958 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1958 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1959 finally:
1959 finally:
1960 wlock.release()
1960 wlock.release()
1961
1961
1962 @command('debugrename',
1962 @command('debugrename',
1963 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1963 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1964 _('[-r REV] FILE'))
1964 _('[-r REV] FILE'))
1965 def debugrename(ui, repo, file1, *pats, **opts):
1965 def debugrename(ui, repo, file1, *pats, **opts):
1966 """dump rename information"""
1966 """dump rename information"""
1967
1967
1968 ctx = scmutil.revsingle(repo, opts.get('rev'))
1968 ctx = scmutil.revsingle(repo, opts.get('rev'))
1969 m = scmutil.match(ctx, (file1,) + pats, opts)
1969 m = scmutil.match(ctx, (file1,) + pats, opts)
1970 for abs in ctx.walk(m):
1970 for abs in ctx.walk(m):
1971 fctx = ctx[abs]
1971 fctx = ctx[abs]
1972 o = fctx.filelog().renamed(fctx.filenode())
1972 o = fctx.filelog().renamed(fctx.filenode())
1973 rel = m.rel(abs)
1973 rel = m.rel(abs)
1974 if o:
1974 if o:
1975 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1975 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1976 else:
1976 else:
1977 ui.write(_("%s not renamed\n") % rel)
1977 ui.write(_("%s not renamed\n") % rel)
1978
1978
1979 @command('debugrevlog',
1979 @command('debugrevlog',
1980 [('c', 'changelog', False, _('open changelog')),
1980 [('c', 'changelog', False, _('open changelog')),
1981 ('m', 'manifest', False, _('open manifest')),
1981 ('m', 'manifest', False, _('open manifest')),
1982 ('d', 'dump', False, _('dump index data'))],
1982 ('d', 'dump', False, _('dump index data'))],
1983 _('-c|-m|FILE'))
1983 _('-c|-m|FILE'))
1984 def debugrevlog(ui, repo, file_ = None, **opts):
1984 def debugrevlog(ui, repo, file_ = None, **opts):
1985 """show data and statistics about a revlog"""
1985 """show data and statistics about a revlog"""
1986 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1986 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1987
1987
1988 if opts.get("dump"):
1988 if opts.get("dump"):
1989 numrevs = len(r)
1989 numrevs = len(r)
1990 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1990 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
1991 " rawsize totalsize compression heads\n")
1991 " rawsize totalsize compression heads\n")
1992 ts = 0
1992 ts = 0
1993 heads = set()
1993 heads = set()
1994 for rev in xrange(numrevs):
1994 for rev in xrange(numrevs):
1995 dbase = r.deltaparent(rev)
1995 dbase = r.deltaparent(rev)
1996 if dbase == -1:
1996 if dbase == -1:
1997 dbase = rev
1997 dbase = rev
1998 cbase = r.chainbase(rev)
1998 cbase = r.chainbase(rev)
1999 p1, p2 = r.parentrevs(rev)
1999 p1, p2 = r.parentrevs(rev)
2000 rs = r.rawsize(rev)
2000 rs = r.rawsize(rev)
2001 ts = ts + rs
2001 ts = ts + rs
2002 heads -= set(r.parentrevs(rev))
2002 heads -= set(r.parentrevs(rev))
2003 heads.add(rev)
2003 heads.add(rev)
2004 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2004 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2005 (rev, p1, p2, r.start(rev), r.end(rev),
2005 (rev, p1, p2, r.start(rev), r.end(rev),
2006 r.start(dbase), r.start(cbase),
2006 r.start(dbase), r.start(cbase),
2007 r.start(p1), r.start(p2),
2007 r.start(p1), r.start(p2),
2008 rs, ts, ts / r.end(rev), len(heads)))
2008 rs, ts, ts / r.end(rev), len(heads)))
2009 return 0
2009 return 0
2010
2010
2011 v = r.version
2011 v = r.version
2012 format = v & 0xFFFF
2012 format = v & 0xFFFF
2013 flags = []
2013 flags = []
2014 gdelta = False
2014 gdelta = False
2015 if v & revlog.REVLOGNGINLINEDATA:
2015 if v & revlog.REVLOGNGINLINEDATA:
2016 flags.append('inline')
2016 flags.append('inline')
2017 if v & revlog.REVLOGGENERALDELTA:
2017 if v & revlog.REVLOGGENERALDELTA:
2018 gdelta = True
2018 gdelta = True
2019 flags.append('generaldelta')
2019 flags.append('generaldelta')
2020 if not flags:
2020 if not flags:
2021 flags = ['(none)']
2021 flags = ['(none)']
2022
2022
2023 nummerges = 0
2023 nummerges = 0
2024 numfull = 0
2024 numfull = 0
2025 numprev = 0
2025 numprev = 0
2026 nump1 = 0
2026 nump1 = 0
2027 nump2 = 0
2027 nump2 = 0
2028 numother = 0
2028 numother = 0
2029 nump1prev = 0
2029 nump1prev = 0
2030 nump2prev = 0
2030 nump2prev = 0
2031 chainlengths = []
2031 chainlengths = []
2032
2032
2033 datasize = [None, 0, 0L]
2033 datasize = [None, 0, 0L]
2034 fullsize = [None, 0, 0L]
2034 fullsize = [None, 0, 0L]
2035 deltasize = [None, 0, 0L]
2035 deltasize = [None, 0, 0L]
2036
2036
2037 def addsize(size, l):
2037 def addsize(size, l):
2038 if l[0] is None or size < l[0]:
2038 if l[0] is None or size < l[0]:
2039 l[0] = size
2039 l[0] = size
2040 if size > l[1]:
2040 if size > l[1]:
2041 l[1] = size
2041 l[1] = size
2042 l[2] += size
2042 l[2] += size
2043
2043
2044 numrevs = len(r)
2044 numrevs = len(r)
2045 for rev in xrange(numrevs):
2045 for rev in xrange(numrevs):
2046 p1, p2 = r.parentrevs(rev)
2046 p1, p2 = r.parentrevs(rev)
2047 delta = r.deltaparent(rev)
2047 delta = r.deltaparent(rev)
2048 if format > 0:
2048 if format > 0:
2049 addsize(r.rawsize(rev), datasize)
2049 addsize(r.rawsize(rev), datasize)
2050 if p2 != nullrev:
2050 if p2 != nullrev:
2051 nummerges += 1
2051 nummerges += 1
2052 size = r.length(rev)
2052 size = r.length(rev)
2053 if delta == nullrev:
2053 if delta == nullrev:
2054 chainlengths.append(0)
2054 chainlengths.append(0)
2055 numfull += 1
2055 numfull += 1
2056 addsize(size, fullsize)
2056 addsize(size, fullsize)
2057 else:
2057 else:
2058 chainlengths.append(chainlengths[delta] + 1)
2058 chainlengths.append(chainlengths[delta] + 1)
2059 addsize(size, deltasize)
2059 addsize(size, deltasize)
2060 if delta == rev - 1:
2060 if delta == rev - 1:
2061 numprev += 1
2061 numprev += 1
2062 if delta == p1:
2062 if delta == p1:
2063 nump1prev += 1
2063 nump1prev += 1
2064 elif delta == p2:
2064 elif delta == p2:
2065 nump2prev += 1
2065 nump2prev += 1
2066 elif delta == p1:
2066 elif delta == p1:
2067 nump1 += 1
2067 nump1 += 1
2068 elif delta == p2:
2068 elif delta == p2:
2069 nump2 += 1
2069 nump2 += 1
2070 elif delta != nullrev:
2070 elif delta != nullrev:
2071 numother += 1
2071 numother += 1
2072
2072
2073 numdeltas = numrevs - numfull
2073 numdeltas = numrevs - numfull
2074 numoprev = numprev - nump1prev - nump2prev
2074 numoprev = numprev - nump1prev - nump2prev
2075 totalrawsize = datasize[2]
2075 totalrawsize = datasize[2]
2076 datasize[2] /= numrevs
2076 datasize[2] /= numrevs
2077 fulltotal = fullsize[2]
2077 fulltotal = fullsize[2]
2078 fullsize[2] /= numfull
2078 fullsize[2] /= numfull
2079 deltatotal = deltasize[2]
2079 deltatotal = deltasize[2]
2080 deltasize[2] /= numrevs - numfull
2080 deltasize[2] /= numrevs - numfull
2081 totalsize = fulltotal + deltatotal
2081 totalsize = fulltotal + deltatotal
2082 avgchainlen = sum(chainlengths) / numrevs
2082 avgchainlen = sum(chainlengths) / numrevs
2083 compratio = totalrawsize / totalsize
2083 compratio = totalrawsize / totalsize
2084
2084
2085 basedfmtstr = '%%%dd\n'
2085 basedfmtstr = '%%%dd\n'
2086 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2086 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2087
2087
2088 def dfmtstr(max):
2088 def dfmtstr(max):
2089 return basedfmtstr % len(str(max))
2089 return basedfmtstr % len(str(max))
2090 def pcfmtstr(max, padding=0):
2090 def pcfmtstr(max, padding=0):
2091 return basepcfmtstr % (len(str(max)), ' ' * padding)
2091 return basepcfmtstr % (len(str(max)), ' ' * padding)
2092
2092
2093 def pcfmt(value, total):
2093 def pcfmt(value, total):
2094 return (value, 100 * float(value) / total)
2094 return (value, 100 * float(value) / total)
2095
2095
2096 ui.write('format : %d\n' % format)
2096 ui.write('format : %d\n' % format)
2097 ui.write('flags : %s\n' % ', '.join(flags))
2097 ui.write('flags : %s\n' % ', '.join(flags))
2098
2098
2099 ui.write('\n')
2099 ui.write('\n')
2100 fmt = pcfmtstr(totalsize)
2100 fmt = pcfmtstr(totalsize)
2101 fmt2 = dfmtstr(totalsize)
2101 fmt2 = dfmtstr(totalsize)
2102 ui.write('revisions : ' + fmt2 % numrevs)
2102 ui.write('revisions : ' + fmt2 % numrevs)
2103 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2103 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2104 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2104 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2105 ui.write('revisions : ' + fmt2 % numrevs)
2105 ui.write('revisions : ' + fmt2 % numrevs)
2106 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2106 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2107 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2107 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2108 ui.write('revision size : ' + fmt2 % totalsize)
2108 ui.write('revision size : ' + fmt2 % totalsize)
2109 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2109 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2110 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2110 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2111
2111
2112 ui.write('\n')
2112 ui.write('\n')
2113 fmt = dfmtstr(max(avgchainlen, compratio))
2113 fmt = dfmtstr(max(avgchainlen, compratio))
2114 ui.write('avg chain length : ' + fmt % avgchainlen)
2114 ui.write('avg chain length : ' + fmt % avgchainlen)
2115 ui.write('compression ratio : ' + fmt % compratio)
2115 ui.write('compression ratio : ' + fmt % compratio)
2116
2116
2117 if format > 0:
2117 if format > 0:
2118 ui.write('\n')
2118 ui.write('\n')
2119 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2119 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2120 % tuple(datasize))
2120 % tuple(datasize))
2121 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2121 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2122 % tuple(fullsize))
2122 % tuple(fullsize))
2123 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2123 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2124 % tuple(deltasize))
2124 % tuple(deltasize))
2125
2125
2126 if numdeltas > 0:
2126 if numdeltas > 0:
2127 ui.write('\n')
2127 ui.write('\n')
2128 fmt = pcfmtstr(numdeltas)
2128 fmt = pcfmtstr(numdeltas)
2129 fmt2 = pcfmtstr(numdeltas, 4)
2129 fmt2 = pcfmtstr(numdeltas, 4)
2130 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2130 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2131 if numprev > 0:
2131 if numprev > 0:
2132 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2132 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev))
2133 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2133 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev))
2134 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2134 ui.write(' other : ' + fmt2 % pcfmt(numoprev, numprev))
2135 if gdelta:
2135 if gdelta:
2136 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2136 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2137 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2137 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2138 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2138 ui.write('deltas against other : ' + fmt % pcfmt(numother, numdeltas))
2139
2139
2140 @command('debugrevspec', [], ('REVSPEC'))
2140 @command('debugrevspec', [], ('REVSPEC'))
2141 def debugrevspec(ui, repo, expr):
2141 def debugrevspec(ui, repo, expr):
2142 '''parse and apply a revision specification'''
2142 '''parse and apply a revision specification'''
2143 if ui.verbose:
2143 if ui.verbose:
2144 tree = revset.parse(expr)[0]
2144 tree = revset.parse(expr)[0]
2145 ui.note(tree, "\n")
2145 ui.note(tree, "\n")
2146 newtree = revset.findaliases(ui, tree)
2146 newtree = revset.findaliases(ui, tree)
2147 if newtree != tree:
2147 if newtree != tree:
2148 ui.note(newtree, "\n")
2148 ui.note(newtree, "\n")
2149 func = revset.match(ui, expr)
2149 func = revset.match(ui, expr)
2150 for c in func(repo, range(len(repo))):
2150 for c in func(repo, range(len(repo))):
2151 ui.write("%s\n" % c)
2151 ui.write("%s\n" % c)
2152
2152
2153 @command('debugsetparents', [], _('REV1 [REV2]'))
2153 @command('debugsetparents', [], _('REV1 [REV2]'))
2154 def debugsetparents(ui, repo, rev1, rev2=None):
2154 def debugsetparents(ui, repo, rev1, rev2=None):
2155 """manually set the parents of the current working directory
2155 """manually set the parents of the current working directory
2156
2156
2157 This is useful for writing repository conversion tools, but should
2157 This is useful for writing repository conversion tools, but should
2158 be used with care.
2158 be used with care.
2159
2159
2160 Returns 0 on success.
2160 Returns 0 on success.
2161 """
2161 """
2162
2162
2163 r1 = scmutil.revsingle(repo, rev1).node()
2163 r1 = scmutil.revsingle(repo, rev1).node()
2164 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2164 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2165
2165
2166 wlock = repo.wlock()
2166 wlock = repo.wlock()
2167 try:
2167 try:
2168 repo.dirstate.setparents(r1, r2)
2168 repo.dirstate.setparents(r1, r2)
2169 finally:
2169 finally:
2170 wlock.release()
2170 wlock.release()
2171
2171
2172 @command('debugstate',
2172 @command('debugstate',
2173 [('', 'nodates', None, _('do not display the saved mtime')),
2173 [('', 'nodates', None, _('do not display the saved mtime')),
2174 ('', 'datesort', None, _('sort by saved mtime'))],
2174 ('', 'datesort', None, _('sort by saved mtime'))],
2175 _('[OPTION]...'))
2175 _('[OPTION]...'))
2176 def debugstate(ui, repo, nodates=None, datesort=None):
2176 def debugstate(ui, repo, nodates=None, datesort=None):
2177 """show the contents of the current dirstate"""
2177 """show the contents of the current dirstate"""
2178 timestr = ""
2178 timestr = ""
2179 showdate = not nodates
2179 showdate = not nodates
2180 if datesort:
2180 if datesort:
2181 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2181 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2182 else:
2182 else:
2183 keyfunc = None # sort by filename
2183 keyfunc = None # sort by filename
2184 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2184 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2185 if showdate:
2185 if showdate:
2186 if ent[3] == -1:
2186 if ent[3] == -1:
2187 # Pad or slice to locale representation
2187 # Pad or slice to locale representation
2188 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2188 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2189 time.localtime(0)))
2189 time.localtime(0)))
2190 timestr = 'unset'
2190 timestr = 'unset'
2191 timestr = (timestr[:locale_len] +
2191 timestr = (timestr[:locale_len] +
2192 ' ' * (locale_len - len(timestr)))
2192 ' ' * (locale_len - len(timestr)))
2193 else:
2193 else:
2194 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2194 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2195 time.localtime(ent[3]))
2195 time.localtime(ent[3]))
2196 if ent[1] & 020000:
2196 if ent[1] & 020000:
2197 mode = 'lnk'
2197 mode = 'lnk'
2198 else:
2198 else:
2199 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2199 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2200 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2200 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2201 for f in repo.dirstate.copies():
2201 for f in repo.dirstate.copies():
2202 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2202 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2203
2203
2204 @command('debugsub',
2204 @command('debugsub',
2205 [('r', 'rev', '',
2205 [('r', 'rev', '',
2206 _('revision to check'), _('REV'))],
2206 _('revision to check'), _('REV'))],
2207 _('[-r REV] [REV]'))
2207 _('[-r REV] [REV]'))
2208 def debugsub(ui, repo, rev=None):
2208 def debugsub(ui, repo, rev=None):
2209 ctx = scmutil.revsingle(repo, rev, None)
2209 ctx = scmutil.revsingle(repo, rev, None)
2210 for k, v in sorted(ctx.substate.items()):
2210 for k, v in sorted(ctx.substate.items()):
2211 ui.write('path %s\n' % k)
2211 ui.write('path %s\n' % k)
2212 ui.write(' source %s\n' % v[0])
2212 ui.write(' source %s\n' % v[0])
2213 ui.write(' revision %s\n' % v[1])
2213 ui.write(' revision %s\n' % v[1])
2214
2214
2215 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2215 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2216 def debugwalk(ui, repo, *pats, **opts):
2216 def debugwalk(ui, repo, *pats, **opts):
2217 """show how files match on given patterns"""
2217 """show how files match on given patterns"""
2218 m = scmutil.match(repo[None], pats, opts)
2218 m = scmutil.match(repo[None], pats, opts)
2219 items = list(repo.walk(m))
2219 items = list(repo.walk(m))
2220 if not items:
2220 if not items:
2221 return
2221 return
2222 fmt = 'f %%-%ds %%-%ds %%s' % (
2222 fmt = 'f %%-%ds %%-%ds %%s' % (
2223 max([len(abs) for abs in items]),
2223 max([len(abs) for abs in items]),
2224 max([len(m.rel(abs)) for abs in items]))
2224 max([len(m.rel(abs)) for abs in items]))
2225 for abs in items:
2225 for abs in items:
2226 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2226 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
2227 ui.write("%s\n" % line.rstrip())
2227 ui.write("%s\n" % line.rstrip())
2228
2228
2229 @command('debugwireargs',
2229 @command('debugwireargs',
2230 [('', 'three', '', 'three'),
2230 [('', 'three', '', 'three'),
2231 ('', 'four', '', 'four'),
2231 ('', 'four', '', 'four'),
2232 ('', 'five', '', 'five'),
2232 ('', 'five', '', 'five'),
2233 ] + remoteopts,
2233 ] + remoteopts,
2234 _('REPO [OPTIONS]... [ONE [TWO]]'))
2234 _('REPO [OPTIONS]... [ONE [TWO]]'))
2235 def debugwireargs(ui, repopath, *vals, **opts):
2235 def debugwireargs(ui, repopath, *vals, **opts):
2236 repo = hg.peer(ui, opts, repopath)
2236 repo = hg.peer(ui, opts, repopath)
2237 for opt in remoteopts:
2237 for opt in remoteopts:
2238 del opts[opt[1]]
2238 del opts[opt[1]]
2239 args = {}
2239 args = {}
2240 for k, v in opts.iteritems():
2240 for k, v in opts.iteritems():
2241 if v:
2241 if v:
2242 args[k] = v
2242 args[k] = v
2243 # run twice to check that we don't mess up the stream for the next command
2243 # run twice to check that we don't mess up the stream for the next command
2244 res1 = repo.debugwireargs(*vals, **args)
2244 res1 = repo.debugwireargs(*vals, **args)
2245 res2 = repo.debugwireargs(*vals, **args)
2245 res2 = repo.debugwireargs(*vals, **args)
2246 ui.write("%s\n" % res1)
2246 ui.write("%s\n" % res1)
2247 if res1 != res2:
2247 if res1 != res2:
2248 ui.warn("%s\n" % res2)
2248 ui.warn("%s\n" % res2)
2249
2249
2250 @command('^diff',
2250 @command('^diff',
2251 [('r', 'rev', [], _('revision'), _('REV')),
2251 [('r', 'rev', [], _('revision'), _('REV')),
2252 ('c', 'change', '', _('change made by revision'), _('REV'))
2252 ('c', 'change', '', _('change made by revision'), _('REV'))
2253 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2253 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2254 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2254 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2255 def diff(ui, repo, *pats, **opts):
2255 def diff(ui, repo, *pats, **opts):
2256 """diff repository (or selected files)
2256 """diff repository (or selected files)
2257
2257
2258 Show differences between revisions for the specified files.
2258 Show differences between revisions for the specified files.
2259
2259
2260 Differences between files are shown using the unified diff format.
2260 Differences between files are shown using the unified diff format.
2261
2261
2262 .. note::
2262 .. note::
2263 diff may generate unexpected results for merges, as it will
2263 diff may generate unexpected results for merges, as it will
2264 default to comparing against the working directory's first
2264 default to comparing against the working directory's first
2265 parent changeset if no revisions are specified.
2265 parent changeset if no revisions are specified.
2266
2266
2267 When two revision arguments are given, then changes are shown
2267 When two revision arguments are given, then changes are shown
2268 between those revisions. If only one revision is specified then
2268 between those revisions. If only one revision is specified then
2269 that revision is compared to the working directory, and, when no
2269 that revision is compared to the working directory, and, when no
2270 revisions are specified, the working directory files are compared
2270 revisions are specified, the working directory files are compared
2271 to its parent.
2271 to its parent.
2272
2272
2273 Alternatively you can specify -c/--change with a revision to see
2273 Alternatively you can specify -c/--change with a revision to see
2274 the changes in that changeset relative to its first parent.
2274 the changes in that changeset relative to its first parent.
2275
2275
2276 Without the -a/--text option, diff will avoid generating diffs of
2276 Without the -a/--text option, diff will avoid generating diffs of
2277 files it detects as binary. With -a, diff will generate a diff
2277 files it detects as binary. With -a, diff will generate a diff
2278 anyway, probably with undesirable results.
2278 anyway, probably with undesirable results.
2279
2279
2280 Use the -g/--git option to generate diffs in the git extended diff
2280 Use the -g/--git option to generate diffs in the git extended diff
2281 format. For more information, read :hg:`help diffs`.
2281 format. For more information, read :hg:`help diffs`.
2282
2282
2283 .. container:: verbose
2283 .. container:: verbose
2284
2284
2285 Examples:
2285 Examples:
2286
2286
2287 - compare a file in the current working directory to its parent::
2287 - compare a file in the current working directory to its parent::
2288
2288
2289 hg diff foo.c
2289 hg diff foo.c
2290
2290
2291 - compare two historical versions of a directory, with rename info::
2291 - compare two historical versions of a directory, with rename info::
2292
2292
2293 hg diff --git -r 1.0:1.2 lib/
2293 hg diff --git -r 1.0:1.2 lib/
2294
2294
2295 - get change stats relative to the last change on some date::
2295 - get change stats relative to the last change on some date::
2296
2296
2297 hg diff --stat -r "date('may 2')"
2297 hg diff --stat -r "date('may 2')"
2298
2298
2299 - diff all newly-added files that contain a keyword::
2299 - diff all newly-added files that contain a keyword::
2300
2300
2301 hg diff "set:added() and grep(GNU)"
2301 hg diff "set:added() and grep(GNU)"
2302
2302
2303 - compare a revision and its parents::
2303 - compare a revision and its parents::
2304
2304
2305 hg diff -c 9353 # compare against first parent
2305 hg diff -c 9353 # compare against first parent
2306 hg diff -r 9353^:9353 # same using revset syntax
2306 hg diff -r 9353^:9353 # same using revset syntax
2307 hg diff -r 9353^2:9353 # compare against the second parent
2307 hg diff -r 9353^2:9353 # compare against the second parent
2308
2308
2309 Returns 0 on success.
2309 Returns 0 on success.
2310 """
2310 """
2311
2311
2312 revs = opts.get('rev')
2312 revs = opts.get('rev')
2313 change = opts.get('change')
2313 change = opts.get('change')
2314 stat = opts.get('stat')
2314 stat = opts.get('stat')
2315 reverse = opts.get('reverse')
2315 reverse = opts.get('reverse')
2316
2316
2317 if revs and change:
2317 if revs and change:
2318 msg = _('cannot specify --rev and --change at the same time')
2318 msg = _('cannot specify --rev and --change at the same time')
2319 raise util.Abort(msg)
2319 raise util.Abort(msg)
2320 elif change:
2320 elif change:
2321 node2 = scmutil.revsingle(repo, change, None).node()
2321 node2 = scmutil.revsingle(repo, change, None).node()
2322 node1 = repo[node2].p1().node()
2322 node1 = repo[node2].p1().node()
2323 else:
2323 else:
2324 node1, node2 = scmutil.revpair(repo, revs)
2324 node1, node2 = scmutil.revpair(repo, revs)
2325
2325
2326 if reverse:
2326 if reverse:
2327 node1, node2 = node2, node1
2327 node1, node2 = node2, node1
2328
2328
2329 diffopts = patch.diffopts(ui, opts)
2329 diffopts = patch.diffopts(ui, opts)
2330 m = scmutil.match(repo[node2], pats, opts)
2330 m = scmutil.match(repo[node2], pats, opts)
2331 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2331 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2332 listsubrepos=opts.get('subrepos'))
2332 listsubrepos=opts.get('subrepos'))
2333
2333
2334 @command('^export',
2334 @command('^export',
2335 [('o', 'output', '',
2335 [('o', 'output', '',
2336 _('print output to file with formatted name'), _('FORMAT')),
2336 _('print output to file with formatted name'), _('FORMAT')),
2337 ('', 'switch-parent', None, _('diff against the second parent')),
2337 ('', 'switch-parent', None, _('diff against the second parent')),
2338 ('r', 'rev', [], _('revisions to export'), _('REV')),
2338 ('r', 'rev', [], _('revisions to export'), _('REV')),
2339 ] + diffopts,
2339 ] + diffopts,
2340 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2340 _('[OPTION]... [-o OUTFILESPEC] REV...'))
2341 def export(ui, repo, *changesets, **opts):
2341 def export(ui, repo, *changesets, **opts):
2342 """dump the header and diffs for one or more changesets
2342 """dump the header and diffs for one or more changesets
2343
2343
2344 Print the changeset header and diffs for one or more revisions.
2344 Print the changeset header and diffs for one or more revisions.
2345
2345
2346 The information shown in the changeset header is: author, date,
2346 The information shown in the changeset header is: author, date,
2347 branch name (if non-default), changeset hash, parent(s) and commit
2347 branch name (if non-default), changeset hash, parent(s) and commit
2348 comment.
2348 comment.
2349
2349
2350 .. note::
2350 .. note::
2351 export may generate unexpected diff output for merge
2351 export may generate unexpected diff output for merge
2352 changesets, as it will compare the merge changeset against its
2352 changesets, as it will compare the merge changeset against its
2353 first parent only.
2353 first parent only.
2354
2354
2355 Output may be to a file, in which case the name of the file is
2355 Output may be to a file, in which case the name of the file is
2356 given using a format string. The formatting rules are as follows:
2356 given using a format string. The formatting rules are as follows:
2357
2357
2358 :``%%``: literal "%" character
2358 :``%%``: literal "%" character
2359 :``%H``: changeset hash (40 hexadecimal digits)
2359 :``%H``: changeset hash (40 hexadecimal digits)
2360 :``%N``: number of patches being generated
2360 :``%N``: number of patches being generated
2361 :``%R``: changeset revision number
2361 :``%R``: changeset revision number
2362 :``%b``: basename of the exporting repository
2362 :``%b``: basename of the exporting repository
2363 :``%h``: short-form changeset hash (12 hexadecimal digits)
2363 :``%h``: short-form changeset hash (12 hexadecimal digits)
2364 :``%m``: first line of the commit message (only alphanumeric characters)
2364 :``%m``: first line of the commit message (only alphanumeric characters)
2365 :``%n``: zero-padded sequence number, starting at 1
2365 :``%n``: zero-padded sequence number, starting at 1
2366 :``%r``: zero-padded changeset revision number
2366 :``%r``: zero-padded changeset revision number
2367
2367
2368 Without the -a/--text option, export will avoid generating diffs
2368 Without the -a/--text option, export will avoid generating diffs
2369 of files it detects as binary. With -a, export will generate a
2369 of files it detects as binary. With -a, export will generate a
2370 diff anyway, probably with undesirable results.
2370 diff anyway, probably with undesirable results.
2371
2371
2372 Use the -g/--git option to generate diffs in the git extended diff
2372 Use the -g/--git option to generate diffs in the git extended diff
2373 format. See :hg:`help diffs` for more information.
2373 format. See :hg:`help diffs` for more information.
2374
2374
2375 With the --switch-parent option, the diff will be against the
2375 With the --switch-parent option, the diff will be against the
2376 second parent. It can be useful to review a merge.
2376 second parent. It can be useful to review a merge.
2377
2377
2378 .. container:: verbose
2378 .. container:: verbose
2379
2379
2380 Examples:
2380 Examples:
2381
2381
2382 - use export and import to transplant a bugfix to the current
2382 - use export and import to transplant a bugfix to the current
2383 branch::
2383 branch::
2384
2384
2385 hg export -r 9353 | hg import -
2385 hg export -r 9353 | hg import -
2386
2386
2387 - export all the changesets between two revisions to a file with
2387 - export all the changesets between two revisions to a file with
2388 rename information::
2388 rename information::
2389
2389
2390 hg export --git -r 123:150 > changes.txt
2390 hg export --git -r 123:150 > changes.txt
2391
2391
2392 - split outgoing changes into a series of patches with
2392 - split outgoing changes into a series of patches with
2393 descriptive names::
2393 descriptive names::
2394
2394
2395 hg export -r "outgoing()" -o "%n-%m.patch"
2395 hg export -r "outgoing()" -o "%n-%m.patch"
2396
2396
2397 Returns 0 on success.
2397 Returns 0 on success.
2398 """
2398 """
2399 changesets += tuple(opts.get('rev', []))
2399 changesets += tuple(opts.get('rev', []))
2400 if not changesets:
2400 if not changesets:
2401 raise util.Abort(_("export requires at least one changeset"))
2401 raise util.Abort(_("export requires at least one changeset"))
2402 revs = scmutil.revrange(repo, changesets)
2402 revs = scmutil.revrange(repo, changesets)
2403 if len(revs) > 1:
2403 if len(revs) > 1:
2404 ui.note(_('exporting patches:\n'))
2404 ui.note(_('exporting patches:\n'))
2405 else:
2405 else:
2406 ui.note(_('exporting patch:\n'))
2406 ui.note(_('exporting patch:\n'))
2407 cmdutil.export(repo, revs, template=opts.get('output'),
2407 cmdutil.export(repo, revs, template=opts.get('output'),
2408 switch_parent=opts.get('switch_parent'),
2408 switch_parent=opts.get('switch_parent'),
2409 opts=patch.diffopts(ui, opts))
2409 opts=patch.diffopts(ui, opts))
2410
2410
2411 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2411 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2412 def forget(ui, repo, *pats, **opts):
2412 def forget(ui, repo, *pats, **opts):
2413 """forget the specified files on the next commit
2413 """forget the specified files on the next commit
2414
2414
2415 Mark the specified files so they will no longer be tracked
2415 Mark the specified files so they will no longer be tracked
2416 after the next commit.
2416 after the next commit.
2417
2417
2418 This only removes files from the current branch, not from the
2418 This only removes files from the current branch, not from the
2419 entire project history, and it does not delete them from the
2419 entire project history, and it does not delete them from the
2420 working directory.
2420 working directory.
2421
2421
2422 To undo a forget before the next commit, see :hg:`add`.
2422 To undo a forget before the next commit, see :hg:`add`.
2423
2423
2424 .. container:: verbose
2424 .. container:: verbose
2425
2425
2426 Examples:
2426 Examples:
2427
2427
2428 - forget newly-added binary files::
2428 - forget newly-added binary files::
2429
2429
2430 hg forget "set:added() and binary()"
2430 hg forget "set:added() and binary()"
2431
2431
2432 - forget files that would be excluded by .hgignore::
2432 - forget files that would be excluded by .hgignore::
2433
2433
2434 hg forget "set:hgignore()"
2434 hg forget "set:hgignore()"
2435
2435
2436 Returns 0 on success.
2436 Returns 0 on success.
2437 """
2437 """
2438
2438
2439 if not pats:
2439 if not pats:
2440 raise util.Abort(_('no files specified'))
2440 raise util.Abort(_('no files specified'))
2441
2441
2442 wctx = repo[None]
2442 wctx = repo[None]
2443 m = scmutil.match(wctx, pats, opts)
2443 m = scmutil.match(wctx, pats, opts)
2444 s = repo.status(match=m, clean=True)
2444 s = repo.status(match=m, clean=True)
2445 forget = sorted(s[0] + s[1] + s[3] + s[6])
2445 forget = sorted(s[0] + s[1] + s[3] + s[6])
2446 subforget = {}
2446 subforget = {}
2447 errs = 0
2447 errs = 0
2448
2448
2449 for subpath in wctx.substate:
2449 for subpath in wctx.substate:
2450 sub = wctx.sub(subpath)
2450 sub = wctx.sub(subpath)
2451 try:
2451 try:
2452 submatch = matchmod.narrowmatcher(subpath, m)
2452 submatch = matchmod.narrowmatcher(subpath, m)
2453 for fsub in sub.walk(submatch):
2453 for fsub in sub.walk(submatch):
2454 if submatch.exact(fsub):
2454 if submatch.exact(fsub):
2455 subforget[subpath + '/' + fsub] = (fsub, sub)
2455 subforget[subpath + '/' + fsub] = (fsub, sub)
2456 except error.LookupError:
2456 except error.LookupError:
2457 ui.status(_("skipping missing subrepository: %s\n") % subpath)
2457 ui.status(_("skipping missing subrepository: %s\n") % subpath)
2458
2458
2459 for f in m.files():
2459 for f in m.files():
2460 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2460 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
2461 if f not in subforget:
2461 if f not in subforget:
2462 if os.path.exists(m.rel(f)):
2462 if os.path.exists(m.rel(f)):
2463 ui.warn(_('not removing %s: file is already untracked\n')
2463 ui.warn(_('not removing %s: file is already untracked\n')
2464 % m.rel(f))
2464 % m.rel(f))
2465 errs = 1
2465 errs = 1
2466
2466
2467 for f in forget:
2467 for f in forget:
2468 if ui.verbose or not m.exact(f):
2468 if ui.verbose or not m.exact(f):
2469 ui.status(_('removing %s\n') % m.rel(f))
2469 ui.status(_('removing %s\n') % m.rel(f))
2470
2470
2471 if ui.verbose:
2471 if ui.verbose:
2472 for f in sorted(subforget.keys()):
2472 for f in sorted(subforget.keys()):
2473 ui.status(_('removing %s\n') % m.rel(f))
2473 ui.status(_('removing %s\n') % m.rel(f))
2474
2474
2475 wctx.forget(forget)
2475 wctx.forget(forget)
2476
2476
2477 for f in sorted(subforget.keys()):
2477 for f in sorted(subforget.keys()):
2478 fsub, sub = subforget[f]
2478 fsub, sub = subforget[f]
2479 sub.forget([fsub])
2479 sub.forget([fsub])
2480
2480
2481 return errs
2481 return errs
2482
2482
2483 @command(
2483 @command(
2484 'graft',
2484 'graft',
2485 [('c', 'continue', False, _('resume interrupted graft')),
2485 [('c', 'continue', False, _('resume interrupted graft')),
2486 ('e', 'edit', False, _('invoke editor on commit messages')),
2486 ('e', 'edit', False, _('invoke editor on commit messages')),
2487 ('D', 'currentdate', False,
2487 ('D', 'currentdate', False,
2488 _('record the current date as commit date')),
2488 _('record the current date as commit date')),
2489 ('U', 'currentuser', False,
2489 ('U', 'currentuser', False,
2490 _('record the current user as committer'), _('DATE'))]
2490 _('record the current user as committer'), _('DATE'))]
2491 + commitopts2 + mergetoolopts,
2491 + commitopts2 + mergetoolopts,
2492 _('[OPTION]... REVISION...'))
2492 _('[OPTION]... REVISION...'))
2493 def graft(ui, repo, *revs, **opts):
2493 def graft(ui, repo, *revs, **opts):
2494 '''copy changes from other branches onto the current branch
2494 '''copy changes from other branches onto the current branch
2495
2495
2496 This command uses Mercurial's merge logic to copy individual
2496 This command uses Mercurial's merge logic to copy individual
2497 changes from other branches without merging branches in the
2497 changes from other branches without merging branches in the
2498 history graph. This is sometimes known as 'backporting' or
2498 history graph. This is sometimes known as 'backporting' or
2499 'cherry-picking'. By default, graft will copy user, date, and
2499 'cherry-picking'. By default, graft will copy user, date, and
2500 description from the source changesets.
2500 description from the source changesets.
2501
2501
2502 Changesets that are ancestors of the current revision, that have
2502 Changesets that are ancestors of the current revision, that have
2503 already been grafted, or that are merges will be skipped.
2503 already been grafted, or that are merges will be skipped.
2504
2504
2505 If a graft merge results in conflicts, the graft process is
2505 If a graft merge results in conflicts, the graft process is
2506 aborted so that the current merge can be manually resolved. Once
2506 aborted so that the current merge can be manually resolved. Once
2507 all conflicts are addressed, the graft process can be continued
2507 all conflicts are addressed, the graft process can be continued
2508 with the -c/--continue option.
2508 with the -c/--continue option.
2509
2509
2510 .. note::
2510 .. note::
2511 The -c/--continue option does not reapply earlier options.
2511 The -c/--continue option does not reapply earlier options.
2512
2512
2513 .. container:: verbose
2513 .. container:: verbose
2514
2514
2515 Examples:
2515 Examples:
2516
2516
2517 - copy a single change to the stable branch and edit its description::
2517 - copy a single change to the stable branch and edit its description::
2518
2518
2519 hg update stable
2519 hg update stable
2520 hg graft --edit 9393
2520 hg graft --edit 9393
2521
2521
2522 - graft a range of changesets with one exception, updating dates::
2522 - graft a range of changesets with one exception, updating dates::
2523
2523
2524 hg graft -D "2085::2093 and not 2091"
2524 hg graft -D "2085::2093 and not 2091"
2525
2525
2526 - continue a graft after resolving conflicts::
2526 - continue a graft after resolving conflicts::
2527
2527
2528 hg graft -c
2528 hg graft -c
2529
2529
2530 - show the source of a grafted changeset::
2530 - show the source of a grafted changeset::
2531
2531
2532 hg log --debug -r tip
2532 hg log --debug -r tip
2533
2533
2534 Returns 0 on successful completion.
2534 Returns 0 on successful completion.
2535 '''
2535 '''
2536
2536
2537 if not opts.get('user') and opts.get('currentuser'):
2537 if not opts.get('user') and opts.get('currentuser'):
2538 opts['user'] = ui.username()
2538 opts['user'] = ui.username()
2539 if not opts.get('date') and opts.get('currentdate'):
2539 if not opts.get('date') and opts.get('currentdate'):
2540 opts['date'] = "%d %d" % util.makedate()
2540 opts['date'] = "%d %d" % util.makedate()
2541
2541
2542 editor = None
2542 editor = None
2543 if opts.get('edit'):
2543 if opts.get('edit'):
2544 editor = cmdutil.commitforceeditor
2544 editor = cmdutil.commitforceeditor
2545
2545
2546 cont = False
2546 cont = False
2547 if opts['continue']:
2547 if opts['continue']:
2548 cont = True
2548 cont = True
2549 if revs:
2549 if revs:
2550 raise util.Abort(_("can't specify --continue and revisions"))
2550 raise util.Abort(_("can't specify --continue and revisions"))
2551 # read in unfinished revisions
2551 # read in unfinished revisions
2552 try:
2552 try:
2553 nodes = repo.opener.read('graftstate').splitlines()
2553 nodes = repo.opener.read('graftstate').splitlines()
2554 revs = [repo[node].rev() for node in nodes]
2554 revs = [repo[node].rev() for node in nodes]
2555 except IOError, inst:
2555 except IOError, inst:
2556 if inst.errno != errno.ENOENT:
2556 if inst.errno != errno.ENOENT:
2557 raise
2557 raise
2558 raise util.Abort(_("no graft state found, can't continue"))
2558 raise util.Abort(_("no graft state found, can't continue"))
2559 else:
2559 else:
2560 cmdutil.bailifchanged(repo)
2560 cmdutil.bailifchanged(repo)
2561 if not revs:
2561 if not revs:
2562 raise util.Abort(_('no revisions specified'))
2562 raise util.Abort(_('no revisions specified'))
2563 revs = scmutil.revrange(repo, revs)
2563 revs = scmutil.revrange(repo, revs)
2564
2564
2565 # check for merges
2565 # check for merges
2566 for rev in repo.revs('%ld and merge()', revs):
2566 for rev in repo.revs('%ld and merge()', revs):
2567 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2567 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2568 revs.remove(rev)
2568 revs.remove(rev)
2569 if not revs:
2569 if not revs:
2570 return -1
2570 return -1
2571
2571
2572 # check for ancestors of dest branch
2572 # check for ancestors of dest branch
2573 for rev in repo.revs('::. and %ld', revs):
2573 for rev in repo.revs('::. and %ld', revs):
2574 ui.warn(_('skipping ancestor revision %s\n') % rev)
2574 ui.warn(_('skipping ancestor revision %s\n') % rev)
2575 revs.remove(rev)
2575 revs.remove(rev)
2576 if not revs:
2576 if not revs:
2577 return -1
2577 return -1
2578
2578
2579 # analyze revs for earlier grafts
2579 # analyze revs for earlier grafts
2580 ids = {}
2580 ids = {}
2581 for ctx in repo.set("%ld", revs):
2581 for ctx in repo.set("%ld", revs):
2582 ids[ctx.hex()] = ctx.rev()
2582 ids[ctx.hex()] = ctx.rev()
2583 n = ctx.extra().get('source')
2583 n = ctx.extra().get('source')
2584 if n:
2584 if n:
2585 ids[n] = ctx.rev()
2585 ids[n] = ctx.rev()
2586
2586
2587 # check ancestors for earlier grafts
2587 # check ancestors for earlier grafts
2588 ui.debug('scanning for duplicate grafts\n')
2588 ui.debug('scanning for duplicate grafts\n')
2589 for ctx in repo.set("::. - ::%ld", revs):
2589 for ctx in repo.set("::. - ::%ld", revs):
2590 n = ctx.extra().get('source')
2590 n = ctx.extra().get('source')
2591 if n in ids:
2591 if n in ids:
2592 r = repo[n].rev()
2592 r = repo[n].rev()
2593 if r in revs:
2593 if r in revs:
2594 ui.warn(_('skipping already grafted revision %s\n') % r)
2594 ui.warn(_('skipping already grafted revision %s\n') % r)
2595 revs.remove(r)
2595 revs.remove(r)
2596 elif ids[n] in revs:
2596 elif ids[n] in revs:
2597 ui.warn(_('skipping already grafted revision %s '
2597 ui.warn(_('skipping already grafted revision %s '
2598 '(same origin %d)\n') % (ids[n], r))
2598 '(same origin %d)\n') % (ids[n], r))
2599 revs.remove(ids[n])
2599 revs.remove(ids[n])
2600 elif ctx.hex() in ids:
2600 elif ctx.hex() in ids:
2601 r = ids[ctx.hex()]
2601 r = ids[ctx.hex()]
2602 ui.warn(_('skipping already grafted revision %s '
2602 ui.warn(_('skipping already grafted revision %s '
2603 '(was grafted from %d)\n') % (r, ctx.rev()))
2603 '(was grafted from %d)\n') % (r, ctx.rev()))
2604 revs.remove(r)
2604 revs.remove(r)
2605 if not revs:
2605 if not revs:
2606 return -1
2606 return -1
2607
2607
2608 for pos, ctx in enumerate(repo.set("%ld", revs)):
2608 for pos, ctx in enumerate(repo.set("%ld", revs)):
2609 current = repo['.']
2609 current = repo['.']
2610 ui.status(_('grafting revision %s\n') % ctx.rev())
2610 ui.status(_('grafting revision %s\n') % ctx.rev())
2611
2611
2612 # we don't merge the first commit when continuing
2612 # we don't merge the first commit when continuing
2613 if not cont:
2613 if not cont:
2614 # perform the graft merge with p1(rev) as 'ancestor'
2614 # perform the graft merge with p1(rev) as 'ancestor'
2615 try:
2615 try:
2616 # ui.forcemerge is an internal variable, do not document
2616 # ui.forcemerge is an internal variable, do not document
2617 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2617 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2618 stats = mergemod.update(repo, ctx.node(), True, True, False,
2618 stats = mergemod.update(repo, ctx.node(), True, True, False,
2619 ctx.p1().node())
2619 ctx.p1().node())
2620 finally:
2620 finally:
2621 ui.setconfig('ui', 'forcemerge', '')
2621 ui.setconfig('ui', 'forcemerge', '')
2622 # drop the second merge parent
2622 # drop the second merge parent
2623 repo.dirstate.setparents(current.node(), nullid)
2623 repo.dirstate.setparents(current.node(), nullid)
2624 repo.dirstate.write()
2624 repo.dirstate.write()
2625 # fix up dirstate for copies and renames
2625 # fix up dirstate for copies and renames
2626 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2626 cmdutil.duplicatecopies(repo, ctx.rev(), current.node(), nullid)
2627 # report any conflicts
2627 # report any conflicts
2628 if stats and stats[3] > 0:
2628 if stats and stats[3] > 0:
2629 # write out state for --continue
2629 # write out state for --continue
2630 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2630 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2631 repo.opener.write('graftstate', ''.join(nodelines))
2631 repo.opener.write('graftstate', ''.join(nodelines))
2632 raise util.Abort(
2632 raise util.Abort(
2633 _("unresolved conflicts, can't continue"),
2633 _("unresolved conflicts, can't continue"),
2634 hint=_('use hg resolve and hg graft --continue'))
2634 hint=_('use hg resolve and hg graft --continue'))
2635 else:
2635 else:
2636 cont = False
2636 cont = False
2637
2637
2638 # commit
2638 # commit
2639 source = ctx.extra().get('source')
2639 source = ctx.extra().get('source')
2640 if not source:
2640 if not source:
2641 source = ctx.hex()
2641 source = ctx.hex()
2642 extra = {'source': source}
2642 extra = {'source': source}
2643 user = ctx.user()
2643 user = ctx.user()
2644 if opts.get('user'):
2644 if opts.get('user'):
2645 user = opts['user']
2645 user = opts['user']
2646 date = ctx.date()
2646 date = ctx.date()
2647 if opts.get('date'):
2647 if opts.get('date'):
2648 date = opts['date']
2648 date = opts['date']
2649 repo.commit(text=ctx.description(), user=user,
2649 repo.commit(text=ctx.description(), user=user,
2650 date=date, extra=extra, editor=editor)
2650 date=date, extra=extra, editor=editor)
2651
2651
2652 # remove state when we complete successfully
2652 # remove state when we complete successfully
2653 if os.path.exists(repo.join('graftstate')):
2653 if os.path.exists(repo.join('graftstate')):
2654 util.unlinkpath(repo.join('graftstate'))
2654 util.unlinkpath(repo.join('graftstate'))
2655
2655
2656 return 0
2656 return 0
2657
2657
2658 @command('grep',
2658 @command('grep',
2659 [('0', 'print0', None, _('end fields with NUL')),
2659 [('0', 'print0', None, _('end fields with NUL')),
2660 ('', 'all', None, _('print all revisions that match')),
2660 ('', 'all', None, _('print all revisions that match')),
2661 ('a', 'text', None, _('treat all files as text')),
2661 ('a', 'text', None, _('treat all files as text')),
2662 ('f', 'follow', None,
2662 ('f', 'follow', None,
2663 _('follow changeset history,'
2663 _('follow changeset history,'
2664 ' or file history across copies and renames')),
2664 ' or file history across copies and renames')),
2665 ('i', 'ignore-case', None, _('ignore case when matching')),
2665 ('i', 'ignore-case', None, _('ignore case when matching')),
2666 ('l', 'files-with-matches', None,
2666 ('l', 'files-with-matches', None,
2667 _('print only filenames and revisions that match')),
2667 _('print only filenames and revisions that match')),
2668 ('n', 'line-number', None, _('print matching line numbers')),
2668 ('n', 'line-number', None, _('print matching line numbers')),
2669 ('r', 'rev', [],
2669 ('r', 'rev', [],
2670 _('only search files changed within revision range'), _('REV')),
2670 _('only search files changed within revision range'), _('REV')),
2671 ('u', 'user', None, _('list the author (long with -v)')),
2671 ('u', 'user', None, _('list the author (long with -v)')),
2672 ('d', 'date', None, _('list the date (short with -q)')),
2672 ('d', 'date', None, _('list the date (short with -q)')),
2673 ] + walkopts,
2673 ] + walkopts,
2674 _('[OPTION]... PATTERN [FILE]...'))
2674 _('[OPTION]... PATTERN [FILE]...'))
2675 def grep(ui, repo, pattern, *pats, **opts):
2675 def grep(ui, repo, pattern, *pats, **opts):
2676 """search for a pattern in specified files and revisions
2676 """search for a pattern in specified files and revisions
2677
2677
2678 Search revisions of files for a regular expression.
2678 Search revisions of files for a regular expression.
2679
2679
2680 This command behaves differently than Unix grep. It only accepts
2680 This command behaves differently than Unix grep. It only accepts
2681 Python/Perl regexps. It searches repository history, not the
2681 Python/Perl regexps. It searches repository history, not the
2682 working directory. It always prints the revision number in which a
2682 working directory. It always prints the revision number in which a
2683 match appears.
2683 match appears.
2684
2684
2685 By default, grep only prints output for the first revision of a
2685 By default, grep only prints output for the first revision of a
2686 file in which it finds a match. To get it to print every revision
2686 file in which it finds a match. To get it to print every revision
2687 that contains a change in match status ("-" for a match that
2687 that contains a change in match status ("-" for a match that
2688 becomes a non-match, or "+" for a non-match that becomes a match),
2688 becomes a non-match, or "+" for a non-match that becomes a match),
2689 use the --all flag.
2689 use the --all flag.
2690
2690
2691 Returns 0 if a match is found, 1 otherwise.
2691 Returns 0 if a match is found, 1 otherwise.
2692 """
2692 """
2693 reflags = 0
2693 reflags = 0
2694 if opts.get('ignore_case'):
2694 if opts.get('ignore_case'):
2695 reflags |= re.I
2695 reflags |= re.I
2696 try:
2696 try:
2697 regexp = re.compile(pattern, reflags)
2697 regexp = re.compile(pattern, reflags)
2698 except re.error, inst:
2698 except re.error, inst:
2699 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2699 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2700 return 1
2700 return 1
2701 sep, eol = ':', '\n'
2701 sep, eol = ':', '\n'
2702 if opts.get('print0'):
2702 if opts.get('print0'):
2703 sep = eol = '\0'
2703 sep = eol = '\0'
2704
2704
2705 getfile = util.lrucachefunc(repo.file)
2705 getfile = util.lrucachefunc(repo.file)
2706
2706
2707 def matchlines(body):
2707 def matchlines(body):
2708 begin = 0
2708 begin = 0
2709 linenum = 0
2709 linenum = 0
2710 while True:
2710 while True:
2711 match = regexp.search(body, begin)
2711 match = regexp.search(body, begin)
2712 if not match:
2712 if not match:
2713 break
2713 break
2714 mstart, mend = match.span()
2714 mstart, mend = match.span()
2715 linenum += body.count('\n', begin, mstart) + 1
2715 linenum += body.count('\n', begin, mstart) + 1
2716 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2716 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2717 begin = body.find('\n', mend) + 1 or len(body) + 1
2717 begin = body.find('\n', mend) + 1 or len(body) + 1
2718 lend = begin - 1
2718 lend = begin - 1
2719 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2719 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2720
2720
2721 class linestate(object):
2721 class linestate(object):
2722 def __init__(self, line, linenum, colstart, colend):
2722 def __init__(self, line, linenum, colstart, colend):
2723 self.line = line
2723 self.line = line
2724 self.linenum = linenum
2724 self.linenum = linenum
2725 self.colstart = colstart
2725 self.colstart = colstart
2726 self.colend = colend
2726 self.colend = colend
2727
2727
2728 def __hash__(self):
2728 def __hash__(self):
2729 return hash((self.linenum, self.line))
2729 return hash((self.linenum, self.line))
2730
2730
2731 def __eq__(self, other):
2731 def __eq__(self, other):
2732 return self.line == other.line
2732 return self.line == other.line
2733
2733
2734 matches = {}
2734 matches = {}
2735 copies = {}
2735 copies = {}
2736 def grepbody(fn, rev, body):
2736 def grepbody(fn, rev, body):
2737 matches[rev].setdefault(fn, [])
2737 matches[rev].setdefault(fn, [])
2738 m = matches[rev][fn]
2738 m = matches[rev][fn]
2739 for lnum, cstart, cend, line in matchlines(body):
2739 for lnum, cstart, cend, line in matchlines(body):
2740 s = linestate(line, lnum, cstart, cend)
2740 s = linestate(line, lnum, cstart, cend)
2741 m.append(s)
2741 m.append(s)
2742
2742
2743 def difflinestates(a, b):
2743 def difflinestates(a, b):
2744 sm = difflib.SequenceMatcher(None, a, b)
2744 sm = difflib.SequenceMatcher(None, a, b)
2745 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2745 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2746 if tag == 'insert':
2746 if tag == 'insert':
2747 for i in xrange(blo, bhi):
2747 for i in xrange(blo, bhi):
2748 yield ('+', b[i])
2748 yield ('+', b[i])
2749 elif tag == 'delete':
2749 elif tag == 'delete':
2750 for i in xrange(alo, ahi):
2750 for i in xrange(alo, ahi):
2751 yield ('-', a[i])
2751 yield ('-', a[i])
2752 elif tag == 'replace':
2752 elif tag == 'replace':
2753 for i in xrange(alo, ahi):
2753 for i in xrange(alo, ahi):
2754 yield ('-', a[i])
2754 yield ('-', a[i])
2755 for i in xrange(blo, bhi):
2755 for i in xrange(blo, bhi):
2756 yield ('+', b[i])
2756 yield ('+', b[i])
2757
2757
2758 def display(fn, ctx, pstates, states):
2758 def display(fn, ctx, pstates, states):
2759 rev = ctx.rev()
2759 rev = ctx.rev()
2760 datefunc = ui.quiet and util.shortdate or util.datestr
2760 datefunc = ui.quiet and util.shortdate or util.datestr
2761 found = False
2761 found = False
2762 filerevmatches = {}
2762 filerevmatches = {}
2763 def binary():
2763 def binary():
2764 flog = getfile(fn)
2764 flog = getfile(fn)
2765 return util.binary(flog.read(ctx.filenode(fn)))
2765 return util.binary(flog.read(ctx.filenode(fn)))
2766
2766
2767 if opts.get('all'):
2767 if opts.get('all'):
2768 iter = difflinestates(pstates, states)
2768 iter = difflinestates(pstates, states)
2769 else:
2769 else:
2770 iter = [('', l) for l in states]
2770 iter = [('', l) for l in states]
2771 for change, l in iter:
2771 for change, l in iter:
2772 cols = [fn, str(rev)]
2772 cols = [fn, str(rev)]
2773 before, match, after = None, None, None
2773 before, match, after = None, None, None
2774 if opts.get('line_number'):
2774 if opts.get('line_number'):
2775 cols.append(str(l.linenum))
2775 cols.append(str(l.linenum))
2776 if opts.get('all'):
2776 if opts.get('all'):
2777 cols.append(change)
2777 cols.append(change)
2778 if opts.get('user'):
2778 if opts.get('user'):
2779 cols.append(ui.shortuser(ctx.user()))
2779 cols.append(ui.shortuser(ctx.user()))
2780 if opts.get('date'):
2780 if opts.get('date'):
2781 cols.append(datefunc(ctx.date()))
2781 cols.append(datefunc(ctx.date()))
2782 if opts.get('files_with_matches'):
2782 if opts.get('files_with_matches'):
2783 c = (fn, rev)
2783 c = (fn, rev)
2784 if c in filerevmatches:
2784 if c in filerevmatches:
2785 continue
2785 continue
2786 filerevmatches[c] = 1
2786 filerevmatches[c] = 1
2787 else:
2787 else:
2788 before = l.line[:l.colstart]
2788 before = l.line[:l.colstart]
2789 match = l.line[l.colstart:l.colend]
2789 match = l.line[l.colstart:l.colend]
2790 after = l.line[l.colend:]
2790 after = l.line[l.colend:]
2791 ui.write(sep.join(cols))
2791 ui.write(sep.join(cols))
2792 if before is not None:
2792 if before is not None:
2793 if not opts.get('text') and binary():
2793 if not opts.get('text') and binary():
2794 ui.write(sep + " Binary file matches")
2794 ui.write(sep + " Binary file matches")
2795 else:
2795 else:
2796 ui.write(sep + before)
2796 ui.write(sep + before)
2797 ui.write(match, label='grep.match')
2797 ui.write(match, label='grep.match')
2798 ui.write(after)
2798 ui.write(after)
2799 ui.write(eol)
2799 ui.write(eol)
2800 found = True
2800 found = True
2801 return found
2801 return found
2802
2802
2803 skip = {}
2803 skip = {}
2804 revfiles = {}
2804 revfiles = {}
2805 matchfn = scmutil.match(repo[None], pats, opts)
2805 matchfn = scmutil.match(repo[None], pats, opts)
2806 found = False
2806 found = False
2807 follow = opts.get('follow')
2807 follow = opts.get('follow')
2808
2808
2809 def prep(ctx, fns):
2809 def prep(ctx, fns):
2810 rev = ctx.rev()
2810 rev = ctx.rev()
2811 pctx = ctx.p1()
2811 pctx = ctx.p1()
2812 parent = pctx.rev()
2812 parent = pctx.rev()
2813 matches.setdefault(rev, {})
2813 matches.setdefault(rev, {})
2814 matches.setdefault(parent, {})
2814 matches.setdefault(parent, {})
2815 files = revfiles.setdefault(rev, [])
2815 files = revfiles.setdefault(rev, [])
2816 for fn in fns:
2816 for fn in fns:
2817 flog = getfile(fn)
2817 flog = getfile(fn)
2818 try:
2818 try:
2819 fnode = ctx.filenode(fn)
2819 fnode = ctx.filenode(fn)
2820 except error.LookupError:
2820 except error.LookupError:
2821 continue
2821 continue
2822
2822
2823 copied = flog.renamed(fnode)
2823 copied = flog.renamed(fnode)
2824 copy = follow and copied and copied[0]
2824 copy = follow and copied and copied[0]
2825 if copy:
2825 if copy:
2826 copies.setdefault(rev, {})[fn] = copy
2826 copies.setdefault(rev, {})[fn] = copy
2827 if fn in skip:
2827 if fn in skip:
2828 if copy:
2828 if copy:
2829 skip[copy] = True
2829 skip[copy] = True
2830 continue
2830 continue
2831 files.append(fn)
2831 files.append(fn)
2832
2832
2833 if fn not in matches[rev]:
2833 if fn not in matches[rev]:
2834 grepbody(fn, rev, flog.read(fnode))
2834 grepbody(fn, rev, flog.read(fnode))
2835
2835
2836 pfn = copy or fn
2836 pfn = copy or fn
2837 if pfn not in matches[parent]:
2837 if pfn not in matches[parent]:
2838 try:
2838 try:
2839 fnode = pctx.filenode(pfn)
2839 fnode = pctx.filenode(pfn)
2840 grepbody(pfn, parent, flog.read(fnode))
2840 grepbody(pfn, parent, flog.read(fnode))
2841 except error.LookupError:
2841 except error.LookupError:
2842 pass
2842 pass
2843
2843
2844 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2844 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2845 rev = ctx.rev()
2845 rev = ctx.rev()
2846 parent = ctx.p1().rev()
2846 parent = ctx.p1().rev()
2847 for fn in sorted(revfiles.get(rev, [])):
2847 for fn in sorted(revfiles.get(rev, [])):
2848 states = matches[rev][fn]
2848 states = matches[rev][fn]
2849 copy = copies.get(rev, {}).get(fn)
2849 copy = copies.get(rev, {}).get(fn)
2850 if fn in skip:
2850 if fn in skip:
2851 if copy:
2851 if copy:
2852 skip[copy] = True
2852 skip[copy] = True
2853 continue
2853 continue
2854 pstates = matches.get(parent, {}).get(copy or fn, [])
2854 pstates = matches.get(parent, {}).get(copy or fn, [])
2855 if pstates or states:
2855 if pstates or states:
2856 r = display(fn, ctx, pstates, states)
2856 r = display(fn, ctx, pstates, states)
2857 found = found or r
2857 found = found or r
2858 if r and not opts.get('all'):
2858 if r and not opts.get('all'):
2859 skip[fn] = True
2859 skip[fn] = True
2860 if copy:
2860 if copy:
2861 skip[copy] = True
2861 skip[copy] = True
2862 del matches[rev]
2862 del matches[rev]
2863 del revfiles[rev]
2863 del revfiles[rev]
2864
2864
2865 return not found
2865 return not found
2866
2866
2867 @command('heads',
2867 @command('heads',
2868 [('r', 'rev', '',
2868 [('r', 'rev', '',
2869 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2869 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2870 ('t', 'topo', False, _('show topological heads only')),
2870 ('t', 'topo', False, _('show topological heads only')),
2871 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2871 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2872 ('c', 'closed', False, _('show normal and closed branch heads')),
2872 ('c', 'closed', False, _('show normal and closed branch heads')),
2873 ] + templateopts,
2873 ] + templateopts,
2874 _('[-ac] [-r STARTREV] [REV]...'))
2874 _('[-ac] [-r STARTREV] [REV]...'))
2875 def heads(ui, repo, *branchrevs, **opts):
2875 def heads(ui, repo, *branchrevs, **opts):
2876 """show current repository heads or show branch heads
2876 """show current repository heads or show branch heads
2877
2877
2878 With no arguments, show all repository branch heads.
2878 With no arguments, show all repository branch heads.
2879
2879
2880 Repository "heads" are changesets with no child changesets. They are
2880 Repository "heads" are changesets with no child changesets. They are
2881 where development generally takes place and are the usual targets
2881 where development generally takes place and are the usual targets
2882 for update and merge operations. Branch heads are changesets that have
2882 for update and merge operations. Branch heads are changesets that have
2883 no child changeset on the same branch.
2883 no child changeset on the same branch.
2884
2884
2885 If one or more REVs are given, only branch heads on the branches
2885 If one or more REVs are given, only branch heads on the branches
2886 associated with the specified changesets are shown. This means
2886 associated with the specified changesets are shown. This means
2887 that you can use :hg:`heads foo` to see the heads on a branch
2887 that you can use :hg:`heads foo` to see the heads on a branch
2888 named ``foo``.
2888 named ``foo``.
2889
2889
2890 If -c/--closed is specified, also show branch heads marked closed
2890 If -c/--closed is specified, also show branch heads marked closed
2891 (see :hg:`commit --close-branch`).
2891 (see :hg:`commit --close-branch`).
2892
2892
2893 If STARTREV is specified, only those heads that are descendants of
2893 If STARTREV is specified, only those heads that are descendants of
2894 STARTREV will be displayed.
2894 STARTREV will be displayed.
2895
2895
2896 If -t/--topo is specified, named branch mechanics will be ignored and only
2896 If -t/--topo is specified, named branch mechanics will be ignored and only
2897 changesets without children will be shown.
2897 changesets without children will be shown.
2898
2898
2899 Returns 0 if matching heads are found, 1 if not.
2899 Returns 0 if matching heads are found, 1 if not.
2900 """
2900 """
2901
2901
2902 start = None
2902 start = None
2903 if 'rev' in opts:
2903 if 'rev' in opts:
2904 start = scmutil.revsingle(repo, opts['rev'], None).node()
2904 start = scmutil.revsingle(repo, opts['rev'], None).node()
2905
2905
2906 if opts.get('topo'):
2906 if opts.get('topo'):
2907 heads = [repo[h] for h in repo.heads(start)]
2907 heads = [repo[h] for h in repo.heads(start)]
2908 else:
2908 else:
2909 heads = []
2909 heads = []
2910 for branch in repo.branchmap():
2910 for branch in repo.branchmap():
2911 heads += repo.branchheads(branch, start, opts.get('closed'))
2911 heads += repo.branchheads(branch, start, opts.get('closed'))
2912 heads = [repo[h] for h in heads]
2912 heads = [repo[h] for h in heads]
2913
2913
2914 if branchrevs:
2914 if branchrevs:
2915 branches = set(repo[br].branch() for br in branchrevs)
2915 branches = set(repo[br].branch() for br in branchrevs)
2916 heads = [h for h in heads if h.branch() in branches]
2916 heads = [h for h in heads if h.branch() in branches]
2917
2917
2918 if opts.get('active') and branchrevs:
2918 if opts.get('active') and branchrevs:
2919 dagheads = repo.heads(start)
2919 dagheads = repo.heads(start)
2920 heads = [h for h in heads if h.node() in dagheads]
2920 heads = [h for h in heads if h.node() in dagheads]
2921
2921
2922 if branchrevs:
2922 if branchrevs:
2923 haveheads = set(h.branch() for h in heads)
2923 haveheads = set(h.branch() for h in heads)
2924 if branches - haveheads:
2924 if branches - haveheads:
2925 headless = ', '.join(b for b in branches - haveheads)
2925 headless = ', '.join(b for b in branches - haveheads)
2926 msg = _('no open branch heads found on branches %s')
2926 msg = _('no open branch heads found on branches %s')
2927 if opts.get('rev'):
2927 if opts.get('rev'):
2928 msg += _(' (started at %s)' % opts['rev'])
2928 msg += _(' (started at %s)' % opts['rev'])
2929 ui.warn((msg + '\n') % headless)
2929 ui.warn((msg + '\n') % headless)
2930
2930
2931 if not heads:
2931 if not heads:
2932 return 1
2932 return 1
2933
2933
2934 heads = sorted(heads, key=lambda x: -x.rev())
2934 heads = sorted(heads, key=lambda x: -x.rev())
2935 displayer = cmdutil.show_changeset(ui, repo, opts)
2935 displayer = cmdutil.show_changeset(ui, repo, opts)
2936 for ctx in heads:
2936 for ctx in heads:
2937 displayer.show(ctx)
2937 displayer.show(ctx)
2938 displayer.close()
2938 displayer.close()
2939
2939
2940 @command('help',
2940 @command('help',
2941 [('e', 'extension', None, _('show only help for extensions')),
2941 [('e', 'extension', None, _('show only help for extensions')),
2942 ('c', 'command', None, _('show only help for commands'))],
2942 ('c', 'command', None, _('show only help for commands'))],
2943 _('[-ec] [TOPIC]'))
2943 _('[-ec] [TOPIC]'))
2944 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2944 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
2945 """show help for a given topic or a help overview
2945 """show help for a given topic or a help overview
2946
2946
2947 With no arguments, print a list of commands with short help messages.
2947 With no arguments, print a list of commands with short help messages.
2948
2948
2949 Given a topic, extension, or command name, print help for that
2949 Given a topic, extension, or command name, print help for that
2950 topic.
2950 topic.
2951
2951
2952 Returns 0 if successful.
2952 Returns 0 if successful.
2953 """
2953 """
2954
2954
2955 textwidth = min(ui.termwidth(), 80) - 2
2955 textwidth = min(ui.termwidth(), 80) - 2
2956
2956
2957 def optrst(options):
2957 def optrst(options):
2958 data = []
2958 data = []
2959 multioccur = False
2959 multioccur = False
2960 for option in options:
2960 for option in options:
2961 if len(option) == 5:
2961 if len(option) == 5:
2962 shortopt, longopt, default, desc, optlabel = option
2962 shortopt, longopt, default, desc, optlabel = option
2963 else:
2963 else:
2964 shortopt, longopt, default, desc = option
2964 shortopt, longopt, default, desc = option
2965 optlabel = _("VALUE") # default label
2965 optlabel = _("VALUE") # default label
2966
2966
2967 if _("DEPRECATED") in desc and not ui.verbose:
2967 if _("DEPRECATED") in desc and not ui.verbose:
2968 continue
2968 continue
2969
2969
2970 so = ''
2970 so = ''
2971 if shortopt:
2971 if shortopt:
2972 so = '-' + shortopt
2972 so = '-' + shortopt
2973 lo = '--' + longopt
2973 lo = '--' + longopt
2974 if default:
2974 if default:
2975 desc += _(" (default: %s)") % default
2975 desc += _(" (default: %s)") % default
2976
2976
2977 if isinstance(default, list):
2977 if isinstance(default, list):
2978 lo += " %s [+]" % optlabel
2978 lo += " %s [+]" % optlabel
2979 multioccur = True
2979 multioccur = True
2980 elif (default is not None) and not isinstance(default, bool):
2980 elif (default is not None) and not isinstance(default, bool):
2981 lo += " %s" % optlabel
2981 lo += " %s" % optlabel
2982
2982
2983 data.append((so, lo, desc))
2983 data.append((so, lo, desc))
2984
2984
2985 rst = minirst.maketable(data, 1)
2985 rst = minirst.maketable(data, 1)
2986
2986
2987 if multioccur:
2987 if multioccur:
2988 rst += _("\n[+] marked option can be specified multiple times\n")
2988 rst += _("\n[+] marked option can be specified multiple times\n")
2989
2989
2990 return rst
2990 return rst
2991
2991
2992 # list all option lists
2992 # list all option lists
2993 def opttext(optlist, width):
2993 def opttext(optlist, width):
2994 rst = ''
2994 rst = ''
2995 if not optlist:
2995 if not optlist:
2996 return ''
2996 return ''
2997
2997
2998 for title, options in optlist:
2998 for title, options in optlist:
2999 rst += '\n%s\n' % title
2999 rst += '\n%s\n' % title
3000 if options:
3000 if options:
3001 rst += "\n"
3001 rst += "\n"
3002 rst += optrst(options)
3002 rst += optrst(options)
3003 rst += '\n'
3003 rst += '\n'
3004
3004
3005 return '\n' + minirst.format(rst, width)
3005 return '\n' + minirst.format(rst, width)
3006
3006
3007 def addglobalopts(optlist, aliases):
3007 def addglobalopts(optlist, aliases):
3008 if ui.quiet:
3008 if ui.quiet:
3009 return []
3009 return []
3010
3010
3011 if ui.verbose:
3011 if ui.verbose:
3012 optlist.append((_("global options:"), globalopts))
3012 optlist.append((_("global options:"), globalopts))
3013 if name == 'shortlist':
3013 if name == 'shortlist':
3014 optlist.append((_('use "hg help" for the full list '
3014 optlist.append((_('use "hg help" for the full list '
3015 'of commands'), ()))
3015 'of commands'), ()))
3016 else:
3016 else:
3017 if name == 'shortlist':
3017 if name == 'shortlist':
3018 msg = _('use "hg help" for the full list of commands '
3018 msg = _('use "hg help" for the full list of commands '
3019 'or "hg -v" for details')
3019 'or "hg -v" for details')
3020 elif name and not full:
3020 elif name and not full:
3021 msg = _('use "hg help %s" to show the full help text' % name)
3021 msg = _('use "hg help %s" to show the full help text' % name)
3022 elif aliases:
3022 elif aliases:
3023 msg = _('use "hg -v help%s" to show builtin aliases and '
3023 msg = _('use "hg -v help%s" to show builtin aliases and '
3024 'global options') % (name and " " + name or "")
3024 'global options') % (name and " " + name or "")
3025 else:
3025 else:
3026 msg = _('use "hg -v help %s" to show more info') % name
3026 msg = _('use "hg -v help %s" to show more info') % name
3027 optlist.append((msg, ()))
3027 optlist.append((msg, ()))
3028
3028
3029 def helpcmd(name):
3029 def helpcmd(name):
3030 try:
3030 try:
3031 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3031 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3032 except error.AmbiguousCommand, inst:
3032 except error.AmbiguousCommand, inst:
3033 # py3k fix: except vars can't be used outside the scope of the
3033 # py3k fix: except vars can't be used outside the scope of the
3034 # except block, nor can be used inside a lambda. python issue4617
3034 # except block, nor can be used inside a lambda. python issue4617
3035 prefix = inst.args[0]
3035 prefix = inst.args[0]
3036 select = lambda c: c.lstrip('^').startswith(prefix)
3036 select = lambda c: c.lstrip('^').startswith(prefix)
3037 helplist(select)
3037 helplist(select)
3038 return
3038 return
3039
3039
3040 # check if it's an invalid alias and display its error if it is
3040 # check if it's an invalid alias and display its error if it is
3041 if getattr(entry[0], 'badalias', False):
3041 if getattr(entry[0], 'badalias', False):
3042 if not unknowncmd:
3042 if not unknowncmd:
3043 entry[0](ui)
3043 entry[0](ui)
3044 return
3044 return
3045
3045
3046 rst = ""
3046 rst = ""
3047
3047
3048 # synopsis
3048 # synopsis
3049 if len(entry) > 2:
3049 if len(entry) > 2:
3050 if entry[2].startswith('hg'):
3050 if entry[2].startswith('hg'):
3051 rst += "%s\n" % entry[2]
3051 rst += "%s\n" % entry[2]
3052 else:
3052 else:
3053 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3053 rst += 'hg %s %s\n' % (aliases[0], entry[2])
3054 else:
3054 else:
3055 rst += 'hg %s\n' % aliases[0]
3055 rst += 'hg %s\n' % aliases[0]
3056
3056
3057 # aliases
3057 # aliases
3058 if full and not ui.quiet and len(aliases) > 1:
3058 if full and not ui.quiet and len(aliases) > 1:
3059 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3059 rst += _("\naliases: %s\n") % ', '.join(aliases[1:])
3060
3060
3061 # description
3061 # description
3062 doc = gettext(entry[0].__doc__)
3062 doc = gettext(entry[0].__doc__)
3063 if not doc:
3063 if not doc:
3064 doc = _("(no help text available)")
3064 doc = _("(no help text available)")
3065 if util.safehasattr(entry[0], 'definition'): # aliased command
3065 if util.safehasattr(entry[0], 'definition'): # aliased command
3066 if entry[0].definition.startswith('!'): # shell alias
3066 if entry[0].definition.startswith('!'): # shell alias
3067 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3067 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3068 else:
3068 else:
3069 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3069 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3070 if ui.quiet or not full:
3070 if ui.quiet or not full:
3071 doc = doc.splitlines()[0]
3071 doc = doc.splitlines()[0]
3072 rst += "\n" + doc + "\n"
3072 rst += "\n" + doc + "\n"
3073
3073
3074 # check if this command shadows a non-trivial (multi-line)
3074 # check if this command shadows a non-trivial (multi-line)
3075 # extension help text
3075 # extension help text
3076 try:
3076 try:
3077 mod = extensions.find(name)
3077 mod = extensions.find(name)
3078 doc = gettext(mod.__doc__) or ''
3078 doc = gettext(mod.__doc__) or ''
3079 if '\n' in doc.strip():
3079 if '\n' in doc.strip():
3080 msg = _('use "hg help -e %s" to show help for '
3080 msg = _('use "hg help -e %s" to show help for '
3081 'the %s extension') % (name, name)
3081 'the %s extension') % (name, name)
3082 rst += '\n%s\n' % msg
3082 rst += '\n%s\n' % msg
3083 except KeyError:
3083 except KeyError:
3084 pass
3084 pass
3085
3085
3086 # options
3086 # options
3087 if not ui.quiet and entry[1]:
3087 if not ui.quiet and entry[1]:
3088 rst += '\noptions:\n\n'
3088 rst += '\noptions:\n\n'
3089 rst += optrst(entry[1])
3089 rst += optrst(entry[1])
3090
3090
3091 if ui.verbose:
3091 if ui.verbose:
3092 rst += '\nglobal options:\n\n'
3092 rst += '\nglobal options:\n\n'
3093 rst += optrst(globalopts)
3093 rst += optrst(globalopts)
3094
3094
3095 keep = ui.verbose and ['verbose'] or []
3095 keep = ui.verbose and ['verbose'] or []
3096 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3096 formatted, pruned = minirst.format(rst, textwidth, keep=keep)
3097 ui.write(formatted)
3097 ui.write(formatted)
3098
3098
3099 if not ui.verbose:
3099 if not ui.verbose:
3100 if not full:
3100 if not full:
3101 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3101 ui.write(_('\nuse "hg help %s" to show the full help text\n')
3102 % name)
3102 % name)
3103 elif not ui.quiet:
3103 elif not ui.quiet:
3104 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3104 ui.write(_('\nuse "hg -v help %s" to show more info\n') % name)
3105
3105
3106
3106
3107 def helplist(select=None):
3107 def helplist(select=None):
3108 # list of commands
3108 # list of commands
3109 if name == "shortlist":
3109 if name == "shortlist":
3110 header = _('basic commands:\n\n')
3110 header = _('basic commands:\n\n')
3111 else:
3111 else:
3112 header = _('list of commands:\n\n')
3112 header = _('list of commands:\n\n')
3113
3113
3114 h = {}
3114 h = {}
3115 cmds = {}
3115 cmds = {}
3116 for c, e in table.iteritems():
3116 for c, e in table.iteritems():
3117 f = c.split("|", 1)[0]
3117 f = c.split("|", 1)[0]
3118 if select and not select(f):
3118 if select and not select(f):
3119 continue
3119 continue
3120 if (not select and name != 'shortlist' and
3120 if (not select and name != 'shortlist' and
3121 e[0].__module__ != __name__):
3121 e[0].__module__ != __name__):
3122 continue
3122 continue
3123 if name == "shortlist" and not f.startswith("^"):
3123 if name == "shortlist" and not f.startswith("^"):
3124 continue
3124 continue
3125 f = f.lstrip("^")
3125 f = f.lstrip("^")
3126 if not ui.debugflag and f.startswith("debug"):
3126 if not ui.debugflag and f.startswith("debug"):
3127 continue
3127 continue
3128 doc = e[0].__doc__
3128 doc = e[0].__doc__
3129 if doc and 'DEPRECATED' in doc and not ui.verbose:
3129 if doc and 'DEPRECATED' in doc and not ui.verbose:
3130 continue
3130 continue
3131 doc = gettext(doc)
3131 doc = gettext(doc)
3132 if not doc:
3132 if not doc:
3133 doc = _("(no help text available)")
3133 doc = _("(no help text available)")
3134 h[f] = doc.splitlines()[0].rstrip()
3134 h[f] = doc.splitlines()[0].rstrip()
3135 cmds[f] = c.lstrip("^")
3135 cmds[f] = c.lstrip("^")
3136
3136
3137 if not h:
3137 if not h:
3138 ui.status(_('no commands defined\n'))
3138 ui.status(_('no commands defined\n'))
3139 return
3139 return
3140
3140
3141 ui.status(header)
3141 ui.status(header)
3142 fns = sorted(h)
3142 fns = sorted(h)
3143 m = max(map(len, fns))
3143 m = max(map(len, fns))
3144 for f in fns:
3144 for f in fns:
3145 if ui.verbose:
3145 if ui.verbose:
3146 commands = cmds[f].replace("|",", ")
3146 commands = cmds[f].replace("|",", ")
3147 ui.write(" %s:\n %s\n"%(commands, h[f]))
3147 ui.write(" %s:\n %s\n"%(commands, h[f]))
3148 else:
3148 else:
3149 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3149 ui.write('%s\n' % (util.wrap(h[f], textwidth,
3150 initindent=' %-*s ' % (m, f),
3150 initindent=' %-*s ' % (m, f),
3151 hangindent=' ' * (m + 4))))
3151 hangindent=' ' * (m + 4))))
3152
3152
3153 if not name:
3153 if not name:
3154 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3154 text = help.listexts(_('enabled extensions:'), extensions.enabled())
3155 if text:
3155 if text:
3156 ui.write("\n%s" % minirst.format(text, textwidth))
3156 ui.write("\n%s" % minirst.format(text, textwidth))
3157
3157
3158 ui.write(_("\nadditional help topics:\n\n"))
3158 ui.write(_("\nadditional help topics:\n\n"))
3159 topics = []
3159 topics = []
3160 for names, header, doc in help.helptable:
3160 for names, header, doc in help.helptable:
3161 topics.append((sorted(names, key=len, reverse=True)[0], header))
3161 topics.append((sorted(names, key=len, reverse=True)[0], header))
3162 topics_len = max([len(s[0]) for s in topics])
3162 topics_len = max([len(s[0]) for s in topics])
3163 for t, desc in topics:
3163 for t, desc in topics:
3164 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3164 ui.write(" %-*s %s\n" % (topics_len, t, desc))
3165
3165
3166 optlist = []
3166 optlist = []
3167 addglobalopts(optlist, True)
3167 addglobalopts(optlist, True)
3168 ui.write(opttext(optlist, textwidth))
3168 ui.write(opttext(optlist, textwidth))
3169
3169
3170 def helptopic(name):
3170 def helptopic(name):
3171 for names, header, doc in help.helptable:
3171 for names, header, doc in help.helptable:
3172 if name in names:
3172 if name in names:
3173 break
3173 break
3174 else:
3174 else:
3175 raise error.UnknownCommand(name)
3175 raise error.UnknownCommand(name)
3176
3176
3177 # description
3177 # description
3178 if not doc:
3178 if not doc:
3179 doc = _("(no help text available)")
3179 doc = _("(no help text available)")
3180 if util.safehasattr(doc, '__call__'):
3180 if util.safehasattr(doc, '__call__'):
3181 doc = doc()
3181 doc = doc()
3182
3182
3183 ui.write("%s\n\n" % header)
3183 ui.write("%s\n\n" % header)
3184 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3184 ui.write("%s" % minirst.format(doc, textwidth, indent=4))
3185 try:
3185 try:
3186 cmdutil.findcmd(name, table)
3186 cmdutil.findcmd(name, table)
3187 ui.write(_('\nuse "hg help -c %s" to see help for '
3187 ui.write(_('\nuse "hg help -c %s" to see help for '
3188 'the %s command\n') % (name, name))
3188 'the %s command\n') % (name, name))
3189 except error.UnknownCommand:
3189 except error.UnknownCommand:
3190 pass
3190 pass
3191
3191
3192 def helpext(name):
3192 def helpext(name):
3193 try:
3193 try:
3194 mod = extensions.find(name)
3194 mod = extensions.find(name)
3195 doc = gettext(mod.__doc__) or _('no help text available')
3195 doc = gettext(mod.__doc__) or _('no help text available')
3196 except KeyError:
3196 except KeyError:
3197 mod = None
3197 mod = None
3198 doc = extensions.disabledext(name)
3198 doc = extensions.disabledext(name)
3199 if not doc:
3199 if not doc:
3200 raise error.UnknownCommand(name)
3200 raise error.UnknownCommand(name)
3201
3201
3202 if '\n' not in doc:
3202 if '\n' not in doc:
3203 head, tail = doc, ""
3203 head, tail = doc, ""
3204 else:
3204 else:
3205 head, tail = doc.split('\n', 1)
3205 head, tail = doc.split('\n', 1)
3206 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3206 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
3207 if tail:
3207 if tail:
3208 ui.write(minirst.format(tail, textwidth))
3208 ui.write(minirst.format(tail, textwidth))
3209 ui.status('\n')
3209 ui.status('\n')
3210
3210
3211 if mod:
3211 if mod:
3212 try:
3212 try:
3213 ct = mod.cmdtable
3213 ct = mod.cmdtable
3214 except AttributeError:
3214 except AttributeError:
3215 ct = {}
3215 ct = {}
3216 modcmds = set([c.split('|', 1)[0] for c in ct])
3216 modcmds = set([c.split('|', 1)[0] for c in ct])
3217 helplist(modcmds.__contains__)
3217 helplist(modcmds.__contains__)
3218 else:
3218 else:
3219 ui.write(_('use "hg help extensions" for information on enabling '
3219 ui.write(_('use "hg help extensions" for information on enabling '
3220 'extensions\n'))
3220 'extensions\n'))
3221
3221
3222 def helpextcmd(name):
3222 def helpextcmd(name):
3223 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3223 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
3224 doc = gettext(mod.__doc__).splitlines()[0]
3224 doc = gettext(mod.__doc__).splitlines()[0]
3225
3225
3226 msg = help.listexts(_("'%s' is provided by the following "
3226 msg = help.listexts(_("'%s' is provided by the following "
3227 "extension:") % cmd, {ext: doc}, indent=4)
3227 "extension:") % cmd, {ext: doc}, indent=4)
3228 ui.write(minirst.format(msg, textwidth))
3228 ui.write(minirst.format(msg, textwidth))
3229 ui.write('\n')
3229 ui.write('\n')
3230 ui.write(_('use "hg help extensions" for information on enabling '
3230 ui.write(_('use "hg help extensions" for information on enabling '
3231 'extensions\n'))
3231 'extensions\n'))
3232
3232
3233 if name and name != 'shortlist':
3233 if name and name != 'shortlist':
3234 i = None
3234 i = None
3235 if unknowncmd:
3235 if unknowncmd:
3236 queries = (helpextcmd,)
3236 queries = (helpextcmd,)
3237 elif opts.get('extension'):
3237 elif opts.get('extension'):
3238 queries = (helpext,)
3238 queries = (helpext,)
3239 elif opts.get('command'):
3239 elif opts.get('command'):
3240 queries = (helpcmd,)
3240 queries = (helpcmd,)
3241 else:
3241 else:
3242 queries = (helptopic, helpcmd, helpext, helpextcmd)
3242 queries = (helptopic, helpcmd, helpext, helpextcmd)
3243 for f in queries:
3243 for f in queries:
3244 try:
3244 try:
3245 f(name)
3245 f(name)
3246 i = None
3246 i = None
3247 break
3247 break
3248 except error.UnknownCommand, inst:
3248 except error.UnknownCommand, inst:
3249 i = inst
3249 i = inst
3250 if i:
3250 if i:
3251 raise i
3251 raise i
3252 else:
3252 else:
3253 # program name
3253 # program name
3254 ui.status(_("Mercurial Distributed SCM\n"))
3254 ui.status(_("Mercurial Distributed SCM\n"))
3255 ui.status('\n')
3255 ui.status('\n')
3256 helplist()
3256 helplist()
3257
3257
3258
3258
3259 @command('identify|id',
3259 @command('identify|id',
3260 [('r', 'rev', '',
3260 [('r', 'rev', '',
3261 _('identify the specified revision'), _('REV')),
3261 _('identify the specified revision'), _('REV')),
3262 ('n', 'num', None, _('show local revision number')),
3262 ('n', 'num', None, _('show local revision number')),
3263 ('i', 'id', None, _('show global revision id')),
3263 ('i', 'id', None, _('show global revision id')),
3264 ('b', 'branch', None, _('show branch')),
3264 ('b', 'branch', None, _('show branch')),
3265 ('t', 'tags', None, _('show tags')),
3265 ('t', 'tags', None, _('show tags')),
3266 ('B', 'bookmarks', None, _('show bookmarks'))],
3266 ('B', 'bookmarks', None, _('show bookmarks'))],
3267 _('[-nibtB] [-r REV] [SOURCE]'))
3267 _('[-nibtB] [-r REV] [SOURCE]'))
3268 def identify(ui, repo, source=None, rev=None,
3268 def identify(ui, repo, source=None, rev=None,
3269 num=None, id=None, branch=None, tags=None, bookmarks=None):
3269 num=None, id=None, branch=None, tags=None, bookmarks=None):
3270 """identify the working copy or specified revision
3270 """identify the working copy or specified revision
3271
3271
3272 Print a summary identifying the repository state at REV using one or
3272 Print a summary identifying the repository state at REV using one or
3273 two parent hash identifiers, followed by a "+" if the working
3273 two parent hash identifiers, followed by a "+" if the working
3274 directory has uncommitted changes, the branch name (if not default),
3274 directory has uncommitted changes, the branch name (if not default),
3275 a list of tags, and a list of bookmarks.
3275 a list of tags, and a list of bookmarks.
3276
3276
3277 When REV is not given, print a summary of the current state of the
3277 When REV is not given, print a summary of the current state of the
3278 repository.
3278 repository.
3279
3279
3280 Specifying a path to a repository root or Mercurial bundle will
3280 Specifying a path to a repository root or Mercurial bundle will
3281 cause lookup to operate on that repository/bundle.
3281 cause lookup to operate on that repository/bundle.
3282
3282
3283 .. container:: verbose
3283 .. container:: verbose
3284
3284
3285 Examples:
3285 Examples:
3286
3286
3287 - generate a build identifier for the working directory::
3287 - generate a build identifier for the working directory::
3288
3288
3289 hg id --id > build-id.dat
3289 hg id --id > build-id.dat
3290
3290
3291 - find the revision corresponding to a tag::
3291 - find the revision corresponding to a tag::
3292
3292
3293 hg id -n -r 1.3
3293 hg id -n -r 1.3
3294
3294
3295 - check the most recent revision of a remote repository::
3295 - check the most recent revision of a remote repository::
3296
3296
3297 hg id -r tip http://selenic.com/hg/
3297 hg id -r tip http://selenic.com/hg/
3298
3298
3299 Returns 0 if successful.
3299 Returns 0 if successful.
3300 """
3300 """
3301
3301
3302 if not repo and not source:
3302 if not repo and not source:
3303 raise util.Abort(_("there is no Mercurial repository here "
3303 raise util.Abort(_("there is no Mercurial repository here "
3304 "(.hg not found)"))
3304 "(.hg not found)"))
3305
3305
3306 hexfunc = ui.debugflag and hex or short
3306 hexfunc = ui.debugflag and hex or short
3307 default = not (num or id or branch or tags or bookmarks)
3307 default = not (num or id or branch or tags or bookmarks)
3308 output = []
3308 output = []
3309 revs = []
3309 revs = []
3310
3310
3311 if source:
3311 if source:
3312 source, branches = hg.parseurl(ui.expandpath(source))
3312 source, branches = hg.parseurl(ui.expandpath(source))
3313 repo = hg.peer(ui, {}, source)
3313 repo = hg.peer(ui, {}, source)
3314 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3314 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3315
3315
3316 if not repo.local():
3316 if not repo.local():
3317 if num or branch or tags:
3317 if num or branch or tags:
3318 raise util.Abort(
3318 raise util.Abort(
3319 _("can't query remote revision number, branch, or tags"))
3319 _("can't query remote revision number, branch, or tags"))
3320 if not rev and revs:
3320 if not rev and revs:
3321 rev = revs[0]
3321 rev = revs[0]
3322 if not rev:
3322 if not rev:
3323 rev = "tip"
3323 rev = "tip"
3324
3324
3325 remoterev = repo.lookup(rev)
3325 remoterev = repo.lookup(rev)
3326 if default or id:
3326 if default or id:
3327 output = [hexfunc(remoterev)]
3327 output = [hexfunc(remoterev)]
3328
3328
3329 def getbms():
3329 def getbms():
3330 bms = []
3330 bms = []
3331
3331
3332 if 'bookmarks' in repo.listkeys('namespaces'):
3332 if 'bookmarks' in repo.listkeys('namespaces'):
3333 hexremoterev = hex(remoterev)
3333 hexremoterev = hex(remoterev)
3334 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3334 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
3335 if bmr == hexremoterev]
3335 if bmr == hexremoterev]
3336
3336
3337 return bms
3337 return bms
3338
3338
3339 if bookmarks:
3339 if bookmarks:
3340 output.extend(getbms())
3340 output.extend(getbms())
3341 elif default and not ui.quiet:
3341 elif default and not ui.quiet:
3342 # multiple bookmarks for a single parent separated by '/'
3342 # multiple bookmarks for a single parent separated by '/'
3343 bm = '/'.join(getbms())
3343 bm = '/'.join(getbms())
3344 if bm:
3344 if bm:
3345 output.append(bm)
3345 output.append(bm)
3346 else:
3346 else:
3347 if not rev:
3347 if not rev:
3348 ctx = repo[None]
3348 ctx = repo[None]
3349 parents = ctx.parents()
3349 parents = ctx.parents()
3350 changed = ""
3350 changed = ""
3351 if default or id or num:
3351 if default or id or num:
3352 changed = util.any(repo.status()) and "+" or ""
3352 changed = util.any(repo.status()) and "+" or ""
3353 if default or id:
3353 if default or id:
3354 output = ["%s%s" %
3354 output = ["%s%s" %
3355 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3355 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3356 if num:
3356 if num:
3357 output.append("%s%s" %
3357 output.append("%s%s" %
3358 ('+'.join([str(p.rev()) for p in parents]), changed))
3358 ('+'.join([str(p.rev()) for p in parents]), changed))
3359 else:
3359 else:
3360 ctx = scmutil.revsingle(repo, rev)
3360 ctx = scmutil.revsingle(repo, rev)
3361 if default or id:
3361 if default or id:
3362 output = [hexfunc(ctx.node())]
3362 output = [hexfunc(ctx.node())]
3363 if num:
3363 if num:
3364 output.append(str(ctx.rev()))
3364 output.append(str(ctx.rev()))
3365
3365
3366 if default and not ui.quiet:
3366 if default and not ui.quiet:
3367 b = ctx.branch()
3367 b = ctx.branch()
3368 if b != 'default':
3368 if b != 'default':
3369 output.append("(%s)" % b)
3369 output.append("(%s)" % b)
3370
3370
3371 # multiple tags for a single parent separated by '/'
3371 # multiple tags for a single parent separated by '/'
3372 t = '/'.join(ctx.tags())
3372 t = '/'.join(ctx.tags())
3373 if t:
3373 if t:
3374 output.append(t)
3374 output.append(t)
3375
3375
3376 # multiple bookmarks for a single parent separated by '/'
3376 # multiple bookmarks for a single parent separated by '/'
3377 bm = '/'.join(ctx.bookmarks())
3377 bm = '/'.join(ctx.bookmarks())
3378 if bm:
3378 if bm:
3379 output.append(bm)
3379 output.append(bm)
3380 else:
3380 else:
3381 if branch:
3381 if branch:
3382 output.append(ctx.branch())
3382 output.append(ctx.branch())
3383
3383
3384 if tags:
3384 if tags:
3385 output.extend(ctx.tags())
3385 output.extend(ctx.tags())
3386
3386
3387 if bookmarks:
3387 if bookmarks:
3388 output.extend(ctx.bookmarks())
3388 output.extend(ctx.bookmarks())
3389
3389
3390 ui.write("%s\n" % ' '.join(output))
3390 ui.write("%s\n" % ' '.join(output))
3391
3391
3392 @command('import|patch',
3392 @command('import|patch',
3393 [('p', 'strip', 1,
3393 [('p', 'strip', 1,
3394 _('directory strip option for patch. This has the same '
3394 _('directory strip option for patch. This has the same '
3395 'meaning as the corresponding patch option'), _('NUM')),
3395 'meaning as the corresponding patch option'), _('NUM')),
3396 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3396 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3397 ('e', 'edit', False, _('invoke editor on commit messages')),
3397 ('e', 'edit', False, _('invoke editor on commit messages')),
3398 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3398 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3399 ('', 'no-commit', None,
3399 ('', 'no-commit', None,
3400 _("don't commit, just update the working directory")),
3400 _("don't commit, just update the working directory")),
3401 ('', 'bypass', None,
3401 ('', 'bypass', None,
3402 _("apply patch without touching the working directory")),
3402 _("apply patch without touching the working directory")),
3403 ('', 'exact', None,
3403 ('', 'exact', None,
3404 _('apply patch to the nodes from which it was generated')),
3404 _('apply patch to the nodes from which it was generated')),
3405 ('', 'import-branch', None,
3405 ('', 'import-branch', None,
3406 _('use any branch information in patch (implied by --exact)'))] +
3406 _('use any branch information in patch (implied by --exact)'))] +
3407 commitopts + commitopts2 + similarityopts,
3407 commitopts + commitopts2 + similarityopts,
3408 _('[OPTION]... PATCH...'))
3408 _('[OPTION]... PATCH...'))
3409 def import_(ui, repo, patch1=None, *patches, **opts):
3409 def import_(ui, repo, patch1=None, *patches, **opts):
3410 """import an ordered set of patches
3410 """import an ordered set of patches
3411
3411
3412 Import a list of patches and commit them individually (unless
3412 Import a list of patches and commit them individually (unless
3413 --no-commit is specified).
3413 --no-commit is specified).
3414
3414
3415 If there are outstanding changes in the working directory, import
3415 If there are outstanding changes in the working directory, import
3416 will abort unless given the -f/--force flag.
3416 will abort unless given the -f/--force flag.
3417
3417
3418 You can import a patch straight from a mail message. Even patches
3418 You can import a patch straight from a mail message. Even patches
3419 as attachments work (to use the body part, it must have type
3419 as attachments work (to use the body part, it must have type
3420 text/plain or text/x-patch). From and Subject headers of email
3420 text/plain or text/x-patch). From and Subject headers of email
3421 message are used as default committer and commit message. All
3421 message are used as default committer and commit message. All
3422 text/plain body parts before first diff are added to commit
3422 text/plain body parts before first diff are added to commit
3423 message.
3423 message.
3424
3424
3425 If the imported patch was generated by :hg:`export`, user and
3425 If the imported patch was generated by :hg:`export`, user and
3426 description from patch override values from message headers and
3426 description from patch override values from message headers and
3427 body. Values given on command line with -m/--message and -u/--user
3427 body. Values given on command line with -m/--message and -u/--user
3428 override these.
3428 override these.
3429
3429
3430 If --exact is specified, import will set the working directory to
3430 If --exact is specified, import will set the working directory to
3431 the parent of each patch before applying it, and will abort if the
3431 the parent of each patch before applying it, and will abort if the
3432 resulting changeset has a different ID than the one recorded in
3432 resulting changeset has a different ID than the one recorded in
3433 the patch. This may happen due to character set problems or other
3433 the patch. This may happen due to character set problems or other
3434 deficiencies in the text patch format.
3434 deficiencies in the text patch format.
3435
3435
3436 Use --bypass to apply and commit patches directly to the
3436 Use --bypass to apply and commit patches directly to the
3437 repository, not touching the working directory. Without --exact,
3437 repository, not touching the working directory. Without --exact,
3438 patches will be applied on top of the working directory parent
3438 patches will be applied on top of the working directory parent
3439 revision.
3439 revision.
3440
3440
3441 With -s/--similarity, hg will attempt to discover renames and
3441 With -s/--similarity, hg will attempt to discover renames and
3442 copies in the patch in the same way as 'addremove'.
3442 copies in the patch in the same way as 'addremove'.
3443
3443
3444 To read a patch from standard input, use "-" as the patch name. If
3444 To read a patch from standard input, use "-" as the patch name. If
3445 a URL is specified, the patch will be downloaded from it.
3445 a URL is specified, the patch will be downloaded from it.
3446 See :hg:`help dates` for a list of formats valid for -d/--date.
3446 See :hg:`help dates` for a list of formats valid for -d/--date.
3447
3447
3448 .. container:: verbose
3448 .. container:: verbose
3449
3449
3450 Examples:
3450 Examples:
3451
3451
3452 - import a traditional patch from a website and detect renames::
3452 - import a traditional patch from a website and detect renames::
3453
3453
3454 hg import -s 80 http://example.com/bugfix.patch
3454 hg import -s 80 http://example.com/bugfix.patch
3455
3455
3456 - import a changeset from an hgweb server::
3456 - import a changeset from an hgweb server::
3457
3457
3458 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3458 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3459
3459
3460 - import all the patches in an Unix-style mbox::
3460 - import all the patches in an Unix-style mbox::
3461
3461
3462 hg import incoming-patches.mbox
3462 hg import incoming-patches.mbox
3463
3463
3464 - attempt to exactly restore an exported changeset (not always
3464 - attempt to exactly restore an exported changeset (not always
3465 possible)::
3465 possible)::
3466
3466
3467 hg import --exact proposed-fix.patch
3467 hg import --exact proposed-fix.patch
3468
3468
3469 Returns 0 on success.
3469 Returns 0 on success.
3470 """
3470 """
3471
3471
3472 if not patch1:
3472 if not patch1:
3473 raise util.Abort(_('need at least one patch to import'))
3473 raise util.Abort(_('need at least one patch to import'))
3474
3474
3475 patches = (patch1,) + patches
3475 patches = (patch1,) + patches
3476
3476
3477 date = opts.get('date')
3477 date = opts.get('date')
3478 if date:
3478 if date:
3479 opts['date'] = util.parsedate(date)
3479 opts['date'] = util.parsedate(date)
3480
3480
3481 editor = cmdutil.commiteditor
3481 editor = cmdutil.commiteditor
3482 if opts.get('edit'):
3482 if opts.get('edit'):
3483 editor = cmdutil.commitforceeditor
3483 editor = cmdutil.commitforceeditor
3484
3484
3485 update = not opts.get('bypass')
3485 update = not opts.get('bypass')
3486 if not update and opts.get('no_commit'):
3486 if not update and opts.get('no_commit'):
3487 raise util.Abort(_('cannot use --no-commit with --bypass'))
3487 raise util.Abort(_('cannot use --no-commit with --bypass'))
3488 try:
3488 try:
3489 sim = float(opts.get('similarity') or 0)
3489 sim = float(opts.get('similarity') or 0)
3490 except ValueError:
3490 except ValueError:
3491 raise util.Abort(_('similarity must be a number'))
3491 raise util.Abort(_('similarity must be a number'))
3492 if sim < 0 or sim > 100:
3492 if sim < 0 or sim > 100:
3493 raise util.Abort(_('similarity must be between 0 and 100'))
3493 raise util.Abort(_('similarity must be between 0 and 100'))
3494 if sim and not update:
3494 if sim and not update:
3495 raise util.Abort(_('cannot use --similarity with --bypass'))
3495 raise util.Abort(_('cannot use --similarity with --bypass'))
3496
3496
3497 if (opts.get('exact') or not opts.get('force')) and update:
3497 if (opts.get('exact') or not opts.get('force')) and update:
3498 cmdutil.bailifchanged(repo)
3498 cmdutil.bailifchanged(repo)
3499
3499
3500 base = opts["base"]
3500 base = opts["base"]
3501 strip = opts["strip"]
3501 strip = opts["strip"]
3502 wlock = lock = tr = None
3502 wlock = lock = tr = None
3503 msgs = []
3503 msgs = []
3504
3504
3505 def checkexact(repo, n, nodeid):
3505 def checkexact(repo, n, nodeid):
3506 if opts.get('exact') and hex(n) != nodeid:
3506 if opts.get('exact') and hex(n) != nodeid:
3507 repo.rollback()
3507 repo.rollback()
3508 raise util.Abort(_('patch is damaged or loses information'))
3508 raise util.Abort(_('patch is damaged or loses information'))
3509
3509
3510 def tryone(ui, hunk, parents):
3510 def tryone(ui, hunk, parents):
3511 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3511 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3512 patch.extract(ui, hunk)
3512 patch.extract(ui, hunk)
3513
3513
3514 if not tmpname:
3514 if not tmpname:
3515 return (None, None)
3515 return (None, None)
3516 msg = _('applied to working directory')
3516 msg = _('applied to working directory')
3517
3517
3518 try:
3518 try:
3519 cmdline_message = cmdutil.logmessage(ui, opts)
3519 cmdline_message = cmdutil.logmessage(ui, opts)
3520 if cmdline_message:
3520 if cmdline_message:
3521 # pickup the cmdline msg
3521 # pickup the cmdline msg
3522 message = cmdline_message
3522 message = cmdline_message
3523 elif message:
3523 elif message:
3524 # pickup the patch msg
3524 # pickup the patch msg
3525 message = message.strip()
3525 message = message.strip()
3526 else:
3526 else:
3527 # launch the editor
3527 # launch the editor
3528 message = None
3528 message = None
3529 ui.debug('message:\n%s\n' % message)
3529 ui.debug('message:\n%s\n' % message)
3530
3530
3531 if len(parents) == 1:
3531 if len(parents) == 1:
3532 parents.append(repo[nullid])
3532 parents.append(repo[nullid])
3533 if opts.get('exact'):
3533 if opts.get('exact'):
3534 if not nodeid or not p1:
3534 if not nodeid or not p1:
3535 raise util.Abort(_('not a Mercurial patch'))
3535 raise util.Abort(_('not a Mercurial patch'))
3536 p1 = repo[p1]
3536 p1 = repo[p1]
3537 p2 = repo[p2 or nullid]
3537 p2 = repo[p2 or nullid]
3538 elif p2:
3538 elif p2:
3539 try:
3539 try:
3540 p1 = repo[p1]
3540 p1 = repo[p1]
3541 p2 = repo[p2]
3541 p2 = repo[p2]
3542 # Without any options, consider p2 only if the
3542 # Without any options, consider p2 only if the
3543 # patch is being applied on top of the recorded
3543 # patch is being applied on top of the recorded
3544 # first parent.
3544 # first parent.
3545 if p1 != parents[0]:
3545 if p1 != parents[0]:
3546 p1 = parents[0]
3546 p1 = parents[0]
3547 p2 = repo[nullid]
3547 p2 = repo[nullid]
3548 except error.RepoError:
3548 except error.RepoError:
3549 p1, p2 = parents
3549 p1, p2 = parents
3550 else:
3550 else:
3551 p1, p2 = parents
3551 p1, p2 = parents
3552
3552
3553 n = None
3553 n = None
3554 if update:
3554 if update:
3555 if p1 != parents[0]:
3555 if p1 != parents[0]:
3556 hg.clean(repo, p1.node())
3556 hg.clean(repo, p1.node())
3557 if p2 != parents[1]:
3557 if p2 != parents[1]:
3558 repo.dirstate.setparents(p1.node(), p2.node())
3558 repo.dirstate.setparents(p1.node(), p2.node())
3559
3559
3560 if opts.get('exact') or opts.get('import_branch'):
3560 if opts.get('exact') or opts.get('import_branch'):
3561 repo.dirstate.setbranch(branch or 'default')
3561 repo.dirstate.setbranch(branch or 'default')
3562
3562
3563 files = set()
3563 files = set()
3564 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3564 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3565 eolmode=None, similarity=sim / 100.0)
3565 eolmode=None, similarity=sim / 100.0)
3566 files = list(files)
3566 files = list(files)
3567 if opts.get('no_commit'):
3567 if opts.get('no_commit'):
3568 if message:
3568 if message:
3569 msgs.append(message)
3569 msgs.append(message)
3570 else:
3570 else:
3571 if opts.get('exact') or p2:
3571 if opts.get('exact') or p2:
3572 # If you got here, you either use --force and know what
3572 # If you got here, you either use --force and know what
3573 # you are doing or used --exact or a merge patch while
3573 # you are doing or used --exact or a merge patch while
3574 # being updated to its first parent.
3574 # being updated to its first parent.
3575 m = None
3575 m = None
3576 else:
3576 else:
3577 m = scmutil.matchfiles(repo, files or [])
3577 m = scmutil.matchfiles(repo, files or [])
3578 n = repo.commit(message, opts.get('user') or user,
3578 n = repo.commit(message, opts.get('user') or user,
3579 opts.get('date') or date, match=m,
3579 opts.get('date') or date, match=m,
3580 editor=editor)
3580 editor=editor)
3581 checkexact(repo, n, nodeid)
3581 checkexact(repo, n, nodeid)
3582 else:
3582 else:
3583 if opts.get('exact') or opts.get('import_branch'):
3583 if opts.get('exact') or opts.get('import_branch'):
3584 branch = branch or 'default'
3584 branch = branch or 'default'
3585 else:
3585 else:
3586 branch = p1.branch()
3586 branch = p1.branch()
3587 store = patch.filestore()
3587 store = patch.filestore()
3588 try:
3588 try:
3589 files = set()
3589 files = set()
3590 try:
3590 try:
3591 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3591 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3592 files, eolmode=None)
3592 files, eolmode=None)
3593 except patch.PatchError, e:
3593 except patch.PatchError, e:
3594 raise util.Abort(str(e))
3594 raise util.Abort(str(e))
3595 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3595 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3596 message,
3596 message,
3597 opts.get('user') or user,
3597 opts.get('user') or user,
3598 opts.get('date') or date,
3598 opts.get('date') or date,
3599 branch, files, store,
3599 branch, files, store,
3600 editor=cmdutil.commiteditor)
3600 editor=cmdutil.commiteditor)
3601 repo.savecommitmessage(memctx.description())
3601 repo.savecommitmessage(memctx.description())
3602 n = memctx.commit()
3602 n = memctx.commit()
3603 checkexact(repo, n, nodeid)
3603 checkexact(repo, n, nodeid)
3604 finally:
3604 finally:
3605 store.close()
3605 store.close()
3606 if n:
3606 if n:
3607 # i18n: refers to a short changeset id
3607 # i18n: refers to a short changeset id
3608 msg = _('created %s') % short(n)
3608 msg = _('created %s') % short(n)
3609 return (msg, n)
3609 return (msg, n)
3610 finally:
3610 finally:
3611 os.unlink(tmpname)
3611 os.unlink(tmpname)
3612
3612
3613 try:
3613 try:
3614 try:
3614 try:
3615 wlock = repo.wlock()
3615 wlock = repo.wlock()
3616 lock = repo.lock()
3616 lock = repo.lock()
3617 tr = repo.transaction('import')
3617 tr = repo.transaction('import')
3618 parents = repo.parents()
3618 parents = repo.parents()
3619 for patchurl in patches:
3619 for patchurl in patches:
3620 if patchurl == '-':
3620 if patchurl == '-':
3621 ui.status(_('applying patch from stdin\n'))
3621 ui.status(_('applying patch from stdin\n'))
3622 patchfile = ui.fin
3622 patchfile = ui.fin
3623 patchurl = 'stdin' # for error message
3623 patchurl = 'stdin' # for error message
3624 else:
3624 else:
3625 patchurl = os.path.join(base, patchurl)
3625 patchurl = os.path.join(base, patchurl)
3626 ui.status(_('applying %s\n') % patchurl)
3626 ui.status(_('applying %s\n') % patchurl)
3627 patchfile = url.open(ui, patchurl)
3627 patchfile = url.open(ui, patchurl)
3628
3628
3629 haspatch = False
3629 haspatch = False
3630 for hunk in patch.split(patchfile):
3630 for hunk in patch.split(patchfile):
3631 (msg, node) = tryone(ui, hunk, parents)
3631 (msg, node) = tryone(ui, hunk, parents)
3632 if msg:
3632 if msg:
3633 haspatch = True
3633 haspatch = True
3634 ui.note(msg + '\n')
3634 ui.note(msg + '\n')
3635 if update or opts.get('exact'):
3635 if update or opts.get('exact'):
3636 parents = repo.parents()
3636 parents = repo.parents()
3637 else:
3637 else:
3638 parents = [repo[node]]
3638 parents = [repo[node]]
3639
3639
3640 if not haspatch:
3640 if not haspatch:
3641 raise util.Abort(_('%s: no diffs found') % patchurl)
3641 raise util.Abort(_('%s: no diffs found') % patchurl)
3642
3642
3643 tr.close()
3643 tr.close()
3644 if msgs:
3644 if msgs:
3645 repo.savecommitmessage('\n* * *\n'.join(msgs))
3645 repo.savecommitmessage('\n* * *\n'.join(msgs))
3646 except:
3646 except:
3647 # wlock.release() indirectly calls dirstate.write(): since
3647 # wlock.release() indirectly calls dirstate.write(): since
3648 # we're crashing, we do not want to change the working dir
3648 # we're crashing, we do not want to change the working dir
3649 # parent after all, so make sure it writes nothing
3649 # parent after all, so make sure it writes nothing
3650 repo.dirstate.invalidate()
3650 repo.dirstate.invalidate()
3651 raise
3651 raise
3652 finally:
3652 finally:
3653 if tr:
3653 if tr:
3654 tr.release()
3654 tr.release()
3655 release(lock, wlock)
3655 release(lock, wlock)
3656
3656
3657 @command('incoming|in',
3657 @command('incoming|in',
3658 [('f', 'force', None,
3658 [('f', 'force', None,
3659 _('run even if remote repository is unrelated')),
3659 _('run even if remote repository is unrelated')),
3660 ('n', 'newest-first', None, _('show newest record first')),
3660 ('n', 'newest-first', None, _('show newest record first')),
3661 ('', 'bundle', '',
3661 ('', 'bundle', '',
3662 _('file to store the bundles into'), _('FILE')),
3662 _('file to store the bundles into'), _('FILE')),
3663 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3663 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3664 ('B', 'bookmarks', False, _("compare bookmarks")),
3664 ('B', 'bookmarks', False, _("compare bookmarks")),
3665 ('b', 'branch', [],
3665 ('b', 'branch', [],
3666 _('a specific branch you would like to pull'), _('BRANCH')),
3666 _('a specific branch you would like to pull'), _('BRANCH')),
3667 ] + logopts + remoteopts + subrepoopts,
3667 ] + logopts + remoteopts + subrepoopts,
3668 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3668 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3669 def incoming(ui, repo, source="default", **opts):
3669 def incoming(ui, repo, source="default", **opts):
3670 """show new changesets found in source
3670 """show new changesets found in source
3671
3671
3672 Show new changesets found in the specified path/URL or the default
3672 Show new changesets found in the specified path/URL or the default
3673 pull location. These are the changesets that would have been pulled
3673 pull location. These are the changesets that would have been pulled
3674 if a pull at the time you issued this command.
3674 if a pull at the time you issued this command.
3675
3675
3676 For remote repository, using --bundle avoids downloading the
3676 For remote repository, using --bundle avoids downloading the
3677 changesets twice if the incoming is followed by a pull.
3677 changesets twice if the incoming is followed by a pull.
3678
3678
3679 See pull for valid source format details.
3679 See pull for valid source format details.
3680
3680
3681 Returns 0 if there are incoming changes, 1 otherwise.
3681 Returns 0 if there are incoming changes, 1 otherwise.
3682 """
3682 """
3683 if opts.get('bundle') and opts.get('subrepos'):
3683 if opts.get('bundle') and opts.get('subrepos'):
3684 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3684 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3685
3685
3686 if opts.get('bookmarks'):
3686 if opts.get('bookmarks'):
3687 source, branches = hg.parseurl(ui.expandpath(source),
3687 source, branches = hg.parseurl(ui.expandpath(source),
3688 opts.get('branch'))
3688 opts.get('branch'))
3689 other = hg.peer(repo, opts, source)
3689 other = hg.peer(repo, opts, source)
3690 if 'bookmarks' not in other.listkeys('namespaces'):
3690 if 'bookmarks' not in other.listkeys('namespaces'):
3691 ui.warn(_("remote doesn't support bookmarks\n"))
3691 ui.warn(_("remote doesn't support bookmarks\n"))
3692 return 0
3692 return 0
3693 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3693 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3694 return bookmarks.diff(ui, repo, other)
3694 return bookmarks.diff(ui, repo, other)
3695
3695
3696 repo._subtoppath = ui.expandpath(source)
3696 repo._subtoppath = ui.expandpath(source)
3697 try:
3697 try:
3698 return hg.incoming(ui, repo, source, opts)
3698 return hg.incoming(ui, repo, source, opts)
3699 finally:
3699 finally:
3700 del repo._subtoppath
3700 del repo._subtoppath
3701
3701
3702
3702
3703 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3703 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3704 def init(ui, dest=".", **opts):
3704 def init(ui, dest=".", **opts):
3705 """create a new repository in the given directory
3705 """create a new repository in the given directory
3706
3706
3707 Initialize a new repository in the given directory. If the given
3707 Initialize a new repository in the given directory. If the given
3708 directory does not exist, it will be created.
3708 directory does not exist, it will be created.
3709
3709
3710 If no directory is given, the current directory is used.
3710 If no directory is given, the current directory is used.
3711
3711
3712 It is possible to specify an ``ssh://`` URL as the destination.
3712 It is possible to specify an ``ssh://`` URL as the destination.
3713 See :hg:`help urls` for more information.
3713 See :hg:`help urls` for more information.
3714
3714
3715 Returns 0 on success.
3715 Returns 0 on success.
3716 """
3716 """
3717 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3717 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3718
3718
3719 @command('locate',
3719 @command('locate',
3720 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3720 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3721 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3721 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3722 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3722 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3723 ] + walkopts,
3723 ] + walkopts,
3724 _('[OPTION]... [PATTERN]...'))
3724 _('[OPTION]... [PATTERN]...'))
3725 def locate(ui, repo, *pats, **opts):
3725 def locate(ui, repo, *pats, **opts):
3726 """locate files matching specific patterns
3726 """locate files matching specific patterns
3727
3727
3728 Print files under Mercurial control in the working directory whose
3728 Print files under Mercurial control in the working directory whose
3729 names match the given patterns.
3729 names match the given patterns.
3730
3730
3731 By default, this command searches all directories in the working
3731 By default, this command searches all directories in the working
3732 directory. To search just the current directory and its
3732 directory. To search just the current directory and its
3733 subdirectories, use "--include .".
3733 subdirectories, use "--include .".
3734
3734
3735 If no patterns are given to match, this command prints the names
3735 If no patterns are given to match, this command prints the names
3736 of all files under Mercurial control in the working directory.
3736 of all files under Mercurial control in the working directory.
3737
3737
3738 If you want to feed the output of this command into the "xargs"
3738 If you want to feed the output of this command into the "xargs"
3739 command, use the -0 option to both this command and "xargs". This
3739 command, use the -0 option to both this command and "xargs". This
3740 will avoid the problem of "xargs" treating single filenames that
3740 will avoid the problem of "xargs" treating single filenames that
3741 contain whitespace as multiple filenames.
3741 contain whitespace as multiple filenames.
3742
3742
3743 Returns 0 if a match is found, 1 otherwise.
3743 Returns 0 if a match is found, 1 otherwise.
3744 """
3744 """
3745 end = opts.get('print0') and '\0' or '\n'
3745 end = opts.get('print0') and '\0' or '\n'
3746 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3746 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3747
3747
3748 ret = 1
3748 ret = 1
3749 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3749 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3750 m.bad = lambda x, y: False
3750 m.bad = lambda x, y: False
3751 for abs in repo[rev].walk(m):
3751 for abs in repo[rev].walk(m):
3752 if not rev and abs not in repo.dirstate:
3752 if not rev and abs not in repo.dirstate:
3753 continue
3753 continue
3754 if opts.get('fullpath'):
3754 if opts.get('fullpath'):
3755 ui.write(repo.wjoin(abs), end)
3755 ui.write(repo.wjoin(abs), end)
3756 else:
3756 else:
3757 ui.write(((pats and m.rel(abs)) or abs), end)
3757 ui.write(((pats and m.rel(abs)) or abs), end)
3758 ret = 0
3758 ret = 0
3759
3759
3760 return ret
3760 return ret
3761
3761
3762 @command('^log|history',
3762 @command('^log|history',
3763 [('f', 'follow', None,
3763 [('f', 'follow', None,
3764 _('follow changeset history, or file history across copies and renames')),
3764 _('follow changeset history, or file history across copies and renames')),
3765 ('', 'follow-first', None,
3765 ('', 'follow-first', None,
3766 _('only follow the first parent of merge changesets (DEPRECATED)')),
3766 _('only follow the first parent of merge changesets (DEPRECATED)')),
3767 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3767 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3768 ('C', 'copies', None, _('show copied files')),
3768 ('C', 'copies', None, _('show copied files')),
3769 ('k', 'keyword', [],
3769 ('k', 'keyword', [],
3770 _('do case-insensitive search for a given text'), _('TEXT')),
3770 _('do case-insensitive search for a given text'), _('TEXT')),
3771 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3771 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3772 ('', 'removed', None, _('include revisions where files were removed')),
3772 ('', 'removed', None, _('include revisions where files were removed')),
3773 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3773 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3774 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3774 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3775 ('', 'only-branch', [],
3775 ('', 'only-branch', [],
3776 _('show only changesets within the given named branch (DEPRECATED)'),
3776 _('show only changesets within the given named branch (DEPRECATED)'),
3777 _('BRANCH')),
3777 _('BRANCH')),
3778 ('b', 'branch', [],
3778 ('b', 'branch', [],
3779 _('show changesets within the given named branch'), _('BRANCH')),
3779 _('show changesets within the given named branch'), _('BRANCH')),
3780 ('P', 'prune', [],
3780 ('P', 'prune', [],
3781 _('do not display revision or any of its ancestors'), _('REV')),
3781 _('do not display revision or any of its ancestors'), _('REV')),
3782 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3782 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3783 ] + logopts + walkopts,
3783 ] + logopts + walkopts,
3784 _('[OPTION]... [FILE]'))
3784 _('[OPTION]... [FILE]'))
3785 def log(ui, repo, *pats, **opts):
3785 def log(ui, repo, *pats, **opts):
3786 """show revision history of entire repository or files
3786 """show revision history of entire repository or files
3787
3787
3788 Print the revision history of the specified files or the entire
3788 Print the revision history of the specified files or the entire
3789 project.
3789 project.
3790
3790
3791 If no revision range is specified, the default is ``tip:0`` unless
3791 If no revision range is specified, the default is ``tip:0`` unless
3792 --follow is set, in which case the working directory parent is
3792 --follow is set, in which case the working directory parent is
3793 used as the starting revision.
3793 used as the starting revision.
3794
3794
3795 File history is shown without following rename or copy history of
3795 File history is shown without following rename or copy history of
3796 files. Use -f/--follow with a filename to follow history across
3796 files. Use -f/--follow with a filename to follow history across
3797 renames and copies. --follow without a filename will only show
3797 renames and copies. --follow without a filename will only show
3798 ancestors or descendants of the starting revision.
3798 ancestors or descendants of the starting revision.
3799
3799
3800 By default this command prints revision number and changeset id,
3800 By default this command prints revision number and changeset id,
3801 tags, non-trivial parents, user, date and time, and a summary for
3801 tags, non-trivial parents, user, date and time, and a summary for
3802 each commit. When the -v/--verbose switch is used, the list of
3802 each commit. When the -v/--verbose switch is used, the list of
3803 changed files and full commit message are shown.
3803 changed files and full commit message are shown.
3804
3804
3805 .. note::
3805 .. note::
3806 log -p/--patch may generate unexpected diff output for merge
3806 log -p/--patch may generate unexpected diff output for merge
3807 changesets, as it will only compare the merge changeset against
3807 changesets, as it will only compare the merge changeset against
3808 its first parent. Also, only files different from BOTH parents
3808 its first parent. Also, only files different from BOTH parents
3809 will appear in files:.
3809 will appear in files:.
3810
3810
3811 .. note::
3811 .. note::
3812 for performance reasons, log FILE may omit duplicate changes
3812 for performance reasons, log FILE may omit duplicate changes
3813 made on branches and will not show deletions. To see all
3813 made on branches and will not show deletions. To see all
3814 changes including duplicates and deletions, use the --removed
3814 changes including duplicates and deletions, use the --removed
3815 switch.
3815 switch.
3816
3816
3817 .. container:: verbose
3817 .. container:: verbose
3818
3818
3819 Some examples:
3819 Some examples:
3820
3820
3821 - changesets with full descriptions and file lists::
3821 - changesets with full descriptions and file lists::
3822
3822
3823 hg log -v
3823 hg log -v
3824
3824
3825 - changesets ancestral to the working directory::
3825 - changesets ancestral to the working directory::
3826
3826
3827 hg log -f
3827 hg log -f
3828
3828
3829 - last 10 commits on the current branch::
3829 - last 10 commits on the current branch::
3830
3830
3831 hg log -l 10 -b .
3831 hg log -l 10 -b .
3832
3832
3833 - changesets showing all modifications of a file, including removals::
3833 - changesets showing all modifications of a file, including removals::
3834
3834
3835 hg log --removed file.c
3835 hg log --removed file.c
3836
3836
3837 - all changesets that touch a directory, with diffs, excluding merges::
3837 - all changesets that touch a directory, with diffs, excluding merges::
3838
3838
3839 hg log -Mp lib/
3839 hg log -Mp lib/
3840
3840
3841 - all revision numbers that match a keyword::
3841 - all revision numbers that match a keyword::
3842
3842
3843 hg log -k bug --template "{rev}\\n"
3843 hg log -k bug --template "{rev}\\n"
3844
3844
3845 - check if a given changeset is included is a tagged release::
3845 - check if a given changeset is included is a tagged release::
3846
3846
3847 hg log -r "a21ccf and ancestor(1.9)"
3847 hg log -r "a21ccf and ancestor(1.9)"
3848
3848
3849 - find all changesets by some user in a date range::
3849 - find all changesets by some user in a date range::
3850
3850
3851 hg log -k alice -d "may 2008 to jul 2008"
3851 hg log -k alice -d "may 2008 to jul 2008"
3852
3852
3853 - summary of all changesets after the last tag::
3853 - summary of all changesets after the last tag::
3854
3854
3855 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3855 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3856
3856
3857 See :hg:`help dates` for a list of formats valid for -d/--date.
3857 See :hg:`help dates` for a list of formats valid for -d/--date.
3858
3858
3859 See :hg:`help revisions` and :hg:`help revsets` for more about
3859 See :hg:`help revisions` and :hg:`help revsets` for more about
3860 specifying revisions.
3860 specifying revisions.
3861
3861
3862 Returns 0 on success.
3862 Returns 0 on success.
3863 """
3863 """
3864
3864
3865 matchfn = scmutil.match(repo[None], pats, opts)
3865 matchfn = scmutil.match(repo[None], pats, opts)
3866 limit = cmdutil.loglimit(opts)
3866 limit = cmdutil.loglimit(opts)
3867 count = 0
3867 count = 0
3868
3868
3869 endrev = None
3869 endrev = None
3870 if opts.get('copies') and opts.get('rev'):
3870 if opts.get('copies') and opts.get('rev'):
3871 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3871 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
3872
3872
3873 df = False
3873 df = False
3874 if opts["date"]:
3874 if opts["date"]:
3875 df = util.matchdate(opts["date"])
3875 df = util.matchdate(opts["date"])
3876
3876
3877 branches = opts.get('branch', []) + opts.get('only_branch', [])
3877 branches = opts.get('branch', []) + opts.get('only_branch', [])
3878 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3878 opts['branch'] = [repo.lookupbranch(b) for b in branches]
3879
3879
3880 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3880 displayer = cmdutil.show_changeset(ui, repo, opts, True)
3881 def prep(ctx, fns):
3881 def prep(ctx, fns):
3882 rev = ctx.rev()
3882 rev = ctx.rev()
3883 parents = [p for p in repo.changelog.parentrevs(rev)
3883 parents = [p for p in repo.changelog.parentrevs(rev)
3884 if p != nullrev]
3884 if p != nullrev]
3885 if opts.get('no_merges') and len(parents) == 2:
3885 if opts.get('no_merges') and len(parents) == 2:
3886 return
3886 return
3887 if opts.get('only_merges') and len(parents) != 2:
3887 if opts.get('only_merges') and len(parents) != 2:
3888 return
3888 return
3889 if opts.get('branch') and ctx.branch() not in opts['branch']:
3889 if opts.get('branch') and ctx.branch() not in opts['branch']:
3890 return
3890 return
3891 if not opts.get('hidden') and ctx.hidden():
3891 if not opts.get('hidden') and ctx.hidden():
3892 return
3892 return
3893 if df and not df(ctx.date()[0]):
3893 if df and not df(ctx.date()[0]):
3894 return
3894 return
3895 if opts['user'] and not [k for k in opts['user']
3895 if opts['user'] and not [k for k in opts['user']
3896 if k.lower() in ctx.user().lower()]:
3896 if k.lower() in ctx.user().lower()]:
3897 return
3897 return
3898 if opts.get('keyword'):
3898 if opts.get('keyword'):
3899 for k in [kw.lower() for kw in opts['keyword']]:
3899 for k in [kw.lower() for kw in opts['keyword']]:
3900 if (k in ctx.user().lower() or
3900 if (k in ctx.user().lower() or
3901 k in ctx.description().lower() or
3901 k in ctx.description().lower() or
3902 k in " ".join(ctx.files()).lower()):
3902 k in " ".join(ctx.files()).lower()):
3903 break
3903 break
3904 else:
3904 else:
3905 return
3905 return
3906
3906
3907 copies = None
3907 copies = None
3908 if opts.get('copies') and rev:
3908 if opts.get('copies') and rev:
3909 copies = []
3909 copies = []
3910 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3910 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3911 for fn in ctx.files():
3911 for fn in ctx.files():
3912 rename = getrenamed(fn, rev)
3912 rename = getrenamed(fn, rev)
3913 if rename:
3913 if rename:
3914 copies.append((fn, rename[0]))
3914 copies.append((fn, rename[0]))
3915
3915
3916 revmatchfn = None
3916 revmatchfn = None
3917 if opts.get('patch') or opts.get('stat'):
3917 if opts.get('patch') or opts.get('stat'):
3918 if opts.get('follow') or opts.get('follow_first'):
3918 if opts.get('follow') or opts.get('follow_first'):
3919 # note: this might be wrong when following through merges
3919 # note: this might be wrong when following through merges
3920 revmatchfn = scmutil.match(repo[None], fns, default='path')
3920 revmatchfn = scmutil.match(repo[None], fns, default='path')
3921 else:
3921 else:
3922 revmatchfn = matchfn
3922 revmatchfn = matchfn
3923
3923
3924 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3924 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3925
3925
3926 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3926 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3927 if count == limit:
3927 if count == limit:
3928 break
3928 break
3929 if displayer.flush(ctx.rev()):
3929 if displayer.flush(ctx.rev()):
3930 count += 1
3930 count += 1
3931 displayer.close()
3931 displayer.close()
3932
3932
3933 @command('manifest',
3933 @command('manifest',
3934 [('r', 'rev', '', _('revision to display'), _('REV')),
3934 [('r', 'rev', '', _('revision to display'), _('REV')),
3935 ('', 'all', False, _("list files from all revisions"))],
3935 ('', 'all', False, _("list files from all revisions"))],
3936 _('[-r REV]'))
3936 _('[-r REV]'))
3937 def manifest(ui, repo, node=None, rev=None, **opts):
3937 def manifest(ui, repo, node=None, rev=None, **opts):
3938 """output the current or given revision of the project manifest
3938 """output the current or given revision of the project manifest
3939
3939
3940 Print a list of version controlled files for the given revision.
3940 Print a list of version controlled files for the given revision.
3941 If no revision is given, the first parent of the working directory
3941 If no revision is given, the first parent of the working directory
3942 is used, or the null revision if no revision is checked out.
3942 is used, or the null revision if no revision is checked out.
3943
3943
3944 With -v, print file permissions, symlink and executable bits.
3944 With -v, print file permissions, symlink and executable bits.
3945 With --debug, print file revision hashes.
3945 With --debug, print file revision hashes.
3946
3946
3947 If option --all is specified, the list of all files from all revisions
3947 If option --all is specified, the list of all files from all revisions
3948 is printed. This includes deleted and renamed files.
3948 is printed. This includes deleted and renamed files.
3949
3949
3950 Returns 0 on success.
3950 Returns 0 on success.
3951 """
3951 """
3952 if opts.get('all'):
3952 if opts.get('all'):
3953 if rev or node:
3953 if rev or node:
3954 raise util.Abort(_("can't specify a revision with --all"))
3954 raise util.Abort(_("can't specify a revision with --all"))
3955
3955
3956 res = []
3956 res = []
3957 prefix = "data/"
3957 prefix = "data/"
3958 suffix = ".i"
3958 suffix = ".i"
3959 plen = len(prefix)
3959 plen = len(prefix)
3960 slen = len(suffix)
3960 slen = len(suffix)
3961 lock = repo.lock()
3961 lock = repo.lock()
3962 try:
3962 try:
3963 for fn, b, size in repo.store.datafiles():
3963 for fn, b, size in repo.store.datafiles():
3964 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3964 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3965 res.append(fn[plen:-slen])
3965 res.append(fn[plen:-slen])
3966 finally:
3966 finally:
3967 lock.release()
3967 lock.release()
3968 for f in sorted(res):
3968 for f in sorted(res):
3969 ui.write("%s\n" % f)
3969 ui.write("%s\n" % f)
3970 return
3970 return
3971
3971
3972 if rev and node:
3972 if rev and node:
3973 raise util.Abort(_("please specify just one revision"))
3973 raise util.Abort(_("please specify just one revision"))
3974
3974
3975 if not node:
3975 if not node:
3976 node = rev
3976 node = rev
3977
3977
3978 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3978 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
3979 ctx = scmutil.revsingle(repo, node)
3979 ctx = scmutil.revsingle(repo, node)
3980 for f in ctx:
3980 for f in ctx:
3981 if ui.debugflag:
3981 if ui.debugflag:
3982 ui.write("%40s " % hex(ctx.manifest()[f]))
3982 ui.write("%40s " % hex(ctx.manifest()[f]))
3983 if ui.verbose:
3983 if ui.verbose:
3984 ui.write(decor[ctx.flags(f)])
3984 ui.write(decor[ctx.flags(f)])
3985 ui.write("%s\n" % f)
3985 ui.write("%s\n" % f)
3986
3986
3987 @command('^merge',
3987 @command('^merge',
3988 [('f', 'force', None, _('force a merge with outstanding changes')),
3988 [('f', 'force', None, _('force a merge with outstanding changes')),
3989 ('r', 'rev', '', _('revision to merge'), _('REV')),
3989 ('r', 'rev', '', _('revision to merge'), _('REV')),
3990 ('P', 'preview', None,
3990 ('P', 'preview', None,
3991 _('review revisions to merge (no merge is performed)'))
3991 _('review revisions to merge (no merge is performed)'))
3992 ] + mergetoolopts,
3992 ] + mergetoolopts,
3993 _('[-P] [-f] [[-r] REV]'))
3993 _('[-P] [-f] [[-r] REV]'))
3994 def merge(ui, repo, node=None, **opts):
3994 def merge(ui, repo, node=None, **opts):
3995 """merge working directory with another revision
3995 """merge working directory with another revision
3996
3996
3997 The current working directory is updated with all changes made in
3997 The current working directory is updated with all changes made in
3998 the requested revision since the last common predecessor revision.
3998 the requested revision since the last common predecessor revision.
3999
3999
4000 Files that changed between either parent are marked as changed for
4000 Files that changed between either parent are marked as changed for
4001 the next commit and a commit must be performed before any further
4001 the next commit and a commit must be performed before any further
4002 updates to the repository are allowed. The next commit will have
4002 updates to the repository are allowed. The next commit will have
4003 two parents.
4003 two parents.
4004
4004
4005 ``--tool`` can be used to specify the merge tool used for file
4005 ``--tool`` can be used to specify the merge tool used for file
4006 merges. It overrides the HGMERGE environment variable and your
4006 merges. It overrides the HGMERGE environment variable and your
4007 configuration files. See :hg:`help merge-tools` for options.
4007 configuration files. See :hg:`help merge-tools` for options.
4008
4008
4009 If no revision is specified, the working directory's parent is a
4009 If no revision is specified, the working directory's parent is a
4010 head revision, and the current branch contains exactly one other
4010 head revision, and the current branch contains exactly one other
4011 head, the other head is merged with by default. Otherwise, an
4011 head, the other head is merged with by default. Otherwise, an
4012 explicit revision with which to merge with must be provided.
4012 explicit revision with which to merge with must be provided.
4013
4013
4014 :hg:`resolve` must be used to resolve unresolved files.
4014 :hg:`resolve` must be used to resolve unresolved files.
4015
4015
4016 To undo an uncommitted merge, use :hg:`update --clean .` which
4016 To undo an uncommitted merge, use :hg:`update --clean .` which
4017 will check out a clean copy of the original merge parent, losing
4017 will check out a clean copy of the original merge parent, losing
4018 all changes.
4018 all changes.
4019
4019
4020 Returns 0 on success, 1 if there are unresolved files.
4020 Returns 0 on success, 1 if there are unresolved files.
4021 """
4021 """
4022
4022
4023 if opts.get('rev') and node:
4023 if opts.get('rev') and node:
4024 raise util.Abort(_("please specify just one revision"))
4024 raise util.Abort(_("please specify just one revision"))
4025 if not node:
4025 if not node:
4026 node = opts.get('rev')
4026 node = opts.get('rev')
4027
4027
4028 if not node:
4028 if not node:
4029 branch = repo[None].branch()
4029 branch = repo[None].branch()
4030 bheads = repo.branchheads(branch)
4030 bheads = repo.branchheads(branch)
4031 if len(bheads) > 2:
4031 if len(bheads) > 2:
4032 raise util.Abort(_("branch '%s' has %d heads - "
4032 raise util.Abort(_("branch '%s' has %d heads - "
4033 "please merge with an explicit rev")
4033 "please merge with an explicit rev")
4034 % (branch, len(bheads)),
4034 % (branch, len(bheads)),
4035 hint=_("run 'hg heads .' to see heads"))
4035 hint=_("run 'hg heads .' to see heads"))
4036
4036
4037 parent = repo.dirstate.p1()
4037 parent = repo.dirstate.p1()
4038 if len(bheads) == 1:
4038 if len(bheads) == 1:
4039 if len(repo.heads()) > 1:
4039 if len(repo.heads()) > 1:
4040 raise util.Abort(_("branch '%s' has one head - "
4040 raise util.Abort(_("branch '%s' has one head - "
4041 "please merge with an explicit rev")
4041 "please merge with an explicit rev")
4042 % branch,
4042 % branch,
4043 hint=_("run 'hg heads' to see all heads"))
4043 hint=_("run 'hg heads' to see all heads"))
4044 msg = _('there is nothing to merge')
4044 msg = _('there is nothing to merge')
4045 if parent != repo.lookup(repo[None].branch()):
4045 if parent != repo.lookup(repo[None].branch()):
4046 msg = _('%s - use "hg update" instead') % msg
4046 msg = _('%s - use "hg update" instead') % msg
4047 raise util.Abort(msg)
4047 raise util.Abort(msg)
4048
4048
4049 if parent not in bheads:
4049 if parent not in bheads:
4050 raise util.Abort(_('working directory not at a head revision'),
4050 raise util.Abort(_('working directory not at a head revision'),
4051 hint=_("use 'hg update' or merge with an "
4051 hint=_("use 'hg update' or merge with an "
4052 "explicit revision"))
4052 "explicit revision"))
4053 node = parent == bheads[0] and bheads[-1] or bheads[0]
4053 node = parent == bheads[0] and bheads[-1] or bheads[0]
4054 else:
4054 else:
4055 node = scmutil.revsingle(repo, node).node()
4055 node = scmutil.revsingle(repo, node).node()
4056
4056
4057 if opts.get('preview'):
4057 if opts.get('preview'):
4058 # find nodes that are ancestors of p2 but not of p1
4058 # find nodes that are ancestors of p2 but not of p1
4059 p1 = repo.lookup('.')
4059 p1 = repo.lookup('.')
4060 p2 = repo.lookup(node)
4060 p2 = repo.lookup(node)
4061 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4061 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4062
4062
4063 displayer = cmdutil.show_changeset(ui, repo, opts)
4063 displayer = cmdutil.show_changeset(ui, repo, opts)
4064 for node in nodes:
4064 for node in nodes:
4065 displayer.show(repo[node])
4065 displayer.show(repo[node])
4066 displayer.close()
4066 displayer.close()
4067 return 0
4067 return 0
4068
4068
4069 try:
4069 try:
4070 # ui.forcemerge is an internal variable, do not document
4070 # ui.forcemerge is an internal variable, do not document
4071 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4071 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4072 return hg.merge(repo, node, force=opts.get('force'))
4072 return hg.merge(repo, node, force=opts.get('force'))
4073 finally:
4073 finally:
4074 ui.setconfig('ui', 'forcemerge', '')
4074 ui.setconfig('ui', 'forcemerge', '')
4075
4075
4076 @command('outgoing|out',
4076 @command('outgoing|out',
4077 [('f', 'force', None, _('run even when the destination is unrelated')),
4077 [('f', 'force', None, _('run even when the destination is unrelated')),
4078 ('r', 'rev', [],
4078 ('r', 'rev', [],
4079 _('a changeset intended to be included in the destination'), _('REV')),
4079 _('a changeset intended to be included in the destination'), _('REV')),
4080 ('n', 'newest-first', None, _('show newest record first')),
4080 ('n', 'newest-first', None, _('show newest record first')),
4081 ('B', 'bookmarks', False, _('compare bookmarks')),
4081 ('B', 'bookmarks', False, _('compare bookmarks')),
4082 ('b', 'branch', [], _('a specific branch you would like to push'),
4082 ('b', 'branch', [], _('a specific branch you would like to push'),
4083 _('BRANCH')),
4083 _('BRANCH')),
4084 ] + logopts + remoteopts + subrepoopts,
4084 ] + logopts + remoteopts + subrepoopts,
4085 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4085 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4086 def outgoing(ui, repo, dest=None, **opts):
4086 def outgoing(ui, repo, dest=None, **opts):
4087 """show changesets not found in the destination
4087 """show changesets not found in the destination
4088
4088
4089 Show changesets not found in the specified destination repository
4089 Show changesets not found in the specified destination repository
4090 or the default push location. These are the changesets that would
4090 or the default push location. These are the changesets that would
4091 be pushed if a push was requested.
4091 be pushed if a push was requested.
4092
4092
4093 See pull for details of valid destination formats.
4093 See pull for details of valid destination formats.
4094
4094
4095 Returns 0 if there are outgoing changes, 1 otherwise.
4095 Returns 0 if there are outgoing changes, 1 otherwise.
4096 """
4096 """
4097
4097
4098 if opts.get('bookmarks'):
4098 if opts.get('bookmarks'):
4099 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4099 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4100 dest, branches = hg.parseurl(dest, opts.get('branch'))
4100 dest, branches = hg.parseurl(dest, opts.get('branch'))
4101 other = hg.peer(repo, opts, dest)
4101 other = hg.peer(repo, opts, dest)
4102 if 'bookmarks' not in other.listkeys('namespaces'):
4102 if 'bookmarks' not in other.listkeys('namespaces'):
4103 ui.warn(_("remote doesn't support bookmarks\n"))
4103 ui.warn(_("remote doesn't support bookmarks\n"))
4104 return 0
4104 return 0
4105 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4105 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4106 return bookmarks.diff(ui, other, repo)
4106 return bookmarks.diff(ui, other, repo)
4107
4107
4108 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4108 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4109 try:
4109 try:
4110 return hg.outgoing(ui, repo, dest, opts)
4110 return hg.outgoing(ui, repo, dest, opts)
4111 finally:
4111 finally:
4112 del repo._subtoppath
4112 del repo._subtoppath
4113
4113
4114 @command('parents',
4114 @command('parents',
4115 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4115 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4116 ] + templateopts,
4116 ] + templateopts,
4117 _('[-r REV] [FILE]'))
4117 _('[-r REV] [FILE]'))
4118 def parents(ui, repo, file_=None, **opts):
4118 def parents(ui, repo, file_=None, **opts):
4119 """show the parents of the working directory or revision
4119 """show the parents of the working directory or revision
4120
4120
4121 Print the working directory's parent revisions. If a revision is
4121 Print the working directory's parent revisions. If a revision is
4122 given via -r/--rev, the parent of that revision will be printed.
4122 given via -r/--rev, the parent of that revision will be printed.
4123 If a file argument is given, the revision in which the file was
4123 If a file argument is given, the revision in which the file was
4124 last changed (before the working directory revision or the
4124 last changed (before the working directory revision or the
4125 argument to --rev if given) is printed.
4125 argument to --rev if given) is printed.
4126
4126
4127 Returns 0 on success.
4127 Returns 0 on success.
4128 """
4128 """
4129
4129
4130 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4130 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4131
4131
4132 if file_:
4132 if file_:
4133 m = scmutil.match(ctx, (file_,), opts)
4133 m = scmutil.match(ctx, (file_,), opts)
4134 if m.anypats() or len(m.files()) != 1:
4134 if m.anypats() or len(m.files()) != 1:
4135 raise util.Abort(_('can only specify an explicit filename'))
4135 raise util.Abort(_('can only specify an explicit filename'))
4136 file_ = m.files()[0]
4136 file_ = m.files()[0]
4137 filenodes = []
4137 filenodes = []
4138 for cp in ctx.parents():
4138 for cp in ctx.parents():
4139 if not cp:
4139 if not cp:
4140 continue
4140 continue
4141 try:
4141 try:
4142 filenodes.append(cp.filenode(file_))
4142 filenodes.append(cp.filenode(file_))
4143 except error.LookupError:
4143 except error.LookupError:
4144 pass
4144 pass
4145 if not filenodes:
4145 if not filenodes:
4146 raise util.Abort(_("'%s' not found in manifest!") % file_)
4146 raise util.Abort(_("'%s' not found in manifest!") % file_)
4147 fl = repo.file(file_)
4147 fl = repo.file(file_)
4148 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4148 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4149 else:
4149 else:
4150 p = [cp.node() for cp in ctx.parents()]
4150 p = [cp.node() for cp in ctx.parents()]
4151
4151
4152 displayer = cmdutil.show_changeset(ui, repo, opts)
4152 displayer = cmdutil.show_changeset(ui, repo, opts)
4153 for n in p:
4153 for n in p:
4154 if n != nullid:
4154 if n != nullid:
4155 displayer.show(repo[n])
4155 displayer.show(repo[n])
4156 displayer.close()
4156 displayer.close()
4157
4157
4158 @command('paths', [], _('[NAME]'))
4158 @command('paths', [], _('[NAME]'))
4159 def paths(ui, repo, search=None):
4159 def paths(ui, repo, search=None):
4160 """show aliases for remote repositories
4160 """show aliases for remote repositories
4161
4161
4162 Show definition of symbolic path name NAME. If no name is given,
4162 Show definition of symbolic path name NAME. If no name is given,
4163 show definition of all available names.
4163 show definition of all available names.
4164
4164
4165 Option -q/--quiet suppresses all output when searching for NAME
4165 Option -q/--quiet suppresses all output when searching for NAME
4166 and shows only the path names when listing all definitions.
4166 and shows only the path names when listing all definitions.
4167
4167
4168 Path names are defined in the [paths] section of your
4168 Path names are defined in the [paths] section of your
4169 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4169 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4170 repository, ``.hg/hgrc`` is used, too.
4170 repository, ``.hg/hgrc`` is used, too.
4171
4171
4172 The path names ``default`` and ``default-push`` have a special
4172 The path names ``default`` and ``default-push`` have a special
4173 meaning. When performing a push or pull operation, they are used
4173 meaning. When performing a push or pull operation, they are used
4174 as fallbacks if no location is specified on the command-line.
4174 as fallbacks if no location is specified on the command-line.
4175 When ``default-push`` is set, it will be used for push and
4175 When ``default-push`` is set, it will be used for push and
4176 ``default`` will be used for pull; otherwise ``default`` is used
4176 ``default`` will be used for pull; otherwise ``default`` is used
4177 as the fallback for both. When cloning a repository, the clone
4177 as the fallback for both. When cloning a repository, the clone
4178 source is written as ``default`` in ``.hg/hgrc``. Note that
4178 source is written as ``default`` in ``.hg/hgrc``. Note that
4179 ``default`` and ``default-push`` apply to all inbound (e.g.
4179 ``default`` and ``default-push`` apply to all inbound (e.g.
4180 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4180 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4181 :hg:`bundle`) operations.
4181 :hg:`bundle`) operations.
4182
4182
4183 See :hg:`help urls` for more information.
4183 See :hg:`help urls` for more information.
4184
4184
4185 Returns 0 on success.
4185 Returns 0 on success.
4186 """
4186 """
4187 if search:
4187 if search:
4188 for name, path in ui.configitems("paths"):
4188 for name, path in ui.configitems("paths"):
4189 if name == search:
4189 if name == search:
4190 ui.status("%s\n" % util.hidepassword(path))
4190 ui.status("%s\n" % util.hidepassword(path))
4191 return
4191 return
4192 if not ui.quiet:
4192 if not ui.quiet:
4193 ui.warn(_("not found!\n"))
4193 ui.warn(_("not found!\n"))
4194 return 1
4194 return 1
4195 else:
4195 else:
4196 for name, path in ui.configitems("paths"):
4196 for name, path in ui.configitems("paths"):
4197 if ui.quiet:
4197 if ui.quiet:
4198 ui.write("%s\n" % name)
4198 ui.write("%s\n" % name)
4199 else:
4199 else:
4200 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4200 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4201
4201
4202 def postincoming(ui, repo, modheads, optupdate, checkout):
4202 def postincoming(ui, repo, modheads, optupdate, checkout):
4203 if modheads == 0:
4203 if modheads == 0:
4204 return
4204 return
4205 if optupdate:
4205 if optupdate:
4206 try:
4206 try:
4207 return hg.update(repo, checkout)
4207 return hg.update(repo, checkout)
4208 except util.Abort, inst:
4208 except util.Abort, inst:
4209 ui.warn(_("not updating: %s\n" % str(inst)))
4209 ui.warn(_("not updating: %s\n" % str(inst)))
4210 return 0
4210 return 0
4211 if modheads > 1:
4211 if modheads > 1:
4212 currentbranchheads = len(repo.branchheads())
4212 currentbranchheads = len(repo.branchheads())
4213 if currentbranchheads == modheads:
4213 if currentbranchheads == modheads:
4214 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4214 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4215 elif currentbranchheads > 1:
4215 elif currentbranchheads > 1:
4216 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4216 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
4217 else:
4217 else:
4218 ui.status(_("(run 'hg heads' to see heads)\n"))
4218 ui.status(_("(run 'hg heads' to see heads)\n"))
4219 else:
4219 else:
4220 ui.status(_("(run 'hg update' to get a working copy)\n"))
4220 ui.status(_("(run 'hg update' to get a working copy)\n"))
4221
4221
4222 @command('^pull',
4222 @command('^pull',
4223 [('u', 'update', None,
4223 [('u', 'update', None,
4224 _('update to new branch head if changesets were pulled')),
4224 _('update to new branch head if changesets were pulled')),
4225 ('f', 'force', None, _('run even when remote repository is unrelated')),
4225 ('f', 'force', None, _('run even when remote repository is unrelated')),
4226 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4226 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4227 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4227 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4228 ('b', 'branch', [], _('a specific branch you would like to pull'),
4228 ('b', 'branch', [], _('a specific branch you would like to pull'),
4229 _('BRANCH')),
4229 _('BRANCH')),
4230 ] + remoteopts,
4230 ] + remoteopts,
4231 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4231 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4232 def pull(ui, repo, source="default", **opts):
4232 def pull(ui, repo, source="default", **opts):
4233 """pull changes from the specified source
4233 """pull changes from the specified source
4234
4234
4235 Pull changes from a remote repository to a local one.
4235 Pull changes from a remote repository to a local one.
4236
4236
4237 This finds all changes from the repository at the specified path
4237 This finds all changes from the repository at the specified path
4238 or URL and adds them to a local repository (the current one unless
4238 or URL and adds them to a local repository (the current one unless
4239 -R is specified). By default, this does not update the copy of the
4239 -R is specified). By default, this does not update the copy of the
4240 project in the working directory.
4240 project in the working directory.
4241
4241
4242 Use :hg:`incoming` if you want to see what would have been added
4242 Use :hg:`incoming` if you want to see what would have been added
4243 by a pull at the time you issued this command. If you then decide
4243 by a pull at the time you issued this command. If you then decide
4244 to add those changes to the repository, you should use :hg:`pull
4244 to add those changes to the repository, you should use :hg:`pull
4245 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4245 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4246
4246
4247 If SOURCE is omitted, the 'default' path will be used.
4247 If SOURCE is omitted, the 'default' path will be used.
4248 See :hg:`help urls` for more information.
4248 See :hg:`help urls` for more information.
4249
4249
4250 Returns 0 on success, 1 if an update had unresolved files.
4250 Returns 0 on success, 1 if an update had unresolved files.
4251 """
4251 """
4252 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4252 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4253 other = hg.peer(repo, opts, source)
4253 other = hg.peer(repo, opts, source)
4254 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4254 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4255 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4255 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4256
4256
4257 if opts.get('bookmark'):
4257 if opts.get('bookmark'):
4258 if not revs:
4258 if not revs:
4259 revs = []
4259 revs = []
4260 rb = other.listkeys('bookmarks')
4260 rb = other.listkeys('bookmarks')
4261 for b in opts['bookmark']:
4261 for b in opts['bookmark']:
4262 if b not in rb:
4262 if b not in rb:
4263 raise util.Abort(_('remote bookmark %s not found!') % b)
4263 raise util.Abort(_('remote bookmark %s not found!') % b)
4264 revs.append(rb[b])
4264 revs.append(rb[b])
4265
4265
4266 if revs:
4266 if revs:
4267 try:
4267 try:
4268 revs = [other.lookup(rev) for rev in revs]
4268 revs = [other.lookup(rev) for rev in revs]
4269 except error.CapabilityError:
4269 except error.CapabilityError:
4270 err = _("other repository doesn't support revision lookup, "
4270 err = _("other repository doesn't support revision lookup, "
4271 "so a rev cannot be specified.")
4271 "so a rev cannot be specified.")
4272 raise util.Abort(err)
4272 raise util.Abort(err)
4273
4273
4274 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4274 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4275 bookmarks.updatefromremote(ui, repo, other)
4275 bookmarks.updatefromremote(ui, repo, other)
4276 if checkout:
4276 if checkout:
4277 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4277 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4278 repo._subtoppath = source
4278 repo._subtoppath = source
4279 try:
4279 try:
4280 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4280 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4281
4281
4282 finally:
4282 finally:
4283 del repo._subtoppath
4283 del repo._subtoppath
4284
4284
4285 # update specified bookmarks
4285 # update specified bookmarks
4286 if opts.get('bookmark'):
4286 if opts.get('bookmark'):
4287 for b in opts['bookmark']:
4287 for b in opts['bookmark']:
4288 # explicit pull overrides local bookmark if any
4288 # explicit pull overrides local bookmark if any
4289 ui.status(_("importing bookmark %s\n") % b)
4289 ui.status(_("importing bookmark %s\n") % b)
4290 repo._bookmarks[b] = repo[rb[b]].node()
4290 repo._bookmarks[b] = repo[rb[b]].node()
4291 bookmarks.write(repo)
4291 bookmarks.write(repo)
4292
4292
4293 return ret
4293 return ret
4294
4294
4295 @command('^push',
4295 @command('^push',
4296 [('f', 'force', None, _('force push')),
4296 [('f', 'force', None, _('force push')),
4297 ('r', 'rev', [],
4297 ('r', 'rev', [],
4298 _('a changeset intended to be included in the destination'),
4298 _('a changeset intended to be included in the destination'),
4299 _('REV')),
4299 _('REV')),
4300 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4300 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4301 ('b', 'branch', [],
4301 ('b', 'branch', [],
4302 _('a specific branch you would like to push'), _('BRANCH')),
4302 _('a specific branch you would like to push'), _('BRANCH')),
4303 ('', 'new-branch', False, _('allow pushing a new branch')),
4303 ('', 'new-branch', False, _('allow pushing a new branch')),
4304 ] + remoteopts,
4304 ] + remoteopts,
4305 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4305 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4306 def push(ui, repo, dest=None, **opts):
4306 def push(ui, repo, dest=None, **opts):
4307 """push changes to the specified destination
4307 """push changes to the specified destination
4308
4308
4309 Push changesets from the local repository to the specified
4309 Push changesets from the local repository to the specified
4310 destination.
4310 destination.
4311
4311
4312 This operation is symmetrical to pull: it is identical to a pull
4312 This operation is symmetrical to pull: it is identical to a pull
4313 in the destination repository from the current one.
4313 in the destination repository from the current one.
4314
4314
4315 By default, push will not allow creation of new heads at the
4315 By default, push will not allow creation of new heads at the
4316 destination, since multiple heads would make it unclear which head
4316 destination, since multiple heads would make it unclear which head
4317 to use. In this situation, it is recommended to pull and merge
4317 to use. In this situation, it is recommended to pull and merge
4318 before pushing.
4318 before pushing.
4319
4319
4320 Use --new-branch if you want to allow push to create a new named
4320 Use --new-branch if you want to allow push to create a new named
4321 branch that is not present at the destination. This allows you to
4321 branch that is not present at the destination. This allows you to
4322 only create a new branch without forcing other changes.
4322 only create a new branch without forcing other changes.
4323
4323
4324 Use -f/--force to override the default behavior and push all
4324 Use -f/--force to override the default behavior and push all
4325 changesets on all branches.
4325 changesets on all branches.
4326
4326
4327 If -r/--rev is used, the specified revision and all its ancestors
4327 If -r/--rev is used, the specified revision and all its ancestors
4328 will be pushed to the remote repository.
4328 will be pushed to the remote repository.
4329
4329
4330 Please see :hg:`help urls` for important details about ``ssh://``
4330 Please see :hg:`help urls` for important details about ``ssh://``
4331 URLs. If DESTINATION is omitted, a default path will be used.
4331 URLs. If DESTINATION is omitted, a default path will be used.
4332
4332
4333 Returns 0 if push was successful, 1 if nothing to push.
4333 Returns 0 if push was successful, 1 if nothing to push.
4334 """
4334 """
4335
4335
4336 if opts.get('bookmark'):
4336 if opts.get('bookmark'):
4337 for b in opts['bookmark']:
4337 for b in opts['bookmark']:
4338 # translate -B options to -r so changesets get pushed
4338 # translate -B options to -r so changesets get pushed
4339 if b in repo._bookmarks:
4339 if b in repo._bookmarks:
4340 opts.setdefault('rev', []).append(b)
4340 opts.setdefault('rev', []).append(b)
4341 else:
4341 else:
4342 # if we try to push a deleted bookmark, translate it to null
4342 # if we try to push a deleted bookmark, translate it to null
4343 # this lets simultaneous -r, -b options continue working
4343 # this lets simultaneous -r, -b options continue working
4344 opts.setdefault('rev', []).append("null")
4344 opts.setdefault('rev', []).append("null")
4345
4345
4346 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4346 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4347 dest, branches = hg.parseurl(dest, opts.get('branch'))
4347 dest, branches = hg.parseurl(dest, opts.get('branch'))
4348 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4348 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4349 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4349 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4350 other = hg.peer(repo, opts, dest)
4350 other = hg.peer(repo, opts, dest)
4351 if revs:
4351 if revs:
4352 revs = [repo.lookup(rev) for rev in revs]
4352 revs = [repo.lookup(rev) for rev in revs]
4353
4353
4354 repo._subtoppath = dest
4354 repo._subtoppath = dest
4355 try:
4355 try:
4356 # push subrepos depth-first for coherent ordering
4356 # push subrepos depth-first for coherent ordering
4357 c = repo['']
4357 c = repo['']
4358 subs = c.substate # only repos that are committed
4358 subs = c.substate # only repos that are committed
4359 for s in sorted(subs):
4359 for s in sorted(subs):
4360 if not c.sub(s).push(opts.get('force')):
4360 if not c.sub(s).push(opts.get('force')):
4361 return False
4361 return False
4362 finally:
4362 finally:
4363 del repo._subtoppath
4363 del repo._subtoppath
4364 result = repo.push(other, opts.get('force'), revs=revs,
4364 result = repo.push(other, opts.get('force'), revs=revs,
4365 newbranch=opts.get('new_branch'))
4365 newbranch=opts.get('new_branch'))
4366
4366
4367 result = (result == 0)
4367 result = (result == 0)
4368
4368
4369 if opts.get('bookmark'):
4369 if opts.get('bookmark'):
4370 rb = other.listkeys('bookmarks')
4370 rb = other.listkeys('bookmarks')
4371 for b in opts['bookmark']:
4371 for b in opts['bookmark']:
4372 # explicit push overrides remote bookmark if any
4372 # explicit push overrides remote bookmark if any
4373 if b in repo._bookmarks:
4373 if b in repo._bookmarks:
4374 ui.status(_("exporting bookmark %s\n") % b)
4374 ui.status(_("exporting bookmark %s\n") % b)
4375 new = repo[b].hex()
4375 new = repo[b].hex()
4376 elif b in rb:
4376 elif b in rb:
4377 ui.status(_("deleting remote bookmark %s\n") % b)
4377 ui.status(_("deleting remote bookmark %s\n") % b)
4378 new = '' # delete
4378 new = '' # delete
4379 else:
4379 else:
4380 ui.warn(_('bookmark %s does not exist on the local '
4380 ui.warn(_('bookmark %s does not exist on the local '
4381 'or remote repository!\n') % b)
4381 'or remote repository!\n') % b)
4382 return 2
4382 return 2
4383 old = rb.get(b, '')
4383 old = rb.get(b, '')
4384 r = other.pushkey('bookmarks', b, old, new)
4384 r = other.pushkey('bookmarks', b, old, new)
4385 if not r:
4385 if not r:
4386 ui.warn(_('updating bookmark %s failed!\n') % b)
4386 ui.warn(_('updating bookmark %s failed!\n') % b)
4387 if not result:
4387 if not result:
4388 result = 2
4388 result = 2
4389
4389
4390 return result
4390 return result
4391
4391
4392 @command('recover', [])
4392 @command('recover', [])
4393 def recover(ui, repo):
4393 def recover(ui, repo):
4394 """roll back an interrupted transaction
4394 """roll back an interrupted transaction
4395
4395
4396 Recover from an interrupted commit or pull.
4396 Recover from an interrupted commit or pull.
4397
4397
4398 This command tries to fix the repository status after an
4398 This command tries to fix the repository status after an
4399 interrupted operation. It should only be necessary when Mercurial
4399 interrupted operation. It should only be necessary when Mercurial
4400 suggests it.
4400 suggests it.
4401
4401
4402 Returns 0 if successful, 1 if nothing to recover or verify fails.
4402 Returns 0 if successful, 1 if nothing to recover or verify fails.
4403 """
4403 """
4404 if repo.recover():
4404 if repo.recover():
4405 return hg.verify(repo)
4405 return hg.verify(repo)
4406 return 1
4406 return 1
4407
4407
4408 @command('^remove|rm',
4408 @command('^remove|rm',
4409 [('A', 'after', None, _('record delete for missing files')),
4409 [('A', 'after', None, _('record delete for missing files')),
4410 ('f', 'force', None,
4410 ('f', 'force', None,
4411 _('remove (and delete) file even if added or modified')),
4411 _('remove (and delete) file even if added or modified')),
4412 ] + walkopts,
4412 ] + walkopts,
4413 _('[OPTION]... FILE...'))
4413 _('[OPTION]... FILE...'))
4414 def remove(ui, repo, *pats, **opts):
4414 def remove(ui, repo, *pats, **opts):
4415 """remove the specified files on the next commit
4415 """remove the specified files on the next commit
4416
4416
4417 Schedule the indicated files for removal from the current branch.
4417 Schedule the indicated files for removal from the current branch.
4418
4418
4419 This command schedules the files to be removed at the next commit.
4419 This command schedules the files to be removed at the next commit.
4420 To undo a remove before that, see :hg:`revert`. To undo added
4420 To undo a remove before that, see :hg:`revert`. To undo added
4421 files, see :hg:`forget`.
4421 files, see :hg:`forget`.
4422
4422
4423 .. container:: verbose
4423 .. container:: verbose
4424
4424
4425 -A/--after can be used to remove only files that have already
4425 -A/--after can be used to remove only files that have already
4426 been deleted, -f/--force can be used to force deletion, and -Af
4426 been deleted, -f/--force can be used to force deletion, and -Af
4427 can be used to remove files from the next revision without
4427 can be used to remove files from the next revision without
4428 deleting them from the working directory.
4428 deleting them from the working directory.
4429
4429
4430 The following table details the behavior of remove for different
4430 The following table details the behavior of remove for different
4431 file states (columns) and option combinations (rows). The file
4431 file states (columns) and option combinations (rows). The file
4432 states are Added [A], Clean [C], Modified [M] and Missing [!]
4432 states are Added [A], Clean [C], Modified [M] and Missing [!]
4433 (as reported by :hg:`status`). The actions are Warn, Remove
4433 (as reported by :hg:`status`). The actions are Warn, Remove
4434 (from branch) and Delete (from disk):
4434 (from branch) and Delete (from disk):
4435
4435
4436 ======= == == == ==
4436 ======= == == == ==
4437 A C M !
4437 A C M !
4438 ======= == == == ==
4438 ======= == == == ==
4439 none W RD W R
4439 none W RD W R
4440 -f R RD RD R
4440 -f R RD RD R
4441 -A W W W R
4441 -A W W W R
4442 -Af R R R R
4442 -Af R R R R
4443 ======= == == == ==
4443 ======= == == == ==
4444
4444
4445 Note that remove never deletes files in Added [A] state from the
4445 Note that remove never deletes files in Added [A] state from the
4446 working directory, not even if option --force is specified.
4446 working directory, not even if option --force is specified.
4447
4447
4448 Returns 0 on success, 1 if any warnings encountered.
4448 Returns 0 on success, 1 if any warnings encountered.
4449 """
4449 """
4450
4450
4451 ret = 0
4451 ret = 0
4452 after, force = opts.get('after'), opts.get('force')
4452 after, force = opts.get('after'), opts.get('force')
4453 if not pats and not after:
4453 if not pats and not after:
4454 raise util.Abort(_('no files specified'))
4454 raise util.Abort(_('no files specified'))
4455
4455
4456 m = scmutil.match(repo[None], pats, opts)
4456 m = scmutil.match(repo[None], pats, opts)
4457 s = repo.status(match=m, clean=True)
4457 s = repo.status(match=m, clean=True)
4458 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4458 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4459
4459
4460 for f in m.files():
4460 for f in m.files():
4461 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4461 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4462 if os.path.exists(m.rel(f)):
4462 if os.path.exists(m.rel(f)):
4463 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4463 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4464 ret = 1
4464 ret = 1
4465
4465
4466 if force:
4466 if force:
4467 list = modified + deleted + clean + added
4467 list = modified + deleted + clean + added
4468 elif after:
4468 elif after:
4469 list = deleted
4469 list = deleted
4470 for f in modified + added + clean:
4470 for f in modified + added + clean:
4471 ui.warn(_('not removing %s: file still exists (use -f'
4471 ui.warn(_('not removing %s: file still exists (use -f'
4472 ' to force removal)\n') % m.rel(f))
4472 ' to force removal)\n') % m.rel(f))
4473 ret = 1
4473 ret = 1
4474 else:
4474 else:
4475 list = deleted + clean
4475 list = deleted + clean
4476 for f in modified:
4476 for f in modified:
4477 ui.warn(_('not removing %s: file is modified (use -f'
4477 ui.warn(_('not removing %s: file is modified (use -f'
4478 ' to force removal)\n') % m.rel(f))
4478 ' to force removal)\n') % m.rel(f))
4479 ret = 1
4479 ret = 1
4480 for f in added:
4480 for f in added:
4481 ui.warn(_('not removing %s: file has been marked for add'
4481 ui.warn(_('not removing %s: file has been marked for add'
4482 ' (use forget to undo)\n') % m.rel(f))
4482 ' (use forget to undo)\n') % m.rel(f))
4483 ret = 1
4483 ret = 1
4484
4484
4485 for f in sorted(list):
4485 for f in sorted(list):
4486 if ui.verbose or not m.exact(f):
4486 if ui.verbose or not m.exact(f):
4487 ui.status(_('removing %s\n') % m.rel(f))
4487 ui.status(_('removing %s\n') % m.rel(f))
4488
4488
4489 wlock = repo.wlock()
4489 wlock = repo.wlock()
4490 try:
4490 try:
4491 if not after:
4491 if not after:
4492 for f in list:
4492 for f in list:
4493 if f in added:
4493 if f in added:
4494 continue # we never unlink added files on remove
4494 continue # we never unlink added files on remove
4495 try:
4495 try:
4496 util.unlinkpath(repo.wjoin(f))
4496 util.unlinkpath(repo.wjoin(f))
4497 except OSError, inst:
4497 except OSError, inst:
4498 if inst.errno != errno.ENOENT:
4498 if inst.errno != errno.ENOENT:
4499 raise
4499 raise
4500 repo[None].forget(list)
4500 repo[None].forget(list)
4501 finally:
4501 finally:
4502 wlock.release()
4502 wlock.release()
4503
4503
4504 return ret
4504 return ret
4505
4505
4506 @command('rename|move|mv',
4506 @command('rename|move|mv',
4507 [('A', 'after', None, _('record a rename that has already occurred')),
4507 [('A', 'after', None, _('record a rename that has already occurred')),
4508 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4508 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4509 ] + walkopts + dryrunopts,
4509 ] + walkopts + dryrunopts,
4510 _('[OPTION]... SOURCE... DEST'))
4510 _('[OPTION]... SOURCE... DEST'))
4511 def rename(ui, repo, *pats, **opts):
4511 def rename(ui, repo, *pats, **opts):
4512 """rename files; equivalent of copy + remove
4512 """rename files; equivalent of copy + remove
4513
4513
4514 Mark dest as copies of sources; mark sources for deletion. If dest
4514 Mark dest as copies of sources; mark sources for deletion. If dest
4515 is a directory, copies are put in that directory. If dest is a
4515 is a directory, copies are put in that directory. If dest is a
4516 file, there can only be one source.
4516 file, there can only be one source.
4517
4517
4518 By default, this command copies the contents of files as they
4518 By default, this command copies the contents of files as they
4519 exist in the working directory. If invoked with -A/--after, the
4519 exist in the working directory. If invoked with -A/--after, the
4520 operation is recorded, but no copying is performed.
4520 operation is recorded, but no copying is performed.
4521
4521
4522 This command takes effect at the next commit. To undo a rename
4522 This command takes effect at the next commit. To undo a rename
4523 before that, see :hg:`revert`.
4523 before that, see :hg:`revert`.
4524
4524
4525 Returns 0 on success, 1 if errors are encountered.
4525 Returns 0 on success, 1 if errors are encountered.
4526 """
4526 """
4527 wlock = repo.wlock(False)
4527 wlock = repo.wlock(False)
4528 try:
4528 try:
4529 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4529 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4530 finally:
4530 finally:
4531 wlock.release()
4531 wlock.release()
4532
4532
4533 @command('resolve',
4533 @command('resolve',
4534 [('a', 'all', None, _('select all unresolved files')),
4534 [('a', 'all', None, _('select all unresolved files')),
4535 ('l', 'list', None, _('list state of files needing merge')),
4535 ('l', 'list', None, _('list state of files needing merge')),
4536 ('m', 'mark', None, _('mark files as resolved')),
4536 ('m', 'mark', None, _('mark files as resolved')),
4537 ('u', 'unmark', None, _('mark files as unresolved')),
4537 ('u', 'unmark', None, _('mark files as unresolved')),
4538 ('n', 'no-status', None, _('hide status prefix'))]
4538 ('n', 'no-status', None, _('hide status prefix'))]
4539 + mergetoolopts + walkopts,
4539 + mergetoolopts + walkopts,
4540 _('[OPTION]... [FILE]...'))
4540 _('[OPTION]... [FILE]...'))
4541 def resolve(ui, repo, *pats, **opts):
4541 def resolve(ui, repo, *pats, **opts):
4542 """redo merges or set/view the merge status of files
4542 """redo merges or set/view the merge status of files
4543
4543
4544 Merges with unresolved conflicts are often the result of
4544 Merges with unresolved conflicts are often the result of
4545 non-interactive merging using the ``internal:merge`` configuration
4545 non-interactive merging using the ``internal:merge`` configuration
4546 setting, or a command-line merge tool like ``diff3``. The resolve
4546 setting, or a command-line merge tool like ``diff3``. The resolve
4547 command is used to manage the files involved in a merge, after
4547 command is used to manage the files involved in a merge, after
4548 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4548 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4549 working directory must have two parents).
4549 working directory must have two parents).
4550
4550
4551 The resolve command can be used in the following ways:
4551 The resolve command can be used in the following ways:
4552
4552
4553 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4553 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4554 files, discarding any previous merge attempts. Re-merging is not
4554 files, discarding any previous merge attempts. Re-merging is not
4555 performed for files already marked as resolved. Use ``--all/-a``
4555 performed for files already marked as resolved. Use ``--all/-a``
4556 to select all unresolved files. ``--tool`` can be used to specify
4556 to select all unresolved files. ``--tool`` can be used to specify
4557 the merge tool used for the given files. It overrides the HGMERGE
4557 the merge tool used for the given files. It overrides the HGMERGE
4558 environment variable and your configuration files. Previous file
4558 environment variable and your configuration files. Previous file
4559 contents are saved with a ``.orig`` suffix.
4559 contents are saved with a ``.orig`` suffix.
4560
4560
4561 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4561 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4562 (e.g. after having manually fixed-up the files). The default is
4562 (e.g. after having manually fixed-up the files). The default is
4563 to mark all unresolved files.
4563 to mark all unresolved files.
4564
4564
4565 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4565 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4566 default is to mark all resolved files.
4566 default is to mark all resolved files.
4567
4567
4568 - :hg:`resolve -l`: list files which had or still have conflicts.
4568 - :hg:`resolve -l`: list files which had or still have conflicts.
4569 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4569 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4570
4570
4571 Note that Mercurial will not let you commit files with unresolved
4571 Note that Mercurial will not let you commit files with unresolved
4572 merge conflicts. You must use :hg:`resolve -m ...` before you can
4572 merge conflicts. You must use :hg:`resolve -m ...` before you can
4573 commit after a conflicting merge.
4573 commit after a conflicting merge.
4574
4574
4575 Returns 0 on success, 1 if any files fail a resolve attempt.
4575 Returns 0 on success, 1 if any files fail a resolve attempt.
4576 """
4576 """
4577
4577
4578 all, mark, unmark, show, nostatus = \
4578 all, mark, unmark, show, nostatus = \
4579 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4579 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4580
4580
4581 if (show and (mark or unmark)) or (mark and unmark):
4581 if (show and (mark or unmark)) or (mark and unmark):
4582 raise util.Abort(_("too many options specified"))
4582 raise util.Abort(_("too many options specified"))
4583 if pats and all:
4583 if pats and all:
4584 raise util.Abort(_("can't specify --all and patterns"))
4584 raise util.Abort(_("can't specify --all and patterns"))
4585 if not (all or pats or show or mark or unmark):
4585 if not (all or pats or show or mark or unmark):
4586 raise util.Abort(_('no files or directories specified; '
4586 raise util.Abort(_('no files or directories specified; '
4587 'use --all to remerge all files'))
4587 'use --all to remerge all files'))
4588
4588
4589 ms = mergemod.mergestate(repo)
4589 ms = mergemod.mergestate(repo)
4590 m = scmutil.match(repo[None], pats, opts)
4590 m = scmutil.match(repo[None], pats, opts)
4591 ret = 0
4591 ret = 0
4592
4592
4593 for f in ms:
4593 for f in ms:
4594 if m(f):
4594 if m(f):
4595 if show:
4595 if show:
4596 if nostatus:
4596 if nostatus:
4597 ui.write("%s\n" % f)
4597 ui.write("%s\n" % f)
4598 else:
4598 else:
4599 ui.write("%s %s\n" % (ms[f].upper(), f),
4599 ui.write("%s %s\n" % (ms[f].upper(), f),
4600 label='resolve.' +
4600 label='resolve.' +
4601 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4601 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4602 elif mark:
4602 elif mark:
4603 ms.mark(f, "r")
4603 ms.mark(f, "r")
4604 elif unmark:
4604 elif unmark:
4605 ms.mark(f, "u")
4605 ms.mark(f, "u")
4606 else:
4606 else:
4607 wctx = repo[None]
4607 wctx = repo[None]
4608 mctx = wctx.parents()[-1]
4608 mctx = wctx.parents()[-1]
4609
4609
4610 # backup pre-resolve (merge uses .orig for its own purposes)
4610 # backup pre-resolve (merge uses .orig for its own purposes)
4611 a = repo.wjoin(f)
4611 a = repo.wjoin(f)
4612 util.copyfile(a, a + ".resolve")
4612 util.copyfile(a, a + ".resolve")
4613
4613
4614 try:
4614 try:
4615 # resolve file
4615 # resolve file
4616 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4616 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4617 if ms.resolve(f, wctx, mctx):
4617 if ms.resolve(f, wctx, mctx):
4618 ret = 1
4618 ret = 1
4619 finally:
4619 finally:
4620 ui.setconfig('ui', 'forcemerge', '')
4620 ui.setconfig('ui', 'forcemerge', '')
4621
4621
4622 # replace filemerge's .orig file with our resolve file
4622 # replace filemerge's .orig file with our resolve file
4623 util.rename(a + ".resolve", a + ".orig")
4623 util.rename(a + ".resolve", a + ".orig")
4624
4624
4625 ms.commit()
4625 ms.commit()
4626 return ret
4626 return ret
4627
4627
4628 @command('revert',
4628 @command('revert',
4629 [('a', 'all', None, _('revert all changes when no arguments given')),
4629 [('a', 'all', None, _('revert all changes when no arguments given')),
4630 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4630 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4631 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4631 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4632 ('C', 'no-backup', None, _('do not save backup copies of files')),
4632 ('C', 'no-backup', None, _('do not save backup copies of files')),
4633 ] + walkopts + dryrunopts,
4633 ] + walkopts + dryrunopts,
4634 _('[OPTION]... [-r REV] [NAME]...'))
4634 _('[OPTION]... [-r REV] [NAME]...'))
4635 def revert(ui, repo, *pats, **opts):
4635 def revert(ui, repo, *pats, **opts):
4636 """restore files to their checkout state
4636 """restore files to their checkout state
4637
4637
4638 .. note::
4638 .. note::
4639 To check out earlier revisions, you should use :hg:`update REV`.
4639 To check out earlier revisions, you should use :hg:`update REV`.
4640 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4640 To cancel a merge (and lose your changes), use :hg:`update --clean .`.
4641
4641
4642 With no revision specified, revert the specified files or directories
4642 With no revision specified, revert the specified files or directories
4643 to the contents they had in the parent of the working directory.
4643 to the contents they had in the parent of the working directory.
4644 This restores the contents of files to an unmodified
4644 This restores the contents of files to an unmodified
4645 state and unschedules adds, removes, copies, and renames. If the
4645 state and unschedules adds, removes, copies, and renames. If the
4646 working directory has two parents, you must explicitly specify a
4646 working directory has two parents, you must explicitly specify a
4647 revision.
4647 revision.
4648
4648
4649 Using the -r/--rev or -d/--date options, revert the given files or
4649 Using the -r/--rev or -d/--date options, revert the given files or
4650 directories to their states as of a specific revision. Because
4650 directories to their states as of a specific revision. Because
4651 revert does not change the working directory parents, this will
4651 revert does not change the working directory parents, this will
4652 cause these files to appear modified. This can be helpful to "back
4652 cause these files to appear modified. This can be helpful to "back
4653 out" some or all of an earlier change. See :hg:`backout` for a
4653 out" some or all of an earlier change. See :hg:`backout` for a
4654 related method.
4654 related method.
4655
4655
4656 Modified files are saved with a .orig suffix before reverting.
4656 Modified files are saved with a .orig suffix before reverting.
4657 To disable these backups, use --no-backup.
4657 To disable these backups, use --no-backup.
4658
4658
4659 See :hg:`help dates` for a list of formats valid for -d/--date.
4659 See :hg:`help dates` for a list of formats valid for -d/--date.
4660
4660
4661 Returns 0 on success.
4661 Returns 0 on success.
4662 """
4662 """
4663
4663
4664 if opts.get("date"):
4664 if opts.get("date"):
4665 if opts.get("rev"):
4665 if opts.get("rev"):
4666 raise util.Abort(_("you can't specify a revision and a date"))
4666 raise util.Abort(_("you can't specify a revision and a date"))
4667 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4667 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4668
4668
4669 parent, p2 = repo.dirstate.parents()
4669 parent, p2 = repo.dirstate.parents()
4670 if not opts.get('rev') and p2 != nullid:
4670 if not opts.get('rev') and p2 != nullid:
4671 # revert after merge is a trap for new users (issue2915)
4671 # revert after merge is a trap for new users (issue2915)
4672 raise util.Abort(_('uncommitted merge with no revision specified'),
4672 raise util.Abort(_('uncommitted merge with no revision specified'),
4673 hint=_('use "hg update" or see "hg help revert"'))
4673 hint=_('use "hg update" or see "hg help revert"'))
4674
4674
4675 ctx = scmutil.revsingle(repo, opts.get('rev'))
4675 ctx = scmutil.revsingle(repo, opts.get('rev'))
4676 node = ctx.node()
4676 node = ctx.node()
4677
4677
4678 if not pats and not opts.get('all'):
4678 if not pats and not opts.get('all'):
4679 msg = _("no files or directories specified")
4679 msg = _("no files or directories specified")
4680 if p2 != nullid:
4680 if p2 != nullid:
4681 hint = _("uncommitted merge, use --all to discard all changes,"
4681 hint = _("uncommitted merge, use --all to discard all changes,"
4682 " or 'hg update -C .' to abort the merge")
4682 " or 'hg update -C .' to abort the merge")
4683 raise util.Abort(msg, hint=hint)
4683 raise util.Abort(msg, hint=hint)
4684 dirty = util.any(repo.status())
4684 dirty = util.any(repo.status())
4685 if node != parent:
4685 if node != parent:
4686 if dirty:
4686 if dirty:
4687 hint = _("uncommitted changes, use --all to discard all"
4687 hint = _("uncommitted changes, use --all to discard all"
4688 " changes, or 'hg update %s' to update") % ctx.rev()
4688 " changes, or 'hg update %s' to update") % ctx.rev()
4689 else:
4689 else:
4690 hint = _("use --all to revert all files,"
4690 hint = _("use --all to revert all files,"
4691 " or 'hg update %s' to update") % ctx.rev()
4691 " or 'hg update %s' to update") % ctx.rev()
4692 elif dirty:
4692 elif dirty:
4693 hint = _("uncommitted changes, use --all to discard all changes")
4693 hint = _("uncommitted changes, use --all to discard all changes")
4694 else:
4694 else:
4695 hint = _("use --all to revert all files")
4695 hint = _("use --all to revert all files")
4696 raise util.Abort(msg, hint=hint)
4696 raise util.Abort(msg, hint=hint)
4697
4697
4698 mf = ctx.manifest()
4698 mf = ctx.manifest()
4699 if node == parent:
4699 if node == parent:
4700 pmf = mf
4700 pmf = mf
4701 else:
4701 else:
4702 pmf = None
4702 pmf = None
4703
4703
4704 # need all matching names in dirstate and manifest of target rev,
4704 # need all matching names in dirstate and manifest of target rev,
4705 # so have to walk both. do not print errors if files exist in one
4705 # so have to walk both. do not print errors if files exist in one
4706 # but not other.
4706 # but not other.
4707
4707
4708 names = {}
4708 names = {}
4709
4709
4710 wlock = repo.wlock()
4710 wlock = repo.wlock()
4711 try:
4711 try:
4712 # walk dirstate.
4712 # walk dirstate.
4713
4713
4714 m = scmutil.match(repo[None], pats, opts)
4714 m = scmutil.match(repo[None], pats, opts)
4715 m.bad = lambda x, y: False
4715 m.bad = lambda x, y: False
4716 for abs in repo.walk(m):
4716 for abs in repo.walk(m):
4717 names[abs] = m.rel(abs), m.exact(abs)
4717 names[abs] = m.rel(abs), m.exact(abs)
4718
4718
4719 # walk target manifest.
4719 # walk target manifest.
4720
4720
4721 def badfn(path, msg):
4721 def badfn(path, msg):
4722 if path in names:
4722 if path in names:
4723 return
4723 return
4724 if path in repo[node].substate:
4724 if path in repo[node].substate:
4725 ui.warn("%s: %s\n" % (m.rel(path),
4725 ui.warn("%s: %s\n" % (m.rel(path),
4726 'reverting subrepos is unsupported'))
4726 'reverting subrepos is unsupported'))
4727 return
4727 return
4728 path_ = path + '/'
4728 path_ = path + '/'
4729 for f in names:
4729 for f in names:
4730 if f.startswith(path_):
4730 if f.startswith(path_):
4731 return
4731 return
4732 ui.warn("%s: %s\n" % (m.rel(path), msg))
4732 ui.warn("%s: %s\n" % (m.rel(path), msg))
4733
4733
4734 m = scmutil.match(repo[node], pats, opts)
4734 m = scmutil.match(repo[node], pats, opts)
4735 m.bad = badfn
4735 m.bad = badfn
4736 for abs in repo[node].walk(m):
4736 for abs in repo[node].walk(m):
4737 if abs not in names:
4737 if abs not in names:
4738 names[abs] = m.rel(abs), m.exact(abs)
4738 names[abs] = m.rel(abs), m.exact(abs)
4739
4739
4740 m = scmutil.matchfiles(repo, names)
4740 m = scmutil.matchfiles(repo, names)
4741 changes = repo.status(match=m)[:4]
4741 changes = repo.status(match=m)[:4]
4742 modified, added, removed, deleted = map(set, changes)
4742 modified, added, removed, deleted = map(set, changes)
4743
4743
4744 # if f is a rename, also revert the source
4744 # if f is a rename, also revert the source
4745 cwd = repo.getcwd()
4745 cwd = repo.getcwd()
4746 for f in added:
4746 for f in added:
4747 src = repo.dirstate.copied(f)
4747 src = repo.dirstate.copied(f)
4748 if src and src not in names and repo.dirstate[src] == 'r':
4748 if src and src not in names and repo.dirstate[src] == 'r':
4749 removed.add(src)
4749 removed.add(src)
4750 names[src] = (repo.pathto(src, cwd), True)
4750 names[src] = (repo.pathto(src, cwd), True)
4751
4751
4752 def removeforget(abs):
4752 def removeforget(abs):
4753 if repo.dirstate[abs] == 'a':
4753 if repo.dirstate[abs] == 'a':
4754 return _('forgetting %s\n')
4754 return _('forgetting %s\n')
4755 return _('removing %s\n')
4755 return _('removing %s\n')
4756
4756
4757 revert = ([], _('reverting %s\n'))
4757 revert = ([], _('reverting %s\n'))
4758 add = ([], _('adding %s\n'))
4758 add = ([], _('adding %s\n'))
4759 remove = ([], removeforget)
4759 remove = ([], removeforget)
4760 undelete = ([], _('undeleting %s\n'))
4760 undelete = ([], _('undeleting %s\n'))
4761
4761
4762 disptable = (
4762 disptable = (
4763 # dispatch table:
4763 # dispatch table:
4764 # file state
4764 # file state
4765 # action if in target manifest
4765 # action if in target manifest
4766 # action if not in target manifest
4766 # action if not in target manifest
4767 # make backup if in target manifest
4767 # make backup if in target manifest
4768 # make backup if not in target manifest
4768 # make backup if not in target manifest
4769 (modified, revert, remove, True, True),
4769 (modified, revert, remove, True, True),
4770 (added, revert, remove, True, False),
4770 (added, revert, remove, True, False),
4771 (removed, undelete, None, False, False),
4771 (removed, undelete, None, False, False),
4772 (deleted, revert, remove, False, False),
4772 (deleted, revert, remove, False, False),
4773 )
4773 )
4774
4774
4775 for abs, (rel, exact) in sorted(names.items()):
4775 for abs, (rel, exact) in sorted(names.items()):
4776 mfentry = mf.get(abs)
4776 mfentry = mf.get(abs)
4777 target = repo.wjoin(abs)
4777 target = repo.wjoin(abs)
4778 def handle(xlist, dobackup):
4778 def handle(xlist, dobackup):
4779 xlist[0].append(abs)
4779 xlist[0].append(abs)
4780 if (dobackup and not opts.get('no_backup') and
4780 if (dobackup and not opts.get('no_backup') and
4781 os.path.lexists(target)):
4781 os.path.lexists(target)):
4782 bakname = "%s.orig" % rel
4782 bakname = "%s.orig" % rel
4783 ui.note(_('saving current version of %s as %s\n') %
4783 ui.note(_('saving current version of %s as %s\n') %
4784 (rel, bakname))
4784 (rel, bakname))
4785 if not opts.get('dry_run'):
4785 if not opts.get('dry_run'):
4786 util.rename(target, bakname)
4786 util.rename(target, bakname)
4787 if ui.verbose or not exact:
4787 if ui.verbose or not exact:
4788 msg = xlist[1]
4788 msg = xlist[1]
4789 if not isinstance(msg, basestring):
4789 if not isinstance(msg, basestring):
4790 msg = msg(abs)
4790 msg = msg(abs)
4791 ui.status(msg % rel)
4791 ui.status(msg % rel)
4792 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4792 for table, hitlist, misslist, backuphit, backupmiss in disptable:
4793 if abs not in table:
4793 if abs not in table:
4794 continue
4794 continue
4795 # file has changed in dirstate
4795 # file has changed in dirstate
4796 if mfentry:
4796 if mfentry:
4797 handle(hitlist, backuphit)
4797 handle(hitlist, backuphit)
4798 elif misslist is not None:
4798 elif misslist is not None:
4799 handle(misslist, backupmiss)
4799 handle(misslist, backupmiss)
4800 break
4800 break
4801 else:
4801 else:
4802 if abs not in repo.dirstate:
4802 if abs not in repo.dirstate:
4803 if mfentry:
4803 if mfentry:
4804 handle(add, True)
4804 handle(add, True)
4805 elif exact:
4805 elif exact:
4806 ui.warn(_('file not managed: %s\n') % rel)
4806 ui.warn(_('file not managed: %s\n') % rel)
4807 continue
4807 continue
4808 # file has not changed in dirstate
4808 # file has not changed in dirstate
4809 if node == parent:
4809 if node == parent:
4810 if exact:
4810 if exact:
4811 ui.warn(_('no changes needed to %s\n') % rel)
4811 ui.warn(_('no changes needed to %s\n') % rel)
4812 continue
4812 continue
4813 if pmf is None:
4813 if pmf is None:
4814 # only need parent manifest in this unlikely case,
4814 # only need parent manifest in this unlikely case,
4815 # so do not read by default
4815 # so do not read by default
4816 pmf = repo[parent].manifest()
4816 pmf = repo[parent].manifest()
4817 if abs in pmf and mfentry:
4817 if abs in pmf and mfentry:
4818 # if version of file is same in parent and target
4818 # if version of file is same in parent and target
4819 # manifests, do nothing
4819 # manifests, do nothing
4820 if (pmf[abs] != mfentry or
4820 if (pmf[abs] != mfentry or
4821 pmf.flags(abs) != mf.flags(abs)):
4821 pmf.flags(abs) != mf.flags(abs)):
4822 handle(revert, False)
4822 handle(revert, False)
4823 else:
4823 else:
4824 handle(remove, False)
4824 handle(remove, False)
4825
4825
4826 if not opts.get('dry_run'):
4826 if not opts.get('dry_run'):
4827 def checkout(f):
4827 def checkout(f):
4828 fc = ctx[f]
4828 fc = ctx[f]
4829 repo.wwrite(f, fc.data(), fc.flags())
4829 repo.wwrite(f, fc.data(), fc.flags())
4830
4830
4831 audit_path = scmutil.pathauditor(repo.root)
4831 audit_path = scmutil.pathauditor(repo.root)
4832 for f in remove[0]:
4832 for f in remove[0]:
4833 if repo.dirstate[f] == 'a':
4833 if repo.dirstate[f] == 'a':
4834 repo.dirstate.drop(f)
4834 repo.dirstate.drop(f)
4835 continue
4835 continue
4836 audit_path(f)
4836 audit_path(f)
4837 try:
4837 try:
4838 util.unlinkpath(repo.wjoin(f))
4838 util.unlinkpath(repo.wjoin(f))
4839 except OSError:
4839 except OSError:
4840 pass
4840 pass
4841 repo.dirstate.remove(f)
4841 repo.dirstate.remove(f)
4842
4842
4843 normal = None
4843 normal = None
4844 if node == parent:
4844 if node == parent:
4845 # We're reverting to our parent. If possible, we'd like status
4845 # We're reverting to our parent. If possible, we'd like status
4846 # to report the file as clean. We have to use normallookup for
4846 # to report the file as clean. We have to use normallookup for
4847 # merges to avoid losing information about merged/dirty files.
4847 # merges to avoid losing information about merged/dirty files.
4848 if p2 != nullid:
4848 if p2 != nullid:
4849 normal = repo.dirstate.normallookup
4849 normal = repo.dirstate.normallookup
4850 else:
4850 else:
4851 normal = repo.dirstate.normal
4851 normal = repo.dirstate.normal
4852 for f in revert[0]:
4852 for f in revert[0]:
4853 checkout(f)
4853 checkout(f)
4854 if normal:
4854 if normal:
4855 normal(f)
4855 normal(f)
4856
4856
4857 for f in add[0]:
4857 for f in add[0]:
4858 checkout(f)
4858 checkout(f)
4859 repo.dirstate.add(f)
4859 repo.dirstate.add(f)
4860
4860
4861 normal = repo.dirstate.normallookup
4861 normal = repo.dirstate.normallookup
4862 if node == parent and p2 == nullid:
4862 if node == parent and p2 == nullid:
4863 normal = repo.dirstate.normal
4863 normal = repo.dirstate.normal
4864 for f in undelete[0]:
4864 for f in undelete[0]:
4865 checkout(f)
4865 checkout(f)
4866 normal(f)
4866 normal(f)
4867
4867
4868 finally:
4868 finally:
4869 wlock.release()
4869 wlock.release()
4870
4870
4871 @command('rollback', dryrunopts +
4871 @command('rollback', dryrunopts +
4872 [('f', 'force', False, _('ignore safety measures'))])
4872 [('f', 'force', False, _('ignore safety measures'))])
4873 def rollback(ui, repo, **opts):
4873 def rollback(ui, repo, **opts):
4874 """roll back the last transaction (dangerous)
4874 """roll back the last transaction (dangerous)
4875
4875
4876 This command should be used with care. There is only one level of
4876 This command should be used with care. There is only one level of
4877 rollback, and there is no way to undo a rollback. It will also
4877 rollback, and there is no way to undo a rollback. It will also
4878 restore the dirstate at the time of the last transaction, losing
4878 restore the dirstate at the time of the last transaction, losing
4879 any dirstate changes since that time. This command does not alter
4879 any dirstate changes since that time. This command does not alter
4880 the working directory.
4880 the working directory.
4881
4881
4882 Transactions are used to encapsulate the effects of all commands
4882 Transactions are used to encapsulate the effects of all commands
4883 that create new changesets or propagate existing changesets into a
4883 that create new changesets or propagate existing changesets into a
4884 repository. For example, the following commands are transactional,
4884 repository. For example, the following commands are transactional,
4885 and their effects can be rolled back:
4885 and their effects can be rolled back:
4886
4886
4887 - commit
4887 - commit
4888 - import
4888 - import
4889 - pull
4889 - pull
4890 - push (with this repository as the destination)
4890 - push (with this repository as the destination)
4891 - unbundle
4891 - unbundle
4892
4892
4893 It's possible to lose data with rollback: commit, update back to
4893 It's possible to lose data with rollback: commit, update back to
4894 an older changeset, and then rollback. The update removes the
4894 an older changeset, and then rollback. The update removes the
4895 changes you committed from the working directory, and rollback
4895 changes you committed from the working directory, and rollback
4896 removes them from history. To avoid data loss, you must pass
4896 removes them from history. To avoid data loss, you must pass
4897 --force in this case.
4897 --force in this case.
4898
4898
4899 This command is not intended for use on public repositories. Once
4899 This command is not intended for use on public repositories. Once
4900 changes are visible for pull by other users, rolling a transaction
4900 changes are visible for pull by other users, rolling a transaction
4901 back locally is ineffective (someone else may already have pulled
4901 back locally is ineffective (someone else may already have pulled
4902 the changes). Furthermore, a race is possible with readers of the
4902 the changes). Furthermore, a race is possible with readers of the
4903 repository; for example an in-progress pull from the repository
4903 repository; for example an in-progress pull from the repository
4904 may fail if a rollback is performed.
4904 may fail if a rollback is performed.
4905
4905
4906 Returns 0 on success, 1 if no rollback data is available.
4906 Returns 0 on success, 1 if no rollback data is available.
4907 """
4907 """
4908 return repo.rollback(dryrun=opts.get('dry_run'),
4908 return repo.rollback(dryrun=opts.get('dry_run'),
4909 force=opts.get('force'))
4909 force=opts.get('force'))
4910
4910
4911 @command('root', [])
4911 @command('root', [])
4912 def root(ui, repo):
4912 def root(ui, repo):
4913 """print the root (top) of the current working directory
4913 """print the root (top) of the current working directory
4914
4914
4915 Print the root directory of the current repository.
4915 Print the root directory of the current repository.
4916
4916
4917 Returns 0 on success.
4917 Returns 0 on success.
4918 """
4918 """
4919 ui.write(repo.root + "\n")
4919 ui.write(repo.root + "\n")
4920
4920
4921 @command('^serve',
4921 @command('^serve',
4922 [('A', 'accesslog', '', _('name of access log file to write to'),
4922 [('A', 'accesslog', '', _('name of access log file to write to'),
4923 _('FILE')),
4923 _('FILE')),
4924 ('d', 'daemon', None, _('run server in background')),
4924 ('d', 'daemon', None, _('run server in background')),
4925 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4925 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
4926 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4926 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4927 # use string type, then we can check if something was passed
4927 # use string type, then we can check if something was passed
4928 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4928 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4929 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4929 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4930 _('ADDR')),
4930 _('ADDR')),
4931 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4931 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4932 _('PREFIX')),
4932 _('PREFIX')),
4933 ('n', 'name', '',
4933 ('n', 'name', '',
4934 _('name to show in web pages (default: working directory)'), _('NAME')),
4934 _('name to show in web pages (default: working directory)'), _('NAME')),
4935 ('', 'web-conf', '',
4935 ('', 'web-conf', '',
4936 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4936 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
4937 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4937 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4938 _('FILE')),
4938 _('FILE')),
4939 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4939 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4940 ('', 'stdio', None, _('for remote clients')),
4940 ('', 'stdio', None, _('for remote clients')),
4941 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4941 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4942 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4942 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4943 ('', 'style', '', _('template style to use'), _('STYLE')),
4943 ('', 'style', '', _('template style to use'), _('STYLE')),
4944 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4944 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4945 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4945 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4946 _('[OPTION]...'))
4946 _('[OPTION]...'))
4947 def serve(ui, repo, **opts):
4947 def serve(ui, repo, **opts):
4948 """start stand-alone webserver
4948 """start stand-alone webserver
4949
4949
4950 Start a local HTTP repository browser and pull server. You can use
4950 Start a local HTTP repository browser and pull server. You can use
4951 this for ad-hoc sharing and browsing of repositories. It is
4951 this for ad-hoc sharing and browsing of repositories. It is
4952 recommended to use a real web server to serve a repository for
4952 recommended to use a real web server to serve a repository for
4953 longer periods of time.
4953 longer periods of time.
4954
4954
4955 Please note that the server does not implement access control.
4955 Please note that the server does not implement access control.
4956 This means that, by default, anybody can read from the server and
4956 This means that, by default, anybody can read from the server and
4957 nobody can write to it by default. Set the ``web.allow_push``
4957 nobody can write to it by default. Set the ``web.allow_push``
4958 option to ``*`` to allow everybody to push to the server. You
4958 option to ``*`` to allow everybody to push to the server. You
4959 should use a real web server if you need to authenticate users.
4959 should use a real web server if you need to authenticate users.
4960
4960
4961 By default, the server logs accesses to stdout and errors to
4961 By default, the server logs accesses to stdout and errors to
4962 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4962 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4963 files.
4963 files.
4964
4964
4965 To have the server choose a free port number to listen on, specify
4965 To have the server choose a free port number to listen on, specify
4966 a port number of 0; in this case, the server will print the port
4966 a port number of 0; in this case, the server will print the port
4967 number it uses.
4967 number it uses.
4968
4968
4969 Returns 0 on success.
4969 Returns 0 on success.
4970 """
4970 """
4971
4971
4972 if opts["stdio"] and opts["cmdserver"]:
4972 if opts["stdio"] and opts["cmdserver"]:
4973 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4973 raise util.Abort(_("cannot use --stdio with --cmdserver"))
4974
4974
4975 def checkrepo():
4975 def checkrepo():
4976 if repo is None:
4976 if repo is None:
4977 raise error.RepoError(_("There is no Mercurial repository here"
4977 raise error.RepoError(_("There is no Mercurial repository here"
4978 " (.hg not found)"))
4978 " (.hg not found)"))
4979
4979
4980 if opts["stdio"]:
4980 if opts["stdio"]:
4981 checkrepo()
4981 checkrepo()
4982 s = sshserver.sshserver(ui, repo)
4982 s = sshserver.sshserver(ui, repo)
4983 s.serve_forever()
4983 s.serve_forever()
4984
4984
4985 if opts["cmdserver"]:
4985 if opts["cmdserver"]:
4986 checkrepo()
4986 checkrepo()
4987 s = commandserver.server(ui, repo, opts["cmdserver"])
4987 s = commandserver.server(ui, repo, opts["cmdserver"])
4988 return s.serve()
4988 return s.serve()
4989
4989
4990 # this way we can check if something was given in the command-line
4990 # this way we can check if something was given in the command-line
4991 if opts.get('port'):
4991 if opts.get('port'):
4992 opts['port'] = util.getport(opts.get('port'))
4992 opts['port'] = util.getport(opts.get('port'))
4993
4993
4994 baseui = repo and repo.baseui or ui
4994 baseui = repo and repo.baseui or ui
4995 optlist = ("name templates style address port prefix ipv6"
4995 optlist = ("name templates style address port prefix ipv6"
4996 " accesslog errorlog certificate encoding")
4996 " accesslog errorlog certificate encoding")
4997 for o in optlist.split():
4997 for o in optlist.split():
4998 val = opts.get(o, '')
4998 val = opts.get(o, '')
4999 if val in (None, ''): # should check against default options instead
4999 if val in (None, ''): # should check against default options instead
5000 continue
5000 continue
5001 baseui.setconfig("web", o, val)
5001 baseui.setconfig("web", o, val)
5002 if repo and repo.ui != baseui:
5002 if repo and repo.ui != baseui:
5003 repo.ui.setconfig("web", o, val)
5003 repo.ui.setconfig("web", o, val)
5004
5004
5005 o = opts.get('web_conf') or opts.get('webdir_conf')
5005 o = opts.get('web_conf') or opts.get('webdir_conf')
5006 if not o:
5006 if not o:
5007 if not repo:
5007 if not repo:
5008 raise error.RepoError(_("There is no Mercurial repository"
5008 raise error.RepoError(_("There is no Mercurial repository"
5009 " here (.hg not found)"))
5009 " here (.hg not found)"))
5010 o = repo.root
5010 o = repo.root
5011
5011
5012 app = hgweb.hgweb(o, baseui=ui)
5012 app = hgweb.hgweb(o, baseui=ui)
5013
5013
5014 class service(object):
5014 class service(object):
5015 def init(self):
5015 def init(self):
5016 util.setsignalhandler()
5016 util.setsignalhandler()
5017 self.httpd = hgweb.server.create_server(ui, app)
5017 self.httpd = hgweb.server.create_server(ui, app)
5018
5018
5019 if opts['port'] and not ui.verbose:
5019 if opts['port'] and not ui.verbose:
5020 return
5020 return
5021
5021
5022 if self.httpd.prefix:
5022 if self.httpd.prefix:
5023 prefix = self.httpd.prefix.strip('/') + '/'
5023 prefix = self.httpd.prefix.strip('/') + '/'
5024 else:
5024 else:
5025 prefix = ''
5025 prefix = ''
5026
5026
5027 port = ':%d' % self.httpd.port
5027 port = ':%d' % self.httpd.port
5028 if port == ':80':
5028 if port == ':80':
5029 port = ''
5029 port = ''
5030
5030
5031 bindaddr = self.httpd.addr
5031 bindaddr = self.httpd.addr
5032 if bindaddr == '0.0.0.0':
5032 if bindaddr == '0.0.0.0':
5033 bindaddr = '*'
5033 bindaddr = '*'
5034 elif ':' in bindaddr: # IPv6
5034 elif ':' in bindaddr: # IPv6
5035 bindaddr = '[%s]' % bindaddr
5035 bindaddr = '[%s]' % bindaddr
5036
5036
5037 fqaddr = self.httpd.fqaddr
5037 fqaddr = self.httpd.fqaddr
5038 if ':' in fqaddr:
5038 if ':' in fqaddr:
5039 fqaddr = '[%s]' % fqaddr
5039 fqaddr = '[%s]' % fqaddr
5040 if opts['port']:
5040 if opts['port']:
5041 write = ui.status
5041 write = ui.status
5042 else:
5042 else:
5043 write = ui.write
5043 write = ui.write
5044 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5044 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5045 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5045 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5046
5046
5047 def run(self):
5047 def run(self):
5048 self.httpd.serve_forever()
5048 self.httpd.serve_forever()
5049
5049
5050 service = service()
5050 service = service()
5051
5051
5052 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5052 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5053
5053
5054 @command('showconfig|debugconfig',
5054 @command('showconfig|debugconfig',
5055 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5055 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5056 _('[-u] [NAME]...'))
5056 _('[-u] [NAME]...'))
5057 def showconfig(ui, repo, *values, **opts):
5057 def showconfig(ui, repo, *values, **opts):
5058 """show combined config settings from all hgrc files
5058 """show combined config settings from all hgrc files
5059
5059
5060 With no arguments, print names and values of all config items.
5060 With no arguments, print names and values of all config items.
5061
5061
5062 With one argument of the form section.name, print just the value
5062 With one argument of the form section.name, print just the value
5063 of that config item.
5063 of that config item.
5064
5064
5065 With multiple arguments, print names and values of all config
5065 With multiple arguments, print names and values of all config
5066 items with matching section names.
5066 items with matching section names.
5067
5067
5068 With --debug, the source (filename and line number) is printed
5068 With --debug, the source (filename and line number) is printed
5069 for each config item.
5069 for each config item.
5070
5070
5071 Returns 0 on success.
5071 Returns 0 on success.
5072 """
5072 """
5073
5073
5074 for f in scmutil.rcpath():
5074 for f in scmutil.rcpath():
5075 ui.debug('read config from: %s\n' % f)
5075 ui.debug('read config from: %s\n' % f)
5076 untrusted = bool(opts.get('untrusted'))
5076 untrusted = bool(opts.get('untrusted'))
5077 if values:
5077 if values:
5078 sections = [v for v in values if '.' not in v]
5078 sections = [v for v in values if '.' not in v]
5079 items = [v for v in values if '.' in v]
5079 items = [v for v in values if '.' in v]
5080 if len(items) > 1 or items and sections:
5080 if len(items) > 1 or items and sections:
5081 raise util.Abort(_('only one config item permitted'))
5081 raise util.Abort(_('only one config item permitted'))
5082 for section, name, value in ui.walkconfig(untrusted=untrusted):
5082 for section, name, value in ui.walkconfig(untrusted=untrusted):
5083 value = str(value).replace('\n', '\\n')
5083 value = str(value).replace('\n', '\\n')
5084 sectname = section + '.' + name
5084 sectname = section + '.' + name
5085 if values:
5085 if values:
5086 for v in values:
5086 for v in values:
5087 if v == section:
5087 if v == section:
5088 ui.debug('%s: ' %
5088 ui.debug('%s: ' %
5089 ui.configsource(section, name, untrusted))
5089 ui.configsource(section, name, untrusted))
5090 ui.write('%s=%s\n' % (sectname, value))
5090 ui.write('%s=%s\n' % (sectname, value))
5091 elif v == sectname:
5091 elif v == sectname:
5092 ui.debug('%s: ' %
5092 ui.debug('%s: ' %
5093 ui.configsource(section, name, untrusted))
5093 ui.configsource(section, name, untrusted))
5094 ui.write(value, '\n')
5094 ui.write(value, '\n')
5095 else:
5095 else:
5096 ui.debug('%s: ' %
5096 ui.debug('%s: ' %
5097 ui.configsource(section, name, untrusted))
5097 ui.configsource(section, name, untrusted))
5098 ui.write('%s=%s\n' % (sectname, value))
5098 ui.write('%s=%s\n' % (sectname, value))
5099
5099
5100 @command('^status|st',
5100 @command('^status|st',
5101 [('A', 'all', None, _('show status of all files')),
5101 [('A', 'all', None, _('show status of all files')),
5102 ('m', 'modified', None, _('show only modified files')),
5102 ('m', 'modified', None, _('show only modified files')),
5103 ('a', 'added', None, _('show only added files')),
5103 ('a', 'added', None, _('show only added files')),
5104 ('r', 'removed', None, _('show only removed files')),
5104 ('r', 'removed', None, _('show only removed files')),
5105 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5105 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5106 ('c', 'clean', None, _('show only files without changes')),
5106 ('c', 'clean', None, _('show only files without changes')),
5107 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5107 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5108 ('i', 'ignored', None, _('show only ignored files')),
5108 ('i', 'ignored', None, _('show only ignored files')),
5109 ('n', 'no-status', None, _('hide status prefix')),
5109 ('n', 'no-status', None, _('hide status prefix')),
5110 ('C', 'copies', None, _('show source of copied files')),
5110 ('C', 'copies', None, _('show source of copied files')),
5111 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5111 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5112 ('', 'rev', [], _('show difference from revision'), _('REV')),
5112 ('', 'rev', [], _('show difference from revision'), _('REV')),
5113 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5113 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5114 ] + walkopts + subrepoopts,
5114 ] + walkopts + subrepoopts,
5115 _('[OPTION]... [FILE]...'))
5115 _('[OPTION]... [FILE]...'))
5116 def status(ui, repo, *pats, **opts):
5116 def status(ui, repo, *pats, **opts):
5117 """show changed files in the working directory
5117 """show changed files in the working directory
5118
5118
5119 Show status of files in the repository. If names are given, only
5119 Show status of files in the repository. If names are given, only
5120 files that match are shown. Files that are clean or ignored or
5120 files that match are shown. Files that are clean or ignored or
5121 the source of a copy/move operation, are not listed unless
5121 the source of a copy/move operation, are not listed unless
5122 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5122 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5123 Unless options described with "show only ..." are given, the
5123 Unless options described with "show only ..." are given, the
5124 options -mardu are used.
5124 options -mardu are used.
5125
5125
5126 Option -q/--quiet hides untracked (unknown and ignored) files
5126 Option -q/--quiet hides untracked (unknown and ignored) files
5127 unless explicitly requested with -u/--unknown or -i/--ignored.
5127 unless explicitly requested with -u/--unknown or -i/--ignored.
5128
5128
5129 .. note::
5129 .. note::
5130 status may appear to disagree with diff if permissions have
5130 status may appear to disagree with diff if permissions have
5131 changed or a merge has occurred. The standard diff format does
5131 changed or a merge has occurred. The standard diff format does
5132 not report permission changes and diff only reports changes
5132 not report permission changes and diff only reports changes
5133 relative to one merge parent.
5133 relative to one merge parent.
5134
5134
5135 If one revision is given, it is used as the base revision.
5135 If one revision is given, it is used as the base revision.
5136 If two revisions are given, the differences between them are
5136 If two revisions are given, the differences between them are
5137 shown. The --change option can also be used as a shortcut to list
5137 shown. The --change option can also be used as a shortcut to list
5138 the changed files of a revision from its first parent.
5138 the changed files of a revision from its first parent.
5139
5139
5140 The codes used to show the status of files are::
5140 The codes used to show the status of files are::
5141
5141
5142 M = modified
5142 M = modified
5143 A = added
5143 A = added
5144 R = removed
5144 R = removed
5145 C = clean
5145 C = clean
5146 ! = missing (deleted by non-hg command, but still tracked)
5146 ! = missing (deleted by non-hg command, but still tracked)
5147 ? = not tracked
5147 ? = not tracked
5148 I = ignored
5148 I = ignored
5149 = origin of the previous file listed as A (added)
5149 = origin of the previous file listed as A (added)
5150
5150
5151 .. container:: verbose
5151 .. container:: verbose
5152
5152
5153 Examples:
5153 Examples:
5154
5154
5155 - show changes in the working directory relative to a changeset:
5155 - show changes in the working directory relative to a changeset:
5156
5156
5157 hg status --rev 9353
5157 hg status --rev 9353
5158
5158
5159 - show all changes including copies in an existing changeset::
5159 - show all changes including copies in an existing changeset::
5160
5160
5161 hg status --copies --change 9353
5161 hg status --copies --change 9353
5162
5162
5163 - get a NUL separated list of added files, suitable for xargs::
5163 - get a NUL separated list of added files, suitable for xargs::
5164
5164
5165 hg status -an0
5165 hg status -an0
5166
5166
5167 Returns 0 on success.
5167 Returns 0 on success.
5168 """
5168 """
5169
5169
5170 revs = opts.get('rev')
5170 revs = opts.get('rev')
5171 change = opts.get('change')
5171 change = opts.get('change')
5172
5172
5173 if revs and change:
5173 if revs and change:
5174 msg = _('cannot specify --rev and --change at the same time')
5174 msg = _('cannot specify --rev and --change at the same time')
5175 raise util.Abort(msg)
5175 raise util.Abort(msg)
5176 elif change:
5176 elif change:
5177 node2 = repo.lookup(change)
5177 node2 = scmutil.revsingle(repo, change, None).node()
5178 node1 = repo[node2].p1().node()
5178 node1 = repo[node2].p1().node()
5179 else:
5179 else:
5180 node1, node2 = scmutil.revpair(repo, revs)
5180 node1, node2 = scmutil.revpair(repo, revs)
5181
5181
5182 cwd = (pats and repo.getcwd()) or ''
5182 cwd = (pats and repo.getcwd()) or ''
5183 end = opts.get('print0') and '\0' or '\n'
5183 end = opts.get('print0') and '\0' or '\n'
5184 copy = {}
5184 copy = {}
5185 states = 'modified added removed deleted unknown ignored clean'.split()
5185 states = 'modified added removed deleted unknown ignored clean'.split()
5186 show = [k for k in states if opts.get(k)]
5186 show = [k for k in states if opts.get(k)]
5187 if opts.get('all'):
5187 if opts.get('all'):
5188 show += ui.quiet and (states[:4] + ['clean']) or states
5188 show += ui.quiet and (states[:4] + ['clean']) or states
5189 if not show:
5189 if not show:
5190 show = ui.quiet and states[:4] or states[:5]
5190 show = ui.quiet and states[:4] or states[:5]
5191
5191
5192 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5192 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5193 'ignored' in show, 'clean' in show, 'unknown' in show,
5193 'ignored' in show, 'clean' in show, 'unknown' in show,
5194 opts.get('subrepos'))
5194 opts.get('subrepos'))
5195 changestates = zip(states, 'MAR!?IC', stat)
5195 changestates = zip(states, 'MAR!?IC', stat)
5196
5196
5197 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5197 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5198 ctxn = repo[nullid]
5198 ctxn = repo[nullid]
5199 ctx1 = repo[node1]
5199 ctx1 = repo[node1]
5200 ctx2 = repo[node2]
5200 ctx2 = repo[node2]
5201 added = stat[1]
5201 added = stat[1]
5202 if node2 is None:
5202 if node2 is None:
5203 added = stat[0] + stat[1] # merged?
5203 added = stat[0] + stat[1] # merged?
5204
5204
5205 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5205 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
5206 if k in added:
5206 if k in added:
5207 copy[k] = v
5207 copy[k] = v
5208 elif v in added:
5208 elif v in added:
5209 copy[v] = k
5209 copy[v] = k
5210
5210
5211 for state, char, files in changestates:
5211 for state, char, files in changestates:
5212 if state in show:
5212 if state in show:
5213 format = "%s %%s%s" % (char, end)
5213 format = "%s %%s%s" % (char, end)
5214 if opts.get('no_status'):
5214 if opts.get('no_status'):
5215 format = "%%s%s" % end
5215 format = "%%s%s" % end
5216
5216
5217 for f in files:
5217 for f in files:
5218 ui.write(format % repo.pathto(f, cwd),
5218 ui.write(format % repo.pathto(f, cwd),
5219 label='status.' + state)
5219 label='status.' + state)
5220 if f in copy:
5220 if f in copy:
5221 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5221 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
5222 label='status.copied')
5222 label='status.copied')
5223
5223
5224 @command('^summary|sum',
5224 @command('^summary|sum',
5225 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5225 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5226 def summary(ui, repo, **opts):
5226 def summary(ui, repo, **opts):
5227 """summarize working directory state
5227 """summarize working directory state
5228
5228
5229 This generates a brief summary of the working directory state,
5229 This generates a brief summary of the working directory state,
5230 including parents, branch, commit status, and available updates.
5230 including parents, branch, commit status, and available updates.
5231
5231
5232 With the --remote option, this will check the default paths for
5232 With the --remote option, this will check the default paths for
5233 incoming and outgoing changes. This can be time-consuming.
5233 incoming and outgoing changes. This can be time-consuming.
5234
5234
5235 Returns 0 on success.
5235 Returns 0 on success.
5236 """
5236 """
5237
5237
5238 ctx = repo[None]
5238 ctx = repo[None]
5239 parents = ctx.parents()
5239 parents = ctx.parents()
5240 pnode = parents[0].node()
5240 pnode = parents[0].node()
5241 marks = []
5241 marks = []
5242
5242
5243 for p in parents:
5243 for p in parents:
5244 # label with log.changeset (instead of log.parent) since this
5244 # label with log.changeset (instead of log.parent) since this
5245 # shows a working directory parent *changeset*:
5245 # shows a working directory parent *changeset*:
5246 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5246 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5247 label='log.changeset')
5247 label='log.changeset')
5248 ui.write(' '.join(p.tags()), label='log.tag')
5248 ui.write(' '.join(p.tags()), label='log.tag')
5249 if p.bookmarks():
5249 if p.bookmarks():
5250 marks.extend(p.bookmarks())
5250 marks.extend(p.bookmarks())
5251 if p.rev() == -1:
5251 if p.rev() == -1:
5252 if not len(repo):
5252 if not len(repo):
5253 ui.write(_(' (empty repository)'))
5253 ui.write(_(' (empty repository)'))
5254 else:
5254 else:
5255 ui.write(_(' (no revision checked out)'))
5255 ui.write(_(' (no revision checked out)'))
5256 ui.write('\n')
5256 ui.write('\n')
5257 if p.description():
5257 if p.description():
5258 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5258 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5259 label='log.summary')
5259 label='log.summary')
5260
5260
5261 branch = ctx.branch()
5261 branch = ctx.branch()
5262 bheads = repo.branchheads(branch)
5262 bheads = repo.branchheads(branch)
5263 m = _('branch: %s\n') % branch
5263 m = _('branch: %s\n') % branch
5264 if branch != 'default':
5264 if branch != 'default':
5265 ui.write(m, label='log.branch')
5265 ui.write(m, label='log.branch')
5266 else:
5266 else:
5267 ui.status(m, label='log.branch')
5267 ui.status(m, label='log.branch')
5268
5268
5269 if marks:
5269 if marks:
5270 current = repo._bookmarkcurrent
5270 current = repo._bookmarkcurrent
5271 ui.write(_('bookmarks:'), label='log.bookmark')
5271 ui.write(_('bookmarks:'), label='log.bookmark')
5272 if current is not None:
5272 if current is not None:
5273 try:
5273 try:
5274 marks.remove(current)
5274 marks.remove(current)
5275 ui.write(' *' + current, label='bookmarks.current')
5275 ui.write(' *' + current, label='bookmarks.current')
5276 except ValueError:
5276 except ValueError:
5277 # current bookmark not in parent ctx marks
5277 # current bookmark not in parent ctx marks
5278 pass
5278 pass
5279 for m in marks:
5279 for m in marks:
5280 ui.write(' ' + m, label='log.bookmark')
5280 ui.write(' ' + m, label='log.bookmark')
5281 ui.write('\n', label='log.bookmark')
5281 ui.write('\n', label='log.bookmark')
5282
5282
5283 st = list(repo.status(unknown=True))[:6]
5283 st = list(repo.status(unknown=True))[:6]
5284
5284
5285 c = repo.dirstate.copies()
5285 c = repo.dirstate.copies()
5286 copied, renamed = [], []
5286 copied, renamed = [], []
5287 for d, s in c.iteritems():
5287 for d, s in c.iteritems():
5288 if s in st[2]:
5288 if s in st[2]:
5289 st[2].remove(s)
5289 st[2].remove(s)
5290 renamed.append(d)
5290 renamed.append(d)
5291 else:
5291 else:
5292 copied.append(d)
5292 copied.append(d)
5293 if d in st[1]:
5293 if d in st[1]:
5294 st[1].remove(d)
5294 st[1].remove(d)
5295 st.insert(3, renamed)
5295 st.insert(3, renamed)
5296 st.insert(4, copied)
5296 st.insert(4, copied)
5297
5297
5298 ms = mergemod.mergestate(repo)
5298 ms = mergemod.mergestate(repo)
5299 st.append([f for f in ms if ms[f] == 'u'])
5299 st.append([f for f in ms if ms[f] == 'u'])
5300
5300
5301 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5301 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5302 st.append(subs)
5302 st.append(subs)
5303
5303
5304 labels = [ui.label(_('%d modified'), 'status.modified'),
5304 labels = [ui.label(_('%d modified'), 'status.modified'),
5305 ui.label(_('%d added'), 'status.added'),
5305 ui.label(_('%d added'), 'status.added'),
5306 ui.label(_('%d removed'), 'status.removed'),
5306 ui.label(_('%d removed'), 'status.removed'),
5307 ui.label(_('%d renamed'), 'status.copied'),
5307 ui.label(_('%d renamed'), 'status.copied'),
5308 ui.label(_('%d copied'), 'status.copied'),
5308 ui.label(_('%d copied'), 'status.copied'),
5309 ui.label(_('%d deleted'), 'status.deleted'),
5309 ui.label(_('%d deleted'), 'status.deleted'),
5310 ui.label(_('%d unknown'), 'status.unknown'),
5310 ui.label(_('%d unknown'), 'status.unknown'),
5311 ui.label(_('%d ignored'), 'status.ignored'),
5311 ui.label(_('%d ignored'), 'status.ignored'),
5312 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5312 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5313 ui.label(_('%d subrepos'), 'status.modified')]
5313 ui.label(_('%d subrepos'), 'status.modified')]
5314 t = []
5314 t = []
5315 for s, l in zip(st, labels):
5315 for s, l in zip(st, labels):
5316 if s:
5316 if s:
5317 t.append(l % len(s))
5317 t.append(l % len(s))
5318
5318
5319 t = ', '.join(t)
5319 t = ', '.join(t)
5320 cleanworkdir = False
5320 cleanworkdir = False
5321
5321
5322 if len(parents) > 1:
5322 if len(parents) > 1:
5323 t += _(' (merge)')
5323 t += _(' (merge)')
5324 elif branch != parents[0].branch():
5324 elif branch != parents[0].branch():
5325 t += _(' (new branch)')
5325 t += _(' (new branch)')
5326 elif (parents[0].extra().get('close') and
5326 elif (parents[0].extra().get('close') and
5327 pnode in repo.branchheads(branch, closed=True)):
5327 pnode in repo.branchheads(branch, closed=True)):
5328 t += _(' (head closed)')
5328 t += _(' (head closed)')
5329 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5329 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5330 t += _(' (clean)')
5330 t += _(' (clean)')
5331 cleanworkdir = True
5331 cleanworkdir = True
5332 elif pnode not in bheads:
5332 elif pnode not in bheads:
5333 t += _(' (new branch head)')
5333 t += _(' (new branch head)')
5334
5334
5335 if cleanworkdir:
5335 if cleanworkdir:
5336 ui.status(_('commit: %s\n') % t.strip())
5336 ui.status(_('commit: %s\n') % t.strip())
5337 else:
5337 else:
5338 ui.write(_('commit: %s\n') % t.strip())
5338 ui.write(_('commit: %s\n') % t.strip())
5339
5339
5340 # all ancestors of branch heads - all ancestors of parent = new csets
5340 # all ancestors of branch heads - all ancestors of parent = new csets
5341 new = [0] * len(repo)
5341 new = [0] * len(repo)
5342 cl = repo.changelog
5342 cl = repo.changelog
5343 for a in [cl.rev(n) for n in bheads]:
5343 for a in [cl.rev(n) for n in bheads]:
5344 new[a] = 1
5344 new[a] = 1
5345 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5345 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
5346 new[a] = 1
5346 new[a] = 1
5347 for a in [p.rev() for p in parents]:
5347 for a in [p.rev() for p in parents]:
5348 if a >= 0:
5348 if a >= 0:
5349 new[a] = 0
5349 new[a] = 0
5350 for a in cl.ancestors(*[p.rev() for p in parents]):
5350 for a in cl.ancestors(*[p.rev() for p in parents]):
5351 new[a] = 0
5351 new[a] = 0
5352 new = sum(new)
5352 new = sum(new)
5353
5353
5354 if new == 0:
5354 if new == 0:
5355 ui.status(_('update: (current)\n'))
5355 ui.status(_('update: (current)\n'))
5356 elif pnode not in bheads:
5356 elif pnode not in bheads:
5357 ui.write(_('update: %d new changesets (update)\n') % new)
5357 ui.write(_('update: %d new changesets (update)\n') % new)
5358 else:
5358 else:
5359 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5359 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5360 (new, len(bheads)))
5360 (new, len(bheads)))
5361
5361
5362 if opts.get('remote'):
5362 if opts.get('remote'):
5363 t = []
5363 t = []
5364 source, branches = hg.parseurl(ui.expandpath('default'))
5364 source, branches = hg.parseurl(ui.expandpath('default'))
5365 other = hg.peer(repo, {}, source)
5365 other = hg.peer(repo, {}, source)
5366 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5366 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
5367 ui.debug('comparing with %s\n' % util.hidepassword(source))
5367 ui.debug('comparing with %s\n' % util.hidepassword(source))
5368 repo.ui.pushbuffer()
5368 repo.ui.pushbuffer()
5369 commoninc = discovery.findcommonincoming(repo, other)
5369 commoninc = discovery.findcommonincoming(repo, other)
5370 _common, incoming, _rheads = commoninc
5370 _common, incoming, _rheads = commoninc
5371 repo.ui.popbuffer()
5371 repo.ui.popbuffer()
5372 if incoming:
5372 if incoming:
5373 t.append(_('1 or more incoming'))
5373 t.append(_('1 or more incoming'))
5374
5374
5375 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5375 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5376 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5376 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5377 if source != dest:
5377 if source != dest:
5378 other = hg.peer(repo, {}, dest)
5378 other = hg.peer(repo, {}, dest)
5379 commoninc = None
5379 commoninc = None
5380 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5380 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5381 repo.ui.pushbuffer()
5381 repo.ui.pushbuffer()
5382 common, outheads = discovery.findcommonoutgoing(repo, other,
5382 common, outheads = discovery.findcommonoutgoing(repo, other,
5383 commoninc=commoninc)
5383 commoninc=commoninc)
5384 repo.ui.popbuffer()
5384 repo.ui.popbuffer()
5385 o = repo.changelog.findmissing(common=common, heads=outheads)
5385 o = repo.changelog.findmissing(common=common, heads=outheads)
5386 if o:
5386 if o:
5387 t.append(_('%d outgoing') % len(o))
5387 t.append(_('%d outgoing') % len(o))
5388 if 'bookmarks' in other.listkeys('namespaces'):
5388 if 'bookmarks' in other.listkeys('namespaces'):
5389 lmarks = repo.listkeys('bookmarks')
5389 lmarks = repo.listkeys('bookmarks')
5390 rmarks = other.listkeys('bookmarks')
5390 rmarks = other.listkeys('bookmarks')
5391 diff = set(rmarks) - set(lmarks)
5391 diff = set(rmarks) - set(lmarks)
5392 if len(diff) > 0:
5392 if len(diff) > 0:
5393 t.append(_('%d incoming bookmarks') % len(diff))
5393 t.append(_('%d incoming bookmarks') % len(diff))
5394 diff = set(lmarks) - set(rmarks)
5394 diff = set(lmarks) - set(rmarks)
5395 if len(diff) > 0:
5395 if len(diff) > 0:
5396 t.append(_('%d outgoing bookmarks') % len(diff))
5396 t.append(_('%d outgoing bookmarks') % len(diff))
5397
5397
5398 if t:
5398 if t:
5399 ui.write(_('remote: %s\n') % (', '.join(t)))
5399 ui.write(_('remote: %s\n') % (', '.join(t)))
5400 else:
5400 else:
5401 ui.status(_('remote: (synced)\n'))
5401 ui.status(_('remote: (synced)\n'))
5402
5402
5403 @command('tag',
5403 @command('tag',
5404 [('f', 'force', None, _('force tag')),
5404 [('f', 'force', None, _('force tag')),
5405 ('l', 'local', None, _('make the tag local')),
5405 ('l', 'local', None, _('make the tag local')),
5406 ('r', 'rev', '', _('revision to tag'), _('REV')),
5406 ('r', 'rev', '', _('revision to tag'), _('REV')),
5407 ('', 'remove', None, _('remove a tag')),
5407 ('', 'remove', None, _('remove a tag')),
5408 # -l/--local is already there, commitopts cannot be used
5408 # -l/--local is already there, commitopts cannot be used
5409 ('e', 'edit', None, _('edit commit message')),
5409 ('e', 'edit', None, _('edit commit message')),
5410 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5410 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5411 ] + commitopts2,
5411 ] + commitopts2,
5412 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5412 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5413 def tag(ui, repo, name1, *names, **opts):
5413 def tag(ui, repo, name1, *names, **opts):
5414 """add one or more tags for the current or given revision
5414 """add one or more tags for the current or given revision
5415
5415
5416 Name a particular revision using <name>.
5416 Name a particular revision using <name>.
5417
5417
5418 Tags are used to name particular revisions of the repository and are
5418 Tags are used to name particular revisions of the repository and are
5419 very useful to compare different revisions, to go back to significant
5419 very useful to compare different revisions, to go back to significant
5420 earlier versions or to mark branch points as releases, etc. Changing
5420 earlier versions or to mark branch points as releases, etc. Changing
5421 an existing tag is normally disallowed; use -f/--force to override.
5421 an existing tag is normally disallowed; use -f/--force to override.
5422
5422
5423 If no revision is given, the parent of the working directory is
5423 If no revision is given, the parent of the working directory is
5424 used, or tip if no revision is checked out.
5424 used, or tip if no revision is checked out.
5425
5425
5426 To facilitate version control, distribution, and merging of tags,
5426 To facilitate version control, distribution, and merging of tags,
5427 they are stored as a file named ".hgtags" which is managed similarly
5427 they are stored as a file named ".hgtags" which is managed similarly
5428 to other project files and can be hand-edited if necessary. This
5428 to other project files and can be hand-edited if necessary. This
5429 also means that tagging creates a new commit. The file
5429 also means that tagging creates a new commit. The file
5430 ".hg/localtags" is used for local tags (not shared among
5430 ".hg/localtags" is used for local tags (not shared among
5431 repositories).
5431 repositories).
5432
5432
5433 Tag commits are usually made at the head of a branch. If the parent
5433 Tag commits are usually made at the head of a branch. If the parent
5434 of the working directory is not a branch head, :hg:`tag` aborts; use
5434 of the working directory is not a branch head, :hg:`tag` aborts; use
5435 -f/--force to force the tag commit to be based on a non-head
5435 -f/--force to force the tag commit to be based on a non-head
5436 changeset.
5436 changeset.
5437
5437
5438 See :hg:`help dates` for a list of formats valid for -d/--date.
5438 See :hg:`help dates` for a list of formats valid for -d/--date.
5439
5439
5440 Since tag names have priority over branch names during revision
5440 Since tag names have priority over branch names during revision
5441 lookup, using an existing branch name as a tag name is discouraged.
5441 lookup, using an existing branch name as a tag name is discouraged.
5442
5442
5443 Returns 0 on success.
5443 Returns 0 on success.
5444 """
5444 """
5445
5445
5446 rev_ = "."
5446 rev_ = "."
5447 names = [t.strip() for t in (name1,) + names]
5447 names = [t.strip() for t in (name1,) + names]
5448 if len(names) != len(set(names)):
5448 if len(names) != len(set(names)):
5449 raise util.Abort(_('tag names must be unique'))
5449 raise util.Abort(_('tag names must be unique'))
5450 for n in names:
5450 for n in names:
5451 if n in ['tip', '.', 'null']:
5451 if n in ['tip', '.', 'null']:
5452 raise util.Abort(_("the name '%s' is reserved") % n)
5452 raise util.Abort(_("the name '%s' is reserved") % n)
5453 if not n:
5453 if not n:
5454 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5454 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
5455 if opts.get('rev') and opts.get('remove'):
5455 if opts.get('rev') and opts.get('remove'):
5456 raise util.Abort(_("--rev and --remove are incompatible"))
5456 raise util.Abort(_("--rev and --remove are incompatible"))
5457 if opts.get('rev'):
5457 if opts.get('rev'):
5458 rev_ = opts['rev']
5458 rev_ = opts['rev']
5459 message = opts.get('message')
5459 message = opts.get('message')
5460 if opts.get('remove'):
5460 if opts.get('remove'):
5461 expectedtype = opts.get('local') and 'local' or 'global'
5461 expectedtype = opts.get('local') and 'local' or 'global'
5462 for n in names:
5462 for n in names:
5463 if not repo.tagtype(n):
5463 if not repo.tagtype(n):
5464 raise util.Abort(_("tag '%s' does not exist") % n)
5464 raise util.Abort(_("tag '%s' does not exist") % n)
5465 if repo.tagtype(n) != expectedtype:
5465 if repo.tagtype(n) != expectedtype:
5466 if expectedtype == 'global':
5466 if expectedtype == 'global':
5467 raise util.Abort(_("tag '%s' is not a global tag") % n)
5467 raise util.Abort(_("tag '%s' is not a global tag") % n)
5468 else:
5468 else:
5469 raise util.Abort(_("tag '%s' is not a local tag") % n)
5469 raise util.Abort(_("tag '%s' is not a local tag") % n)
5470 rev_ = nullid
5470 rev_ = nullid
5471 if not message:
5471 if not message:
5472 # we don't translate commit messages
5472 # we don't translate commit messages
5473 message = 'Removed tag %s' % ', '.join(names)
5473 message = 'Removed tag %s' % ', '.join(names)
5474 elif not opts.get('force'):
5474 elif not opts.get('force'):
5475 for n in names:
5475 for n in names:
5476 if n in repo.tags():
5476 if n in repo.tags():
5477 raise util.Abort(_("tag '%s' already exists "
5477 raise util.Abort(_("tag '%s' already exists "
5478 "(use -f to force)") % n)
5478 "(use -f to force)") % n)
5479 if not opts.get('local'):
5479 if not opts.get('local'):
5480 p1, p2 = repo.dirstate.parents()
5480 p1, p2 = repo.dirstate.parents()
5481 if p2 != nullid:
5481 if p2 != nullid:
5482 raise util.Abort(_('uncommitted merge'))
5482 raise util.Abort(_('uncommitted merge'))
5483 bheads = repo.branchheads()
5483 bheads = repo.branchheads()
5484 if not opts.get('force') and bheads and p1 not in bheads:
5484 if not opts.get('force') and bheads and p1 not in bheads:
5485 raise util.Abort(_('not at a branch head (use -f to force)'))
5485 raise util.Abort(_('not at a branch head (use -f to force)'))
5486 r = scmutil.revsingle(repo, rev_).node()
5486 r = scmutil.revsingle(repo, rev_).node()
5487
5487
5488 if not message:
5488 if not message:
5489 # we don't translate commit messages
5489 # we don't translate commit messages
5490 message = ('Added tag %s for changeset %s' %
5490 message = ('Added tag %s for changeset %s' %
5491 (', '.join(names), short(r)))
5491 (', '.join(names), short(r)))
5492
5492
5493 date = opts.get('date')
5493 date = opts.get('date')
5494 if date:
5494 if date:
5495 date = util.parsedate(date)
5495 date = util.parsedate(date)
5496
5496
5497 if opts.get('edit'):
5497 if opts.get('edit'):
5498 message = ui.edit(message, ui.username())
5498 message = ui.edit(message, ui.username())
5499
5499
5500 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5500 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5501
5501
5502 @command('tags', [], '')
5502 @command('tags', [], '')
5503 def tags(ui, repo):
5503 def tags(ui, repo):
5504 """list repository tags
5504 """list repository tags
5505
5505
5506 This lists both regular and local tags. When the -v/--verbose
5506 This lists both regular and local tags. When the -v/--verbose
5507 switch is used, a third column "local" is printed for local tags.
5507 switch is used, a third column "local" is printed for local tags.
5508
5508
5509 Returns 0 on success.
5509 Returns 0 on success.
5510 """
5510 """
5511
5511
5512 hexfunc = ui.debugflag and hex or short
5512 hexfunc = ui.debugflag and hex or short
5513 tagtype = ""
5513 tagtype = ""
5514
5514
5515 for t, n in reversed(repo.tagslist()):
5515 for t, n in reversed(repo.tagslist()):
5516 if ui.quiet:
5516 if ui.quiet:
5517 ui.write("%s\n" % t, label='tags.normal')
5517 ui.write("%s\n" % t, label='tags.normal')
5518 continue
5518 continue
5519
5519
5520 hn = hexfunc(n)
5520 hn = hexfunc(n)
5521 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5521 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5522 rev = ui.label(r, 'log.changeset')
5522 rev = ui.label(r, 'log.changeset')
5523 spaces = " " * (30 - encoding.colwidth(t))
5523 spaces = " " * (30 - encoding.colwidth(t))
5524
5524
5525 tag = ui.label(t, 'tags.normal')
5525 tag = ui.label(t, 'tags.normal')
5526 if ui.verbose:
5526 if ui.verbose:
5527 if repo.tagtype(t) == 'local':
5527 if repo.tagtype(t) == 'local':
5528 tagtype = " local"
5528 tagtype = " local"
5529 tag = ui.label(t, 'tags.local')
5529 tag = ui.label(t, 'tags.local')
5530 else:
5530 else:
5531 tagtype = ""
5531 tagtype = ""
5532 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5532 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5533
5533
5534 @command('tip',
5534 @command('tip',
5535 [('p', 'patch', None, _('show patch')),
5535 [('p', 'patch', None, _('show patch')),
5536 ('g', 'git', None, _('use git extended diff format')),
5536 ('g', 'git', None, _('use git extended diff format')),
5537 ] + templateopts,
5537 ] + templateopts,
5538 _('[-p] [-g]'))
5538 _('[-p] [-g]'))
5539 def tip(ui, repo, **opts):
5539 def tip(ui, repo, **opts):
5540 """show the tip revision
5540 """show the tip revision
5541
5541
5542 The tip revision (usually just called the tip) is the changeset
5542 The tip revision (usually just called the tip) is the changeset
5543 most recently added to the repository (and therefore the most
5543 most recently added to the repository (and therefore the most
5544 recently changed head).
5544 recently changed head).
5545
5545
5546 If you have just made a commit, that commit will be the tip. If
5546 If you have just made a commit, that commit will be the tip. If
5547 you have just pulled changes from another repository, the tip of
5547 you have just pulled changes from another repository, the tip of
5548 that repository becomes the current tip. The "tip" tag is special
5548 that repository becomes the current tip. The "tip" tag is special
5549 and cannot be renamed or assigned to a different changeset.
5549 and cannot be renamed or assigned to a different changeset.
5550
5550
5551 Returns 0 on success.
5551 Returns 0 on success.
5552 """
5552 """
5553 displayer = cmdutil.show_changeset(ui, repo, opts)
5553 displayer = cmdutil.show_changeset(ui, repo, opts)
5554 displayer.show(repo[len(repo) - 1])
5554 displayer.show(repo[len(repo) - 1])
5555 displayer.close()
5555 displayer.close()
5556
5556
5557 @command('unbundle',
5557 @command('unbundle',
5558 [('u', 'update', None,
5558 [('u', 'update', None,
5559 _('update to new branch head if changesets were unbundled'))],
5559 _('update to new branch head if changesets were unbundled'))],
5560 _('[-u] FILE...'))
5560 _('[-u] FILE...'))
5561 def unbundle(ui, repo, fname1, *fnames, **opts):
5561 def unbundle(ui, repo, fname1, *fnames, **opts):
5562 """apply one or more changegroup files
5562 """apply one or more changegroup files
5563
5563
5564 Apply one or more compressed changegroup files generated by the
5564 Apply one or more compressed changegroup files generated by the
5565 bundle command.
5565 bundle command.
5566
5566
5567 Returns 0 on success, 1 if an update has unresolved files.
5567 Returns 0 on success, 1 if an update has unresolved files.
5568 """
5568 """
5569 fnames = (fname1,) + fnames
5569 fnames = (fname1,) + fnames
5570
5570
5571 lock = repo.lock()
5571 lock = repo.lock()
5572 wc = repo['.']
5572 wc = repo['.']
5573 try:
5573 try:
5574 for fname in fnames:
5574 for fname in fnames:
5575 f = url.open(ui, fname)
5575 f = url.open(ui, fname)
5576 gen = changegroup.readbundle(f, fname)
5576 gen = changegroup.readbundle(f, fname)
5577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5577 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
5578 lock=lock)
5578 lock=lock)
5579 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5579 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5580 finally:
5580 finally:
5581 lock.release()
5581 lock.release()
5582 return postincoming(ui, repo, modheads, opts.get('update'), None)
5582 return postincoming(ui, repo, modheads, opts.get('update'), None)
5583
5583
5584 @command('^update|up|checkout|co',
5584 @command('^update|up|checkout|co',
5585 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5585 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5586 ('c', 'check', None,
5586 ('c', 'check', None,
5587 _('update across branches if no uncommitted changes')),
5587 _('update across branches if no uncommitted changes')),
5588 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5588 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5589 ('r', 'rev', '', _('revision'), _('REV'))],
5589 ('r', 'rev', '', _('revision'), _('REV'))],
5590 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5590 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5591 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5591 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5592 """update working directory (or switch revisions)
5592 """update working directory (or switch revisions)
5593
5593
5594 Update the repository's working directory to the specified
5594 Update the repository's working directory to the specified
5595 changeset. If no changeset is specified, update to the tip of the
5595 changeset. If no changeset is specified, update to the tip of the
5596 current named branch.
5596 current named branch.
5597
5597
5598 If the changeset is not a descendant of the working directory's
5598 If the changeset is not a descendant of the working directory's
5599 parent, the update is aborted. With the -c/--check option, the
5599 parent, the update is aborted. With the -c/--check option, the
5600 working directory is checked for uncommitted changes; if none are
5600 working directory is checked for uncommitted changes; if none are
5601 found, the working directory is updated to the specified
5601 found, the working directory is updated to the specified
5602 changeset.
5602 changeset.
5603
5603
5604 Update sets the working directory's parent revison to the specified
5604 Update sets the working directory's parent revison to the specified
5605 changeset (see :hg:`help parents`).
5605 changeset (see :hg:`help parents`).
5606
5606
5607 The following rules apply when the working directory contains
5607 The following rules apply when the working directory contains
5608 uncommitted changes:
5608 uncommitted changes:
5609
5609
5610 1. If neither -c/--check nor -C/--clean is specified, and if
5610 1. If neither -c/--check nor -C/--clean is specified, and if
5611 the requested changeset is an ancestor or descendant of
5611 the requested changeset is an ancestor or descendant of
5612 the working directory's parent, the uncommitted changes
5612 the working directory's parent, the uncommitted changes
5613 are merged into the requested changeset and the merged
5613 are merged into the requested changeset and the merged
5614 result is left uncommitted. If the requested changeset is
5614 result is left uncommitted. If the requested changeset is
5615 not an ancestor or descendant (that is, it is on another
5615 not an ancestor or descendant (that is, it is on another
5616 branch), the update is aborted and the uncommitted changes
5616 branch), the update is aborted and the uncommitted changes
5617 are preserved.
5617 are preserved.
5618
5618
5619 2. With the -c/--check option, the update is aborted and the
5619 2. With the -c/--check option, the update is aborted and the
5620 uncommitted changes are preserved.
5620 uncommitted changes are preserved.
5621
5621
5622 3. With the -C/--clean option, uncommitted changes are discarded and
5622 3. With the -C/--clean option, uncommitted changes are discarded and
5623 the working directory is updated to the requested changeset.
5623 the working directory is updated to the requested changeset.
5624
5624
5625 Use null as the changeset to remove the working directory (like
5625 Use null as the changeset to remove the working directory (like
5626 :hg:`clone -U`).
5626 :hg:`clone -U`).
5627
5627
5628 If you want to revert just one file to an older revision, use
5628 If you want to revert just one file to an older revision, use
5629 :hg:`revert [-r REV] NAME`.
5629 :hg:`revert [-r REV] NAME`.
5630
5630
5631 See :hg:`help dates` for a list of formats valid for -d/--date.
5631 See :hg:`help dates` for a list of formats valid for -d/--date.
5632
5632
5633 Returns 0 on success, 1 if there are unresolved files.
5633 Returns 0 on success, 1 if there are unresolved files.
5634 """
5634 """
5635 if rev and node:
5635 if rev and node:
5636 raise util.Abort(_("please specify just one revision"))
5636 raise util.Abort(_("please specify just one revision"))
5637
5637
5638 if rev is None or rev == '':
5638 if rev is None or rev == '':
5639 rev = node
5639 rev = node
5640
5640
5641 # if we defined a bookmark, we have to remember the original bookmark name
5641 # if we defined a bookmark, we have to remember the original bookmark name
5642 brev = rev
5642 brev = rev
5643 rev = scmutil.revsingle(repo, rev, rev).rev()
5643 rev = scmutil.revsingle(repo, rev, rev).rev()
5644
5644
5645 if check and clean:
5645 if check and clean:
5646 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5646 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5647
5647
5648 if check:
5648 if check:
5649 # we could use dirty() but we can ignore merge and branch trivia
5649 # we could use dirty() but we can ignore merge and branch trivia
5650 c = repo[None]
5650 c = repo[None]
5651 if c.modified() or c.added() or c.removed():
5651 if c.modified() or c.added() or c.removed():
5652 raise util.Abort(_("uncommitted local changes"))
5652 raise util.Abort(_("uncommitted local changes"))
5653
5653
5654 if date:
5654 if date:
5655 if rev is not None:
5655 if rev is not None:
5656 raise util.Abort(_("you can't specify a revision and a date"))
5656 raise util.Abort(_("you can't specify a revision and a date"))
5657 rev = cmdutil.finddate(ui, repo, date)
5657 rev = cmdutil.finddate(ui, repo, date)
5658
5658
5659 if clean or check:
5659 if clean or check:
5660 ret = hg.clean(repo, rev)
5660 ret = hg.clean(repo, rev)
5661 else:
5661 else:
5662 ret = hg.update(repo, rev)
5662 ret = hg.update(repo, rev)
5663
5663
5664 if brev in repo._bookmarks:
5664 if brev in repo._bookmarks:
5665 bookmarks.setcurrent(repo, brev)
5665 bookmarks.setcurrent(repo, brev)
5666
5666
5667 return ret
5667 return ret
5668
5668
5669 @command('verify', [])
5669 @command('verify', [])
5670 def verify(ui, repo):
5670 def verify(ui, repo):
5671 """verify the integrity of the repository
5671 """verify the integrity of the repository
5672
5672
5673 Verify the integrity of the current repository.
5673 Verify the integrity of the current repository.
5674
5674
5675 This will perform an extensive check of the repository's
5675 This will perform an extensive check of the repository's
5676 integrity, validating the hashes and checksums of each entry in
5676 integrity, validating the hashes and checksums of each entry in
5677 the changelog, manifest, and tracked files, as well as the
5677 the changelog, manifest, and tracked files, as well as the
5678 integrity of their crosslinks and indices.
5678 integrity of their crosslinks and indices.
5679
5679
5680 Returns 0 on success, 1 if errors are encountered.
5680 Returns 0 on success, 1 if errors are encountered.
5681 """
5681 """
5682 return hg.verify(repo)
5682 return hg.verify(repo)
5683
5683
5684 @command('version', [])
5684 @command('version', [])
5685 def version_(ui):
5685 def version_(ui):
5686 """output version and copyright information"""
5686 """output version and copyright information"""
5687 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5687 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5688 % util.version())
5688 % util.version())
5689 ui.status(_(
5689 ui.status(_(
5690 "(see http://mercurial.selenic.com for more information)\n"
5690 "(see http://mercurial.selenic.com for more information)\n"
5691 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5691 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
5692 "This is free software; see the source for copying conditions. "
5692 "This is free software; see the source for copying conditions. "
5693 "There is NO\nwarranty; "
5693 "There is NO\nwarranty; "
5694 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5694 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5695 ))
5695 ))
5696
5696
5697 norepo = ("clone init version help debugcommands debugcomplete"
5697 norepo = ("clone init version help debugcommands debugcomplete"
5698 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5698 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5699 " debugknown debuggetbundle debugbundle")
5699 " debugknown debuggetbundle debugbundle")
5700 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5700 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5701 " debugdata debugindex debugindexdot debugrevlog")
5701 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,274 +1,274 b''
1 $ hg init repo1
1 $ hg init repo1
2 $ cd repo1
2 $ cd repo1
3 $ mkdir a b a/1 b/1 b/2
3 $ mkdir a b a/1 b/1 b/2
4 $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
4 $ touch in_root a/in_a b/in_b a/1/in_a_1 b/1/in_b_1 b/2/in_b_2
5
5
6 hg status in repo root:
6 hg status in repo root:
7
7
8 $ hg status
8 $ hg status
9 ? a/1/in_a_1
9 ? a/1/in_a_1
10 ? a/in_a
10 ? a/in_a
11 ? b/1/in_b_1
11 ? b/1/in_b_1
12 ? b/2/in_b_2
12 ? b/2/in_b_2
13 ? b/in_b
13 ? b/in_b
14 ? in_root
14 ? in_root
15
15
16 hg status . in repo root:
16 hg status . in repo root:
17
17
18 $ hg status .
18 $ hg status .
19 ? a/1/in_a_1
19 ? a/1/in_a_1
20 ? a/in_a
20 ? a/in_a
21 ? b/1/in_b_1
21 ? b/1/in_b_1
22 ? b/2/in_b_2
22 ? b/2/in_b_2
23 ? b/in_b
23 ? b/in_b
24 ? in_root
24 ? in_root
25
25
26 $ hg status --cwd a
26 $ hg status --cwd a
27 ? a/1/in_a_1
27 ? a/1/in_a_1
28 ? a/in_a
28 ? a/in_a
29 ? b/1/in_b_1
29 ? b/1/in_b_1
30 ? b/2/in_b_2
30 ? b/2/in_b_2
31 ? b/in_b
31 ? b/in_b
32 ? in_root
32 ? in_root
33 $ hg status --cwd a .
33 $ hg status --cwd a .
34 ? 1/in_a_1
34 ? 1/in_a_1
35 ? in_a
35 ? in_a
36 $ hg status --cwd a ..
36 $ hg status --cwd a ..
37 ? 1/in_a_1
37 ? 1/in_a_1
38 ? in_a
38 ? in_a
39 ? ../b/1/in_b_1
39 ? ../b/1/in_b_1
40 ? ../b/2/in_b_2
40 ? ../b/2/in_b_2
41 ? ../b/in_b
41 ? ../b/in_b
42 ? ../in_root
42 ? ../in_root
43
43
44 $ hg status --cwd b
44 $ hg status --cwd b
45 ? a/1/in_a_1
45 ? a/1/in_a_1
46 ? a/in_a
46 ? a/in_a
47 ? b/1/in_b_1
47 ? b/1/in_b_1
48 ? b/2/in_b_2
48 ? b/2/in_b_2
49 ? b/in_b
49 ? b/in_b
50 ? in_root
50 ? in_root
51 $ hg status --cwd b .
51 $ hg status --cwd b .
52 ? 1/in_b_1
52 ? 1/in_b_1
53 ? 2/in_b_2
53 ? 2/in_b_2
54 ? in_b
54 ? in_b
55 $ hg status --cwd b ..
55 $ hg status --cwd b ..
56 ? ../a/1/in_a_1
56 ? ../a/1/in_a_1
57 ? ../a/in_a
57 ? ../a/in_a
58 ? 1/in_b_1
58 ? 1/in_b_1
59 ? 2/in_b_2
59 ? 2/in_b_2
60 ? in_b
60 ? in_b
61 ? ../in_root
61 ? ../in_root
62
62
63 $ hg status --cwd a/1
63 $ hg status --cwd a/1
64 ? a/1/in_a_1
64 ? a/1/in_a_1
65 ? a/in_a
65 ? a/in_a
66 ? b/1/in_b_1
66 ? b/1/in_b_1
67 ? b/2/in_b_2
67 ? b/2/in_b_2
68 ? b/in_b
68 ? b/in_b
69 ? in_root
69 ? in_root
70 $ hg status --cwd a/1 .
70 $ hg status --cwd a/1 .
71 ? in_a_1
71 ? in_a_1
72 $ hg status --cwd a/1 ..
72 $ hg status --cwd a/1 ..
73 ? in_a_1
73 ? in_a_1
74 ? ../in_a
74 ? ../in_a
75
75
76 $ hg status --cwd b/1
76 $ hg status --cwd b/1
77 ? a/1/in_a_1
77 ? a/1/in_a_1
78 ? a/in_a
78 ? a/in_a
79 ? b/1/in_b_1
79 ? b/1/in_b_1
80 ? b/2/in_b_2
80 ? b/2/in_b_2
81 ? b/in_b
81 ? b/in_b
82 ? in_root
82 ? in_root
83 $ hg status --cwd b/1 .
83 $ hg status --cwd b/1 .
84 ? in_b_1
84 ? in_b_1
85 $ hg status --cwd b/1 ..
85 $ hg status --cwd b/1 ..
86 ? in_b_1
86 ? in_b_1
87 ? ../2/in_b_2
87 ? ../2/in_b_2
88 ? ../in_b
88 ? ../in_b
89
89
90 $ hg status --cwd b/2
90 $ hg status --cwd b/2
91 ? a/1/in_a_1
91 ? a/1/in_a_1
92 ? a/in_a
92 ? a/in_a
93 ? b/1/in_b_1
93 ? b/1/in_b_1
94 ? b/2/in_b_2
94 ? b/2/in_b_2
95 ? b/in_b
95 ? b/in_b
96 ? in_root
96 ? in_root
97 $ hg status --cwd b/2 .
97 $ hg status --cwd b/2 .
98 ? in_b_2
98 ? in_b_2
99 $ hg status --cwd b/2 ..
99 $ hg status --cwd b/2 ..
100 ? ../1/in_b_1
100 ? ../1/in_b_1
101 ? in_b_2
101 ? in_b_2
102 ? ../in_b
102 ? ../in_b
103 $ cd ..
103 $ cd ..
104
104
105 $ hg init repo2
105 $ hg init repo2
106 $ cd repo2
106 $ cd repo2
107 $ touch modified removed deleted ignored
107 $ touch modified removed deleted ignored
108 $ echo "^ignored$" > .hgignore
108 $ echo "^ignored$" > .hgignore
109 $ hg ci -A -m 'initial checkin'
109 $ hg ci -A -m 'initial checkin'
110 adding .hgignore
110 adding .hgignore
111 adding deleted
111 adding deleted
112 adding modified
112 adding modified
113 adding removed
113 adding removed
114 $ touch modified added unknown ignored
114 $ touch modified added unknown ignored
115 $ hg add added
115 $ hg add added
116 $ hg remove removed
116 $ hg remove removed
117 $ rm deleted
117 $ rm deleted
118
118
119 hg status:
119 hg status:
120
120
121 $ hg status
121 $ hg status
122 A added
122 A added
123 R removed
123 R removed
124 ! deleted
124 ! deleted
125 ? unknown
125 ? unknown
126
126
127 hg status modified added removed deleted unknown never-existed ignored:
127 hg status modified added removed deleted unknown never-existed ignored:
128
128
129 $ hg status modified added removed deleted unknown never-existed ignored
129 $ hg status modified added removed deleted unknown never-existed ignored
130 never-existed: * (glob)
130 never-existed: * (glob)
131 A added
131 A added
132 R removed
132 R removed
133 ! deleted
133 ! deleted
134 ? unknown
134 ? unknown
135
135
136 $ hg copy modified copied
136 $ hg copy modified copied
137
137
138 hg status -C:
138 hg status -C:
139
139
140 $ hg status -C
140 $ hg status -C
141 A added
141 A added
142 A copied
142 A copied
143 modified
143 modified
144 R removed
144 R removed
145 ! deleted
145 ! deleted
146 ? unknown
146 ? unknown
147
147
148 hg status -A:
148 hg status -A:
149
149
150 $ hg status -A
150 $ hg status -A
151 A added
151 A added
152 A copied
152 A copied
153 modified
153 modified
154 R removed
154 R removed
155 ! deleted
155 ! deleted
156 ? unknown
156 ? unknown
157 I ignored
157 I ignored
158 C .hgignore
158 C .hgignore
159 C modified
159 C modified
160
160
161
161
162 $ echo "^ignoreddir$" > .hgignore
162 $ echo "^ignoreddir$" > .hgignore
163 $ mkdir ignoreddir
163 $ mkdir ignoreddir
164 $ touch ignoreddir/file
164 $ touch ignoreddir/file
165
165
166 hg status ignoreddir/file:
166 hg status ignoreddir/file:
167
167
168 $ hg status ignoreddir/file
168 $ hg status ignoreddir/file
169
169
170 hg status -i ignoreddir/file:
170 hg status -i ignoreddir/file:
171
171
172 $ hg status -i ignoreddir/file
172 $ hg status -i ignoreddir/file
173 I ignoreddir/file
173 I ignoreddir/file
174 $ cd ..
174 $ cd ..
175
175
176 Check 'status -q' and some combinations
176 Check 'status -q' and some combinations
177
177
178 $ hg init repo3
178 $ hg init repo3
179 $ cd repo3
179 $ cd repo3
180 $ touch modified removed deleted ignored
180 $ touch modified removed deleted ignored
181 $ echo "^ignored$" > .hgignore
181 $ echo "^ignored$" > .hgignore
182 $ hg commit -A -m 'initial checkin'
182 $ hg commit -A -m 'initial checkin'
183 adding .hgignore
183 adding .hgignore
184 adding deleted
184 adding deleted
185 adding modified
185 adding modified
186 adding removed
186 adding removed
187 $ touch added unknown ignored
187 $ touch added unknown ignored
188 $ hg add added
188 $ hg add added
189 $ echo "test" >> modified
189 $ echo "test" >> modified
190 $ hg remove removed
190 $ hg remove removed
191 $ rm deleted
191 $ rm deleted
192 $ hg copy modified copied
192 $ hg copy modified copied
193
193
194 Run status with 2 different flags.
194 Run status with 2 different flags.
195 Check if result is the same or different.
195 Check if result is the same or different.
196 If result is not as expected, raise error
196 If result is not as expected, raise error
197
197
198 $ assert() {
198 $ assert() {
199 > hg status $1 > ../a
199 > hg status $1 > ../a
200 > hg status $2 > ../b
200 > hg status $2 > ../b
201 > if diff ../a ../b > /dev/null; then
201 > if diff ../a ../b > /dev/null; then
202 > out=0
202 > out=0
203 > else
203 > else
204 > out=1
204 > out=1
205 > fi
205 > fi
206 > if [ $3 -eq 0 ]; then
206 > if [ $3 -eq 0 ]; then
207 > df="same"
207 > df="same"
208 > else
208 > else
209 > df="different"
209 > df="different"
210 > fi
210 > fi
211 > if [ $out -ne $3 ]; then
211 > if [ $out -ne $3 ]; then
212 > echo "Error on $1 and $2, should be $df."
212 > echo "Error on $1 and $2, should be $df."
213 > fi
213 > fi
214 > }
214 > }
215
215
216 Assert flag1 flag2 [0-same | 1-different]
216 Assert flag1 flag2 [0-same | 1-different]
217
217
218 $ assert "-q" "-mard" 0
218 $ assert "-q" "-mard" 0
219 $ assert "-A" "-marduicC" 0
219 $ assert "-A" "-marduicC" 0
220 $ assert "-qA" "-mardcC" 0
220 $ assert "-qA" "-mardcC" 0
221 $ assert "-qAui" "-A" 0
221 $ assert "-qAui" "-A" 0
222 $ assert "-qAu" "-marducC" 0
222 $ assert "-qAu" "-marducC" 0
223 $ assert "-qAi" "-mardicC" 0
223 $ assert "-qAi" "-mardicC" 0
224 $ assert "-qu" "-u" 0
224 $ assert "-qu" "-u" 0
225 $ assert "-q" "-u" 1
225 $ assert "-q" "-u" 1
226 $ assert "-m" "-a" 1
226 $ assert "-m" "-a" 1
227 $ assert "-r" "-d" 1
227 $ assert "-r" "-d" 1
228 $ cd ..
228 $ cd ..
229
229
230 $ hg init repo4
230 $ hg init repo4
231 $ cd repo4
231 $ cd repo4
232 $ touch modified removed deleted
232 $ touch modified removed deleted
233 $ hg ci -q -A -m 'initial checkin'
233 $ hg ci -q -A -m 'initial checkin'
234 $ touch added unknown
234 $ touch added unknown
235 $ hg add added
235 $ hg add added
236 $ hg remove removed
236 $ hg remove removed
237 $ rm deleted
237 $ rm deleted
238 $ echo x > modified
238 $ echo x > modified
239 $ hg copy modified copied
239 $ hg copy modified copied
240 $ hg ci -m 'test checkin' -d "1000001 0"
240 $ hg ci -m 'test checkin' -d "1000001 0"
241 $ rm *
241 $ rm *
242 $ touch unrelated
242 $ touch unrelated
243 $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0"
243 $ hg ci -q -A -m 'unrelated checkin' -d "1000002 0"
244
244
245 hg status --change 1:
245 hg status --change 1:
246
246
247 $ hg status --change 1
247 $ hg status --change 1
248 M modified
248 M modified
249 A added
249 A added
250 A copied
250 A copied
251 R removed
251 R removed
252
252
253 hg status --change 1 unrelated:
253 hg status --change 1 unrelated:
254
254
255 $ hg status --change 1 unrelated
255 $ hg status --change 1 unrelated
256
256
257 hg status -C --change 1 added modified copied removed deleted:
257 hg status -C --change 1 added modified copied removed deleted:
258
258
259 $ hg status -C --change 1 added modified copied removed deleted
259 $ hg status -C --change 1 added modified copied removed deleted
260 M modified
260 M modified
261 A added
261 A added
262 A copied
262 A copied
263 modified
263 modified
264 R removed
264 R removed
265
265
266 hg status -A --change 1:
266 hg status -A --change 1 and revset:
267
267
268 $ hg status -A --change 1
268 $ hg status -A --change '1|1'
269 M modified
269 M modified
270 A added
270 A added
271 A copied
271 A copied
272 modified
272 modified
273 R removed
273 R removed
274 C deleted
274 C deleted
General Comments 0
You need to be logged in to leave comments. Login now