##// END OF EJS Templates
strip: move bookmarks to nearest ancestor rather than '.'...
Augie Fackler -
r17264:ec7b9bec stable
parent child Browse files
Show More
@@ -1,5871 +1,5881 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. With a
193 Use the -s/--similarity option to detect renamed files. With a
194 parameter greater than 0, this compares every removed file with
194 parameter greater than 0, this compares every removed file with
195 every added file and records those similar enough as renames. This
195 every added file and records those similar enough as renames. This
196 option takes a percentage between 0 (disabled) and 100 (files must
196 option takes a percentage between 0 (disabled) and 100 (files must
197 be identical) as its parameter. Detecting renamed files this way
197 be identical) as its parameter. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed.
199 used to check which files were identified as moved or renamed.
200 If this option is not specified, only renames of identical files
200 If this option is not specified, only renames of identical files
201 are detected.
201 are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (eg. if
546 - mark the current revision, or a known revision, to be skipped (eg. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - forget the current bisection::
552 - forget the current bisection::
553
553
554 hg bisect --reset
554 hg bisect --reset
555
555
556 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
557 revision::
557 revision::
558
558
559 hg bisect --reset
559 hg bisect --reset
560 hg bisect --bad 34
560 hg bisect --bad 34
561 hg bisect --good 12
561 hg bisect --good 12
562 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
563
563
564 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
565 bisection::
565 bisection::
566
566
567 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
568
568
569 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
570 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
571
571
572 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
573
573
574 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
575
575
576 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
577
577
578 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
579
579
580 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
581
581
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
583
583
584 Returns 0 on success.
584 Returns 0 on success.
585 """
585 """
586 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
587 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
588 # one of the parent was not checked.
588 # one of the parent was not checked.
589 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
590 if len(parents) > 1:
590 if len(parents) > 1:
591 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
592 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
593 if num == 1:
593 if num == 1:
594 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
595 return None
595 return None
596
596
597 def print_result(nodes, good):
597 def print_result(nodes, good):
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
599 if len(nodes) == 1:
599 if len(nodes) == 1:
600 # narrowed it down to a single revision
600 # narrowed it down to a single revision
601 if good:
601 if good:
602 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
603 else:
603 else:
604 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
605 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
606 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
607 if extendnode is not None:
607 if extendnode is not None:
608 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
609 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
610 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
611 % extendnode)
611 % extendnode)
612 else:
612 else:
613 # multiple possible revisions
613 # multiple possible revisions
614 if good:
614 if good:
615 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
616 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
617 else:
617 else:
618 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
619 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
620 for n in nodes:
620 for n in nodes:
621 displayer.show(repo[n])
621 displayer.show(repo[n])
622 displayer.close()
622 displayer.close()
623
623
624 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
625 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
626 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
627 return
627 return
628 if not state['good']:
628 if not state['good']:
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
630 else:
630 else:
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
632 return True
632 return True
633
633
634 # backward compatibility
634 # backward compatibility
635 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
637 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
638 if cmd == "good":
638 if cmd == "good":
639 good = True
639 good = True
640 elif cmd == "bad":
640 elif cmd == "bad":
641 bad = True
641 bad = True
642 else:
642 else:
643 reset = True
643 reset = True
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
645 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
646
646
647 if reset:
647 if reset:
648 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
649 if os.path.exists(p):
649 if os.path.exists(p):
650 os.unlink(p)
650 os.unlink(p)
651 return
651 return
652
652
653 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
654
654
655 if command:
655 if command:
656 changesets = 1
656 changesets = 1
657 try:
657 try:
658 node = state['current'][0]
658 node = state['current'][0]
659 except LookupError:
659 except LookupError:
660 if noupdate:
660 if noupdate:
661 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
662 'start a new bisect to fix'))
662 'start a new bisect to fix'))
663 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
664 if p2 != nullid:
664 if p2 != nullid:
665 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
666 try:
666 try:
667 while changesets:
667 while changesets:
668 # update state
668 # update state
669 state['current'] = [node]
669 state['current'] = [node]
670 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
671 status = util.system(command,
671 status = util.system(command,
672 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
673 out=ui.fout)
673 out=ui.fout)
674 if status == 125:
674 if status == 125:
675 transition = "skip"
675 transition = "skip"
676 elif status == 0:
676 elif status == 0:
677 transition = "good"
677 transition = "good"
678 # status < 0 means process was killed
678 # status < 0 means process was killed
679 elif status == 127:
679 elif status == 127:
680 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
681 elif status < 0:
681 elif status < 0:
682 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
683 else:
683 else:
684 transition = "bad"
684 transition = "bad"
685 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
686 rev = None # clear for future iterations
686 rev = None # clear for future iterations
687 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
689 check_state(state, interactive=False)
689 check_state(state, interactive=False)
690 # bisect
690 # bisect
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
692 # update to next check
692 # update to next check
693 node = nodes[0]
693 node = nodes[0]
694 if not noupdate:
694 if not noupdate:
695 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 finally:
697 finally:
698 state['current'] = [node]
698 state['current'] = [node]
699 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
700 print_result(nodes, good)
700 print_result(nodes, good)
701 return
701 return
702
702
703 # update state
703 # update state
704
704
705 if rev:
705 if rev:
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
707 else:
707 else:
708 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
709
709
710 if good or bad or skip:
710 if good or bad or skip:
711 if good:
711 if good:
712 state['good'] += nodes
712 state['good'] += nodes
713 elif bad:
713 elif bad:
714 state['bad'] += nodes
714 state['bad'] += nodes
715 elif skip:
715 elif skip:
716 state['skip'] += nodes
716 state['skip'] += nodes
717 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
718
718
719 if not check_state(state):
719 if not check_state(state):
720 return
720 return
721
721
722 # actually bisect
722 # actually bisect
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
724 if extend:
724 if extend:
725 if not changesets:
725 if not changesets:
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
729 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
730 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
731 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
732 if noupdate:
732 if noupdate:
733 return
733 return
734 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
735 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
736 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
737
737
738 if changesets == 0:
738 if changesets == 0:
739 print_result(nodes, good)
739 print_result(nodes, good)
740 else:
740 else:
741 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
742 node = nodes[0]
742 node = nodes[0]
743 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
744 tests, size = 0, 2
744 tests, size = 0, 2
745 while size <= changesets:
745 while size <= changesets:
746 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
747 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
748 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
749 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
750 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
751 state['current'] = [node]
751 state['current'] = [node]
752 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
753 if not noupdate:
753 if not noupdate:
754 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
755 return hg.clean(repo, node)
755 return hg.clean(repo, node)
756
756
757 @command('bookmarks',
757 @command('bookmarks',
758 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
765 rename=None, inactive=False):
765 rename=None, inactive=False):
766 '''track a line of development with movable markers
766 '''track a line of development with movable markers
767
767
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
771 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
772
772
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
774 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
775 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
776 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
777
777
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
779 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
781 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
782
782
783 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
785 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
786 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
787 '''
787 '''
788 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
789 marks = repo._bookmarks
789 marks = repo._bookmarks
790 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
791
791
792 if delete:
792 if delete:
793 if mark is None:
793 if mark is None:
794 raise util.Abort(_("bookmark name required"))
794 raise util.Abort(_("bookmark name required"))
795 if mark not in marks:
795 if mark not in marks:
796 raise util.Abort(_("bookmark '%s' does not exist") % mark)
796 raise util.Abort(_("bookmark '%s' does not exist") % mark)
797 if mark == repo._bookmarkcurrent:
797 if mark == repo._bookmarkcurrent:
798 bookmarks.setcurrent(repo, None)
798 bookmarks.setcurrent(repo, None)
799 del marks[mark]
799 del marks[mark]
800 bookmarks.write(repo)
800 bookmarks.write(repo)
801 return
801 return
802
802
803 if rename:
803 if rename:
804 if rename not in marks:
804 if rename not in marks:
805 raise util.Abort(_("bookmark '%s' does not exist") % rename)
805 raise util.Abort(_("bookmark '%s' does not exist") % rename)
806 if mark in marks and not force:
806 if mark in marks and not force:
807 raise util.Abort(_("bookmark '%s' already exists "
807 raise util.Abort(_("bookmark '%s' already exists "
808 "(use -f to force)") % mark)
808 "(use -f to force)") % mark)
809 if mark is None:
809 if mark is None:
810 raise util.Abort(_("new bookmark name required"))
810 raise util.Abort(_("new bookmark name required"))
811 marks[mark] = marks[rename]
811 marks[mark] = marks[rename]
812 if repo._bookmarkcurrent == rename and not inactive:
812 if repo._bookmarkcurrent == rename and not inactive:
813 bookmarks.setcurrent(repo, mark)
813 bookmarks.setcurrent(repo, mark)
814 del marks[rename]
814 del marks[rename]
815 bookmarks.write(repo)
815 bookmarks.write(repo)
816 return
816 return
817
817
818 if mark is not None:
818 if mark is not None:
819 if "\n" in mark:
819 if "\n" in mark:
820 raise util.Abort(_("bookmark name cannot contain newlines"))
820 raise util.Abort(_("bookmark name cannot contain newlines"))
821 mark = mark.strip()
821 mark = mark.strip()
822 if not mark:
822 if not mark:
823 raise util.Abort(_("bookmark names cannot consist entirely of "
823 raise util.Abort(_("bookmark names cannot consist entirely of "
824 "whitespace"))
824 "whitespace"))
825 if inactive and mark == repo._bookmarkcurrent:
825 if inactive and mark == repo._bookmarkcurrent:
826 bookmarks.setcurrent(repo, None)
826 bookmarks.setcurrent(repo, None)
827 return
827 return
828 if mark in marks and not force:
828 if mark in marks and not force:
829 raise util.Abort(_("bookmark '%s' already exists "
829 raise util.Abort(_("bookmark '%s' already exists "
830 "(use -f to force)") % mark)
830 "(use -f to force)") % mark)
831 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
831 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
832 and not force):
832 and not force):
833 raise util.Abort(
833 raise util.Abort(
834 _("a bookmark cannot have the name of an existing branch"))
834 _("a bookmark cannot have the name of an existing branch"))
835 if rev:
835 if rev:
836 marks[mark] = repo.lookup(rev)
836 marks[mark] = repo.lookup(rev)
837 else:
837 else:
838 marks[mark] = cur
838 marks[mark] = cur
839 if not inactive and cur == marks[mark]:
839 if not inactive and cur == marks[mark]:
840 bookmarks.setcurrent(repo, mark)
840 bookmarks.setcurrent(repo, mark)
841 bookmarks.write(repo)
841 bookmarks.write(repo)
842 return
842 return
843
843
844 if mark is None:
844 if mark is None:
845 if rev:
845 if rev:
846 raise util.Abort(_("bookmark name required"))
846 raise util.Abort(_("bookmark name required"))
847 if len(marks) == 0:
847 if len(marks) == 0:
848 ui.status(_("no bookmarks set\n"))
848 ui.status(_("no bookmarks set\n"))
849 else:
849 else:
850 for bmark, n in sorted(marks.iteritems()):
850 for bmark, n in sorted(marks.iteritems()):
851 current = repo._bookmarkcurrent
851 current = repo._bookmarkcurrent
852 if bmark == current and n == cur:
852 if bmark == current and n == cur:
853 prefix, label = '*', 'bookmarks.current'
853 prefix, label = '*', 'bookmarks.current'
854 else:
854 else:
855 prefix, label = ' ', ''
855 prefix, label = ' ', ''
856
856
857 if ui.quiet:
857 if ui.quiet:
858 ui.write("%s\n" % bmark, label=label)
858 ui.write("%s\n" % bmark, label=label)
859 else:
859 else:
860 ui.write(" %s %-25s %d:%s\n" % (
860 ui.write(" %s %-25s %d:%s\n" % (
861 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
861 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
862 label=label)
862 label=label)
863 return
863 return
864
864
865 @command('branch',
865 @command('branch',
866 [('f', 'force', None,
866 [('f', 'force', None,
867 _('set branch name even if it shadows an existing branch')),
867 _('set branch name even if it shadows an existing branch')),
868 ('C', 'clean', None, _('reset branch name to parent branch name'))],
868 ('C', 'clean', None, _('reset branch name to parent branch name'))],
869 _('[-fC] [NAME]'))
869 _('[-fC] [NAME]'))
870 def branch(ui, repo, label=None, **opts):
870 def branch(ui, repo, label=None, **opts):
871 """set or show the current branch name
871 """set or show the current branch name
872
872
873 .. note::
873 .. note::
874 Branch names are permanent and global. Use :hg:`bookmark` to create a
874 Branch names are permanent and global. Use :hg:`bookmark` to create a
875 light-weight bookmark instead. See :hg:`help glossary` for more
875 light-weight bookmark instead. See :hg:`help glossary` for more
876 information about named branches and bookmarks.
876 information about named branches and bookmarks.
877
877
878 With no argument, show the current branch name. With one argument,
878 With no argument, show the current branch name. With one argument,
879 set the working directory branch name (the branch will not exist
879 set the working directory branch name (the branch will not exist
880 in the repository until the next commit). Standard practice
880 in the repository until the next commit). Standard practice
881 recommends that primary development take place on the 'default'
881 recommends that primary development take place on the 'default'
882 branch.
882 branch.
883
883
884 Unless -f/--force is specified, branch will not let you set a
884 Unless -f/--force is specified, branch will not let you set a
885 branch name that already exists, even if it's inactive.
885 branch name that already exists, even if it's inactive.
886
886
887 Use -C/--clean to reset the working directory branch to that of
887 Use -C/--clean to reset the working directory branch to that of
888 the parent of the working directory, negating a previous branch
888 the parent of the working directory, negating a previous branch
889 change.
889 change.
890
890
891 Use the command :hg:`update` to switch to an existing branch. Use
891 Use the command :hg:`update` to switch to an existing branch. Use
892 :hg:`commit --close-branch` to mark this branch as closed.
892 :hg:`commit --close-branch` to mark this branch as closed.
893
893
894 Returns 0 on success.
894 Returns 0 on success.
895 """
895 """
896 if not opts.get('clean') and not label:
896 if not opts.get('clean') and not label:
897 ui.write("%s\n" % repo.dirstate.branch())
897 ui.write("%s\n" % repo.dirstate.branch())
898 return
898 return
899
899
900 wlock = repo.wlock()
900 wlock = repo.wlock()
901 try:
901 try:
902 if opts.get('clean'):
902 if opts.get('clean'):
903 label = repo[None].p1().branch()
903 label = repo[None].p1().branch()
904 repo.dirstate.setbranch(label)
904 repo.dirstate.setbranch(label)
905 ui.status(_('reset working directory to branch %s\n') % label)
905 ui.status(_('reset working directory to branch %s\n') % label)
906 elif label:
906 elif label:
907 if not opts.get('force') and label in repo.branchmap():
907 if not opts.get('force') and label in repo.branchmap():
908 if label not in [p.branch() for p in repo.parents()]:
908 if label not in [p.branch() for p in repo.parents()]:
909 raise util.Abort(_('a branch of the same name already'
909 raise util.Abort(_('a branch of the same name already'
910 ' exists'),
910 ' exists'),
911 # i18n: "it" refers to an existing branch
911 # i18n: "it" refers to an existing branch
912 hint=_("use 'hg update' to switch to it"))
912 hint=_("use 'hg update' to switch to it"))
913 repo.dirstate.setbranch(label)
913 repo.dirstate.setbranch(label)
914 ui.status(_('marked working directory as branch %s\n') % label)
914 ui.status(_('marked working directory as branch %s\n') % label)
915 ui.status(_('(branches are permanent and global, '
915 ui.status(_('(branches are permanent and global, '
916 'did you want a bookmark?)\n'))
916 'did you want a bookmark?)\n'))
917 finally:
917 finally:
918 wlock.release()
918 wlock.release()
919
919
920 @command('branches',
920 @command('branches',
921 [('a', 'active', False, _('show only branches that have unmerged heads')),
921 [('a', 'active', False, _('show only branches that have unmerged heads')),
922 ('c', 'closed', False, _('show normal and closed branches'))],
922 ('c', 'closed', False, _('show normal and closed branches'))],
923 _('[-ac]'))
923 _('[-ac]'))
924 def branches(ui, repo, active=False, closed=False):
924 def branches(ui, repo, active=False, closed=False):
925 """list repository named branches
925 """list repository named branches
926
926
927 List the repository's named branches, indicating which ones are
927 List the repository's named branches, indicating which ones are
928 inactive. If -c/--closed is specified, also list branches which have
928 inactive. If -c/--closed is specified, also list branches which have
929 been marked closed (see :hg:`commit --close-branch`).
929 been marked closed (see :hg:`commit --close-branch`).
930
930
931 If -a/--active is specified, only show active branches. A branch
931 If -a/--active is specified, only show active branches. A branch
932 is considered active if it contains repository heads.
932 is considered active if it contains repository heads.
933
933
934 Use the command :hg:`update` to switch to an existing branch.
934 Use the command :hg:`update` to switch to an existing branch.
935
935
936 Returns 0.
936 Returns 0.
937 """
937 """
938
938
939 hexfunc = ui.debugflag and hex or short
939 hexfunc = ui.debugflag and hex or short
940
940
941 activebranches = set([repo[n].branch() for n in repo.heads()])
941 activebranches = set([repo[n].branch() for n in repo.heads()])
942 branches = []
942 branches = []
943 for tag, heads in repo.branchmap().iteritems():
943 for tag, heads in repo.branchmap().iteritems():
944 for h in reversed(heads):
944 for h in reversed(heads):
945 ctx = repo[h]
945 ctx = repo[h]
946 isopen = not ctx.closesbranch()
946 isopen = not ctx.closesbranch()
947 if isopen:
947 if isopen:
948 tip = ctx
948 tip = ctx
949 break
949 break
950 else:
950 else:
951 tip = repo[heads[-1]]
951 tip = repo[heads[-1]]
952 isactive = tag in activebranches and isopen
952 isactive = tag in activebranches and isopen
953 branches.append((tip, isactive, isopen))
953 branches.append((tip, isactive, isopen))
954 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
954 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
955 reverse=True)
955 reverse=True)
956
956
957 for ctx, isactive, isopen in branches:
957 for ctx, isactive, isopen in branches:
958 if (not active) or isactive:
958 if (not active) or isactive:
959 if isactive:
959 if isactive:
960 label = 'branches.active'
960 label = 'branches.active'
961 notice = ''
961 notice = ''
962 elif not isopen:
962 elif not isopen:
963 if not closed:
963 if not closed:
964 continue
964 continue
965 label = 'branches.closed'
965 label = 'branches.closed'
966 notice = _(' (closed)')
966 notice = _(' (closed)')
967 else:
967 else:
968 label = 'branches.inactive'
968 label = 'branches.inactive'
969 notice = _(' (inactive)')
969 notice = _(' (inactive)')
970 if ctx.branch() == repo.dirstate.branch():
970 if ctx.branch() == repo.dirstate.branch():
971 label = 'branches.current'
971 label = 'branches.current'
972 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
972 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
973 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
973 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
974 'log.changeset')
974 'log.changeset')
975 tag = ui.label(ctx.branch(), label)
975 tag = ui.label(ctx.branch(), label)
976 if ui.quiet:
976 if ui.quiet:
977 ui.write("%s\n" % tag)
977 ui.write("%s\n" % tag)
978 else:
978 else:
979 ui.write("%s %s%s\n" % (tag, rev, notice))
979 ui.write("%s %s%s\n" % (tag, rev, notice))
980
980
981 @command('bundle',
981 @command('bundle',
982 [('f', 'force', None, _('run even when the destination is unrelated')),
982 [('f', 'force', None, _('run even when the destination is unrelated')),
983 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
983 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
984 _('REV')),
984 _('REV')),
985 ('b', 'branch', [], _('a specific branch you would like to bundle'),
985 ('b', 'branch', [], _('a specific branch you would like to bundle'),
986 _('BRANCH')),
986 _('BRANCH')),
987 ('', 'base', [],
987 ('', 'base', [],
988 _('a base changeset assumed to be available at the destination'),
988 _('a base changeset assumed to be available at the destination'),
989 _('REV')),
989 _('REV')),
990 ('a', 'all', None, _('bundle all changesets in the repository')),
990 ('a', 'all', None, _('bundle all changesets in the repository')),
991 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
991 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
992 ] + remoteopts,
992 ] + remoteopts,
993 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
993 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
994 def bundle(ui, repo, fname, dest=None, **opts):
994 def bundle(ui, repo, fname, dest=None, **opts):
995 """create a changegroup file
995 """create a changegroup file
996
996
997 Generate a compressed changegroup file collecting changesets not
997 Generate a compressed changegroup file collecting changesets not
998 known to be in another repository.
998 known to be in another repository.
999
999
1000 If you omit the destination repository, then hg assumes the
1000 If you omit the destination repository, then hg assumes the
1001 destination will have all the nodes you specify with --base
1001 destination will have all the nodes you specify with --base
1002 parameters. To create a bundle containing all changesets, use
1002 parameters. To create a bundle containing all changesets, use
1003 -a/--all (or --base null).
1003 -a/--all (or --base null).
1004
1004
1005 You can change compression method with the -t/--type option.
1005 You can change compression method with the -t/--type option.
1006 The available compression methods are: none, bzip2, and
1006 The available compression methods are: none, bzip2, and
1007 gzip (by default, bundles are compressed using bzip2).
1007 gzip (by default, bundles are compressed using bzip2).
1008
1008
1009 The bundle file can then be transferred using conventional means
1009 The bundle file can then be transferred using conventional means
1010 and applied to another repository with the unbundle or pull
1010 and applied to another repository with the unbundle or pull
1011 command. This is useful when direct push and pull are not
1011 command. This is useful when direct push and pull are not
1012 available or when exporting an entire repository is undesirable.
1012 available or when exporting an entire repository is undesirable.
1013
1013
1014 Applying bundles preserves all changeset contents including
1014 Applying bundles preserves all changeset contents including
1015 permissions, copy/rename information, and revision history.
1015 permissions, copy/rename information, and revision history.
1016
1016
1017 Returns 0 on success, 1 if no changes found.
1017 Returns 0 on success, 1 if no changes found.
1018 """
1018 """
1019 revs = None
1019 revs = None
1020 if 'rev' in opts:
1020 if 'rev' in opts:
1021 revs = scmutil.revrange(repo, opts['rev'])
1021 revs = scmutil.revrange(repo, opts['rev'])
1022
1022
1023 bundletype = opts.get('type', 'bzip2').lower()
1023 bundletype = opts.get('type', 'bzip2').lower()
1024 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1024 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1025 bundletype = btypes.get(bundletype)
1025 bundletype = btypes.get(bundletype)
1026 if bundletype not in changegroup.bundletypes:
1026 if bundletype not in changegroup.bundletypes:
1027 raise util.Abort(_('unknown bundle type specified with --type'))
1027 raise util.Abort(_('unknown bundle type specified with --type'))
1028
1028
1029 if opts.get('all'):
1029 if opts.get('all'):
1030 base = ['null']
1030 base = ['null']
1031 else:
1031 else:
1032 base = scmutil.revrange(repo, opts.get('base'))
1032 base = scmutil.revrange(repo, opts.get('base'))
1033 if base:
1033 if base:
1034 if dest:
1034 if dest:
1035 raise util.Abort(_("--base is incompatible with specifying "
1035 raise util.Abort(_("--base is incompatible with specifying "
1036 "a destination"))
1036 "a destination"))
1037 common = [repo.lookup(rev) for rev in base]
1037 common = [repo.lookup(rev) for rev in base]
1038 heads = revs and map(repo.lookup, revs) or revs
1038 heads = revs and map(repo.lookup, revs) or revs
1039 cg = repo.getbundle('bundle', heads=heads, common=common)
1039 cg = repo.getbundle('bundle', heads=heads, common=common)
1040 outgoing = None
1040 outgoing = None
1041 else:
1041 else:
1042 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1042 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1043 dest, branches = hg.parseurl(dest, opts.get('branch'))
1043 dest, branches = hg.parseurl(dest, opts.get('branch'))
1044 other = hg.peer(repo, opts, dest)
1044 other = hg.peer(repo, opts, dest)
1045 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1045 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1046 heads = revs and map(repo.lookup, revs) or revs
1046 heads = revs and map(repo.lookup, revs) or revs
1047 outgoing = discovery.findcommonoutgoing(repo, other,
1047 outgoing = discovery.findcommonoutgoing(repo, other,
1048 onlyheads=heads,
1048 onlyheads=heads,
1049 force=opts.get('force'),
1049 force=opts.get('force'),
1050 portable=True)
1050 portable=True)
1051 cg = repo.getlocalbundle('bundle', outgoing)
1051 cg = repo.getlocalbundle('bundle', outgoing)
1052 if not cg:
1052 if not cg:
1053 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1053 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1054 return 1
1054 return 1
1055
1055
1056 changegroup.writebundle(cg, fname, bundletype)
1056 changegroup.writebundle(cg, fname, bundletype)
1057
1057
1058 @command('cat',
1058 @command('cat',
1059 [('o', 'output', '',
1059 [('o', 'output', '',
1060 _('print output to file with formatted name'), _('FORMAT')),
1060 _('print output to file with formatted name'), _('FORMAT')),
1061 ('r', 'rev', '', _('print the given revision'), _('REV')),
1061 ('r', 'rev', '', _('print the given revision'), _('REV')),
1062 ('', 'decode', None, _('apply any matching decode filter')),
1062 ('', 'decode', None, _('apply any matching decode filter')),
1063 ] + walkopts,
1063 ] + walkopts,
1064 _('[OPTION]... FILE...'))
1064 _('[OPTION]... FILE...'))
1065 def cat(ui, repo, file1, *pats, **opts):
1065 def cat(ui, repo, file1, *pats, **opts):
1066 """output the current or given revision of files
1066 """output the current or given revision of files
1067
1067
1068 Print the specified files as they were at the given revision. If
1068 Print the specified files as they were at the given revision. If
1069 no revision is given, the parent of the working directory is used,
1069 no revision is given, the parent of the working directory is used,
1070 or tip if no revision is checked out.
1070 or tip if no revision is checked out.
1071
1071
1072 Output may be to a file, in which case the name of the file is
1072 Output may be to a file, in which case the name of the file is
1073 given using a format string. The formatting rules are the same as
1073 given using a format string. The formatting rules are the same as
1074 for the export command, with the following additions:
1074 for the export command, with the following additions:
1075
1075
1076 :``%s``: basename of file being printed
1076 :``%s``: basename of file being printed
1077 :``%d``: dirname of file being printed, or '.' if in repository root
1077 :``%d``: dirname of file being printed, or '.' if in repository root
1078 :``%p``: root-relative path name of file being printed
1078 :``%p``: root-relative path name of file being printed
1079
1079
1080 Returns 0 on success.
1080 Returns 0 on success.
1081 """
1081 """
1082 ctx = scmutil.revsingle(repo, opts.get('rev'))
1082 ctx = scmutil.revsingle(repo, opts.get('rev'))
1083 err = 1
1083 err = 1
1084 m = scmutil.match(ctx, (file1,) + pats, opts)
1084 m = scmutil.match(ctx, (file1,) + pats, opts)
1085 for abs in ctx.walk(m):
1085 for abs in ctx.walk(m):
1086 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1086 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1087 pathname=abs)
1087 pathname=abs)
1088 data = ctx[abs].data()
1088 data = ctx[abs].data()
1089 if opts.get('decode'):
1089 if opts.get('decode'):
1090 data = repo.wwritedata(abs, data)
1090 data = repo.wwritedata(abs, data)
1091 fp.write(data)
1091 fp.write(data)
1092 fp.close()
1092 fp.close()
1093 err = 0
1093 err = 0
1094 return err
1094 return err
1095
1095
1096 @command('^clone',
1096 @command('^clone',
1097 [('U', 'noupdate', None,
1097 [('U', 'noupdate', None,
1098 _('the clone will include an empty working copy (only a repository)')),
1098 _('the clone will include an empty working copy (only a repository)')),
1099 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1099 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1100 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1100 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1101 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1101 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1102 ('', 'pull', None, _('use pull protocol to copy metadata')),
1102 ('', 'pull', None, _('use pull protocol to copy metadata')),
1103 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1103 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1104 ] + remoteopts,
1104 ] + remoteopts,
1105 _('[OPTION]... SOURCE [DEST]'))
1105 _('[OPTION]... SOURCE [DEST]'))
1106 def clone(ui, source, dest=None, **opts):
1106 def clone(ui, source, dest=None, **opts):
1107 """make a copy of an existing repository
1107 """make a copy of an existing repository
1108
1108
1109 Create a copy of an existing repository in a new directory.
1109 Create a copy of an existing repository in a new directory.
1110
1110
1111 If no destination directory name is specified, it defaults to the
1111 If no destination directory name is specified, it defaults to the
1112 basename of the source.
1112 basename of the source.
1113
1113
1114 The location of the source is added to the new repository's
1114 The location of the source is added to the new repository's
1115 ``.hg/hgrc`` file, as the default to be used for future pulls.
1115 ``.hg/hgrc`` file, as the default to be used for future pulls.
1116
1116
1117 Only local paths and ``ssh://`` URLs are supported as
1117 Only local paths and ``ssh://`` URLs are supported as
1118 destinations. For ``ssh://`` destinations, no working directory or
1118 destinations. For ``ssh://`` destinations, no working directory or
1119 ``.hg/hgrc`` will be created on the remote side.
1119 ``.hg/hgrc`` will be created on the remote side.
1120
1120
1121 To pull only a subset of changesets, specify one or more revisions
1121 To pull only a subset of changesets, specify one or more revisions
1122 identifiers with -r/--rev or branches with -b/--branch. The
1122 identifiers with -r/--rev or branches with -b/--branch. The
1123 resulting clone will contain only the specified changesets and
1123 resulting clone will contain only the specified changesets and
1124 their ancestors. These options (or 'clone src#rev dest') imply
1124 their ancestors. These options (or 'clone src#rev dest') imply
1125 --pull, even for local source repositories. Note that specifying a
1125 --pull, even for local source repositories. Note that specifying a
1126 tag will include the tagged changeset but not the changeset
1126 tag will include the tagged changeset but not the changeset
1127 containing the tag.
1127 containing the tag.
1128
1128
1129 To check out a particular version, use -u/--update, or
1129 To check out a particular version, use -u/--update, or
1130 -U/--noupdate to create a clone with no working directory.
1130 -U/--noupdate to create a clone with no working directory.
1131
1131
1132 .. container:: verbose
1132 .. container:: verbose
1133
1133
1134 For efficiency, hardlinks are used for cloning whenever the
1134 For efficiency, hardlinks are used for cloning whenever the
1135 source and destination are on the same filesystem (note this
1135 source and destination are on the same filesystem (note this
1136 applies only to the repository data, not to the working
1136 applies only to the repository data, not to the working
1137 directory). Some filesystems, such as AFS, implement hardlinking
1137 directory). Some filesystems, such as AFS, implement hardlinking
1138 incorrectly, but do not report errors. In these cases, use the
1138 incorrectly, but do not report errors. In these cases, use the
1139 --pull option to avoid hardlinking.
1139 --pull option to avoid hardlinking.
1140
1140
1141 In some cases, you can clone repositories and the working
1141 In some cases, you can clone repositories and the working
1142 directory using full hardlinks with ::
1142 directory using full hardlinks with ::
1143
1143
1144 $ cp -al REPO REPOCLONE
1144 $ cp -al REPO REPOCLONE
1145
1145
1146 This is the fastest way to clone, but it is not always safe. The
1146 This is the fastest way to clone, but it is not always safe. The
1147 operation is not atomic (making sure REPO is not modified during
1147 operation is not atomic (making sure REPO is not modified during
1148 the operation is up to you) and you have to make sure your
1148 the operation is up to you) and you have to make sure your
1149 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1149 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1150 so). Also, this is not compatible with certain extensions that
1150 so). Also, this is not compatible with certain extensions that
1151 place their metadata under the .hg directory, such as mq.
1151 place their metadata under the .hg directory, such as mq.
1152
1152
1153 Mercurial will update the working directory to the first applicable
1153 Mercurial will update the working directory to the first applicable
1154 revision from this list:
1154 revision from this list:
1155
1155
1156 a) null if -U or the source repository has no changesets
1156 a) null if -U or the source repository has no changesets
1157 b) if -u . and the source repository is local, the first parent of
1157 b) if -u . and the source repository is local, the first parent of
1158 the source repository's working directory
1158 the source repository's working directory
1159 c) the changeset specified with -u (if a branch name, this means the
1159 c) the changeset specified with -u (if a branch name, this means the
1160 latest head of that branch)
1160 latest head of that branch)
1161 d) the changeset specified with -r
1161 d) the changeset specified with -r
1162 e) the tipmost head specified with -b
1162 e) the tipmost head specified with -b
1163 f) the tipmost head specified with the url#branch source syntax
1163 f) the tipmost head specified with the url#branch source syntax
1164 g) the tipmost head of the default branch
1164 g) the tipmost head of the default branch
1165 h) tip
1165 h) tip
1166
1166
1167 Examples:
1167 Examples:
1168
1168
1169 - clone a remote repository to a new directory named hg/::
1169 - clone a remote repository to a new directory named hg/::
1170
1170
1171 hg clone http://selenic.com/hg
1171 hg clone http://selenic.com/hg
1172
1172
1173 - create a lightweight local clone::
1173 - create a lightweight local clone::
1174
1174
1175 hg clone project/ project-feature/
1175 hg clone project/ project-feature/
1176
1176
1177 - clone from an absolute path on an ssh server (note double-slash)::
1177 - clone from an absolute path on an ssh server (note double-slash)::
1178
1178
1179 hg clone ssh://user@server//home/projects/alpha/
1179 hg clone ssh://user@server//home/projects/alpha/
1180
1180
1181 - do a high-speed clone over a LAN while checking out a
1181 - do a high-speed clone over a LAN while checking out a
1182 specified version::
1182 specified version::
1183
1183
1184 hg clone --uncompressed http://server/repo -u 1.5
1184 hg clone --uncompressed http://server/repo -u 1.5
1185
1185
1186 - create a repository without changesets after a particular revision::
1186 - create a repository without changesets after a particular revision::
1187
1187
1188 hg clone -r 04e544 experimental/ good/
1188 hg clone -r 04e544 experimental/ good/
1189
1189
1190 - clone (and track) a particular named branch::
1190 - clone (and track) a particular named branch::
1191
1191
1192 hg clone http://selenic.com/hg#stable
1192 hg clone http://selenic.com/hg#stable
1193
1193
1194 See :hg:`help urls` for details on specifying URLs.
1194 See :hg:`help urls` for details on specifying URLs.
1195
1195
1196 Returns 0 on success.
1196 Returns 0 on success.
1197 """
1197 """
1198 if opts.get('noupdate') and opts.get('updaterev'):
1198 if opts.get('noupdate') and opts.get('updaterev'):
1199 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1199 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1200
1200
1201 r = hg.clone(ui, opts, source, dest,
1201 r = hg.clone(ui, opts, source, dest,
1202 pull=opts.get('pull'),
1202 pull=opts.get('pull'),
1203 stream=opts.get('uncompressed'),
1203 stream=opts.get('uncompressed'),
1204 rev=opts.get('rev'),
1204 rev=opts.get('rev'),
1205 update=opts.get('updaterev') or not opts.get('noupdate'),
1205 update=opts.get('updaterev') or not opts.get('noupdate'),
1206 branch=opts.get('branch'))
1206 branch=opts.get('branch'))
1207
1207
1208 return r is None
1208 return r is None
1209
1209
1210 @command('^commit|ci',
1210 @command('^commit|ci',
1211 [('A', 'addremove', None,
1211 [('A', 'addremove', None,
1212 _('mark new/missing files as added/removed before committing')),
1212 _('mark new/missing files as added/removed before committing')),
1213 ('', 'close-branch', None,
1213 ('', 'close-branch', None,
1214 _('mark a branch as closed, hiding it from the branch list')),
1214 _('mark a branch as closed, hiding it from the branch list')),
1215 ('', 'amend', None, _('amend the parent of the working dir')),
1215 ('', 'amend', None, _('amend the parent of the working dir')),
1216 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1216 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1217 _('[OPTION]... [FILE]...'))
1217 _('[OPTION]... [FILE]...'))
1218 def commit(ui, repo, *pats, **opts):
1218 def commit(ui, repo, *pats, **opts):
1219 """commit the specified files or all outstanding changes
1219 """commit the specified files or all outstanding changes
1220
1220
1221 Commit changes to the given files into the repository. Unlike a
1221 Commit changes to the given files into the repository. Unlike a
1222 centralized SCM, this operation is a local operation. See
1222 centralized SCM, this operation is a local operation. See
1223 :hg:`push` for a way to actively distribute your changes.
1223 :hg:`push` for a way to actively distribute your changes.
1224
1224
1225 If a list of files is omitted, all changes reported by :hg:`status`
1225 If a list of files is omitted, all changes reported by :hg:`status`
1226 will be committed.
1226 will be committed.
1227
1227
1228 If you are committing the result of a merge, do not provide any
1228 If you are committing the result of a merge, do not provide any
1229 filenames or -I/-X filters.
1229 filenames or -I/-X filters.
1230
1230
1231 If no commit message is specified, Mercurial starts your
1231 If no commit message is specified, Mercurial starts your
1232 configured editor where you can enter a message. In case your
1232 configured editor where you can enter a message. In case your
1233 commit fails, you will find a backup of your message in
1233 commit fails, you will find a backup of your message in
1234 ``.hg/last-message.txt``.
1234 ``.hg/last-message.txt``.
1235
1235
1236 The --amend flag can be used to amend the parent of the
1236 The --amend flag can be used to amend the parent of the
1237 working directory with a new commit that contains the changes
1237 working directory with a new commit that contains the changes
1238 in the parent in addition to those currently reported by :hg:`status`,
1238 in the parent in addition to those currently reported by :hg:`status`,
1239 if there are any. The old commit is stored in a backup bundle in
1239 if there are any. The old commit is stored in a backup bundle in
1240 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1240 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1241 on how to restore it).
1241 on how to restore it).
1242
1242
1243 Message, user and date are taken from the amended commit unless
1243 Message, user and date are taken from the amended commit unless
1244 specified. When a message isn't specified on the command line,
1244 specified. When a message isn't specified on the command line,
1245 the editor will open with the message of the amended commit.
1245 the editor will open with the message of the amended commit.
1246
1246
1247 It is not possible to amend public changesets (see :hg:`help phases`)
1247 It is not possible to amend public changesets (see :hg:`help phases`)
1248 or changesets that have children.
1248 or changesets that have children.
1249
1249
1250 See :hg:`help dates` for a list of formats valid for -d/--date.
1250 See :hg:`help dates` for a list of formats valid for -d/--date.
1251
1251
1252 Returns 0 on success, 1 if nothing changed.
1252 Returns 0 on success, 1 if nothing changed.
1253 """
1253 """
1254 if opts.get('subrepos'):
1254 if opts.get('subrepos'):
1255 # Let --subrepos on the command line overide config setting.
1255 # Let --subrepos on the command line overide config setting.
1256 ui.setconfig('ui', 'commitsubrepos', True)
1256 ui.setconfig('ui', 'commitsubrepos', True)
1257
1257
1258 extra = {}
1258 extra = {}
1259 if opts.get('close_branch'):
1259 if opts.get('close_branch'):
1260 if repo['.'].node() not in repo.branchheads():
1260 if repo['.'].node() not in repo.branchheads():
1261 # The topo heads set is included in the branch heads set of the
1261 # The topo heads set is included in the branch heads set of the
1262 # current branch, so it's sufficient to test branchheads
1262 # current branch, so it's sufficient to test branchheads
1263 raise util.Abort(_('can only close branch heads'))
1263 raise util.Abort(_('can only close branch heads'))
1264 extra['close'] = 1
1264 extra['close'] = 1
1265
1265
1266 branch = repo[None].branch()
1266 branch = repo[None].branch()
1267 bheads = repo.branchheads(branch)
1267 bheads = repo.branchheads(branch)
1268
1268
1269 if opts.get('amend'):
1269 if opts.get('amend'):
1270 if ui.configbool('ui', 'commitsubrepos'):
1270 if ui.configbool('ui', 'commitsubrepos'):
1271 raise util.Abort(_('cannot amend recursively'))
1271 raise util.Abort(_('cannot amend recursively'))
1272
1272
1273 old = repo['.']
1273 old = repo['.']
1274 if old.phase() == phases.public:
1274 if old.phase() == phases.public:
1275 raise util.Abort(_('cannot amend public changesets'))
1275 raise util.Abort(_('cannot amend public changesets'))
1276 if len(old.parents()) > 1:
1276 if len(old.parents()) > 1:
1277 raise util.Abort(_('cannot amend merge changesets'))
1277 raise util.Abort(_('cannot amend merge changesets'))
1278 if len(repo[None].parents()) > 1:
1278 if len(repo[None].parents()) > 1:
1279 raise util.Abort(_('cannot amend while merging'))
1279 raise util.Abort(_('cannot amend while merging'))
1280 if old.children():
1280 if old.children():
1281 raise util.Abort(_('cannot amend changeset with children'))
1281 raise util.Abort(_('cannot amend changeset with children'))
1282
1282
1283 e = cmdutil.commiteditor
1283 e = cmdutil.commiteditor
1284 if opts.get('force_editor'):
1284 if opts.get('force_editor'):
1285 e = cmdutil.commitforceeditor
1285 e = cmdutil.commitforceeditor
1286
1286
1287 def commitfunc(ui, repo, message, match, opts):
1287 def commitfunc(ui, repo, message, match, opts):
1288 editor = e
1288 editor = e
1289 # message contains text from -m or -l, if it's empty,
1289 # message contains text from -m or -l, if it's empty,
1290 # open the editor with the old message
1290 # open the editor with the old message
1291 if not message:
1291 if not message:
1292 message = old.description()
1292 message = old.description()
1293 editor = cmdutil.commitforceeditor
1293 editor = cmdutil.commitforceeditor
1294 return repo.commit(message,
1294 return repo.commit(message,
1295 opts.get('user') or old.user(),
1295 opts.get('user') or old.user(),
1296 opts.get('date') or old.date(),
1296 opts.get('date') or old.date(),
1297 match,
1297 match,
1298 editor=editor,
1298 editor=editor,
1299 extra=extra)
1299 extra=extra)
1300
1300
1301 current = repo._bookmarkcurrent
1302 marks = old.bookmarks()
1301 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1303 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1302 if node == old.node():
1304 if node == old.node():
1303 ui.status(_("nothing changed\n"))
1305 ui.status(_("nothing changed\n"))
1304 return 1
1306 return 1
1307 elif marks:
1308 ui.debug('moving bookmarks %r from %s to %s\n' %
1309 (marks, old.hex(), hex(node)))
1310 for bm in marks:
1311 repo._bookmarks[bm] = node
1312 if bm == current:
1313 bookmarks.setcurrent(repo, bm)
1314 bookmarks.write(repo)
1305 else:
1315 else:
1306 e = cmdutil.commiteditor
1316 e = cmdutil.commiteditor
1307 if opts.get('force_editor'):
1317 if opts.get('force_editor'):
1308 e = cmdutil.commitforceeditor
1318 e = cmdutil.commitforceeditor
1309
1319
1310 def commitfunc(ui, repo, message, match, opts):
1320 def commitfunc(ui, repo, message, match, opts):
1311 return repo.commit(message, opts.get('user'), opts.get('date'),
1321 return repo.commit(message, opts.get('user'), opts.get('date'),
1312 match, editor=e, extra=extra)
1322 match, editor=e, extra=extra)
1313
1323
1314 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1324 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1315
1325
1316 if not node:
1326 if not node:
1317 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1327 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1318 if stat[3]:
1328 if stat[3]:
1319 ui.status(_("nothing changed (%d missing files, see "
1329 ui.status(_("nothing changed (%d missing files, see "
1320 "'hg status')\n") % len(stat[3]))
1330 "'hg status')\n") % len(stat[3]))
1321 else:
1331 else:
1322 ui.status(_("nothing changed\n"))
1332 ui.status(_("nothing changed\n"))
1323 return 1
1333 return 1
1324
1334
1325 ctx = repo[node]
1335 ctx = repo[node]
1326 parents = ctx.parents()
1336 parents = ctx.parents()
1327
1337
1328 if (not opts.get('amend') and bheads and node not in bheads and not
1338 if (not opts.get('amend') and bheads and node not in bheads and not
1329 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1339 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1330 ui.status(_('created new head\n'))
1340 ui.status(_('created new head\n'))
1331 # The message is not printed for initial roots. For the other
1341 # The message is not printed for initial roots. For the other
1332 # changesets, it is printed in the following situations:
1342 # changesets, it is printed in the following situations:
1333 #
1343 #
1334 # Par column: for the 2 parents with ...
1344 # Par column: for the 2 parents with ...
1335 # N: null or no parent
1345 # N: null or no parent
1336 # B: parent is on another named branch
1346 # B: parent is on another named branch
1337 # C: parent is a regular non head changeset
1347 # C: parent is a regular non head changeset
1338 # H: parent was a branch head of the current branch
1348 # H: parent was a branch head of the current branch
1339 # Msg column: whether we print "created new head" message
1349 # Msg column: whether we print "created new head" message
1340 # In the following, it is assumed that there already exists some
1350 # In the following, it is assumed that there already exists some
1341 # initial branch heads of the current branch, otherwise nothing is
1351 # initial branch heads of the current branch, otherwise nothing is
1342 # printed anyway.
1352 # printed anyway.
1343 #
1353 #
1344 # Par Msg Comment
1354 # Par Msg Comment
1345 # NN y additional topo root
1355 # NN y additional topo root
1346 #
1356 #
1347 # BN y additional branch root
1357 # BN y additional branch root
1348 # CN y additional topo head
1358 # CN y additional topo head
1349 # HN n usual case
1359 # HN n usual case
1350 #
1360 #
1351 # BB y weird additional branch root
1361 # BB y weird additional branch root
1352 # CB y branch merge
1362 # CB y branch merge
1353 # HB n merge with named branch
1363 # HB n merge with named branch
1354 #
1364 #
1355 # CC y additional head from merge
1365 # CC y additional head from merge
1356 # CH n merge with a head
1366 # CH n merge with a head
1357 #
1367 #
1358 # HH n head merge: head count decreases
1368 # HH n head merge: head count decreases
1359
1369
1360 if not opts.get('close_branch'):
1370 if not opts.get('close_branch'):
1361 for r in parents:
1371 for r in parents:
1362 if r.closesbranch() and r.branch() == branch:
1372 if r.closesbranch() and r.branch() == branch:
1363 ui.status(_('reopening closed branch head %d\n') % r)
1373 ui.status(_('reopening closed branch head %d\n') % r)
1364
1374
1365 if ui.debugflag:
1375 if ui.debugflag:
1366 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1376 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1367 elif ui.verbose:
1377 elif ui.verbose:
1368 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1378 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1369
1379
1370 @command('copy|cp',
1380 @command('copy|cp',
1371 [('A', 'after', None, _('record a copy that has already occurred')),
1381 [('A', 'after', None, _('record a copy that has already occurred')),
1372 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1382 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1373 ] + walkopts + dryrunopts,
1383 ] + walkopts + dryrunopts,
1374 _('[OPTION]... [SOURCE]... DEST'))
1384 _('[OPTION]... [SOURCE]... DEST'))
1375 def copy(ui, repo, *pats, **opts):
1385 def copy(ui, repo, *pats, **opts):
1376 """mark files as copied for the next commit
1386 """mark files as copied for the next commit
1377
1387
1378 Mark dest as having copies of source files. If dest is a
1388 Mark dest as having copies of source files. If dest is a
1379 directory, copies are put in that directory. If dest is a file,
1389 directory, copies are put in that directory. If dest is a file,
1380 the source must be a single file.
1390 the source must be a single file.
1381
1391
1382 By default, this command copies the contents of files as they
1392 By default, this command copies the contents of files as they
1383 exist in the working directory. If invoked with -A/--after, the
1393 exist in the working directory. If invoked with -A/--after, the
1384 operation is recorded, but no copying is performed.
1394 operation is recorded, but no copying is performed.
1385
1395
1386 This command takes effect with the next commit. To undo a copy
1396 This command takes effect with the next commit. To undo a copy
1387 before that, see :hg:`revert`.
1397 before that, see :hg:`revert`.
1388
1398
1389 Returns 0 on success, 1 if errors are encountered.
1399 Returns 0 on success, 1 if errors are encountered.
1390 """
1400 """
1391 wlock = repo.wlock(False)
1401 wlock = repo.wlock(False)
1392 try:
1402 try:
1393 return cmdutil.copy(ui, repo, pats, opts)
1403 return cmdutil.copy(ui, repo, pats, opts)
1394 finally:
1404 finally:
1395 wlock.release()
1405 wlock.release()
1396
1406
1397 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1407 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1398 def debugancestor(ui, repo, *args):
1408 def debugancestor(ui, repo, *args):
1399 """find the ancestor revision of two revisions in a given index"""
1409 """find the ancestor revision of two revisions in a given index"""
1400 if len(args) == 3:
1410 if len(args) == 3:
1401 index, rev1, rev2 = args
1411 index, rev1, rev2 = args
1402 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1412 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1403 lookup = r.lookup
1413 lookup = r.lookup
1404 elif len(args) == 2:
1414 elif len(args) == 2:
1405 if not repo:
1415 if not repo:
1406 raise util.Abort(_("there is no Mercurial repository here "
1416 raise util.Abort(_("there is no Mercurial repository here "
1407 "(.hg not found)"))
1417 "(.hg not found)"))
1408 rev1, rev2 = args
1418 rev1, rev2 = args
1409 r = repo.changelog
1419 r = repo.changelog
1410 lookup = repo.lookup
1420 lookup = repo.lookup
1411 else:
1421 else:
1412 raise util.Abort(_('either two or three arguments required'))
1422 raise util.Abort(_('either two or three arguments required'))
1413 a = r.ancestor(lookup(rev1), lookup(rev2))
1423 a = r.ancestor(lookup(rev1), lookup(rev2))
1414 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1424 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1415
1425
1416 @command('debugbuilddag',
1426 @command('debugbuilddag',
1417 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1427 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1418 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1428 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1419 ('n', 'new-file', None, _('add new file at each rev'))],
1429 ('n', 'new-file', None, _('add new file at each rev'))],
1420 _('[OPTION]... [TEXT]'))
1430 _('[OPTION]... [TEXT]'))
1421 def debugbuilddag(ui, repo, text=None,
1431 def debugbuilddag(ui, repo, text=None,
1422 mergeable_file=False,
1432 mergeable_file=False,
1423 overwritten_file=False,
1433 overwritten_file=False,
1424 new_file=False):
1434 new_file=False):
1425 """builds a repo with a given DAG from scratch in the current empty repo
1435 """builds a repo with a given DAG from scratch in the current empty repo
1426
1436
1427 The description of the DAG is read from stdin if not given on the
1437 The description of the DAG is read from stdin if not given on the
1428 command line.
1438 command line.
1429
1439
1430 Elements:
1440 Elements:
1431
1441
1432 - "+n" is a linear run of n nodes based on the current default parent
1442 - "+n" is a linear run of n nodes based on the current default parent
1433 - "." is a single node based on the current default parent
1443 - "." is a single node based on the current default parent
1434 - "$" resets the default parent to null (implied at the start);
1444 - "$" resets the default parent to null (implied at the start);
1435 otherwise the default parent is always the last node created
1445 otherwise the default parent is always the last node created
1436 - "<p" sets the default parent to the backref p
1446 - "<p" sets the default parent to the backref p
1437 - "*p" is a fork at parent p, which is a backref
1447 - "*p" is a fork at parent p, which is a backref
1438 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1448 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1439 - "/p2" is a merge of the preceding node and p2
1449 - "/p2" is a merge of the preceding node and p2
1440 - ":tag" defines a local tag for the preceding node
1450 - ":tag" defines a local tag for the preceding node
1441 - "@branch" sets the named branch for subsequent nodes
1451 - "@branch" sets the named branch for subsequent nodes
1442 - "#...\\n" is a comment up to the end of the line
1452 - "#...\\n" is a comment up to the end of the line
1443
1453
1444 Whitespace between the above elements is ignored.
1454 Whitespace between the above elements is ignored.
1445
1455
1446 A backref is either
1456 A backref is either
1447
1457
1448 - a number n, which references the node curr-n, where curr is the current
1458 - a number n, which references the node curr-n, where curr is the current
1449 node, or
1459 node, or
1450 - the name of a local tag you placed earlier using ":tag", or
1460 - the name of a local tag you placed earlier using ":tag", or
1451 - empty to denote the default parent.
1461 - empty to denote the default parent.
1452
1462
1453 All string valued-elements are either strictly alphanumeric, or must
1463 All string valued-elements are either strictly alphanumeric, or must
1454 be enclosed in double quotes ("..."), with "\\" as escape character.
1464 be enclosed in double quotes ("..."), with "\\" as escape character.
1455 """
1465 """
1456
1466
1457 if text is None:
1467 if text is None:
1458 ui.status(_("reading DAG from stdin\n"))
1468 ui.status(_("reading DAG from stdin\n"))
1459 text = ui.fin.read()
1469 text = ui.fin.read()
1460
1470
1461 cl = repo.changelog
1471 cl = repo.changelog
1462 if len(cl) > 0:
1472 if len(cl) > 0:
1463 raise util.Abort(_('repository is not empty'))
1473 raise util.Abort(_('repository is not empty'))
1464
1474
1465 # determine number of revs in DAG
1475 # determine number of revs in DAG
1466 total = 0
1476 total = 0
1467 for type, data in dagparser.parsedag(text):
1477 for type, data in dagparser.parsedag(text):
1468 if type == 'n':
1478 if type == 'n':
1469 total += 1
1479 total += 1
1470
1480
1471 if mergeable_file:
1481 if mergeable_file:
1472 linesperrev = 2
1482 linesperrev = 2
1473 # make a file with k lines per rev
1483 # make a file with k lines per rev
1474 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1484 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1475 initialmergedlines.append("")
1485 initialmergedlines.append("")
1476
1486
1477 tags = []
1487 tags = []
1478
1488
1479 lock = tr = None
1489 lock = tr = None
1480 try:
1490 try:
1481 lock = repo.lock()
1491 lock = repo.lock()
1482 tr = repo.transaction("builddag")
1492 tr = repo.transaction("builddag")
1483
1493
1484 at = -1
1494 at = -1
1485 atbranch = 'default'
1495 atbranch = 'default'
1486 nodeids = []
1496 nodeids = []
1487 id = 0
1497 id = 0
1488 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1498 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1489 for type, data in dagparser.parsedag(text):
1499 for type, data in dagparser.parsedag(text):
1490 if type == 'n':
1500 if type == 'n':
1491 ui.note('node %s\n' % str(data))
1501 ui.note('node %s\n' % str(data))
1492 id, ps = data
1502 id, ps = data
1493
1503
1494 files = []
1504 files = []
1495 fctxs = {}
1505 fctxs = {}
1496
1506
1497 p2 = None
1507 p2 = None
1498 if mergeable_file:
1508 if mergeable_file:
1499 fn = "mf"
1509 fn = "mf"
1500 p1 = repo[ps[0]]
1510 p1 = repo[ps[0]]
1501 if len(ps) > 1:
1511 if len(ps) > 1:
1502 p2 = repo[ps[1]]
1512 p2 = repo[ps[1]]
1503 pa = p1.ancestor(p2)
1513 pa = p1.ancestor(p2)
1504 base, local, other = [x[fn].data() for x in pa, p1, p2]
1514 base, local, other = [x[fn].data() for x in pa, p1, p2]
1505 m3 = simplemerge.Merge3Text(base, local, other)
1515 m3 = simplemerge.Merge3Text(base, local, other)
1506 ml = [l.strip() for l in m3.merge_lines()]
1516 ml = [l.strip() for l in m3.merge_lines()]
1507 ml.append("")
1517 ml.append("")
1508 elif at > 0:
1518 elif at > 0:
1509 ml = p1[fn].data().split("\n")
1519 ml = p1[fn].data().split("\n")
1510 else:
1520 else:
1511 ml = initialmergedlines
1521 ml = initialmergedlines
1512 ml[id * linesperrev] += " r%i" % id
1522 ml[id * linesperrev] += " r%i" % id
1513 mergedtext = "\n".join(ml)
1523 mergedtext = "\n".join(ml)
1514 files.append(fn)
1524 files.append(fn)
1515 fctxs[fn] = context.memfilectx(fn, mergedtext)
1525 fctxs[fn] = context.memfilectx(fn, mergedtext)
1516
1526
1517 if overwritten_file:
1527 if overwritten_file:
1518 fn = "of"
1528 fn = "of"
1519 files.append(fn)
1529 files.append(fn)
1520 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1530 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1521
1531
1522 if new_file:
1532 if new_file:
1523 fn = "nf%i" % id
1533 fn = "nf%i" % id
1524 files.append(fn)
1534 files.append(fn)
1525 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1535 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1526 if len(ps) > 1:
1536 if len(ps) > 1:
1527 if not p2:
1537 if not p2:
1528 p2 = repo[ps[1]]
1538 p2 = repo[ps[1]]
1529 for fn in p2:
1539 for fn in p2:
1530 if fn.startswith("nf"):
1540 if fn.startswith("nf"):
1531 files.append(fn)
1541 files.append(fn)
1532 fctxs[fn] = p2[fn]
1542 fctxs[fn] = p2[fn]
1533
1543
1534 def fctxfn(repo, cx, path):
1544 def fctxfn(repo, cx, path):
1535 return fctxs.get(path)
1545 return fctxs.get(path)
1536
1546
1537 if len(ps) == 0 or ps[0] < 0:
1547 if len(ps) == 0 or ps[0] < 0:
1538 pars = [None, None]
1548 pars = [None, None]
1539 elif len(ps) == 1:
1549 elif len(ps) == 1:
1540 pars = [nodeids[ps[0]], None]
1550 pars = [nodeids[ps[0]], None]
1541 else:
1551 else:
1542 pars = [nodeids[p] for p in ps]
1552 pars = [nodeids[p] for p in ps]
1543 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1553 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1544 date=(id, 0),
1554 date=(id, 0),
1545 user="debugbuilddag",
1555 user="debugbuilddag",
1546 extra={'branch': atbranch})
1556 extra={'branch': atbranch})
1547 nodeid = repo.commitctx(cx)
1557 nodeid = repo.commitctx(cx)
1548 nodeids.append(nodeid)
1558 nodeids.append(nodeid)
1549 at = id
1559 at = id
1550 elif type == 'l':
1560 elif type == 'l':
1551 id, name = data
1561 id, name = data
1552 ui.note('tag %s\n' % name)
1562 ui.note('tag %s\n' % name)
1553 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1563 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1554 elif type == 'a':
1564 elif type == 'a':
1555 ui.note('branch %s\n' % data)
1565 ui.note('branch %s\n' % data)
1556 atbranch = data
1566 atbranch = data
1557 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1567 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1558 tr.close()
1568 tr.close()
1559
1569
1560 if tags:
1570 if tags:
1561 repo.opener.write("localtags", "".join(tags))
1571 repo.opener.write("localtags", "".join(tags))
1562 finally:
1572 finally:
1563 ui.progress(_('building'), None)
1573 ui.progress(_('building'), None)
1564 release(tr, lock)
1574 release(tr, lock)
1565
1575
1566 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1576 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1567 def debugbundle(ui, bundlepath, all=None, **opts):
1577 def debugbundle(ui, bundlepath, all=None, **opts):
1568 """lists the contents of a bundle"""
1578 """lists the contents of a bundle"""
1569 f = url.open(ui, bundlepath)
1579 f = url.open(ui, bundlepath)
1570 try:
1580 try:
1571 gen = changegroup.readbundle(f, bundlepath)
1581 gen = changegroup.readbundle(f, bundlepath)
1572 if all:
1582 if all:
1573 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1583 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1574
1584
1575 def showchunks(named):
1585 def showchunks(named):
1576 ui.write("\n%s\n" % named)
1586 ui.write("\n%s\n" % named)
1577 chain = None
1587 chain = None
1578 while True:
1588 while True:
1579 chunkdata = gen.deltachunk(chain)
1589 chunkdata = gen.deltachunk(chain)
1580 if not chunkdata:
1590 if not chunkdata:
1581 break
1591 break
1582 node = chunkdata['node']
1592 node = chunkdata['node']
1583 p1 = chunkdata['p1']
1593 p1 = chunkdata['p1']
1584 p2 = chunkdata['p2']
1594 p2 = chunkdata['p2']
1585 cs = chunkdata['cs']
1595 cs = chunkdata['cs']
1586 deltabase = chunkdata['deltabase']
1596 deltabase = chunkdata['deltabase']
1587 delta = chunkdata['delta']
1597 delta = chunkdata['delta']
1588 ui.write("%s %s %s %s %s %s\n" %
1598 ui.write("%s %s %s %s %s %s\n" %
1589 (hex(node), hex(p1), hex(p2),
1599 (hex(node), hex(p1), hex(p2),
1590 hex(cs), hex(deltabase), len(delta)))
1600 hex(cs), hex(deltabase), len(delta)))
1591 chain = node
1601 chain = node
1592
1602
1593 chunkdata = gen.changelogheader()
1603 chunkdata = gen.changelogheader()
1594 showchunks("changelog")
1604 showchunks("changelog")
1595 chunkdata = gen.manifestheader()
1605 chunkdata = gen.manifestheader()
1596 showchunks("manifest")
1606 showchunks("manifest")
1597 while True:
1607 while True:
1598 chunkdata = gen.filelogheader()
1608 chunkdata = gen.filelogheader()
1599 if not chunkdata:
1609 if not chunkdata:
1600 break
1610 break
1601 fname = chunkdata['filename']
1611 fname = chunkdata['filename']
1602 showchunks(fname)
1612 showchunks(fname)
1603 else:
1613 else:
1604 chunkdata = gen.changelogheader()
1614 chunkdata = gen.changelogheader()
1605 chain = None
1615 chain = None
1606 while True:
1616 while True:
1607 chunkdata = gen.deltachunk(chain)
1617 chunkdata = gen.deltachunk(chain)
1608 if not chunkdata:
1618 if not chunkdata:
1609 break
1619 break
1610 node = chunkdata['node']
1620 node = chunkdata['node']
1611 ui.write("%s\n" % hex(node))
1621 ui.write("%s\n" % hex(node))
1612 chain = node
1622 chain = node
1613 finally:
1623 finally:
1614 f.close()
1624 f.close()
1615
1625
1616 @command('debugcheckstate', [], '')
1626 @command('debugcheckstate', [], '')
1617 def debugcheckstate(ui, repo):
1627 def debugcheckstate(ui, repo):
1618 """validate the correctness of the current dirstate"""
1628 """validate the correctness of the current dirstate"""
1619 parent1, parent2 = repo.dirstate.parents()
1629 parent1, parent2 = repo.dirstate.parents()
1620 m1 = repo[parent1].manifest()
1630 m1 = repo[parent1].manifest()
1621 m2 = repo[parent2].manifest()
1631 m2 = repo[parent2].manifest()
1622 errors = 0
1632 errors = 0
1623 for f in repo.dirstate:
1633 for f in repo.dirstate:
1624 state = repo.dirstate[f]
1634 state = repo.dirstate[f]
1625 if state in "nr" and f not in m1:
1635 if state in "nr" and f not in m1:
1626 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1636 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1627 errors += 1
1637 errors += 1
1628 if state in "a" and f in m1:
1638 if state in "a" and f in m1:
1629 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1639 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1630 errors += 1
1640 errors += 1
1631 if state in "m" and f not in m1 and f not in m2:
1641 if state in "m" and f not in m1 and f not in m2:
1632 ui.warn(_("%s in state %s, but not in either manifest\n") %
1642 ui.warn(_("%s in state %s, but not in either manifest\n") %
1633 (f, state))
1643 (f, state))
1634 errors += 1
1644 errors += 1
1635 for f in m1:
1645 for f in m1:
1636 state = repo.dirstate[f]
1646 state = repo.dirstate[f]
1637 if state not in "nrm":
1647 if state not in "nrm":
1638 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1648 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1639 errors += 1
1649 errors += 1
1640 if errors:
1650 if errors:
1641 error = _(".hg/dirstate inconsistent with current parent's manifest")
1651 error = _(".hg/dirstate inconsistent with current parent's manifest")
1642 raise util.Abort(error)
1652 raise util.Abort(error)
1643
1653
1644 @command('debugcommands', [], _('[COMMAND]'))
1654 @command('debugcommands', [], _('[COMMAND]'))
1645 def debugcommands(ui, cmd='', *args):
1655 def debugcommands(ui, cmd='', *args):
1646 """list all available commands and options"""
1656 """list all available commands and options"""
1647 for cmd, vals in sorted(table.iteritems()):
1657 for cmd, vals in sorted(table.iteritems()):
1648 cmd = cmd.split('|')[0].strip('^')
1658 cmd = cmd.split('|')[0].strip('^')
1649 opts = ', '.join([i[1] for i in vals[1]])
1659 opts = ', '.join([i[1] for i in vals[1]])
1650 ui.write('%s: %s\n' % (cmd, opts))
1660 ui.write('%s: %s\n' % (cmd, opts))
1651
1661
1652 @command('debugcomplete',
1662 @command('debugcomplete',
1653 [('o', 'options', None, _('show the command options'))],
1663 [('o', 'options', None, _('show the command options'))],
1654 _('[-o] CMD'))
1664 _('[-o] CMD'))
1655 def debugcomplete(ui, cmd='', **opts):
1665 def debugcomplete(ui, cmd='', **opts):
1656 """returns the completion list associated with the given command"""
1666 """returns the completion list associated with the given command"""
1657
1667
1658 if opts.get('options'):
1668 if opts.get('options'):
1659 options = []
1669 options = []
1660 otables = [globalopts]
1670 otables = [globalopts]
1661 if cmd:
1671 if cmd:
1662 aliases, entry = cmdutil.findcmd(cmd, table, False)
1672 aliases, entry = cmdutil.findcmd(cmd, table, False)
1663 otables.append(entry[1])
1673 otables.append(entry[1])
1664 for t in otables:
1674 for t in otables:
1665 for o in t:
1675 for o in t:
1666 if "(DEPRECATED)" in o[3]:
1676 if "(DEPRECATED)" in o[3]:
1667 continue
1677 continue
1668 if o[0]:
1678 if o[0]:
1669 options.append('-%s' % o[0])
1679 options.append('-%s' % o[0])
1670 options.append('--%s' % o[1])
1680 options.append('--%s' % o[1])
1671 ui.write("%s\n" % "\n".join(options))
1681 ui.write("%s\n" % "\n".join(options))
1672 return
1682 return
1673
1683
1674 cmdlist = cmdutil.findpossible(cmd, table)
1684 cmdlist = cmdutil.findpossible(cmd, table)
1675 if ui.verbose:
1685 if ui.verbose:
1676 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1686 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1677 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1687 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1678
1688
1679 @command('debugdag',
1689 @command('debugdag',
1680 [('t', 'tags', None, _('use tags as labels')),
1690 [('t', 'tags', None, _('use tags as labels')),
1681 ('b', 'branches', None, _('annotate with branch names')),
1691 ('b', 'branches', None, _('annotate with branch names')),
1682 ('', 'dots', None, _('use dots for runs')),
1692 ('', 'dots', None, _('use dots for runs')),
1683 ('s', 'spaces', None, _('separate elements by spaces'))],
1693 ('s', 'spaces', None, _('separate elements by spaces'))],
1684 _('[OPTION]... [FILE [REV]...]'))
1694 _('[OPTION]... [FILE [REV]...]'))
1685 def debugdag(ui, repo, file_=None, *revs, **opts):
1695 def debugdag(ui, repo, file_=None, *revs, **opts):
1686 """format the changelog or an index DAG as a concise textual description
1696 """format the changelog or an index DAG as a concise textual description
1687
1697
1688 If you pass a revlog index, the revlog's DAG is emitted. If you list
1698 If you pass a revlog index, the revlog's DAG is emitted. If you list
1689 revision numbers, they get labelled in the output as rN.
1699 revision numbers, they get labelled in the output as rN.
1690
1700
1691 Otherwise, the changelog DAG of the current repo is emitted.
1701 Otherwise, the changelog DAG of the current repo is emitted.
1692 """
1702 """
1693 spaces = opts.get('spaces')
1703 spaces = opts.get('spaces')
1694 dots = opts.get('dots')
1704 dots = opts.get('dots')
1695 if file_:
1705 if file_:
1696 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1706 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1697 revs = set((int(r) for r in revs))
1707 revs = set((int(r) for r in revs))
1698 def events():
1708 def events():
1699 for r in rlog:
1709 for r in rlog:
1700 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1710 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1701 if p != -1)))
1711 if p != -1)))
1702 if r in revs:
1712 if r in revs:
1703 yield 'l', (r, "r%i" % r)
1713 yield 'l', (r, "r%i" % r)
1704 elif repo:
1714 elif repo:
1705 cl = repo.changelog
1715 cl = repo.changelog
1706 tags = opts.get('tags')
1716 tags = opts.get('tags')
1707 branches = opts.get('branches')
1717 branches = opts.get('branches')
1708 if tags:
1718 if tags:
1709 labels = {}
1719 labels = {}
1710 for l, n in repo.tags().items():
1720 for l, n in repo.tags().items():
1711 labels.setdefault(cl.rev(n), []).append(l)
1721 labels.setdefault(cl.rev(n), []).append(l)
1712 def events():
1722 def events():
1713 b = "default"
1723 b = "default"
1714 for r in cl:
1724 for r in cl:
1715 if branches:
1725 if branches:
1716 newb = cl.read(cl.node(r))[5]['branch']
1726 newb = cl.read(cl.node(r))[5]['branch']
1717 if newb != b:
1727 if newb != b:
1718 yield 'a', newb
1728 yield 'a', newb
1719 b = newb
1729 b = newb
1720 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1730 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1721 if p != -1)))
1731 if p != -1)))
1722 if tags:
1732 if tags:
1723 ls = labels.get(r)
1733 ls = labels.get(r)
1724 if ls:
1734 if ls:
1725 for l in ls:
1735 for l in ls:
1726 yield 'l', (r, l)
1736 yield 'l', (r, l)
1727 else:
1737 else:
1728 raise util.Abort(_('need repo for changelog dag'))
1738 raise util.Abort(_('need repo for changelog dag'))
1729
1739
1730 for line in dagparser.dagtextlines(events(),
1740 for line in dagparser.dagtextlines(events(),
1731 addspaces=spaces,
1741 addspaces=spaces,
1732 wraplabels=True,
1742 wraplabels=True,
1733 wrapannotations=True,
1743 wrapannotations=True,
1734 wrapnonlinear=dots,
1744 wrapnonlinear=dots,
1735 usedots=dots,
1745 usedots=dots,
1736 maxlinewidth=70):
1746 maxlinewidth=70):
1737 ui.write(line)
1747 ui.write(line)
1738 ui.write("\n")
1748 ui.write("\n")
1739
1749
1740 @command('debugdata',
1750 @command('debugdata',
1741 [('c', 'changelog', False, _('open changelog')),
1751 [('c', 'changelog', False, _('open changelog')),
1742 ('m', 'manifest', False, _('open manifest'))],
1752 ('m', 'manifest', False, _('open manifest'))],
1743 _('-c|-m|FILE REV'))
1753 _('-c|-m|FILE REV'))
1744 def debugdata(ui, repo, file_, rev = None, **opts):
1754 def debugdata(ui, repo, file_, rev = None, **opts):
1745 """dump the contents of a data file revision"""
1755 """dump the contents of a data file revision"""
1746 if opts.get('changelog') or opts.get('manifest'):
1756 if opts.get('changelog') or opts.get('manifest'):
1747 file_, rev = None, file_
1757 file_, rev = None, file_
1748 elif rev is None:
1758 elif rev is None:
1749 raise error.CommandError('debugdata', _('invalid arguments'))
1759 raise error.CommandError('debugdata', _('invalid arguments'))
1750 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1760 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1751 try:
1761 try:
1752 ui.write(r.revision(r.lookup(rev)))
1762 ui.write(r.revision(r.lookup(rev)))
1753 except KeyError:
1763 except KeyError:
1754 raise util.Abort(_('invalid revision identifier %s') % rev)
1764 raise util.Abort(_('invalid revision identifier %s') % rev)
1755
1765
1756 @command('debugdate',
1766 @command('debugdate',
1757 [('e', 'extended', None, _('try extended date formats'))],
1767 [('e', 'extended', None, _('try extended date formats'))],
1758 _('[-e] DATE [RANGE]'))
1768 _('[-e] DATE [RANGE]'))
1759 def debugdate(ui, date, range=None, **opts):
1769 def debugdate(ui, date, range=None, **opts):
1760 """parse and display a date"""
1770 """parse and display a date"""
1761 if opts["extended"]:
1771 if opts["extended"]:
1762 d = util.parsedate(date, util.extendeddateformats)
1772 d = util.parsedate(date, util.extendeddateformats)
1763 else:
1773 else:
1764 d = util.parsedate(date)
1774 d = util.parsedate(date)
1765 ui.write("internal: %s %s\n" % d)
1775 ui.write("internal: %s %s\n" % d)
1766 ui.write("standard: %s\n" % util.datestr(d))
1776 ui.write("standard: %s\n" % util.datestr(d))
1767 if range:
1777 if range:
1768 m = util.matchdate(range)
1778 m = util.matchdate(range)
1769 ui.write("match: %s\n" % m(d[0]))
1779 ui.write("match: %s\n" % m(d[0]))
1770
1780
1771 @command('debugdiscovery',
1781 @command('debugdiscovery',
1772 [('', 'old', None, _('use old-style discovery')),
1782 [('', 'old', None, _('use old-style discovery')),
1773 ('', 'nonheads', None,
1783 ('', 'nonheads', None,
1774 _('use old-style discovery with non-heads included')),
1784 _('use old-style discovery with non-heads included')),
1775 ] + remoteopts,
1785 ] + remoteopts,
1776 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1786 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1777 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1787 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1778 """runs the changeset discovery protocol in isolation"""
1788 """runs the changeset discovery protocol in isolation"""
1779 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1789 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1780 opts.get('branch'))
1790 opts.get('branch'))
1781 remote = hg.peer(repo, opts, remoteurl)
1791 remote = hg.peer(repo, opts, remoteurl)
1782 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1792 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1783
1793
1784 # make sure tests are repeatable
1794 # make sure tests are repeatable
1785 random.seed(12323)
1795 random.seed(12323)
1786
1796
1787 def doit(localheads, remoteheads, remote=remote):
1797 def doit(localheads, remoteheads, remote=remote):
1788 if opts.get('old'):
1798 if opts.get('old'):
1789 if localheads:
1799 if localheads:
1790 raise util.Abort('cannot use localheads with old style '
1800 raise util.Abort('cannot use localheads with old style '
1791 'discovery')
1801 'discovery')
1792 if not util.safehasattr(remote, 'branches'):
1802 if not util.safehasattr(remote, 'branches'):
1793 # enable in-client legacy support
1803 # enable in-client legacy support
1794 remote = localrepo.locallegacypeer(remote.local())
1804 remote = localrepo.locallegacypeer(remote.local())
1795 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1805 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1796 force=True)
1806 force=True)
1797 common = set(common)
1807 common = set(common)
1798 if not opts.get('nonheads'):
1808 if not opts.get('nonheads'):
1799 ui.write("unpruned common: %s\n" % " ".join([short(n)
1809 ui.write("unpruned common: %s\n" % " ".join([short(n)
1800 for n in common]))
1810 for n in common]))
1801 dag = dagutil.revlogdag(repo.changelog)
1811 dag = dagutil.revlogdag(repo.changelog)
1802 all = dag.ancestorset(dag.internalizeall(common))
1812 all = dag.ancestorset(dag.internalizeall(common))
1803 common = dag.externalizeall(dag.headsetofconnecteds(all))
1813 common = dag.externalizeall(dag.headsetofconnecteds(all))
1804 else:
1814 else:
1805 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1815 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1806 common = set(common)
1816 common = set(common)
1807 rheads = set(hds)
1817 rheads = set(hds)
1808 lheads = set(repo.heads())
1818 lheads = set(repo.heads())
1809 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1819 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1810 if lheads <= common:
1820 if lheads <= common:
1811 ui.write("local is subset\n")
1821 ui.write("local is subset\n")
1812 elif rheads <= common:
1822 elif rheads <= common:
1813 ui.write("remote is subset\n")
1823 ui.write("remote is subset\n")
1814
1824
1815 serverlogs = opts.get('serverlog')
1825 serverlogs = opts.get('serverlog')
1816 if serverlogs:
1826 if serverlogs:
1817 for filename in serverlogs:
1827 for filename in serverlogs:
1818 logfile = open(filename, 'r')
1828 logfile = open(filename, 'r')
1819 try:
1829 try:
1820 line = logfile.readline()
1830 line = logfile.readline()
1821 while line:
1831 while line:
1822 parts = line.strip().split(';')
1832 parts = line.strip().split(';')
1823 op = parts[1]
1833 op = parts[1]
1824 if op == 'cg':
1834 if op == 'cg':
1825 pass
1835 pass
1826 elif op == 'cgss':
1836 elif op == 'cgss':
1827 doit(parts[2].split(' '), parts[3].split(' '))
1837 doit(parts[2].split(' '), parts[3].split(' '))
1828 elif op == 'unb':
1838 elif op == 'unb':
1829 doit(parts[3].split(' '), parts[2].split(' '))
1839 doit(parts[3].split(' '), parts[2].split(' '))
1830 line = logfile.readline()
1840 line = logfile.readline()
1831 finally:
1841 finally:
1832 logfile.close()
1842 logfile.close()
1833
1843
1834 else:
1844 else:
1835 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1845 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1836 opts.get('remote_head'))
1846 opts.get('remote_head'))
1837 localrevs = opts.get('local_head')
1847 localrevs = opts.get('local_head')
1838 doit(localrevs, remoterevs)
1848 doit(localrevs, remoterevs)
1839
1849
1840 @command('debugfileset', [], ('REVSPEC'))
1850 @command('debugfileset', [], ('REVSPEC'))
1841 def debugfileset(ui, repo, expr):
1851 def debugfileset(ui, repo, expr):
1842 '''parse and apply a fileset specification'''
1852 '''parse and apply a fileset specification'''
1843 if ui.verbose:
1853 if ui.verbose:
1844 tree = fileset.parse(expr)[0]
1854 tree = fileset.parse(expr)[0]
1845 ui.note(tree, "\n")
1855 ui.note(tree, "\n")
1846
1856
1847 for f in fileset.getfileset(repo[None], expr):
1857 for f in fileset.getfileset(repo[None], expr):
1848 ui.write("%s\n" % f)
1858 ui.write("%s\n" % f)
1849
1859
1850 @command('debugfsinfo', [], _('[PATH]'))
1860 @command('debugfsinfo', [], _('[PATH]'))
1851 def debugfsinfo(ui, path = "."):
1861 def debugfsinfo(ui, path = "."):
1852 """show information detected about current filesystem"""
1862 """show information detected about current filesystem"""
1853 util.writefile('.debugfsinfo', '')
1863 util.writefile('.debugfsinfo', '')
1854 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1864 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1855 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1865 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1856 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1866 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1857 and 'yes' or 'no'))
1867 and 'yes' or 'no'))
1858 os.unlink('.debugfsinfo')
1868 os.unlink('.debugfsinfo')
1859
1869
1860 @command('debuggetbundle',
1870 @command('debuggetbundle',
1861 [('H', 'head', [], _('id of head node'), _('ID')),
1871 [('H', 'head', [], _('id of head node'), _('ID')),
1862 ('C', 'common', [], _('id of common node'), _('ID')),
1872 ('C', 'common', [], _('id of common node'), _('ID')),
1863 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1873 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1864 _('REPO FILE [-H|-C ID]...'))
1874 _('REPO FILE [-H|-C ID]...'))
1865 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1875 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1866 """retrieves a bundle from a repo
1876 """retrieves a bundle from a repo
1867
1877
1868 Every ID must be a full-length hex node id string. Saves the bundle to the
1878 Every ID must be a full-length hex node id string. Saves the bundle to the
1869 given file.
1879 given file.
1870 """
1880 """
1871 repo = hg.peer(ui, opts, repopath)
1881 repo = hg.peer(ui, opts, repopath)
1872 if not repo.capable('getbundle'):
1882 if not repo.capable('getbundle'):
1873 raise util.Abort("getbundle() not supported by target repository")
1883 raise util.Abort("getbundle() not supported by target repository")
1874 args = {}
1884 args = {}
1875 if common:
1885 if common:
1876 args['common'] = [bin(s) for s in common]
1886 args['common'] = [bin(s) for s in common]
1877 if head:
1887 if head:
1878 args['heads'] = [bin(s) for s in head]
1888 args['heads'] = [bin(s) for s in head]
1879 bundle = repo.getbundle('debug', **args)
1889 bundle = repo.getbundle('debug', **args)
1880
1890
1881 bundletype = opts.get('type', 'bzip2').lower()
1891 bundletype = opts.get('type', 'bzip2').lower()
1882 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1892 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1883 bundletype = btypes.get(bundletype)
1893 bundletype = btypes.get(bundletype)
1884 if bundletype not in changegroup.bundletypes:
1894 if bundletype not in changegroup.bundletypes:
1885 raise util.Abort(_('unknown bundle type specified with --type'))
1895 raise util.Abort(_('unknown bundle type specified with --type'))
1886 changegroup.writebundle(bundle, bundlepath, bundletype)
1896 changegroup.writebundle(bundle, bundlepath, bundletype)
1887
1897
1888 @command('debugignore', [], '')
1898 @command('debugignore', [], '')
1889 def debugignore(ui, repo, *values, **opts):
1899 def debugignore(ui, repo, *values, **opts):
1890 """display the combined ignore pattern"""
1900 """display the combined ignore pattern"""
1891 ignore = repo.dirstate._ignore
1901 ignore = repo.dirstate._ignore
1892 includepat = getattr(ignore, 'includepat', None)
1902 includepat = getattr(ignore, 'includepat', None)
1893 if includepat is not None:
1903 if includepat is not None:
1894 ui.write("%s\n" % includepat)
1904 ui.write("%s\n" % includepat)
1895 else:
1905 else:
1896 raise util.Abort(_("no ignore patterns found"))
1906 raise util.Abort(_("no ignore patterns found"))
1897
1907
1898 @command('debugindex',
1908 @command('debugindex',
1899 [('c', 'changelog', False, _('open changelog')),
1909 [('c', 'changelog', False, _('open changelog')),
1900 ('m', 'manifest', False, _('open manifest')),
1910 ('m', 'manifest', False, _('open manifest')),
1901 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1911 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1902 _('[-f FORMAT] -c|-m|FILE'))
1912 _('[-f FORMAT] -c|-m|FILE'))
1903 def debugindex(ui, repo, file_ = None, **opts):
1913 def debugindex(ui, repo, file_ = None, **opts):
1904 """dump the contents of an index file"""
1914 """dump the contents of an index file"""
1905 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1915 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1906 format = opts.get('format', 0)
1916 format = opts.get('format', 0)
1907 if format not in (0, 1):
1917 if format not in (0, 1):
1908 raise util.Abort(_("unknown format %d") % format)
1918 raise util.Abort(_("unknown format %d") % format)
1909
1919
1910 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1920 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1911 if generaldelta:
1921 if generaldelta:
1912 basehdr = ' delta'
1922 basehdr = ' delta'
1913 else:
1923 else:
1914 basehdr = ' base'
1924 basehdr = ' base'
1915
1925
1916 if format == 0:
1926 if format == 0:
1917 ui.write(" rev offset length " + basehdr + " linkrev"
1927 ui.write(" rev offset length " + basehdr + " linkrev"
1918 " nodeid p1 p2\n")
1928 " nodeid p1 p2\n")
1919 elif format == 1:
1929 elif format == 1:
1920 ui.write(" rev flag offset length"
1930 ui.write(" rev flag offset length"
1921 " size " + basehdr + " link p1 p2"
1931 " size " + basehdr + " link p1 p2"
1922 " nodeid\n")
1932 " nodeid\n")
1923
1933
1924 for i in r:
1934 for i in r:
1925 node = r.node(i)
1935 node = r.node(i)
1926 if generaldelta:
1936 if generaldelta:
1927 base = r.deltaparent(i)
1937 base = r.deltaparent(i)
1928 else:
1938 else:
1929 base = r.chainbase(i)
1939 base = r.chainbase(i)
1930 if format == 0:
1940 if format == 0:
1931 try:
1941 try:
1932 pp = r.parents(node)
1942 pp = r.parents(node)
1933 except Exception:
1943 except Exception:
1934 pp = [nullid, nullid]
1944 pp = [nullid, nullid]
1935 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1945 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1936 i, r.start(i), r.length(i), base, r.linkrev(i),
1946 i, r.start(i), r.length(i), base, r.linkrev(i),
1937 short(node), short(pp[0]), short(pp[1])))
1947 short(node), short(pp[0]), short(pp[1])))
1938 elif format == 1:
1948 elif format == 1:
1939 pr = r.parentrevs(i)
1949 pr = r.parentrevs(i)
1940 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1950 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1941 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1951 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1942 base, r.linkrev(i), pr[0], pr[1], short(node)))
1952 base, r.linkrev(i), pr[0], pr[1], short(node)))
1943
1953
1944 @command('debugindexdot', [], _('FILE'))
1954 @command('debugindexdot', [], _('FILE'))
1945 def debugindexdot(ui, repo, file_):
1955 def debugindexdot(ui, repo, file_):
1946 """dump an index DAG as a graphviz dot file"""
1956 """dump an index DAG as a graphviz dot file"""
1947 r = None
1957 r = None
1948 if repo:
1958 if repo:
1949 filelog = repo.file(file_)
1959 filelog = repo.file(file_)
1950 if len(filelog):
1960 if len(filelog):
1951 r = filelog
1961 r = filelog
1952 if not r:
1962 if not r:
1953 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1963 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1954 ui.write("digraph G {\n")
1964 ui.write("digraph G {\n")
1955 for i in r:
1965 for i in r:
1956 node = r.node(i)
1966 node = r.node(i)
1957 pp = r.parents(node)
1967 pp = r.parents(node)
1958 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1968 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1959 if pp[1] != nullid:
1969 if pp[1] != nullid:
1960 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1970 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1961 ui.write("}\n")
1971 ui.write("}\n")
1962
1972
1963 @command('debuginstall', [], '')
1973 @command('debuginstall', [], '')
1964 def debuginstall(ui):
1974 def debuginstall(ui):
1965 '''test Mercurial installation
1975 '''test Mercurial installation
1966
1976
1967 Returns 0 on success.
1977 Returns 0 on success.
1968 '''
1978 '''
1969
1979
1970 def writetemp(contents):
1980 def writetemp(contents):
1971 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1981 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1972 f = os.fdopen(fd, "wb")
1982 f = os.fdopen(fd, "wb")
1973 f.write(contents)
1983 f.write(contents)
1974 f.close()
1984 f.close()
1975 return name
1985 return name
1976
1986
1977 problems = 0
1987 problems = 0
1978
1988
1979 # encoding
1989 # encoding
1980 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1990 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
1981 try:
1991 try:
1982 encoding.fromlocal("test")
1992 encoding.fromlocal("test")
1983 except util.Abort, inst:
1993 except util.Abort, inst:
1984 ui.write(" %s\n" % inst)
1994 ui.write(" %s\n" % inst)
1985 ui.write(_(" (check that your locale is properly set)\n"))
1995 ui.write(_(" (check that your locale is properly set)\n"))
1986 problems += 1
1996 problems += 1
1987
1997
1988 # compiled modules
1998 # compiled modules
1989 ui.status(_("checking installed modules (%s)...\n")
1999 ui.status(_("checking installed modules (%s)...\n")
1990 % os.path.dirname(__file__))
2000 % os.path.dirname(__file__))
1991 try:
2001 try:
1992 import bdiff, mpatch, base85, osutil
2002 import bdiff, mpatch, base85, osutil
1993 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2003 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1994 except Exception, inst:
2004 except Exception, inst:
1995 ui.write(" %s\n" % inst)
2005 ui.write(" %s\n" % inst)
1996 ui.write(_(" One or more extensions could not be found"))
2006 ui.write(_(" One or more extensions could not be found"))
1997 ui.write(_(" (check that you compiled the extensions)\n"))
2007 ui.write(_(" (check that you compiled the extensions)\n"))
1998 problems += 1
2008 problems += 1
1999
2009
2000 # templates
2010 # templates
2001 import templater
2011 import templater
2002 p = templater.templatepath()
2012 p = templater.templatepath()
2003 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2013 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2004 try:
2014 try:
2005 templater.templater(templater.templatepath("map-cmdline.default"))
2015 templater.templater(templater.templatepath("map-cmdline.default"))
2006 except Exception, inst:
2016 except Exception, inst:
2007 ui.write(" %s\n" % inst)
2017 ui.write(" %s\n" % inst)
2008 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2018 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2009 problems += 1
2019 problems += 1
2010
2020
2011 # editor
2021 # editor
2012 ui.status(_("checking commit editor...\n"))
2022 ui.status(_("checking commit editor...\n"))
2013 editor = ui.geteditor()
2023 editor = ui.geteditor()
2014 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2024 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2015 if not cmdpath:
2025 if not cmdpath:
2016 if editor == 'vi':
2026 if editor == 'vi':
2017 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2027 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2018 ui.write(_(" (specify a commit editor in your configuration"
2028 ui.write(_(" (specify a commit editor in your configuration"
2019 " file)\n"))
2029 " file)\n"))
2020 else:
2030 else:
2021 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2031 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2022 ui.write(_(" (specify a commit editor in your configuration"
2032 ui.write(_(" (specify a commit editor in your configuration"
2023 " file)\n"))
2033 " file)\n"))
2024 problems += 1
2034 problems += 1
2025
2035
2026 # check username
2036 # check username
2027 ui.status(_("checking username...\n"))
2037 ui.status(_("checking username...\n"))
2028 try:
2038 try:
2029 ui.username()
2039 ui.username()
2030 except util.Abort, e:
2040 except util.Abort, e:
2031 ui.write(" %s\n" % e)
2041 ui.write(" %s\n" % e)
2032 ui.write(_(" (specify a username in your configuration file)\n"))
2042 ui.write(_(" (specify a username in your configuration file)\n"))
2033 problems += 1
2043 problems += 1
2034
2044
2035 if not problems:
2045 if not problems:
2036 ui.status(_("no problems detected\n"))
2046 ui.status(_("no problems detected\n"))
2037 else:
2047 else:
2038 ui.write(_("%s problems detected,"
2048 ui.write(_("%s problems detected,"
2039 " please check your install!\n") % problems)
2049 " please check your install!\n") % problems)
2040
2050
2041 return problems
2051 return problems
2042
2052
2043 @command('debugknown', [], _('REPO ID...'))
2053 @command('debugknown', [], _('REPO ID...'))
2044 def debugknown(ui, repopath, *ids, **opts):
2054 def debugknown(ui, repopath, *ids, **opts):
2045 """test whether node ids are known to a repo
2055 """test whether node ids are known to a repo
2046
2056
2047 Every ID must be a full-length hex node id string. Returns a list of 0s
2057 Every ID must be a full-length hex node id string. Returns a list of 0s
2048 and 1s indicating unknown/known.
2058 and 1s indicating unknown/known.
2049 """
2059 """
2050 repo = hg.peer(ui, opts, repopath)
2060 repo = hg.peer(ui, opts, repopath)
2051 if not repo.capable('known'):
2061 if not repo.capable('known'):
2052 raise util.Abort("known() not supported by target repository")
2062 raise util.Abort("known() not supported by target repository")
2053 flags = repo.known([bin(s) for s in ids])
2063 flags = repo.known([bin(s) for s in ids])
2054 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2064 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2055
2065
2056 @command('debugobsolete', [] + commitopts2,
2066 @command('debugobsolete', [] + commitopts2,
2057 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2067 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2058 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2068 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2059 """create arbitrary obsolete marker"""
2069 """create arbitrary obsolete marker"""
2060 if precursor is not None:
2070 if precursor is not None:
2061 metadata = {}
2071 metadata = {}
2062 if 'date' in opts:
2072 if 'date' in opts:
2063 metadata['date'] = opts['date']
2073 metadata['date'] = opts['date']
2064 metadata['user'] = opts['user'] or ui.username()
2074 metadata['user'] = opts['user'] or ui.username()
2065 succs = tuple(bin(succ) for succ in successors)
2075 succs = tuple(bin(succ) for succ in successors)
2066 l = repo.lock()
2076 l = repo.lock()
2067 try:
2077 try:
2068 tr = repo.transaction('debugobsolete')
2078 tr = repo.transaction('debugobsolete')
2069 try:
2079 try:
2070 repo.obsstore.create(tr, bin(precursor), succs, 0, metadata)
2080 repo.obsstore.create(tr, bin(precursor), succs, 0, metadata)
2071 tr.close()
2081 tr.close()
2072 finally:
2082 finally:
2073 tr.release()
2083 tr.release()
2074 finally:
2084 finally:
2075 l.release()
2085 l.release()
2076 else:
2086 else:
2077 for m in obsolete.allmarkers(repo):
2087 for m in obsolete.allmarkers(repo):
2078 ui.write(hex(m.precnode()))
2088 ui.write(hex(m.precnode()))
2079 for repl in m.succnodes():
2089 for repl in m.succnodes():
2080 ui.write(' ')
2090 ui.write(' ')
2081 ui.write(hex(repl))
2091 ui.write(hex(repl))
2082 ui.write(' %X ' % m._data[2])
2092 ui.write(' %X ' % m._data[2])
2083 ui.write(m.metadata())
2093 ui.write(m.metadata())
2084 ui.write('\n')
2094 ui.write('\n')
2085
2095
2086 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2096 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2087 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2097 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2088 '''access the pushkey key/value protocol
2098 '''access the pushkey key/value protocol
2089
2099
2090 With two args, list the keys in the given namespace.
2100 With two args, list the keys in the given namespace.
2091
2101
2092 With five args, set a key to new if it currently is set to old.
2102 With five args, set a key to new if it currently is set to old.
2093 Reports success or failure.
2103 Reports success or failure.
2094 '''
2104 '''
2095
2105
2096 target = hg.peer(ui, {}, repopath)
2106 target = hg.peer(ui, {}, repopath)
2097 if keyinfo:
2107 if keyinfo:
2098 key, old, new = keyinfo
2108 key, old, new = keyinfo
2099 r = target.pushkey(namespace, key, old, new)
2109 r = target.pushkey(namespace, key, old, new)
2100 ui.status(str(r) + '\n')
2110 ui.status(str(r) + '\n')
2101 return not r
2111 return not r
2102 else:
2112 else:
2103 for k, v in target.listkeys(namespace).iteritems():
2113 for k, v in target.listkeys(namespace).iteritems():
2104 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2114 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2105 v.encode('string-escape')))
2115 v.encode('string-escape')))
2106
2116
2107 @command('debugpvec', [], _('A B'))
2117 @command('debugpvec', [], _('A B'))
2108 def debugpvec(ui, repo, a, b=None):
2118 def debugpvec(ui, repo, a, b=None):
2109 ca = scmutil.revsingle(repo, a)
2119 ca = scmutil.revsingle(repo, a)
2110 cb = scmutil.revsingle(repo, b)
2120 cb = scmutil.revsingle(repo, b)
2111 pa = pvec.ctxpvec(ca)
2121 pa = pvec.ctxpvec(ca)
2112 pb = pvec.ctxpvec(cb)
2122 pb = pvec.ctxpvec(cb)
2113 if pa == pb:
2123 if pa == pb:
2114 rel = "="
2124 rel = "="
2115 elif pa > pb:
2125 elif pa > pb:
2116 rel = ">"
2126 rel = ">"
2117 elif pa < pb:
2127 elif pa < pb:
2118 rel = "<"
2128 rel = "<"
2119 elif pa | pb:
2129 elif pa | pb:
2120 rel = "|"
2130 rel = "|"
2121 ui.write(_("a: %s\n") % pa)
2131 ui.write(_("a: %s\n") % pa)
2122 ui.write(_("b: %s\n") % pb)
2132 ui.write(_("b: %s\n") % pb)
2123 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2133 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2124 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2134 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2125 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2135 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2126 pa.distance(pb), rel))
2136 pa.distance(pb), rel))
2127
2137
2128 @command('debugrebuildstate',
2138 @command('debugrebuildstate',
2129 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2139 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2130 _('[-r REV] [REV]'))
2140 _('[-r REV] [REV]'))
2131 def debugrebuildstate(ui, repo, rev="tip"):
2141 def debugrebuildstate(ui, repo, rev="tip"):
2132 """rebuild the dirstate as it would look like for the given revision"""
2142 """rebuild the dirstate as it would look like for the given revision"""
2133 ctx = scmutil.revsingle(repo, rev)
2143 ctx = scmutil.revsingle(repo, rev)
2134 wlock = repo.wlock()
2144 wlock = repo.wlock()
2135 try:
2145 try:
2136 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2146 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2137 finally:
2147 finally:
2138 wlock.release()
2148 wlock.release()
2139
2149
2140 @command('debugrename',
2150 @command('debugrename',
2141 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2151 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2142 _('[-r REV] FILE'))
2152 _('[-r REV] FILE'))
2143 def debugrename(ui, repo, file1, *pats, **opts):
2153 def debugrename(ui, repo, file1, *pats, **opts):
2144 """dump rename information"""
2154 """dump rename information"""
2145
2155
2146 ctx = scmutil.revsingle(repo, opts.get('rev'))
2156 ctx = scmutil.revsingle(repo, opts.get('rev'))
2147 m = scmutil.match(ctx, (file1,) + pats, opts)
2157 m = scmutil.match(ctx, (file1,) + pats, opts)
2148 for abs in ctx.walk(m):
2158 for abs in ctx.walk(m):
2149 fctx = ctx[abs]
2159 fctx = ctx[abs]
2150 o = fctx.filelog().renamed(fctx.filenode())
2160 o = fctx.filelog().renamed(fctx.filenode())
2151 rel = m.rel(abs)
2161 rel = m.rel(abs)
2152 if o:
2162 if o:
2153 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2163 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2154 else:
2164 else:
2155 ui.write(_("%s not renamed\n") % rel)
2165 ui.write(_("%s not renamed\n") % rel)
2156
2166
2157 @command('debugrevlog',
2167 @command('debugrevlog',
2158 [('c', 'changelog', False, _('open changelog')),
2168 [('c', 'changelog', False, _('open changelog')),
2159 ('m', 'manifest', False, _('open manifest')),
2169 ('m', 'manifest', False, _('open manifest')),
2160 ('d', 'dump', False, _('dump index data'))],
2170 ('d', 'dump', False, _('dump index data'))],
2161 _('-c|-m|FILE'))
2171 _('-c|-m|FILE'))
2162 def debugrevlog(ui, repo, file_ = None, **opts):
2172 def debugrevlog(ui, repo, file_ = None, **opts):
2163 """show data and statistics about a revlog"""
2173 """show data and statistics about a revlog"""
2164 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2174 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2165
2175
2166 if opts.get("dump"):
2176 if opts.get("dump"):
2167 numrevs = len(r)
2177 numrevs = len(r)
2168 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2178 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2169 " rawsize totalsize compression heads\n")
2179 " rawsize totalsize compression heads\n")
2170 ts = 0
2180 ts = 0
2171 heads = set()
2181 heads = set()
2172 for rev in xrange(numrevs):
2182 for rev in xrange(numrevs):
2173 dbase = r.deltaparent(rev)
2183 dbase = r.deltaparent(rev)
2174 if dbase == -1:
2184 if dbase == -1:
2175 dbase = rev
2185 dbase = rev
2176 cbase = r.chainbase(rev)
2186 cbase = r.chainbase(rev)
2177 p1, p2 = r.parentrevs(rev)
2187 p1, p2 = r.parentrevs(rev)
2178 rs = r.rawsize(rev)
2188 rs = r.rawsize(rev)
2179 ts = ts + rs
2189 ts = ts + rs
2180 heads -= set(r.parentrevs(rev))
2190 heads -= set(r.parentrevs(rev))
2181 heads.add(rev)
2191 heads.add(rev)
2182 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2192 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2183 (rev, p1, p2, r.start(rev), r.end(rev),
2193 (rev, p1, p2, r.start(rev), r.end(rev),
2184 r.start(dbase), r.start(cbase),
2194 r.start(dbase), r.start(cbase),
2185 r.start(p1), r.start(p2),
2195 r.start(p1), r.start(p2),
2186 rs, ts, ts / r.end(rev), len(heads)))
2196 rs, ts, ts / r.end(rev), len(heads)))
2187 return 0
2197 return 0
2188
2198
2189 v = r.version
2199 v = r.version
2190 format = v & 0xFFFF
2200 format = v & 0xFFFF
2191 flags = []
2201 flags = []
2192 gdelta = False
2202 gdelta = False
2193 if v & revlog.REVLOGNGINLINEDATA:
2203 if v & revlog.REVLOGNGINLINEDATA:
2194 flags.append('inline')
2204 flags.append('inline')
2195 if v & revlog.REVLOGGENERALDELTA:
2205 if v & revlog.REVLOGGENERALDELTA:
2196 gdelta = True
2206 gdelta = True
2197 flags.append('generaldelta')
2207 flags.append('generaldelta')
2198 if not flags:
2208 if not flags:
2199 flags = ['(none)']
2209 flags = ['(none)']
2200
2210
2201 nummerges = 0
2211 nummerges = 0
2202 numfull = 0
2212 numfull = 0
2203 numprev = 0
2213 numprev = 0
2204 nump1 = 0
2214 nump1 = 0
2205 nump2 = 0
2215 nump2 = 0
2206 numother = 0
2216 numother = 0
2207 nump1prev = 0
2217 nump1prev = 0
2208 nump2prev = 0
2218 nump2prev = 0
2209 chainlengths = []
2219 chainlengths = []
2210
2220
2211 datasize = [None, 0, 0L]
2221 datasize = [None, 0, 0L]
2212 fullsize = [None, 0, 0L]
2222 fullsize = [None, 0, 0L]
2213 deltasize = [None, 0, 0L]
2223 deltasize = [None, 0, 0L]
2214
2224
2215 def addsize(size, l):
2225 def addsize(size, l):
2216 if l[0] is None or size < l[0]:
2226 if l[0] is None or size < l[0]:
2217 l[0] = size
2227 l[0] = size
2218 if size > l[1]:
2228 if size > l[1]:
2219 l[1] = size
2229 l[1] = size
2220 l[2] += size
2230 l[2] += size
2221
2231
2222 numrevs = len(r)
2232 numrevs = len(r)
2223 for rev in xrange(numrevs):
2233 for rev in xrange(numrevs):
2224 p1, p2 = r.parentrevs(rev)
2234 p1, p2 = r.parentrevs(rev)
2225 delta = r.deltaparent(rev)
2235 delta = r.deltaparent(rev)
2226 if format > 0:
2236 if format > 0:
2227 addsize(r.rawsize(rev), datasize)
2237 addsize(r.rawsize(rev), datasize)
2228 if p2 != nullrev:
2238 if p2 != nullrev:
2229 nummerges += 1
2239 nummerges += 1
2230 size = r.length(rev)
2240 size = r.length(rev)
2231 if delta == nullrev:
2241 if delta == nullrev:
2232 chainlengths.append(0)
2242 chainlengths.append(0)
2233 numfull += 1
2243 numfull += 1
2234 addsize(size, fullsize)
2244 addsize(size, fullsize)
2235 else:
2245 else:
2236 chainlengths.append(chainlengths[delta] + 1)
2246 chainlengths.append(chainlengths[delta] + 1)
2237 addsize(size, deltasize)
2247 addsize(size, deltasize)
2238 if delta == rev - 1:
2248 if delta == rev - 1:
2239 numprev += 1
2249 numprev += 1
2240 if delta == p1:
2250 if delta == p1:
2241 nump1prev += 1
2251 nump1prev += 1
2242 elif delta == p2:
2252 elif delta == p2:
2243 nump2prev += 1
2253 nump2prev += 1
2244 elif delta == p1:
2254 elif delta == p1:
2245 nump1 += 1
2255 nump1 += 1
2246 elif delta == p2:
2256 elif delta == p2:
2247 nump2 += 1
2257 nump2 += 1
2248 elif delta != nullrev:
2258 elif delta != nullrev:
2249 numother += 1
2259 numother += 1
2250
2260
2251 # Adjust size min value for empty cases
2261 # Adjust size min value for empty cases
2252 for size in (datasize, fullsize, deltasize):
2262 for size in (datasize, fullsize, deltasize):
2253 if size[0] is None:
2263 if size[0] is None:
2254 size[0] = 0
2264 size[0] = 0
2255
2265
2256 numdeltas = numrevs - numfull
2266 numdeltas = numrevs - numfull
2257 numoprev = numprev - nump1prev - nump2prev
2267 numoprev = numprev - nump1prev - nump2prev
2258 totalrawsize = datasize[2]
2268 totalrawsize = datasize[2]
2259 datasize[2] /= numrevs
2269 datasize[2] /= numrevs
2260 fulltotal = fullsize[2]
2270 fulltotal = fullsize[2]
2261 fullsize[2] /= numfull
2271 fullsize[2] /= numfull
2262 deltatotal = deltasize[2]
2272 deltatotal = deltasize[2]
2263 if numrevs - numfull > 0:
2273 if numrevs - numfull > 0:
2264 deltasize[2] /= numrevs - numfull
2274 deltasize[2] /= numrevs - numfull
2265 totalsize = fulltotal + deltatotal
2275 totalsize = fulltotal + deltatotal
2266 avgchainlen = sum(chainlengths) / numrevs
2276 avgchainlen = sum(chainlengths) / numrevs
2267 compratio = totalrawsize / totalsize
2277 compratio = totalrawsize / totalsize
2268
2278
2269 basedfmtstr = '%%%dd\n'
2279 basedfmtstr = '%%%dd\n'
2270 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2280 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2271
2281
2272 def dfmtstr(max):
2282 def dfmtstr(max):
2273 return basedfmtstr % len(str(max))
2283 return basedfmtstr % len(str(max))
2274 def pcfmtstr(max, padding=0):
2284 def pcfmtstr(max, padding=0):
2275 return basepcfmtstr % (len(str(max)), ' ' * padding)
2285 return basepcfmtstr % (len(str(max)), ' ' * padding)
2276
2286
2277 def pcfmt(value, total):
2287 def pcfmt(value, total):
2278 return (value, 100 * float(value) / total)
2288 return (value, 100 * float(value) / total)
2279
2289
2280 ui.write('format : %d\n' % format)
2290 ui.write('format : %d\n' % format)
2281 ui.write('flags : %s\n' % ', '.join(flags))
2291 ui.write('flags : %s\n' % ', '.join(flags))
2282
2292
2283 ui.write('\n')
2293 ui.write('\n')
2284 fmt = pcfmtstr(totalsize)
2294 fmt = pcfmtstr(totalsize)
2285 fmt2 = dfmtstr(totalsize)
2295 fmt2 = dfmtstr(totalsize)
2286 ui.write('revisions : ' + fmt2 % numrevs)
2296 ui.write('revisions : ' + fmt2 % numrevs)
2287 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2297 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2288 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2298 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2289 ui.write('revisions : ' + fmt2 % numrevs)
2299 ui.write('revisions : ' + fmt2 % numrevs)
2290 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2300 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2291 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2301 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2292 ui.write('revision size : ' + fmt2 % totalsize)
2302 ui.write('revision size : ' + fmt2 % totalsize)
2293 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2303 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2294 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2304 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2295
2305
2296 ui.write('\n')
2306 ui.write('\n')
2297 fmt = dfmtstr(max(avgchainlen, compratio))
2307 fmt = dfmtstr(max(avgchainlen, compratio))
2298 ui.write('avg chain length : ' + fmt % avgchainlen)
2308 ui.write('avg chain length : ' + fmt % avgchainlen)
2299 ui.write('compression ratio : ' + fmt % compratio)
2309 ui.write('compression ratio : ' + fmt % compratio)
2300
2310
2301 if format > 0:
2311 if format > 0:
2302 ui.write('\n')
2312 ui.write('\n')
2303 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2313 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2304 % tuple(datasize))
2314 % tuple(datasize))
2305 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2315 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2306 % tuple(fullsize))
2316 % tuple(fullsize))
2307 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2317 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2308 % tuple(deltasize))
2318 % tuple(deltasize))
2309
2319
2310 if numdeltas > 0:
2320 if numdeltas > 0:
2311 ui.write('\n')
2321 ui.write('\n')
2312 fmt = pcfmtstr(numdeltas)
2322 fmt = pcfmtstr(numdeltas)
2313 fmt2 = pcfmtstr(numdeltas, 4)
2323 fmt2 = pcfmtstr(numdeltas, 4)
2314 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2324 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2315 if numprev > 0:
2325 if numprev > 0:
2316 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2326 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2317 numprev))
2327 numprev))
2318 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2328 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2319 numprev))
2329 numprev))
2320 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2330 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2321 numprev))
2331 numprev))
2322 if gdelta:
2332 if gdelta:
2323 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2333 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2324 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2334 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2325 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2335 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2326 numdeltas))
2336 numdeltas))
2327
2337
2328 @command('debugrevspec', [], ('REVSPEC'))
2338 @command('debugrevspec', [], ('REVSPEC'))
2329 def debugrevspec(ui, repo, expr):
2339 def debugrevspec(ui, repo, expr):
2330 """parse and apply a revision specification
2340 """parse and apply a revision specification
2331
2341
2332 Use --verbose to print the parsed tree before and after aliases
2342 Use --verbose to print the parsed tree before and after aliases
2333 expansion.
2343 expansion.
2334 """
2344 """
2335 if ui.verbose:
2345 if ui.verbose:
2336 tree = revset.parse(expr)[0]
2346 tree = revset.parse(expr)[0]
2337 ui.note(revset.prettyformat(tree), "\n")
2347 ui.note(revset.prettyformat(tree), "\n")
2338 newtree = revset.findaliases(ui, tree)
2348 newtree = revset.findaliases(ui, tree)
2339 if newtree != tree:
2349 if newtree != tree:
2340 ui.note(revset.prettyformat(newtree), "\n")
2350 ui.note(revset.prettyformat(newtree), "\n")
2341 func = revset.match(ui, expr)
2351 func = revset.match(ui, expr)
2342 for c in func(repo, range(len(repo))):
2352 for c in func(repo, range(len(repo))):
2343 ui.write("%s\n" % c)
2353 ui.write("%s\n" % c)
2344
2354
2345 @command('debugsetparents', [], _('REV1 [REV2]'))
2355 @command('debugsetparents', [], _('REV1 [REV2]'))
2346 def debugsetparents(ui, repo, rev1, rev2=None):
2356 def debugsetparents(ui, repo, rev1, rev2=None):
2347 """manually set the parents of the current working directory
2357 """manually set the parents of the current working directory
2348
2358
2349 This is useful for writing repository conversion tools, but should
2359 This is useful for writing repository conversion tools, but should
2350 be used with care.
2360 be used with care.
2351
2361
2352 Returns 0 on success.
2362 Returns 0 on success.
2353 """
2363 """
2354
2364
2355 r1 = scmutil.revsingle(repo, rev1).node()
2365 r1 = scmutil.revsingle(repo, rev1).node()
2356 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2366 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2357
2367
2358 wlock = repo.wlock()
2368 wlock = repo.wlock()
2359 try:
2369 try:
2360 repo.setparents(r1, r2)
2370 repo.setparents(r1, r2)
2361 finally:
2371 finally:
2362 wlock.release()
2372 wlock.release()
2363
2373
2364 @command('debugstate',
2374 @command('debugstate',
2365 [('', 'nodates', None, _('do not display the saved mtime')),
2375 [('', 'nodates', None, _('do not display the saved mtime')),
2366 ('', 'datesort', None, _('sort by saved mtime'))],
2376 ('', 'datesort', None, _('sort by saved mtime'))],
2367 _('[OPTION]...'))
2377 _('[OPTION]...'))
2368 def debugstate(ui, repo, nodates=None, datesort=None):
2378 def debugstate(ui, repo, nodates=None, datesort=None):
2369 """show the contents of the current dirstate"""
2379 """show the contents of the current dirstate"""
2370 timestr = ""
2380 timestr = ""
2371 showdate = not nodates
2381 showdate = not nodates
2372 if datesort:
2382 if datesort:
2373 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2383 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2374 else:
2384 else:
2375 keyfunc = None # sort by filename
2385 keyfunc = None # sort by filename
2376 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2386 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2377 if showdate:
2387 if showdate:
2378 if ent[3] == -1:
2388 if ent[3] == -1:
2379 # Pad or slice to locale representation
2389 # Pad or slice to locale representation
2380 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2390 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2381 time.localtime(0)))
2391 time.localtime(0)))
2382 timestr = 'unset'
2392 timestr = 'unset'
2383 timestr = (timestr[:locale_len] +
2393 timestr = (timestr[:locale_len] +
2384 ' ' * (locale_len - len(timestr)))
2394 ' ' * (locale_len - len(timestr)))
2385 else:
2395 else:
2386 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2396 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2387 time.localtime(ent[3]))
2397 time.localtime(ent[3]))
2388 if ent[1] & 020000:
2398 if ent[1] & 020000:
2389 mode = 'lnk'
2399 mode = 'lnk'
2390 else:
2400 else:
2391 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2401 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2392 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2402 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2393 for f in repo.dirstate.copies():
2403 for f in repo.dirstate.copies():
2394 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2404 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2395
2405
2396 @command('debugsub',
2406 @command('debugsub',
2397 [('r', 'rev', '',
2407 [('r', 'rev', '',
2398 _('revision to check'), _('REV'))],
2408 _('revision to check'), _('REV'))],
2399 _('[-r REV] [REV]'))
2409 _('[-r REV] [REV]'))
2400 def debugsub(ui, repo, rev=None):
2410 def debugsub(ui, repo, rev=None):
2401 ctx = scmutil.revsingle(repo, rev, None)
2411 ctx = scmutil.revsingle(repo, rev, None)
2402 for k, v in sorted(ctx.substate.items()):
2412 for k, v in sorted(ctx.substate.items()):
2403 ui.write('path %s\n' % k)
2413 ui.write('path %s\n' % k)
2404 ui.write(' source %s\n' % v[0])
2414 ui.write(' source %s\n' % v[0])
2405 ui.write(' revision %s\n' % v[1])
2415 ui.write(' revision %s\n' % v[1])
2406
2416
2407 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2417 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2408 def debugwalk(ui, repo, *pats, **opts):
2418 def debugwalk(ui, repo, *pats, **opts):
2409 """show how files match on given patterns"""
2419 """show how files match on given patterns"""
2410 m = scmutil.match(repo[None], pats, opts)
2420 m = scmutil.match(repo[None], pats, opts)
2411 items = list(repo.walk(m))
2421 items = list(repo.walk(m))
2412 if not items:
2422 if not items:
2413 return
2423 return
2414 f = lambda fn: fn
2424 f = lambda fn: fn
2415 if ui.configbool('ui', 'slash') and os.sep != '/':
2425 if ui.configbool('ui', 'slash') and os.sep != '/':
2416 f = lambda fn: util.normpath(fn)
2426 f = lambda fn: util.normpath(fn)
2417 fmt = 'f %%-%ds %%-%ds %%s' % (
2427 fmt = 'f %%-%ds %%-%ds %%s' % (
2418 max([len(abs) for abs in items]),
2428 max([len(abs) for abs in items]),
2419 max([len(m.rel(abs)) for abs in items]))
2429 max([len(m.rel(abs)) for abs in items]))
2420 for abs in items:
2430 for abs in items:
2421 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2431 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2422 ui.write("%s\n" % line.rstrip())
2432 ui.write("%s\n" % line.rstrip())
2423
2433
2424 @command('debugwireargs',
2434 @command('debugwireargs',
2425 [('', 'three', '', 'three'),
2435 [('', 'three', '', 'three'),
2426 ('', 'four', '', 'four'),
2436 ('', 'four', '', 'four'),
2427 ('', 'five', '', 'five'),
2437 ('', 'five', '', 'five'),
2428 ] + remoteopts,
2438 ] + remoteopts,
2429 _('REPO [OPTIONS]... [ONE [TWO]]'))
2439 _('REPO [OPTIONS]... [ONE [TWO]]'))
2430 def debugwireargs(ui, repopath, *vals, **opts):
2440 def debugwireargs(ui, repopath, *vals, **opts):
2431 repo = hg.peer(ui, opts, repopath)
2441 repo = hg.peer(ui, opts, repopath)
2432 for opt in remoteopts:
2442 for opt in remoteopts:
2433 del opts[opt[1]]
2443 del opts[opt[1]]
2434 args = {}
2444 args = {}
2435 for k, v in opts.iteritems():
2445 for k, v in opts.iteritems():
2436 if v:
2446 if v:
2437 args[k] = v
2447 args[k] = v
2438 # run twice to check that we don't mess up the stream for the next command
2448 # run twice to check that we don't mess up the stream for the next command
2439 res1 = repo.debugwireargs(*vals, **args)
2449 res1 = repo.debugwireargs(*vals, **args)
2440 res2 = repo.debugwireargs(*vals, **args)
2450 res2 = repo.debugwireargs(*vals, **args)
2441 ui.write("%s\n" % res1)
2451 ui.write("%s\n" % res1)
2442 if res1 != res2:
2452 if res1 != res2:
2443 ui.warn("%s\n" % res2)
2453 ui.warn("%s\n" % res2)
2444
2454
2445 @command('^diff',
2455 @command('^diff',
2446 [('r', 'rev', [], _('revision'), _('REV')),
2456 [('r', 'rev', [], _('revision'), _('REV')),
2447 ('c', 'change', '', _('change made by revision'), _('REV'))
2457 ('c', 'change', '', _('change made by revision'), _('REV'))
2448 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2458 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2449 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2459 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2450 def diff(ui, repo, *pats, **opts):
2460 def diff(ui, repo, *pats, **opts):
2451 """diff repository (or selected files)
2461 """diff repository (or selected files)
2452
2462
2453 Show differences between revisions for the specified files.
2463 Show differences between revisions for the specified files.
2454
2464
2455 Differences between files are shown using the unified diff format.
2465 Differences between files are shown using the unified diff format.
2456
2466
2457 .. note::
2467 .. note::
2458 diff may generate unexpected results for merges, as it will
2468 diff may generate unexpected results for merges, as it will
2459 default to comparing against the working directory's first
2469 default to comparing against the working directory's first
2460 parent changeset if no revisions are specified.
2470 parent changeset if no revisions are specified.
2461
2471
2462 When two revision arguments are given, then changes are shown
2472 When two revision arguments are given, then changes are shown
2463 between those revisions. If only one revision is specified then
2473 between those revisions. If only one revision is specified then
2464 that revision is compared to the working directory, and, when no
2474 that revision is compared to the working directory, and, when no
2465 revisions are specified, the working directory files are compared
2475 revisions are specified, the working directory files are compared
2466 to its parent.
2476 to its parent.
2467
2477
2468 Alternatively you can specify -c/--change with a revision to see
2478 Alternatively you can specify -c/--change with a revision to see
2469 the changes in that changeset relative to its first parent.
2479 the changes in that changeset relative to its first parent.
2470
2480
2471 Without the -a/--text option, diff will avoid generating diffs of
2481 Without the -a/--text option, diff will avoid generating diffs of
2472 files it detects as binary. With -a, diff will generate a diff
2482 files it detects as binary. With -a, diff will generate a diff
2473 anyway, probably with undesirable results.
2483 anyway, probably with undesirable results.
2474
2484
2475 Use the -g/--git option to generate diffs in the git extended diff
2485 Use the -g/--git option to generate diffs in the git extended diff
2476 format. For more information, read :hg:`help diffs`.
2486 format. For more information, read :hg:`help diffs`.
2477
2487
2478 .. container:: verbose
2488 .. container:: verbose
2479
2489
2480 Examples:
2490 Examples:
2481
2491
2482 - compare a file in the current working directory to its parent::
2492 - compare a file in the current working directory to its parent::
2483
2493
2484 hg diff foo.c
2494 hg diff foo.c
2485
2495
2486 - compare two historical versions of a directory, with rename info::
2496 - compare two historical versions of a directory, with rename info::
2487
2497
2488 hg diff --git -r 1.0:1.2 lib/
2498 hg diff --git -r 1.0:1.2 lib/
2489
2499
2490 - get change stats relative to the last change on some date::
2500 - get change stats relative to the last change on some date::
2491
2501
2492 hg diff --stat -r "date('may 2')"
2502 hg diff --stat -r "date('may 2')"
2493
2503
2494 - diff all newly-added files that contain a keyword::
2504 - diff all newly-added files that contain a keyword::
2495
2505
2496 hg diff "set:added() and grep(GNU)"
2506 hg diff "set:added() and grep(GNU)"
2497
2507
2498 - compare a revision and its parents::
2508 - compare a revision and its parents::
2499
2509
2500 hg diff -c 9353 # compare against first parent
2510 hg diff -c 9353 # compare against first parent
2501 hg diff -r 9353^:9353 # same using revset syntax
2511 hg diff -r 9353^:9353 # same using revset syntax
2502 hg diff -r 9353^2:9353 # compare against the second parent
2512 hg diff -r 9353^2:9353 # compare against the second parent
2503
2513
2504 Returns 0 on success.
2514 Returns 0 on success.
2505 """
2515 """
2506
2516
2507 revs = opts.get('rev')
2517 revs = opts.get('rev')
2508 change = opts.get('change')
2518 change = opts.get('change')
2509 stat = opts.get('stat')
2519 stat = opts.get('stat')
2510 reverse = opts.get('reverse')
2520 reverse = opts.get('reverse')
2511
2521
2512 if revs and change:
2522 if revs and change:
2513 msg = _('cannot specify --rev and --change at the same time')
2523 msg = _('cannot specify --rev and --change at the same time')
2514 raise util.Abort(msg)
2524 raise util.Abort(msg)
2515 elif change:
2525 elif change:
2516 node2 = scmutil.revsingle(repo, change, None).node()
2526 node2 = scmutil.revsingle(repo, change, None).node()
2517 node1 = repo[node2].p1().node()
2527 node1 = repo[node2].p1().node()
2518 else:
2528 else:
2519 node1, node2 = scmutil.revpair(repo, revs)
2529 node1, node2 = scmutil.revpair(repo, revs)
2520
2530
2521 if reverse:
2531 if reverse:
2522 node1, node2 = node2, node1
2532 node1, node2 = node2, node1
2523
2533
2524 diffopts = patch.diffopts(ui, opts)
2534 diffopts = patch.diffopts(ui, opts)
2525 m = scmutil.match(repo[node2], pats, opts)
2535 m = scmutil.match(repo[node2], pats, opts)
2526 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2536 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2527 listsubrepos=opts.get('subrepos'))
2537 listsubrepos=opts.get('subrepos'))
2528
2538
2529 @command('^export',
2539 @command('^export',
2530 [('o', 'output', '',
2540 [('o', 'output', '',
2531 _('print output to file with formatted name'), _('FORMAT')),
2541 _('print output to file with formatted name'), _('FORMAT')),
2532 ('', 'switch-parent', None, _('diff against the second parent')),
2542 ('', 'switch-parent', None, _('diff against the second parent')),
2533 ('r', 'rev', [], _('revisions to export'), _('REV')),
2543 ('r', 'rev', [], _('revisions to export'), _('REV')),
2534 ] + diffopts,
2544 ] + diffopts,
2535 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2545 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2536 def export(ui, repo, *changesets, **opts):
2546 def export(ui, repo, *changesets, **opts):
2537 """dump the header and diffs for one or more changesets
2547 """dump the header and diffs for one or more changesets
2538
2548
2539 Print the changeset header and diffs for one or more revisions.
2549 Print the changeset header and diffs for one or more revisions.
2540
2550
2541 The information shown in the changeset header is: author, date,
2551 The information shown in the changeset header is: author, date,
2542 branch name (if non-default), changeset hash, parent(s) and commit
2552 branch name (if non-default), changeset hash, parent(s) and commit
2543 comment.
2553 comment.
2544
2554
2545 .. note::
2555 .. note::
2546 export may generate unexpected diff output for merge
2556 export may generate unexpected diff output for merge
2547 changesets, as it will compare the merge changeset against its
2557 changesets, as it will compare the merge changeset against its
2548 first parent only.
2558 first parent only.
2549
2559
2550 Output may be to a file, in which case the name of the file is
2560 Output may be to a file, in which case the name of the file is
2551 given using a format string. The formatting rules are as follows:
2561 given using a format string. The formatting rules are as follows:
2552
2562
2553 :``%%``: literal "%" character
2563 :``%%``: literal "%" character
2554 :``%H``: changeset hash (40 hexadecimal digits)
2564 :``%H``: changeset hash (40 hexadecimal digits)
2555 :``%N``: number of patches being generated
2565 :``%N``: number of patches being generated
2556 :``%R``: changeset revision number
2566 :``%R``: changeset revision number
2557 :``%b``: basename of the exporting repository
2567 :``%b``: basename of the exporting repository
2558 :``%h``: short-form changeset hash (12 hexadecimal digits)
2568 :``%h``: short-form changeset hash (12 hexadecimal digits)
2559 :``%m``: first line of the commit message (only alphanumeric characters)
2569 :``%m``: first line of the commit message (only alphanumeric characters)
2560 :``%n``: zero-padded sequence number, starting at 1
2570 :``%n``: zero-padded sequence number, starting at 1
2561 :``%r``: zero-padded changeset revision number
2571 :``%r``: zero-padded changeset revision number
2562
2572
2563 Without the -a/--text option, export will avoid generating diffs
2573 Without the -a/--text option, export will avoid generating diffs
2564 of files it detects as binary. With -a, export will generate a
2574 of files it detects as binary. With -a, export will generate a
2565 diff anyway, probably with undesirable results.
2575 diff anyway, probably with undesirable results.
2566
2576
2567 Use the -g/--git option to generate diffs in the git extended diff
2577 Use the -g/--git option to generate diffs in the git extended diff
2568 format. See :hg:`help diffs` for more information.
2578 format. See :hg:`help diffs` for more information.
2569
2579
2570 With the --switch-parent option, the diff will be against the
2580 With the --switch-parent option, the diff will be against the
2571 second parent. It can be useful to review a merge.
2581 second parent. It can be useful to review a merge.
2572
2582
2573 .. container:: verbose
2583 .. container:: verbose
2574
2584
2575 Examples:
2585 Examples:
2576
2586
2577 - use export and import to transplant a bugfix to the current
2587 - use export and import to transplant a bugfix to the current
2578 branch::
2588 branch::
2579
2589
2580 hg export -r 9353 | hg import -
2590 hg export -r 9353 | hg import -
2581
2591
2582 - export all the changesets between two revisions to a file with
2592 - export all the changesets between two revisions to a file with
2583 rename information::
2593 rename information::
2584
2594
2585 hg export --git -r 123:150 > changes.txt
2595 hg export --git -r 123:150 > changes.txt
2586
2596
2587 - split outgoing changes into a series of patches with
2597 - split outgoing changes into a series of patches with
2588 descriptive names::
2598 descriptive names::
2589
2599
2590 hg export -r "outgoing()" -o "%n-%m.patch"
2600 hg export -r "outgoing()" -o "%n-%m.patch"
2591
2601
2592 Returns 0 on success.
2602 Returns 0 on success.
2593 """
2603 """
2594 changesets += tuple(opts.get('rev', []))
2604 changesets += tuple(opts.get('rev', []))
2595 revs = scmutil.revrange(repo, changesets)
2605 revs = scmutil.revrange(repo, changesets)
2596 if not revs:
2606 if not revs:
2597 raise util.Abort(_("export requires at least one changeset"))
2607 raise util.Abort(_("export requires at least one changeset"))
2598 if len(revs) > 1:
2608 if len(revs) > 1:
2599 ui.note(_('exporting patches:\n'))
2609 ui.note(_('exporting patches:\n'))
2600 else:
2610 else:
2601 ui.note(_('exporting patch:\n'))
2611 ui.note(_('exporting patch:\n'))
2602 cmdutil.export(repo, revs, template=opts.get('output'),
2612 cmdutil.export(repo, revs, template=opts.get('output'),
2603 switch_parent=opts.get('switch_parent'),
2613 switch_parent=opts.get('switch_parent'),
2604 opts=patch.diffopts(ui, opts))
2614 opts=patch.diffopts(ui, opts))
2605
2615
2606 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2616 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2607 def forget(ui, repo, *pats, **opts):
2617 def forget(ui, repo, *pats, **opts):
2608 """forget the specified files on the next commit
2618 """forget the specified files on the next commit
2609
2619
2610 Mark the specified files so they will no longer be tracked
2620 Mark the specified files so they will no longer be tracked
2611 after the next commit.
2621 after the next commit.
2612
2622
2613 This only removes files from the current branch, not from the
2623 This only removes files from the current branch, not from the
2614 entire project history, and it does not delete them from the
2624 entire project history, and it does not delete them from the
2615 working directory.
2625 working directory.
2616
2626
2617 To undo a forget before the next commit, see :hg:`add`.
2627 To undo a forget before the next commit, see :hg:`add`.
2618
2628
2619 .. container:: verbose
2629 .. container:: verbose
2620
2630
2621 Examples:
2631 Examples:
2622
2632
2623 - forget newly-added binary files::
2633 - forget newly-added binary files::
2624
2634
2625 hg forget "set:added() and binary()"
2635 hg forget "set:added() and binary()"
2626
2636
2627 - forget files that would be excluded by .hgignore::
2637 - forget files that would be excluded by .hgignore::
2628
2638
2629 hg forget "set:hgignore()"
2639 hg forget "set:hgignore()"
2630
2640
2631 Returns 0 on success.
2641 Returns 0 on success.
2632 """
2642 """
2633
2643
2634 if not pats:
2644 if not pats:
2635 raise util.Abort(_('no files specified'))
2645 raise util.Abort(_('no files specified'))
2636
2646
2637 m = scmutil.match(repo[None], pats, opts)
2647 m = scmutil.match(repo[None], pats, opts)
2638 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2648 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2639 return rejected and 1 or 0
2649 return rejected and 1 or 0
2640
2650
2641 @command(
2651 @command(
2642 'graft',
2652 'graft',
2643 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2653 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2644 ('c', 'continue', False, _('resume interrupted graft')),
2654 ('c', 'continue', False, _('resume interrupted graft')),
2645 ('e', 'edit', False, _('invoke editor on commit messages')),
2655 ('e', 'edit', False, _('invoke editor on commit messages')),
2646 ('', 'log', None, _('append graft info to log message')),
2656 ('', 'log', None, _('append graft info to log message')),
2647 ('D', 'currentdate', False,
2657 ('D', 'currentdate', False,
2648 _('record the current date as commit date')),
2658 _('record the current date as commit date')),
2649 ('U', 'currentuser', False,
2659 ('U', 'currentuser', False,
2650 _('record the current user as committer'), _('DATE'))]
2660 _('record the current user as committer'), _('DATE'))]
2651 + commitopts2 + mergetoolopts + dryrunopts,
2661 + commitopts2 + mergetoolopts + dryrunopts,
2652 _('[OPTION]... [-r] REV...'))
2662 _('[OPTION]... [-r] REV...'))
2653 def graft(ui, repo, *revs, **opts):
2663 def graft(ui, repo, *revs, **opts):
2654 '''copy changes from other branches onto the current branch
2664 '''copy changes from other branches onto the current branch
2655
2665
2656 This command uses Mercurial's merge logic to copy individual
2666 This command uses Mercurial's merge logic to copy individual
2657 changes from other branches without merging branches in the
2667 changes from other branches without merging branches in the
2658 history graph. This is sometimes known as 'backporting' or
2668 history graph. This is sometimes known as 'backporting' or
2659 'cherry-picking'. By default, graft will copy user, date, and
2669 'cherry-picking'. By default, graft will copy user, date, and
2660 description from the source changesets.
2670 description from the source changesets.
2661
2671
2662 Changesets that are ancestors of the current revision, that have
2672 Changesets that are ancestors of the current revision, that have
2663 already been grafted, or that are merges will be skipped.
2673 already been grafted, or that are merges will be skipped.
2664
2674
2665 If --log is specified, log messages will have a comment appended
2675 If --log is specified, log messages will have a comment appended
2666 of the form::
2676 of the form::
2667
2677
2668 (grafted from CHANGESETHASH)
2678 (grafted from CHANGESETHASH)
2669
2679
2670 If a graft merge results in conflicts, the graft process is
2680 If a graft merge results in conflicts, the graft process is
2671 interrupted so that the current merge can be manually resolved.
2681 interrupted so that the current merge can be manually resolved.
2672 Once all conflicts are addressed, the graft process can be
2682 Once all conflicts are addressed, the graft process can be
2673 continued with the -c/--continue option.
2683 continued with the -c/--continue option.
2674
2684
2675 .. note::
2685 .. note::
2676 The -c/--continue option does not reapply earlier options.
2686 The -c/--continue option does not reapply earlier options.
2677
2687
2678 .. container:: verbose
2688 .. container:: verbose
2679
2689
2680 Examples:
2690 Examples:
2681
2691
2682 - copy a single change to the stable branch and edit its description::
2692 - copy a single change to the stable branch and edit its description::
2683
2693
2684 hg update stable
2694 hg update stable
2685 hg graft --edit 9393
2695 hg graft --edit 9393
2686
2696
2687 - graft a range of changesets with one exception, updating dates::
2697 - graft a range of changesets with one exception, updating dates::
2688
2698
2689 hg graft -D "2085::2093 and not 2091"
2699 hg graft -D "2085::2093 and not 2091"
2690
2700
2691 - continue a graft after resolving conflicts::
2701 - continue a graft after resolving conflicts::
2692
2702
2693 hg graft -c
2703 hg graft -c
2694
2704
2695 - show the source of a grafted changeset::
2705 - show the source of a grafted changeset::
2696
2706
2697 hg log --debug -r tip
2707 hg log --debug -r tip
2698
2708
2699 Returns 0 on successful completion.
2709 Returns 0 on successful completion.
2700 '''
2710 '''
2701
2711
2702 revs = list(revs)
2712 revs = list(revs)
2703 revs.extend(opts['rev'])
2713 revs.extend(opts['rev'])
2704
2714
2705 if not opts.get('user') and opts.get('currentuser'):
2715 if not opts.get('user') and opts.get('currentuser'):
2706 opts['user'] = ui.username()
2716 opts['user'] = ui.username()
2707 if not opts.get('date') and opts.get('currentdate'):
2717 if not opts.get('date') and opts.get('currentdate'):
2708 opts['date'] = "%d %d" % util.makedate()
2718 opts['date'] = "%d %d" % util.makedate()
2709
2719
2710 editor = None
2720 editor = None
2711 if opts.get('edit'):
2721 if opts.get('edit'):
2712 editor = cmdutil.commitforceeditor
2722 editor = cmdutil.commitforceeditor
2713
2723
2714 cont = False
2724 cont = False
2715 if opts['continue']:
2725 if opts['continue']:
2716 cont = True
2726 cont = True
2717 if revs:
2727 if revs:
2718 raise util.Abort(_("can't specify --continue and revisions"))
2728 raise util.Abort(_("can't specify --continue and revisions"))
2719 # read in unfinished revisions
2729 # read in unfinished revisions
2720 try:
2730 try:
2721 nodes = repo.opener.read('graftstate').splitlines()
2731 nodes = repo.opener.read('graftstate').splitlines()
2722 revs = [repo[node].rev() for node in nodes]
2732 revs = [repo[node].rev() for node in nodes]
2723 except IOError, inst:
2733 except IOError, inst:
2724 if inst.errno != errno.ENOENT:
2734 if inst.errno != errno.ENOENT:
2725 raise
2735 raise
2726 raise util.Abort(_("no graft state found, can't continue"))
2736 raise util.Abort(_("no graft state found, can't continue"))
2727 else:
2737 else:
2728 cmdutil.bailifchanged(repo)
2738 cmdutil.bailifchanged(repo)
2729 if not revs:
2739 if not revs:
2730 raise util.Abort(_('no revisions specified'))
2740 raise util.Abort(_('no revisions specified'))
2731 revs = scmutil.revrange(repo, revs)
2741 revs = scmutil.revrange(repo, revs)
2732
2742
2733 # check for merges
2743 # check for merges
2734 for rev in repo.revs('%ld and merge()', revs):
2744 for rev in repo.revs('%ld and merge()', revs):
2735 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2745 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2736 revs.remove(rev)
2746 revs.remove(rev)
2737 if not revs:
2747 if not revs:
2738 return -1
2748 return -1
2739
2749
2740 # check for ancestors of dest branch
2750 # check for ancestors of dest branch
2741 for rev in repo.revs('::. and %ld', revs):
2751 for rev in repo.revs('::. and %ld', revs):
2742 ui.warn(_('skipping ancestor revision %s\n') % rev)
2752 ui.warn(_('skipping ancestor revision %s\n') % rev)
2743 revs.remove(rev)
2753 revs.remove(rev)
2744 if not revs:
2754 if not revs:
2745 return -1
2755 return -1
2746
2756
2747 # analyze revs for earlier grafts
2757 # analyze revs for earlier grafts
2748 ids = {}
2758 ids = {}
2749 for ctx in repo.set("%ld", revs):
2759 for ctx in repo.set("%ld", revs):
2750 ids[ctx.hex()] = ctx.rev()
2760 ids[ctx.hex()] = ctx.rev()
2751 n = ctx.extra().get('source')
2761 n = ctx.extra().get('source')
2752 if n:
2762 if n:
2753 ids[n] = ctx.rev()
2763 ids[n] = ctx.rev()
2754
2764
2755 # check ancestors for earlier grafts
2765 # check ancestors for earlier grafts
2756 ui.debug('scanning for duplicate grafts\n')
2766 ui.debug('scanning for duplicate grafts\n')
2757 for ctx in repo.set("::. - ::%ld", revs):
2767 for ctx in repo.set("::. - ::%ld", revs):
2758 n = ctx.extra().get('source')
2768 n = ctx.extra().get('source')
2759 if n in ids:
2769 if n in ids:
2760 r = repo[n].rev()
2770 r = repo[n].rev()
2761 if r in revs:
2771 if r in revs:
2762 ui.warn(_('skipping already grafted revision %s\n') % r)
2772 ui.warn(_('skipping already grafted revision %s\n') % r)
2763 revs.remove(r)
2773 revs.remove(r)
2764 elif ids[n] in revs:
2774 elif ids[n] in revs:
2765 ui.warn(_('skipping already grafted revision %s '
2775 ui.warn(_('skipping already grafted revision %s '
2766 '(same origin %d)\n') % (ids[n], r))
2776 '(same origin %d)\n') % (ids[n], r))
2767 revs.remove(ids[n])
2777 revs.remove(ids[n])
2768 elif ctx.hex() in ids:
2778 elif ctx.hex() in ids:
2769 r = ids[ctx.hex()]
2779 r = ids[ctx.hex()]
2770 ui.warn(_('skipping already grafted revision %s '
2780 ui.warn(_('skipping already grafted revision %s '
2771 '(was grafted from %d)\n') % (r, ctx.rev()))
2781 '(was grafted from %d)\n') % (r, ctx.rev()))
2772 revs.remove(r)
2782 revs.remove(r)
2773 if not revs:
2783 if not revs:
2774 return -1
2784 return -1
2775
2785
2776 wlock = repo.wlock()
2786 wlock = repo.wlock()
2777 try:
2787 try:
2778 for pos, ctx in enumerate(repo.set("%ld", revs)):
2788 for pos, ctx in enumerate(repo.set("%ld", revs)):
2779 current = repo['.']
2789 current = repo['.']
2780
2790
2781 ui.status(_('grafting revision %s\n') % ctx.rev())
2791 ui.status(_('grafting revision %s\n') % ctx.rev())
2782 if opts.get('dry_run'):
2792 if opts.get('dry_run'):
2783 continue
2793 continue
2784
2794
2785 # we don't merge the first commit when continuing
2795 # we don't merge the first commit when continuing
2786 if not cont:
2796 if not cont:
2787 # perform the graft merge with p1(rev) as 'ancestor'
2797 # perform the graft merge with p1(rev) as 'ancestor'
2788 try:
2798 try:
2789 # ui.forcemerge is an internal variable, do not document
2799 # ui.forcemerge is an internal variable, do not document
2790 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2800 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2791 stats = mergemod.update(repo, ctx.node(), True, True, False,
2801 stats = mergemod.update(repo, ctx.node(), True, True, False,
2792 ctx.p1().node())
2802 ctx.p1().node())
2793 finally:
2803 finally:
2794 repo.ui.setconfig('ui', 'forcemerge', '')
2804 repo.ui.setconfig('ui', 'forcemerge', '')
2795 # report any conflicts
2805 # report any conflicts
2796 if stats and stats[3] > 0:
2806 if stats and stats[3] > 0:
2797 # write out state for --continue
2807 # write out state for --continue
2798 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2808 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2799 repo.opener.write('graftstate', ''.join(nodelines))
2809 repo.opener.write('graftstate', ''.join(nodelines))
2800 raise util.Abort(
2810 raise util.Abort(
2801 _("unresolved conflicts, can't continue"),
2811 _("unresolved conflicts, can't continue"),
2802 hint=_('use hg resolve and hg graft --continue'))
2812 hint=_('use hg resolve and hg graft --continue'))
2803 else:
2813 else:
2804 cont = False
2814 cont = False
2805
2815
2806 # drop the second merge parent
2816 # drop the second merge parent
2807 repo.setparents(current.node(), nullid)
2817 repo.setparents(current.node(), nullid)
2808 repo.dirstate.write()
2818 repo.dirstate.write()
2809 # fix up dirstate for copies and renames
2819 # fix up dirstate for copies and renames
2810 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2820 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2811
2821
2812 # commit
2822 # commit
2813 source = ctx.extra().get('source')
2823 source = ctx.extra().get('source')
2814 if not source:
2824 if not source:
2815 source = ctx.hex()
2825 source = ctx.hex()
2816 extra = {'source': source}
2826 extra = {'source': source}
2817 user = ctx.user()
2827 user = ctx.user()
2818 if opts.get('user'):
2828 if opts.get('user'):
2819 user = opts['user']
2829 user = opts['user']
2820 date = ctx.date()
2830 date = ctx.date()
2821 if opts.get('date'):
2831 if opts.get('date'):
2822 date = opts['date']
2832 date = opts['date']
2823 message = ctx.description()
2833 message = ctx.description()
2824 if opts.get('log'):
2834 if opts.get('log'):
2825 message += '\n(grafted from %s)' % ctx.hex()
2835 message += '\n(grafted from %s)' % ctx.hex()
2826 node = repo.commit(text=message, user=user,
2836 node = repo.commit(text=message, user=user,
2827 date=date, extra=extra, editor=editor)
2837 date=date, extra=extra, editor=editor)
2828 if node is None:
2838 if node is None:
2829 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2839 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2830 finally:
2840 finally:
2831 wlock.release()
2841 wlock.release()
2832
2842
2833 # remove state when we complete successfully
2843 # remove state when we complete successfully
2834 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2844 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2835 util.unlinkpath(repo.join('graftstate'))
2845 util.unlinkpath(repo.join('graftstate'))
2836
2846
2837 return 0
2847 return 0
2838
2848
2839 @command('grep',
2849 @command('grep',
2840 [('0', 'print0', None, _('end fields with NUL')),
2850 [('0', 'print0', None, _('end fields with NUL')),
2841 ('', 'all', None, _('print all revisions that match')),
2851 ('', 'all', None, _('print all revisions that match')),
2842 ('a', 'text', None, _('treat all files as text')),
2852 ('a', 'text', None, _('treat all files as text')),
2843 ('f', 'follow', None,
2853 ('f', 'follow', None,
2844 _('follow changeset history,'
2854 _('follow changeset history,'
2845 ' or file history across copies and renames')),
2855 ' or file history across copies and renames')),
2846 ('i', 'ignore-case', None, _('ignore case when matching')),
2856 ('i', 'ignore-case', None, _('ignore case when matching')),
2847 ('l', 'files-with-matches', None,
2857 ('l', 'files-with-matches', None,
2848 _('print only filenames and revisions that match')),
2858 _('print only filenames and revisions that match')),
2849 ('n', 'line-number', None, _('print matching line numbers')),
2859 ('n', 'line-number', None, _('print matching line numbers')),
2850 ('r', 'rev', [],
2860 ('r', 'rev', [],
2851 _('only search files changed within revision range'), _('REV')),
2861 _('only search files changed within revision range'), _('REV')),
2852 ('u', 'user', None, _('list the author (long with -v)')),
2862 ('u', 'user', None, _('list the author (long with -v)')),
2853 ('d', 'date', None, _('list the date (short with -q)')),
2863 ('d', 'date', None, _('list the date (short with -q)')),
2854 ] + walkopts,
2864 ] + walkopts,
2855 _('[OPTION]... PATTERN [FILE]...'))
2865 _('[OPTION]... PATTERN [FILE]...'))
2856 def grep(ui, repo, pattern, *pats, **opts):
2866 def grep(ui, repo, pattern, *pats, **opts):
2857 """search for a pattern in specified files and revisions
2867 """search for a pattern in specified files and revisions
2858
2868
2859 Search revisions of files for a regular expression.
2869 Search revisions of files for a regular expression.
2860
2870
2861 This command behaves differently than Unix grep. It only accepts
2871 This command behaves differently than Unix grep. It only accepts
2862 Python/Perl regexps. It searches repository history, not the
2872 Python/Perl regexps. It searches repository history, not the
2863 working directory. It always prints the revision number in which a
2873 working directory. It always prints the revision number in which a
2864 match appears.
2874 match appears.
2865
2875
2866 By default, grep only prints output for the first revision of a
2876 By default, grep only prints output for the first revision of a
2867 file in which it finds a match. To get it to print every revision
2877 file in which it finds a match. To get it to print every revision
2868 that contains a change in match status ("-" for a match that
2878 that contains a change in match status ("-" for a match that
2869 becomes a non-match, or "+" for a non-match that becomes a match),
2879 becomes a non-match, or "+" for a non-match that becomes a match),
2870 use the --all flag.
2880 use the --all flag.
2871
2881
2872 Returns 0 if a match is found, 1 otherwise.
2882 Returns 0 if a match is found, 1 otherwise.
2873 """
2883 """
2874 reflags = re.M
2884 reflags = re.M
2875 if opts.get('ignore_case'):
2885 if opts.get('ignore_case'):
2876 reflags |= re.I
2886 reflags |= re.I
2877 try:
2887 try:
2878 regexp = re.compile(pattern, reflags)
2888 regexp = re.compile(pattern, reflags)
2879 except re.error, inst:
2889 except re.error, inst:
2880 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2890 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2881 return 1
2891 return 1
2882 sep, eol = ':', '\n'
2892 sep, eol = ':', '\n'
2883 if opts.get('print0'):
2893 if opts.get('print0'):
2884 sep = eol = '\0'
2894 sep = eol = '\0'
2885
2895
2886 getfile = util.lrucachefunc(repo.file)
2896 getfile = util.lrucachefunc(repo.file)
2887
2897
2888 def matchlines(body):
2898 def matchlines(body):
2889 begin = 0
2899 begin = 0
2890 linenum = 0
2900 linenum = 0
2891 while True:
2901 while True:
2892 match = regexp.search(body, begin)
2902 match = regexp.search(body, begin)
2893 if not match:
2903 if not match:
2894 break
2904 break
2895 mstart, mend = match.span()
2905 mstart, mend = match.span()
2896 linenum += body.count('\n', begin, mstart) + 1
2906 linenum += body.count('\n', begin, mstart) + 1
2897 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2907 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2898 begin = body.find('\n', mend) + 1 or len(body) + 1
2908 begin = body.find('\n', mend) + 1 or len(body) + 1
2899 lend = begin - 1
2909 lend = begin - 1
2900 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2910 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2901
2911
2902 class linestate(object):
2912 class linestate(object):
2903 def __init__(self, line, linenum, colstart, colend):
2913 def __init__(self, line, linenum, colstart, colend):
2904 self.line = line
2914 self.line = line
2905 self.linenum = linenum
2915 self.linenum = linenum
2906 self.colstart = colstart
2916 self.colstart = colstart
2907 self.colend = colend
2917 self.colend = colend
2908
2918
2909 def __hash__(self):
2919 def __hash__(self):
2910 return hash((self.linenum, self.line))
2920 return hash((self.linenum, self.line))
2911
2921
2912 def __eq__(self, other):
2922 def __eq__(self, other):
2913 return self.line == other.line
2923 return self.line == other.line
2914
2924
2915 matches = {}
2925 matches = {}
2916 copies = {}
2926 copies = {}
2917 def grepbody(fn, rev, body):
2927 def grepbody(fn, rev, body):
2918 matches[rev].setdefault(fn, [])
2928 matches[rev].setdefault(fn, [])
2919 m = matches[rev][fn]
2929 m = matches[rev][fn]
2920 for lnum, cstart, cend, line in matchlines(body):
2930 for lnum, cstart, cend, line in matchlines(body):
2921 s = linestate(line, lnum, cstart, cend)
2931 s = linestate(line, lnum, cstart, cend)
2922 m.append(s)
2932 m.append(s)
2923
2933
2924 def difflinestates(a, b):
2934 def difflinestates(a, b):
2925 sm = difflib.SequenceMatcher(None, a, b)
2935 sm = difflib.SequenceMatcher(None, a, b)
2926 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2936 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2927 if tag == 'insert':
2937 if tag == 'insert':
2928 for i in xrange(blo, bhi):
2938 for i in xrange(blo, bhi):
2929 yield ('+', b[i])
2939 yield ('+', b[i])
2930 elif tag == 'delete':
2940 elif tag == 'delete':
2931 for i in xrange(alo, ahi):
2941 for i in xrange(alo, ahi):
2932 yield ('-', a[i])
2942 yield ('-', a[i])
2933 elif tag == 'replace':
2943 elif tag == 'replace':
2934 for i in xrange(alo, ahi):
2944 for i in xrange(alo, ahi):
2935 yield ('-', a[i])
2945 yield ('-', a[i])
2936 for i in xrange(blo, bhi):
2946 for i in xrange(blo, bhi):
2937 yield ('+', b[i])
2947 yield ('+', b[i])
2938
2948
2939 def display(fn, ctx, pstates, states):
2949 def display(fn, ctx, pstates, states):
2940 rev = ctx.rev()
2950 rev = ctx.rev()
2941 datefunc = ui.quiet and util.shortdate or util.datestr
2951 datefunc = ui.quiet and util.shortdate or util.datestr
2942 found = False
2952 found = False
2943 filerevmatches = {}
2953 filerevmatches = {}
2944 def binary():
2954 def binary():
2945 flog = getfile(fn)
2955 flog = getfile(fn)
2946 return util.binary(flog.read(ctx.filenode(fn)))
2956 return util.binary(flog.read(ctx.filenode(fn)))
2947
2957
2948 if opts.get('all'):
2958 if opts.get('all'):
2949 iter = difflinestates(pstates, states)
2959 iter = difflinestates(pstates, states)
2950 else:
2960 else:
2951 iter = [('', l) for l in states]
2961 iter = [('', l) for l in states]
2952 for change, l in iter:
2962 for change, l in iter:
2953 cols = [fn, str(rev)]
2963 cols = [fn, str(rev)]
2954 before, match, after = None, None, None
2964 before, match, after = None, None, None
2955 if opts.get('line_number'):
2965 if opts.get('line_number'):
2956 cols.append(str(l.linenum))
2966 cols.append(str(l.linenum))
2957 if opts.get('all'):
2967 if opts.get('all'):
2958 cols.append(change)
2968 cols.append(change)
2959 if opts.get('user'):
2969 if opts.get('user'):
2960 cols.append(ui.shortuser(ctx.user()))
2970 cols.append(ui.shortuser(ctx.user()))
2961 if opts.get('date'):
2971 if opts.get('date'):
2962 cols.append(datefunc(ctx.date()))
2972 cols.append(datefunc(ctx.date()))
2963 if opts.get('files_with_matches'):
2973 if opts.get('files_with_matches'):
2964 c = (fn, rev)
2974 c = (fn, rev)
2965 if c in filerevmatches:
2975 if c in filerevmatches:
2966 continue
2976 continue
2967 filerevmatches[c] = 1
2977 filerevmatches[c] = 1
2968 else:
2978 else:
2969 before = l.line[:l.colstart]
2979 before = l.line[:l.colstart]
2970 match = l.line[l.colstart:l.colend]
2980 match = l.line[l.colstart:l.colend]
2971 after = l.line[l.colend:]
2981 after = l.line[l.colend:]
2972 ui.write(sep.join(cols))
2982 ui.write(sep.join(cols))
2973 if before is not None:
2983 if before is not None:
2974 if not opts.get('text') and binary():
2984 if not opts.get('text') and binary():
2975 ui.write(sep + " Binary file matches")
2985 ui.write(sep + " Binary file matches")
2976 else:
2986 else:
2977 ui.write(sep + before)
2987 ui.write(sep + before)
2978 ui.write(match, label='grep.match')
2988 ui.write(match, label='grep.match')
2979 ui.write(after)
2989 ui.write(after)
2980 ui.write(eol)
2990 ui.write(eol)
2981 found = True
2991 found = True
2982 return found
2992 return found
2983
2993
2984 skip = {}
2994 skip = {}
2985 revfiles = {}
2995 revfiles = {}
2986 matchfn = scmutil.match(repo[None], pats, opts)
2996 matchfn = scmutil.match(repo[None], pats, opts)
2987 found = False
2997 found = False
2988 follow = opts.get('follow')
2998 follow = opts.get('follow')
2989
2999
2990 def prep(ctx, fns):
3000 def prep(ctx, fns):
2991 rev = ctx.rev()
3001 rev = ctx.rev()
2992 pctx = ctx.p1()
3002 pctx = ctx.p1()
2993 parent = pctx.rev()
3003 parent = pctx.rev()
2994 matches.setdefault(rev, {})
3004 matches.setdefault(rev, {})
2995 matches.setdefault(parent, {})
3005 matches.setdefault(parent, {})
2996 files = revfiles.setdefault(rev, [])
3006 files = revfiles.setdefault(rev, [])
2997 for fn in fns:
3007 for fn in fns:
2998 flog = getfile(fn)
3008 flog = getfile(fn)
2999 try:
3009 try:
3000 fnode = ctx.filenode(fn)
3010 fnode = ctx.filenode(fn)
3001 except error.LookupError:
3011 except error.LookupError:
3002 continue
3012 continue
3003
3013
3004 copied = flog.renamed(fnode)
3014 copied = flog.renamed(fnode)
3005 copy = follow and copied and copied[0]
3015 copy = follow and copied and copied[0]
3006 if copy:
3016 if copy:
3007 copies.setdefault(rev, {})[fn] = copy
3017 copies.setdefault(rev, {})[fn] = copy
3008 if fn in skip:
3018 if fn in skip:
3009 if copy:
3019 if copy:
3010 skip[copy] = True
3020 skip[copy] = True
3011 continue
3021 continue
3012 files.append(fn)
3022 files.append(fn)
3013
3023
3014 if fn not in matches[rev]:
3024 if fn not in matches[rev]:
3015 grepbody(fn, rev, flog.read(fnode))
3025 grepbody(fn, rev, flog.read(fnode))
3016
3026
3017 pfn = copy or fn
3027 pfn = copy or fn
3018 if pfn not in matches[parent]:
3028 if pfn not in matches[parent]:
3019 try:
3029 try:
3020 fnode = pctx.filenode(pfn)
3030 fnode = pctx.filenode(pfn)
3021 grepbody(pfn, parent, flog.read(fnode))
3031 grepbody(pfn, parent, flog.read(fnode))
3022 except error.LookupError:
3032 except error.LookupError:
3023 pass
3033 pass
3024
3034
3025 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3035 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3026 rev = ctx.rev()
3036 rev = ctx.rev()
3027 parent = ctx.p1().rev()
3037 parent = ctx.p1().rev()
3028 for fn in sorted(revfiles.get(rev, [])):
3038 for fn in sorted(revfiles.get(rev, [])):
3029 states = matches[rev][fn]
3039 states = matches[rev][fn]
3030 copy = copies.get(rev, {}).get(fn)
3040 copy = copies.get(rev, {}).get(fn)
3031 if fn in skip:
3041 if fn in skip:
3032 if copy:
3042 if copy:
3033 skip[copy] = True
3043 skip[copy] = True
3034 continue
3044 continue
3035 pstates = matches.get(parent, {}).get(copy or fn, [])
3045 pstates = matches.get(parent, {}).get(copy or fn, [])
3036 if pstates or states:
3046 if pstates or states:
3037 r = display(fn, ctx, pstates, states)
3047 r = display(fn, ctx, pstates, states)
3038 found = found or r
3048 found = found or r
3039 if r and not opts.get('all'):
3049 if r and not opts.get('all'):
3040 skip[fn] = True
3050 skip[fn] = True
3041 if copy:
3051 if copy:
3042 skip[copy] = True
3052 skip[copy] = True
3043 del matches[rev]
3053 del matches[rev]
3044 del revfiles[rev]
3054 del revfiles[rev]
3045
3055
3046 return not found
3056 return not found
3047
3057
3048 @command('heads',
3058 @command('heads',
3049 [('r', 'rev', '',
3059 [('r', 'rev', '',
3050 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3060 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3051 ('t', 'topo', False, _('show topological heads only')),
3061 ('t', 'topo', False, _('show topological heads only')),
3052 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3062 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3053 ('c', 'closed', False, _('show normal and closed branch heads')),
3063 ('c', 'closed', False, _('show normal and closed branch heads')),
3054 ] + templateopts,
3064 ] + templateopts,
3055 _('[-ct] [-r STARTREV] [REV]...'))
3065 _('[-ct] [-r STARTREV] [REV]...'))
3056 def heads(ui, repo, *branchrevs, **opts):
3066 def heads(ui, repo, *branchrevs, **opts):
3057 """show current repository heads or show branch heads
3067 """show current repository heads or show branch heads
3058
3068
3059 With no arguments, show all repository branch heads.
3069 With no arguments, show all repository branch heads.
3060
3070
3061 Repository "heads" are changesets with no child changesets. They are
3071 Repository "heads" are changesets with no child changesets. They are
3062 where development generally takes place and are the usual targets
3072 where development generally takes place and are the usual targets
3063 for update and merge operations. Branch heads are changesets that have
3073 for update and merge operations. Branch heads are changesets that have
3064 no child changeset on the same branch.
3074 no child changeset on the same branch.
3065
3075
3066 If one or more REVs are given, only branch heads on the branches
3076 If one or more REVs are given, only branch heads on the branches
3067 associated with the specified changesets are shown. This means
3077 associated with the specified changesets are shown. This means
3068 that you can use :hg:`heads foo` to see the heads on a branch
3078 that you can use :hg:`heads foo` to see the heads on a branch
3069 named ``foo``.
3079 named ``foo``.
3070
3080
3071 If -c/--closed is specified, also show branch heads marked closed
3081 If -c/--closed is specified, also show branch heads marked closed
3072 (see :hg:`commit --close-branch`).
3082 (see :hg:`commit --close-branch`).
3073
3083
3074 If STARTREV is specified, only those heads that are descendants of
3084 If STARTREV is specified, only those heads that are descendants of
3075 STARTREV will be displayed.
3085 STARTREV will be displayed.
3076
3086
3077 If -t/--topo is specified, named branch mechanics will be ignored and only
3087 If -t/--topo is specified, named branch mechanics will be ignored and only
3078 changesets without children will be shown.
3088 changesets without children will be shown.
3079
3089
3080 Returns 0 if matching heads are found, 1 if not.
3090 Returns 0 if matching heads are found, 1 if not.
3081 """
3091 """
3082
3092
3083 start = None
3093 start = None
3084 if 'rev' in opts:
3094 if 'rev' in opts:
3085 start = scmutil.revsingle(repo, opts['rev'], None).node()
3095 start = scmutil.revsingle(repo, opts['rev'], None).node()
3086
3096
3087 if opts.get('topo'):
3097 if opts.get('topo'):
3088 heads = [repo[h] for h in repo.heads(start)]
3098 heads = [repo[h] for h in repo.heads(start)]
3089 else:
3099 else:
3090 heads = []
3100 heads = []
3091 for branch in repo.branchmap():
3101 for branch in repo.branchmap():
3092 heads += repo.branchheads(branch, start, opts.get('closed'))
3102 heads += repo.branchheads(branch, start, opts.get('closed'))
3093 heads = [repo[h] for h in heads]
3103 heads = [repo[h] for h in heads]
3094
3104
3095 if branchrevs:
3105 if branchrevs:
3096 branches = set(repo[br].branch() for br in branchrevs)
3106 branches = set(repo[br].branch() for br in branchrevs)
3097 heads = [h for h in heads if h.branch() in branches]
3107 heads = [h for h in heads if h.branch() in branches]
3098
3108
3099 if opts.get('active') and branchrevs:
3109 if opts.get('active') and branchrevs:
3100 dagheads = repo.heads(start)
3110 dagheads = repo.heads(start)
3101 heads = [h for h in heads if h.node() in dagheads]
3111 heads = [h for h in heads if h.node() in dagheads]
3102
3112
3103 if branchrevs:
3113 if branchrevs:
3104 haveheads = set(h.branch() for h in heads)
3114 haveheads = set(h.branch() for h in heads)
3105 if branches - haveheads:
3115 if branches - haveheads:
3106 headless = ', '.join(b for b in branches - haveheads)
3116 headless = ', '.join(b for b in branches - haveheads)
3107 msg = _('no open branch heads found on branches %s')
3117 msg = _('no open branch heads found on branches %s')
3108 if opts.get('rev'):
3118 if opts.get('rev'):
3109 msg += _(' (started at %s)') % opts['rev']
3119 msg += _(' (started at %s)') % opts['rev']
3110 ui.warn((msg + '\n') % headless)
3120 ui.warn((msg + '\n') % headless)
3111
3121
3112 if not heads:
3122 if not heads:
3113 return 1
3123 return 1
3114
3124
3115 heads = sorted(heads, key=lambda x: -x.rev())
3125 heads = sorted(heads, key=lambda x: -x.rev())
3116 displayer = cmdutil.show_changeset(ui, repo, opts)
3126 displayer = cmdutil.show_changeset(ui, repo, opts)
3117 for ctx in heads:
3127 for ctx in heads:
3118 displayer.show(ctx)
3128 displayer.show(ctx)
3119 displayer.close()
3129 displayer.close()
3120
3130
3121 @command('help',
3131 @command('help',
3122 [('e', 'extension', None, _('show only help for extensions')),
3132 [('e', 'extension', None, _('show only help for extensions')),
3123 ('c', 'command', None, _('show only help for commands')),
3133 ('c', 'command', None, _('show only help for commands')),
3124 ('k', 'keyword', '', _('show topics matching keyword')),
3134 ('k', 'keyword', '', _('show topics matching keyword')),
3125 ],
3135 ],
3126 _('[-ec] [TOPIC]'))
3136 _('[-ec] [TOPIC]'))
3127 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3137 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3128 """show help for a given topic or a help overview
3138 """show help for a given topic or a help overview
3129
3139
3130 With no arguments, print a list of commands with short help messages.
3140 With no arguments, print a list of commands with short help messages.
3131
3141
3132 Given a topic, extension, or command name, print help for that
3142 Given a topic, extension, or command name, print help for that
3133 topic.
3143 topic.
3134
3144
3135 Returns 0 if successful.
3145 Returns 0 if successful.
3136 """
3146 """
3137
3147
3138 textwidth = min(ui.termwidth(), 80) - 2
3148 textwidth = min(ui.termwidth(), 80) - 2
3139
3149
3140 def helpcmd(name):
3150 def helpcmd(name):
3141 try:
3151 try:
3142 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3152 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3143 except error.AmbiguousCommand, inst:
3153 except error.AmbiguousCommand, inst:
3144 # py3k fix: except vars can't be used outside the scope of the
3154 # py3k fix: except vars can't be used outside the scope of the
3145 # except block, nor can be used inside a lambda. python issue4617
3155 # except block, nor can be used inside a lambda. python issue4617
3146 prefix = inst.args[0]
3156 prefix = inst.args[0]
3147 select = lambda c: c.lstrip('^').startswith(prefix)
3157 select = lambda c: c.lstrip('^').startswith(prefix)
3148 rst = helplist(select)
3158 rst = helplist(select)
3149 return rst
3159 return rst
3150
3160
3151 rst = []
3161 rst = []
3152
3162
3153 # check if it's an invalid alias and display its error if it is
3163 # check if it's an invalid alias and display its error if it is
3154 if getattr(entry[0], 'badalias', False):
3164 if getattr(entry[0], 'badalias', False):
3155 if not unknowncmd:
3165 if not unknowncmd:
3156 ui.pushbuffer()
3166 ui.pushbuffer()
3157 entry[0](ui)
3167 entry[0](ui)
3158 rst.append(ui.popbuffer())
3168 rst.append(ui.popbuffer())
3159 return rst
3169 return rst
3160
3170
3161 # synopsis
3171 # synopsis
3162 if len(entry) > 2:
3172 if len(entry) > 2:
3163 if entry[2].startswith('hg'):
3173 if entry[2].startswith('hg'):
3164 rst.append("%s\n" % entry[2])
3174 rst.append("%s\n" % entry[2])
3165 else:
3175 else:
3166 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3176 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3167 else:
3177 else:
3168 rst.append('hg %s\n' % aliases[0])
3178 rst.append('hg %s\n' % aliases[0])
3169 # aliases
3179 # aliases
3170 if full and not ui.quiet and len(aliases) > 1:
3180 if full and not ui.quiet and len(aliases) > 1:
3171 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3181 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3172 rst.append('\n')
3182 rst.append('\n')
3173
3183
3174 # description
3184 # description
3175 doc = gettext(entry[0].__doc__)
3185 doc = gettext(entry[0].__doc__)
3176 if not doc:
3186 if not doc:
3177 doc = _("(no help text available)")
3187 doc = _("(no help text available)")
3178 if util.safehasattr(entry[0], 'definition'): # aliased command
3188 if util.safehasattr(entry[0], 'definition'): # aliased command
3179 if entry[0].definition.startswith('!'): # shell alias
3189 if entry[0].definition.startswith('!'): # shell alias
3180 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3190 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3181 else:
3191 else:
3182 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3192 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3183 doc = doc.splitlines(True)
3193 doc = doc.splitlines(True)
3184 if ui.quiet or not full:
3194 if ui.quiet or not full:
3185 rst.append(doc[0])
3195 rst.append(doc[0])
3186 else:
3196 else:
3187 rst.extend(doc)
3197 rst.extend(doc)
3188 rst.append('\n')
3198 rst.append('\n')
3189
3199
3190 # check if this command shadows a non-trivial (multi-line)
3200 # check if this command shadows a non-trivial (multi-line)
3191 # extension help text
3201 # extension help text
3192 try:
3202 try:
3193 mod = extensions.find(name)
3203 mod = extensions.find(name)
3194 doc = gettext(mod.__doc__) or ''
3204 doc = gettext(mod.__doc__) or ''
3195 if '\n' in doc.strip():
3205 if '\n' in doc.strip():
3196 msg = _('use "hg help -e %s" to show help for '
3206 msg = _('use "hg help -e %s" to show help for '
3197 'the %s extension') % (name, name)
3207 'the %s extension') % (name, name)
3198 rst.append('\n%s\n' % msg)
3208 rst.append('\n%s\n' % msg)
3199 except KeyError:
3209 except KeyError:
3200 pass
3210 pass
3201
3211
3202 # options
3212 # options
3203 if not ui.quiet and entry[1]:
3213 if not ui.quiet and entry[1]:
3204 rst.append('\n%s\n\n' % _("options:"))
3214 rst.append('\n%s\n\n' % _("options:"))
3205 rst.append(help.optrst(entry[1], ui.verbose))
3215 rst.append(help.optrst(entry[1], ui.verbose))
3206
3216
3207 if ui.verbose:
3217 if ui.verbose:
3208 rst.append('\n%s\n\n' % _("global options:"))
3218 rst.append('\n%s\n\n' % _("global options:"))
3209 rst.append(help.optrst(globalopts, ui.verbose))
3219 rst.append(help.optrst(globalopts, ui.verbose))
3210
3220
3211 if not ui.verbose:
3221 if not ui.verbose:
3212 if not full:
3222 if not full:
3213 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3223 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3214 % name)
3224 % name)
3215 elif not ui.quiet:
3225 elif not ui.quiet:
3216 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3226 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3217 % name)
3227 % name)
3218 return rst
3228 return rst
3219
3229
3220
3230
3221 def helplist(select=None):
3231 def helplist(select=None):
3222 # list of commands
3232 # list of commands
3223 if name == "shortlist":
3233 if name == "shortlist":
3224 header = _('basic commands:\n\n')
3234 header = _('basic commands:\n\n')
3225 else:
3235 else:
3226 header = _('list of commands:\n\n')
3236 header = _('list of commands:\n\n')
3227
3237
3228 h = {}
3238 h = {}
3229 cmds = {}
3239 cmds = {}
3230 for c, e in table.iteritems():
3240 for c, e in table.iteritems():
3231 f = c.split("|", 1)[0]
3241 f = c.split("|", 1)[0]
3232 if select and not select(f):
3242 if select and not select(f):
3233 continue
3243 continue
3234 if (not select and name != 'shortlist' and
3244 if (not select and name != 'shortlist' and
3235 e[0].__module__ != __name__):
3245 e[0].__module__ != __name__):
3236 continue
3246 continue
3237 if name == "shortlist" and not f.startswith("^"):
3247 if name == "shortlist" and not f.startswith("^"):
3238 continue
3248 continue
3239 f = f.lstrip("^")
3249 f = f.lstrip("^")
3240 if not ui.debugflag and f.startswith("debug"):
3250 if not ui.debugflag and f.startswith("debug"):
3241 continue
3251 continue
3242 doc = e[0].__doc__
3252 doc = e[0].__doc__
3243 if doc and 'DEPRECATED' in doc and not ui.verbose:
3253 if doc and 'DEPRECATED' in doc and not ui.verbose:
3244 continue
3254 continue
3245 doc = gettext(doc)
3255 doc = gettext(doc)
3246 if not doc:
3256 if not doc:
3247 doc = _("(no help text available)")
3257 doc = _("(no help text available)")
3248 h[f] = doc.splitlines()[0].rstrip()
3258 h[f] = doc.splitlines()[0].rstrip()
3249 cmds[f] = c.lstrip("^")
3259 cmds[f] = c.lstrip("^")
3250
3260
3251 rst = []
3261 rst = []
3252 if not h:
3262 if not h:
3253 if not ui.quiet:
3263 if not ui.quiet:
3254 rst.append(_('no commands defined\n'))
3264 rst.append(_('no commands defined\n'))
3255 return rst
3265 return rst
3256
3266
3257 if not ui.quiet:
3267 if not ui.quiet:
3258 rst.append(header)
3268 rst.append(header)
3259 fns = sorted(h)
3269 fns = sorted(h)
3260 for f in fns:
3270 for f in fns:
3261 if ui.verbose:
3271 if ui.verbose:
3262 commands = cmds[f].replace("|",", ")
3272 commands = cmds[f].replace("|",", ")
3263 rst.append(" :%s: %s\n" % (commands, h[f]))
3273 rst.append(" :%s: %s\n" % (commands, h[f]))
3264 else:
3274 else:
3265 rst.append(' :%s: %s\n' % (f, h[f]))
3275 rst.append(' :%s: %s\n' % (f, h[f]))
3266
3276
3267 if not name:
3277 if not name:
3268 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3278 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3269 if exts:
3279 if exts:
3270 rst.append('\n')
3280 rst.append('\n')
3271 rst.extend(exts)
3281 rst.extend(exts)
3272
3282
3273 rst.append(_("\nadditional help topics:\n\n"))
3283 rst.append(_("\nadditional help topics:\n\n"))
3274 topics = []
3284 topics = []
3275 for names, header, doc in help.helptable:
3285 for names, header, doc in help.helptable:
3276 topics.append((sorted(names, key=len, reverse=True)[0], header))
3286 topics.append((sorted(names, key=len, reverse=True)[0], header))
3277 for t, desc in topics:
3287 for t, desc in topics:
3278 rst.append(" :%s: %s\n" % (t, desc))
3288 rst.append(" :%s: %s\n" % (t, desc))
3279
3289
3280 optlist = []
3290 optlist = []
3281 if not ui.quiet:
3291 if not ui.quiet:
3282 if ui.verbose:
3292 if ui.verbose:
3283 optlist.append((_("global options:"), globalopts))
3293 optlist.append((_("global options:"), globalopts))
3284 if name == 'shortlist':
3294 if name == 'shortlist':
3285 optlist.append((_('use "hg help" for the full list '
3295 optlist.append((_('use "hg help" for the full list '
3286 'of commands'), ()))
3296 'of commands'), ()))
3287 else:
3297 else:
3288 if name == 'shortlist':
3298 if name == 'shortlist':
3289 msg = _('use "hg help" for the full list of commands '
3299 msg = _('use "hg help" for the full list of commands '
3290 'or "hg -v" for details')
3300 'or "hg -v" for details')
3291 elif name and not full:
3301 elif name and not full:
3292 msg = _('use "hg help %s" to show the full help '
3302 msg = _('use "hg help %s" to show the full help '
3293 'text') % name
3303 'text') % name
3294 else:
3304 else:
3295 msg = _('use "hg -v help%s" to show builtin aliases and '
3305 msg = _('use "hg -v help%s" to show builtin aliases and '
3296 'global options') % (name and " " + name or "")
3306 'global options') % (name and " " + name or "")
3297 optlist.append((msg, ()))
3307 optlist.append((msg, ()))
3298
3308
3299 if optlist:
3309 if optlist:
3300 for title, options in optlist:
3310 for title, options in optlist:
3301 rst.append('\n%s\n' % title)
3311 rst.append('\n%s\n' % title)
3302 if options:
3312 if options:
3303 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3313 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3304 return rst
3314 return rst
3305
3315
3306 def helptopic(name):
3316 def helptopic(name):
3307 for names, header, doc in help.helptable:
3317 for names, header, doc in help.helptable:
3308 if name in names:
3318 if name in names:
3309 break
3319 break
3310 else:
3320 else:
3311 raise error.UnknownCommand(name)
3321 raise error.UnknownCommand(name)
3312
3322
3313 rst = ["%s\n\n" % header]
3323 rst = ["%s\n\n" % header]
3314 # description
3324 # description
3315 if not doc:
3325 if not doc:
3316 rst.append(" %s\n" % _("(no help text available)"))
3326 rst.append(" %s\n" % _("(no help text available)"))
3317 if util.safehasattr(doc, '__call__'):
3327 if util.safehasattr(doc, '__call__'):
3318 rst += [" %s\n" % l for l in doc().splitlines()]
3328 rst += [" %s\n" % l for l in doc().splitlines()]
3319
3329
3320 try:
3330 try:
3321 cmdutil.findcmd(name, table)
3331 cmdutil.findcmd(name, table)
3322 rst.append(_('\nuse "hg help -c %s" to see help for '
3332 rst.append(_('\nuse "hg help -c %s" to see help for '
3323 'the %s command\n') % (name, name))
3333 'the %s command\n') % (name, name))
3324 except error.UnknownCommand:
3334 except error.UnknownCommand:
3325 pass
3335 pass
3326 return rst
3336 return rst
3327
3337
3328 def helpext(name):
3338 def helpext(name):
3329 try:
3339 try:
3330 mod = extensions.find(name)
3340 mod = extensions.find(name)
3331 doc = gettext(mod.__doc__) or _('no help text available')
3341 doc = gettext(mod.__doc__) or _('no help text available')
3332 except KeyError:
3342 except KeyError:
3333 mod = None
3343 mod = None
3334 doc = extensions.disabledext(name)
3344 doc = extensions.disabledext(name)
3335 if not doc:
3345 if not doc:
3336 raise error.UnknownCommand(name)
3346 raise error.UnknownCommand(name)
3337
3347
3338 if '\n' not in doc:
3348 if '\n' not in doc:
3339 head, tail = doc, ""
3349 head, tail = doc, ""
3340 else:
3350 else:
3341 head, tail = doc.split('\n', 1)
3351 head, tail = doc.split('\n', 1)
3342 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3352 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3343 if tail:
3353 if tail:
3344 rst.extend(tail.splitlines(True))
3354 rst.extend(tail.splitlines(True))
3345 rst.append('\n')
3355 rst.append('\n')
3346
3356
3347 if mod:
3357 if mod:
3348 try:
3358 try:
3349 ct = mod.cmdtable
3359 ct = mod.cmdtable
3350 except AttributeError:
3360 except AttributeError:
3351 ct = {}
3361 ct = {}
3352 modcmds = set([c.split('|', 1)[0] for c in ct])
3362 modcmds = set([c.split('|', 1)[0] for c in ct])
3353 rst.extend(helplist(modcmds.__contains__))
3363 rst.extend(helplist(modcmds.__contains__))
3354 else:
3364 else:
3355 rst.append(_('use "hg help extensions" for information on enabling '
3365 rst.append(_('use "hg help extensions" for information on enabling '
3356 'extensions\n'))
3366 'extensions\n'))
3357 return rst
3367 return rst
3358
3368
3359 def helpextcmd(name):
3369 def helpextcmd(name):
3360 cmd, ext, mod = extensions.disabledcmd(ui, name,
3370 cmd, ext, mod = extensions.disabledcmd(ui, name,
3361 ui.configbool('ui', 'strict'))
3371 ui.configbool('ui', 'strict'))
3362 doc = gettext(mod.__doc__).splitlines()[0]
3372 doc = gettext(mod.__doc__).splitlines()[0]
3363
3373
3364 rst = help.listexts(_("'%s' is provided by the following "
3374 rst = help.listexts(_("'%s' is provided by the following "
3365 "extension:") % cmd, {ext: doc}, indent=4)
3375 "extension:") % cmd, {ext: doc}, indent=4)
3366 rst.append('\n')
3376 rst.append('\n')
3367 rst.append(_('use "hg help extensions" for information on enabling '
3377 rst.append(_('use "hg help extensions" for information on enabling '
3368 'extensions\n'))
3378 'extensions\n'))
3369 return rst
3379 return rst
3370
3380
3371
3381
3372 rst = []
3382 rst = []
3373 kw = opts.get('keyword')
3383 kw = opts.get('keyword')
3374 if kw:
3384 if kw:
3375 matches = help.topicmatch(kw)
3385 matches = help.topicmatch(kw)
3376 for t, title in (('topics', _('Topics')),
3386 for t, title in (('topics', _('Topics')),
3377 ('commands', _('Commands')),
3387 ('commands', _('Commands')),
3378 ('extensions', _('Extensions')),
3388 ('extensions', _('Extensions')),
3379 ('extensioncommands', _('Extension Commands'))):
3389 ('extensioncommands', _('Extension Commands'))):
3380 if matches[t]:
3390 if matches[t]:
3381 rst.append('%s:\n\n' % title)
3391 rst.append('%s:\n\n' % title)
3382 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3392 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3383 rst.append('\n')
3393 rst.append('\n')
3384 elif name and name != 'shortlist':
3394 elif name and name != 'shortlist':
3385 i = None
3395 i = None
3386 if unknowncmd:
3396 if unknowncmd:
3387 queries = (helpextcmd,)
3397 queries = (helpextcmd,)
3388 elif opts.get('extension'):
3398 elif opts.get('extension'):
3389 queries = (helpext,)
3399 queries = (helpext,)
3390 elif opts.get('command'):
3400 elif opts.get('command'):
3391 queries = (helpcmd,)
3401 queries = (helpcmd,)
3392 else:
3402 else:
3393 queries = (helptopic, helpcmd, helpext, helpextcmd)
3403 queries = (helptopic, helpcmd, helpext, helpextcmd)
3394 for f in queries:
3404 for f in queries:
3395 try:
3405 try:
3396 rst = f(name)
3406 rst = f(name)
3397 i = None
3407 i = None
3398 break
3408 break
3399 except error.UnknownCommand, inst:
3409 except error.UnknownCommand, inst:
3400 i = inst
3410 i = inst
3401 if i:
3411 if i:
3402 raise i
3412 raise i
3403 else:
3413 else:
3404 # program name
3414 # program name
3405 if not ui.quiet:
3415 if not ui.quiet:
3406 rst = [_("Mercurial Distributed SCM\n"), '\n']
3416 rst = [_("Mercurial Distributed SCM\n"), '\n']
3407 rst.extend(helplist())
3417 rst.extend(helplist())
3408
3418
3409 keep = ui.verbose and ['verbose'] or []
3419 keep = ui.verbose and ['verbose'] or []
3410 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3420 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3411 ui.write(formatted)
3421 ui.write(formatted)
3412
3422
3413
3423
3414 @command('identify|id',
3424 @command('identify|id',
3415 [('r', 'rev', '',
3425 [('r', 'rev', '',
3416 _('identify the specified revision'), _('REV')),
3426 _('identify the specified revision'), _('REV')),
3417 ('n', 'num', None, _('show local revision number')),
3427 ('n', 'num', None, _('show local revision number')),
3418 ('i', 'id', None, _('show global revision id')),
3428 ('i', 'id', None, _('show global revision id')),
3419 ('b', 'branch', None, _('show branch')),
3429 ('b', 'branch', None, _('show branch')),
3420 ('t', 'tags', None, _('show tags')),
3430 ('t', 'tags', None, _('show tags')),
3421 ('B', 'bookmarks', None, _('show bookmarks')),
3431 ('B', 'bookmarks', None, _('show bookmarks')),
3422 ] + remoteopts,
3432 ] + remoteopts,
3423 _('[-nibtB] [-r REV] [SOURCE]'))
3433 _('[-nibtB] [-r REV] [SOURCE]'))
3424 def identify(ui, repo, source=None, rev=None,
3434 def identify(ui, repo, source=None, rev=None,
3425 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3435 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3426 """identify the working copy or specified revision
3436 """identify the working copy or specified revision
3427
3437
3428 Print a summary identifying the repository state at REV using one or
3438 Print a summary identifying the repository state at REV using one or
3429 two parent hash identifiers, followed by a "+" if the working
3439 two parent hash identifiers, followed by a "+" if the working
3430 directory has uncommitted changes, the branch name (if not default),
3440 directory has uncommitted changes, the branch name (if not default),
3431 a list of tags, and a list of bookmarks.
3441 a list of tags, and a list of bookmarks.
3432
3442
3433 When REV is not given, print a summary of the current state of the
3443 When REV is not given, print a summary of the current state of the
3434 repository.
3444 repository.
3435
3445
3436 Specifying a path to a repository root or Mercurial bundle will
3446 Specifying a path to a repository root or Mercurial bundle will
3437 cause lookup to operate on that repository/bundle.
3447 cause lookup to operate on that repository/bundle.
3438
3448
3439 .. container:: verbose
3449 .. container:: verbose
3440
3450
3441 Examples:
3451 Examples:
3442
3452
3443 - generate a build identifier for the working directory::
3453 - generate a build identifier for the working directory::
3444
3454
3445 hg id --id > build-id.dat
3455 hg id --id > build-id.dat
3446
3456
3447 - find the revision corresponding to a tag::
3457 - find the revision corresponding to a tag::
3448
3458
3449 hg id -n -r 1.3
3459 hg id -n -r 1.3
3450
3460
3451 - check the most recent revision of a remote repository::
3461 - check the most recent revision of a remote repository::
3452
3462
3453 hg id -r tip http://selenic.com/hg/
3463 hg id -r tip http://selenic.com/hg/
3454
3464
3455 Returns 0 if successful.
3465 Returns 0 if successful.
3456 """
3466 """
3457
3467
3458 if not repo and not source:
3468 if not repo and not source:
3459 raise util.Abort(_("there is no Mercurial repository here "
3469 raise util.Abort(_("there is no Mercurial repository here "
3460 "(.hg not found)"))
3470 "(.hg not found)"))
3461
3471
3462 hexfunc = ui.debugflag and hex or short
3472 hexfunc = ui.debugflag and hex or short
3463 default = not (num or id or branch or tags or bookmarks)
3473 default = not (num or id or branch or tags or bookmarks)
3464 output = []
3474 output = []
3465 revs = []
3475 revs = []
3466
3476
3467 if source:
3477 if source:
3468 source, branches = hg.parseurl(ui.expandpath(source))
3478 source, branches = hg.parseurl(ui.expandpath(source))
3469 peer = hg.peer(ui, opts, source)
3479 peer = hg.peer(ui, opts, source)
3470 repo = peer.local()
3480 repo = peer.local()
3471 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3481 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3472
3482
3473 if not repo:
3483 if not repo:
3474 if num or branch or tags:
3484 if num or branch or tags:
3475 raise util.Abort(
3485 raise util.Abort(
3476 _("can't query remote revision number, branch, or tags"))
3486 _("can't query remote revision number, branch, or tags"))
3477 if not rev and revs:
3487 if not rev and revs:
3478 rev = revs[0]
3488 rev = revs[0]
3479 if not rev:
3489 if not rev:
3480 rev = "tip"
3490 rev = "tip"
3481
3491
3482 remoterev = peer.lookup(rev)
3492 remoterev = peer.lookup(rev)
3483 if default or id:
3493 if default or id:
3484 output = [hexfunc(remoterev)]
3494 output = [hexfunc(remoterev)]
3485
3495
3486 def getbms():
3496 def getbms():
3487 bms = []
3497 bms = []
3488
3498
3489 if 'bookmarks' in peer.listkeys('namespaces'):
3499 if 'bookmarks' in peer.listkeys('namespaces'):
3490 hexremoterev = hex(remoterev)
3500 hexremoterev = hex(remoterev)
3491 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3501 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3492 if bmr == hexremoterev]
3502 if bmr == hexremoterev]
3493
3503
3494 return bms
3504 return bms
3495
3505
3496 if bookmarks:
3506 if bookmarks:
3497 output.extend(getbms())
3507 output.extend(getbms())
3498 elif default and not ui.quiet:
3508 elif default and not ui.quiet:
3499 # multiple bookmarks for a single parent separated by '/'
3509 # multiple bookmarks for a single parent separated by '/'
3500 bm = '/'.join(getbms())
3510 bm = '/'.join(getbms())
3501 if bm:
3511 if bm:
3502 output.append(bm)
3512 output.append(bm)
3503 else:
3513 else:
3504 if not rev:
3514 if not rev:
3505 ctx = repo[None]
3515 ctx = repo[None]
3506 parents = ctx.parents()
3516 parents = ctx.parents()
3507 changed = ""
3517 changed = ""
3508 if default or id or num:
3518 if default or id or num:
3509 if (util.any(repo.status())
3519 if (util.any(repo.status())
3510 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3520 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3511 changed = '+'
3521 changed = '+'
3512 if default or id:
3522 if default or id:
3513 output = ["%s%s" %
3523 output = ["%s%s" %
3514 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3524 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3515 if num:
3525 if num:
3516 output.append("%s%s" %
3526 output.append("%s%s" %
3517 ('+'.join([str(p.rev()) for p in parents]), changed))
3527 ('+'.join([str(p.rev()) for p in parents]), changed))
3518 else:
3528 else:
3519 ctx = scmutil.revsingle(repo, rev)
3529 ctx = scmutil.revsingle(repo, rev)
3520 if default or id:
3530 if default or id:
3521 output = [hexfunc(ctx.node())]
3531 output = [hexfunc(ctx.node())]
3522 if num:
3532 if num:
3523 output.append(str(ctx.rev()))
3533 output.append(str(ctx.rev()))
3524
3534
3525 if default and not ui.quiet:
3535 if default and not ui.quiet:
3526 b = ctx.branch()
3536 b = ctx.branch()
3527 if b != 'default':
3537 if b != 'default':
3528 output.append("(%s)" % b)
3538 output.append("(%s)" % b)
3529
3539
3530 # multiple tags for a single parent separated by '/'
3540 # multiple tags for a single parent separated by '/'
3531 t = '/'.join(ctx.tags())
3541 t = '/'.join(ctx.tags())
3532 if t:
3542 if t:
3533 output.append(t)
3543 output.append(t)
3534
3544
3535 # multiple bookmarks for a single parent separated by '/'
3545 # multiple bookmarks for a single parent separated by '/'
3536 bm = '/'.join(ctx.bookmarks())
3546 bm = '/'.join(ctx.bookmarks())
3537 if bm:
3547 if bm:
3538 output.append(bm)
3548 output.append(bm)
3539 else:
3549 else:
3540 if branch:
3550 if branch:
3541 output.append(ctx.branch())
3551 output.append(ctx.branch())
3542
3552
3543 if tags:
3553 if tags:
3544 output.extend(ctx.tags())
3554 output.extend(ctx.tags())
3545
3555
3546 if bookmarks:
3556 if bookmarks:
3547 output.extend(ctx.bookmarks())
3557 output.extend(ctx.bookmarks())
3548
3558
3549 ui.write("%s\n" % ' '.join(output))
3559 ui.write("%s\n" % ' '.join(output))
3550
3560
3551 @command('import|patch',
3561 @command('import|patch',
3552 [('p', 'strip', 1,
3562 [('p', 'strip', 1,
3553 _('directory strip option for patch. This has the same '
3563 _('directory strip option for patch. This has the same '
3554 'meaning as the corresponding patch option'), _('NUM')),
3564 'meaning as the corresponding patch option'), _('NUM')),
3555 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3565 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3556 ('e', 'edit', False, _('invoke editor on commit messages')),
3566 ('e', 'edit', False, _('invoke editor on commit messages')),
3557 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3567 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3558 ('', 'no-commit', None,
3568 ('', 'no-commit', None,
3559 _("don't commit, just update the working directory")),
3569 _("don't commit, just update the working directory")),
3560 ('', 'bypass', None,
3570 ('', 'bypass', None,
3561 _("apply patch without touching the working directory")),
3571 _("apply patch without touching the working directory")),
3562 ('', 'exact', None,
3572 ('', 'exact', None,
3563 _('apply patch to the nodes from which it was generated')),
3573 _('apply patch to the nodes from which it was generated')),
3564 ('', 'import-branch', None,
3574 ('', 'import-branch', None,
3565 _('use any branch information in patch (implied by --exact)'))] +
3575 _('use any branch information in patch (implied by --exact)'))] +
3566 commitopts + commitopts2 + similarityopts,
3576 commitopts + commitopts2 + similarityopts,
3567 _('[OPTION]... PATCH...'))
3577 _('[OPTION]... PATCH...'))
3568 def import_(ui, repo, patch1=None, *patches, **opts):
3578 def import_(ui, repo, patch1=None, *patches, **opts):
3569 """import an ordered set of patches
3579 """import an ordered set of patches
3570
3580
3571 Import a list of patches and commit them individually (unless
3581 Import a list of patches and commit them individually (unless
3572 --no-commit is specified).
3582 --no-commit is specified).
3573
3583
3574 If there are outstanding changes in the working directory, import
3584 If there are outstanding changes in the working directory, import
3575 will abort unless given the -f/--force flag.
3585 will abort unless given the -f/--force flag.
3576
3586
3577 You can import a patch straight from a mail message. Even patches
3587 You can import a patch straight from a mail message. Even patches
3578 as attachments work (to use the body part, it must have type
3588 as attachments work (to use the body part, it must have type
3579 text/plain or text/x-patch). From and Subject headers of email
3589 text/plain or text/x-patch). From and Subject headers of email
3580 message are used as default committer and commit message. All
3590 message are used as default committer and commit message. All
3581 text/plain body parts before first diff are added to commit
3591 text/plain body parts before first diff are added to commit
3582 message.
3592 message.
3583
3593
3584 If the imported patch was generated by :hg:`export`, user and
3594 If the imported patch was generated by :hg:`export`, user and
3585 description from patch override values from message headers and
3595 description from patch override values from message headers and
3586 body. Values given on command line with -m/--message and -u/--user
3596 body. Values given on command line with -m/--message and -u/--user
3587 override these.
3597 override these.
3588
3598
3589 If --exact is specified, import will set the working directory to
3599 If --exact is specified, import will set the working directory to
3590 the parent of each patch before applying it, and will abort if the
3600 the parent of each patch before applying it, and will abort if the
3591 resulting changeset has a different ID than the one recorded in
3601 resulting changeset has a different ID than the one recorded in
3592 the patch. This may happen due to character set problems or other
3602 the patch. This may happen due to character set problems or other
3593 deficiencies in the text patch format.
3603 deficiencies in the text patch format.
3594
3604
3595 Use --bypass to apply and commit patches directly to the
3605 Use --bypass to apply and commit patches directly to the
3596 repository, not touching the working directory. Without --exact,
3606 repository, not touching the working directory. Without --exact,
3597 patches will be applied on top of the working directory parent
3607 patches will be applied on top of the working directory parent
3598 revision.
3608 revision.
3599
3609
3600 With -s/--similarity, hg will attempt to discover renames and
3610 With -s/--similarity, hg will attempt to discover renames and
3601 copies in the patch in the same way as :hg:`addremove`.
3611 copies in the patch in the same way as :hg:`addremove`.
3602
3612
3603 To read a patch from standard input, use "-" as the patch name. If
3613 To read a patch from standard input, use "-" as the patch name. If
3604 a URL is specified, the patch will be downloaded from it.
3614 a URL is specified, the patch will be downloaded from it.
3605 See :hg:`help dates` for a list of formats valid for -d/--date.
3615 See :hg:`help dates` for a list of formats valid for -d/--date.
3606
3616
3607 .. container:: verbose
3617 .. container:: verbose
3608
3618
3609 Examples:
3619 Examples:
3610
3620
3611 - import a traditional patch from a website and detect renames::
3621 - import a traditional patch from a website and detect renames::
3612
3622
3613 hg import -s 80 http://example.com/bugfix.patch
3623 hg import -s 80 http://example.com/bugfix.patch
3614
3624
3615 - import a changeset from an hgweb server::
3625 - import a changeset from an hgweb server::
3616
3626
3617 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3627 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3618
3628
3619 - import all the patches in an Unix-style mbox::
3629 - import all the patches in an Unix-style mbox::
3620
3630
3621 hg import incoming-patches.mbox
3631 hg import incoming-patches.mbox
3622
3632
3623 - attempt to exactly restore an exported changeset (not always
3633 - attempt to exactly restore an exported changeset (not always
3624 possible)::
3634 possible)::
3625
3635
3626 hg import --exact proposed-fix.patch
3636 hg import --exact proposed-fix.patch
3627
3637
3628 Returns 0 on success.
3638 Returns 0 on success.
3629 """
3639 """
3630
3640
3631 if not patch1:
3641 if not patch1:
3632 raise util.Abort(_('need at least one patch to import'))
3642 raise util.Abort(_('need at least one patch to import'))
3633
3643
3634 patches = (patch1,) + patches
3644 patches = (patch1,) + patches
3635
3645
3636 date = opts.get('date')
3646 date = opts.get('date')
3637 if date:
3647 if date:
3638 opts['date'] = util.parsedate(date)
3648 opts['date'] = util.parsedate(date)
3639
3649
3640 editor = cmdutil.commiteditor
3650 editor = cmdutil.commiteditor
3641 if opts.get('edit'):
3651 if opts.get('edit'):
3642 editor = cmdutil.commitforceeditor
3652 editor = cmdutil.commitforceeditor
3643
3653
3644 update = not opts.get('bypass')
3654 update = not opts.get('bypass')
3645 if not update and opts.get('no_commit'):
3655 if not update and opts.get('no_commit'):
3646 raise util.Abort(_('cannot use --no-commit with --bypass'))
3656 raise util.Abort(_('cannot use --no-commit with --bypass'))
3647 try:
3657 try:
3648 sim = float(opts.get('similarity') or 0)
3658 sim = float(opts.get('similarity') or 0)
3649 except ValueError:
3659 except ValueError:
3650 raise util.Abort(_('similarity must be a number'))
3660 raise util.Abort(_('similarity must be a number'))
3651 if sim < 0 or sim > 100:
3661 if sim < 0 or sim > 100:
3652 raise util.Abort(_('similarity must be between 0 and 100'))
3662 raise util.Abort(_('similarity must be between 0 and 100'))
3653 if sim and not update:
3663 if sim and not update:
3654 raise util.Abort(_('cannot use --similarity with --bypass'))
3664 raise util.Abort(_('cannot use --similarity with --bypass'))
3655
3665
3656 if (opts.get('exact') or not opts.get('force')) and update:
3666 if (opts.get('exact') or not opts.get('force')) and update:
3657 cmdutil.bailifchanged(repo)
3667 cmdutil.bailifchanged(repo)
3658
3668
3659 base = opts["base"]
3669 base = opts["base"]
3660 strip = opts["strip"]
3670 strip = opts["strip"]
3661 wlock = lock = tr = None
3671 wlock = lock = tr = None
3662 msgs = []
3672 msgs = []
3663
3673
3664 def checkexact(repo, n, nodeid):
3674 def checkexact(repo, n, nodeid):
3665 if opts.get('exact') and hex(n) != nodeid:
3675 if opts.get('exact') and hex(n) != nodeid:
3666 repo.rollback()
3676 repo.rollback()
3667 raise util.Abort(_('patch is damaged or loses information'))
3677 raise util.Abort(_('patch is damaged or loses information'))
3668
3678
3669 def tryone(ui, hunk, parents):
3679 def tryone(ui, hunk, parents):
3670 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3680 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3671 patch.extract(ui, hunk)
3681 patch.extract(ui, hunk)
3672
3682
3673 if not tmpname:
3683 if not tmpname:
3674 return (None, None)
3684 return (None, None)
3675 msg = _('applied to working directory')
3685 msg = _('applied to working directory')
3676
3686
3677 try:
3687 try:
3678 cmdline_message = cmdutil.logmessage(ui, opts)
3688 cmdline_message = cmdutil.logmessage(ui, opts)
3679 if cmdline_message:
3689 if cmdline_message:
3680 # pickup the cmdline msg
3690 # pickup the cmdline msg
3681 message = cmdline_message
3691 message = cmdline_message
3682 elif message:
3692 elif message:
3683 # pickup the patch msg
3693 # pickup the patch msg
3684 message = message.strip()
3694 message = message.strip()
3685 else:
3695 else:
3686 # launch the editor
3696 # launch the editor
3687 message = None
3697 message = None
3688 ui.debug('message:\n%s\n' % message)
3698 ui.debug('message:\n%s\n' % message)
3689
3699
3690 if len(parents) == 1:
3700 if len(parents) == 1:
3691 parents.append(repo[nullid])
3701 parents.append(repo[nullid])
3692 if opts.get('exact'):
3702 if opts.get('exact'):
3693 if not nodeid or not p1:
3703 if not nodeid or not p1:
3694 raise util.Abort(_('not a Mercurial patch'))
3704 raise util.Abort(_('not a Mercurial patch'))
3695 p1 = repo[p1]
3705 p1 = repo[p1]
3696 p2 = repo[p2 or nullid]
3706 p2 = repo[p2 or nullid]
3697 elif p2:
3707 elif p2:
3698 try:
3708 try:
3699 p1 = repo[p1]
3709 p1 = repo[p1]
3700 p2 = repo[p2]
3710 p2 = repo[p2]
3701 # Without any options, consider p2 only if the
3711 # Without any options, consider p2 only if the
3702 # patch is being applied on top of the recorded
3712 # patch is being applied on top of the recorded
3703 # first parent.
3713 # first parent.
3704 if p1 != parents[0]:
3714 if p1 != parents[0]:
3705 p1 = parents[0]
3715 p1 = parents[0]
3706 p2 = repo[nullid]
3716 p2 = repo[nullid]
3707 except error.RepoError:
3717 except error.RepoError:
3708 p1, p2 = parents
3718 p1, p2 = parents
3709 else:
3719 else:
3710 p1, p2 = parents
3720 p1, p2 = parents
3711
3721
3712 n = None
3722 n = None
3713 if update:
3723 if update:
3714 if p1 != parents[0]:
3724 if p1 != parents[0]:
3715 hg.clean(repo, p1.node())
3725 hg.clean(repo, p1.node())
3716 if p2 != parents[1]:
3726 if p2 != parents[1]:
3717 repo.setparents(p1.node(), p2.node())
3727 repo.setparents(p1.node(), p2.node())
3718
3728
3719 if opts.get('exact') or opts.get('import_branch'):
3729 if opts.get('exact') or opts.get('import_branch'):
3720 repo.dirstate.setbranch(branch or 'default')
3730 repo.dirstate.setbranch(branch or 'default')
3721
3731
3722 files = set()
3732 files = set()
3723 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3733 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3724 eolmode=None, similarity=sim / 100.0)
3734 eolmode=None, similarity=sim / 100.0)
3725 files = list(files)
3735 files = list(files)
3726 if opts.get('no_commit'):
3736 if opts.get('no_commit'):
3727 if message:
3737 if message:
3728 msgs.append(message)
3738 msgs.append(message)
3729 else:
3739 else:
3730 if opts.get('exact') or p2:
3740 if opts.get('exact') or p2:
3731 # If you got here, you either use --force and know what
3741 # If you got here, you either use --force and know what
3732 # you are doing or used --exact or a merge patch while
3742 # you are doing or used --exact or a merge patch while
3733 # being updated to its first parent.
3743 # being updated to its first parent.
3734 m = None
3744 m = None
3735 else:
3745 else:
3736 m = scmutil.matchfiles(repo, files or [])
3746 m = scmutil.matchfiles(repo, files or [])
3737 n = repo.commit(message, opts.get('user') or user,
3747 n = repo.commit(message, opts.get('user') or user,
3738 opts.get('date') or date, match=m,
3748 opts.get('date') or date, match=m,
3739 editor=editor)
3749 editor=editor)
3740 checkexact(repo, n, nodeid)
3750 checkexact(repo, n, nodeid)
3741 else:
3751 else:
3742 if opts.get('exact') or opts.get('import_branch'):
3752 if opts.get('exact') or opts.get('import_branch'):
3743 branch = branch or 'default'
3753 branch = branch or 'default'
3744 else:
3754 else:
3745 branch = p1.branch()
3755 branch = p1.branch()
3746 store = patch.filestore()
3756 store = patch.filestore()
3747 try:
3757 try:
3748 files = set()
3758 files = set()
3749 try:
3759 try:
3750 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3760 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3751 files, eolmode=None)
3761 files, eolmode=None)
3752 except patch.PatchError, e:
3762 except patch.PatchError, e:
3753 raise util.Abort(str(e))
3763 raise util.Abort(str(e))
3754 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3764 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3755 message,
3765 message,
3756 opts.get('user') or user,
3766 opts.get('user') or user,
3757 opts.get('date') or date,
3767 opts.get('date') or date,
3758 branch, files, store,
3768 branch, files, store,
3759 editor=cmdutil.commiteditor)
3769 editor=cmdutil.commiteditor)
3760 repo.savecommitmessage(memctx.description())
3770 repo.savecommitmessage(memctx.description())
3761 n = memctx.commit()
3771 n = memctx.commit()
3762 checkexact(repo, n, nodeid)
3772 checkexact(repo, n, nodeid)
3763 finally:
3773 finally:
3764 store.close()
3774 store.close()
3765 if n:
3775 if n:
3766 # i18n: refers to a short changeset id
3776 # i18n: refers to a short changeset id
3767 msg = _('created %s') % short(n)
3777 msg = _('created %s') % short(n)
3768 return (msg, n)
3778 return (msg, n)
3769 finally:
3779 finally:
3770 os.unlink(tmpname)
3780 os.unlink(tmpname)
3771
3781
3772 try:
3782 try:
3773 try:
3783 try:
3774 wlock = repo.wlock()
3784 wlock = repo.wlock()
3775 if not opts.get('no_commit'):
3785 if not opts.get('no_commit'):
3776 lock = repo.lock()
3786 lock = repo.lock()
3777 tr = repo.transaction('import')
3787 tr = repo.transaction('import')
3778 parents = repo.parents()
3788 parents = repo.parents()
3779 for patchurl in patches:
3789 for patchurl in patches:
3780 if patchurl == '-':
3790 if patchurl == '-':
3781 ui.status(_('applying patch from stdin\n'))
3791 ui.status(_('applying patch from stdin\n'))
3782 patchfile = ui.fin
3792 patchfile = ui.fin
3783 patchurl = 'stdin' # for error message
3793 patchurl = 'stdin' # for error message
3784 else:
3794 else:
3785 patchurl = os.path.join(base, patchurl)
3795 patchurl = os.path.join(base, patchurl)
3786 ui.status(_('applying %s\n') % patchurl)
3796 ui.status(_('applying %s\n') % patchurl)
3787 patchfile = url.open(ui, patchurl)
3797 patchfile = url.open(ui, patchurl)
3788
3798
3789 haspatch = False
3799 haspatch = False
3790 for hunk in patch.split(patchfile):
3800 for hunk in patch.split(patchfile):
3791 (msg, node) = tryone(ui, hunk, parents)
3801 (msg, node) = tryone(ui, hunk, parents)
3792 if msg:
3802 if msg:
3793 haspatch = True
3803 haspatch = True
3794 ui.note(msg + '\n')
3804 ui.note(msg + '\n')
3795 if update or opts.get('exact'):
3805 if update or opts.get('exact'):
3796 parents = repo.parents()
3806 parents = repo.parents()
3797 else:
3807 else:
3798 parents = [repo[node]]
3808 parents = [repo[node]]
3799
3809
3800 if not haspatch:
3810 if not haspatch:
3801 raise util.Abort(_('%s: no diffs found') % patchurl)
3811 raise util.Abort(_('%s: no diffs found') % patchurl)
3802
3812
3803 if tr:
3813 if tr:
3804 tr.close()
3814 tr.close()
3805 if msgs:
3815 if msgs:
3806 repo.savecommitmessage('\n* * *\n'.join(msgs))
3816 repo.savecommitmessage('\n* * *\n'.join(msgs))
3807 except: # re-raises
3817 except: # re-raises
3808 # wlock.release() indirectly calls dirstate.write(): since
3818 # wlock.release() indirectly calls dirstate.write(): since
3809 # we're crashing, we do not want to change the working dir
3819 # we're crashing, we do not want to change the working dir
3810 # parent after all, so make sure it writes nothing
3820 # parent after all, so make sure it writes nothing
3811 repo.dirstate.invalidate()
3821 repo.dirstate.invalidate()
3812 raise
3822 raise
3813 finally:
3823 finally:
3814 if tr:
3824 if tr:
3815 tr.release()
3825 tr.release()
3816 release(lock, wlock)
3826 release(lock, wlock)
3817
3827
3818 @command('incoming|in',
3828 @command('incoming|in',
3819 [('f', 'force', None,
3829 [('f', 'force', None,
3820 _('run even if remote repository is unrelated')),
3830 _('run even if remote repository is unrelated')),
3821 ('n', 'newest-first', None, _('show newest record first')),
3831 ('n', 'newest-first', None, _('show newest record first')),
3822 ('', 'bundle', '',
3832 ('', 'bundle', '',
3823 _('file to store the bundles into'), _('FILE')),
3833 _('file to store the bundles into'), _('FILE')),
3824 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3834 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3825 ('B', 'bookmarks', False, _("compare bookmarks")),
3835 ('B', 'bookmarks', False, _("compare bookmarks")),
3826 ('b', 'branch', [],
3836 ('b', 'branch', [],
3827 _('a specific branch you would like to pull'), _('BRANCH')),
3837 _('a specific branch you would like to pull'), _('BRANCH')),
3828 ] + logopts + remoteopts + subrepoopts,
3838 ] + logopts + remoteopts + subrepoopts,
3829 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3839 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3830 def incoming(ui, repo, source="default", **opts):
3840 def incoming(ui, repo, source="default", **opts):
3831 """show new changesets found in source
3841 """show new changesets found in source
3832
3842
3833 Show new changesets found in the specified path/URL or the default
3843 Show new changesets found in the specified path/URL or the default
3834 pull location. These are the changesets that would have been pulled
3844 pull location. These are the changesets that would have been pulled
3835 if a pull at the time you issued this command.
3845 if a pull at the time you issued this command.
3836
3846
3837 For remote repository, using --bundle avoids downloading the
3847 For remote repository, using --bundle avoids downloading the
3838 changesets twice if the incoming is followed by a pull.
3848 changesets twice if the incoming is followed by a pull.
3839
3849
3840 See pull for valid source format details.
3850 See pull for valid source format details.
3841
3851
3842 Returns 0 if there are incoming changes, 1 otherwise.
3852 Returns 0 if there are incoming changes, 1 otherwise.
3843 """
3853 """
3844 if opts.get('graph'):
3854 if opts.get('graph'):
3845 cmdutil.checkunsupportedgraphflags([], opts)
3855 cmdutil.checkunsupportedgraphflags([], opts)
3846 def display(other, chlist, displayer):
3856 def display(other, chlist, displayer):
3847 revdag = cmdutil.graphrevs(other, chlist, opts)
3857 revdag = cmdutil.graphrevs(other, chlist, opts)
3848 showparents = [ctx.node() for ctx in repo[None].parents()]
3858 showparents = [ctx.node() for ctx in repo[None].parents()]
3849 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3859 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3850 graphmod.asciiedges)
3860 graphmod.asciiedges)
3851
3861
3852 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3862 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3853 return 0
3863 return 0
3854
3864
3855 if opts.get('bundle') and opts.get('subrepos'):
3865 if opts.get('bundle') and opts.get('subrepos'):
3856 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3866 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3857
3867
3858 if opts.get('bookmarks'):
3868 if opts.get('bookmarks'):
3859 source, branches = hg.parseurl(ui.expandpath(source),
3869 source, branches = hg.parseurl(ui.expandpath(source),
3860 opts.get('branch'))
3870 opts.get('branch'))
3861 other = hg.peer(repo, opts, source)
3871 other = hg.peer(repo, opts, source)
3862 if 'bookmarks' not in other.listkeys('namespaces'):
3872 if 'bookmarks' not in other.listkeys('namespaces'):
3863 ui.warn(_("remote doesn't support bookmarks\n"))
3873 ui.warn(_("remote doesn't support bookmarks\n"))
3864 return 0
3874 return 0
3865 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3875 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3866 return bookmarks.diff(ui, repo, other)
3876 return bookmarks.diff(ui, repo, other)
3867
3877
3868 repo._subtoppath = ui.expandpath(source)
3878 repo._subtoppath = ui.expandpath(source)
3869 try:
3879 try:
3870 return hg.incoming(ui, repo, source, opts)
3880 return hg.incoming(ui, repo, source, opts)
3871 finally:
3881 finally:
3872 del repo._subtoppath
3882 del repo._subtoppath
3873
3883
3874
3884
3875 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3885 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3876 def init(ui, dest=".", **opts):
3886 def init(ui, dest=".", **opts):
3877 """create a new repository in the given directory
3887 """create a new repository in the given directory
3878
3888
3879 Initialize a new repository in the given directory. If the given
3889 Initialize a new repository in the given directory. If the given
3880 directory does not exist, it will be created.
3890 directory does not exist, it will be created.
3881
3891
3882 If no directory is given, the current directory is used.
3892 If no directory is given, the current directory is used.
3883
3893
3884 It is possible to specify an ``ssh://`` URL as the destination.
3894 It is possible to specify an ``ssh://`` URL as the destination.
3885 See :hg:`help urls` for more information.
3895 See :hg:`help urls` for more information.
3886
3896
3887 Returns 0 on success.
3897 Returns 0 on success.
3888 """
3898 """
3889 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3899 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3890
3900
3891 @command('locate',
3901 @command('locate',
3892 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3902 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3893 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3903 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3894 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3904 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3895 ] + walkopts,
3905 ] + walkopts,
3896 _('[OPTION]... [PATTERN]...'))
3906 _('[OPTION]... [PATTERN]...'))
3897 def locate(ui, repo, *pats, **opts):
3907 def locate(ui, repo, *pats, **opts):
3898 """locate files matching specific patterns
3908 """locate files matching specific patterns
3899
3909
3900 Print files under Mercurial control in the working directory whose
3910 Print files under Mercurial control in the working directory whose
3901 names match the given patterns.
3911 names match the given patterns.
3902
3912
3903 By default, this command searches all directories in the working
3913 By default, this command searches all directories in the working
3904 directory. To search just the current directory and its
3914 directory. To search just the current directory and its
3905 subdirectories, use "--include .".
3915 subdirectories, use "--include .".
3906
3916
3907 If no patterns are given to match, this command prints the names
3917 If no patterns are given to match, this command prints the names
3908 of all files under Mercurial control in the working directory.
3918 of all files under Mercurial control in the working directory.
3909
3919
3910 If you want to feed the output of this command into the "xargs"
3920 If you want to feed the output of this command into the "xargs"
3911 command, use the -0 option to both this command and "xargs". This
3921 command, use the -0 option to both this command and "xargs". This
3912 will avoid the problem of "xargs" treating single filenames that
3922 will avoid the problem of "xargs" treating single filenames that
3913 contain whitespace as multiple filenames.
3923 contain whitespace as multiple filenames.
3914
3924
3915 Returns 0 if a match is found, 1 otherwise.
3925 Returns 0 if a match is found, 1 otherwise.
3916 """
3926 """
3917 end = opts.get('print0') and '\0' or '\n'
3927 end = opts.get('print0') and '\0' or '\n'
3918 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3928 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3919
3929
3920 ret = 1
3930 ret = 1
3921 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3931 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3922 m.bad = lambda x, y: False
3932 m.bad = lambda x, y: False
3923 for abs in repo[rev].walk(m):
3933 for abs in repo[rev].walk(m):
3924 if not rev and abs not in repo.dirstate:
3934 if not rev and abs not in repo.dirstate:
3925 continue
3935 continue
3926 if opts.get('fullpath'):
3936 if opts.get('fullpath'):
3927 ui.write(repo.wjoin(abs), end)
3937 ui.write(repo.wjoin(abs), end)
3928 else:
3938 else:
3929 ui.write(((pats and m.rel(abs)) or abs), end)
3939 ui.write(((pats and m.rel(abs)) or abs), end)
3930 ret = 0
3940 ret = 0
3931
3941
3932 return ret
3942 return ret
3933
3943
3934 @command('^log|history',
3944 @command('^log|history',
3935 [('f', 'follow', None,
3945 [('f', 'follow', None,
3936 _('follow changeset history, or file history across copies and renames')),
3946 _('follow changeset history, or file history across copies and renames')),
3937 ('', 'follow-first', None,
3947 ('', 'follow-first', None,
3938 _('only follow the first parent of merge changesets (DEPRECATED)')),
3948 _('only follow the first parent of merge changesets (DEPRECATED)')),
3939 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3949 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3940 ('C', 'copies', None, _('show copied files')),
3950 ('C', 'copies', None, _('show copied files')),
3941 ('k', 'keyword', [],
3951 ('k', 'keyword', [],
3942 _('do case-insensitive search for a given text'), _('TEXT')),
3952 _('do case-insensitive search for a given text'), _('TEXT')),
3943 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3953 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3944 ('', 'removed', None, _('include revisions where files were removed')),
3954 ('', 'removed', None, _('include revisions where files were removed')),
3945 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3955 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3946 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3956 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3947 ('', 'only-branch', [],
3957 ('', 'only-branch', [],
3948 _('show only changesets within the given named branch (DEPRECATED)'),
3958 _('show only changesets within the given named branch (DEPRECATED)'),
3949 _('BRANCH')),
3959 _('BRANCH')),
3950 ('b', 'branch', [],
3960 ('b', 'branch', [],
3951 _('show changesets within the given named branch'), _('BRANCH')),
3961 _('show changesets within the given named branch'), _('BRANCH')),
3952 ('P', 'prune', [],
3962 ('P', 'prune', [],
3953 _('do not display revision or any of its ancestors'), _('REV')),
3963 _('do not display revision or any of its ancestors'), _('REV')),
3954 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3964 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3955 ] + logopts + walkopts,
3965 ] + logopts + walkopts,
3956 _('[OPTION]... [FILE]'))
3966 _('[OPTION]... [FILE]'))
3957 def log(ui, repo, *pats, **opts):
3967 def log(ui, repo, *pats, **opts):
3958 """show revision history of entire repository or files
3968 """show revision history of entire repository or files
3959
3969
3960 Print the revision history of the specified files or the entire
3970 Print the revision history of the specified files or the entire
3961 project.
3971 project.
3962
3972
3963 If no revision range is specified, the default is ``tip:0`` unless
3973 If no revision range is specified, the default is ``tip:0`` unless
3964 --follow is set, in which case the working directory parent is
3974 --follow is set, in which case the working directory parent is
3965 used as the starting revision.
3975 used as the starting revision.
3966
3976
3967 File history is shown without following rename or copy history of
3977 File history is shown without following rename or copy history of
3968 files. Use -f/--follow with a filename to follow history across
3978 files. Use -f/--follow with a filename to follow history across
3969 renames and copies. --follow without a filename will only show
3979 renames and copies. --follow without a filename will only show
3970 ancestors or descendants of the starting revision.
3980 ancestors or descendants of the starting revision.
3971
3981
3972 By default this command prints revision number and changeset id,
3982 By default this command prints revision number and changeset id,
3973 tags, non-trivial parents, user, date and time, and a summary for
3983 tags, non-trivial parents, user, date and time, and a summary for
3974 each commit. When the -v/--verbose switch is used, the list of
3984 each commit. When the -v/--verbose switch is used, the list of
3975 changed files and full commit message are shown.
3985 changed files and full commit message are shown.
3976
3986
3977 .. note::
3987 .. note::
3978 log -p/--patch may generate unexpected diff output for merge
3988 log -p/--patch may generate unexpected diff output for merge
3979 changesets, as it will only compare the merge changeset against
3989 changesets, as it will only compare the merge changeset against
3980 its first parent. Also, only files different from BOTH parents
3990 its first parent. Also, only files different from BOTH parents
3981 will appear in files:.
3991 will appear in files:.
3982
3992
3983 .. note::
3993 .. note::
3984 for performance reasons, log FILE may omit duplicate changes
3994 for performance reasons, log FILE may omit duplicate changes
3985 made on branches and will not show deletions. To see all
3995 made on branches and will not show deletions. To see all
3986 changes including duplicates and deletions, use the --removed
3996 changes including duplicates and deletions, use the --removed
3987 switch.
3997 switch.
3988
3998
3989 .. container:: verbose
3999 .. container:: verbose
3990
4000
3991 Some examples:
4001 Some examples:
3992
4002
3993 - changesets with full descriptions and file lists::
4003 - changesets with full descriptions and file lists::
3994
4004
3995 hg log -v
4005 hg log -v
3996
4006
3997 - changesets ancestral to the working directory::
4007 - changesets ancestral to the working directory::
3998
4008
3999 hg log -f
4009 hg log -f
4000
4010
4001 - last 10 commits on the current branch::
4011 - last 10 commits on the current branch::
4002
4012
4003 hg log -l 10 -b .
4013 hg log -l 10 -b .
4004
4014
4005 - changesets showing all modifications of a file, including removals::
4015 - changesets showing all modifications of a file, including removals::
4006
4016
4007 hg log --removed file.c
4017 hg log --removed file.c
4008
4018
4009 - all changesets that touch a directory, with diffs, excluding merges::
4019 - all changesets that touch a directory, with diffs, excluding merges::
4010
4020
4011 hg log -Mp lib/
4021 hg log -Mp lib/
4012
4022
4013 - all revision numbers that match a keyword::
4023 - all revision numbers that match a keyword::
4014
4024
4015 hg log -k bug --template "{rev}\\n"
4025 hg log -k bug --template "{rev}\\n"
4016
4026
4017 - check if a given changeset is included is a tagged release::
4027 - check if a given changeset is included is a tagged release::
4018
4028
4019 hg log -r "a21ccf and ancestor(1.9)"
4029 hg log -r "a21ccf and ancestor(1.9)"
4020
4030
4021 - find all changesets by some user in a date range::
4031 - find all changesets by some user in a date range::
4022
4032
4023 hg log -k alice -d "may 2008 to jul 2008"
4033 hg log -k alice -d "may 2008 to jul 2008"
4024
4034
4025 - summary of all changesets after the last tag::
4035 - summary of all changesets after the last tag::
4026
4036
4027 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4037 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4028
4038
4029 See :hg:`help dates` for a list of formats valid for -d/--date.
4039 See :hg:`help dates` for a list of formats valid for -d/--date.
4030
4040
4031 See :hg:`help revisions` and :hg:`help revsets` for more about
4041 See :hg:`help revisions` and :hg:`help revsets` for more about
4032 specifying revisions.
4042 specifying revisions.
4033
4043
4034 See :hg:`help templates` for more about pre-packaged styles and
4044 See :hg:`help templates` for more about pre-packaged styles and
4035 specifying custom templates.
4045 specifying custom templates.
4036
4046
4037 Returns 0 on success.
4047 Returns 0 on success.
4038 """
4048 """
4039 if opts.get('graph'):
4049 if opts.get('graph'):
4040 return cmdutil.graphlog(ui, repo, *pats, **opts)
4050 return cmdutil.graphlog(ui, repo, *pats, **opts)
4041
4051
4042 matchfn = scmutil.match(repo[None], pats, opts)
4052 matchfn = scmutil.match(repo[None], pats, opts)
4043 limit = cmdutil.loglimit(opts)
4053 limit = cmdutil.loglimit(opts)
4044 count = 0
4054 count = 0
4045
4055
4046 getrenamed, endrev = None, None
4056 getrenamed, endrev = None, None
4047 if opts.get('copies'):
4057 if opts.get('copies'):
4048 if opts.get('rev'):
4058 if opts.get('rev'):
4049 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4059 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4050 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4060 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4051
4061
4052 df = False
4062 df = False
4053 if opts["date"]:
4063 if opts["date"]:
4054 df = util.matchdate(opts["date"])
4064 df = util.matchdate(opts["date"])
4055
4065
4056 branches = opts.get('branch', []) + opts.get('only_branch', [])
4066 branches = opts.get('branch', []) + opts.get('only_branch', [])
4057 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4067 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4058
4068
4059 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4069 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4060 def prep(ctx, fns):
4070 def prep(ctx, fns):
4061 rev = ctx.rev()
4071 rev = ctx.rev()
4062 parents = [p for p in repo.changelog.parentrevs(rev)
4072 parents = [p for p in repo.changelog.parentrevs(rev)
4063 if p != nullrev]
4073 if p != nullrev]
4064 if opts.get('no_merges') and len(parents) == 2:
4074 if opts.get('no_merges') and len(parents) == 2:
4065 return
4075 return
4066 if opts.get('only_merges') and len(parents) != 2:
4076 if opts.get('only_merges') and len(parents) != 2:
4067 return
4077 return
4068 if opts.get('branch') and ctx.branch() not in opts['branch']:
4078 if opts.get('branch') and ctx.branch() not in opts['branch']:
4069 return
4079 return
4070 if not opts.get('hidden') and ctx.hidden():
4080 if not opts.get('hidden') and ctx.hidden():
4071 return
4081 return
4072 if df and not df(ctx.date()[0]):
4082 if df and not df(ctx.date()[0]):
4073 return
4083 return
4074
4084
4075 lower = encoding.lower
4085 lower = encoding.lower
4076 if opts.get('user'):
4086 if opts.get('user'):
4077 luser = lower(ctx.user())
4087 luser = lower(ctx.user())
4078 for k in [lower(x) for x in opts['user']]:
4088 for k in [lower(x) for x in opts['user']]:
4079 if (k in luser):
4089 if (k in luser):
4080 break
4090 break
4081 else:
4091 else:
4082 return
4092 return
4083 if opts.get('keyword'):
4093 if opts.get('keyword'):
4084 luser = lower(ctx.user())
4094 luser = lower(ctx.user())
4085 ldesc = lower(ctx.description())
4095 ldesc = lower(ctx.description())
4086 lfiles = lower(" ".join(ctx.files()))
4096 lfiles = lower(" ".join(ctx.files()))
4087 for k in [lower(x) for x in opts['keyword']]:
4097 for k in [lower(x) for x in opts['keyword']]:
4088 if (k in luser or k in ldesc or k in lfiles):
4098 if (k in luser or k in ldesc or k in lfiles):
4089 break
4099 break
4090 else:
4100 else:
4091 return
4101 return
4092
4102
4093 copies = None
4103 copies = None
4094 if getrenamed is not None and rev:
4104 if getrenamed is not None and rev:
4095 copies = []
4105 copies = []
4096 for fn in ctx.files():
4106 for fn in ctx.files():
4097 rename = getrenamed(fn, rev)
4107 rename = getrenamed(fn, rev)
4098 if rename:
4108 if rename:
4099 copies.append((fn, rename[0]))
4109 copies.append((fn, rename[0]))
4100
4110
4101 revmatchfn = None
4111 revmatchfn = None
4102 if opts.get('patch') or opts.get('stat'):
4112 if opts.get('patch') or opts.get('stat'):
4103 if opts.get('follow') or opts.get('follow_first'):
4113 if opts.get('follow') or opts.get('follow_first'):
4104 # note: this might be wrong when following through merges
4114 # note: this might be wrong when following through merges
4105 revmatchfn = scmutil.match(repo[None], fns, default='path')
4115 revmatchfn = scmutil.match(repo[None], fns, default='path')
4106 else:
4116 else:
4107 revmatchfn = matchfn
4117 revmatchfn = matchfn
4108
4118
4109 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4119 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4110
4120
4111 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4121 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4112 if count == limit:
4122 if count == limit:
4113 break
4123 break
4114 if displayer.flush(ctx.rev()):
4124 if displayer.flush(ctx.rev()):
4115 count += 1
4125 count += 1
4116 displayer.close()
4126 displayer.close()
4117
4127
4118 @command('manifest',
4128 @command('manifest',
4119 [('r', 'rev', '', _('revision to display'), _('REV')),
4129 [('r', 'rev', '', _('revision to display'), _('REV')),
4120 ('', 'all', False, _("list files from all revisions"))],
4130 ('', 'all', False, _("list files from all revisions"))],
4121 _('[-r REV]'))
4131 _('[-r REV]'))
4122 def manifest(ui, repo, node=None, rev=None, **opts):
4132 def manifest(ui, repo, node=None, rev=None, **opts):
4123 """output the current or given revision of the project manifest
4133 """output the current or given revision of the project manifest
4124
4134
4125 Print a list of version controlled files for the given revision.
4135 Print a list of version controlled files for the given revision.
4126 If no revision is given, the first parent of the working directory
4136 If no revision is given, the first parent of the working directory
4127 is used, or the null revision if no revision is checked out.
4137 is used, or the null revision if no revision is checked out.
4128
4138
4129 With -v, print file permissions, symlink and executable bits.
4139 With -v, print file permissions, symlink and executable bits.
4130 With --debug, print file revision hashes.
4140 With --debug, print file revision hashes.
4131
4141
4132 If option --all is specified, the list of all files from all revisions
4142 If option --all is specified, the list of all files from all revisions
4133 is printed. This includes deleted and renamed files.
4143 is printed. This includes deleted and renamed files.
4134
4144
4135 Returns 0 on success.
4145 Returns 0 on success.
4136 """
4146 """
4137 if opts.get('all'):
4147 if opts.get('all'):
4138 if rev or node:
4148 if rev or node:
4139 raise util.Abort(_("can't specify a revision with --all"))
4149 raise util.Abort(_("can't specify a revision with --all"))
4140
4150
4141 res = []
4151 res = []
4142 prefix = "data/"
4152 prefix = "data/"
4143 suffix = ".i"
4153 suffix = ".i"
4144 plen = len(prefix)
4154 plen = len(prefix)
4145 slen = len(suffix)
4155 slen = len(suffix)
4146 lock = repo.lock()
4156 lock = repo.lock()
4147 try:
4157 try:
4148 for fn, b, size in repo.store.datafiles():
4158 for fn, b, size in repo.store.datafiles():
4149 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4159 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4150 res.append(fn[plen:-slen])
4160 res.append(fn[plen:-slen])
4151 finally:
4161 finally:
4152 lock.release()
4162 lock.release()
4153 for f in sorted(res):
4163 for f in sorted(res):
4154 ui.write("%s\n" % f)
4164 ui.write("%s\n" % f)
4155 return
4165 return
4156
4166
4157 if rev and node:
4167 if rev and node:
4158 raise util.Abort(_("please specify just one revision"))
4168 raise util.Abort(_("please specify just one revision"))
4159
4169
4160 if not node:
4170 if not node:
4161 node = rev
4171 node = rev
4162
4172
4163 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4173 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4164 ctx = scmutil.revsingle(repo, node)
4174 ctx = scmutil.revsingle(repo, node)
4165 for f in ctx:
4175 for f in ctx:
4166 if ui.debugflag:
4176 if ui.debugflag:
4167 ui.write("%40s " % hex(ctx.manifest()[f]))
4177 ui.write("%40s " % hex(ctx.manifest()[f]))
4168 if ui.verbose:
4178 if ui.verbose:
4169 ui.write(decor[ctx.flags(f)])
4179 ui.write(decor[ctx.flags(f)])
4170 ui.write("%s\n" % f)
4180 ui.write("%s\n" % f)
4171
4181
4172 @command('^merge',
4182 @command('^merge',
4173 [('f', 'force', None, _('force a merge with outstanding changes')),
4183 [('f', 'force', None, _('force a merge with outstanding changes')),
4174 ('r', 'rev', '', _('revision to merge'), _('REV')),
4184 ('r', 'rev', '', _('revision to merge'), _('REV')),
4175 ('P', 'preview', None,
4185 ('P', 'preview', None,
4176 _('review revisions to merge (no merge is performed)'))
4186 _('review revisions to merge (no merge is performed)'))
4177 ] + mergetoolopts,
4187 ] + mergetoolopts,
4178 _('[-P] [-f] [[-r] REV]'))
4188 _('[-P] [-f] [[-r] REV]'))
4179 def merge(ui, repo, node=None, **opts):
4189 def merge(ui, repo, node=None, **opts):
4180 """merge working directory with another revision
4190 """merge working directory with another revision
4181
4191
4182 The current working directory is updated with all changes made in
4192 The current working directory is updated with all changes made in
4183 the requested revision since the last common predecessor revision.
4193 the requested revision since the last common predecessor revision.
4184
4194
4185 Files that changed between either parent are marked as changed for
4195 Files that changed between either parent are marked as changed for
4186 the next commit and a commit must be performed before any further
4196 the next commit and a commit must be performed before any further
4187 updates to the repository are allowed. The next commit will have
4197 updates to the repository are allowed. The next commit will have
4188 two parents.
4198 two parents.
4189
4199
4190 ``--tool`` can be used to specify the merge tool used for file
4200 ``--tool`` can be used to specify the merge tool used for file
4191 merges. It overrides the HGMERGE environment variable and your
4201 merges. It overrides the HGMERGE environment variable and your
4192 configuration files. See :hg:`help merge-tools` for options.
4202 configuration files. See :hg:`help merge-tools` for options.
4193
4203
4194 If no revision is specified, the working directory's parent is a
4204 If no revision is specified, the working directory's parent is a
4195 head revision, and the current branch contains exactly one other
4205 head revision, and the current branch contains exactly one other
4196 head, the other head is merged with by default. Otherwise, an
4206 head, the other head is merged with by default. Otherwise, an
4197 explicit revision with which to merge with must be provided.
4207 explicit revision with which to merge with must be provided.
4198
4208
4199 :hg:`resolve` must be used to resolve unresolved files.
4209 :hg:`resolve` must be used to resolve unresolved files.
4200
4210
4201 To undo an uncommitted merge, use :hg:`update --clean .` which
4211 To undo an uncommitted merge, use :hg:`update --clean .` which
4202 will check out a clean copy of the original merge parent, losing
4212 will check out a clean copy of the original merge parent, losing
4203 all changes.
4213 all changes.
4204
4214
4205 Returns 0 on success, 1 if there are unresolved files.
4215 Returns 0 on success, 1 if there are unresolved files.
4206 """
4216 """
4207
4217
4208 if opts.get('rev') and node:
4218 if opts.get('rev') and node:
4209 raise util.Abort(_("please specify just one revision"))
4219 raise util.Abort(_("please specify just one revision"))
4210 if not node:
4220 if not node:
4211 node = opts.get('rev')
4221 node = opts.get('rev')
4212
4222
4213 if node:
4223 if node:
4214 node = scmutil.revsingle(repo, node).node()
4224 node = scmutil.revsingle(repo, node).node()
4215
4225
4216 if not node and repo._bookmarkcurrent:
4226 if not node and repo._bookmarkcurrent:
4217 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4227 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4218 curhead = repo[repo._bookmarkcurrent]
4228 curhead = repo[repo._bookmarkcurrent]
4219 if len(bmheads) == 2:
4229 if len(bmheads) == 2:
4220 if curhead == bmheads[0]:
4230 if curhead == bmheads[0]:
4221 node = bmheads[1]
4231 node = bmheads[1]
4222 else:
4232 else:
4223 node = bmheads[0]
4233 node = bmheads[0]
4224 elif len(bmheads) > 2:
4234 elif len(bmheads) > 2:
4225 raise util.Abort(_("multiple matching bookmarks to merge - "
4235 raise util.Abort(_("multiple matching bookmarks to merge - "
4226 "please merge with an explicit rev or bookmark"),
4236 "please merge with an explicit rev or bookmark"),
4227 hint=_("run 'hg heads' to see all heads"))
4237 hint=_("run 'hg heads' to see all heads"))
4228 elif len(bmheads) <= 1:
4238 elif len(bmheads) <= 1:
4229 raise util.Abort(_("no matching bookmark to merge - "
4239 raise util.Abort(_("no matching bookmark to merge - "
4230 "please merge with an explicit rev or bookmark"),
4240 "please merge with an explicit rev or bookmark"),
4231 hint=_("run 'hg heads' to see all heads"))
4241 hint=_("run 'hg heads' to see all heads"))
4232
4242
4233 if not node and not repo._bookmarkcurrent:
4243 if not node and not repo._bookmarkcurrent:
4234 branch = repo[None].branch()
4244 branch = repo[None].branch()
4235 bheads = repo.branchheads(branch)
4245 bheads = repo.branchheads(branch)
4236 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4246 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4237
4247
4238 if len(nbhs) > 2:
4248 if len(nbhs) > 2:
4239 raise util.Abort(_("branch '%s' has %d heads - "
4249 raise util.Abort(_("branch '%s' has %d heads - "
4240 "please merge with an explicit rev")
4250 "please merge with an explicit rev")
4241 % (branch, len(bheads)),
4251 % (branch, len(bheads)),
4242 hint=_("run 'hg heads .' to see heads"))
4252 hint=_("run 'hg heads .' to see heads"))
4243
4253
4244 parent = repo.dirstate.p1()
4254 parent = repo.dirstate.p1()
4245 if len(nbhs) == 1:
4255 if len(nbhs) == 1:
4246 if len(bheads) > 1:
4256 if len(bheads) > 1:
4247 raise util.Abort(_("heads are bookmarked - "
4257 raise util.Abort(_("heads are bookmarked - "
4248 "please merge with an explicit rev"),
4258 "please merge with an explicit rev"),
4249 hint=_("run 'hg heads' to see all heads"))
4259 hint=_("run 'hg heads' to see all heads"))
4250 if len(repo.heads()) > 1:
4260 if len(repo.heads()) > 1:
4251 raise util.Abort(_("branch '%s' has one head - "
4261 raise util.Abort(_("branch '%s' has one head - "
4252 "please merge with an explicit rev")
4262 "please merge with an explicit rev")
4253 % branch,
4263 % branch,
4254 hint=_("run 'hg heads' to see all heads"))
4264 hint=_("run 'hg heads' to see all heads"))
4255 msg, hint = _('nothing to merge'), None
4265 msg, hint = _('nothing to merge'), None
4256 if parent != repo.lookup(branch):
4266 if parent != repo.lookup(branch):
4257 hint = _("use 'hg update' instead")
4267 hint = _("use 'hg update' instead")
4258 raise util.Abort(msg, hint=hint)
4268 raise util.Abort(msg, hint=hint)
4259
4269
4260 if parent not in bheads:
4270 if parent not in bheads:
4261 raise util.Abort(_('working directory not at a head revision'),
4271 raise util.Abort(_('working directory not at a head revision'),
4262 hint=_("use 'hg update' or merge with an "
4272 hint=_("use 'hg update' or merge with an "
4263 "explicit revision"))
4273 "explicit revision"))
4264 if parent == nbhs[0]:
4274 if parent == nbhs[0]:
4265 node = nbhs[-1]
4275 node = nbhs[-1]
4266 else:
4276 else:
4267 node = nbhs[0]
4277 node = nbhs[0]
4268
4278
4269 if opts.get('preview'):
4279 if opts.get('preview'):
4270 # find nodes that are ancestors of p2 but not of p1
4280 # find nodes that are ancestors of p2 but not of p1
4271 p1 = repo.lookup('.')
4281 p1 = repo.lookup('.')
4272 p2 = repo.lookup(node)
4282 p2 = repo.lookup(node)
4273 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4283 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4274
4284
4275 displayer = cmdutil.show_changeset(ui, repo, opts)
4285 displayer = cmdutil.show_changeset(ui, repo, opts)
4276 for node in nodes:
4286 for node in nodes:
4277 displayer.show(repo[node])
4287 displayer.show(repo[node])
4278 displayer.close()
4288 displayer.close()
4279 return 0
4289 return 0
4280
4290
4281 try:
4291 try:
4282 # ui.forcemerge is an internal variable, do not document
4292 # ui.forcemerge is an internal variable, do not document
4283 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4293 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4284 return hg.merge(repo, node, force=opts.get('force'))
4294 return hg.merge(repo, node, force=opts.get('force'))
4285 finally:
4295 finally:
4286 ui.setconfig('ui', 'forcemerge', '')
4296 ui.setconfig('ui', 'forcemerge', '')
4287
4297
4288 @command('outgoing|out',
4298 @command('outgoing|out',
4289 [('f', 'force', None, _('run even when the destination is unrelated')),
4299 [('f', 'force', None, _('run even when the destination is unrelated')),
4290 ('r', 'rev', [],
4300 ('r', 'rev', [],
4291 _('a changeset intended to be included in the destination'), _('REV')),
4301 _('a changeset intended to be included in the destination'), _('REV')),
4292 ('n', 'newest-first', None, _('show newest record first')),
4302 ('n', 'newest-first', None, _('show newest record first')),
4293 ('B', 'bookmarks', False, _('compare bookmarks')),
4303 ('B', 'bookmarks', False, _('compare bookmarks')),
4294 ('b', 'branch', [], _('a specific branch you would like to push'),
4304 ('b', 'branch', [], _('a specific branch you would like to push'),
4295 _('BRANCH')),
4305 _('BRANCH')),
4296 ] + logopts + remoteopts + subrepoopts,
4306 ] + logopts + remoteopts + subrepoopts,
4297 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4307 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4298 def outgoing(ui, repo, dest=None, **opts):
4308 def outgoing(ui, repo, dest=None, **opts):
4299 """show changesets not found in the destination
4309 """show changesets not found in the destination
4300
4310
4301 Show changesets not found in the specified destination repository
4311 Show changesets not found in the specified destination repository
4302 or the default push location. These are the changesets that would
4312 or the default push location. These are the changesets that would
4303 be pushed if a push was requested.
4313 be pushed if a push was requested.
4304
4314
4305 See pull for details of valid destination formats.
4315 See pull for details of valid destination formats.
4306
4316
4307 Returns 0 if there are outgoing changes, 1 otherwise.
4317 Returns 0 if there are outgoing changes, 1 otherwise.
4308 """
4318 """
4309 if opts.get('graph'):
4319 if opts.get('graph'):
4310 cmdutil.checkunsupportedgraphflags([], opts)
4320 cmdutil.checkunsupportedgraphflags([], opts)
4311 o = hg._outgoing(ui, repo, dest, opts)
4321 o = hg._outgoing(ui, repo, dest, opts)
4312 if o is None:
4322 if o is None:
4313 return
4323 return
4314
4324
4315 revdag = cmdutil.graphrevs(repo, o, opts)
4325 revdag = cmdutil.graphrevs(repo, o, opts)
4316 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4326 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4317 showparents = [ctx.node() for ctx in repo[None].parents()]
4327 showparents = [ctx.node() for ctx in repo[None].parents()]
4318 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4328 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4319 graphmod.asciiedges)
4329 graphmod.asciiedges)
4320 return 0
4330 return 0
4321
4331
4322 if opts.get('bookmarks'):
4332 if opts.get('bookmarks'):
4323 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4333 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4324 dest, branches = hg.parseurl(dest, opts.get('branch'))
4334 dest, branches = hg.parseurl(dest, opts.get('branch'))
4325 other = hg.peer(repo, opts, dest)
4335 other = hg.peer(repo, opts, dest)
4326 if 'bookmarks' not in other.listkeys('namespaces'):
4336 if 'bookmarks' not in other.listkeys('namespaces'):
4327 ui.warn(_("remote doesn't support bookmarks\n"))
4337 ui.warn(_("remote doesn't support bookmarks\n"))
4328 return 0
4338 return 0
4329 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4339 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4330 return bookmarks.diff(ui, other, repo)
4340 return bookmarks.diff(ui, other, repo)
4331
4341
4332 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4342 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4333 try:
4343 try:
4334 return hg.outgoing(ui, repo, dest, opts)
4344 return hg.outgoing(ui, repo, dest, opts)
4335 finally:
4345 finally:
4336 del repo._subtoppath
4346 del repo._subtoppath
4337
4347
4338 @command('parents',
4348 @command('parents',
4339 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4349 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4340 ] + templateopts,
4350 ] + templateopts,
4341 _('[-r REV] [FILE]'))
4351 _('[-r REV] [FILE]'))
4342 def parents(ui, repo, file_=None, **opts):
4352 def parents(ui, repo, file_=None, **opts):
4343 """show the parents of the working directory or revision
4353 """show the parents of the working directory or revision
4344
4354
4345 Print the working directory's parent revisions. If a revision is
4355 Print the working directory's parent revisions. If a revision is
4346 given via -r/--rev, the parent of that revision will be printed.
4356 given via -r/--rev, the parent of that revision will be printed.
4347 If a file argument is given, the revision in which the file was
4357 If a file argument is given, the revision in which the file was
4348 last changed (before the working directory revision or the
4358 last changed (before the working directory revision or the
4349 argument to --rev if given) is printed.
4359 argument to --rev if given) is printed.
4350
4360
4351 Returns 0 on success.
4361 Returns 0 on success.
4352 """
4362 """
4353
4363
4354 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4364 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4355
4365
4356 if file_:
4366 if file_:
4357 m = scmutil.match(ctx, (file_,), opts)
4367 m = scmutil.match(ctx, (file_,), opts)
4358 if m.anypats() or len(m.files()) != 1:
4368 if m.anypats() or len(m.files()) != 1:
4359 raise util.Abort(_('can only specify an explicit filename'))
4369 raise util.Abort(_('can only specify an explicit filename'))
4360 file_ = m.files()[0]
4370 file_ = m.files()[0]
4361 filenodes = []
4371 filenodes = []
4362 for cp in ctx.parents():
4372 for cp in ctx.parents():
4363 if not cp:
4373 if not cp:
4364 continue
4374 continue
4365 try:
4375 try:
4366 filenodes.append(cp.filenode(file_))
4376 filenodes.append(cp.filenode(file_))
4367 except error.LookupError:
4377 except error.LookupError:
4368 pass
4378 pass
4369 if not filenodes:
4379 if not filenodes:
4370 raise util.Abort(_("'%s' not found in manifest!") % file_)
4380 raise util.Abort(_("'%s' not found in manifest!") % file_)
4371 fl = repo.file(file_)
4381 fl = repo.file(file_)
4372 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4382 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4373 else:
4383 else:
4374 p = [cp.node() for cp in ctx.parents()]
4384 p = [cp.node() for cp in ctx.parents()]
4375
4385
4376 displayer = cmdutil.show_changeset(ui, repo, opts)
4386 displayer = cmdutil.show_changeset(ui, repo, opts)
4377 for n in p:
4387 for n in p:
4378 if n != nullid:
4388 if n != nullid:
4379 displayer.show(repo[n])
4389 displayer.show(repo[n])
4380 displayer.close()
4390 displayer.close()
4381
4391
4382 @command('paths', [], _('[NAME]'))
4392 @command('paths', [], _('[NAME]'))
4383 def paths(ui, repo, search=None):
4393 def paths(ui, repo, search=None):
4384 """show aliases for remote repositories
4394 """show aliases for remote repositories
4385
4395
4386 Show definition of symbolic path name NAME. If no name is given,
4396 Show definition of symbolic path name NAME. If no name is given,
4387 show definition of all available names.
4397 show definition of all available names.
4388
4398
4389 Option -q/--quiet suppresses all output when searching for NAME
4399 Option -q/--quiet suppresses all output when searching for NAME
4390 and shows only the path names when listing all definitions.
4400 and shows only the path names when listing all definitions.
4391
4401
4392 Path names are defined in the [paths] section of your
4402 Path names are defined in the [paths] section of your
4393 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4403 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4394 repository, ``.hg/hgrc`` is used, too.
4404 repository, ``.hg/hgrc`` is used, too.
4395
4405
4396 The path names ``default`` and ``default-push`` have a special
4406 The path names ``default`` and ``default-push`` have a special
4397 meaning. When performing a push or pull operation, they are used
4407 meaning. When performing a push or pull operation, they are used
4398 as fallbacks if no location is specified on the command-line.
4408 as fallbacks if no location is specified on the command-line.
4399 When ``default-push`` is set, it will be used for push and
4409 When ``default-push`` is set, it will be used for push and
4400 ``default`` will be used for pull; otherwise ``default`` is used
4410 ``default`` will be used for pull; otherwise ``default`` is used
4401 as the fallback for both. When cloning a repository, the clone
4411 as the fallback for both. When cloning a repository, the clone
4402 source is written as ``default`` in ``.hg/hgrc``. Note that
4412 source is written as ``default`` in ``.hg/hgrc``. Note that
4403 ``default`` and ``default-push`` apply to all inbound (e.g.
4413 ``default`` and ``default-push`` apply to all inbound (e.g.
4404 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4414 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4405 :hg:`bundle`) operations.
4415 :hg:`bundle`) operations.
4406
4416
4407 See :hg:`help urls` for more information.
4417 See :hg:`help urls` for more information.
4408
4418
4409 Returns 0 on success.
4419 Returns 0 on success.
4410 """
4420 """
4411 if search:
4421 if search:
4412 for name, path in ui.configitems("paths"):
4422 for name, path in ui.configitems("paths"):
4413 if name == search:
4423 if name == search:
4414 ui.status("%s\n" % util.hidepassword(path))
4424 ui.status("%s\n" % util.hidepassword(path))
4415 return
4425 return
4416 if not ui.quiet:
4426 if not ui.quiet:
4417 ui.warn(_("not found!\n"))
4427 ui.warn(_("not found!\n"))
4418 return 1
4428 return 1
4419 else:
4429 else:
4420 for name, path in ui.configitems("paths"):
4430 for name, path in ui.configitems("paths"):
4421 if ui.quiet:
4431 if ui.quiet:
4422 ui.write("%s\n" % name)
4432 ui.write("%s\n" % name)
4423 else:
4433 else:
4424 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4434 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4425
4435
4426 @command('^phase',
4436 @command('^phase',
4427 [('p', 'public', False, _('set changeset phase to public')),
4437 [('p', 'public', False, _('set changeset phase to public')),
4428 ('d', 'draft', False, _('set changeset phase to draft')),
4438 ('d', 'draft', False, _('set changeset phase to draft')),
4429 ('s', 'secret', False, _('set changeset phase to secret')),
4439 ('s', 'secret', False, _('set changeset phase to secret')),
4430 ('f', 'force', False, _('allow to move boundary backward')),
4440 ('f', 'force', False, _('allow to move boundary backward')),
4431 ('r', 'rev', [], _('target revision'), _('REV')),
4441 ('r', 'rev', [], _('target revision'), _('REV')),
4432 ],
4442 ],
4433 _('[-p|-d|-s] [-f] [-r] REV...'))
4443 _('[-p|-d|-s] [-f] [-r] REV...'))
4434 def phase(ui, repo, *revs, **opts):
4444 def phase(ui, repo, *revs, **opts):
4435 """set or show the current phase name
4445 """set or show the current phase name
4436
4446
4437 With no argument, show the phase name of specified revisions.
4447 With no argument, show the phase name of specified revisions.
4438
4448
4439 With one of -p/--public, -d/--draft or -s/--secret, change the
4449 With one of -p/--public, -d/--draft or -s/--secret, change the
4440 phase value of the specified revisions.
4450 phase value of the specified revisions.
4441
4451
4442 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4452 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4443 lower phase to an higher phase. Phases are ordered as follows::
4453 lower phase to an higher phase. Phases are ordered as follows::
4444
4454
4445 public < draft < secret
4455 public < draft < secret
4446
4456
4447 Return 0 on success, 1 if no phases were changed or some could not
4457 Return 0 on success, 1 if no phases were changed or some could not
4448 be changed.
4458 be changed.
4449 """
4459 """
4450 # search for a unique phase argument
4460 # search for a unique phase argument
4451 targetphase = None
4461 targetphase = None
4452 for idx, name in enumerate(phases.phasenames):
4462 for idx, name in enumerate(phases.phasenames):
4453 if opts[name]:
4463 if opts[name]:
4454 if targetphase is not None:
4464 if targetphase is not None:
4455 raise util.Abort(_('only one phase can be specified'))
4465 raise util.Abort(_('only one phase can be specified'))
4456 targetphase = idx
4466 targetphase = idx
4457
4467
4458 # look for specified revision
4468 # look for specified revision
4459 revs = list(revs)
4469 revs = list(revs)
4460 revs.extend(opts['rev'])
4470 revs.extend(opts['rev'])
4461 if not revs:
4471 if not revs:
4462 raise util.Abort(_('no revisions specified'))
4472 raise util.Abort(_('no revisions specified'))
4463
4473
4464 revs = scmutil.revrange(repo, revs)
4474 revs = scmutil.revrange(repo, revs)
4465
4475
4466 lock = None
4476 lock = None
4467 ret = 0
4477 ret = 0
4468 if targetphase is None:
4478 if targetphase is None:
4469 # display
4479 # display
4470 for r in revs:
4480 for r in revs:
4471 ctx = repo[r]
4481 ctx = repo[r]
4472 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4482 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4473 else:
4483 else:
4474 lock = repo.lock()
4484 lock = repo.lock()
4475 try:
4485 try:
4476 # set phase
4486 # set phase
4477 if not revs:
4487 if not revs:
4478 raise util.Abort(_('empty revision set'))
4488 raise util.Abort(_('empty revision set'))
4479 nodes = [repo[r].node() for r in revs]
4489 nodes = [repo[r].node() for r in revs]
4480 olddata = repo._phasecache.getphaserevs(repo)[:]
4490 olddata = repo._phasecache.getphaserevs(repo)[:]
4481 phases.advanceboundary(repo, targetphase, nodes)
4491 phases.advanceboundary(repo, targetphase, nodes)
4482 if opts['force']:
4492 if opts['force']:
4483 phases.retractboundary(repo, targetphase, nodes)
4493 phases.retractboundary(repo, targetphase, nodes)
4484 finally:
4494 finally:
4485 lock.release()
4495 lock.release()
4486 newdata = repo._phasecache.getphaserevs(repo)
4496 newdata = repo._phasecache.getphaserevs(repo)
4487 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4497 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4488 rejected = [n for n in nodes
4498 rejected = [n for n in nodes
4489 if newdata[repo[n].rev()] < targetphase]
4499 if newdata[repo[n].rev()] < targetphase]
4490 if rejected:
4500 if rejected:
4491 ui.warn(_('cannot move %i changesets to a more permissive '
4501 ui.warn(_('cannot move %i changesets to a more permissive '
4492 'phase, use --force\n') % len(rejected))
4502 'phase, use --force\n') % len(rejected))
4493 ret = 1
4503 ret = 1
4494 if changes:
4504 if changes:
4495 msg = _('phase changed for %i changesets\n') % changes
4505 msg = _('phase changed for %i changesets\n') % changes
4496 if ret:
4506 if ret:
4497 ui.status(msg)
4507 ui.status(msg)
4498 else:
4508 else:
4499 ui.note(msg)
4509 ui.note(msg)
4500 else:
4510 else:
4501 ui.warn(_('no phases changed\n'))
4511 ui.warn(_('no phases changed\n'))
4502 ret = 1
4512 ret = 1
4503 return ret
4513 return ret
4504
4514
4505 def postincoming(ui, repo, modheads, optupdate, checkout):
4515 def postincoming(ui, repo, modheads, optupdate, checkout):
4506 if modheads == 0:
4516 if modheads == 0:
4507 return
4517 return
4508 if optupdate:
4518 if optupdate:
4509 movemarkfrom = repo['.'].node()
4519 movemarkfrom = repo['.'].node()
4510 try:
4520 try:
4511 ret = hg.update(repo, checkout)
4521 ret = hg.update(repo, checkout)
4512 except util.Abort, inst:
4522 except util.Abort, inst:
4513 ui.warn(_("not updating: %s\n") % str(inst))
4523 ui.warn(_("not updating: %s\n") % str(inst))
4514 return 0
4524 return 0
4515 if not ret and not checkout:
4525 if not ret and not checkout:
4516 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4526 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4517 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4527 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4518 return ret
4528 return ret
4519 if modheads > 1:
4529 if modheads > 1:
4520 currentbranchheads = len(repo.branchheads())
4530 currentbranchheads = len(repo.branchheads())
4521 if currentbranchheads == modheads:
4531 if currentbranchheads == modheads:
4522 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4532 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4523 elif currentbranchheads > 1:
4533 elif currentbranchheads > 1:
4524 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4534 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4525 "merge)\n"))
4535 "merge)\n"))
4526 else:
4536 else:
4527 ui.status(_("(run 'hg heads' to see heads)\n"))
4537 ui.status(_("(run 'hg heads' to see heads)\n"))
4528 else:
4538 else:
4529 ui.status(_("(run 'hg update' to get a working copy)\n"))
4539 ui.status(_("(run 'hg update' to get a working copy)\n"))
4530
4540
4531 @command('^pull',
4541 @command('^pull',
4532 [('u', 'update', None,
4542 [('u', 'update', None,
4533 _('update to new branch head if changesets were pulled')),
4543 _('update to new branch head if changesets were pulled')),
4534 ('f', 'force', None, _('run even when remote repository is unrelated')),
4544 ('f', 'force', None, _('run even when remote repository is unrelated')),
4535 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4545 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4536 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4546 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4537 ('b', 'branch', [], _('a specific branch you would like to pull'),
4547 ('b', 'branch', [], _('a specific branch you would like to pull'),
4538 _('BRANCH')),
4548 _('BRANCH')),
4539 ] + remoteopts,
4549 ] + remoteopts,
4540 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4550 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4541 def pull(ui, repo, source="default", **opts):
4551 def pull(ui, repo, source="default", **opts):
4542 """pull changes from the specified source
4552 """pull changes from the specified source
4543
4553
4544 Pull changes from a remote repository to a local one.
4554 Pull changes from a remote repository to a local one.
4545
4555
4546 This finds all changes from the repository at the specified path
4556 This finds all changes from the repository at the specified path
4547 or URL and adds them to a local repository (the current one unless
4557 or URL and adds them to a local repository (the current one unless
4548 -R is specified). By default, this does not update the copy of the
4558 -R is specified). By default, this does not update the copy of the
4549 project in the working directory.
4559 project in the working directory.
4550
4560
4551 Use :hg:`incoming` if you want to see what would have been added
4561 Use :hg:`incoming` if you want to see what would have been added
4552 by a pull at the time you issued this command. If you then decide
4562 by a pull at the time you issued this command. If you then decide
4553 to add those changes to the repository, you should use :hg:`pull
4563 to add those changes to the repository, you should use :hg:`pull
4554 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4564 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4555
4565
4556 If SOURCE is omitted, the 'default' path will be used.
4566 If SOURCE is omitted, the 'default' path will be used.
4557 See :hg:`help urls` for more information.
4567 See :hg:`help urls` for more information.
4558
4568
4559 Returns 0 on success, 1 if an update had unresolved files.
4569 Returns 0 on success, 1 if an update had unresolved files.
4560 """
4570 """
4561 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4571 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4562 other = hg.peer(repo, opts, source)
4572 other = hg.peer(repo, opts, source)
4563 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4573 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4564 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4574 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4565
4575
4566 if opts.get('bookmark'):
4576 if opts.get('bookmark'):
4567 if not revs:
4577 if not revs:
4568 revs = []
4578 revs = []
4569 rb = other.listkeys('bookmarks')
4579 rb = other.listkeys('bookmarks')
4570 for b in opts['bookmark']:
4580 for b in opts['bookmark']:
4571 if b not in rb:
4581 if b not in rb:
4572 raise util.Abort(_('remote bookmark %s not found!') % b)
4582 raise util.Abort(_('remote bookmark %s not found!') % b)
4573 revs.append(rb[b])
4583 revs.append(rb[b])
4574
4584
4575 if revs:
4585 if revs:
4576 try:
4586 try:
4577 revs = [other.lookup(rev) for rev in revs]
4587 revs = [other.lookup(rev) for rev in revs]
4578 except error.CapabilityError:
4588 except error.CapabilityError:
4579 err = _("other repository doesn't support revision lookup, "
4589 err = _("other repository doesn't support revision lookup, "
4580 "so a rev cannot be specified.")
4590 "so a rev cannot be specified.")
4581 raise util.Abort(err)
4591 raise util.Abort(err)
4582
4592
4583 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4593 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4584 bookmarks.updatefromremote(ui, repo, other, source)
4594 bookmarks.updatefromremote(ui, repo, other, source)
4585 if checkout:
4595 if checkout:
4586 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4596 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4587 repo._subtoppath = source
4597 repo._subtoppath = source
4588 try:
4598 try:
4589 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4599 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4590
4600
4591 finally:
4601 finally:
4592 del repo._subtoppath
4602 del repo._subtoppath
4593
4603
4594 # update specified bookmarks
4604 # update specified bookmarks
4595 if opts.get('bookmark'):
4605 if opts.get('bookmark'):
4596 for b in opts['bookmark']:
4606 for b in opts['bookmark']:
4597 # explicit pull overrides local bookmark if any
4607 # explicit pull overrides local bookmark if any
4598 ui.status(_("importing bookmark %s\n") % b)
4608 ui.status(_("importing bookmark %s\n") % b)
4599 repo._bookmarks[b] = repo[rb[b]].node()
4609 repo._bookmarks[b] = repo[rb[b]].node()
4600 bookmarks.write(repo)
4610 bookmarks.write(repo)
4601
4611
4602 return ret
4612 return ret
4603
4613
4604 @command('^push',
4614 @command('^push',
4605 [('f', 'force', None, _('force push')),
4615 [('f', 'force', None, _('force push')),
4606 ('r', 'rev', [],
4616 ('r', 'rev', [],
4607 _('a changeset intended to be included in the destination'),
4617 _('a changeset intended to be included in the destination'),
4608 _('REV')),
4618 _('REV')),
4609 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4619 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4610 ('b', 'branch', [],
4620 ('b', 'branch', [],
4611 _('a specific branch you would like to push'), _('BRANCH')),
4621 _('a specific branch you would like to push'), _('BRANCH')),
4612 ('', 'new-branch', False, _('allow pushing a new branch')),
4622 ('', 'new-branch', False, _('allow pushing a new branch')),
4613 ] + remoteopts,
4623 ] + remoteopts,
4614 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4624 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4615 def push(ui, repo, dest=None, **opts):
4625 def push(ui, repo, dest=None, **opts):
4616 """push changes to the specified destination
4626 """push changes to the specified destination
4617
4627
4618 Push changesets from the local repository to the specified
4628 Push changesets from the local repository to the specified
4619 destination.
4629 destination.
4620
4630
4621 This operation is symmetrical to pull: it is identical to a pull
4631 This operation is symmetrical to pull: it is identical to a pull
4622 in the destination repository from the current one.
4632 in the destination repository from the current one.
4623
4633
4624 By default, push will not allow creation of new heads at the
4634 By default, push will not allow creation of new heads at the
4625 destination, since multiple heads would make it unclear which head
4635 destination, since multiple heads would make it unclear which head
4626 to use. In this situation, it is recommended to pull and merge
4636 to use. In this situation, it is recommended to pull and merge
4627 before pushing.
4637 before pushing.
4628
4638
4629 Use --new-branch if you want to allow push to create a new named
4639 Use --new-branch if you want to allow push to create a new named
4630 branch that is not present at the destination. This allows you to
4640 branch that is not present at the destination. This allows you to
4631 only create a new branch without forcing other changes.
4641 only create a new branch without forcing other changes.
4632
4642
4633 Use -f/--force to override the default behavior and push all
4643 Use -f/--force to override the default behavior and push all
4634 changesets on all branches.
4644 changesets on all branches.
4635
4645
4636 If -r/--rev is used, the specified revision and all its ancestors
4646 If -r/--rev is used, the specified revision and all its ancestors
4637 will be pushed to the remote repository.
4647 will be pushed to the remote repository.
4638
4648
4639 If -B/--bookmark is used, the specified bookmarked revision, its
4649 If -B/--bookmark is used, the specified bookmarked revision, its
4640 ancestors, and the bookmark will be pushed to the remote
4650 ancestors, and the bookmark will be pushed to the remote
4641 repository.
4651 repository.
4642
4652
4643 Please see :hg:`help urls` for important details about ``ssh://``
4653 Please see :hg:`help urls` for important details about ``ssh://``
4644 URLs. If DESTINATION is omitted, a default path will be used.
4654 URLs. If DESTINATION is omitted, a default path will be used.
4645
4655
4646 Returns 0 if push was successful, 1 if nothing to push.
4656 Returns 0 if push was successful, 1 if nothing to push.
4647 """
4657 """
4648
4658
4649 if opts.get('bookmark'):
4659 if opts.get('bookmark'):
4650 for b in opts['bookmark']:
4660 for b in opts['bookmark']:
4651 # translate -B options to -r so changesets get pushed
4661 # translate -B options to -r so changesets get pushed
4652 if b in repo._bookmarks:
4662 if b in repo._bookmarks:
4653 opts.setdefault('rev', []).append(b)
4663 opts.setdefault('rev', []).append(b)
4654 else:
4664 else:
4655 # if we try to push a deleted bookmark, translate it to null
4665 # if we try to push a deleted bookmark, translate it to null
4656 # this lets simultaneous -r, -b options continue working
4666 # this lets simultaneous -r, -b options continue working
4657 opts.setdefault('rev', []).append("null")
4667 opts.setdefault('rev', []).append("null")
4658
4668
4659 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4669 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4660 dest, branches = hg.parseurl(dest, opts.get('branch'))
4670 dest, branches = hg.parseurl(dest, opts.get('branch'))
4661 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4671 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4662 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4672 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4663 other = hg.peer(repo, opts, dest)
4673 other = hg.peer(repo, opts, dest)
4664 if revs:
4674 if revs:
4665 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4675 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4666
4676
4667 repo._subtoppath = dest
4677 repo._subtoppath = dest
4668 try:
4678 try:
4669 # push subrepos depth-first for coherent ordering
4679 # push subrepos depth-first for coherent ordering
4670 c = repo['']
4680 c = repo['']
4671 subs = c.substate # only repos that are committed
4681 subs = c.substate # only repos that are committed
4672 for s in sorted(subs):
4682 for s in sorted(subs):
4673 if c.sub(s).push(opts) == 0:
4683 if c.sub(s).push(opts) == 0:
4674 return False
4684 return False
4675 finally:
4685 finally:
4676 del repo._subtoppath
4686 del repo._subtoppath
4677 result = repo.push(other, opts.get('force'), revs=revs,
4687 result = repo.push(other, opts.get('force'), revs=revs,
4678 newbranch=opts.get('new_branch'))
4688 newbranch=opts.get('new_branch'))
4679
4689
4680 result = not result
4690 result = not result
4681
4691
4682 if opts.get('bookmark'):
4692 if opts.get('bookmark'):
4683 rb = other.listkeys('bookmarks')
4693 rb = other.listkeys('bookmarks')
4684 for b in opts['bookmark']:
4694 for b in opts['bookmark']:
4685 # explicit push overrides remote bookmark if any
4695 # explicit push overrides remote bookmark if any
4686 if b in repo._bookmarks:
4696 if b in repo._bookmarks:
4687 ui.status(_("exporting bookmark %s\n") % b)
4697 ui.status(_("exporting bookmark %s\n") % b)
4688 new = repo[b].hex()
4698 new = repo[b].hex()
4689 elif b in rb:
4699 elif b in rb:
4690 ui.status(_("deleting remote bookmark %s\n") % b)
4700 ui.status(_("deleting remote bookmark %s\n") % b)
4691 new = '' # delete
4701 new = '' # delete
4692 else:
4702 else:
4693 ui.warn(_('bookmark %s does not exist on the local '
4703 ui.warn(_('bookmark %s does not exist on the local '
4694 'or remote repository!\n') % b)
4704 'or remote repository!\n') % b)
4695 return 2
4705 return 2
4696 old = rb.get(b, '')
4706 old = rb.get(b, '')
4697 r = other.pushkey('bookmarks', b, old, new)
4707 r = other.pushkey('bookmarks', b, old, new)
4698 if not r:
4708 if not r:
4699 ui.warn(_('updating bookmark %s failed!\n') % b)
4709 ui.warn(_('updating bookmark %s failed!\n') % b)
4700 if not result:
4710 if not result:
4701 result = 2
4711 result = 2
4702
4712
4703 return result
4713 return result
4704
4714
4705 @command('recover', [])
4715 @command('recover', [])
4706 def recover(ui, repo):
4716 def recover(ui, repo):
4707 """roll back an interrupted transaction
4717 """roll back an interrupted transaction
4708
4718
4709 Recover from an interrupted commit or pull.
4719 Recover from an interrupted commit or pull.
4710
4720
4711 This command tries to fix the repository status after an
4721 This command tries to fix the repository status after an
4712 interrupted operation. It should only be necessary when Mercurial
4722 interrupted operation. It should only be necessary when Mercurial
4713 suggests it.
4723 suggests it.
4714
4724
4715 Returns 0 if successful, 1 if nothing to recover or verify fails.
4725 Returns 0 if successful, 1 if nothing to recover or verify fails.
4716 """
4726 """
4717 if repo.recover():
4727 if repo.recover():
4718 return hg.verify(repo)
4728 return hg.verify(repo)
4719 return 1
4729 return 1
4720
4730
4721 @command('^remove|rm',
4731 @command('^remove|rm',
4722 [('A', 'after', None, _('record delete for missing files')),
4732 [('A', 'after', None, _('record delete for missing files')),
4723 ('f', 'force', None,
4733 ('f', 'force', None,
4724 _('remove (and delete) file even if added or modified')),
4734 _('remove (and delete) file even if added or modified')),
4725 ] + walkopts,
4735 ] + walkopts,
4726 _('[OPTION]... FILE...'))
4736 _('[OPTION]... FILE...'))
4727 def remove(ui, repo, *pats, **opts):
4737 def remove(ui, repo, *pats, **opts):
4728 """remove the specified files on the next commit
4738 """remove the specified files on the next commit
4729
4739
4730 Schedule the indicated files for removal from the current branch.
4740 Schedule the indicated files for removal from the current branch.
4731
4741
4732 This command schedules the files to be removed at the next commit.
4742 This command schedules the files to be removed at the next commit.
4733 To undo a remove before that, see :hg:`revert`. To undo added
4743 To undo a remove before that, see :hg:`revert`. To undo added
4734 files, see :hg:`forget`.
4744 files, see :hg:`forget`.
4735
4745
4736 .. container:: verbose
4746 .. container:: verbose
4737
4747
4738 -A/--after can be used to remove only files that have already
4748 -A/--after can be used to remove only files that have already
4739 been deleted, -f/--force can be used to force deletion, and -Af
4749 been deleted, -f/--force can be used to force deletion, and -Af
4740 can be used to remove files from the next revision without
4750 can be used to remove files from the next revision without
4741 deleting them from the working directory.
4751 deleting them from the working directory.
4742
4752
4743 The following table details the behavior of remove for different
4753 The following table details the behavior of remove for different
4744 file states (columns) and option combinations (rows). The file
4754 file states (columns) and option combinations (rows). The file
4745 states are Added [A], Clean [C], Modified [M] and Missing [!]
4755 states are Added [A], Clean [C], Modified [M] and Missing [!]
4746 (as reported by :hg:`status`). The actions are Warn, Remove
4756 (as reported by :hg:`status`). The actions are Warn, Remove
4747 (from branch) and Delete (from disk):
4757 (from branch) and Delete (from disk):
4748
4758
4749 ======= == == == ==
4759 ======= == == == ==
4750 A C M !
4760 A C M !
4751 ======= == == == ==
4761 ======= == == == ==
4752 none W RD W R
4762 none W RD W R
4753 -f R RD RD R
4763 -f R RD RD R
4754 -A W W W R
4764 -A W W W R
4755 -Af R R R R
4765 -Af R R R R
4756 ======= == == == ==
4766 ======= == == == ==
4757
4767
4758 Note that remove never deletes files in Added [A] state from the
4768 Note that remove never deletes files in Added [A] state from the
4759 working directory, not even if option --force is specified.
4769 working directory, not even if option --force is specified.
4760
4770
4761 Returns 0 on success, 1 if any warnings encountered.
4771 Returns 0 on success, 1 if any warnings encountered.
4762 """
4772 """
4763
4773
4764 ret = 0
4774 ret = 0
4765 after, force = opts.get('after'), opts.get('force')
4775 after, force = opts.get('after'), opts.get('force')
4766 if not pats and not after:
4776 if not pats and not after:
4767 raise util.Abort(_('no files specified'))
4777 raise util.Abort(_('no files specified'))
4768
4778
4769 m = scmutil.match(repo[None], pats, opts)
4779 m = scmutil.match(repo[None], pats, opts)
4770 s = repo.status(match=m, clean=True)
4780 s = repo.status(match=m, clean=True)
4771 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4781 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4772
4782
4773 for f in m.files():
4783 for f in m.files():
4774 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4784 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4775 if os.path.exists(m.rel(f)):
4785 if os.path.exists(m.rel(f)):
4776 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4786 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4777 ret = 1
4787 ret = 1
4778
4788
4779 if force:
4789 if force:
4780 list = modified + deleted + clean + added
4790 list = modified + deleted + clean + added
4781 elif after:
4791 elif after:
4782 list = deleted
4792 list = deleted
4783 for f in modified + added + clean:
4793 for f in modified + added + clean:
4784 ui.warn(_('not removing %s: file still exists (use -f'
4794 ui.warn(_('not removing %s: file still exists (use -f'
4785 ' to force removal)\n') % m.rel(f))
4795 ' to force removal)\n') % m.rel(f))
4786 ret = 1
4796 ret = 1
4787 else:
4797 else:
4788 list = deleted + clean
4798 list = deleted + clean
4789 for f in modified:
4799 for f in modified:
4790 ui.warn(_('not removing %s: file is modified (use -f'
4800 ui.warn(_('not removing %s: file is modified (use -f'
4791 ' to force removal)\n') % m.rel(f))
4801 ' to force removal)\n') % m.rel(f))
4792 ret = 1
4802 ret = 1
4793 for f in added:
4803 for f in added:
4794 ui.warn(_('not removing %s: file has been marked for add'
4804 ui.warn(_('not removing %s: file has been marked for add'
4795 ' (use forget to undo)\n') % m.rel(f))
4805 ' (use forget to undo)\n') % m.rel(f))
4796 ret = 1
4806 ret = 1
4797
4807
4798 for f in sorted(list):
4808 for f in sorted(list):
4799 if ui.verbose or not m.exact(f):
4809 if ui.verbose or not m.exact(f):
4800 ui.status(_('removing %s\n') % m.rel(f))
4810 ui.status(_('removing %s\n') % m.rel(f))
4801
4811
4802 wlock = repo.wlock()
4812 wlock = repo.wlock()
4803 try:
4813 try:
4804 if not after:
4814 if not after:
4805 for f in list:
4815 for f in list:
4806 if f in added:
4816 if f in added:
4807 continue # we never unlink added files on remove
4817 continue # we never unlink added files on remove
4808 try:
4818 try:
4809 util.unlinkpath(repo.wjoin(f))
4819 util.unlinkpath(repo.wjoin(f))
4810 except OSError, inst:
4820 except OSError, inst:
4811 if inst.errno != errno.ENOENT:
4821 if inst.errno != errno.ENOENT:
4812 raise
4822 raise
4813 repo[None].forget(list)
4823 repo[None].forget(list)
4814 finally:
4824 finally:
4815 wlock.release()
4825 wlock.release()
4816
4826
4817 return ret
4827 return ret
4818
4828
4819 @command('rename|move|mv',
4829 @command('rename|move|mv',
4820 [('A', 'after', None, _('record a rename that has already occurred')),
4830 [('A', 'after', None, _('record a rename that has already occurred')),
4821 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4831 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4822 ] + walkopts + dryrunopts,
4832 ] + walkopts + dryrunopts,
4823 _('[OPTION]... SOURCE... DEST'))
4833 _('[OPTION]... SOURCE... DEST'))
4824 def rename(ui, repo, *pats, **opts):
4834 def rename(ui, repo, *pats, **opts):
4825 """rename files; equivalent of copy + remove
4835 """rename files; equivalent of copy + remove
4826
4836
4827 Mark dest as copies of sources; mark sources for deletion. If dest
4837 Mark dest as copies of sources; mark sources for deletion. If dest
4828 is a directory, copies are put in that directory. If dest is a
4838 is a directory, copies are put in that directory. If dest is a
4829 file, there can only be one source.
4839 file, there can only be one source.
4830
4840
4831 By default, this command copies the contents of files as they
4841 By default, this command copies the contents of files as they
4832 exist in the working directory. If invoked with -A/--after, the
4842 exist in the working directory. If invoked with -A/--after, the
4833 operation is recorded, but no copying is performed.
4843 operation is recorded, but no copying is performed.
4834
4844
4835 This command takes effect at the next commit. To undo a rename
4845 This command takes effect at the next commit. To undo a rename
4836 before that, see :hg:`revert`.
4846 before that, see :hg:`revert`.
4837
4847
4838 Returns 0 on success, 1 if errors are encountered.
4848 Returns 0 on success, 1 if errors are encountered.
4839 """
4849 """
4840 wlock = repo.wlock(False)
4850 wlock = repo.wlock(False)
4841 try:
4851 try:
4842 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4852 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4843 finally:
4853 finally:
4844 wlock.release()
4854 wlock.release()
4845
4855
4846 @command('resolve',
4856 @command('resolve',
4847 [('a', 'all', None, _('select all unresolved files')),
4857 [('a', 'all', None, _('select all unresolved files')),
4848 ('l', 'list', None, _('list state of files needing merge')),
4858 ('l', 'list', None, _('list state of files needing merge')),
4849 ('m', 'mark', None, _('mark files as resolved')),
4859 ('m', 'mark', None, _('mark files as resolved')),
4850 ('u', 'unmark', None, _('mark files as unresolved')),
4860 ('u', 'unmark', None, _('mark files as unresolved')),
4851 ('n', 'no-status', None, _('hide status prefix'))]
4861 ('n', 'no-status', None, _('hide status prefix'))]
4852 + mergetoolopts + walkopts,
4862 + mergetoolopts + walkopts,
4853 _('[OPTION]... [FILE]...'))
4863 _('[OPTION]... [FILE]...'))
4854 def resolve(ui, repo, *pats, **opts):
4864 def resolve(ui, repo, *pats, **opts):
4855 """redo merges or set/view the merge status of files
4865 """redo merges or set/view the merge status of files
4856
4866
4857 Merges with unresolved conflicts are often the result of
4867 Merges with unresolved conflicts are often the result of
4858 non-interactive merging using the ``internal:merge`` configuration
4868 non-interactive merging using the ``internal:merge`` configuration
4859 setting, or a command-line merge tool like ``diff3``. The resolve
4869 setting, or a command-line merge tool like ``diff3``. The resolve
4860 command is used to manage the files involved in a merge, after
4870 command is used to manage the files involved in a merge, after
4861 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4871 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4862 working directory must have two parents). See :hg:`help
4872 working directory must have two parents). See :hg:`help
4863 merge-tools` for information on configuring merge tools.
4873 merge-tools` for information on configuring merge tools.
4864
4874
4865 The resolve command can be used in the following ways:
4875 The resolve command can be used in the following ways:
4866
4876
4867 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4877 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4868 files, discarding any previous merge attempts. Re-merging is not
4878 files, discarding any previous merge attempts. Re-merging is not
4869 performed for files already marked as resolved. Use ``--all/-a``
4879 performed for files already marked as resolved. Use ``--all/-a``
4870 to select all unresolved files. ``--tool`` can be used to specify
4880 to select all unresolved files. ``--tool`` can be used to specify
4871 the merge tool used for the given files. It overrides the HGMERGE
4881 the merge tool used for the given files. It overrides the HGMERGE
4872 environment variable and your configuration files. Previous file
4882 environment variable and your configuration files. Previous file
4873 contents are saved with a ``.orig`` suffix.
4883 contents are saved with a ``.orig`` suffix.
4874
4884
4875 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4885 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4876 (e.g. after having manually fixed-up the files). The default is
4886 (e.g. after having manually fixed-up the files). The default is
4877 to mark all unresolved files.
4887 to mark all unresolved files.
4878
4888
4879 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4889 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4880 default is to mark all resolved files.
4890 default is to mark all resolved files.
4881
4891
4882 - :hg:`resolve -l`: list files which had or still have conflicts.
4892 - :hg:`resolve -l`: list files which had or still have conflicts.
4883 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4893 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4884
4894
4885 Note that Mercurial will not let you commit files with unresolved
4895 Note that Mercurial will not let you commit files with unresolved
4886 merge conflicts. You must use :hg:`resolve -m ...` before you can
4896 merge conflicts. You must use :hg:`resolve -m ...` before you can
4887 commit after a conflicting merge.
4897 commit after a conflicting merge.
4888
4898
4889 Returns 0 on success, 1 if any files fail a resolve attempt.
4899 Returns 0 on success, 1 if any files fail a resolve attempt.
4890 """
4900 """
4891
4901
4892 all, mark, unmark, show, nostatus = \
4902 all, mark, unmark, show, nostatus = \
4893 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4903 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4894
4904
4895 if (show and (mark or unmark)) or (mark and unmark):
4905 if (show and (mark or unmark)) or (mark and unmark):
4896 raise util.Abort(_("too many options specified"))
4906 raise util.Abort(_("too many options specified"))
4897 if pats and all:
4907 if pats and all:
4898 raise util.Abort(_("can't specify --all and patterns"))
4908 raise util.Abort(_("can't specify --all and patterns"))
4899 if not (all or pats or show or mark or unmark):
4909 if not (all or pats or show or mark or unmark):
4900 raise util.Abort(_('no files or directories specified; '
4910 raise util.Abort(_('no files or directories specified; '
4901 'use --all to remerge all files'))
4911 'use --all to remerge all files'))
4902
4912
4903 ms = mergemod.mergestate(repo)
4913 ms = mergemod.mergestate(repo)
4904 m = scmutil.match(repo[None], pats, opts)
4914 m = scmutil.match(repo[None], pats, opts)
4905 ret = 0
4915 ret = 0
4906
4916
4907 for f in ms:
4917 for f in ms:
4908 if m(f):
4918 if m(f):
4909 if show:
4919 if show:
4910 if nostatus:
4920 if nostatus:
4911 ui.write("%s\n" % f)
4921 ui.write("%s\n" % f)
4912 else:
4922 else:
4913 ui.write("%s %s\n" % (ms[f].upper(), f),
4923 ui.write("%s %s\n" % (ms[f].upper(), f),
4914 label='resolve.' +
4924 label='resolve.' +
4915 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4925 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4916 elif mark:
4926 elif mark:
4917 ms.mark(f, "r")
4927 ms.mark(f, "r")
4918 elif unmark:
4928 elif unmark:
4919 ms.mark(f, "u")
4929 ms.mark(f, "u")
4920 else:
4930 else:
4921 wctx = repo[None]
4931 wctx = repo[None]
4922 mctx = wctx.parents()[-1]
4932 mctx = wctx.parents()[-1]
4923
4933
4924 # backup pre-resolve (merge uses .orig for its own purposes)
4934 # backup pre-resolve (merge uses .orig for its own purposes)
4925 a = repo.wjoin(f)
4935 a = repo.wjoin(f)
4926 util.copyfile(a, a + ".resolve")
4936 util.copyfile(a, a + ".resolve")
4927
4937
4928 try:
4938 try:
4929 # resolve file
4939 # resolve file
4930 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4940 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4931 if ms.resolve(f, wctx, mctx):
4941 if ms.resolve(f, wctx, mctx):
4932 ret = 1
4942 ret = 1
4933 finally:
4943 finally:
4934 ui.setconfig('ui', 'forcemerge', '')
4944 ui.setconfig('ui', 'forcemerge', '')
4935
4945
4936 # replace filemerge's .orig file with our resolve file
4946 # replace filemerge's .orig file with our resolve file
4937 util.rename(a + ".resolve", a + ".orig")
4947 util.rename(a + ".resolve", a + ".orig")
4938
4948
4939 ms.commit()
4949 ms.commit()
4940 return ret
4950 return ret
4941
4951
4942 @command('revert',
4952 @command('revert',
4943 [('a', 'all', None, _('revert all changes when no arguments given')),
4953 [('a', 'all', None, _('revert all changes when no arguments given')),
4944 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4954 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4945 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4955 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4946 ('C', 'no-backup', None, _('do not save backup copies of files')),
4956 ('C', 'no-backup', None, _('do not save backup copies of files')),
4947 ] + walkopts + dryrunopts,
4957 ] + walkopts + dryrunopts,
4948 _('[OPTION]... [-r REV] [NAME]...'))
4958 _('[OPTION]... [-r REV] [NAME]...'))
4949 def revert(ui, repo, *pats, **opts):
4959 def revert(ui, repo, *pats, **opts):
4950 """restore files to their checkout state
4960 """restore files to their checkout state
4951
4961
4952 .. note::
4962 .. note::
4953
4963
4954 To check out earlier revisions, you should use :hg:`update REV`.
4964 To check out earlier revisions, you should use :hg:`update REV`.
4955 To cancel an uncommitted merge (and lose your changes), use
4965 To cancel an uncommitted merge (and lose your changes), use
4956 :hg:`update --clean .`.
4966 :hg:`update --clean .`.
4957
4967
4958 With no revision specified, revert the specified files or directories
4968 With no revision specified, revert the specified files or directories
4959 to the contents they had in the parent of the working directory.
4969 to the contents they had in the parent of the working directory.
4960 This restores the contents of files to an unmodified
4970 This restores the contents of files to an unmodified
4961 state and unschedules adds, removes, copies, and renames. If the
4971 state and unschedules adds, removes, copies, and renames. If the
4962 working directory has two parents, you must explicitly specify a
4972 working directory has two parents, you must explicitly specify a
4963 revision.
4973 revision.
4964
4974
4965 Using the -r/--rev or -d/--date options, revert the given files or
4975 Using the -r/--rev or -d/--date options, revert the given files or
4966 directories to their states as of a specific revision. Because
4976 directories to their states as of a specific revision. Because
4967 revert does not change the working directory parents, this will
4977 revert does not change the working directory parents, this will
4968 cause these files to appear modified. This can be helpful to "back
4978 cause these files to appear modified. This can be helpful to "back
4969 out" some or all of an earlier change. See :hg:`backout` for a
4979 out" some or all of an earlier change. See :hg:`backout` for a
4970 related method.
4980 related method.
4971
4981
4972 Modified files are saved with a .orig suffix before reverting.
4982 Modified files are saved with a .orig suffix before reverting.
4973 To disable these backups, use --no-backup.
4983 To disable these backups, use --no-backup.
4974
4984
4975 See :hg:`help dates` for a list of formats valid for -d/--date.
4985 See :hg:`help dates` for a list of formats valid for -d/--date.
4976
4986
4977 Returns 0 on success.
4987 Returns 0 on success.
4978 """
4988 """
4979
4989
4980 if opts.get("date"):
4990 if opts.get("date"):
4981 if opts.get("rev"):
4991 if opts.get("rev"):
4982 raise util.Abort(_("you can't specify a revision and a date"))
4992 raise util.Abort(_("you can't specify a revision and a date"))
4983 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4993 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4984
4994
4985 parent, p2 = repo.dirstate.parents()
4995 parent, p2 = repo.dirstate.parents()
4986 if not opts.get('rev') and p2 != nullid:
4996 if not opts.get('rev') and p2 != nullid:
4987 # revert after merge is a trap for new users (issue2915)
4997 # revert after merge is a trap for new users (issue2915)
4988 raise util.Abort(_('uncommitted merge with no revision specified'),
4998 raise util.Abort(_('uncommitted merge with no revision specified'),
4989 hint=_('use "hg update" or see "hg help revert"'))
4999 hint=_('use "hg update" or see "hg help revert"'))
4990
5000
4991 ctx = scmutil.revsingle(repo, opts.get('rev'))
5001 ctx = scmutil.revsingle(repo, opts.get('rev'))
4992
5002
4993 if not pats and not opts.get('all'):
5003 if not pats and not opts.get('all'):
4994 msg = _("no files or directories specified")
5004 msg = _("no files or directories specified")
4995 if p2 != nullid:
5005 if p2 != nullid:
4996 hint = _("uncommitted merge, use --all to discard all changes,"
5006 hint = _("uncommitted merge, use --all to discard all changes,"
4997 " or 'hg update -C .' to abort the merge")
5007 " or 'hg update -C .' to abort the merge")
4998 raise util.Abort(msg, hint=hint)
5008 raise util.Abort(msg, hint=hint)
4999 dirty = util.any(repo.status())
5009 dirty = util.any(repo.status())
5000 node = ctx.node()
5010 node = ctx.node()
5001 if node != parent:
5011 if node != parent:
5002 if dirty:
5012 if dirty:
5003 hint = _("uncommitted changes, use --all to discard all"
5013 hint = _("uncommitted changes, use --all to discard all"
5004 " changes, or 'hg update %s' to update") % ctx.rev()
5014 " changes, or 'hg update %s' to update") % ctx.rev()
5005 else:
5015 else:
5006 hint = _("use --all to revert all files,"
5016 hint = _("use --all to revert all files,"
5007 " or 'hg update %s' to update") % ctx.rev()
5017 " or 'hg update %s' to update") % ctx.rev()
5008 elif dirty:
5018 elif dirty:
5009 hint = _("uncommitted changes, use --all to discard all changes")
5019 hint = _("uncommitted changes, use --all to discard all changes")
5010 else:
5020 else:
5011 hint = _("use --all to revert all files")
5021 hint = _("use --all to revert all files")
5012 raise util.Abort(msg, hint=hint)
5022 raise util.Abort(msg, hint=hint)
5013
5023
5014 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5024 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5015
5025
5016 @command('rollback', dryrunopts +
5026 @command('rollback', dryrunopts +
5017 [('f', 'force', False, _('ignore safety measures'))])
5027 [('f', 'force', False, _('ignore safety measures'))])
5018 def rollback(ui, repo, **opts):
5028 def rollback(ui, repo, **opts):
5019 """roll back the last transaction (dangerous)
5029 """roll back the last transaction (dangerous)
5020
5030
5021 This command should be used with care. There is only one level of
5031 This command should be used with care. There is only one level of
5022 rollback, and there is no way to undo a rollback. It will also
5032 rollback, and there is no way to undo a rollback. It will also
5023 restore the dirstate at the time of the last transaction, losing
5033 restore the dirstate at the time of the last transaction, losing
5024 any dirstate changes since that time. This command does not alter
5034 any dirstate changes since that time. This command does not alter
5025 the working directory.
5035 the working directory.
5026
5036
5027 Transactions are used to encapsulate the effects of all commands
5037 Transactions are used to encapsulate the effects of all commands
5028 that create new changesets or propagate existing changesets into a
5038 that create new changesets or propagate existing changesets into a
5029 repository.
5039 repository.
5030
5040
5031 .. container:: verbose
5041 .. container:: verbose
5032
5042
5033 For example, the following commands are transactional, and their
5043 For example, the following commands are transactional, and their
5034 effects can be rolled back:
5044 effects can be rolled back:
5035
5045
5036 - commit
5046 - commit
5037 - import
5047 - import
5038 - pull
5048 - pull
5039 - push (with this repository as the destination)
5049 - push (with this repository as the destination)
5040 - unbundle
5050 - unbundle
5041
5051
5042 To avoid permanent data loss, rollback will refuse to rollback a
5052 To avoid permanent data loss, rollback will refuse to rollback a
5043 commit transaction if it isn't checked out. Use --force to
5053 commit transaction if it isn't checked out. Use --force to
5044 override this protection.
5054 override this protection.
5045
5055
5046 This command is not intended for use on public repositories. Once
5056 This command is not intended for use on public repositories. Once
5047 changes are visible for pull by other users, rolling a transaction
5057 changes are visible for pull by other users, rolling a transaction
5048 back locally is ineffective (someone else may already have pulled
5058 back locally is ineffective (someone else may already have pulled
5049 the changes). Furthermore, a race is possible with readers of the
5059 the changes). Furthermore, a race is possible with readers of the
5050 repository; for example an in-progress pull from the repository
5060 repository; for example an in-progress pull from the repository
5051 may fail if a rollback is performed.
5061 may fail if a rollback is performed.
5052
5062
5053 Returns 0 on success, 1 if no rollback data is available.
5063 Returns 0 on success, 1 if no rollback data is available.
5054 """
5064 """
5055 return repo.rollback(dryrun=opts.get('dry_run'),
5065 return repo.rollback(dryrun=opts.get('dry_run'),
5056 force=opts.get('force'))
5066 force=opts.get('force'))
5057
5067
5058 @command('root', [])
5068 @command('root', [])
5059 def root(ui, repo):
5069 def root(ui, repo):
5060 """print the root (top) of the current working directory
5070 """print the root (top) of the current working directory
5061
5071
5062 Print the root directory of the current repository.
5072 Print the root directory of the current repository.
5063
5073
5064 Returns 0 on success.
5074 Returns 0 on success.
5065 """
5075 """
5066 ui.write(repo.root + "\n")
5076 ui.write(repo.root + "\n")
5067
5077
5068 @command('^serve',
5078 @command('^serve',
5069 [('A', 'accesslog', '', _('name of access log file to write to'),
5079 [('A', 'accesslog', '', _('name of access log file to write to'),
5070 _('FILE')),
5080 _('FILE')),
5071 ('d', 'daemon', None, _('run server in background')),
5081 ('d', 'daemon', None, _('run server in background')),
5072 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5082 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5073 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5083 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5074 # use string type, then we can check if something was passed
5084 # use string type, then we can check if something was passed
5075 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5085 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5076 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5086 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5077 _('ADDR')),
5087 _('ADDR')),
5078 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5088 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5079 _('PREFIX')),
5089 _('PREFIX')),
5080 ('n', 'name', '',
5090 ('n', 'name', '',
5081 _('name to show in web pages (default: working directory)'), _('NAME')),
5091 _('name to show in web pages (default: working directory)'), _('NAME')),
5082 ('', 'web-conf', '',
5092 ('', 'web-conf', '',
5083 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5093 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5084 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5094 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5085 _('FILE')),
5095 _('FILE')),
5086 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5096 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5087 ('', 'stdio', None, _('for remote clients')),
5097 ('', 'stdio', None, _('for remote clients')),
5088 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5098 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5089 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5099 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5090 ('', 'style', '', _('template style to use'), _('STYLE')),
5100 ('', 'style', '', _('template style to use'), _('STYLE')),
5091 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5101 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5092 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5102 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5093 _('[OPTION]...'))
5103 _('[OPTION]...'))
5094 def serve(ui, repo, **opts):
5104 def serve(ui, repo, **opts):
5095 """start stand-alone webserver
5105 """start stand-alone webserver
5096
5106
5097 Start a local HTTP repository browser and pull server. You can use
5107 Start a local HTTP repository browser and pull server. You can use
5098 this for ad-hoc sharing and browsing of repositories. It is
5108 this for ad-hoc sharing and browsing of repositories. It is
5099 recommended to use a real web server to serve a repository for
5109 recommended to use a real web server to serve a repository for
5100 longer periods of time.
5110 longer periods of time.
5101
5111
5102 Please note that the server does not implement access control.
5112 Please note that the server does not implement access control.
5103 This means that, by default, anybody can read from the server and
5113 This means that, by default, anybody can read from the server and
5104 nobody can write to it by default. Set the ``web.allow_push``
5114 nobody can write to it by default. Set the ``web.allow_push``
5105 option to ``*`` to allow everybody to push to the server. You
5115 option to ``*`` to allow everybody to push to the server. You
5106 should use a real web server if you need to authenticate users.
5116 should use a real web server if you need to authenticate users.
5107
5117
5108 By default, the server logs accesses to stdout and errors to
5118 By default, the server logs accesses to stdout and errors to
5109 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5119 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5110 files.
5120 files.
5111
5121
5112 To have the server choose a free port number to listen on, specify
5122 To have the server choose a free port number to listen on, specify
5113 a port number of 0; in this case, the server will print the port
5123 a port number of 0; in this case, the server will print the port
5114 number it uses.
5124 number it uses.
5115
5125
5116 Returns 0 on success.
5126 Returns 0 on success.
5117 """
5127 """
5118
5128
5119 if opts["stdio"] and opts["cmdserver"]:
5129 if opts["stdio"] and opts["cmdserver"]:
5120 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5130 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5121
5131
5122 def checkrepo():
5132 def checkrepo():
5123 if repo is None:
5133 if repo is None:
5124 raise error.RepoError(_("there is no Mercurial repository here"
5134 raise error.RepoError(_("there is no Mercurial repository here"
5125 " (.hg not found)"))
5135 " (.hg not found)"))
5126
5136
5127 if opts["stdio"]:
5137 if opts["stdio"]:
5128 checkrepo()
5138 checkrepo()
5129 s = sshserver.sshserver(ui, repo)
5139 s = sshserver.sshserver(ui, repo)
5130 s.serve_forever()
5140 s.serve_forever()
5131
5141
5132 if opts["cmdserver"]:
5142 if opts["cmdserver"]:
5133 checkrepo()
5143 checkrepo()
5134 s = commandserver.server(ui, repo, opts["cmdserver"])
5144 s = commandserver.server(ui, repo, opts["cmdserver"])
5135 return s.serve()
5145 return s.serve()
5136
5146
5137 # this way we can check if something was given in the command-line
5147 # this way we can check if something was given in the command-line
5138 if opts.get('port'):
5148 if opts.get('port'):
5139 opts['port'] = util.getport(opts.get('port'))
5149 opts['port'] = util.getport(opts.get('port'))
5140
5150
5141 baseui = repo and repo.baseui or ui
5151 baseui = repo and repo.baseui or ui
5142 optlist = ("name templates style address port prefix ipv6"
5152 optlist = ("name templates style address port prefix ipv6"
5143 " accesslog errorlog certificate encoding")
5153 " accesslog errorlog certificate encoding")
5144 for o in optlist.split():
5154 for o in optlist.split():
5145 val = opts.get(o, '')
5155 val = opts.get(o, '')
5146 if val in (None, ''): # should check against default options instead
5156 if val in (None, ''): # should check against default options instead
5147 continue
5157 continue
5148 baseui.setconfig("web", o, val)
5158 baseui.setconfig("web", o, val)
5149 if repo and repo.ui != baseui:
5159 if repo and repo.ui != baseui:
5150 repo.ui.setconfig("web", o, val)
5160 repo.ui.setconfig("web", o, val)
5151
5161
5152 o = opts.get('web_conf') or opts.get('webdir_conf')
5162 o = opts.get('web_conf') or opts.get('webdir_conf')
5153 if not o:
5163 if not o:
5154 if not repo:
5164 if not repo:
5155 raise error.RepoError(_("there is no Mercurial repository"
5165 raise error.RepoError(_("there is no Mercurial repository"
5156 " here (.hg not found)"))
5166 " here (.hg not found)"))
5157 o = repo.root
5167 o = repo.root
5158
5168
5159 app = hgweb.hgweb(o, baseui=ui)
5169 app = hgweb.hgweb(o, baseui=ui)
5160
5170
5161 class service(object):
5171 class service(object):
5162 def init(self):
5172 def init(self):
5163 util.setsignalhandler()
5173 util.setsignalhandler()
5164 self.httpd = hgweb.server.create_server(ui, app)
5174 self.httpd = hgweb.server.create_server(ui, app)
5165
5175
5166 if opts['port'] and not ui.verbose:
5176 if opts['port'] and not ui.verbose:
5167 return
5177 return
5168
5178
5169 if self.httpd.prefix:
5179 if self.httpd.prefix:
5170 prefix = self.httpd.prefix.strip('/') + '/'
5180 prefix = self.httpd.prefix.strip('/') + '/'
5171 else:
5181 else:
5172 prefix = ''
5182 prefix = ''
5173
5183
5174 port = ':%d' % self.httpd.port
5184 port = ':%d' % self.httpd.port
5175 if port == ':80':
5185 if port == ':80':
5176 port = ''
5186 port = ''
5177
5187
5178 bindaddr = self.httpd.addr
5188 bindaddr = self.httpd.addr
5179 if bindaddr == '0.0.0.0':
5189 if bindaddr == '0.0.0.0':
5180 bindaddr = '*'
5190 bindaddr = '*'
5181 elif ':' in bindaddr: # IPv6
5191 elif ':' in bindaddr: # IPv6
5182 bindaddr = '[%s]' % bindaddr
5192 bindaddr = '[%s]' % bindaddr
5183
5193
5184 fqaddr = self.httpd.fqaddr
5194 fqaddr = self.httpd.fqaddr
5185 if ':' in fqaddr:
5195 if ':' in fqaddr:
5186 fqaddr = '[%s]' % fqaddr
5196 fqaddr = '[%s]' % fqaddr
5187 if opts['port']:
5197 if opts['port']:
5188 write = ui.status
5198 write = ui.status
5189 else:
5199 else:
5190 write = ui.write
5200 write = ui.write
5191 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5201 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5192 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5202 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5193
5203
5194 def run(self):
5204 def run(self):
5195 self.httpd.serve_forever()
5205 self.httpd.serve_forever()
5196
5206
5197 service = service()
5207 service = service()
5198
5208
5199 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5209 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5200
5210
5201 @command('showconfig|debugconfig',
5211 @command('showconfig|debugconfig',
5202 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5212 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5203 _('[-u] [NAME]...'))
5213 _('[-u] [NAME]...'))
5204 def showconfig(ui, repo, *values, **opts):
5214 def showconfig(ui, repo, *values, **opts):
5205 """show combined config settings from all hgrc files
5215 """show combined config settings from all hgrc files
5206
5216
5207 With no arguments, print names and values of all config items.
5217 With no arguments, print names and values of all config items.
5208
5218
5209 With one argument of the form section.name, print just the value
5219 With one argument of the form section.name, print just the value
5210 of that config item.
5220 of that config item.
5211
5221
5212 With multiple arguments, print names and values of all config
5222 With multiple arguments, print names and values of all config
5213 items with matching section names.
5223 items with matching section names.
5214
5224
5215 With --debug, the source (filename and line number) is printed
5225 With --debug, the source (filename and line number) is printed
5216 for each config item.
5226 for each config item.
5217
5227
5218 Returns 0 on success.
5228 Returns 0 on success.
5219 """
5229 """
5220
5230
5221 for f in scmutil.rcpath():
5231 for f in scmutil.rcpath():
5222 ui.debug('read config from: %s\n' % f)
5232 ui.debug('read config from: %s\n' % f)
5223 untrusted = bool(opts.get('untrusted'))
5233 untrusted = bool(opts.get('untrusted'))
5224 if values:
5234 if values:
5225 sections = [v for v in values if '.' not in v]
5235 sections = [v for v in values if '.' not in v]
5226 items = [v for v in values if '.' in v]
5236 items = [v for v in values if '.' in v]
5227 if len(items) > 1 or items and sections:
5237 if len(items) > 1 or items and sections:
5228 raise util.Abort(_('only one config item permitted'))
5238 raise util.Abort(_('only one config item permitted'))
5229 for section, name, value in ui.walkconfig(untrusted=untrusted):
5239 for section, name, value in ui.walkconfig(untrusted=untrusted):
5230 value = str(value).replace('\n', '\\n')
5240 value = str(value).replace('\n', '\\n')
5231 sectname = section + '.' + name
5241 sectname = section + '.' + name
5232 if values:
5242 if values:
5233 for v in values:
5243 for v in values:
5234 if v == section:
5244 if v == section:
5235 ui.debug('%s: ' %
5245 ui.debug('%s: ' %
5236 ui.configsource(section, name, untrusted))
5246 ui.configsource(section, name, untrusted))
5237 ui.write('%s=%s\n' % (sectname, value))
5247 ui.write('%s=%s\n' % (sectname, value))
5238 elif v == sectname:
5248 elif v == sectname:
5239 ui.debug('%s: ' %
5249 ui.debug('%s: ' %
5240 ui.configsource(section, name, untrusted))
5250 ui.configsource(section, name, untrusted))
5241 ui.write(value, '\n')
5251 ui.write(value, '\n')
5242 else:
5252 else:
5243 ui.debug('%s: ' %
5253 ui.debug('%s: ' %
5244 ui.configsource(section, name, untrusted))
5254 ui.configsource(section, name, untrusted))
5245 ui.write('%s=%s\n' % (sectname, value))
5255 ui.write('%s=%s\n' % (sectname, value))
5246
5256
5247 @command('^status|st',
5257 @command('^status|st',
5248 [('A', 'all', None, _('show status of all files')),
5258 [('A', 'all', None, _('show status of all files')),
5249 ('m', 'modified', None, _('show only modified files')),
5259 ('m', 'modified', None, _('show only modified files')),
5250 ('a', 'added', None, _('show only added files')),
5260 ('a', 'added', None, _('show only added files')),
5251 ('r', 'removed', None, _('show only removed files')),
5261 ('r', 'removed', None, _('show only removed files')),
5252 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5262 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5253 ('c', 'clean', None, _('show only files without changes')),
5263 ('c', 'clean', None, _('show only files without changes')),
5254 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5264 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5255 ('i', 'ignored', None, _('show only ignored files')),
5265 ('i', 'ignored', None, _('show only ignored files')),
5256 ('n', 'no-status', None, _('hide status prefix')),
5266 ('n', 'no-status', None, _('hide status prefix')),
5257 ('C', 'copies', None, _('show source of copied files')),
5267 ('C', 'copies', None, _('show source of copied files')),
5258 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5268 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5259 ('', 'rev', [], _('show difference from revision'), _('REV')),
5269 ('', 'rev', [], _('show difference from revision'), _('REV')),
5260 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5270 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5261 ] + walkopts + subrepoopts,
5271 ] + walkopts + subrepoopts,
5262 _('[OPTION]... [FILE]...'))
5272 _('[OPTION]... [FILE]...'))
5263 def status(ui, repo, *pats, **opts):
5273 def status(ui, repo, *pats, **opts):
5264 """show changed files in the working directory
5274 """show changed files in the working directory
5265
5275
5266 Show status of files in the repository. If names are given, only
5276 Show status of files in the repository. If names are given, only
5267 files that match are shown. Files that are clean or ignored or
5277 files that match are shown. Files that are clean or ignored or
5268 the source of a copy/move operation, are not listed unless
5278 the source of a copy/move operation, are not listed unless
5269 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5279 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5270 Unless options described with "show only ..." are given, the
5280 Unless options described with "show only ..." are given, the
5271 options -mardu are used.
5281 options -mardu are used.
5272
5282
5273 Option -q/--quiet hides untracked (unknown and ignored) files
5283 Option -q/--quiet hides untracked (unknown and ignored) files
5274 unless explicitly requested with -u/--unknown or -i/--ignored.
5284 unless explicitly requested with -u/--unknown or -i/--ignored.
5275
5285
5276 .. note::
5286 .. note::
5277 status may appear to disagree with diff if permissions have
5287 status may appear to disagree with diff if permissions have
5278 changed or a merge has occurred. The standard diff format does
5288 changed or a merge has occurred. The standard diff format does
5279 not report permission changes and diff only reports changes
5289 not report permission changes and diff only reports changes
5280 relative to one merge parent.
5290 relative to one merge parent.
5281
5291
5282 If one revision is given, it is used as the base revision.
5292 If one revision is given, it is used as the base revision.
5283 If two revisions are given, the differences between them are
5293 If two revisions are given, the differences between them are
5284 shown. The --change option can also be used as a shortcut to list
5294 shown. The --change option can also be used as a shortcut to list
5285 the changed files of a revision from its first parent.
5295 the changed files of a revision from its first parent.
5286
5296
5287 The codes used to show the status of files are::
5297 The codes used to show the status of files are::
5288
5298
5289 M = modified
5299 M = modified
5290 A = added
5300 A = added
5291 R = removed
5301 R = removed
5292 C = clean
5302 C = clean
5293 ! = missing (deleted by non-hg command, but still tracked)
5303 ! = missing (deleted by non-hg command, but still tracked)
5294 ? = not tracked
5304 ? = not tracked
5295 I = ignored
5305 I = ignored
5296 = origin of the previous file listed as A (added)
5306 = origin of the previous file listed as A (added)
5297
5307
5298 .. container:: verbose
5308 .. container:: verbose
5299
5309
5300 Examples:
5310 Examples:
5301
5311
5302 - show changes in the working directory relative to a
5312 - show changes in the working directory relative to a
5303 changeset::
5313 changeset::
5304
5314
5305 hg status --rev 9353
5315 hg status --rev 9353
5306
5316
5307 - show all changes including copies in an existing changeset::
5317 - show all changes including copies in an existing changeset::
5308
5318
5309 hg status --copies --change 9353
5319 hg status --copies --change 9353
5310
5320
5311 - get a NUL separated list of added files, suitable for xargs::
5321 - get a NUL separated list of added files, suitable for xargs::
5312
5322
5313 hg status -an0
5323 hg status -an0
5314
5324
5315 Returns 0 on success.
5325 Returns 0 on success.
5316 """
5326 """
5317
5327
5318 revs = opts.get('rev')
5328 revs = opts.get('rev')
5319 change = opts.get('change')
5329 change = opts.get('change')
5320
5330
5321 if revs and change:
5331 if revs and change:
5322 msg = _('cannot specify --rev and --change at the same time')
5332 msg = _('cannot specify --rev and --change at the same time')
5323 raise util.Abort(msg)
5333 raise util.Abort(msg)
5324 elif change:
5334 elif change:
5325 node2 = scmutil.revsingle(repo, change, None).node()
5335 node2 = scmutil.revsingle(repo, change, None).node()
5326 node1 = repo[node2].p1().node()
5336 node1 = repo[node2].p1().node()
5327 else:
5337 else:
5328 node1, node2 = scmutil.revpair(repo, revs)
5338 node1, node2 = scmutil.revpair(repo, revs)
5329
5339
5330 cwd = (pats and repo.getcwd()) or ''
5340 cwd = (pats and repo.getcwd()) or ''
5331 end = opts.get('print0') and '\0' or '\n'
5341 end = opts.get('print0') and '\0' or '\n'
5332 copy = {}
5342 copy = {}
5333 states = 'modified added removed deleted unknown ignored clean'.split()
5343 states = 'modified added removed deleted unknown ignored clean'.split()
5334 show = [k for k in states if opts.get(k)]
5344 show = [k for k in states if opts.get(k)]
5335 if opts.get('all'):
5345 if opts.get('all'):
5336 show += ui.quiet and (states[:4] + ['clean']) or states
5346 show += ui.quiet and (states[:4] + ['clean']) or states
5337 if not show:
5347 if not show:
5338 show = ui.quiet and states[:4] or states[:5]
5348 show = ui.quiet and states[:4] or states[:5]
5339
5349
5340 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5350 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5341 'ignored' in show, 'clean' in show, 'unknown' in show,
5351 'ignored' in show, 'clean' in show, 'unknown' in show,
5342 opts.get('subrepos'))
5352 opts.get('subrepos'))
5343 changestates = zip(states, 'MAR!?IC', stat)
5353 changestates = zip(states, 'MAR!?IC', stat)
5344
5354
5345 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5355 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5346 copy = copies.pathcopies(repo[node1], repo[node2])
5356 copy = copies.pathcopies(repo[node1], repo[node2])
5347
5357
5348 fm = ui.formatter('status', opts)
5358 fm = ui.formatter('status', opts)
5349 format = '%s %s' + end
5359 format = '%s %s' + end
5350 if opts.get('no_status'):
5360 if opts.get('no_status'):
5351 format = '%.0s%s' + end
5361 format = '%.0s%s' + end
5352
5362
5353 for state, char, files in changestates:
5363 for state, char, files in changestates:
5354 if state in show:
5364 if state in show:
5355 label = 'status.' + state
5365 label = 'status.' + state
5356 for f in files:
5366 for f in files:
5357 fm.startitem()
5367 fm.startitem()
5358 fm.write("status path", format, char,
5368 fm.write("status path", format, char,
5359 repo.pathto(f, cwd), label=label)
5369 repo.pathto(f, cwd), label=label)
5360 if f in copy:
5370 if f in copy:
5361 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5371 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5362 label='status.copied')
5372 label='status.copied')
5363 fm.end()
5373 fm.end()
5364
5374
5365 @command('^summary|sum',
5375 @command('^summary|sum',
5366 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5376 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5367 def summary(ui, repo, **opts):
5377 def summary(ui, repo, **opts):
5368 """summarize working directory state
5378 """summarize working directory state
5369
5379
5370 This generates a brief summary of the working directory state,
5380 This generates a brief summary of the working directory state,
5371 including parents, branch, commit status, and available updates.
5381 including parents, branch, commit status, and available updates.
5372
5382
5373 With the --remote option, this will check the default paths for
5383 With the --remote option, this will check the default paths for
5374 incoming and outgoing changes. This can be time-consuming.
5384 incoming and outgoing changes. This can be time-consuming.
5375
5385
5376 Returns 0 on success.
5386 Returns 0 on success.
5377 """
5387 """
5378
5388
5379 ctx = repo[None]
5389 ctx = repo[None]
5380 parents = ctx.parents()
5390 parents = ctx.parents()
5381 pnode = parents[0].node()
5391 pnode = parents[0].node()
5382 marks = []
5392 marks = []
5383
5393
5384 for p in parents:
5394 for p in parents:
5385 # label with log.changeset (instead of log.parent) since this
5395 # label with log.changeset (instead of log.parent) since this
5386 # shows a working directory parent *changeset*:
5396 # shows a working directory parent *changeset*:
5387 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5397 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5388 label='log.changeset')
5398 label='log.changeset')
5389 ui.write(' '.join(p.tags()), label='log.tag')
5399 ui.write(' '.join(p.tags()), label='log.tag')
5390 if p.bookmarks():
5400 if p.bookmarks():
5391 marks.extend(p.bookmarks())
5401 marks.extend(p.bookmarks())
5392 if p.rev() == -1:
5402 if p.rev() == -1:
5393 if not len(repo):
5403 if not len(repo):
5394 ui.write(_(' (empty repository)'))
5404 ui.write(_(' (empty repository)'))
5395 else:
5405 else:
5396 ui.write(_(' (no revision checked out)'))
5406 ui.write(_(' (no revision checked out)'))
5397 ui.write('\n')
5407 ui.write('\n')
5398 if p.description():
5408 if p.description():
5399 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5409 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5400 label='log.summary')
5410 label='log.summary')
5401
5411
5402 branch = ctx.branch()
5412 branch = ctx.branch()
5403 bheads = repo.branchheads(branch)
5413 bheads = repo.branchheads(branch)
5404 m = _('branch: %s\n') % branch
5414 m = _('branch: %s\n') % branch
5405 if branch != 'default':
5415 if branch != 'default':
5406 ui.write(m, label='log.branch')
5416 ui.write(m, label='log.branch')
5407 else:
5417 else:
5408 ui.status(m, label='log.branch')
5418 ui.status(m, label='log.branch')
5409
5419
5410 if marks:
5420 if marks:
5411 current = repo._bookmarkcurrent
5421 current = repo._bookmarkcurrent
5412 ui.write(_('bookmarks:'), label='log.bookmark')
5422 ui.write(_('bookmarks:'), label='log.bookmark')
5413 if current is not None:
5423 if current is not None:
5414 try:
5424 try:
5415 marks.remove(current)
5425 marks.remove(current)
5416 ui.write(' *' + current, label='bookmarks.current')
5426 ui.write(' *' + current, label='bookmarks.current')
5417 except ValueError:
5427 except ValueError:
5418 # current bookmark not in parent ctx marks
5428 # current bookmark not in parent ctx marks
5419 pass
5429 pass
5420 for m in marks:
5430 for m in marks:
5421 ui.write(' ' + m, label='log.bookmark')
5431 ui.write(' ' + m, label='log.bookmark')
5422 ui.write('\n', label='log.bookmark')
5432 ui.write('\n', label='log.bookmark')
5423
5433
5424 st = list(repo.status(unknown=True))[:6]
5434 st = list(repo.status(unknown=True))[:6]
5425
5435
5426 c = repo.dirstate.copies()
5436 c = repo.dirstate.copies()
5427 copied, renamed = [], []
5437 copied, renamed = [], []
5428 for d, s in c.iteritems():
5438 for d, s in c.iteritems():
5429 if s in st[2]:
5439 if s in st[2]:
5430 st[2].remove(s)
5440 st[2].remove(s)
5431 renamed.append(d)
5441 renamed.append(d)
5432 else:
5442 else:
5433 copied.append(d)
5443 copied.append(d)
5434 if d in st[1]:
5444 if d in st[1]:
5435 st[1].remove(d)
5445 st[1].remove(d)
5436 st.insert(3, renamed)
5446 st.insert(3, renamed)
5437 st.insert(4, copied)
5447 st.insert(4, copied)
5438
5448
5439 ms = mergemod.mergestate(repo)
5449 ms = mergemod.mergestate(repo)
5440 st.append([f for f in ms if ms[f] == 'u'])
5450 st.append([f for f in ms if ms[f] == 'u'])
5441
5451
5442 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5452 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5443 st.append(subs)
5453 st.append(subs)
5444
5454
5445 labels = [ui.label(_('%d modified'), 'status.modified'),
5455 labels = [ui.label(_('%d modified'), 'status.modified'),
5446 ui.label(_('%d added'), 'status.added'),
5456 ui.label(_('%d added'), 'status.added'),
5447 ui.label(_('%d removed'), 'status.removed'),
5457 ui.label(_('%d removed'), 'status.removed'),
5448 ui.label(_('%d renamed'), 'status.copied'),
5458 ui.label(_('%d renamed'), 'status.copied'),
5449 ui.label(_('%d copied'), 'status.copied'),
5459 ui.label(_('%d copied'), 'status.copied'),
5450 ui.label(_('%d deleted'), 'status.deleted'),
5460 ui.label(_('%d deleted'), 'status.deleted'),
5451 ui.label(_('%d unknown'), 'status.unknown'),
5461 ui.label(_('%d unknown'), 'status.unknown'),
5452 ui.label(_('%d ignored'), 'status.ignored'),
5462 ui.label(_('%d ignored'), 'status.ignored'),
5453 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5463 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5454 ui.label(_('%d subrepos'), 'status.modified')]
5464 ui.label(_('%d subrepos'), 'status.modified')]
5455 t = []
5465 t = []
5456 for s, l in zip(st, labels):
5466 for s, l in zip(st, labels):
5457 if s:
5467 if s:
5458 t.append(l % len(s))
5468 t.append(l % len(s))
5459
5469
5460 t = ', '.join(t)
5470 t = ', '.join(t)
5461 cleanworkdir = False
5471 cleanworkdir = False
5462
5472
5463 if len(parents) > 1:
5473 if len(parents) > 1:
5464 t += _(' (merge)')
5474 t += _(' (merge)')
5465 elif branch != parents[0].branch():
5475 elif branch != parents[0].branch():
5466 t += _(' (new branch)')
5476 t += _(' (new branch)')
5467 elif (parents[0].closesbranch() and
5477 elif (parents[0].closesbranch() and
5468 pnode in repo.branchheads(branch, closed=True)):
5478 pnode in repo.branchheads(branch, closed=True)):
5469 t += _(' (head closed)')
5479 t += _(' (head closed)')
5470 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5480 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5471 t += _(' (clean)')
5481 t += _(' (clean)')
5472 cleanworkdir = True
5482 cleanworkdir = True
5473 elif pnode not in bheads:
5483 elif pnode not in bheads:
5474 t += _(' (new branch head)')
5484 t += _(' (new branch head)')
5475
5485
5476 if cleanworkdir:
5486 if cleanworkdir:
5477 ui.status(_('commit: %s\n') % t.strip())
5487 ui.status(_('commit: %s\n') % t.strip())
5478 else:
5488 else:
5479 ui.write(_('commit: %s\n') % t.strip())
5489 ui.write(_('commit: %s\n') % t.strip())
5480
5490
5481 # all ancestors of branch heads - all ancestors of parent = new csets
5491 # all ancestors of branch heads - all ancestors of parent = new csets
5482 new = [0] * len(repo)
5492 new = [0] * len(repo)
5483 cl = repo.changelog
5493 cl = repo.changelog
5484 for a in [cl.rev(n) for n in bheads]:
5494 for a in [cl.rev(n) for n in bheads]:
5485 new[a] = 1
5495 new[a] = 1
5486 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5496 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5487 new[a] = 1
5497 new[a] = 1
5488 for a in [p.rev() for p in parents]:
5498 for a in [p.rev() for p in parents]:
5489 if a >= 0:
5499 if a >= 0:
5490 new[a] = 0
5500 new[a] = 0
5491 for a in cl.ancestors([p.rev() for p in parents]):
5501 for a in cl.ancestors([p.rev() for p in parents]):
5492 new[a] = 0
5502 new[a] = 0
5493 new = sum(new)
5503 new = sum(new)
5494
5504
5495 if new == 0:
5505 if new == 0:
5496 ui.status(_('update: (current)\n'))
5506 ui.status(_('update: (current)\n'))
5497 elif pnode not in bheads:
5507 elif pnode not in bheads:
5498 ui.write(_('update: %d new changesets (update)\n') % new)
5508 ui.write(_('update: %d new changesets (update)\n') % new)
5499 else:
5509 else:
5500 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5510 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5501 (new, len(bheads)))
5511 (new, len(bheads)))
5502
5512
5503 if opts.get('remote'):
5513 if opts.get('remote'):
5504 t = []
5514 t = []
5505 source, branches = hg.parseurl(ui.expandpath('default'))
5515 source, branches = hg.parseurl(ui.expandpath('default'))
5506 other = hg.peer(repo, {}, source)
5516 other = hg.peer(repo, {}, source)
5507 revs, checkout = hg.addbranchrevs(repo, other, branches,
5517 revs, checkout = hg.addbranchrevs(repo, other, branches,
5508 opts.get('rev'))
5518 opts.get('rev'))
5509 ui.debug('comparing with %s\n' % util.hidepassword(source))
5519 ui.debug('comparing with %s\n' % util.hidepassword(source))
5510 repo.ui.pushbuffer()
5520 repo.ui.pushbuffer()
5511 commoninc = discovery.findcommonincoming(repo, other)
5521 commoninc = discovery.findcommonincoming(repo, other)
5512 _common, incoming, _rheads = commoninc
5522 _common, incoming, _rheads = commoninc
5513 repo.ui.popbuffer()
5523 repo.ui.popbuffer()
5514 if incoming:
5524 if incoming:
5515 t.append(_('1 or more incoming'))
5525 t.append(_('1 or more incoming'))
5516
5526
5517 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5527 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5518 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5528 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5519 if source != dest:
5529 if source != dest:
5520 other = hg.peer(repo, {}, dest)
5530 other = hg.peer(repo, {}, dest)
5521 commoninc = None
5531 commoninc = None
5522 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5532 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5523 repo.ui.pushbuffer()
5533 repo.ui.pushbuffer()
5524 outgoing = discovery.findcommonoutgoing(repo, other,
5534 outgoing = discovery.findcommonoutgoing(repo, other,
5525 commoninc=commoninc)
5535 commoninc=commoninc)
5526 repo.ui.popbuffer()
5536 repo.ui.popbuffer()
5527 o = outgoing.missing
5537 o = outgoing.missing
5528 if o:
5538 if o:
5529 t.append(_('%d outgoing') % len(o))
5539 t.append(_('%d outgoing') % len(o))
5530 if 'bookmarks' in other.listkeys('namespaces'):
5540 if 'bookmarks' in other.listkeys('namespaces'):
5531 lmarks = repo.listkeys('bookmarks')
5541 lmarks = repo.listkeys('bookmarks')
5532 rmarks = other.listkeys('bookmarks')
5542 rmarks = other.listkeys('bookmarks')
5533 diff = set(rmarks) - set(lmarks)
5543 diff = set(rmarks) - set(lmarks)
5534 if len(diff) > 0:
5544 if len(diff) > 0:
5535 t.append(_('%d incoming bookmarks') % len(diff))
5545 t.append(_('%d incoming bookmarks') % len(diff))
5536 diff = set(lmarks) - set(rmarks)
5546 diff = set(lmarks) - set(rmarks)
5537 if len(diff) > 0:
5547 if len(diff) > 0:
5538 t.append(_('%d outgoing bookmarks') % len(diff))
5548 t.append(_('%d outgoing bookmarks') % len(diff))
5539
5549
5540 if t:
5550 if t:
5541 ui.write(_('remote: %s\n') % (', '.join(t)))
5551 ui.write(_('remote: %s\n') % (', '.join(t)))
5542 else:
5552 else:
5543 ui.status(_('remote: (synced)\n'))
5553 ui.status(_('remote: (synced)\n'))
5544
5554
5545 @command('tag',
5555 @command('tag',
5546 [('f', 'force', None, _('force tag')),
5556 [('f', 'force', None, _('force tag')),
5547 ('l', 'local', None, _('make the tag local')),
5557 ('l', 'local', None, _('make the tag local')),
5548 ('r', 'rev', '', _('revision to tag'), _('REV')),
5558 ('r', 'rev', '', _('revision to tag'), _('REV')),
5549 ('', 'remove', None, _('remove a tag')),
5559 ('', 'remove', None, _('remove a tag')),
5550 # -l/--local is already there, commitopts cannot be used
5560 # -l/--local is already there, commitopts cannot be used
5551 ('e', 'edit', None, _('edit commit message')),
5561 ('e', 'edit', None, _('edit commit message')),
5552 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5562 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5553 ] + commitopts2,
5563 ] + commitopts2,
5554 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5564 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5555 def tag(ui, repo, name1, *names, **opts):
5565 def tag(ui, repo, name1, *names, **opts):
5556 """add one or more tags for the current or given revision
5566 """add one or more tags for the current or given revision
5557
5567
5558 Name a particular revision using <name>.
5568 Name a particular revision using <name>.
5559
5569
5560 Tags are used to name particular revisions of the repository and are
5570 Tags are used to name particular revisions of the repository and are
5561 very useful to compare different revisions, to go back to significant
5571 very useful to compare different revisions, to go back to significant
5562 earlier versions or to mark branch points as releases, etc. Changing
5572 earlier versions or to mark branch points as releases, etc. Changing
5563 an existing tag is normally disallowed; use -f/--force to override.
5573 an existing tag is normally disallowed; use -f/--force to override.
5564
5574
5565 If no revision is given, the parent of the working directory is
5575 If no revision is given, the parent of the working directory is
5566 used, or tip if no revision is checked out.
5576 used, or tip if no revision is checked out.
5567
5577
5568 To facilitate version control, distribution, and merging of tags,
5578 To facilitate version control, distribution, and merging of tags,
5569 they are stored as a file named ".hgtags" which is managed similarly
5579 they are stored as a file named ".hgtags" which is managed similarly
5570 to other project files and can be hand-edited if necessary. This
5580 to other project files and can be hand-edited if necessary. This
5571 also means that tagging creates a new commit. The file
5581 also means that tagging creates a new commit. The file
5572 ".hg/localtags" is used for local tags (not shared among
5582 ".hg/localtags" is used for local tags (not shared among
5573 repositories).
5583 repositories).
5574
5584
5575 Tag commits are usually made at the head of a branch. If the parent
5585 Tag commits are usually made at the head of a branch. If the parent
5576 of the working directory is not a branch head, :hg:`tag` aborts; use
5586 of the working directory is not a branch head, :hg:`tag` aborts; use
5577 -f/--force to force the tag commit to be based on a non-head
5587 -f/--force to force the tag commit to be based on a non-head
5578 changeset.
5588 changeset.
5579
5589
5580 See :hg:`help dates` for a list of formats valid for -d/--date.
5590 See :hg:`help dates` for a list of formats valid for -d/--date.
5581
5591
5582 Since tag names have priority over branch names during revision
5592 Since tag names have priority over branch names during revision
5583 lookup, using an existing branch name as a tag name is discouraged.
5593 lookup, using an existing branch name as a tag name is discouraged.
5584
5594
5585 Returns 0 on success.
5595 Returns 0 on success.
5586 """
5596 """
5587 wlock = lock = None
5597 wlock = lock = None
5588 try:
5598 try:
5589 wlock = repo.wlock()
5599 wlock = repo.wlock()
5590 lock = repo.lock()
5600 lock = repo.lock()
5591 rev_ = "."
5601 rev_ = "."
5592 names = [t.strip() for t in (name1,) + names]
5602 names = [t.strip() for t in (name1,) + names]
5593 if len(names) != len(set(names)):
5603 if len(names) != len(set(names)):
5594 raise util.Abort(_('tag names must be unique'))
5604 raise util.Abort(_('tag names must be unique'))
5595 for n in names:
5605 for n in names:
5596 if n in ['tip', '.', 'null']:
5606 if n in ['tip', '.', 'null']:
5597 raise util.Abort(_("the name '%s' is reserved") % n)
5607 raise util.Abort(_("the name '%s' is reserved") % n)
5598 if not n:
5608 if not n:
5599 raise util.Abort(_('tag names cannot consist entirely of '
5609 raise util.Abort(_('tag names cannot consist entirely of '
5600 'whitespace'))
5610 'whitespace'))
5601 if opts.get('rev') and opts.get('remove'):
5611 if opts.get('rev') and opts.get('remove'):
5602 raise util.Abort(_("--rev and --remove are incompatible"))
5612 raise util.Abort(_("--rev and --remove are incompatible"))
5603 if opts.get('rev'):
5613 if opts.get('rev'):
5604 rev_ = opts['rev']
5614 rev_ = opts['rev']
5605 message = opts.get('message')
5615 message = opts.get('message')
5606 if opts.get('remove'):
5616 if opts.get('remove'):
5607 expectedtype = opts.get('local') and 'local' or 'global'
5617 expectedtype = opts.get('local') and 'local' or 'global'
5608 for n in names:
5618 for n in names:
5609 if not repo.tagtype(n):
5619 if not repo.tagtype(n):
5610 raise util.Abort(_("tag '%s' does not exist") % n)
5620 raise util.Abort(_("tag '%s' does not exist") % n)
5611 if repo.tagtype(n) != expectedtype:
5621 if repo.tagtype(n) != expectedtype:
5612 if expectedtype == 'global':
5622 if expectedtype == 'global':
5613 raise util.Abort(_("tag '%s' is not a global tag") % n)
5623 raise util.Abort(_("tag '%s' is not a global tag") % n)
5614 else:
5624 else:
5615 raise util.Abort(_("tag '%s' is not a local tag") % n)
5625 raise util.Abort(_("tag '%s' is not a local tag") % n)
5616 rev_ = nullid
5626 rev_ = nullid
5617 if not message:
5627 if not message:
5618 # we don't translate commit messages
5628 # we don't translate commit messages
5619 message = 'Removed tag %s' % ', '.join(names)
5629 message = 'Removed tag %s' % ', '.join(names)
5620 elif not opts.get('force'):
5630 elif not opts.get('force'):
5621 for n in names:
5631 for n in names:
5622 if n in repo.tags():
5632 if n in repo.tags():
5623 raise util.Abort(_("tag '%s' already exists "
5633 raise util.Abort(_("tag '%s' already exists "
5624 "(use -f to force)") % n)
5634 "(use -f to force)") % n)
5625 if not opts.get('local'):
5635 if not opts.get('local'):
5626 p1, p2 = repo.dirstate.parents()
5636 p1, p2 = repo.dirstate.parents()
5627 if p2 != nullid:
5637 if p2 != nullid:
5628 raise util.Abort(_('uncommitted merge'))
5638 raise util.Abort(_('uncommitted merge'))
5629 bheads = repo.branchheads()
5639 bheads = repo.branchheads()
5630 if not opts.get('force') and bheads and p1 not in bheads:
5640 if not opts.get('force') and bheads and p1 not in bheads:
5631 raise util.Abort(_('not at a branch head (use -f to force)'))
5641 raise util.Abort(_('not at a branch head (use -f to force)'))
5632 r = scmutil.revsingle(repo, rev_).node()
5642 r = scmutil.revsingle(repo, rev_).node()
5633
5643
5634 if not message:
5644 if not message:
5635 # we don't translate commit messages
5645 # we don't translate commit messages
5636 message = ('Added tag %s for changeset %s' %
5646 message = ('Added tag %s for changeset %s' %
5637 (', '.join(names), short(r)))
5647 (', '.join(names), short(r)))
5638
5648
5639 date = opts.get('date')
5649 date = opts.get('date')
5640 if date:
5650 if date:
5641 date = util.parsedate(date)
5651 date = util.parsedate(date)
5642
5652
5643 if opts.get('edit'):
5653 if opts.get('edit'):
5644 message = ui.edit(message, ui.username())
5654 message = ui.edit(message, ui.username())
5645
5655
5646 # don't allow tagging the null rev
5656 # don't allow tagging the null rev
5647 if (not opts.get('remove') and
5657 if (not opts.get('remove') and
5648 scmutil.revsingle(repo, rev_).rev() == nullrev):
5658 scmutil.revsingle(repo, rev_).rev() == nullrev):
5649 raise util.Abort(_("null revision specified"))
5659 raise util.Abort(_("null revision specified"))
5650
5660
5651 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5661 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5652 finally:
5662 finally:
5653 release(lock, wlock)
5663 release(lock, wlock)
5654
5664
5655 @command('tags', [], '')
5665 @command('tags', [], '')
5656 def tags(ui, repo):
5666 def tags(ui, repo):
5657 """list repository tags
5667 """list repository tags
5658
5668
5659 This lists both regular and local tags. When the -v/--verbose
5669 This lists both regular and local tags. When the -v/--verbose
5660 switch is used, a third column "local" is printed for local tags.
5670 switch is used, a third column "local" is printed for local tags.
5661
5671
5662 Returns 0 on success.
5672 Returns 0 on success.
5663 """
5673 """
5664
5674
5665 hexfunc = ui.debugflag and hex or short
5675 hexfunc = ui.debugflag and hex or short
5666 tagtype = ""
5676 tagtype = ""
5667
5677
5668 for t, n in reversed(repo.tagslist()):
5678 for t, n in reversed(repo.tagslist()):
5669 if ui.quiet:
5679 if ui.quiet:
5670 ui.write("%s\n" % t, label='tags.normal')
5680 ui.write("%s\n" % t, label='tags.normal')
5671 continue
5681 continue
5672
5682
5673 hn = hexfunc(n)
5683 hn = hexfunc(n)
5674 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5684 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5675 rev = ui.label(r, 'log.changeset')
5685 rev = ui.label(r, 'log.changeset')
5676 spaces = " " * (30 - encoding.colwidth(t))
5686 spaces = " " * (30 - encoding.colwidth(t))
5677
5687
5678 tag = ui.label(t, 'tags.normal')
5688 tag = ui.label(t, 'tags.normal')
5679 if ui.verbose:
5689 if ui.verbose:
5680 if repo.tagtype(t) == 'local':
5690 if repo.tagtype(t) == 'local':
5681 tagtype = " local"
5691 tagtype = " local"
5682 tag = ui.label(t, 'tags.local')
5692 tag = ui.label(t, 'tags.local')
5683 else:
5693 else:
5684 tagtype = ""
5694 tagtype = ""
5685 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5695 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5686
5696
5687 @command('tip',
5697 @command('tip',
5688 [('p', 'patch', None, _('show patch')),
5698 [('p', 'patch', None, _('show patch')),
5689 ('g', 'git', None, _('use git extended diff format')),
5699 ('g', 'git', None, _('use git extended diff format')),
5690 ] + templateopts,
5700 ] + templateopts,
5691 _('[-p] [-g]'))
5701 _('[-p] [-g]'))
5692 def tip(ui, repo, **opts):
5702 def tip(ui, repo, **opts):
5693 """show the tip revision
5703 """show the tip revision
5694
5704
5695 The tip revision (usually just called the tip) is the changeset
5705 The tip revision (usually just called the tip) is the changeset
5696 most recently added to the repository (and therefore the most
5706 most recently added to the repository (and therefore the most
5697 recently changed head).
5707 recently changed head).
5698
5708
5699 If you have just made a commit, that commit will be the tip. If
5709 If you have just made a commit, that commit will be the tip. If
5700 you have just pulled changes from another repository, the tip of
5710 you have just pulled changes from another repository, the tip of
5701 that repository becomes the current tip. The "tip" tag is special
5711 that repository becomes the current tip. The "tip" tag is special
5702 and cannot be renamed or assigned to a different changeset.
5712 and cannot be renamed or assigned to a different changeset.
5703
5713
5704 Returns 0 on success.
5714 Returns 0 on success.
5705 """
5715 """
5706 displayer = cmdutil.show_changeset(ui, repo, opts)
5716 displayer = cmdutil.show_changeset(ui, repo, opts)
5707 displayer.show(repo[len(repo) - 1])
5717 displayer.show(repo[len(repo) - 1])
5708 displayer.close()
5718 displayer.close()
5709
5719
5710 @command('unbundle',
5720 @command('unbundle',
5711 [('u', 'update', None,
5721 [('u', 'update', None,
5712 _('update to new branch head if changesets were unbundled'))],
5722 _('update to new branch head if changesets were unbundled'))],
5713 _('[-u] FILE...'))
5723 _('[-u] FILE...'))
5714 def unbundle(ui, repo, fname1, *fnames, **opts):
5724 def unbundle(ui, repo, fname1, *fnames, **opts):
5715 """apply one or more changegroup files
5725 """apply one or more changegroup files
5716
5726
5717 Apply one or more compressed changegroup files generated by the
5727 Apply one or more compressed changegroup files generated by the
5718 bundle command.
5728 bundle command.
5719
5729
5720 Returns 0 on success, 1 if an update has unresolved files.
5730 Returns 0 on success, 1 if an update has unresolved files.
5721 """
5731 """
5722 fnames = (fname1,) + fnames
5732 fnames = (fname1,) + fnames
5723
5733
5724 lock = repo.lock()
5734 lock = repo.lock()
5725 wc = repo['.']
5735 wc = repo['.']
5726 try:
5736 try:
5727 for fname in fnames:
5737 for fname in fnames:
5728 f = url.open(ui, fname)
5738 f = url.open(ui, fname)
5729 gen = changegroup.readbundle(f, fname)
5739 gen = changegroup.readbundle(f, fname)
5730 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5740 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5731 finally:
5741 finally:
5732 lock.release()
5742 lock.release()
5733 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5743 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5734 return postincoming(ui, repo, modheads, opts.get('update'), None)
5744 return postincoming(ui, repo, modheads, opts.get('update'), None)
5735
5745
5736 @command('^update|up|checkout|co',
5746 @command('^update|up|checkout|co',
5737 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5747 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5738 ('c', 'check', None,
5748 ('c', 'check', None,
5739 _('update across branches if no uncommitted changes')),
5749 _('update across branches if no uncommitted changes')),
5740 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5750 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5741 ('r', 'rev', '', _('revision'), _('REV'))],
5751 ('r', 'rev', '', _('revision'), _('REV'))],
5742 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5752 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5743 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5753 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5744 """update working directory (or switch revisions)
5754 """update working directory (or switch revisions)
5745
5755
5746 Update the repository's working directory to the specified
5756 Update the repository's working directory to the specified
5747 changeset. If no changeset is specified, update to the tip of the
5757 changeset. If no changeset is specified, update to the tip of the
5748 current named branch and move the current bookmark (see :hg:`help
5758 current named branch and move the current bookmark (see :hg:`help
5749 bookmarks`).
5759 bookmarks`).
5750
5760
5751 Update sets the working directory's parent revison to the specified
5761 Update sets the working directory's parent revison to the specified
5752 changeset (see :hg:`help parents`).
5762 changeset (see :hg:`help parents`).
5753
5763
5754 If the changeset is not a descendant or ancestor of the working
5764 If the changeset is not a descendant or ancestor of the working
5755 directory's parent, the update is aborted. With the -c/--check
5765 directory's parent, the update is aborted. With the -c/--check
5756 option, the working directory is checked for uncommitted changes; if
5766 option, the working directory is checked for uncommitted changes; if
5757 none are found, the working directory is updated to the specified
5767 none are found, the working directory is updated to the specified
5758 changeset.
5768 changeset.
5759
5769
5760 .. container:: verbose
5770 .. container:: verbose
5761
5771
5762 The following rules apply when the working directory contains
5772 The following rules apply when the working directory contains
5763 uncommitted changes:
5773 uncommitted changes:
5764
5774
5765 1. If neither -c/--check nor -C/--clean is specified, and if
5775 1. If neither -c/--check nor -C/--clean is specified, and if
5766 the requested changeset is an ancestor or descendant of
5776 the requested changeset is an ancestor or descendant of
5767 the working directory's parent, the uncommitted changes
5777 the working directory's parent, the uncommitted changes
5768 are merged into the requested changeset and the merged
5778 are merged into the requested changeset and the merged
5769 result is left uncommitted. If the requested changeset is
5779 result is left uncommitted. If the requested changeset is
5770 not an ancestor or descendant (that is, it is on another
5780 not an ancestor or descendant (that is, it is on another
5771 branch), the update is aborted and the uncommitted changes
5781 branch), the update is aborted and the uncommitted changes
5772 are preserved.
5782 are preserved.
5773
5783
5774 2. With the -c/--check option, the update is aborted and the
5784 2. With the -c/--check option, the update is aborted and the
5775 uncommitted changes are preserved.
5785 uncommitted changes are preserved.
5776
5786
5777 3. With the -C/--clean option, uncommitted changes are discarded and
5787 3. With the -C/--clean option, uncommitted changes are discarded and
5778 the working directory is updated to the requested changeset.
5788 the working directory is updated to the requested changeset.
5779
5789
5780 To cancel an uncommitted merge (and lose your changes), use
5790 To cancel an uncommitted merge (and lose your changes), use
5781 :hg:`update --clean .`.
5791 :hg:`update --clean .`.
5782
5792
5783 Use null as the changeset to remove the working directory (like
5793 Use null as the changeset to remove the working directory (like
5784 :hg:`clone -U`).
5794 :hg:`clone -U`).
5785
5795
5786 If you want to revert just one file to an older revision, use
5796 If you want to revert just one file to an older revision, use
5787 :hg:`revert [-r REV] NAME`.
5797 :hg:`revert [-r REV] NAME`.
5788
5798
5789 See :hg:`help dates` for a list of formats valid for -d/--date.
5799 See :hg:`help dates` for a list of formats valid for -d/--date.
5790
5800
5791 Returns 0 on success, 1 if there are unresolved files.
5801 Returns 0 on success, 1 if there are unresolved files.
5792 """
5802 """
5793 if rev and node:
5803 if rev and node:
5794 raise util.Abort(_("please specify just one revision"))
5804 raise util.Abort(_("please specify just one revision"))
5795
5805
5796 if rev is None or rev == '':
5806 if rev is None or rev == '':
5797 rev = node
5807 rev = node
5798
5808
5799 # with no argument, we also move the current bookmark, if any
5809 # with no argument, we also move the current bookmark, if any
5800 movemarkfrom = None
5810 movemarkfrom = None
5801 if rev is None or node == '':
5811 if rev is None or node == '':
5802 movemarkfrom = repo['.'].node()
5812 movemarkfrom = repo['.'].node()
5803
5813
5804 # if we defined a bookmark, we have to remember the original bookmark name
5814 # if we defined a bookmark, we have to remember the original bookmark name
5805 brev = rev
5815 brev = rev
5806 rev = scmutil.revsingle(repo, rev, rev).rev()
5816 rev = scmutil.revsingle(repo, rev, rev).rev()
5807
5817
5808 if check and clean:
5818 if check and clean:
5809 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5819 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5810
5820
5811 if date:
5821 if date:
5812 if rev is not None:
5822 if rev is not None:
5813 raise util.Abort(_("you can't specify a revision and a date"))
5823 raise util.Abort(_("you can't specify a revision and a date"))
5814 rev = cmdutil.finddate(ui, repo, date)
5824 rev = cmdutil.finddate(ui, repo, date)
5815
5825
5816 if check:
5826 if check:
5817 c = repo[None]
5827 c = repo[None]
5818 if c.dirty(merge=False, branch=False):
5828 if c.dirty(merge=False, branch=False):
5819 raise util.Abort(_("uncommitted local changes"))
5829 raise util.Abort(_("uncommitted local changes"))
5820 if rev is None:
5830 if rev is None:
5821 rev = repo[repo[None].branch()].rev()
5831 rev = repo[repo[None].branch()].rev()
5822 mergemod._checkunknown(repo, repo[None], repo[rev])
5832 mergemod._checkunknown(repo, repo[None], repo[rev])
5823
5833
5824 if clean:
5834 if clean:
5825 ret = hg.clean(repo, rev)
5835 ret = hg.clean(repo, rev)
5826 else:
5836 else:
5827 ret = hg.update(repo, rev)
5837 ret = hg.update(repo, rev)
5828
5838
5829 if not ret and movemarkfrom:
5839 if not ret and movemarkfrom:
5830 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5840 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5831 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5841 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5832 elif brev in repo._bookmarks:
5842 elif brev in repo._bookmarks:
5833 bookmarks.setcurrent(repo, brev)
5843 bookmarks.setcurrent(repo, brev)
5834 elif brev:
5844 elif brev:
5835 bookmarks.unsetcurrent(repo)
5845 bookmarks.unsetcurrent(repo)
5836
5846
5837 return ret
5847 return ret
5838
5848
5839 @command('verify', [])
5849 @command('verify', [])
5840 def verify(ui, repo):
5850 def verify(ui, repo):
5841 """verify the integrity of the repository
5851 """verify the integrity of the repository
5842
5852
5843 Verify the integrity of the current repository.
5853 Verify the integrity of the current repository.
5844
5854
5845 This will perform an extensive check of the repository's
5855 This will perform an extensive check of the repository's
5846 integrity, validating the hashes and checksums of each entry in
5856 integrity, validating the hashes and checksums of each entry in
5847 the changelog, manifest, and tracked files, as well as the
5857 the changelog, manifest, and tracked files, as well as the
5848 integrity of their crosslinks and indices.
5858 integrity of their crosslinks and indices.
5849
5859
5850 Returns 0 on success, 1 if errors are encountered.
5860 Returns 0 on success, 1 if errors are encountered.
5851 """
5861 """
5852 return hg.verify(repo)
5862 return hg.verify(repo)
5853
5863
5854 @command('version', [])
5864 @command('version', [])
5855 def version_(ui):
5865 def version_(ui):
5856 """output version and copyright information"""
5866 """output version and copyright information"""
5857 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5867 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5858 % util.version())
5868 % util.version())
5859 ui.status(_(
5869 ui.status(_(
5860 "(see http://mercurial.selenic.com for more information)\n"
5870 "(see http://mercurial.selenic.com for more information)\n"
5861 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5871 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5862 "This is free software; see the source for copying conditions. "
5872 "This is free software; see the source for copying conditions. "
5863 "There is NO\nwarranty; "
5873 "There is NO\nwarranty; "
5864 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5874 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5865 ))
5875 ))
5866
5876
5867 norepo = ("clone init version help debugcommands debugcomplete"
5877 norepo = ("clone init version help debugcommands debugcomplete"
5868 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5878 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5869 " debugknown debuggetbundle debugbundle")
5879 " debugknown debuggetbundle debugbundle")
5870 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5880 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5871 " debugdata debugindex debugindexdot debugrevlog")
5881 " debugdata debugindex debugindexdot debugrevlog")
@@ -1,195 +1,201 b''
1 # repair.py - functions for repository repair for mercurial
1 # repair.py - functions for repository repair for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 # Copyright 2007 Matt Mackall
4 # Copyright 2007 Matt Mackall
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from mercurial import changegroup, bookmarks
9 from mercurial import changegroup, bookmarks
10 from mercurial.node import short
10 from mercurial.node import short
11 from mercurial.i18n import _
11 from mercurial.i18n import _
12 import os
12 import os
13 import errno
13 import errno
14
14
15 def _bundle(repo, bases, heads, node, suffix, compress=True):
15 def _bundle(repo, bases, heads, node, suffix, compress=True):
16 """create a bundle with the specified revisions as a backup"""
16 """create a bundle with the specified revisions as a backup"""
17 cg = repo.changegroupsubset(bases, heads, 'strip')
17 cg = repo.changegroupsubset(bases, heads, 'strip')
18 backupdir = repo.join("strip-backup")
18 backupdir = repo.join("strip-backup")
19 if not os.path.isdir(backupdir):
19 if not os.path.isdir(backupdir):
20 os.mkdir(backupdir)
20 os.mkdir(backupdir)
21 name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
21 name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
22 if compress:
22 if compress:
23 bundletype = "HG10BZ"
23 bundletype = "HG10BZ"
24 else:
24 else:
25 bundletype = "HG10UN"
25 bundletype = "HG10UN"
26 return changegroup.writebundle(cg, name, bundletype)
26 return changegroup.writebundle(cg, name, bundletype)
27
27
28 def _collectfiles(repo, striprev):
28 def _collectfiles(repo, striprev):
29 """find out the filelogs affected by the strip"""
29 """find out the filelogs affected by the strip"""
30 files = set()
30 files = set()
31
31
32 for x in xrange(striprev, len(repo)):
32 for x in xrange(striprev, len(repo)):
33 files.update(repo[x].files())
33 files.update(repo[x].files())
34
34
35 return sorted(files)
35 return sorted(files)
36
36
37 def _collectbrokencsets(repo, files, striprev):
37 def _collectbrokencsets(repo, files, striprev):
38 """return the changesets which will be broken by the truncation"""
38 """return the changesets which will be broken by the truncation"""
39 s = set()
39 s = set()
40 def collectone(revlog):
40 def collectone(revlog):
41 linkgen = (revlog.linkrev(i) for i in revlog)
41 linkgen = (revlog.linkrev(i) for i in revlog)
42 # find the truncation point of the revlog
42 # find the truncation point of the revlog
43 for lrev in linkgen:
43 for lrev in linkgen:
44 if lrev >= striprev:
44 if lrev >= striprev:
45 break
45 break
46 # see if any revision after this point has a linkrev
46 # see if any revision after this point has a linkrev
47 # less than striprev (those will be broken by strip)
47 # less than striprev (those will be broken by strip)
48 for lrev in linkgen:
48 for lrev in linkgen:
49 if lrev < striprev:
49 if lrev < striprev:
50 s.add(lrev)
50 s.add(lrev)
51
51
52 collectone(repo.manifest)
52 collectone(repo.manifest)
53 for fname in files:
53 for fname in files:
54 collectone(repo.file(fname))
54 collectone(repo.file(fname))
55
55
56 return s
56 return s
57
57
58 def strip(ui, repo, nodelist, backup="all", topic='backup'):
58 def strip(ui, repo, nodelist, backup="all", topic='backup'):
59 # It simplifies the logic around updating the branchheads cache if we only
59 # It simplifies the logic around updating the branchheads cache if we only
60 # have to consider the effect of the stripped revisions and not revisions
60 # have to consider the effect of the stripped revisions and not revisions
61 # missing because the cache is out-of-date.
61 # missing because the cache is out-of-date.
62 repo.updatebranchcache()
62 repo.updatebranchcache()
63
63
64 cl = repo.changelog
64 cl = repo.changelog
65 # TODO handle undo of merge sets
65 # TODO handle undo of merge sets
66 if isinstance(nodelist, str):
66 if isinstance(nodelist, str):
67 nodelist = [nodelist]
67 nodelist = [nodelist]
68 striplist = [cl.rev(node) for node in nodelist]
68 striplist = [cl.rev(node) for node in nodelist]
69 striprev = min(striplist)
69 striprev = min(striplist)
70
70
71 # Generate set of branches who will have nodes stripped.
71 # Generate set of branches who will have nodes stripped.
72 striprevs = repo.revs("%ld::", striplist)
72 striprevs = repo.revs("%ld::", striplist)
73 stripbranches = set([repo[rev].branch() for rev in striprevs])
73 stripbranches = set([repo[rev].branch() for rev in striprevs])
74
74
75 # Set of potential new heads resulting from the strip. The parents of any
75 # Set of potential new heads resulting from the strip. The parents of any
76 # node removed could be a new head because the node to be removed could have
76 # node removed could be a new head because the node to be removed could have
77 # been the only child of the parent.
77 # been the only child of the parent.
78 newheadrevs = repo.revs("parents(%ld::) - %ld::", striprevs, striprevs)
78 newheadrevs = repo.revs("parents(%ld::) - %ld::", striprevs, striprevs)
79 newheadnodes = set([cl.node(rev) for rev in newheadrevs])
79 newheadnodes = set([cl.node(rev) for rev in newheadrevs])
80 newheadbranches = set([repo[rev].branch() for rev in newheadrevs])
80 newheadbranches = set([repo[rev].branch() for rev in newheadrevs])
81
81
82 keeppartialbundle = backup == 'strip'
82 keeppartialbundle = backup == 'strip'
83
83
84 # Some revisions with rev > striprev may not be descendants of striprev.
84 # Some revisions with rev > striprev may not be descendants of striprev.
85 # We have to find these revisions and put them in a bundle, so that
85 # We have to find these revisions and put them in a bundle, so that
86 # we can restore them after the truncations.
86 # we can restore them after the truncations.
87 # To create the bundle we use repo.changegroupsubset which requires
87 # To create the bundle we use repo.changegroupsubset which requires
88 # the list of heads and bases of the set of interesting revisions.
88 # the list of heads and bases of the set of interesting revisions.
89 # (head = revision in the set that has no descendant in the set;
89 # (head = revision in the set that has no descendant in the set;
90 # base = revision in the set that has no ancestor in the set)
90 # base = revision in the set that has no ancestor in the set)
91 tostrip = set(striplist)
91 tostrip = set(striplist)
92 for rev in striplist:
92 for rev in striplist:
93 for desc in cl.descendants([rev]):
93 for desc in cl.descendants([rev]):
94 tostrip.add(desc)
94 tostrip.add(desc)
95
95
96 files = _collectfiles(repo, striprev)
96 files = _collectfiles(repo, striprev)
97 saverevs = _collectbrokencsets(repo, files, striprev)
97 saverevs = _collectbrokencsets(repo, files, striprev)
98
98
99 # compute heads
99 # compute heads
100 saveheads = set(saverevs)
100 saveheads = set(saverevs)
101 for r in xrange(striprev + 1, len(cl)):
101 for r in xrange(striprev + 1, len(cl)):
102 if r not in tostrip:
102 if r not in tostrip:
103 saverevs.add(r)
103 saverevs.add(r)
104 saveheads.difference_update(cl.parentrevs(r))
104 saveheads.difference_update(cl.parentrevs(r))
105 saveheads.add(r)
105 saveheads.add(r)
106 saveheads = [cl.node(r) for r in saveheads]
106 saveheads = [cl.node(r) for r in saveheads]
107
107
108 # compute base nodes
108 # compute base nodes
109 if saverevs:
109 if saverevs:
110 descendants = set(cl.descendants(saverevs))
110 descendants = set(cl.descendants(saverevs))
111 saverevs.difference_update(descendants)
111 saverevs.difference_update(descendants)
112 savebases = [cl.node(r) for r in saverevs]
112 savebases = [cl.node(r) for r in saverevs]
113 stripbases = [cl.node(r) for r in tostrip]
113 stripbases = [cl.node(r) for r in tostrip]
114 rset = ' or '.join([str(r) for r in tostrip])
115 newbmtarget = repo.revs('sort(heads(ancestors(%r) - (%r)), -rev)',
116 rset, rset)
117 if newbmtarget:
118 newbmtarget = newbmtarget[0]
119 else:
120 newbmtarget = '.'
114
121
115 bm = repo._bookmarks
122 bm = repo._bookmarks
116 updatebm = []
123 updatebm = []
117 for m in bm:
124 for m in bm:
118 rev = repo[bm[m]].rev()
125 rev = repo[bm[m]].rev()
119 if rev in tostrip:
126 if rev in tostrip:
120 updatebm.append(m)
127 updatebm.append(m)
121
128
122 # create a changegroup for all the branches we need to keep
129 # create a changegroup for all the branches we need to keep
123 backupfile = None
130 backupfile = None
124 if backup == "all":
131 if backup == "all":
125 backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
132 backupfile = _bundle(repo, stripbases, cl.heads(), node, topic)
126 repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
133 repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
127 if saveheads or savebases:
134 if saveheads or savebases:
128 # do not compress partial bundle if we remove it from disk later
135 # do not compress partial bundle if we remove it from disk later
129 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
136 chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
130 compress=keeppartialbundle)
137 compress=keeppartialbundle)
131
138
132 mfst = repo.manifest
139 mfst = repo.manifest
133
140
134 tr = repo.transaction("strip")
141 tr = repo.transaction("strip")
135 offset = len(tr.entries)
142 offset = len(tr.entries)
136
143
137 try:
144 try:
138 tr.startgroup()
145 tr.startgroup()
139 cl.strip(striprev, tr)
146 cl.strip(striprev, tr)
140 mfst.strip(striprev, tr)
147 mfst.strip(striprev, tr)
141 for fn in files:
148 for fn in files:
142 repo.file(fn).strip(striprev, tr)
149 repo.file(fn).strip(striprev, tr)
143 tr.endgroup()
150 tr.endgroup()
144
151
145 try:
152 try:
146 for i in xrange(offset, len(tr.entries)):
153 for i in xrange(offset, len(tr.entries)):
147 file, troffset, ignore = tr.entries[i]
154 file, troffset, ignore = tr.entries[i]
148 repo.sopener(file, 'a').truncate(troffset)
155 repo.sopener(file, 'a').truncate(troffset)
149 tr.close()
156 tr.close()
150 except: # re-raises
157 except: # re-raises
151 tr.abort()
158 tr.abort()
152 raise
159 raise
153
160
154 if saveheads or savebases:
161 if saveheads or savebases:
155 ui.note(_("adding branch\n"))
162 ui.note(_("adding branch\n"))
156 f = open(chgrpfile, "rb")
163 f = open(chgrpfile, "rb")
157 gen = changegroup.readbundle(f, chgrpfile)
164 gen = changegroup.readbundle(f, chgrpfile)
158 if not repo.ui.verbose:
165 if not repo.ui.verbose:
159 # silence internal shuffling chatter
166 # silence internal shuffling chatter
160 repo.ui.pushbuffer()
167 repo.ui.pushbuffer()
161 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
168 repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
162 if not repo.ui.verbose:
169 if not repo.ui.verbose:
163 repo.ui.popbuffer()
170 repo.ui.popbuffer()
164 f.close()
171 f.close()
165 if not keeppartialbundle:
172 if not keeppartialbundle:
166 os.unlink(chgrpfile)
173 os.unlink(chgrpfile)
167
174
168 # remove undo files
175 # remove undo files
169 for undofile in repo.undofiles():
176 for undofile in repo.undofiles():
170 try:
177 try:
171 os.unlink(undofile)
178 os.unlink(undofile)
172 except OSError, e:
179 except OSError, e:
173 if e.errno != errno.ENOENT:
180 if e.errno != errno.ENOENT:
174 ui.warn(_('error removing %s: %s\n') % (undofile, str(e)))
181 ui.warn(_('error removing %s: %s\n') % (undofile, str(e)))
175
182
176 for m in updatebm:
183 for m in updatebm:
177 bm[m] = repo['.'].node()
184 bm[m] = repo[newbmtarget].node()
178 bookmarks.write(repo)
185 bookmarks.write(repo)
179 except: # re-raises
186 except: # re-raises
180 if backupfile:
187 if backupfile:
181 ui.warn(_("strip failed, full bundle stored in '%s'\n")
188 ui.warn(_("strip failed, full bundle stored in '%s'\n")
182 % backupfile)
189 % backupfile)
183 elif saveheads:
190 elif saveheads:
184 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
191 ui.warn(_("strip failed, partial bundle stored in '%s'\n")
185 % chgrpfile)
192 % chgrpfile)
186 raise
193 raise
187
194
188 if len(stripbranches) == 1 and len(newheadbranches) == 1 \
195 if len(stripbranches) == 1 and len(newheadbranches) == 1 \
189 and stripbranches == newheadbranches:
196 and stripbranches == newheadbranches:
190 repo.destroyed(newheadnodes)
197 repo.destroyed(newheadnodes)
191 else:
198 else:
192 # Multiple branches involved in strip. Will allow branchcache to become
199 # Multiple branches involved in strip. Will allow branchcache to become
193 # invalid and later on rebuilt from scratch
200 # invalid and later on rebuilt from scratch
194 repo.destroyed()
201 repo.destroyed()
195
@@ -1,116 +1,116 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
2 $ echo "mq=" >> $HGRCPATH
3
3
4 $ hg init
4 $ hg init
5
5
6 $ echo qqq>qqq.txt
6 $ echo qqq>qqq.txt
7
7
8 rollback dry run without rollback information
8 rollback dry run without rollback information
9
9
10 $ hg rollback
10 $ hg rollback
11 no rollback information available
11 no rollback information available
12 [1]
12 [1]
13
13
14 add file
14 add file
15
15
16 $ hg add
16 $ hg add
17 adding qqq.txt
17 adding qqq.txt
18
18
19 commit first revision
19 commit first revision
20
20
21 $ hg ci -m 1
21 $ hg ci -m 1
22
22
23 set bookmark
23 set bookmark
24
24
25 $ hg book test
25 $ hg book test
26
26
27 $ echo www>>qqq.txt
27 $ echo www>>qqq.txt
28
28
29 commit second revision
29 commit second revision
30
30
31 $ hg ci -m 2
31 $ hg ci -m 2
32
32
33 set bookmark
33 set bookmark
34
34
35 $ hg book test2
35 $ hg book test2
36
36
37 update to -2 (inactives the active bookmark)
37 update to -2 (inactives the active bookmark)
38
38
39 $ hg update -r -2
39 $ hg update -r -2
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41
41
42 $ echo eee>>qqq.txt
42 $ echo eee>>qqq.txt
43
43
44 commit new head
44 commit new head
45
45
46 $ hg ci -m 3
46 $ hg ci -m 3
47 created new head
47 created new head
48
48
49 bookmarks updated?
49 bookmarks updated?
50
50
51 $ hg book
51 $ hg book
52 test 1:25e1ee7a0081
52 test 1:25e1ee7a0081
53 test2 1:25e1ee7a0081
53 test2 1:25e1ee7a0081
54
54
55 strip to revision 1
55 strip to revision 1
56
56
57 $ hg strip 1
57 $ hg strip 1
58 saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
58 saved backup bundle to $TESTTMP/.hg/strip-backup/*-backup.hg (glob)
59
59
60 list bookmarks
60 list bookmarks
61
61
62 $ hg book
62 $ hg book
63 test 1:8cf31af87a2b
63 test 0:5c9ad3787638
64 test2 1:8cf31af87a2b
64 test2 0:5c9ad3787638
65
65
66 immediate rollback and reentrancy issue
66 immediate rollback and reentrancy issue
67
67
68 $ echo "mq=!" >> $HGRCPATH
68 $ echo "mq=!" >> $HGRCPATH
69 $ hg init repo
69 $ hg init repo
70 $ cd repo
70 $ cd repo
71 $ echo a > a
71 $ echo a > a
72 $ hg ci -Am adda
72 $ hg ci -Am adda
73 adding a
73 adding a
74 $ echo b > b
74 $ echo b > b
75 $ hg ci -Am addb
75 $ hg ci -Am addb
76 adding b
76 adding b
77 $ hg bookmarks markb
77 $ hg bookmarks markb
78 $ hg rollback
78 $ hg rollback
79 repository tip rolled back to revision 0 (undo commit)
79 repository tip rolled back to revision 0 (undo commit)
80 working directory now based on revision 0
80 working directory now based on revision 0
81
81
82 are you there?
82 are you there?
83
83
84 $ hg bookmarks
84 $ hg bookmarks
85 no bookmarks set
85 no bookmarks set
86
86
87 can we commit? (issue2692)
87 can we commit? (issue2692)
88
88
89 $ echo c > c
89 $ echo c > c
90 $ hg ci -Am rockon
90 $ hg ci -Am rockon
91 adding c
91 adding c
92
92
93 can you be added again?
93 can you be added again?
94
94
95 $ hg bookmarks markb
95 $ hg bookmarks markb
96 $ hg bookmarks
96 $ hg bookmarks
97 * markb 1:fdb34407462c
97 * markb 1:fdb34407462c
98
98
99 rollback dry run with rollback information
99 rollback dry run with rollback information
100
100
101 $ hg rollback -n
101 $ hg rollback -n
102 repository tip rolled back to revision 0 (undo commit)
102 repository tip rolled back to revision 0 (undo commit)
103 $ hg bookmarks
103 $ hg bookmarks
104 * markb 1:fdb34407462c
104 * markb 1:fdb34407462c
105
105
106 rollback dry run with rollback information and no commit undo
106 rollback dry run with rollback information and no commit undo
107
107
108 $ rm .hg/store/undo
108 $ rm .hg/store/undo
109 $ hg rollback -n
109 $ hg rollback -n
110 no rollback information available
110 no rollback information available
111 [1]
111 [1]
112 $ hg bookmarks
112 $ hg bookmarks
113 * markb 1:fdb34407462c
113 * markb 1:fdb34407462c
114
114
115 $ cd ..
115 $ cd ..
116
116
@@ -1,392 +1,459 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 bookmark rev -1
8 bookmark rev -1
9
9
10 $ hg bookmark X
10 $ hg bookmark X
11
11
12 list bookmarks
12 list bookmarks
13
13
14 $ hg bookmarks
14 $ hg bookmarks
15 * X -1:000000000000
15 * X -1:000000000000
16
16
17 list bookmarks with color
17 list bookmarks with color
18
18
19 $ hg --config extensions.color= --config color.mode=ansi \
19 $ hg --config extensions.color= --config color.mode=ansi \
20 > bookmarks --color=always
20 > bookmarks --color=always
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
21 \x1b[0;32m * X -1:000000000000\x1b[0m (esc)
22
22
23 $ echo a > a
23 $ echo a > a
24 $ hg add a
24 $ hg add a
25 $ hg commit -m 0
25 $ hg commit -m 0
26
26
27 bookmark X moved to rev 0
27 bookmark X moved to rev 0
28
28
29 $ hg bookmarks
29 $ hg bookmarks
30 * X 0:f7b1eb17ad24
30 * X 0:f7b1eb17ad24
31
31
32 look up bookmark
32 look up bookmark
33
33
34 $ hg log -r X
34 $ hg log -r X
35 changeset: 0:f7b1eb17ad24
35 changeset: 0:f7b1eb17ad24
36 bookmark: X
36 bookmark: X
37 tag: tip
37 tag: tip
38 user: test
38 user: test
39 date: Thu Jan 01 00:00:00 1970 +0000
39 date: Thu Jan 01 00:00:00 1970 +0000
40 summary: 0
40 summary: 0
41
41
42
42
43 second bookmark for rev 0
43 second bookmark for rev 0
44
44
45 $ hg bookmark X2
45 $ hg bookmark X2
46
46
47 bookmark rev -1 again
47 bookmark rev -1 again
48
48
49 $ hg bookmark -r null Y
49 $ hg bookmark -r null Y
50
50
51 list bookmarks
51 list bookmarks
52
52
53 $ hg bookmarks
53 $ hg bookmarks
54 X 0:f7b1eb17ad24
54 X 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
55 * X2 0:f7b1eb17ad24
56 Y -1:000000000000
56 Y -1:000000000000
57
57
58 $ echo b > b
58 $ echo b > b
59 $ hg add b
59 $ hg add b
60 $ hg commit -m 1
60 $ hg commit -m 1
61
61
62 bookmarks revset
62 bookmarks revset
63
63
64 $ hg log -r 'bookmark()'
64 $ hg log -r 'bookmark()'
65 changeset: 0:f7b1eb17ad24
65 changeset: 0:f7b1eb17ad24
66 bookmark: X
66 bookmark: X
67 user: test
67 user: test
68 date: Thu Jan 01 00:00:00 1970 +0000
68 date: Thu Jan 01 00:00:00 1970 +0000
69 summary: 0
69 summary: 0
70
70
71 changeset: 1:925d80f479bb
71 changeset: 1:925d80f479bb
72 bookmark: X2
72 bookmark: X2
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: 1
76 summary: 1
77
77
78 $ hg log -r 'bookmark(Y)'
78 $ hg log -r 'bookmark(Y)'
79 $ hg log -r 'bookmark(X2)'
79 $ hg log -r 'bookmark(X2)'
80 changeset: 1:925d80f479bb
80 changeset: 1:925d80f479bb
81 bookmark: X2
81 bookmark: X2
82 tag: tip
82 tag: tip
83 user: test
83 user: test
84 date: Thu Jan 01 00:00:00 1970 +0000
84 date: Thu Jan 01 00:00:00 1970 +0000
85 summary: 1
85 summary: 1
86
86
87 $ hg log -r 'bookmark("re:X")'
87 $ hg log -r 'bookmark("re:X")'
88 changeset: 0:f7b1eb17ad24
88 changeset: 0:f7b1eb17ad24
89 bookmark: X
89 bookmark: X
90 user: test
90 user: test
91 date: Thu Jan 01 00:00:00 1970 +0000
91 date: Thu Jan 01 00:00:00 1970 +0000
92 summary: 0
92 summary: 0
93
93
94 changeset: 1:925d80f479bb
94 changeset: 1:925d80f479bb
95 bookmark: X2
95 bookmark: X2
96 tag: tip
96 tag: tip
97 user: test
97 user: test
98 date: Thu Jan 01 00:00:00 1970 +0000
98 date: Thu Jan 01 00:00:00 1970 +0000
99 summary: 1
99 summary: 1
100
100
101 $ hg log -r 'bookmark(unknown)'
101 $ hg log -r 'bookmark(unknown)'
102 abort: bookmark 'unknown' does not exist
102 abort: bookmark 'unknown' does not exist
103 [255]
103 [255]
104
104
105 $ hg help revsets | grep 'bookmark('
105 $ hg help revsets | grep 'bookmark('
106 "bookmark([name])"
106 "bookmark([name])"
107
107
108 bookmarks X and X2 moved to rev 1, Y at rev -1
108 bookmarks X and X2 moved to rev 1, Y at rev -1
109
109
110 $ hg bookmarks
110 $ hg bookmarks
111 X 0:f7b1eb17ad24
111 X 0:f7b1eb17ad24
112 * X2 1:925d80f479bb
112 * X2 1:925d80f479bb
113 Y -1:000000000000
113 Y -1:000000000000
114
114
115 bookmark rev 0 again
115 bookmark rev 0 again
116
116
117 $ hg bookmark -r 0 Z
117 $ hg bookmark -r 0 Z
118
118
119 $ hg update X
119 $ hg update X
120 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
120 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
121 $ echo c > c
121 $ echo c > c
122 $ hg add c
122 $ hg add c
123 $ hg commit -m 2
123 $ hg commit -m 2
124 created new head
124 created new head
125
125
126 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
126 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
127
127
128 $ hg bookmarks
128 $ hg bookmarks
129 * X 2:db815d6d32e6
129 * X 2:db815d6d32e6
130 X2 1:925d80f479bb
130 X2 1:925d80f479bb
131 Y -1:000000000000
131 Y -1:000000000000
132 Z 0:f7b1eb17ad24
132 Z 0:f7b1eb17ad24
133
133
134 rename nonexistent bookmark
134 rename nonexistent bookmark
135
135
136 $ hg bookmark -m A B
136 $ hg bookmark -m A B
137 abort: bookmark 'A' does not exist
137 abort: bookmark 'A' does not exist
138 [255]
138 [255]
139
139
140 rename to existent bookmark
140 rename to existent bookmark
141
141
142 $ hg bookmark -m X Y
142 $ hg bookmark -m X Y
143 abort: bookmark 'Y' already exists (use -f to force)
143 abort: bookmark 'Y' already exists (use -f to force)
144 [255]
144 [255]
145
145
146 force rename to existent bookmark
146 force rename to existent bookmark
147
147
148 $ hg bookmark -f -m X Y
148 $ hg bookmark -f -m X Y
149
149
150 list bookmarks
150 list bookmarks
151
151
152 $ hg bookmark
152 $ hg bookmark
153 X2 1:925d80f479bb
153 X2 1:925d80f479bb
154 * Y 2:db815d6d32e6
154 * Y 2:db815d6d32e6
155 Z 0:f7b1eb17ad24
155 Z 0:f7b1eb17ad24
156
156
157 rename without new name
157 rename without new name
158
158
159 $ hg bookmark -m Y
159 $ hg bookmark -m Y
160 abort: new bookmark name required
160 abort: new bookmark name required
161 [255]
161 [255]
162
162
163 delete without name
163 delete without name
164
164
165 $ hg bookmark -d
165 $ hg bookmark -d
166 abort: bookmark name required
166 abort: bookmark name required
167 [255]
167 [255]
168
168
169 delete nonexistent bookmark
169 delete nonexistent bookmark
170
170
171 $ hg bookmark -d A
171 $ hg bookmark -d A
172 abort: bookmark 'A' does not exist
172 abort: bookmark 'A' does not exist
173 [255]
173 [255]
174
174
175 bookmark name with spaces should be stripped
175 bookmark name with spaces should be stripped
176
176
177 $ hg bookmark ' x y '
177 $ hg bookmark ' x y '
178
178
179 list bookmarks
179 list bookmarks
180
180
181 $ hg bookmarks
181 $ hg bookmarks
182 X2 1:925d80f479bb
182 X2 1:925d80f479bb
183 Y 2:db815d6d32e6
183 Y 2:db815d6d32e6
184 Z 0:f7b1eb17ad24
184 Z 0:f7b1eb17ad24
185 * x y 2:db815d6d32e6
185 * x y 2:db815d6d32e6
186
186
187 look up stripped bookmark name
187 look up stripped bookmark name
188
188
189 $ hg log -r '"x y"'
189 $ hg log -r '"x y"'
190 changeset: 2:db815d6d32e6
190 changeset: 2:db815d6d32e6
191 bookmark: Y
191 bookmark: Y
192 bookmark: x y
192 bookmark: x y
193 tag: tip
193 tag: tip
194 parent: 0:f7b1eb17ad24
194 parent: 0:f7b1eb17ad24
195 user: test
195 user: test
196 date: Thu Jan 01 00:00:00 1970 +0000
196 date: Thu Jan 01 00:00:00 1970 +0000
197 summary: 2
197 summary: 2
198
198
199
199
200 reject bookmark name with newline
200 reject bookmark name with newline
201
201
202 $ hg bookmark '
202 $ hg bookmark '
203 > '
203 > '
204 abort: bookmark name cannot contain newlines
204 abort: bookmark name cannot contain newlines
205 [255]
205 [255]
206
206
207 bookmark with existing name
207 bookmark with existing name
208
208
209 $ hg bookmark Z
209 $ hg bookmark Z
210 abort: bookmark 'Z' already exists (use -f to force)
210 abort: bookmark 'Z' already exists (use -f to force)
211 [255]
211 [255]
212
212
213 force bookmark with existing name
213 force bookmark with existing name
214
214
215 $ hg bookmark -f Z
215 $ hg bookmark -f Z
216
216
217 list bookmarks
217 list bookmarks
218
218
219 $ hg bookmark
219 $ hg bookmark
220 X2 1:925d80f479bb
220 X2 1:925d80f479bb
221 Y 2:db815d6d32e6
221 Y 2:db815d6d32e6
222 * Z 2:db815d6d32e6
222 * Z 2:db815d6d32e6
223 x y 2:db815d6d32e6
223 x y 2:db815d6d32e6
224
224
225 revision but no bookmark name
225 revision but no bookmark name
226
226
227 $ hg bookmark -r .
227 $ hg bookmark -r .
228 abort: bookmark name required
228 abort: bookmark name required
229 [255]
229 [255]
230
230
231 bookmark name with whitespace only
231 bookmark name with whitespace only
232
232
233 $ hg bookmark ' '
233 $ hg bookmark ' '
234 abort: bookmark names cannot consist entirely of whitespace
234 abort: bookmark names cannot consist entirely of whitespace
235 [255]
235 [255]
236
236
237 invalid bookmark
237 invalid bookmark
238
238
239 $ hg bookmark 'foo:bar'
239 $ hg bookmark 'foo:bar'
240 abort: bookmark 'foo:bar' contains illegal character
240 abort: bookmark 'foo:bar' contains illegal character
241 [255]
241 [255]
242
242
243 the bookmark extension should be ignored now that it is part of core
243 the bookmark extension should be ignored now that it is part of core
244
244
245 $ echo "[extensions]" >> $HGRCPATH
245 $ echo "[extensions]" >> $HGRCPATH
246 $ echo "bookmarks=" >> $HGRCPATH
246 $ echo "bookmarks=" >> $HGRCPATH
247 $ hg bookmarks
247 $ hg bookmarks
248 X2 1:925d80f479bb
248 X2 1:925d80f479bb
249 Y 2:db815d6d32e6
249 Y 2:db815d6d32e6
250 * Z 2:db815d6d32e6
250 * Z 2:db815d6d32e6
251 x y 2:db815d6d32e6
251 x y 2:db815d6d32e6
252
252
253 test summary
253 test summary
254
254
255 $ hg summary
255 $ hg summary
256 parent: 2:db815d6d32e6 tip
256 parent: 2:db815d6d32e6 tip
257 2
257 2
258 branch: default
258 branch: default
259 bookmarks: *Z Y x y
259 bookmarks: *Z Y x y
260 commit: (clean)
260 commit: (clean)
261 update: 1 new changesets, 2 branch heads (merge)
261 update: 1 new changesets, 2 branch heads (merge)
262
262
263 test id
263 test id
264
264
265 $ hg id
265 $ hg id
266 db815d6d32e6 tip Y/Z/x y
266 db815d6d32e6 tip Y/Z/x y
267
267
268 test rollback
268 test rollback
269
269
270 $ echo foo > f1
270 $ echo foo > f1
271 $ hg ci -Amr
271 $ hg ci -Amr
272 adding f1
272 adding f1
273 $ hg bookmark -f Y -r 1
273 $ hg bookmark -f Y -r 1
274 $ hg bookmark -f Z -r 1
274 $ hg bookmark -f Z -r 1
275 $ hg rollback
275 $ hg rollback
276 repository tip rolled back to revision 2 (undo commit)
276 repository tip rolled back to revision 2 (undo commit)
277 working directory now based on revision 2
277 working directory now based on revision 2
278 $ hg bookmarks
278 $ hg bookmarks
279 X2 1:925d80f479bb
279 X2 1:925d80f479bb
280 Y 2:db815d6d32e6
280 Y 2:db815d6d32e6
281 * Z 2:db815d6d32e6
281 * Z 2:db815d6d32e6
282 x y 2:db815d6d32e6
282 x y 2:db815d6d32e6
283
283
284 test clone
284 test clone
285
285
286 $ hg bookmark -r 2 -i @
286 $ hg bookmark -r 2 -i @
287 $ hg bookmark -r 2 -i a@
287 $ hg bookmark -r 2 -i a@
288 $ hg bookmarks
288 $ hg bookmarks
289 @ 2:db815d6d32e6
289 @ 2:db815d6d32e6
290 X2 1:925d80f479bb
290 X2 1:925d80f479bb
291 Y 2:db815d6d32e6
291 Y 2:db815d6d32e6
292 * Z 2:db815d6d32e6
292 * Z 2:db815d6d32e6
293 a@ 2:db815d6d32e6
293 a@ 2:db815d6d32e6
294 x y 2:db815d6d32e6
294 x y 2:db815d6d32e6
295 $ hg clone . cloned-bookmarks
295 $ hg clone . cloned-bookmarks
296 updating to branch default
296 updating to branch default
297 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
297 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
298 $ hg -R cloned-bookmarks bookmarks
298 $ hg -R cloned-bookmarks bookmarks
299 @ 2:db815d6d32e6
299 @ 2:db815d6d32e6
300 X2 1:925d80f479bb
300 X2 1:925d80f479bb
301 Y 2:db815d6d32e6
301 Y 2:db815d6d32e6
302 Z 2:db815d6d32e6
302 Z 2:db815d6d32e6
303 a@ 2:db815d6d32e6
303 a@ 2:db815d6d32e6
304 x y 2:db815d6d32e6
304 x y 2:db815d6d32e6
305
305
306 test clone with pull protocol
306 test clone with pull protocol
307
307
308 $ hg clone --pull . cloned-bookmarks-pull
308 $ hg clone --pull . cloned-bookmarks-pull
309 requesting all changes
309 requesting all changes
310 adding changesets
310 adding changesets
311 adding manifests
311 adding manifests
312 adding file changes
312 adding file changes
313 added 3 changesets with 3 changes to 3 files (+1 heads)
313 added 3 changesets with 3 changes to 3 files (+1 heads)
314 updating to branch default
314 updating to branch default
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
315 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 $ hg -R cloned-bookmarks-pull bookmarks
316 $ hg -R cloned-bookmarks-pull bookmarks
317 @ 2:db815d6d32e6
317 @ 2:db815d6d32e6
318 X2 1:925d80f479bb
318 X2 1:925d80f479bb
319 Y 2:db815d6d32e6
319 Y 2:db815d6d32e6
320 Z 2:db815d6d32e6
320 Z 2:db815d6d32e6
321 a@ 2:db815d6d32e6
321 a@ 2:db815d6d32e6
322 x y 2:db815d6d32e6
322 x y 2:db815d6d32e6
323
323
324 $ hg bookmark -d @
324 $ hg bookmark -d @
325 $ hg bookmark -d a@
325 $ hg bookmark -d a@
326
326
327 test clone with a specific revision
327 test clone with a specific revision
328
328
329 $ hg clone -r 925d80 . cloned-bookmarks-rev
329 $ hg clone -r 925d80 . cloned-bookmarks-rev
330 adding changesets
330 adding changesets
331 adding manifests
331 adding manifests
332 adding file changes
332 adding file changes
333 added 2 changesets with 2 changes to 2 files
333 added 2 changesets with 2 changes to 2 files
334 updating to branch default
334 updating to branch default
335 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
335 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
336 $ hg -R cloned-bookmarks-rev bookmarks
336 $ hg -R cloned-bookmarks-rev bookmarks
337 X2 1:925d80f479bb
337 X2 1:925d80f479bb
338
338
339 create bundle with two heads
339 create bundle with two heads
340
340
341 $ hg clone . tobundle
341 $ hg clone . tobundle
342 updating to branch default
342 updating to branch default
343 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
344 $ echo x > tobundle/x
344 $ echo x > tobundle/x
345 $ hg -R tobundle add tobundle/x
345 $ hg -R tobundle add tobundle/x
346 $ hg -R tobundle commit -m'x'
346 $ hg -R tobundle commit -m'x'
347 $ hg -R tobundle update -r -2
347 $ hg -R tobundle update -r -2
348 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
348 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
349 $ echo y > tobundle/y
349 $ echo y > tobundle/y
350 $ hg -R tobundle branch test
350 $ hg -R tobundle branch test
351 marked working directory as branch test
351 marked working directory as branch test
352 (branches are permanent and global, did you want a bookmark?)
352 (branches are permanent and global, did you want a bookmark?)
353 $ hg -R tobundle add tobundle/y
353 $ hg -R tobundle add tobundle/y
354 $ hg -R tobundle commit -m'y'
354 $ hg -R tobundle commit -m'y'
355 $ hg -R tobundle bundle tobundle.hg
355 $ hg -R tobundle bundle tobundle.hg
356 searching for changes
356 searching for changes
357 2 changesets found
357 2 changesets found
358 $ hg unbundle tobundle.hg
358 $ hg unbundle tobundle.hg
359 adding changesets
359 adding changesets
360 adding manifests
360 adding manifests
361 adding file changes
361 adding file changes
362 added 2 changesets with 2 changes to 2 files (+1 heads)
362 added 2 changesets with 2 changes to 2 files (+1 heads)
363 (run 'hg heads' to see heads, 'hg merge' to merge)
363 (run 'hg heads' to see heads, 'hg merge' to merge)
364 $ hg update
364 $ hg update
365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
366 $ hg bookmarks
366 $ hg bookmarks
367 X2 1:925d80f479bb
367 X2 1:925d80f479bb
368 Y 2:db815d6d32e6
368 Y 2:db815d6d32e6
369 * Z 3:125c9a1d6df6
369 * Z 3:125c9a1d6df6
370 x y 2:db815d6d32e6
370 x y 2:db815d6d32e6
371
371
372 test wrongly formated bookmark
372 test wrongly formated bookmark
373
373
374 $ echo '' >> .hg/bookmarks
374 $ echo '' >> .hg/bookmarks
375 $ hg bookmarks
375 $ hg bookmarks
376 X2 1:925d80f479bb
376 X2 1:925d80f479bb
377 Y 2:db815d6d32e6
377 Y 2:db815d6d32e6
378 * Z 3:125c9a1d6df6
378 * Z 3:125c9a1d6df6
379 x y 2:db815d6d32e6
379 x y 2:db815d6d32e6
380 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
380 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
381 $ hg bookmarks
381 $ hg bookmarks
382 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
382 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
383 X2 1:925d80f479bb
383 X2 1:925d80f479bb
384 Y 2:db815d6d32e6
384 Y 2:db815d6d32e6
385 * Z 3:125c9a1d6df6
385 * Z 3:125c9a1d6df6
386 x y 2:db815d6d32e6
386 x y 2:db815d6d32e6
387
387
388 test missing revisions
388 test missing revisions
389
389
390 $ echo "925d80f479bc z" > .hg/bookmarks
390 $ echo "925d80f479bc z" > .hg/bookmarks
391 $ hg book
391 $ hg book
392 no bookmarks set
392 no bookmarks set
393
394 test stripping a non-checked-out but bookmarked revision
395
396 $ hg --config extensions.graphlog= log --graph
397 o changeset: 4:9ba5f110a0b3
398 | branch: test
399 | tag: tip
400 | parent: 2:db815d6d32e6
401 | user: test
402 | date: Thu Jan 01 00:00:00 1970 +0000
403 | summary: y
404 |
405 | @ changeset: 3:125c9a1d6df6
406 |/ user: test
407 | date: Thu Jan 01 00:00:00 1970 +0000
408 | summary: x
409 |
410 o changeset: 2:db815d6d32e6
411 | parent: 0:f7b1eb17ad24
412 | user: test
413 | date: Thu Jan 01 00:00:00 1970 +0000
414 | summary: 2
415 |
416 | o changeset: 1:925d80f479bb
417 |/ user: test
418 | date: Thu Jan 01 00:00:00 1970 +0000
419 | summary: 1
420 |
421 o changeset: 0:f7b1eb17ad24
422 user: test
423 date: Thu Jan 01 00:00:00 1970 +0000
424 summary: 0
425
426 $ hg book should-end-on-two
427 $ hg co --clean 4
428 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
429 $ hg book four
430 $ hg --config extensions.mq= strip 3
431 saved backup bundle to * (glob)
432 should-end-on-two should end up pointing to revision 2, as that's the
433 tipmost surviving ancestor of the stripped revision.
434 $ hg --config extensions.graphlog= log --graph
435 @ changeset: 3:9ba5f110a0b3
436 | branch: test
437 | bookmark: four
438 | tag: tip
439 | user: test
440 | date: Thu Jan 01 00:00:00 1970 +0000
441 | summary: y
442 |
443 o changeset: 2:db815d6d32e6
444 | bookmark: should-end-on-two
445 | parent: 0:f7b1eb17ad24
446 | user: test
447 | date: Thu Jan 01 00:00:00 1970 +0000
448 | summary: 2
449 |
450 | o changeset: 1:925d80f479bb
451 |/ user: test
452 | date: Thu Jan 01 00:00:00 1970 +0000
453 | summary: 1
454 |
455 o changeset: 0:f7b1eb17ad24
456 user: test
457 date: Thu Jan 01 00:00:00 1970 +0000
458 summary: 0
459
General Comments 0
You need to be logged in to leave comments. Login now