##// END OF EJS Templates
debugobsolete: add --flags option...
Pierre-Yves David -
r17830:1cb51d65 default
parent child Browse files
Show More
@@ -1,5927 +1,5929 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (e.g. if
546 - mark the current revision, or a known revision, to be skipped (e.g. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - forget the current bisection::
552 - forget the current bisection::
553
553
554 hg bisect --reset
554 hg bisect --reset
555
555
556 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
557 revision::
557 revision::
558
558
559 hg bisect --reset
559 hg bisect --reset
560 hg bisect --bad 34
560 hg bisect --bad 34
561 hg bisect --good 12
561 hg bisect --good 12
562 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
563
563
564 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
565 bisection::
565 bisection::
566
566
567 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
568
568
569 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
570 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
571
571
572 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
573
573
574 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
575
575
576 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
577
577
578 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
579
579
580 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
581
581
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
583
583
584 Returns 0 on success.
584 Returns 0 on success.
585 """
585 """
586 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
587 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
588 # one of the parent was not checked.
588 # one of the parent was not checked.
589 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
590 if len(parents) > 1:
590 if len(parents) > 1:
591 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
592 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
593 if num == 1:
593 if num == 1:
594 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
595 return None
595 return None
596
596
597 def print_result(nodes, good):
597 def print_result(nodes, good):
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
599 if len(nodes) == 1:
599 if len(nodes) == 1:
600 # narrowed it down to a single revision
600 # narrowed it down to a single revision
601 if good:
601 if good:
602 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
603 else:
603 else:
604 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
605 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
606 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
607 if extendnode is not None:
607 if extendnode is not None:
608 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
609 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
610 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
611 % extendnode)
611 % extendnode)
612 else:
612 else:
613 # multiple possible revisions
613 # multiple possible revisions
614 if good:
614 if good:
615 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
616 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
617 else:
617 else:
618 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
619 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
620 for n in nodes:
620 for n in nodes:
621 displayer.show(repo[n])
621 displayer.show(repo[n])
622 displayer.close()
622 displayer.close()
623
623
624 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
625 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
626 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
627 return
627 return
628 if not state['good']:
628 if not state['good']:
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
630 else:
630 else:
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
632 return True
632 return True
633
633
634 # backward compatibility
634 # backward compatibility
635 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
637 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
638 if cmd == "good":
638 if cmd == "good":
639 good = True
639 good = True
640 elif cmd == "bad":
640 elif cmd == "bad":
641 bad = True
641 bad = True
642 else:
642 else:
643 reset = True
643 reset = True
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
645 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
646
646
647 if reset:
647 if reset:
648 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
649 if os.path.exists(p):
649 if os.path.exists(p):
650 os.unlink(p)
650 os.unlink(p)
651 return
651 return
652
652
653 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
654
654
655 if command:
655 if command:
656 changesets = 1
656 changesets = 1
657 try:
657 try:
658 node = state['current'][0]
658 node = state['current'][0]
659 except LookupError:
659 except LookupError:
660 if noupdate:
660 if noupdate:
661 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
662 'start a new bisect to fix'))
662 'start a new bisect to fix'))
663 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
664 if p2 != nullid:
664 if p2 != nullid:
665 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
666 try:
666 try:
667 while changesets:
667 while changesets:
668 # update state
668 # update state
669 state['current'] = [node]
669 state['current'] = [node]
670 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
671 status = util.system(command,
671 status = util.system(command,
672 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
673 out=ui.fout)
673 out=ui.fout)
674 if status == 125:
674 if status == 125:
675 transition = "skip"
675 transition = "skip"
676 elif status == 0:
676 elif status == 0:
677 transition = "good"
677 transition = "good"
678 # status < 0 means process was killed
678 # status < 0 means process was killed
679 elif status == 127:
679 elif status == 127:
680 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
681 elif status < 0:
681 elif status < 0:
682 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
683 else:
683 else:
684 transition = "bad"
684 transition = "bad"
685 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
686 rev = None # clear for future iterations
686 rev = None # clear for future iterations
687 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
689 check_state(state, interactive=False)
689 check_state(state, interactive=False)
690 # bisect
690 # bisect
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
692 # update to next check
692 # update to next check
693 node = nodes[0]
693 node = nodes[0]
694 if not noupdate:
694 if not noupdate:
695 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 finally:
697 finally:
698 state['current'] = [node]
698 state['current'] = [node]
699 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
700 print_result(nodes, good)
700 print_result(nodes, good)
701 return
701 return
702
702
703 # update state
703 # update state
704
704
705 if rev:
705 if rev:
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
707 else:
707 else:
708 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
709
709
710 if good or bad or skip:
710 if good or bad or skip:
711 if good:
711 if good:
712 state['good'] += nodes
712 state['good'] += nodes
713 elif bad:
713 elif bad:
714 state['bad'] += nodes
714 state['bad'] += nodes
715 elif skip:
715 elif skip:
716 state['skip'] += nodes
716 state['skip'] += nodes
717 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
718
718
719 if not check_state(state):
719 if not check_state(state):
720 return
720 return
721
721
722 # actually bisect
722 # actually bisect
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
724 if extend:
724 if extend:
725 if not changesets:
725 if not changesets:
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
729 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
730 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
731 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
732 if noupdate:
732 if noupdate:
733 return
733 return
734 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
735 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
736 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
737
737
738 if changesets == 0:
738 if changesets == 0:
739 print_result(nodes, good)
739 print_result(nodes, good)
740 else:
740 else:
741 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
742 node = nodes[0]
742 node = nodes[0]
743 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
744 tests, size = 0, 2
744 tests, size = 0, 2
745 while size <= changesets:
745 while size <= changesets:
746 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
747 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
748 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
749 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
750 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
751 state['current'] = [node]
751 state['current'] = [node]
752 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
753 if not noupdate:
753 if not noupdate:
754 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
755 return hg.clean(repo, node)
755 return hg.clean(repo, node)
756
756
757 @command('bookmarks',
757 @command('bookmarks',
758 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
765 rename=None, inactive=False):
765 rename=None, inactive=False):
766 '''track a line of development with movable markers
766 '''track a line of development with movable markers
767
767
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
771 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
772
772
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
774 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
775 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
776 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
777
777
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
779 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
781 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
782
782
783 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
785 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
786 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
787 '''
787 '''
788 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
789 marks = repo._bookmarks
789 marks = repo._bookmarks
790 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
791
791
792 def checkformat(mark):
792 def checkformat(mark):
793 mark = mark.strip()
793 mark = mark.strip()
794 if not mark:
794 if not mark:
795 raise util.Abort(_("bookmark names cannot consist entirely of "
795 raise util.Abort(_("bookmark names cannot consist entirely of "
796 "whitespace"))
796 "whitespace"))
797 scmutil.checknewlabel(repo, mark, 'bookmark')
797 scmutil.checknewlabel(repo, mark, 'bookmark')
798 return mark
798 return mark
799
799
800 def checkconflict(repo, mark, force=False):
800 def checkconflict(repo, mark, force=False):
801 if mark in marks and not force:
801 if mark in marks and not force:
802 raise util.Abort(_("bookmark '%s' already exists "
802 raise util.Abort(_("bookmark '%s' already exists "
803 "(use -f to force)") % mark)
803 "(use -f to force)") % mark)
804 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
804 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
805 and not force):
805 and not force):
806 raise util.Abort(
806 raise util.Abort(
807 _("a bookmark cannot have the name of an existing branch"))
807 _("a bookmark cannot have the name of an existing branch"))
808
808
809 if delete and rename:
809 if delete and rename:
810 raise util.Abort(_("--delete and --rename are incompatible"))
810 raise util.Abort(_("--delete and --rename are incompatible"))
811 if delete and rev:
811 if delete and rev:
812 raise util.Abort(_("--rev is incompatible with --delete"))
812 raise util.Abort(_("--rev is incompatible with --delete"))
813 if rename and rev:
813 if rename and rev:
814 raise util.Abort(_("--rev is incompatible with --rename"))
814 raise util.Abort(_("--rev is incompatible with --rename"))
815 if mark is None and (delete or rev):
815 if mark is None and (delete or rev):
816 raise util.Abort(_("bookmark name required"))
816 raise util.Abort(_("bookmark name required"))
817
817
818 if delete:
818 if delete:
819 if mark not in marks:
819 if mark not in marks:
820 raise util.Abort(_("bookmark '%s' does not exist") % mark)
820 raise util.Abort(_("bookmark '%s' does not exist") % mark)
821 if mark == repo._bookmarkcurrent:
821 if mark == repo._bookmarkcurrent:
822 bookmarks.setcurrent(repo, None)
822 bookmarks.setcurrent(repo, None)
823 del marks[mark]
823 del marks[mark]
824 bookmarks.write(repo)
824 bookmarks.write(repo)
825
825
826 elif rename:
826 elif rename:
827 if mark is None:
827 if mark is None:
828 raise util.Abort(_("new bookmark name required"))
828 raise util.Abort(_("new bookmark name required"))
829 mark = checkformat(mark)
829 mark = checkformat(mark)
830 if rename not in marks:
830 if rename not in marks:
831 raise util.Abort(_("bookmark '%s' does not exist") % rename)
831 raise util.Abort(_("bookmark '%s' does not exist") % rename)
832 checkconflict(repo, mark, force)
832 checkconflict(repo, mark, force)
833 marks[mark] = marks[rename]
833 marks[mark] = marks[rename]
834 if repo._bookmarkcurrent == rename and not inactive:
834 if repo._bookmarkcurrent == rename and not inactive:
835 bookmarks.setcurrent(repo, mark)
835 bookmarks.setcurrent(repo, mark)
836 del marks[rename]
836 del marks[rename]
837 bookmarks.write(repo)
837 bookmarks.write(repo)
838
838
839 elif mark is not None:
839 elif mark is not None:
840 mark = checkformat(mark)
840 mark = checkformat(mark)
841 if inactive and mark == repo._bookmarkcurrent:
841 if inactive and mark == repo._bookmarkcurrent:
842 bookmarks.setcurrent(repo, None)
842 bookmarks.setcurrent(repo, None)
843 return
843 return
844 checkconflict(repo, mark, force)
844 checkconflict(repo, mark, force)
845 if rev:
845 if rev:
846 marks[mark] = scmutil.revsingle(repo, rev).node()
846 marks[mark] = scmutil.revsingle(repo, rev).node()
847 else:
847 else:
848 marks[mark] = cur
848 marks[mark] = cur
849 if not inactive and cur == marks[mark]:
849 if not inactive and cur == marks[mark]:
850 bookmarks.setcurrent(repo, mark)
850 bookmarks.setcurrent(repo, mark)
851 bookmarks.write(repo)
851 bookmarks.write(repo)
852
852
853 # Same message whether trying to deactivate the current bookmark (-i
853 # Same message whether trying to deactivate the current bookmark (-i
854 # with no NAME) or listing bookmarks
854 # with no NAME) or listing bookmarks
855 elif len(marks) == 0:
855 elif len(marks) == 0:
856 ui.status(_("no bookmarks set\n"))
856 ui.status(_("no bookmarks set\n"))
857
857
858 elif inactive:
858 elif inactive:
859 if not repo._bookmarkcurrent:
859 if not repo._bookmarkcurrent:
860 ui.status(_("no active bookmark\n"))
860 ui.status(_("no active bookmark\n"))
861 else:
861 else:
862 bookmarks.setcurrent(repo, None)
862 bookmarks.setcurrent(repo, None)
863
863
864 else: # show bookmarks
864 else: # show bookmarks
865 for bmark, n in sorted(marks.iteritems()):
865 for bmark, n in sorted(marks.iteritems()):
866 current = repo._bookmarkcurrent
866 current = repo._bookmarkcurrent
867 if bmark == current and n == cur:
867 if bmark == current and n == cur:
868 prefix, label = '*', 'bookmarks.current'
868 prefix, label = '*', 'bookmarks.current'
869 else:
869 else:
870 prefix, label = ' ', ''
870 prefix, label = ' ', ''
871
871
872 if ui.quiet:
872 if ui.quiet:
873 ui.write("%s\n" % bmark, label=label)
873 ui.write("%s\n" % bmark, label=label)
874 else:
874 else:
875 ui.write(" %s %-25s %d:%s\n" % (
875 ui.write(" %s %-25s %d:%s\n" % (
876 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
876 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
877 label=label)
877 label=label)
878
878
879 @command('branch',
879 @command('branch',
880 [('f', 'force', None,
880 [('f', 'force', None,
881 _('set branch name even if it shadows an existing branch')),
881 _('set branch name even if it shadows an existing branch')),
882 ('C', 'clean', None, _('reset branch name to parent branch name'))],
882 ('C', 'clean', None, _('reset branch name to parent branch name'))],
883 _('[-fC] [NAME]'))
883 _('[-fC] [NAME]'))
884 def branch(ui, repo, label=None, **opts):
884 def branch(ui, repo, label=None, **opts):
885 """set or show the current branch name
885 """set or show the current branch name
886
886
887 .. note::
887 .. note::
888 Branch names are permanent and global. Use :hg:`bookmark` to create a
888 Branch names are permanent and global. Use :hg:`bookmark` to create a
889 light-weight bookmark instead. See :hg:`help glossary` for more
889 light-weight bookmark instead. See :hg:`help glossary` for more
890 information about named branches and bookmarks.
890 information about named branches and bookmarks.
891
891
892 With no argument, show the current branch name. With one argument,
892 With no argument, show the current branch name. With one argument,
893 set the working directory branch name (the branch will not exist
893 set the working directory branch name (the branch will not exist
894 in the repository until the next commit). Standard practice
894 in the repository until the next commit). Standard practice
895 recommends that primary development take place on the 'default'
895 recommends that primary development take place on the 'default'
896 branch.
896 branch.
897
897
898 Unless -f/--force is specified, branch will not let you set a
898 Unless -f/--force is specified, branch will not let you set a
899 branch name that already exists, even if it's inactive.
899 branch name that already exists, even if it's inactive.
900
900
901 Use -C/--clean to reset the working directory branch to that of
901 Use -C/--clean to reset the working directory branch to that of
902 the parent of the working directory, negating a previous branch
902 the parent of the working directory, negating a previous branch
903 change.
903 change.
904
904
905 Use the command :hg:`update` to switch to an existing branch. Use
905 Use the command :hg:`update` to switch to an existing branch. Use
906 :hg:`commit --close-branch` to mark this branch as closed.
906 :hg:`commit --close-branch` to mark this branch as closed.
907
907
908 Returns 0 on success.
908 Returns 0 on success.
909 """
909 """
910 if not opts.get('clean') and not label:
910 if not opts.get('clean') and not label:
911 ui.write("%s\n" % repo.dirstate.branch())
911 ui.write("%s\n" % repo.dirstate.branch())
912 return
912 return
913
913
914 wlock = repo.wlock()
914 wlock = repo.wlock()
915 try:
915 try:
916 if opts.get('clean'):
916 if opts.get('clean'):
917 label = repo[None].p1().branch()
917 label = repo[None].p1().branch()
918 repo.dirstate.setbranch(label)
918 repo.dirstate.setbranch(label)
919 ui.status(_('reset working directory to branch %s\n') % label)
919 ui.status(_('reset working directory to branch %s\n') % label)
920 elif label:
920 elif label:
921 if not opts.get('force') and label in repo.branchmap():
921 if not opts.get('force') and label in repo.branchmap():
922 if label not in [p.branch() for p in repo.parents()]:
922 if label not in [p.branch() for p in repo.parents()]:
923 raise util.Abort(_('a branch of the same name already'
923 raise util.Abort(_('a branch of the same name already'
924 ' exists'),
924 ' exists'),
925 # i18n: "it" refers to an existing branch
925 # i18n: "it" refers to an existing branch
926 hint=_("use 'hg update' to switch to it"))
926 hint=_("use 'hg update' to switch to it"))
927 repo.dirstate.setbranch(label)
927 repo.dirstate.setbranch(label)
928 ui.status(_('marked working directory as branch %s\n') % label)
928 ui.status(_('marked working directory as branch %s\n') % label)
929 ui.status(_('(branches are permanent and global, '
929 ui.status(_('(branches are permanent and global, '
930 'did you want a bookmark?)\n'))
930 'did you want a bookmark?)\n'))
931 finally:
931 finally:
932 wlock.release()
932 wlock.release()
933
933
934 @command('branches',
934 @command('branches',
935 [('a', 'active', False, _('show only branches that have unmerged heads')),
935 [('a', 'active', False, _('show only branches that have unmerged heads')),
936 ('c', 'closed', False, _('show normal and closed branches'))],
936 ('c', 'closed', False, _('show normal and closed branches'))],
937 _('[-ac]'))
937 _('[-ac]'))
938 def branches(ui, repo, active=False, closed=False):
938 def branches(ui, repo, active=False, closed=False):
939 """list repository named branches
939 """list repository named branches
940
940
941 List the repository's named branches, indicating which ones are
941 List the repository's named branches, indicating which ones are
942 inactive. If -c/--closed is specified, also list branches which have
942 inactive. If -c/--closed is specified, also list branches which have
943 been marked closed (see :hg:`commit --close-branch`).
943 been marked closed (see :hg:`commit --close-branch`).
944
944
945 If -a/--active is specified, only show active branches. A branch
945 If -a/--active is specified, only show active branches. A branch
946 is considered active if it contains repository heads.
946 is considered active if it contains repository heads.
947
947
948 Use the command :hg:`update` to switch to an existing branch.
948 Use the command :hg:`update` to switch to an existing branch.
949
949
950 Returns 0.
950 Returns 0.
951 """
951 """
952
952
953 hexfunc = ui.debugflag and hex or short
953 hexfunc = ui.debugflag and hex or short
954
954
955 activebranches = set([repo[n].branch() for n in repo.heads()])
955 activebranches = set([repo[n].branch() for n in repo.heads()])
956 branches = []
956 branches = []
957 for tag, heads in repo.branchmap().iteritems():
957 for tag, heads in repo.branchmap().iteritems():
958 for h in reversed(heads):
958 for h in reversed(heads):
959 ctx = repo[h]
959 ctx = repo[h]
960 isopen = not ctx.closesbranch()
960 isopen = not ctx.closesbranch()
961 if isopen:
961 if isopen:
962 tip = ctx
962 tip = ctx
963 break
963 break
964 else:
964 else:
965 tip = repo[heads[-1]]
965 tip = repo[heads[-1]]
966 isactive = tag in activebranches and isopen
966 isactive = tag in activebranches and isopen
967 branches.append((tip, isactive, isopen))
967 branches.append((tip, isactive, isopen))
968 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
968 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
969 reverse=True)
969 reverse=True)
970
970
971 for ctx, isactive, isopen in branches:
971 for ctx, isactive, isopen in branches:
972 if (not active) or isactive:
972 if (not active) or isactive:
973 if isactive:
973 if isactive:
974 label = 'branches.active'
974 label = 'branches.active'
975 notice = ''
975 notice = ''
976 elif not isopen:
976 elif not isopen:
977 if not closed:
977 if not closed:
978 continue
978 continue
979 label = 'branches.closed'
979 label = 'branches.closed'
980 notice = _(' (closed)')
980 notice = _(' (closed)')
981 else:
981 else:
982 label = 'branches.inactive'
982 label = 'branches.inactive'
983 notice = _(' (inactive)')
983 notice = _(' (inactive)')
984 if ctx.branch() == repo.dirstate.branch():
984 if ctx.branch() == repo.dirstate.branch():
985 label = 'branches.current'
985 label = 'branches.current'
986 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
986 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
987 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
987 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
988 'log.changeset changeset.%s' % ctx.phasestr())
988 'log.changeset changeset.%s' % ctx.phasestr())
989 tag = ui.label(ctx.branch(), label)
989 tag = ui.label(ctx.branch(), label)
990 if ui.quiet:
990 if ui.quiet:
991 ui.write("%s\n" % tag)
991 ui.write("%s\n" % tag)
992 else:
992 else:
993 ui.write("%s %s%s\n" % (tag, rev, notice))
993 ui.write("%s %s%s\n" % (tag, rev, notice))
994
994
995 @command('bundle',
995 @command('bundle',
996 [('f', 'force', None, _('run even when the destination is unrelated')),
996 [('f', 'force', None, _('run even when the destination is unrelated')),
997 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
997 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
998 _('REV')),
998 _('REV')),
999 ('b', 'branch', [], _('a specific branch you would like to bundle'),
999 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1000 _('BRANCH')),
1000 _('BRANCH')),
1001 ('', 'base', [],
1001 ('', 'base', [],
1002 _('a base changeset assumed to be available at the destination'),
1002 _('a base changeset assumed to be available at the destination'),
1003 _('REV')),
1003 _('REV')),
1004 ('a', 'all', None, _('bundle all changesets in the repository')),
1004 ('a', 'all', None, _('bundle all changesets in the repository')),
1005 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1005 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1006 ] + remoteopts,
1006 ] + remoteopts,
1007 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1007 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1008 def bundle(ui, repo, fname, dest=None, **opts):
1008 def bundle(ui, repo, fname, dest=None, **opts):
1009 """create a changegroup file
1009 """create a changegroup file
1010
1010
1011 Generate a compressed changegroup file collecting changesets not
1011 Generate a compressed changegroup file collecting changesets not
1012 known to be in another repository.
1012 known to be in another repository.
1013
1013
1014 If you omit the destination repository, then hg assumes the
1014 If you omit the destination repository, then hg assumes the
1015 destination will have all the nodes you specify with --base
1015 destination will have all the nodes you specify with --base
1016 parameters. To create a bundle containing all changesets, use
1016 parameters. To create a bundle containing all changesets, use
1017 -a/--all (or --base null).
1017 -a/--all (or --base null).
1018
1018
1019 You can change compression method with the -t/--type option.
1019 You can change compression method with the -t/--type option.
1020 The available compression methods are: none, bzip2, and
1020 The available compression methods are: none, bzip2, and
1021 gzip (by default, bundles are compressed using bzip2).
1021 gzip (by default, bundles are compressed using bzip2).
1022
1022
1023 The bundle file can then be transferred using conventional means
1023 The bundle file can then be transferred using conventional means
1024 and applied to another repository with the unbundle or pull
1024 and applied to another repository with the unbundle or pull
1025 command. This is useful when direct push and pull are not
1025 command. This is useful when direct push and pull are not
1026 available or when exporting an entire repository is undesirable.
1026 available or when exporting an entire repository is undesirable.
1027
1027
1028 Applying bundles preserves all changeset contents including
1028 Applying bundles preserves all changeset contents including
1029 permissions, copy/rename information, and revision history.
1029 permissions, copy/rename information, and revision history.
1030
1030
1031 Returns 0 on success, 1 if no changes found.
1031 Returns 0 on success, 1 if no changes found.
1032 """
1032 """
1033 revs = None
1033 revs = None
1034 if 'rev' in opts:
1034 if 'rev' in opts:
1035 revs = scmutil.revrange(repo, opts['rev'])
1035 revs = scmutil.revrange(repo, opts['rev'])
1036
1036
1037 bundletype = opts.get('type', 'bzip2').lower()
1037 bundletype = opts.get('type', 'bzip2').lower()
1038 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1038 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1039 bundletype = btypes.get(bundletype)
1039 bundletype = btypes.get(bundletype)
1040 if bundletype not in changegroup.bundletypes:
1040 if bundletype not in changegroup.bundletypes:
1041 raise util.Abort(_('unknown bundle type specified with --type'))
1041 raise util.Abort(_('unknown bundle type specified with --type'))
1042
1042
1043 if opts.get('all'):
1043 if opts.get('all'):
1044 base = ['null']
1044 base = ['null']
1045 else:
1045 else:
1046 base = scmutil.revrange(repo, opts.get('base'))
1046 base = scmutil.revrange(repo, opts.get('base'))
1047 if base:
1047 if base:
1048 if dest:
1048 if dest:
1049 raise util.Abort(_("--base is incompatible with specifying "
1049 raise util.Abort(_("--base is incompatible with specifying "
1050 "a destination"))
1050 "a destination"))
1051 common = [repo.lookup(rev) for rev in base]
1051 common = [repo.lookup(rev) for rev in base]
1052 heads = revs and map(repo.lookup, revs) or revs
1052 heads = revs and map(repo.lookup, revs) or revs
1053 cg = repo.getbundle('bundle', heads=heads, common=common)
1053 cg = repo.getbundle('bundle', heads=heads, common=common)
1054 outgoing = None
1054 outgoing = None
1055 else:
1055 else:
1056 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1056 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1057 dest, branches = hg.parseurl(dest, opts.get('branch'))
1057 dest, branches = hg.parseurl(dest, opts.get('branch'))
1058 other = hg.peer(repo, opts, dest)
1058 other = hg.peer(repo, opts, dest)
1059 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1059 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1060 heads = revs and map(repo.lookup, revs) or revs
1060 heads = revs and map(repo.lookup, revs) or revs
1061 outgoing = discovery.findcommonoutgoing(repo, other,
1061 outgoing = discovery.findcommonoutgoing(repo, other,
1062 onlyheads=heads,
1062 onlyheads=heads,
1063 force=opts.get('force'),
1063 force=opts.get('force'),
1064 portable=True)
1064 portable=True)
1065 cg = repo.getlocalbundle('bundle', outgoing)
1065 cg = repo.getlocalbundle('bundle', outgoing)
1066 if not cg:
1066 if not cg:
1067 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1067 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1068 return 1
1068 return 1
1069
1069
1070 changegroup.writebundle(cg, fname, bundletype)
1070 changegroup.writebundle(cg, fname, bundletype)
1071
1071
1072 @command('cat',
1072 @command('cat',
1073 [('o', 'output', '',
1073 [('o', 'output', '',
1074 _('print output to file with formatted name'), _('FORMAT')),
1074 _('print output to file with formatted name'), _('FORMAT')),
1075 ('r', 'rev', '', _('print the given revision'), _('REV')),
1075 ('r', 'rev', '', _('print the given revision'), _('REV')),
1076 ('', 'decode', None, _('apply any matching decode filter')),
1076 ('', 'decode', None, _('apply any matching decode filter')),
1077 ] + walkopts,
1077 ] + walkopts,
1078 _('[OPTION]... FILE...'))
1078 _('[OPTION]... FILE...'))
1079 def cat(ui, repo, file1, *pats, **opts):
1079 def cat(ui, repo, file1, *pats, **opts):
1080 """output the current or given revision of files
1080 """output the current or given revision of files
1081
1081
1082 Print the specified files as they were at the given revision. If
1082 Print the specified files as they were at the given revision. If
1083 no revision is given, the parent of the working directory is used,
1083 no revision is given, the parent of the working directory is used,
1084 or tip if no revision is checked out.
1084 or tip if no revision is checked out.
1085
1085
1086 Output may be to a file, in which case the name of the file is
1086 Output may be to a file, in which case the name of the file is
1087 given using a format string. The formatting rules are the same as
1087 given using a format string. The formatting rules are the same as
1088 for the export command, with the following additions:
1088 for the export command, with the following additions:
1089
1089
1090 :``%s``: basename of file being printed
1090 :``%s``: basename of file being printed
1091 :``%d``: dirname of file being printed, or '.' if in repository root
1091 :``%d``: dirname of file being printed, or '.' if in repository root
1092 :``%p``: root-relative path name of file being printed
1092 :``%p``: root-relative path name of file being printed
1093
1093
1094 Returns 0 on success.
1094 Returns 0 on success.
1095 """
1095 """
1096 ctx = scmutil.revsingle(repo, opts.get('rev'))
1096 ctx = scmutil.revsingle(repo, opts.get('rev'))
1097 err = 1
1097 err = 1
1098 m = scmutil.match(ctx, (file1,) + pats, opts)
1098 m = scmutil.match(ctx, (file1,) + pats, opts)
1099 for abs in ctx.walk(m):
1099 for abs in ctx.walk(m):
1100 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1100 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1101 pathname=abs)
1101 pathname=abs)
1102 data = ctx[abs].data()
1102 data = ctx[abs].data()
1103 if opts.get('decode'):
1103 if opts.get('decode'):
1104 data = repo.wwritedata(abs, data)
1104 data = repo.wwritedata(abs, data)
1105 fp.write(data)
1105 fp.write(data)
1106 fp.close()
1106 fp.close()
1107 err = 0
1107 err = 0
1108 return err
1108 return err
1109
1109
1110 @command('^clone',
1110 @command('^clone',
1111 [('U', 'noupdate', None,
1111 [('U', 'noupdate', None,
1112 _('the clone will include an empty working copy (only a repository)')),
1112 _('the clone will include an empty working copy (only a repository)')),
1113 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1113 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1114 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1114 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1115 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1115 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1116 ('', 'pull', None, _('use pull protocol to copy metadata')),
1116 ('', 'pull', None, _('use pull protocol to copy metadata')),
1117 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1117 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1118 ] + remoteopts,
1118 ] + remoteopts,
1119 _('[OPTION]... SOURCE [DEST]'))
1119 _('[OPTION]... SOURCE [DEST]'))
1120 def clone(ui, source, dest=None, **opts):
1120 def clone(ui, source, dest=None, **opts):
1121 """make a copy of an existing repository
1121 """make a copy of an existing repository
1122
1122
1123 Create a copy of an existing repository in a new directory.
1123 Create a copy of an existing repository in a new directory.
1124
1124
1125 If no destination directory name is specified, it defaults to the
1125 If no destination directory name is specified, it defaults to the
1126 basename of the source.
1126 basename of the source.
1127
1127
1128 The location of the source is added to the new repository's
1128 The location of the source is added to the new repository's
1129 ``.hg/hgrc`` file, as the default to be used for future pulls.
1129 ``.hg/hgrc`` file, as the default to be used for future pulls.
1130
1130
1131 Only local paths and ``ssh://`` URLs are supported as
1131 Only local paths and ``ssh://`` URLs are supported as
1132 destinations. For ``ssh://`` destinations, no working directory or
1132 destinations. For ``ssh://`` destinations, no working directory or
1133 ``.hg/hgrc`` will be created on the remote side.
1133 ``.hg/hgrc`` will be created on the remote side.
1134
1134
1135 To pull only a subset of changesets, specify one or more revisions
1135 To pull only a subset of changesets, specify one or more revisions
1136 identifiers with -r/--rev or branches with -b/--branch. The
1136 identifiers with -r/--rev or branches with -b/--branch. The
1137 resulting clone will contain only the specified changesets and
1137 resulting clone will contain only the specified changesets and
1138 their ancestors. These options (or 'clone src#rev dest') imply
1138 their ancestors. These options (or 'clone src#rev dest') imply
1139 --pull, even for local source repositories. Note that specifying a
1139 --pull, even for local source repositories. Note that specifying a
1140 tag will include the tagged changeset but not the changeset
1140 tag will include the tagged changeset but not the changeset
1141 containing the tag.
1141 containing the tag.
1142
1142
1143 To check out a particular version, use -u/--update, or
1143 To check out a particular version, use -u/--update, or
1144 -U/--noupdate to create a clone with no working directory.
1144 -U/--noupdate to create a clone with no working directory.
1145
1145
1146 .. container:: verbose
1146 .. container:: verbose
1147
1147
1148 For efficiency, hardlinks are used for cloning whenever the
1148 For efficiency, hardlinks are used for cloning whenever the
1149 source and destination are on the same filesystem (note this
1149 source and destination are on the same filesystem (note this
1150 applies only to the repository data, not to the working
1150 applies only to the repository data, not to the working
1151 directory). Some filesystems, such as AFS, implement hardlinking
1151 directory). Some filesystems, such as AFS, implement hardlinking
1152 incorrectly, but do not report errors. In these cases, use the
1152 incorrectly, but do not report errors. In these cases, use the
1153 --pull option to avoid hardlinking.
1153 --pull option to avoid hardlinking.
1154
1154
1155 In some cases, you can clone repositories and the working
1155 In some cases, you can clone repositories and the working
1156 directory using full hardlinks with ::
1156 directory using full hardlinks with ::
1157
1157
1158 $ cp -al REPO REPOCLONE
1158 $ cp -al REPO REPOCLONE
1159
1159
1160 This is the fastest way to clone, but it is not always safe. The
1160 This is the fastest way to clone, but it is not always safe. The
1161 operation is not atomic (making sure REPO is not modified during
1161 operation is not atomic (making sure REPO is not modified during
1162 the operation is up to you) and you have to make sure your
1162 the operation is up to you) and you have to make sure your
1163 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1163 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1164 so). Also, this is not compatible with certain extensions that
1164 so). Also, this is not compatible with certain extensions that
1165 place their metadata under the .hg directory, such as mq.
1165 place their metadata under the .hg directory, such as mq.
1166
1166
1167 Mercurial will update the working directory to the first applicable
1167 Mercurial will update the working directory to the first applicable
1168 revision from this list:
1168 revision from this list:
1169
1169
1170 a) null if -U or the source repository has no changesets
1170 a) null if -U or the source repository has no changesets
1171 b) if -u . and the source repository is local, the first parent of
1171 b) if -u . and the source repository is local, the first parent of
1172 the source repository's working directory
1172 the source repository's working directory
1173 c) the changeset specified with -u (if a branch name, this means the
1173 c) the changeset specified with -u (if a branch name, this means the
1174 latest head of that branch)
1174 latest head of that branch)
1175 d) the changeset specified with -r
1175 d) the changeset specified with -r
1176 e) the tipmost head specified with -b
1176 e) the tipmost head specified with -b
1177 f) the tipmost head specified with the url#branch source syntax
1177 f) the tipmost head specified with the url#branch source syntax
1178 g) the tipmost head of the default branch
1178 g) the tipmost head of the default branch
1179 h) tip
1179 h) tip
1180
1180
1181 Examples:
1181 Examples:
1182
1182
1183 - clone a remote repository to a new directory named hg/::
1183 - clone a remote repository to a new directory named hg/::
1184
1184
1185 hg clone http://selenic.com/hg
1185 hg clone http://selenic.com/hg
1186
1186
1187 - create a lightweight local clone::
1187 - create a lightweight local clone::
1188
1188
1189 hg clone project/ project-feature/
1189 hg clone project/ project-feature/
1190
1190
1191 - clone from an absolute path on an ssh server (note double-slash)::
1191 - clone from an absolute path on an ssh server (note double-slash)::
1192
1192
1193 hg clone ssh://user@server//home/projects/alpha/
1193 hg clone ssh://user@server//home/projects/alpha/
1194
1194
1195 - do a high-speed clone over a LAN while checking out a
1195 - do a high-speed clone over a LAN while checking out a
1196 specified version::
1196 specified version::
1197
1197
1198 hg clone --uncompressed http://server/repo -u 1.5
1198 hg clone --uncompressed http://server/repo -u 1.5
1199
1199
1200 - create a repository without changesets after a particular revision::
1200 - create a repository without changesets after a particular revision::
1201
1201
1202 hg clone -r 04e544 experimental/ good/
1202 hg clone -r 04e544 experimental/ good/
1203
1203
1204 - clone (and track) a particular named branch::
1204 - clone (and track) a particular named branch::
1205
1205
1206 hg clone http://selenic.com/hg#stable
1206 hg clone http://selenic.com/hg#stable
1207
1207
1208 See :hg:`help urls` for details on specifying URLs.
1208 See :hg:`help urls` for details on specifying URLs.
1209
1209
1210 Returns 0 on success.
1210 Returns 0 on success.
1211 """
1211 """
1212 if opts.get('noupdate') and opts.get('updaterev'):
1212 if opts.get('noupdate') and opts.get('updaterev'):
1213 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1213 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1214
1214
1215 r = hg.clone(ui, opts, source, dest,
1215 r = hg.clone(ui, opts, source, dest,
1216 pull=opts.get('pull'),
1216 pull=opts.get('pull'),
1217 stream=opts.get('uncompressed'),
1217 stream=opts.get('uncompressed'),
1218 rev=opts.get('rev'),
1218 rev=opts.get('rev'),
1219 update=opts.get('updaterev') or not opts.get('noupdate'),
1219 update=opts.get('updaterev') or not opts.get('noupdate'),
1220 branch=opts.get('branch'))
1220 branch=opts.get('branch'))
1221
1221
1222 return r is None
1222 return r is None
1223
1223
1224 @command('^commit|ci',
1224 @command('^commit|ci',
1225 [('A', 'addremove', None,
1225 [('A', 'addremove', None,
1226 _('mark new/missing files as added/removed before committing')),
1226 _('mark new/missing files as added/removed before committing')),
1227 ('', 'close-branch', None,
1227 ('', 'close-branch', None,
1228 _('mark a branch as closed, hiding it from the branch list')),
1228 _('mark a branch as closed, hiding it from the branch list')),
1229 ('', 'amend', None, _('amend the parent of the working dir')),
1229 ('', 'amend', None, _('amend the parent of the working dir')),
1230 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1230 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1231 _('[OPTION]... [FILE]...'))
1231 _('[OPTION]... [FILE]...'))
1232 def commit(ui, repo, *pats, **opts):
1232 def commit(ui, repo, *pats, **opts):
1233 """commit the specified files or all outstanding changes
1233 """commit the specified files or all outstanding changes
1234
1234
1235 Commit changes to the given files into the repository. Unlike a
1235 Commit changes to the given files into the repository. Unlike a
1236 centralized SCM, this operation is a local operation. See
1236 centralized SCM, this operation is a local operation. See
1237 :hg:`push` for a way to actively distribute your changes.
1237 :hg:`push` for a way to actively distribute your changes.
1238
1238
1239 If a list of files is omitted, all changes reported by :hg:`status`
1239 If a list of files is omitted, all changes reported by :hg:`status`
1240 will be committed.
1240 will be committed.
1241
1241
1242 If you are committing the result of a merge, do not provide any
1242 If you are committing the result of a merge, do not provide any
1243 filenames or -I/-X filters.
1243 filenames or -I/-X filters.
1244
1244
1245 If no commit message is specified, Mercurial starts your
1245 If no commit message is specified, Mercurial starts your
1246 configured editor where you can enter a message. In case your
1246 configured editor where you can enter a message. In case your
1247 commit fails, you will find a backup of your message in
1247 commit fails, you will find a backup of your message in
1248 ``.hg/last-message.txt``.
1248 ``.hg/last-message.txt``.
1249
1249
1250 The --amend flag can be used to amend the parent of the
1250 The --amend flag can be used to amend the parent of the
1251 working directory with a new commit that contains the changes
1251 working directory with a new commit that contains the changes
1252 in the parent in addition to those currently reported by :hg:`status`,
1252 in the parent in addition to those currently reported by :hg:`status`,
1253 if there are any. The old commit is stored in a backup bundle in
1253 if there are any. The old commit is stored in a backup bundle in
1254 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1254 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1255 on how to restore it).
1255 on how to restore it).
1256
1256
1257 Message, user and date are taken from the amended commit unless
1257 Message, user and date are taken from the amended commit unless
1258 specified. When a message isn't specified on the command line,
1258 specified. When a message isn't specified on the command line,
1259 the editor will open with the message of the amended commit.
1259 the editor will open with the message of the amended commit.
1260
1260
1261 It is not possible to amend public changesets (see :hg:`help phases`)
1261 It is not possible to amend public changesets (see :hg:`help phases`)
1262 or changesets that have children.
1262 or changesets that have children.
1263
1263
1264 See :hg:`help dates` for a list of formats valid for -d/--date.
1264 See :hg:`help dates` for a list of formats valid for -d/--date.
1265
1265
1266 Returns 0 on success, 1 if nothing changed.
1266 Returns 0 on success, 1 if nothing changed.
1267 """
1267 """
1268 if opts.get('subrepos'):
1268 if opts.get('subrepos'):
1269 # Let --subrepos on the command line override config setting.
1269 # Let --subrepos on the command line override config setting.
1270 ui.setconfig('ui', 'commitsubrepos', True)
1270 ui.setconfig('ui', 'commitsubrepos', True)
1271
1271
1272 extra = {}
1272 extra = {}
1273 if opts.get('close_branch'):
1273 if opts.get('close_branch'):
1274 if repo['.'].node() not in repo.branchheads():
1274 if repo['.'].node() not in repo.branchheads():
1275 # The topo heads set is included in the branch heads set of the
1275 # The topo heads set is included in the branch heads set of the
1276 # current branch, so it's sufficient to test branchheads
1276 # current branch, so it's sufficient to test branchheads
1277 raise util.Abort(_('can only close branch heads'))
1277 raise util.Abort(_('can only close branch heads'))
1278 extra['close'] = 1
1278 extra['close'] = 1
1279
1279
1280 branch = repo[None].branch()
1280 branch = repo[None].branch()
1281 bheads = repo.branchheads(branch)
1281 bheads = repo.branchheads(branch)
1282
1282
1283 if opts.get('amend'):
1283 if opts.get('amend'):
1284 if ui.configbool('ui', 'commitsubrepos'):
1284 if ui.configbool('ui', 'commitsubrepos'):
1285 raise util.Abort(_('cannot amend recursively'))
1285 raise util.Abort(_('cannot amend recursively'))
1286
1286
1287 old = repo['.']
1287 old = repo['.']
1288 if old.phase() == phases.public:
1288 if old.phase() == phases.public:
1289 raise util.Abort(_('cannot amend public changesets'))
1289 raise util.Abort(_('cannot amend public changesets'))
1290 if len(old.parents()) > 1:
1290 if len(old.parents()) > 1:
1291 raise util.Abort(_('cannot amend merge changesets'))
1291 raise util.Abort(_('cannot amend merge changesets'))
1292 if len(repo[None].parents()) > 1:
1292 if len(repo[None].parents()) > 1:
1293 raise util.Abort(_('cannot amend while merging'))
1293 raise util.Abort(_('cannot amend while merging'))
1294 if old.children():
1294 if old.children():
1295 raise util.Abort(_('cannot amend changeset with children'))
1295 raise util.Abort(_('cannot amend changeset with children'))
1296
1296
1297 e = cmdutil.commiteditor
1297 e = cmdutil.commiteditor
1298 if opts.get('force_editor'):
1298 if opts.get('force_editor'):
1299 e = cmdutil.commitforceeditor
1299 e = cmdutil.commitforceeditor
1300
1300
1301 def commitfunc(ui, repo, message, match, opts):
1301 def commitfunc(ui, repo, message, match, opts):
1302 editor = e
1302 editor = e
1303 # message contains text from -m or -l, if it's empty,
1303 # message contains text from -m or -l, if it's empty,
1304 # open the editor with the old message
1304 # open the editor with the old message
1305 if not message:
1305 if not message:
1306 message = old.description()
1306 message = old.description()
1307 editor = cmdutil.commitforceeditor
1307 editor = cmdutil.commitforceeditor
1308 return repo.commit(message,
1308 return repo.commit(message,
1309 opts.get('user') or old.user(),
1309 opts.get('user') or old.user(),
1310 opts.get('date') or old.date(),
1310 opts.get('date') or old.date(),
1311 match,
1311 match,
1312 editor=editor,
1312 editor=editor,
1313 extra=extra)
1313 extra=extra)
1314
1314
1315 current = repo._bookmarkcurrent
1315 current = repo._bookmarkcurrent
1316 marks = old.bookmarks()
1316 marks = old.bookmarks()
1317 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1317 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1318 if node == old.node():
1318 if node == old.node():
1319 ui.status(_("nothing changed\n"))
1319 ui.status(_("nothing changed\n"))
1320 return 1
1320 return 1
1321 elif marks:
1321 elif marks:
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1322 ui.debug('moving bookmarks %r from %s to %s\n' %
1323 (marks, old.hex(), hex(node)))
1323 (marks, old.hex(), hex(node)))
1324 for bm in marks:
1324 for bm in marks:
1325 repo._bookmarks[bm] = node
1325 repo._bookmarks[bm] = node
1326 if bm == current:
1326 if bm == current:
1327 bookmarks.setcurrent(repo, bm)
1327 bookmarks.setcurrent(repo, bm)
1328 bookmarks.write(repo)
1328 bookmarks.write(repo)
1329 else:
1329 else:
1330 e = cmdutil.commiteditor
1330 e = cmdutil.commiteditor
1331 if opts.get('force_editor'):
1331 if opts.get('force_editor'):
1332 e = cmdutil.commitforceeditor
1332 e = cmdutil.commitforceeditor
1333
1333
1334 def commitfunc(ui, repo, message, match, opts):
1334 def commitfunc(ui, repo, message, match, opts):
1335 return repo.commit(message, opts.get('user'), opts.get('date'),
1335 return repo.commit(message, opts.get('user'), opts.get('date'),
1336 match, editor=e, extra=extra)
1336 match, editor=e, extra=extra)
1337
1337
1338 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1338 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1339
1339
1340 if not node:
1340 if not node:
1341 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1341 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1342 if stat[3]:
1342 if stat[3]:
1343 ui.status(_("nothing changed (%d missing files, see "
1343 ui.status(_("nothing changed (%d missing files, see "
1344 "'hg status')\n") % len(stat[3]))
1344 "'hg status')\n") % len(stat[3]))
1345 else:
1345 else:
1346 ui.status(_("nothing changed\n"))
1346 ui.status(_("nothing changed\n"))
1347 return 1
1347 return 1
1348
1348
1349 ctx = repo[node]
1349 ctx = repo[node]
1350 parents = ctx.parents()
1350 parents = ctx.parents()
1351
1351
1352 if (not opts.get('amend') and bheads and node not in bheads and not
1352 if (not opts.get('amend') and bheads and node not in bheads and not
1353 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1353 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1354 ui.status(_('created new head\n'))
1354 ui.status(_('created new head\n'))
1355 # The message is not printed for initial roots. For the other
1355 # The message is not printed for initial roots. For the other
1356 # changesets, it is printed in the following situations:
1356 # changesets, it is printed in the following situations:
1357 #
1357 #
1358 # Par column: for the 2 parents with ...
1358 # Par column: for the 2 parents with ...
1359 # N: null or no parent
1359 # N: null or no parent
1360 # B: parent is on another named branch
1360 # B: parent is on another named branch
1361 # C: parent is a regular non head changeset
1361 # C: parent is a regular non head changeset
1362 # H: parent was a branch head of the current branch
1362 # H: parent was a branch head of the current branch
1363 # Msg column: whether we print "created new head" message
1363 # Msg column: whether we print "created new head" message
1364 # In the following, it is assumed that there already exists some
1364 # In the following, it is assumed that there already exists some
1365 # initial branch heads of the current branch, otherwise nothing is
1365 # initial branch heads of the current branch, otherwise nothing is
1366 # printed anyway.
1366 # printed anyway.
1367 #
1367 #
1368 # Par Msg Comment
1368 # Par Msg Comment
1369 # N N y additional topo root
1369 # N N y additional topo root
1370 #
1370 #
1371 # B N y additional branch root
1371 # B N y additional branch root
1372 # C N y additional topo head
1372 # C N y additional topo head
1373 # H N n usual case
1373 # H N n usual case
1374 #
1374 #
1375 # B B y weird additional branch root
1375 # B B y weird additional branch root
1376 # C B y branch merge
1376 # C B y branch merge
1377 # H B n merge with named branch
1377 # H B n merge with named branch
1378 #
1378 #
1379 # C C y additional head from merge
1379 # C C y additional head from merge
1380 # C H n merge with a head
1380 # C H n merge with a head
1381 #
1381 #
1382 # H H n head merge: head count decreases
1382 # H H n head merge: head count decreases
1383
1383
1384 if not opts.get('close_branch'):
1384 if not opts.get('close_branch'):
1385 for r in parents:
1385 for r in parents:
1386 if r.closesbranch() and r.branch() == branch:
1386 if r.closesbranch() and r.branch() == branch:
1387 ui.status(_('reopening closed branch head %d\n') % r)
1387 ui.status(_('reopening closed branch head %d\n') % r)
1388
1388
1389 if ui.debugflag:
1389 if ui.debugflag:
1390 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1390 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1391 elif ui.verbose:
1391 elif ui.verbose:
1392 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1392 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1393
1393
1394 @command('copy|cp',
1394 @command('copy|cp',
1395 [('A', 'after', None, _('record a copy that has already occurred')),
1395 [('A', 'after', None, _('record a copy that has already occurred')),
1396 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1396 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1397 ] + walkopts + dryrunopts,
1397 ] + walkopts + dryrunopts,
1398 _('[OPTION]... [SOURCE]... DEST'))
1398 _('[OPTION]... [SOURCE]... DEST'))
1399 def copy(ui, repo, *pats, **opts):
1399 def copy(ui, repo, *pats, **opts):
1400 """mark files as copied for the next commit
1400 """mark files as copied for the next commit
1401
1401
1402 Mark dest as having copies of source files. If dest is a
1402 Mark dest as having copies of source files. If dest is a
1403 directory, copies are put in that directory. If dest is a file,
1403 directory, copies are put in that directory. If dest is a file,
1404 the source must be a single file.
1404 the source must be a single file.
1405
1405
1406 By default, this command copies the contents of files as they
1406 By default, this command copies the contents of files as they
1407 exist in the working directory. If invoked with -A/--after, the
1407 exist in the working directory. If invoked with -A/--after, the
1408 operation is recorded, but no copying is performed.
1408 operation is recorded, but no copying is performed.
1409
1409
1410 This command takes effect with the next commit. To undo a copy
1410 This command takes effect with the next commit. To undo a copy
1411 before that, see :hg:`revert`.
1411 before that, see :hg:`revert`.
1412
1412
1413 Returns 0 on success, 1 if errors are encountered.
1413 Returns 0 on success, 1 if errors are encountered.
1414 """
1414 """
1415 wlock = repo.wlock(False)
1415 wlock = repo.wlock(False)
1416 try:
1416 try:
1417 return cmdutil.copy(ui, repo, pats, opts)
1417 return cmdutil.copy(ui, repo, pats, opts)
1418 finally:
1418 finally:
1419 wlock.release()
1419 wlock.release()
1420
1420
1421 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1421 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1422 def debugancestor(ui, repo, *args):
1422 def debugancestor(ui, repo, *args):
1423 """find the ancestor revision of two revisions in a given index"""
1423 """find the ancestor revision of two revisions in a given index"""
1424 if len(args) == 3:
1424 if len(args) == 3:
1425 index, rev1, rev2 = args
1425 index, rev1, rev2 = args
1426 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1426 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1427 lookup = r.lookup
1427 lookup = r.lookup
1428 elif len(args) == 2:
1428 elif len(args) == 2:
1429 if not repo:
1429 if not repo:
1430 raise util.Abort(_("there is no Mercurial repository here "
1430 raise util.Abort(_("there is no Mercurial repository here "
1431 "(.hg not found)"))
1431 "(.hg not found)"))
1432 rev1, rev2 = args
1432 rev1, rev2 = args
1433 r = repo.changelog
1433 r = repo.changelog
1434 lookup = repo.lookup
1434 lookup = repo.lookup
1435 else:
1435 else:
1436 raise util.Abort(_('either two or three arguments required'))
1436 raise util.Abort(_('either two or three arguments required'))
1437 a = r.ancestor(lookup(rev1), lookup(rev2))
1437 a = r.ancestor(lookup(rev1), lookup(rev2))
1438 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1438 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1439
1439
1440 @command('debugbuilddag',
1440 @command('debugbuilddag',
1441 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1441 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1442 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1442 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1443 ('n', 'new-file', None, _('add new file at each rev'))],
1443 ('n', 'new-file', None, _('add new file at each rev'))],
1444 _('[OPTION]... [TEXT]'))
1444 _('[OPTION]... [TEXT]'))
1445 def debugbuilddag(ui, repo, text=None,
1445 def debugbuilddag(ui, repo, text=None,
1446 mergeable_file=False,
1446 mergeable_file=False,
1447 overwritten_file=False,
1447 overwritten_file=False,
1448 new_file=False):
1448 new_file=False):
1449 """builds a repo with a given DAG from scratch in the current empty repo
1449 """builds a repo with a given DAG from scratch in the current empty repo
1450
1450
1451 The description of the DAG is read from stdin if not given on the
1451 The description of the DAG is read from stdin if not given on the
1452 command line.
1452 command line.
1453
1453
1454 Elements:
1454 Elements:
1455
1455
1456 - "+n" is a linear run of n nodes based on the current default parent
1456 - "+n" is a linear run of n nodes based on the current default parent
1457 - "." is a single node based on the current default parent
1457 - "." is a single node based on the current default parent
1458 - "$" resets the default parent to null (implied at the start);
1458 - "$" resets the default parent to null (implied at the start);
1459 otherwise the default parent is always the last node created
1459 otherwise the default parent is always the last node created
1460 - "<p" sets the default parent to the backref p
1460 - "<p" sets the default parent to the backref p
1461 - "*p" is a fork at parent p, which is a backref
1461 - "*p" is a fork at parent p, which is a backref
1462 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1462 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1463 - "/p2" is a merge of the preceding node and p2
1463 - "/p2" is a merge of the preceding node and p2
1464 - ":tag" defines a local tag for the preceding node
1464 - ":tag" defines a local tag for the preceding node
1465 - "@branch" sets the named branch for subsequent nodes
1465 - "@branch" sets the named branch for subsequent nodes
1466 - "#...\\n" is a comment up to the end of the line
1466 - "#...\\n" is a comment up to the end of the line
1467
1467
1468 Whitespace between the above elements is ignored.
1468 Whitespace between the above elements is ignored.
1469
1469
1470 A backref is either
1470 A backref is either
1471
1471
1472 - a number n, which references the node curr-n, where curr is the current
1472 - a number n, which references the node curr-n, where curr is the current
1473 node, or
1473 node, or
1474 - the name of a local tag you placed earlier using ":tag", or
1474 - the name of a local tag you placed earlier using ":tag", or
1475 - empty to denote the default parent.
1475 - empty to denote the default parent.
1476
1476
1477 All string valued-elements are either strictly alphanumeric, or must
1477 All string valued-elements are either strictly alphanumeric, or must
1478 be enclosed in double quotes ("..."), with "\\" as escape character.
1478 be enclosed in double quotes ("..."), with "\\" as escape character.
1479 """
1479 """
1480
1480
1481 if text is None:
1481 if text is None:
1482 ui.status(_("reading DAG from stdin\n"))
1482 ui.status(_("reading DAG from stdin\n"))
1483 text = ui.fin.read()
1483 text = ui.fin.read()
1484
1484
1485 cl = repo.changelog
1485 cl = repo.changelog
1486 if len(cl) > 0:
1486 if len(cl) > 0:
1487 raise util.Abort(_('repository is not empty'))
1487 raise util.Abort(_('repository is not empty'))
1488
1488
1489 # determine number of revs in DAG
1489 # determine number of revs in DAG
1490 total = 0
1490 total = 0
1491 for type, data in dagparser.parsedag(text):
1491 for type, data in dagparser.parsedag(text):
1492 if type == 'n':
1492 if type == 'n':
1493 total += 1
1493 total += 1
1494
1494
1495 if mergeable_file:
1495 if mergeable_file:
1496 linesperrev = 2
1496 linesperrev = 2
1497 # make a file with k lines per rev
1497 # make a file with k lines per rev
1498 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1498 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1499 initialmergedlines.append("")
1499 initialmergedlines.append("")
1500
1500
1501 tags = []
1501 tags = []
1502
1502
1503 lock = tr = None
1503 lock = tr = None
1504 try:
1504 try:
1505 lock = repo.lock()
1505 lock = repo.lock()
1506 tr = repo.transaction("builddag")
1506 tr = repo.transaction("builddag")
1507
1507
1508 at = -1
1508 at = -1
1509 atbranch = 'default'
1509 atbranch = 'default'
1510 nodeids = []
1510 nodeids = []
1511 id = 0
1511 id = 0
1512 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1512 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1513 for type, data in dagparser.parsedag(text):
1513 for type, data in dagparser.parsedag(text):
1514 if type == 'n':
1514 if type == 'n':
1515 ui.note('node %s\n' % str(data))
1515 ui.note('node %s\n' % str(data))
1516 id, ps = data
1516 id, ps = data
1517
1517
1518 files = []
1518 files = []
1519 fctxs = {}
1519 fctxs = {}
1520
1520
1521 p2 = None
1521 p2 = None
1522 if mergeable_file:
1522 if mergeable_file:
1523 fn = "mf"
1523 fn = "mf"
1524 p1 = repo[ps[0]]
1524 p1 = repo[ps[0]]
1525 if len(ps) > 1:
1525 if len(ps) > 1:
1526 p2 = repo[ps[1]]
1526 p2 = repo[ps[1]]
1527 pa = p1.ancestor(p2)
1527 pa = p1.ancestor(p2)
1528 base, local, other = [x[fn].data() for x in pa, p1, p2]
1528 base, local, other = [x[fn].data() for x in pa, p1, p2]
1529 m3 = simplemerge.Merge3Text(base, local, other)
1529 m3 = simplemerge.Merge3Text(base, local, other)
1530 ml = [l.strip() for l in m3.merge_lines()]
1530 ml = [l.strip() for l in m3.merge_lines()]
1531 ml.append("")
1531 ml.append("")
1532 elif at > 0:
1532 elif at > 0:
1533 ml = p1[fn].data().split("\n")
1533 ml = p1[fn].data().split("\n")
1534 else:
1534 else:
1535 ml = initialmergedlines
1535 ml = initialmergedlines
1536 ml[id * linesperrev] += " r%i" % id
1536 ml[id * linesperrev] += " r%i" % id
1537 mergedtext = "\n".join(ml)
1537 mergedtext = "\n".join(ml)
1538 files.append(fn)
1538 files.append(fn)
1539 fctxs[fn] = context.memfilectx(fn, mergedtext)
1539 fctxs[fn] = context.memfilectx(fn, mergedtext)
1540
1540
1541 if overwritten_file:
1541 if overwritten_file:
1542 fn = "of"
1542 fn = "of"
1543 files.append(fn)
1543 files.append(fn)
1544 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1544 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1545
1545
1546 if new_file:
1546 if new_file:
1547 fn = "nf%i" % id
1547 fn = "nf%i" % id
1548 files.append(fn)
1548 files.append(fn)
1549 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1549 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1550 if len(ps) > 1:
1550 if len(ps) > 1:
1551 if not p2:
1551 if not p2:
1552 p2 = repo[ps[1]]
1552 p2 = repo[ps[1]]
1553 for fn in p2:
1553 for fn in p2:
1554 if fn.startswith("nf"):
1554 if fn.startswith("nf"):
1555 files.append(fn)
1555 files.append(fn)
1556 fctxs[fn] = p2[fn]
1556 fctxs[fn] = p2[fn]
1557
1557
1558 def fctxfn(repo, cx, path):
1558 def fctxfn(repo, cx, path):
1559 return fctxs.get(path)
1559 return fctxs.get(path)
1560
1560
1561 if len(ps) == 0 or ps[0] < 0:
1561 if len(ps) == 0 or ps[0] < 0:
1562 pars = [None, None]
1562 pars = [None, None]
1563 elif len(ps) == 1:
1563 elif len(ps) == 1:
1564 pars = [nodeids[ps[0]], None]
1564 pars = [nodeids[ps[0]], None]
1565 else:
1565 else:
1566 pars = [nodeids[p] for p in ps]
1566 pars = [nodeids[p] for p in ps]
1567 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1567 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1568 date=(id, 0),
1568 date=(id, 0),
1569 user="debugbuilddag",
1569 user="debugbuilddag",
1570 extra={'branch': atbranch})
1570 extra={'branch': atbranch})
1571 nodeid = repo.commitctx(cx)
1571 nodeid = repo.commitctx(cx)
1572 nodeids.append(nodeid)
1572 nodeids.append(nodeid)
1573 at = id
1573 at = id
1574 elif type == 'l':
1574 elif type == 'l':
1575 id, name = data
1575 id, name = data
1576 ui.note('tag %s\n' % name)
1576 ui.note('tag %s\n' % name)
1577 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1577 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1578 elif type == 'a':
1578 elif type == 'a':
1579 ui.note('branch %s\n' % data)
1579 ui.note('branch %s\n' % data)
1580 atbranch = data
1580 atbranch = data
1581 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1581 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1582 tr.close()
1582 tr.close()
1583
1583
1584 if tags:
1584 if tags:
1585 repo.opener.write("localtags", "".join(tags))
1585 repo.opener.write("localtags", "".join(tags))
1586 finally:
1586 finally:
1587 ui.progress(_('building'), None)
1587 ui.progress(_('building'), None)
1588 release(tr, lock)
1588 release(tr, lock)
1589
1589
1590 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1590 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1591 def debugbundle(ui, bundlepath, all=None, **opts):
1591 def debugbundle(ui, bundlepath, all=None, **opts):
1592 """lists the contents of a bundle"""
1592 """lists the contents of a bundle"""
1593 f = url.open(ui, bundlepath)
1593 f = url.open(ui, bundlepath)
1594 try:
1594 try:
1595 gen = changegroup.readbundle(f, bundlepath)
1595 gen = changegroup.readbundle(f, bundlepath)
1596 if all:
1596 if all:
1597 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1597 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1598
1598
1599 def showchunks(named):
1599 def showchunks(named):
1600 ui.write("\n%s\n" % named)
1600 ui.write("\n%s\n" % named)
1601 chain = None
1601 chain = None
1602 while True:
1602 while True:
1603 chunkdata = gen.deltachunk(chain)
1603 chunkdata = gen.deltachunk(chain)
1604 if not chunkdata:
1604 if not chunkdata:
1605 break
1605 break
1606 node = chunkdata['node']
1606 node = chunkdata['node']
1607 p1 = chunkdata['p1']
1607 p1 = chunkdata['p1']
1608 p2 = chunkdata['p2']
1608 p2 = chunkdata['p2']
1609 cs = chunkdata['cs']
1609 cs = chunkdata['cs']
1610 deltabase = chunkdata['deltabase']
1610 deltabase = chunkdata['deltabase']
1611 delta = chunkdata['delta']
1611 delta = chunkdata['delta']
1612 ui.write("%s %s %s %s %s %s\n" %
1612 ui.write("%s %s %s %s %s %s\n" %
1613 (hex(node), hex(p1), hex(p2),
1613 (hex(node), hex(p1), hex(p2),
1614 hex(cs), hex(deltabase), len(delta)))
1614 hex(cs), hex(deltabase), len(delta)))
1615 chain = node
1615 chain = node
1616
1616
1617 chunkdata = gen.changelogheader()
1617 chunkdata = gen.changelogheader()
1618 showchunks("changelog")
1618 showchunks("changelog")
1619 chunkdata = gen.manifestheader()
1619 chunkdata = gen.manifestheader()
1620 showchunks("manifest")
1620 showchunks("manifest")
1621 while True:
1621 while True:
1622 chunkdata = gen.filelogheader()
1622 chunkdata = gen.filelogheader()
1623 if not chunkdata:
1623 if not chunkdata:
1624 break
1624 break
1625 fname = chunkdata['filename']
1625 fname = chunkdata['filename']
1626 showchunks(fname)
1626 showchunks(fname)
1627 else:
1627 else:
1628 chunkdata = gen.changelogheader()
1628 chunkdata = gen.changelogheader()
1629 chain = None
1629 chain = None
1630 while True:
1630 while True:
1631 chunkdata = gen.deltachunk(chain)
1631 chunkdata = gen.deltachunk(chain)
1632 if not chunkdata:
1632 if not chunkdata:
1633 break
1633 break
1634 node = chunkdata['node']
1634 node = chunkdata['node']
1635 ui.write("%s\n" % hex(node))
1635 ui.write("%s\n" % hex(node))
1636 chain = node
1636 chain = node
1637 finally:
1637 finally:
1638 f.close()
1638 f.close()
1639
1639
1640 @command('debugcheckstate', [], '')
1640 @command('debugcheckstate', [], '')
1641 def debugcheckstate(ui, repo):
1641 def debugcheckstate(ui, repo):
1642 """validate the correctness of the current dirstate"""
1642 """validate the correctness of the current dirstate"""
1643 parent1, parent2 = repo.dirstate.parents()
1643 parent1, parent2 = repo.dirstate.parents()
1644 m1 = repo[parent1].manifest()
1644 m1 = repo[parent1].manifest()
1645 m2 = repo[parent2].manifest()
1645 m2 = repo[parent2].manifest()
1646 errors = 0
1646 errors = 0
1647 for f in repo.dirstate:
1647 for f in repo.dirstate:
1648 state = repo.dirstate[f]
1648 state = repo.dirstate[f]
1649 if state in "nr" and f not in m1:
1649 if state in "nr" and f not in m1:
1650 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1650 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1651 errors += 1
1651 errors += 1
1652 if state in "a" and f in m1:
1652 if state in "a" and f in m1:
1653 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1653 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1654 errors += 1
1654 errors += 1
1655 if state in "m" and f not in m1 and f not in m2:
1655 if state in "m" and f not in m1 and f not in m2:
1656 ui.warn(_("%s in state %s, but not in either manifest\n") %
1656 ui.warn(_("%s in state %s, but not in either manifest\n") %
1657 (f, state))
1657 (f, state))
1658 errors += 1
1658 errors += 1
1659 for f in m1:
1659 for f in m1:
1660 state = repo.dirstate[f]
1660 state = repo.dirstate[f]
1661 if state not in "nrm":
1661 if state not in "nrm":
1662 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1662 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1663 errors += 1
1663 errors += 1
1664 if errors:
1664 if errors:
1665 error = _(".hg/dirstate inconsistent with current parent's manifest")
1665 error = _(".hg/dirstate inconsistent with current parent's manifest")
1666 raise util.Abort(error)
1666 raise util.Abort(error)
1667
1667
1668 @command('debugcommands', [], _('[COMMAND]'))
1668 @command('debugcommands', [], _('[COMMAND]'))
1669 def debugcommands(ui, cmd='', *args):
1669 def debugcommands(ui, cmd='', *args):
1670 """list all available commands and options"""
1670 """list all available commands and options"""
1671 for cmd, vals in sorted(table.iteritems()):
1671 for cmd, vals in sorted(table.iteritems()):
1672 cmd = cmd.split('|')[0].strip('^')
1672 cmd = cmd.split('|')[0].strip('^')
1673 opts = ', '.join([i[1] for i in vals[1]])
1673 opts = ', '.join([i[1] for i in vals[1]])
1674 ui.write('%s: %s\n' % (cmd, opts))
1674 ui.write('%s: %s\n' % (cmd, opts))
1675
1675
1676 @command('debugcomplete',
1676 @command('debugcomplete',
1677 [('o', 'options', None, _('show the command options'))],
1677 [('o', 'options', None, _('show the command options'))],
1678 _('[-o] CMD'))
1678 _('[-o] CMD'))
1679 def debugcomplete(ui, cmd='', **opts):
1679 def debugcomplete(ui, cmd='', **opts):
1680 """returns the completion list associated with the given command"""
1680 """returns the completion list associated with the given command"""
1681
1681
1682 if opts.get('options'):
1682 if opts.get('options'):
1683 options = []
1683 options = []
1684 otables = [globalopts]
1684 otables = [globalopts]
1685 if cmd:
1685 if cmd:
1686 aliases, entry = cmdutil.findcmd(cmd, table, False)
1686 aliases, entry = cmdutil.findcmd(cmd, table, False)
1687 otables.append(entry[1])
1687 otables.append(entry[1])
1688 for t in otables:
1688 for t in otables:
1689 for o in t:
1689 for o in t:
1690 if "(DEPRECATED)" in o[3]:
1690 if "(DEPRECATED)" in o[3]:
1691 continue
1691 continue
1692 if o[0]:
1692 if o[0]:
1693 options.append('-%s' % o[0])
1693 options.append('-%s' % o[0])
1694 options.append('--%s' % o[1])
1694 options.append('--%s' % o[1])
1695 ui.write("%s\n" % "\n".join(options))
1695 ui.write("%s\n" % "\n".join(options))
1696 return
1696 return
1697
1697
1698 cmdlist = cmdutil.findpossible(cmd, table)
1698 cmdlist = cmdutil.findpossible(cmd, table)
1699 if ui.verbose:
1699 if ui.verbose:
1700 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1700 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1701 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1701 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1702
1702
1703 @command('debugdag',
1703 @command('debugdag',
1704 [('t', 'tags', None, _('use tags as labels')),
1704 [('t', 'tags', None, _('use tags as labels')),
1705 ('b', 'branches', None, _('annotate with branch names')),
1705 ('b', 'branches', None, _('annotate with branch names')),
1706 ('', 'dots', None, _('use dots for runs')),
1706 ('', 'dots', None, _('use dots for runs')),
1707 ('s', 'spaces', None, _('separate elements by spaces'))],
1707 ('s', 'spaces', None, _('separate elements by spaces'))],
1708 _('[OPTION]... [FILE [REV]...]'))
1708 _('[OPTION]... [FILE [REV]...]'))
1709 def debugdag(ui, repo, file_=None, *revs, **opts):
1709 def debugdag(ui, repo, file_=None, *revs, **opts):
1710 """format the changelog or an index DAG as a concise textual description
1710 """format the changelog or an index DAG as a concise textual description
1711
1711
1712 If you pass a revlog index, the revlog's DAG is emitted. If you list
1712 If you pass a revlog index, the revlog's DAG is emitted. If you list
1713 revision numbers, they get labeled in the output as rN.
1713 revision numbers, they get labeled in the output as rN.
1714
1714
1715 Otherwise, the changelog DAG of the current repo is emitted.
1715 Otherwise, the changelog DAG of the current repo is emitted.
1716 """
1716 """
1717 spaces = opts.get('spaces')
1717 spaces = opts.get('spaces')
1718 dots = opts.get('dots')
1718 dots = opts.get('dots')
1719 if file_:
1719 if file_:
1720 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1720 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1721 revs = set((int(r) for r in revs))
1721 revs = set((int(r) for r in revs))
1722 def events():
1722 def events():
1723 for r in rlog:
1723 for r in rlog:
1724 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1724 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1725 if p != -1)))
1725 if p != -1)))
1726 if r in revs:
1726 if r in revs:
1727 yield 'l', (r, "r%i" % r)
1727 yield 'l', (r, "r%i" % r)
1728 elif repo:
1728 elif repo:
1729 cl = repo.changelog
1729 cl = repo.changelog
1730 tags = opts.get('tags')
1730 tags = opts.get('tags')
1731 branches = opts.get('branches')
1731 branches = opts.get('branches')
1732 if tags:
1732 if tags:
1733 labels = {}
1733 labels = {}
1734 for l, n in repo.tags().items():
1734 for l, n in repo.tags().items():
1735 labels.setdefault(cl.rev(n), []).append(l)
1735 labels.setdefault(cl.rev(n), []).append(l)
1736 def events():
1736 def events():
1737 b = "default"
1737 b = "default"
1738 for r in cl:
1738 for r in cl:
1739 if branches:
1739 if branches:
1740 newb = cl.read(cl.node(r))[5]['branch']
1740 newb = cl.read(cl.node(r))[5]['branch']
1741 if newb != b:
1741 if newb != b:
1742 yield 'a', newb
1742 yield 'a', newb
1743 b = newb
1743 b = newb
1744 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1744 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1745 if p != -1)))
1745 if p != -1)))
1746 if tags:
1746 if tags:
1747 ls = labels.get(r)
1747 ls = labels.get(r)
1748 if ls:
1748 if ls:
1749 for l in ls:
1749 for l in ls:
1750 yield 'l', (r, l)
1750 yield 'l', (r, l)
1751 else:
1751 else:
1752 raise util.Abort(_('need repo for changelog dag'))
1752 raise util.Abort(_('need repo for changelog dag'))
1753
1753
1754 for line in dagparser.dagtextlines(events(),
1754 for line in dagparser.dagtextlines(events(),
1755 addspaces=spaces,
1755 addspaces=spaces,
1756 wraplabels=True,
1756 wraplabels=True,
1757 wrapannotations=True,
1757 wrapannotations=True,
1758 wrapnonlinear=dots,
1758 wrapnonlinear=dots,
1759 usedots=dots,
1759 usedots=dots,
1760 maxlinewidth=70):
1760 maxlinewidth=70):
1761 ui.write(line)
1761 ui.write(line)
1762 ui.write("\n")
1762 ui.write("\n")
1763
1763
1764 @command('debugdata',
1764 @command('debugdata',
1765 [('c', 'changelog', False, _('open changelog')),
1765 [('c', 'changelog', False, _('open changelog')),
1766 ('m', 'manifest', False, _('open manifest'))],
1766 ('m', 'manifest', False, _('open manifest'))],
1767 _('-c|-m|FILE REV'))
1767 _('-c|-m|FILE REV'))
1768 def debugdata(ui, repo, file_, rev = None, **opts):
1768 def debugdata(ui, repo, file_, rev = None, **opts):
1769 """dump the contents of a data file revision"""
1769 """dump the contents of a data file revision"""
1770 if opts.get('changelog') or opts.get('manifest'):
1770 if opts.get('changelog') or opts.get('manifest'):
1771 file_, rev = None, file_
1771 file_, rev = None, file_
1772 elif rev is None:
1772 elif rev is None:
1773 raise error.CommandError('debugdata', _('invalid arguments'))
1773 raise error.CommandError('debugdata', _('invalid arguments'))
1774 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1774 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1775 try:
1775 try:
1776 ui.write(r.revision(r.lookup(rev)))
1776 ui.write(r.revision(r.lookup(rev)))
1777 except KeyError:
1777 except KeyError:
1778 raise util.Abort(_('invalid revision identifier %s') % rev)
1778 raise util.Abort(_('invalid revision identifier %s') % rev)
1779
1779
1780 @command('debugdate',
1780 @command('debugdate',
1781 [('e', 'extended', None, _('try extended date formats'))],
1781 [('e', 'extended', None, _('try extended date formats'))],
1782 _('[-e] DATE [RANGE]'))
1782 _('[-e] DATE [RANGE]'))
1783 def debugdate(ui, date, range=None, **opts):
1783 def debugdate(ui, date, range=None, **opts):
1784 """parse and display a date"""
1784 """parse and display a date"""
1785 if opts["extended"]:
1785 if opts["extended"]:
1786 d = util.parsedate(date, util.extendeddateformats)
1786 d = util.parsedate(date, util.extendeddateformats)
1787 else:
1787 else:
1788 d = util.parsedate(date)
1788 d = util.parsedate(date)
1789 ui.write("internal: %s %s\n" % d)
1789 ui.write("internal: %s %s\n" % d)
1790 ui.write("standard: %s\n" % util.datestr(d))
1790 ui.write("standard: %s\n" % util.datestr(d))
1791 if range:
1791 if range:
1792 m = util.matchdate(range)
1792 m = util.matchdate(range)
1793 ui.write("match: %s\n" % m(d[0]))
1793 ui.write("match: %s\n" % m(d[0]))
1794
1794
1795 @command('debugdiscovery',
1795 @command('debugdiscovery',
1796 [('', 'old', None, _('use old-style discovery')),
1796 [('', 'old', None, _('use old-style discovery')),
1797 ('', 'nonheads', None,
1797 ('', 'nonheads', None,
1798 _('use old-style discovery with non-heads included')),
1798 _('use old-style discovery with non-heads included')),
1799 ] + remoteopts,
1799 ] + remoteopts,
1800 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1800 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1801 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1801 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1802 """runs the changeset discovery protocol in isolation"""
1802 """runs the changeset discovery protocol in isolation"""
1803 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1803 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1804 opts.get('branch'))
1804 opts.get('branch'))
1805 remote = hg.peer(repo, opts, remoteurl)
1805 remote = hg.peer(repo, opts, remoteurl)
1806 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1806 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1807
1807
1808 # make sure tests are repeatable
1808 # make sure tests are repeatable
1809 random.seed(12323)
1809 random.seed(12323)
1810
1810
1811 def doit(localheads, remoteheads, remote=remote):
1811 def doit(localheads, remoteheads, remote=remote):
1812 if opts.get('old'):
1812 if opts.get('old'):
1813 if localheads:
1813 if localheads:
1814 raise util.Abort('cannot use localheads with old style '
1814 raise util.Abort('cannot use localheads with old style '
1815 'discovery')
1815 'discovery')
1816 if not util.safehasattr(remote, 'branches'):
1816 if not util.safehasattr(remote, 'branches'):
1817 # enable in-client legacy support
1817 # enable in-client legacy support
1818 remote = localrepo.locallegacypeer(remote.local())
1818 remote = localrepo.locallegacypeer(remote.local())
1819 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1819 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1820 force=True)
1820 force=True)
1821 common = set(common)
1821 common = set(common)
1822 if not opts.get('nonheads'):
1822 if not opts.get('nonheads'):
1823 ui.write("unpruned common: %s\n" % " ".join([short(n)
1823 ui.write("unpruned common: %s\n" % " ".join([short(n)
1824 for n in common]))
1824 for n in common]))
1825 dag = dagutil.revlogdag(repo.changelog)
1825 dag = dagutil.revlogdag(repo.changelog)
1826 all = dag.ancestorset(dag.internalizeall(common))
1826 all = dag.ancestorset(dag.internalizeall(common))
1827 common = dag.externalizeall(dag.headsetofconnecteds(all))
1827 common = dag.externalizeall(dag.headsetofconnecteds(all))
1828 else:
1828 else:
1829 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1829 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1830 common = set(common)
1830 common = set(common)
1831 rheads = set(hds)
1831 rheads = set(hds)
1832 lheads = set(repo.heads())
1832 lheads = set(repo.heads())
1833 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1833 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1834 if lheads <= common:
1834 if lheads <= common:
1835 ui.write("local is subset\n")
1835 ui.write("local is subset\n")
1836 elif rheads <= common:
1836 elif rheads <= common:
1837 ui.write("remote is subset\n")
1837 ui.write("remote is subset\n")
1838
1838
1839 serverlogs = opts.get('serverlog')
1839 serverlogs = opts.get('serverlog')
1840 if serverlogs:
1840 if serverlogs:
1841 for filename in serverlogs:
1841 for filename in serverlogs:
1842 logfile = open(filename, 'r')
1842 logfile = open(filename, 'r')
1843 try:
1843 try:
1844 line = logfile.readline()
1844 line = logfile.readline()
1845 while line:
1845 while line:
1846 parts = line.strip().split(';')
1846 parts = line.strip().split(';')
1847 op = parts[1]
1847 op = parts[1]
1848 if op == 'cg':
1848 if op == 'cg':
1849 pass
1849 pass
1850 elif op == 'cgss':
1850 elif op == 'cgss':
1851 doit(parts[2].split(' '), parts[3].split(' '))
1851 doit(parts[2].split(' '), parts[3].split(' '))
1852 elif op == 'unb':
1852 elif op == 'unb':
1853 doit(parts[3].split(' '), parts[2].split(' '))
1853 doit(parts[3].split(' '), parts[2].split(' '))
1854 line = logfile.readline()
1854 line = logfile.readline()
1855 finally:
1855 finally:
1856 logfile.close()
1856 logfile.close()
1857
1857
1858 else:
1858 else:
1859 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1859 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1860 opts.get('remote_head'))
1860 opts.get('remote_head'))
1861 localrevs = opts.get('local_head')
1861 localrevs = opts.get('local_head')
1862 doit(localrevs, remoterevs)
1862 doit(localrevs, remoterevs)
1863
1863
1864 @command('debugfileset',
1864 @command('debugfileset',
1865 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1865 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1866 _('[-r REV] FILESPEC'))
1866 _('[-r REV] FILESPEC'))
1867 def debugfileset(ui, repo, expr, **opts):
1867 def debugfileset(ui, repo, expr, **opts):
1868 '''parse and apply a fileset specification'''
1868 '''parse and apply a fileset specification'''
1869 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1869 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1870 if ui.verbose:
1870 if ui.verbose:
1871 tree = fileset.parse(expr)[0]
1871 tree = fileset.parse(expr)[0]
1872 ui.note(tree, "\n")
1872 ui.note(tree, "\n")
1873
1873
1874 for f in fileset.getfileset(ctx, expr):
1874 for f in fileset.getfileset(ctx, expr):
1875 ui.write("%s\n" % f)
1875 ui.write("%s\n" % f)
1876
1876
1877 @command('debugfsinfo', [], _('[PATH]'))
1877 @command('debugfsinfo', [], _('[PATH]'))
1878 def debugfsinfo(ui, path = "."):
1878 def debugfsinfo(ui, path = "."):
1879 """show information detected about current filesystem"""
1879 """show information detected about current filesystem"""
1880 util.writefile('.debugfsinfo', '')
1880 util.writefile('.debugfsinfo', '')
1881 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1881 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1882 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1882 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1883 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1883 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1884 and 'yes' or 'no'))
1884 and 'yes' or 'no'))
1885 os.unlink('.debugfsinfo')
1885 os.unlink('.debugfsinfo')
1886
1886
1887 @command('debuggetbundle',
1887 @command('debuggetbundle',
1888 [('H', 'head', [], _('id of head node'), _('ID')),
1888 [('H', 'head', [], _('id of head node'), _('ID')),
1889 ('C', 'common', [], _('id of common node'), _('ID')),
1889 ('C', 'common', [], _('id of common node'), _('ID')),
1890 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1890 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1891 _('REPO FILE [-H|-C ID]...'))
1891 _('REPO FILE [-H|-C ID]...'))
1892 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1892 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1893 """retrieves a bundle from a repo
1893 """retrieves a bundle from a repo
1894
1894
1895 Every ID must be a full-length hex node id string. Saves the bundle to the
1895 Every ID must be a full-length hex node id string. Saves the bundle to the
1896 given file.
1896 given file.
1897 """
1897 """
1898 repo = hg.peer(ui, opts, repopath)
1898 repo = hg.peer(ui, opts, repopath)
1899 if not repo.capable('getbundle'):
1899 if not repo.capable('getbundle'):
1900 raise util.Abort("getbundle() not supported by target repository")
1900 raise util.Abort("getbundle() not supported by target repository")
1901 args = {}
1901 args = {}
1902 if common:
1902 if common:
1903 args['common'] = [bin(s) for s in common]
1903 args['common'] = [bin(s) for s in common]
1904 if head:
1904 if head:
1905 args['heads'] = [bin(s) for s in head]
1905 args['heads'] = [bin(s) for s in head]
1906 bundle = repo.getbundle('debug', **args)
1906 bundle = repo.getbundle('debug', **args)
1907
1907
1908 bundletype = opts.get('type', 'bzip2').lower()
1908 bundletype = opts.get('type', 'bzip2').lower()
1909 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1909 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1910 bundletype = btypes.get(bundletype)
1910 bundletype = btypes.get(bundletype)
1911 if bundletype not in changegroup.bundletypes:
1911 if bundletype not in changegroup.bundletypes:
1912 raise util.Abort(_('unknown bundle type specified with --type'))
1912 raise util.Abort(_('unknown bundle type specified with --type'))
1913 changegroup.writebundle(bundle, bundlepath, bundletype)
1913 changegroup.writebundle(bundle, bundlepath, bundletype)
1914
1914
1915 @command('debugignore', [], '')
1915 @command('debugignore', [], '')
1916 def debugignore(ui, repo, *values, **opts):
1916 def debugignore(ui, repo, *values, **opts):
1917 """display the combined ignore pattern"""
1917 """display the combined ignore pattern"""
1918 ignore = repo.dirstate._ignore
1918 ignore = repo.dirstate._ignore
1919 includepat = getattr(ignore, 'includepat', None)
1919 includepat = getattr(ignore, 'includepat', None)
1920 if includepat is not None:
1920 if includepat is not None:
1921 ui.write("%s\n" % includepat)
1921 ui.write("%s\n" % includepat)
1922 else:
1922 else:
1923 raise util.Abort(_("no ignore patterns found"))
1923 raise util.Abort(_("no ignore patterns found"))
1924
1924
1925 @command('debugindex',
1925 @command('debugindex',
1926 [('c', 'changelog', False, _('open changelog')),
1926 [('c', 'changelog', False, _('open changelog')),
1927 ('m', 'manifest', False, _('open manifest')),
1927 ('m', 'manifest', False, _('open manifest')),
1928 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1928 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1929 _('[-f FORMAT] -c|-m|FILE'))
1929 _('[-f FORMAT] -c|-m|FILE'))
1930 def debugindex(ui, repo, file_ = None, **opts):
1930 def debugindex(ui, repo, file_ = None, **opts):
1931 """dump the contents of an index file"""
1931 """dump the contents of an index file"""
1932 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1932 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1933 format = opts.get('format', 0)
1933 format = opts.get('format', 0)
1934 if format not in (0, 1):
1934 if format not in (0, 1):
1935 raise util.Abort(_("unknown format %d") % format)
1935 raise util.Abort(_("unknown format %d") % format)
1936
1936
1937 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1937 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1938 if generaldelta:
1938 if generaldelta:
1939 basehdr = ' delta'
1939 basehdr = ' delta'
1940 else:
1940 else:
1941 basehdr = ' base'
1941 basehdr = ' base'
1942
1942
1943 if format == 0:
1943 if format == 0:
1944 ui.write(" rev offset length " + basehdr + " linkrev"
1944 ui.write(" rev offset length " + basehdr + " linkrev"
1945 " nodeid p1 p2\n")
1945 " nodeid p1 p2\n")
1946 elif format == 1:
1946 elif format == 1:
1947 ui.write(" rev flag offset length"
1947 ui.write(" rev flag offset length"
1948 " size " + basehdr + " link p1 p2"
1948 " size " + basehdr + " link p1 p2"
1949 " nodeid\n")
1949 " nodeid\n")
1950
1950
1951 for i in r:
1951 for i in r:
1952 node = r.node(i)
1952 node = r.node(i)
1953 if generaldelta:
1953 if generaldelta:
1954 base = r.deltaparent(i)
1954 base = r.deltaparent(i)
1955 else:
1955 else:
1956 base = r.chainbase(i)
1956 base = r.chainbase(i)
1957 if format == 0:
1957 if format == 0:
1958 try:
1958 try:
1959 pp = r.parents(node)
1959 pp = r.parents(node)
1960 except Exception:
1960 except Exception:
1961 pp = [nullid, nullid]
1961 pp = [nullid, nullid]
1962 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1962 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1963 i, r.start(i), r.length(i), base, r.linkrev(i),
1963 i, r.start(i), r.length(i), base, r.linkrev(i),
1964 short(node), short(pp[0]), short(pp[1])))
1964 short(node), short(pp[0]), short(pp[1])))
1965 elif format == 1:
1965 elif format == 1:
1966 pr = r.parentrevs(i)
1966 pr = r.parentrevs(i)
1967 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1967 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1968 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1968 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1969 base, r.linkrev(i), pr[0], pr[1], short(node)))
1969 base, r.linkrev(i), pr[0], pr[1], short(node)))
1970
1970
1971 @command('debugindexdot', [], _('FILE'))
1971 @command('debugindexdot', [], _('FILE'))
1972 def debugindexdot(ui, repo, file_):
1972 def debugindexdot(ui, repo, file_):
1973 """dump an index DAG as a graphviz dot file"""
1973 """dump an index DAG as a graphviz dot file"""
1974 r = None
1974 r = None
1975 if repo:
1975 if repo:
1976 filelog = repo.file(file_)
1976 filelog = repo.file(file_)
1977 if len(filelog):
1977 if len(filelog):
1978 r = filelog
1978 r = filelog
1979 if not r:
1979 if not r:
1980 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1980 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1981 ui.write("digraph G {\n")
1981 ui.write("digraph G {\n")
1982 for i in r:
1982 for i in r:
1983 node = r.node(i)
1983 node = r.node(i)
1984 pp = r.parents(node)
1984 pp = r.parents(node)
1985 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1985 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1986 if pp[1] != nullid:
1986 if pp[1] != nullid:
1987 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1987 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1988 ui.write("}\n")
1988 ui.write("}\n")
1989
1989
1990 @command('debuginstall', [], '')
1990 @command('debuginstall', [], '')
1991 def debuginstall(ui):
1991 def debuginstall(ui):
1992 '''test Mercurial installation
1992 '''test Mercurial installation
1993
1993
1994 Returns 0 on success.
1994 Returns 0 on success.
1995 '''
1995 '''
1996
1996
1997 def writetemp(contents):
1997 def writetemp(contents):
1998 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1998 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1999 f = os.fdopen(fd, "wb")
1999 f = os.fdopen(fd, "wb")
2000 f.write(contents)
2000 f.write(contents)
2001 f.close()
2001 f.close()
2002 return name
2002 return name
2003
2003
2004 problems = 0
2004 problems = 0
2005
2005
2006 # encoding
2006 # encoding
2007 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2007 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2008 try:
2008 try:
2009 encoding.fromlocal("test")
2009 encoding.fromlocal("test")
2010 except util.Abort, inst:
2010 except util.Abort, inst:
2011 ui.write(" %s\n" % inst)
2011 ui.write(" %s\n" % inst)
2012 ui.write(_(" (check that your locale is properly set)\n"))
2012 ui.write(_(" (check that your locale is properly set)\n"))
2013 problems += 1
2013 problems += 1
2014
2014
2015 # Python lib
2015 # Python lib
2016 ui.status(_("checking Python lib (%s)...\n")
2016 ui.status(_("checking Python lib (%s)...\n")
2017 % os.path.dirname(os.__file__))
2017 % os.path.dirname(os.__file__))
2018
2018
2019 # compiled modules
2019 # compiled modules
2020 ui.status(_("checking installed modules (%s)...\n")
2020 ui.status(_("checking installed modules (%s)...\n")
2021 % os.path.dirname(__file__))
2021 % os.path.dirname(__file__))
2022 try:
2022 try:
2023 import bdiff, mpatch, base85, osutil
2023 import bdiff, mpatch, base85, osutil
2024 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2024 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2025 except Exception, inst:
2025 except Exception, inst:
2026 ui.write(" %s\n" % inst)
2026 ui.write(" %s\n" % inst)
2027 ui.write(_(" One or more extensions could not be found"))
2027 ui.write(_(" One or more extensions could not be found"))
2028 ui.write(_(" (check that you compiled the extensions)\n"))
2028 ui.write(_(" (check that you compiled the extensions)\n"))
2029 problems += 1
2029 problems += 1
2030
2030
2031 # templates
2031 # templates
2032 import templater
2032 import templater
2033 p = templater.templatepath()
2033 p = templater.templatepath()
2034 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2034 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2035 try:
2035 try:
2036 templater.templater(templater.templatepath("map-cmdline.default"))
2036 templater.templater(templater.templatepath("map-cmdline.default"))
2037 except Exception, inst:
2037 except Exception, inst:
2038 ui.write(" %s\n" % inst)
2038 ui.write(" %s\n" % inst)
2039 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2039 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2040 problems += 1
2040 problems += 1
2041
2041
2042 # editor
2042 # editor
2043 ui.status(_("checking commit editor...\n"))
2043 ui.status(_("checking commit editor...\n"))
2044 editor = ui.geteditor()
2044 editor = ui.geteditor()
2045 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2045 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2046 if not cmdpath:
2046 if not cmdpath:
2047 if editor == 'vi':
2047 if editor == 'vi':
2048 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2048 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2049 ui.write(_(" (specify a commit editor in your configuration"
2049 ui.write(_(" (specify a commit editor in your configuration"
2050 " file)\n"))
2050 " file)\n"))
2051 else:
2051 else:
2052 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2052 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2053 ui.write(_(" (specify a commit editor in your configuration"
2053 ui.write(_(" (specify a commit editor in your configuration"
2054 " file)\n"))
2054 " file)\n"))
2055 problems += 1
2055 problems += 1
2056
2056
2057 # check username
2057 # check username
2058 ui.status(_("checking username...\n"))
2058 ui.status(_("checking username...\n"))
2059 try:
2059 try:
2060 ui.username()
2060 ui.username()
2061 except util.Abort, e:
2061 except util.Abort, e:
2062 ui.write(" %s\n" % e)
2062 ui.write(" %s\n" % e)
2063 ui.write(_(" (specify a username in your configuration file)\n"))
2063 ui.write(_(" (specify a username in your configuration file)\n"))
2064 problems += 1
2064 problems += 1
2065
2065
2066 if not problems:
2066 if not problems:
2067 ui.status(_("no problems detected\n"))
2067 ui.status(_("no problems detected\n"))
2068 else:
2068 else:
2069 ui.write(_("%s problems detected,"
2069 ui.write(_("%s problems detected,"
2070 " please check your install!\n") % problems)
2070 " please check your install!\n") % problems)
2071
2071
2072 return problems
2072 return problems
2073
2073
2074 @command('debugknown', [], _('REPO ID...'))
2074 @command('debugknown', [], _('REPO ID...'))
2075 def debugknown(ui, repopath, *ids, **opts):
2075 def debugknown(ui, repopath, *ids, **opts):
2076 """test whether node ids are known to a repo
2076 """test whether node ids are known to a repo
2077
2077
2078 Every ID must be a full-length hex node id string. Returns a list of 0s
2078 Every ID must be a full-length hex node id string. Returns a list of 0s
2079 and 1s indicating unknown/known.
2079 and 1s indicating unknown/known.
2080 """
2080 """
2081 repo = hg.peer(ui, opts, repopath)
2081 repo = hg.peer(ui, opts, repopath)
2082 if not repo.capable('known'):
2082 if not repo.capable('known'):
2083 raise util.Abort("known() not supported by target repository")
2083 raise util.Abort("known() not supported by target repository")
2084 flags = repo.known([bin(s) for s in ids])
2084 flags = repo.known([bin(s) for s in ids])
2085 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2085 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2086
2086
2087 @command('debugobsolete', [] + commitopts2,
2087 @command('debugobsolete',
2088 [('', 'flags', 0, _('markers flag')),
2089 ] + commitopts2,
2088 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2090 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2089 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2091 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2090 """create arbitrary obsolete marker"""
2092 """create arbitrary obsolete marker"""
2091 def parsenodeid(s):
2093 def parsenodeid(s):
2092 try:
2094 try:
2093 # We do not use revsingle/revrange functions here to accept
2095 # We do not use revsingle/revrange functions here to accept
2094 # arbitrary node identifiers, possibly not present in the
2096 # arbitrary node identifiers, possibly not present in the
2095 # local repository.
2097 # local repository.
2096 n = bin(s)
2098 n = bin(s)
2097 if len(n) != len(nullid):
2099 if len(n) != len(nullid):
2098 raise TypeError()
2100 raise TypeError()
2099 return n
2101 return n
2100 except TypeError:
2102 except TypeError:
2101 raise util.Abort('changeset references must be full hexadecimal '
2103 raise util.Abort('changeset references must be full hexadecimal '
2102 'node identifiers')
2104 'node identifiers')
2103
2105
2104 if precursor is not None:
2106 if precursor is not None:
2105 metadata = {}
2107 metadata = {}
2106 if 'date' in opts:
2108 if 'date' in opts:
2107 metadata['date'] = opts['date']
2109 metadata['date'] = opts['date']
2108 metadata['user'] = opts['user'] or ui.username()
2110 metadata['user'] = opts['user'] or ui.username()
2109 succs = tuple(parsenodeid(succ) for succ in successors)
2111 succs = tuple(parsenodeid(succ) for succ in successors)
2110 l = repo.lock()
2112 l = repo.lock()
2111 try:
2113 try:
2112 tr = repo.transaction('debugobsolete')
2114 tr = repo.transaction('debugobsolete')
2113 try:
2115 try:
2114 repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
2116 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2115 metadata)
2117 opts['flags'], metadata)
2116 tr.close()
2118 tr.close()
2117 finally:
2119 finally:
2118 tr.release()
2120 tr.release()
2119 finally:
2121 finally:
2120 l.release()
2122 l.release()
2121 else:
2123 else:
2122 for m in obsolete.allmarkers(repo):
2124 for m in obsolete.allmarkers(repo):
2123 ui.write(hex(m.precnode()))
2125 ui.write(hex(m.precnode()))
2124 for repl in m.succnodes():
2126 for repl in m.succnodes():
2125 ui.write(' ')
2127 ui.write(' ')
2126 ui.write(hex(repl))
2128 ui.write(hex(repl))
2127 ui.write(' %X ' % m._data[2])
2129 ui.write(' %X ' % m._data[2])
2128 ui.write(m.metadata())
2130 ui.write(m.metadata())
2129 ui.write('\n')
2131 ui.write('\n')
2130
2132
2131 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2133 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2132 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2134 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2133 '''access the pushkey key/value protocol
2135 '''access the pushkey key/value protocol
2134
2136
2135 With two args, list the keys in the given namespace.
2137 With two args, list the keys in the given namespace.
2136
2138
2137 With five args, set a key to new if it currently is set to old.
2139 With five args, set a key to new if it currently is set to old.
2138 Reports success or failure.
2140 Reports success or failure.
2139 '''
2141 '''
2140
2142
2141 target = hg.peer(ui, {}, repopath)
2143 target = hg.peer(ui, {}, repopath)
2142 if keyinfo:
2144 if keyinfo:
2143 key, old, new = keyinfo
2145 key, old, new = keyinfo
2144 r = target.pushkey(namespace, key, old, new)
2146 r = target.pushkey(namespace, key, old, new)
2145 ui.status(str(r) + '\n')
2147 ui.status(str(r) + '\n')
2146 return not r
2148 return not r
2147 else:
2149 else:
2148 for k, v in target.listkeys(namespace).iteritems():
2150 for k, v in target.listkeys(namespace).iteritems():
2149 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2151 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2150 v.encode('string-escape')))
2152 v.encode('string-escape')))
2151
2153
2152 @command('debugpvec', [], _('A B'))
2154 @command('debugpvec', [], _('A B'))
2153 def debugpvec(ui, repo, a, b=None):
2155 def debugpvec(ui, repo, a, b=None):
2154 ca = scmutil.revsingle(repo, a)
2156 ca = scmutil.revsingle(repo, a)
2155 cb = scmutil.revsingle(repo, b)
2157 cb = scmutil.revsingle(repo, b)
2156 pa = pvec.ctxpvec(ca)
2158 pa = pvec.ctxpvec(ca)
2157 pb = pvec.ctxpvec(cb)
2159 pb = pvec.ctxpvec(cb)
2158 if pa == pb:
2160 if pa == pb:
2159 rel = "="
2161 rel = "="
2160 elif pa > pb:
2162 elif pa > pb:
2161 rel = ">"
2163 rel = ">"
2162 elif pa < pb:
2164 elif pa < pb:
2163 rel = "<"
2165 rel = "<"
2164 elif pa | pb:
2166 elif pa | pb:
2165 rel = "|"
2167 rel = "|"
2166 ui.write(_("a: %s\n") % pa)
2168 ui.write(_("a: %s\n") % pa)
2167 ui.write(_("b: %s\n") % pb)
2169 ui.write(_("b: %s\n") % pb)
2168 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2170 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2169 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2171 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2170 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2172 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2171 pa.distance(pb), rel))
2173 pa.distance(pb), rel))
2172
2174
2173 @command('debugrebuildstate',
2175 @command('debugrebuildstate',
2174 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2176 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2175 _('[-r REV] [REV]'))
2177 _('[-r REV] [REV]'))
2176 def debugrebuildstate(ui, repo, rev="tip"):
2178 def debugrebuildstate(ui, repo, rev="tip"):
2177 """rebuild the dirstate as it would look like for the given revision"""
2179 """rebuild the dirstate as it would look like for the given revision"""
2178 ctx = scmutil.revsingle(repo, rev)
2180 ctx = scmutil.revsingle(repo, rev)
2179 wlock = repo.wlock()
2181 wlock = repo.wlock()
2180 try:
2182 try:
2181 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2183 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2182 finally:
2184 finally:
2183 wlock.release()
2185 wlock.release()
2184
2186
2185 @command('debugrename',
2187 @command('debugrename',
2186 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2188 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2187 _('[-r REV] FILE'))
2189 _('[-r REV] FILE'))
2188 def debugrename(ui, repo, file1, *pats, **opts):
2190 def debugrename(ui, repo, file1, *pats, **opts):
2189 """dump rename information"""
2191 """dump rename information"""
2190
2192
2191 ctx = scmutil.revsingle(repo, opts.get('rev'))
2193 ctx = scmutil.revsingle(repo, opts.get('rev'))
2192 m = scmutil.match(ctx, (file1,) + pats, opts)
2194 m = scmutil.match(ctx, (file1,) + pats, opts)
2193 for abs in ctx.walk(m):
2195 for abs in ctx.walk(m):
2194 fctx = ctx[abs]
2196 fctx = ctx[abs]
2195 o = fctx.filelog().renamed(fctx.filenode())
2197 o = fctx.filelog().renamed(fctx.filenode())
2196 rel = m.rel(abs)
2198 rel = m.rel(abs)
2197 if o:
2199 if o:
2198 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2200 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2199 else:
2201 else:
2200 ui.write(_("%s not renamed\n") % rel)
2202 ui.write(_("%s not renamed\n") % rel)
2201
2203
2202 @command('debugrevlog',
2204 @command('debugrevlog',
2203 [('c', 'changelog', False, _('open changelog')),
2205 [('c', 'changelog', False, _('open changelog')),
2204 ('m', 'manifest', False, _('open manifest')),
2206 ('m', 'manifest', False, _('open manifest')),
2205 ('d', 'dump', False, _('dump index data'))],
2207 ('d', 'dump', False, _('dump index data'))],
2206 _('-c|-m|FILE'))
2208 _('-c|-m|FILE'))
2207 def debugrevlog(ui, repo, file_ = None, **opts):
2209 def debugrevlog(ui, repo, file_ = None, **opts):
2208 """show data and statistics about a revlog"""
2210 """show data and statistics about a revlog"""
2209 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2211 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2210
2212
2211 if opts.get("dump"):
2213 if opts.get("dump"):
2212 numrevs = len(r)
2214 numrevs = len(r)
2213 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2215 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2214 " rawsize totalsize compression heads\n")
2216 " rawsize totalsize compression heads\n")
2215 ts = 0
2217 ts = 0
2216 heads = set()
2218 heads = set()
2217 for rev in xrange(numrevs):
2219 for rev in xrange(numrevs):
2218 dbase = r.deltaparent(rev)
2220 dbase = r.deltaparent(rev)
2219 if dbase == -1:
2221 if dbase == -1:
2220 dbase = rev
2222 dbase = rev
2221 cbase = r.chainbase(rev)
2223 cbase = r.chainbase(rev)
2222 p1, p2 = r.parentrevs(rev)
2224 p1, p2 = r.parentrevs(rev)
2223 rs = r.rawsize(rev)
2225 rs = r.rawsize(rev)
2224 ts = ts + rs
2226 ts = ts + rs
2225 heads -= set(r.parentrevs(rev))
2227 heads -= set(r.parentrevs(rev))
2226 heads.add(rev)
2228 heads.add(rev)
2227 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2229 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2228 (rev, p1, p2, r.start(rev), r.end(rev),
2230 (rev, p1, p2, r.start(rev), r.end(rev),
2229 r.start(dbase), r.start(cbase),
2231 r.start(dbase), r.start(cbase),
2230 r.start(p1), r.start(p2),
2232 r.start(p1), r.start(p2),
2231 rs, ts, ts / r.end(rev), len(heads)))
2233 rs, ts, ts / r.end(rev), len(heads)))
2232 return 0
2234 return 0
2233
2235
2234 v = r.version
2236 v = r.version
2235 format = v & 0xFFFF
2237 format = v & 0xFFFF
2236 flags = []
2238 flags = []
2237 gdelta = False
2239 gdelta = False
2238 if v & revlog.REVLOGNGINLINEDATA:
2240 if v & revlog.REVLOGNGINLINEDATA:
2239 flags.append('inline')
2241 flags.append('inline')
2240 if v & revlog.REVLOGGENERALDELTA:
2242 if v & revlog.REVLOGGENERALDELTA:
2241 gdelta = True
2243 gdelta = True
2242 flags.append('generaldelta')
2244 flags.append('generaldelta')
2243 if not flags:
2245 if not flags:
2244 flags = ['(none)']
2246 flags = ['(none)']
2245
2247
2246 nummerges = 0
2248 nummerges = 0
2247 numfull = 0
2249 numfull = 0
2248 numprev = 0
2250 numprev = 0
2249 nump1 = 0
2251 nump1 = 0
2250 nump2 = 0
2252 nump2 = 0
2251 numother = 0
2253 numother = 0
2252 nump1prev = 0
2254 nump1prev = 0
2253 nump2prev = 0
2255 nump2prev = 0
2254 chainlengths = []
2256 chainlengths = []
2255
2257
2256 datasize = [None, 0, 0L]
2258 datasize = [None, 0, 0L]
2257 fullsize = [None, 0, 0L]
2259 fullsize = [None, 0, 0L]
2258 deltasize = [None, 0, 0L]
2260 deltasize = [None, 0, 0L]
2259
2261
2260 def addsize(size, l):
2262 def addsize(size, l):
2261 if l[0] is None or size < l[0]:
2263 if l[0] is None or size < l[0]:
2262 l[0] = size
2264 l[0] = size
2263 if size > l[1]:
2265 if size > l[1]:
2264 l[1] = size
2266 l[1] = size
2265 l[2] += size
2267 l[2] += size
2266
2268
2267 numrevs = len(r)
2269 numrevs = len(r)
2268 for rev in xrange(numrevs):
2270 for rev in xrange(numrevs):
2269 p1, p2 = r.parentrevs(rev)
2271 p1, p2 = r.parentrevs(rev)
2270 delta = r.deltaparent(rev)
2272 delta = r.deltaparent(rev)
2271 if format > 0:
2273 if format > 0:
2272 addsize(r.rawsize(rev), datasize)
2274 addsize(r.rawsize(rev), datasize)
2273 if p2 != nullrev:
2275 if p2 != nullrev:
2274 nummerges += 1
2276 nummerges += 1
2275 size = r.length(rev)
2277 size = r.length(rev)
2276 if delta == nullrev:
2278 if delta == nullrev:
2277 chainlengths.append(0)
2279 chainlengths.append(0)
2278 numfull += 1
2280 numfull += 1
2279 addsize(size, fullsize)
2281 addsize(size, fullsize)
2280 else:
2282 else:
2281 chainlengths.append(chainlengths[delta] + 1)
2283 chainlengths.append(chainlengths[delta] + 1)
2282 addsize(size, deltasize)
2284 addsize(size, deltasize)
2283 if delta == rev - 1:
2285 if delta == rev - 1:
2284 numprev += 1
2286 numprev += 1
2285 if delta == p1:
2287 if delta == p1:
2286 nump1prev += 1
2288 nump1prev += 1
2287 elif delta == p2:
2289 elif delta == p2:
2288 nump2prev += 1
2290 nump2prev += 1
2289 elif delta == p1:
2291 elif delta == p1:
2290 nump1 += 1
2292 nump1 += 1
2291 elif delta == p2:
2293 elif delta == p2:
2292 nump2 += 1
2294 nump2 += 1
2293 elif delta != nullrev:
2295 elif delta != nullrev:
2294 numother += 1
2296 numother += 1
2295
2297
2296 # Adjust size min value for empty cases
2298 # Adjust size min value for empty cases
2297 for size in (datasize, fullsize, deltasize):
2299 for size in (datasize, fullsize, deltasize):
2298 if size[0] is None:
2300 if size[0] is None:
2299 size[0] = 0
2301 size[0] = 0
2300
2302
2301 numdeltas = numrevs - numfull
2303 numdeltas = numrevs - numfull
2302 numoprev = numprev - nump1prev - nump2prev
2304 numoprev = numprev - nump1prev - nump2prev
2303 totalrawsize = datasize[2]
2305 totalrawsize = datasize[2]
2304 datasize[2] /= numrevs
2306 datasize[2] /= numrevs
2305 fulltotal = fullsize[2]
2307 fulltotal = fullsize[2]
2306 fullsize[2] /= numfull
2308 fullsize[2] /= numfull
2307 deltatotal = deltasize[2]
2309 deltatotal = deltasize[2]
2308 if numrevs - numfull > 0:
2310 if numrevs - numfull > 0:
2309 deltasize[2] /= numrevs - numfull
2311 deltasize[2] /= numrevs - numfull
2310 totalsize = fulltotal + deltatotal
2312 totalsize = fulltotal + deltatotal
2311 avgchainlen = sum(chainlengths) / numrevs
2313 avgchainlen = sum(chainlengths) / numrevs
2312 compratio = totalrawsize / totalsize
2314 compratio = totalrawsize / totalsize
2313
2315
2314 basedfmtstr = '%%%dd\n'
2316 basedfmtstr = '%%%dd\n'
2315 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2317 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2316
2318
2317 def dfmtstr(max):
2319 def dfmtstr(max):
2318 return basedfmtstr % len(str(max))
2320 return basedfmtstr % len(str(max))
2319 def pcfmtstr(max, padding=0):
2321 def pcfmtstr(max, padding=0):
2320 return basepcfmtstr % (len(str(max)), ' ' * padding)
2322 return basepcfmtstr % (len(str(max)), ' ' * padding)
2321
2323
2322 def pcfmt(value, total):
2324 def pcfmt(value, total):
2323 return (value, 100 * float(value) / total)
2325 return (value, 100 * float(value) / total)
2324
2326
2325 ui.write('format : %d\n' % format)
2327 ui.write('format : %d\n' % format)
2326 ui.write('flags : %s\n' % ', '.join(flags))
2328 ui.write('flags : %s\n' % ', '.join(flags))
2327
2329
2328 ui.write('\n')
2330 ui.write('\n')
2329 fmt = pcfmtstr(totalsize)
2331 fmt = pcfmtstr(totalsize)
2330 fmt2 = dfmtstr(totalsize)
2332 fmt2 = dfmtstr(totalsize)
2331 ui.write('revisions : ' + fmt2 % numrevs)
2333 ui.write('revisions : ' + fmt2 % numrevs)
2332 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2334 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2333 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2335 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2334 ui.write('revisions : ' + fmt2 % numrevs)
2336 ui.write('revisions : ' + fmt2 % numrevs)
2335 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2337 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2336 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2338 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2337 ui.write('revision size : ' + fmt2 % totalsize)
2339 ui.write('revision size : ' + fmt2 % totalsize)
2338 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2340 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2339 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2341 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2340
2342
2341 ui.write('\n')
2343 ui.write('\n')
2342 fmt = dfmtstr(max(avgchainlen, compratio))
2344 fmt = dfmtstr(max(avgchainlen, compratio))
2343 ui.write('avg chain length : ' + fmt % avgchainlen)
2345 ui.write('avg chain length : ' + fmt % avgchainlen)
2344 ui.write('compression ratio : ' + fmt % compratio)
2346 ui.write('compression ratio : ' + fmt % compratio)
2345
2347
2346 if format > 0:
2348 if format > 0:
2347 ui.write('\n')
2349 ui.write('\n')
2348 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2350 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2349 % tuple(datasize))
2351 % tuple(datasize))
2350 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2352 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2351 % tuple(fullsize))
2353 % tuple(fullsize))
2352 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2354 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2353 % tuple(deltasize))
2355 % tuple(deltasize))
2354
2356
2355 if numdeltas > 0:
2357 if numdeltas > 0:
2356 ui.write('\n')
2358 ui.write('\n')
2357 fmt = pcfmtstr(numdeltas)
2359 fmt = pcfmtstr(numdeltas)
2358 fmt2 = pcfmtstr(numdeltas, 4)
2360 fmt2 = pcfmtstr(numdeltas, 4)
2359 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2361 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2360 if numprev > 0:
2362 if numprev > 0:
2361 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2363 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2362 numprev))
2364 numprev))
2363 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2365 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2364 numprev))
2366 numprev))
2365 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2367 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2366 numprev))
2368 numprev))
2367 if gdelta:
2369 if gdelta:
2368 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2370 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2369 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2371 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2370 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2372 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2371 numdeltas))
2373 numdeltas))
2372
2374
2373 @command('debugrevspec', [], ('REVSPEC'))
2375 @command('debugrevspec', [], ('REVSPEC'))
2374 def debugrevspec(ui, repo, expr):
2376 def debugrevspec(ui, repo, expr):
2375 """parse and apply a revision specification
2377 """parse and apply a revision specification
2376
2378
2377 Use --verbose to print the parsed tree before and after aliases
2379 Use --verbose to print the parsed tree before and after aliases
2378 expansion.
2380 expansion.
2379 """
2381 """
2380 if ui.verbose:
2382 if ui.verbose:
2381 tree = revset.parse(expr)[0]
2383 tree = revset.parse(expr)[0]
2382 ui.note(revset.prettyformat(tree), "\n")
2384 ui.note(revset.prettyformat(tree), "\n")
2383 newtree = revset.findaliases(ui, tree)
2385 newtree = revset.findaliases(ui, tree)
2384 if newtree != tree:
2386 if newtree != tree:
2385 ui.note(revset.prettyformat(newtree), "\n")
2387 ui.note(revset.prettyformat(newtree), "\n")
2386 func = revset.match(ui, expr)
2388 func = revset.match(ui, expr)
2387 for c in func(repo, range(len(repo))):
2389 for c in func(repo, range(len(repo))):
2388 ui.write("%s\n" % c)
2390 ui.write("%s\n" % c)
2389
2391
2390 @command('debugsetparents', [], _('REV1 [REV2]'))
2392 @command('debugsetparents', [], _('REV1 [REV2]'))
2391 def debugsetparents(ui, repo, rev1, rev2=None):
2393 def debugsetparents(ui, repo, rev1, rev2=None):
2392 """manually set the parents of the current working directory
2394 """manually set the parents of the current working directory
2393
2395
2394 This is useful for writing repository conversion tools, but should
2396 This is useful for writing repository conversion tools, but should
2395 be used with care.
2397 be used with care.
2396
2398
2397 Returns 0 on success.
2399 Returns 0 on success.
2398 """
2400 """
2399
2401
2400 r1 = scmutil.revsingle(repo, rev1).node()
2402 r1 = scmutil.revsingle(repo, rev1).node()
2401 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2403 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2402
2404
2403 wlock = repo.wlock()
2405 wlock = repo.wlock()
2404 try:
2406 try:
2405 repo.setparents(r1, r2)
2407 repo.setparents(r1, r2)
2406 finally:
2408 finally:
2407 wlock.release()
2409 wlock.release()
2408
2410
2409 @command('debugstate',
2411 @command('debugstate',
2410 [('', 'nodates', None, _('do not display the saved mtime')),
2412 [('', 'nodates', None, _('do not display the saved mtime')),
2411 ('', 'datesort', None, _('sort by saved mtime'))],
2413 ('', 'datesort', None, _('sort by saved mtime'))],
2412 _('[OPTION]...'))
2414 _('[OPTION]...'))
2413 def debugstate(ui, repo, nodates=None, datesort=None):
2415 def debugstate(ui, repo, nodates=None, datesort=None):
2414 """show the contents of the current dirstate"""
2416 """show the contents of the current dirstate"""
2415 timestr = ""
2417 timestr = ""
2416 showdate = not nodates
2418 showdate = not nodates
2417 if datesort:
2419 if datesort:
2418 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2420 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2419 else:
2421 else:
2420 keyfunc = None # sort by filename
2422 keyfunc = None # sort by filename
2421 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2423 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2422 if showdate:
2424 if showdate:
2423 if ent[3] == -1:
2425 if ent[3] == -1:
2424 # Pad or slice to locale representation
2426 # Pad or slice to locale representation
2425 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2427 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2426 time.localtime(0)))
2428 time.localtime(0)))
2427 timestr = 'unset'
2429 timestr = 'unset'
2428 timestr = (timestr[:locale_len] +
2430 timestr = (timestr[:locale_len] +
2429 ' ' * (locale_len - len(timestr)))
2431 ' ' * (locale_len - len(timestr)))
2430 else:
2432 else:
2431 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2433 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2432 time.localtime(ent[3]))
2434 time.localtime(ent[3]))
2433 if ent[1] & 020000:
2435 if ent[1] & 020000:
2434 mode = 'lnk'
2436 mode = 'lnk'
2435 else:
2437 else:
2436 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2438 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2437 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2439 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2438 for f in repo.dirstate.copies():
2440 for f in repo.dirstate.copies():
2439 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2441 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2440
2442
2441 @command('debugsub',
2443 @command('debugsub',
2442 [('r', 'rev', '',
2444 [('r', 'rev', '',
2443 _('revision to check'), _('REV'))],
2445 _('revision to check'), _('REV'))],
2444 _('[-r REV] [REV]'))
2446 _('[-r REV] [REV]'))
2445 def debugsub(ui, repo, rev=None):
2447 def debugsub(ui, repo, rev=None):
2446 ctx = scmutil.revsingle(repo, rev, None)
2448 ctx = scmutil.revsingle(repo, rev, None)
2447 for k, v in sorted(ctx.substate.items()):
2449 for k, v in sorted(ctx.substate.items()):
2448 ui.write('path %s\n' % k)
2450 ui.write('path %s\n' % k)
2449 ui.write(' source %s\n' % v[0])
2451 ui.write(' source %s\n' % v[0])
2450 ui.write(' revision %s\n' % v[1])
2452 ui.write(' revision %s\n' % v[1])
2451
2453
2452 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2454 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2453 def debugwalk(ui, repo, *pats, **opts):
2455 def debugwalk(ui, repo, *pats, **opts):
2454 """show how files match on given patterns"""
2456 """show how files match on given patterns"""
2455 m = scmutil.match(repo[None], pats, opts)
2457 m = scmutil.match(repo[None], pats, opts)
2456 items = list(repo.walk(m))
2458 items = list(repo.walk(m))
2457 if not items:
2459 if not items:
2458 return
2460 return
2459 f = lambda fn: fn
2461 f = lambda fn: fn
2460 if ui.configbool('ui', 'slash') and os.sep != '/':
2462 if ui.configbool('ui', 'slash') and os.sep != '/':
2461 f = lambda fn: util.normpath(fn)
2463 f = lambda fn: util.normpath(fn)
2462 fmt = 'f %%-%ds %%-%ds %%s' % (
2464 fmt = 'f %%-%ds %%-%ds %%s' % (
2463 max([len(abs) for abs in items]),
2465 max([len(abs) for abs in items]),
2464 max([len(m.rel(abs)) for abs in items]))
2466 max([len(m.rel(abs)) for abs in items]))
2465 for abs in items:
2467 for abs in items:
2466 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2468 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2467 ui.write("%s\n" % line.rstrip())
2469 ui.write("%s\n" % line.rstrip())
2468
2470
2469 @command('debugwireargs',
2471 @command('debugwireargs',
2470 [('', 'three', '', 'three'),
2472 [('', 'three', '', 'three'),
2471 ('', 'four', '', 'four'),
2473 ('', 'four', '', 'four'),
2472 ('', 'five', '', 'five'),
2474 ('', 'five', '', 'five'),
2473 ] + remoteopts,
2475 ] + remoteopts,
2474 _('REPO [OPTIONS]... [ONE [TWO]]'))
2476 _('REPO [OPTIONS]... [ONE [TWO]]'))
2475 def debugwireargs(ui, repopath, *vals, **opts):
2477 def debugwireargs(ui, repopath, *vals, **opts):
2476 repo = hg.peer(ui, opts, repopath)
2478 repo = hg.peer(ui, opts, repopath)
2477 for opt in remoteopts:
2479 for opt in remoteopts:
2478 del opts[opt[1]]
2480 del opts[opt[1]]
2479 args = {}
2481 args = {}
2480 for k, v in opts.iteritems():
2482 for k, v in opts.iteritems():
2481 if v:
2483 if v:
2482 args[k] = v
2484 args[k] = v
2483 # run twice to check that we don't mess up the stream for the next command
2485 # run twice to check that we don't mess up the stream for the next command
2484 res1 = repo.debugwireargs(*vals, **args)
2486 res1 = repo.debugwireargs(*vals, **args)
2485 res2 = repo.debugwireargs(*vals, **args)
2487 res2 = repo.debugwireargs(*vals, **args)
2486 ui.write("%s\n" % res1)
2488 ui.write("%s\n" % res1)
2487 if res1 != res2:
2489 if res1 != res2:
2488 ui.warn("%s\n" % res2)
2490 ui.warn("%s\n" % res2)
2489
2491
2490 @command('^diff',
2492 @command('^diff',
2491 [('r', 'rev', [], _('revision'), _('REV')),
2493 [('r', 'rev', [], _('revision'), _('REV')),
2492 ('c', 'change', '', _('change made by revision'), _('REV'))
2494 ('c', 'change', '', _('change made by revision'), _('REV'))
2493 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2495 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2494 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2496 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2495 def diff(ui, repo, *pats, **opts):
2497 def diff(ui, repo, *pats, **opts):
2496 """diff repository (or selected files)
2498 """diff repository (or selected files)
2497
2499
2498 Show differences between revisions for the specified files.
2500 Show differences between revisions for the specified files.
2499
2501
2500 Differences between files are shown using the unified diff format.
2502 Differences between files are shown using the unified diff format.
2501
2503
2502 .. note::
2504 .. note::
2503 diff may generate unexpected results for merges, as it will
2505 diff may generate unexpected results for merges, as it will
2504 default to comparing against the working directory's first
2506 default to comparing against the working directory's first
2505 parent changeset if no revisions are specified.
2507 parent changeset if no revisions are specified.
2506
2508
2507 When two revision arguments are given, then changes are shown
2509 When two revision arguments are given, then changes are shown
2508 between those revisions. If only one revision is specified then
2510 between those revisions. If only one revision is specified then
2509 that revision is compared to the working directory, and, when no
2511 that revision is compared to the working directory, and, when no
2510 revisions are specified, the working directory files are compared
2512 revisions are specified, the working directory files are compared
2511 to its parent.
2513 to its parent.
2512
2514
2513 Alternatively you can specify -c/--change with a revision to see
2515 Alternatively you can specify -c/--change with a revision to see
2514 the changes in that changeset relative to its first parent.
2516 the changes in that changeset relative to its first parent.
2515
2517
2516 Without the -a/--text option, diff will avoid generating diffs of
2518 Without the -a/--text option, diff will avoid generating diffs of
2517 files it detects as binary. With -a, diff will generate a diff
2519 files it detects as binary. With -a, diff will generate a diff
2518 anyway, probably with undesirable results.
2520 anyway, probably with undesirable results.
2519
2521
2520 Use the -g/--git option to generate diffs in the git extended diff
2522 Use the -g/--git option to generate diffs in the git extended diff
2521 format. For more information, read :hg:`help diffs`.
2523 format. For more information, read :hg:`help diffs`.
2522
2524
2523 .. container:: verbose
2525 .. container:: verbose
2524
2526
2525 Examples:
2527 Examples:
2526
2528
2527 - compare a file in the current working directory to its parent::
2529 - compare a file in the current working directory to its parent::
2528
2530
2529 hg diff foo.c
2531 hg diff foo.c
2530
2532
2531 - compare two historical versions of a directory, with rename info::
2533 - compare two historical versions of a directory, with rename info::
2532
2534
2533 hg diff --git -r 1.0:1.2 lib/
2535 hg diff --git -r 1.0:1.2 lib/
2534
2536
2535 - get change stats relative to the last change on some date::
2537 - get change stats relative to the last change on some date::
2536
2538
2537 hg diff --stat -r "date('may 2')"
2539 hg diff --stat -r "date('may 2')"
2538
2540
2539 - diff all newly-added files that contain a keyword::
2541 - diff all newly-added files that contain a keyword::
2540
2542
2541 hg diff "set:added() and grep(GNU)"
2543 hg diff "set:added() and grep(GNU)"
2542
2544
2543 - compare a revision and its parents::
2545 - compare a revision and its parents::
2544
2546
2545 hg diff -c 9353 # compare against first parent
2547 hg diff -c 9353 # compare against first parent
2546 hg diff -r 9353^:9353 # same using revset syntax
2548 hg diff -r 9353^:9353 # same using revset syntax
2547 hg diff -r 9353^2:9353 # compare against the second parent
2549 hg diff -r 9353^2:9353 # compare against the second parent
2548
2550
2549 Returns 0 on success.
2551 Returns 0 on success.
2550 """
2552 """
2551
2553
2552 revs = opts.get('rev')
2554 revs = opts.get('rev')
2553 change = opts.get('change')
2555 change = opts.get('change')
2554 stat = opts.get('stat')
2556 stat = opts.get('stat')
2555 reverse = opts.get('reverse')
2557 reverse = opts.get('reverse')
2556
2558
2557 if revs and change:
2559 if revs and change:
2558 msg = _('cannot specify --rev and --change at the same time')
2560 msg = _('cannot specify --rev and --change at the same time')
2559 raise util.Abort(msg)
2561 raise util.Abort(msg)
2560 elif change:
2562 elif change:
2561 node2 = scmutil.revsingle(repo, change, None).node()
2563 node2 = scmutil.revsingle(repo, change, None).node()
2562 node1 = repo[node2].p1().node()
2564 node1 = repo[node2].p1().node()
2563 else:
2565 else:
2564 node1, node2 = scmutil.revpair(repo, revs)
2566 node1, node2 = scmutil.revpair(repo, revs)
2565
2567
2566 if reverse:
2568 if reverse:
2567 node1, node2 = node2, node1
2569 node1, node2 = node2, node1
2568
2570
2569 diffopts = patch.diffopts(ui, opts)
2571 diffopts = patch.diffopts(ui, opts)
2570 m = scmutil.match(repo[node2], pats, opts)
2572 m = scmutil.match(repo[node2], pats, opts)
2571 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2573 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2572 listsubrepos=opts.get('subrepos'))
2574 listsubrepos=opts.get('subrepos'))
2573
2575
2574 @command('^export',
2576 @command('^export',
2575 [('o', 'output', '',
2577 [('o', 'output', '',
2576 _('print output to file with formatted name'), _('FORMAT')),
2578 _('print output to file with formatted name'), _('FORMAT')),
2577 ('', 'switch-parent', None, _('diff against the second parent')),
2579 ('', 'switch-parent', None, _('diff against the second parent')),
2578 ('r', 'rev', [], _('revisions to export'), _('REV')),
2580 ('r', 'rev', [], _('revisions to export'), _('REV')),
2579 ] + diffopts,
2581 ] + diffopts,
2580 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2582 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2581 def export(ui, repo, *changesets, **opts):
2583 def export(ui, repo, *changesets, **opts):
2582 """dump the header and diffs for one or more changesets
2584 """dump the header and diffs for one or more changesets
2583
2585
2584 Print the changeset header and diffs for one or more revisions.
2586 Print the changeset header and diffs for one or more revisions.
2585
2587
2586 The information shown in the changeset header is: author, date,
2588 The information shown in the changeset header is: author, date,
2587 branch name (if non-default), changeset hash, parent(s) and commit
2589 branch name (if non-default), changeset hash, parent(s) and commit
2588 comment.
2590 comment.
2589
2591
2590 .. note::
2592 .. note::
2591 export may generate unexpected diff output for merge
2593 export may generate unexpected diff output for merge
2592 changesets, as it will compare the merge changeset against its
2594 changesets, as it will compare the merge changeset against its
2593 first parent only.
2595 first parent only.
2594
2596
2595 Output may be to a file, in which case the name of the file is
2597 Output may be to a file, in which case the name of the file is
2596 given using a format string. The formatting rules are as follows:
2598 given using a format string. The formatting rules are as follows:
2597
2599
2598 :``%%``: literal "%" character
2600 :``%%``: literal "%" character
2599 :``%H``: changeset hash (40 hexadecimal digits)
2601 :``%H``: changeset hash (40 hexadecimal digits)
2600 :``%N``: number of patches being generated
2602 :``%N``: number of patches being generated
2601 :``%R``: changeset revision number
2603 :``%R``: changeset revision number
2602 :``%b``: basename of the exporting repository
2604 :``%b``: basename of the exporting repository
2603 :``%h``: short-form changeset hash (12 hexadecimal digits)
2605 :``%h``: short-form changeset hash (12 hexadecimal digits)
2604 :``%m``: first line of the commit message (only alphanumeric characters)
2606 :``%m``: first line of the commit message (only alphanumeric characters)
2605 :``%n``: zero-padded sequence number, starting at 1
2607 :``%n``: zero-padded sequence number, starting at 1
2606 :``%r``: zero-padded changeset revision number
2608 :``%r``: zero-padded changeset revision number
2607
2609
2608 Without the -a/--text option, export will avoid generating diffs
2610 Without the -a/--text option, export will avoid generating diffs
2609 of files it detects as binary. With -a, export will generate a
2611 of files it detects as binary. With -a, export will generate a
2610 diff anyway, probably with undesirable results.
2612 diff anyway, probably with undesirable results.
2611
2613
2612 Use the -g/--git option to generate diffs in the git extended diff
2614 Use the -g/--git option to generate diffs in the git extended diff
2613 format. See :hg:`help diffs` for more information.
2615 format. See :hg:`help diffs` for more information.
2614
2616
2615 With the --switch-parent option, the diff will be against the
2617 With the --switch-parent option, the diff will be against the
2616 second parent. It can be useful to review a merge.
2618 second parent. It can be useful to review a merge.
2617
2619
2618 .. container:: verbose
2620 .. container:: verbose
2619
2621
2620 Examples:
2622 Examples:
2621
2623
2622 - use export and import to transplant a bugfix to the current
2624 - use export and import to transplant a bugfix to the current
2623 branch::
2625 branch::
2624
2626
2625 hg export -r 9353 | hg import -
2627 hg export -r 9353 | hg import -
2626
2628
2627 - export all the changesets between two revisions to a file with
2629 - export all the changesets between two revisions to a file with
2628 rename information::
2630 rename information::
2629
2631
2630 hg export --git -r 123:150 > changes.txt
2632 hg export --git -r 123:150 > changes.txt
2631
2633
2632 - split outgoing changes into a series of patches with
2634 - split outgoing changes into a series of patches with
2633 descriptive names::
2635 descriptive names::
2634
2636
2635 hg export -r "outgoing()" -o "%n-%m.patch"
2637 hg export -r "outgoing()" -o "%n-%m.patch"
2636
2638
2637 Returns 0 on success.
2639 Returns 0 on success.
2638 """
2640 """
2639 changesets += tuple(opts.get('rev', []))
2641 changesets += tuple(opts.get('rev', []))
2640 revs = scmutil.revrange(repo, changesets)
2642 revs = scmutil.revrange(repo, changesets)
2641 if not revs:
2643 if not revs:
2642 raise util.Abort(_("export requires at least one changeset"))
2644 raise util.Abort(_("export requires at least one changeset"))
2643 if len(revs) > 1:
2645 if len(revs) > 1:
2644 ui.note(_('exporting patches:\n'))
2646 ui.note(_('exporting patches:\n'))
2645 else:
2647 else:
2646 ui.note(_('exporting patch:\n'))
2648 ui.note(_('exporting patch:\n'))
2647 cmdutil.export(repo, revs, template=opts.get('output'),
2649 cmdutil.export(repo, revs, template=opts.get('output'),
2648 switch_parent=opts.get('switch_parent'),
2650 switch_parent=opts.get('switch_parent'),
2649 opts=patch.diffopts(ui, opts))
2651 opts=patch.diffopts(ui, opts))
2650
2652
2651 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2653 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2652 def forget(ui, repo, *pats, **opts):
2654 def forget(ui, repo, *pats, **opts):
2653 """forget the specified files on the next commit
2655 """forget the specified files on the next commit
2654
2656
2655 Mark the specified files so they will no longer be tracked
2657 Mark the specified files so they will no longer be tracked
2656 after the next commit.
2658 after the next commit.
2657
2659
2658 This only removes files from the current branch, not from the
2660 This only removes files from the current branch, not from the
2659 entire project history, and it does not delete them from the
2661 entire project history, and it does not delete them from the
2660 working directory.
2662 working directory.
2661
2663
2662 To undo a forget before the next commit, see :hg:`add`.
2664 To undo a forget before the next commit, see :hg:`add`.
2663
2665
2664 .. container:: verbose
2666 .. container:: verbose
2665
2667
2666 Examples:
2668 Examples:
2667
2669
2668 - forget newly-added binary files::
2670 - forget newly-added binary files::
2669
2671
2670 hg forget "set:added() and binary()"
2672 hg forget "set:added() and binary()"
2671
2673
2672 - forget files that would be excluded by .hgignore::
2674 - forget files that would be excluded by .hgignore::
2673
2675
2674 hg forget "set:hgignore()"
2676 hg forget "set:hgignore()"
2675
2677
2676 Returns 0 on success.
2678 Returns 0 on success.
2677 """
2679 """
2678
2680
2679 if not pats:
2681 if not pats:
2680 raise util.Abort(_('no files specified'))
2682 raise util.Abort(_('no files specified'))
2681
2683
2682 m = scmutil.match(repo[None], pats, opts)
2684 m = scmutil.match(repo[None], pats, opts)
2683 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2685 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2684 return rejected and 1 or 0
2686 return rejected and 1 or 0
2685
2687
2686 @command(
2688 @command(
2687 'graft',
2689 'graft',
2688 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2690 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2689 ('c', 'continue', False, _('resume interrupted graft')),
2691 ('c', 'continue', False, _('resume interrupted graft')),
2690 ('e', 'edit', False, _('invoke editor on commit messages')),
2692 ('e', 'edit', False, _('invoke editor on commit messages')),
2691 ('', 'log', None, _('append graft info to log message')),
2693 ('', 'log', None, _('append graft info to log message')),
2692 ('D', 'currentdate', False,
2694 ('D', 'currentdate', False,
2693 _('record the current date as commit date')),
2695 _('record the current date as commit date')),
2694 ('U', 'currentuser', False,
2696 ('U', 'currentuser', False,
2695 _('record the current user as committer'), _('DATE'))]
2697 _('record the current user as committer'), _('DATE'))]
2696 + commitopts2 + mergetoolopts + dryrunopts,
2698 + commitopts2 + mergetoolopts + dryrunopts,
2697 _('[OPTION]... [-r] REV...'))
2699 _('[OPTION]... [-r] REV...'))
2698 def graft(ui, repo, *revs, **opts):
2700 def graft(ui, repo, *revs, **opts):
2699 '''copy changes from other branches onto the current branch
2701 '''copy changes from other branches onto the current branch
2700
2702
2701 This command uses Mercurial's merge logic to copy individual
2703 This command uses Mercurial's merge logic to copy individual
2702 changes from other branches without merging branches in the
2704 changes from other branches without merging branches in the
2703 history graph. This is sometimes known as 'backporting' or
2705 history graph. This is sometimes known as 'backporting' or
2704 'cherry-picking'. By default, graft will copy user, date, and
2706 'cherry-picking'. By default, graft will copy user, date, and
2705 description from the source changesets.
2707 description from the source changesets.
2706
2708
2707 Changesets that are ancestors of the current revision, that have
2709 Changesets that are ancestors of the current revision, that have
2708 already been grafted, or that are merges will be skipped.
2710 already been grafted, or that are merges will be skipped.
2709
2711
2710 If --log is specified, log messages will have a comment appended
2712 If --log is specified, log messages will have a comment appended
2711 of the form::
2713 of the form::
2712
2714
2713 (grafted from CHANGESETHASH)
2715 (grafted from CHANGESETHASH)
2714
2716
2715 If a graft merge results in conflicts, the graft process is
2717 If a graft merge results in conflicts, the graft process is
2716 interrupted so that the current merge can be manually resolved.
2718 interrupted so that the current merge can be manually resolved.
2717 Once all conflicts are addressed, the graft process can be
2719 Once all conflicts are addressed, the graft process can be
2718 continued with the -c/--continue option.
2720 continued with the -c/--continue option.
2719
2721
2720 .. note::
2722 .. note::
2721 The -c/--continue option does not reapply earlier options.
2723 The -c/--continue option does not reapply earlier options.
2722
2724
2723 .. container:: verbose
2725 .. container:: verbose
2724
2726
2725 Examples:
2727 Examples:
2726
2728
2727 - copy a single change to the stable branch and edit its description::
2729 - copy a single change to the stable branch and edit its description::
2728
2730
2729 hg update stable
2731 hg update stable
2730 hg graft --edit 9393
2732 hg graft --edit 9393
2731
2733
2732 - graft a range of changesets with one exception, updating dates::
2734 - graft a range of changesets with one exception, updating dates::
2733
2735
2734 hg graft -D "2085::2093 and not 2091"
2736 hg graft -D "2085::2093 and not 2091"
2735
2737
2736 - continue a graft after resolving conflicts::
2738 - continue a graft after resolving conflicts::
2737
2739
2738 hg graft -c
2740 hg graft -c
2739
2741
2740 - show the source of a grafted changeset::
2742 - show the source of a grafted changeset::
2741
2743
2742 hg log --debug -r tip
2744 hg log --debug -r tip
2743
2745
2744 Returns 0 on successful completion.
2746 Returns 0 on successful completion.
2745 '''
2747 '''
2746
2748
2747 revs = list(revs)
2749 revs = list(revs)
2748 revs.extend(opts['rev'])
2750 revs.extend(opts['rev'])
2749
2751
2750 if not opts.get('user') and opts.get('currentuser'):
2752 if not opts.get('user') and opts.get('currentuser'):
2751 opts['user'] = ui.username()
2753 opts['user'] = ui.username()
2752 if not opts.get('date') and opts.get('currentdate'):
2754 if not opts.get('date') and opts.get('currentdate'):
2753 opts['date'] = "%d %d" % util.makedate()
2755 opts['date'] = "%d %d" % util.makedate()
2754
2756
2755 editor = None
2757 editor = None
2756 if opts.get('edit'):
2758 if opts.get('edit'):
2757 editor = cmdutil.commitforceeditor
2759 editor = cmdutil.commitforceeditor
2758
2760
2759 cont = False
2761 cont = False
2760 if opts['continue']:
2762 if opts['continue']:
2761 cont = True
2763 cont = True
2762 if revs:
2764 if revs:
2763 raise util.Abort(_("can't specify --continue and revisions"))
2765 raise util.Abort(_("can't specify --continue and revisions"))
2764 # read in unfinished revisions
2766 # read in unfinished revisions
2765 try:
2767 try:
2766 nodes = repo.opener.read('graftstate').splitlines()
2768 nodes = repo.opener.read('graftstate').splitlines()
2767 revs = [repo[node].rev() for node in nodes]
2769 revs = [repo[node].rev() for node in nodes]
2768 except IOError, inst:
2770 except IOError, inst:
2769 if inst.errno != errno.ENOENT:
2771 if inst.errno != errno.ENOENT:
2770 raise
2772 raise
2771 raise util.Abort(_("no graft state found, can't continue"))
2773 raise util.Abort(_("no graft state found, can't continue"))
2772 else:
2774 else:
2773 cmdutil.bailifchanged(repo)
2775 cmdutil.bailifchanged(repo)
2774 if not revs:
2776 if not revs:
2775 raise util.Abort(_('no revisions specified'))
2777 raise util.Abort(_('no revisions specified'))
2776 revs = scmutil.revrange(repo, revs)
2778 revs = scmutil.revrange(repo, revs)
2777
2779
2778 # check for merges
2780 # check for merges
2779 for rev in repo.revs('%ld and merge()', revs):
2781 for rev in repo.revs('%ld and merge()', revs):
2780 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2782 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2781 revs.remove(rev)
2783 revs.remove(rev)
2782 if not revs:
2784 if not revs:
2783 return -1
2785 return -1
2784
2786
2785 # check for ancestors of dest branch
2787 # check for ancestors of dest branch
2786 for rev in repo.revs('::. and %ld', revs):
2788 for rev in repo.revs('::. and %ld', revs):
2787 ui.warn(_('skipping ancestor revision %s\n') % rev)
2789 ui.warn(_('skipping ancestor revision %s\n') % rev)
2788 revs.remove(rev)
2790 revs.remove(rev)
2789 if not revs:
2791 if not revs:
2790 return -1
2792 return -1
2791
2793
2792 # analyze revs for earlier grafts
2794 # analyze revs for earlier grafts
2793 ids = {}
2795 ids = {}
2794 for ctx in repo.set("%ld", revs):
2796 for ctx in repo.set("%ld", revs):
2795 ids[ctx.hex()] = ctx.rev()
2797 ids[ctx.hex()] = ctx.rev()
2796 n = ctx.extra().get('source')
2798 n = ctx.extra().get('source')
2797 if n:
2799 if n:
2798 ids[n] = ctx.rev()
2800 ids[n] = ctx.rev()
2799
2801
2800 # check ancestors for earlier grafts
2802 # check ancestors for earlier grafts
2801 ui.debug('scanning for duplicate grafts\n')
2803 ui.debug('scanning for duplicate grafts\n')
2802 for ctx in repo.set("::. - ::%ld", revs):
2804 for ctx in repo.set("::. - ::%ld", revs):
2803 n = ctx.extra().get('source')
2805 n = ctx.extra().get('source')
2804 if n in ids:
2806 if n in ids:
2805 r = repo[n].rev()
2807 r = repo[n].rev()
2806 if r in revs:
2808 if r in revs:
2807 ui.warn(_('skipping already grafted revision %s\n') % r)
2809 ui.warn(_('skipping already grafted revision %s\n') % r)
2808 revs.remove(r)
2810 revs.remove(r)
2809 elif ids[n] in revs:
2811 elif ids[n] in revs:
2810 ui.warn(_('skipping already grafted revision %s '
2812 ui.warn(_('skipping already grafted revision %s '
2811 '(same origin %d)\n') % (ids[n], r))
2813 '(same origin %d)\n') % (ids[n], r))
2812 revs.remove(ids[n])
2814 revs.remove(ids[n])
2813 elif ctx.hex() in ids:
2815 elif ctx.hex() in ids:
2814 r = ids[ctx.hex()]
2816 r = ids[ctx.hex()]
2815 ui.warn(_('skipping already grafted revision %s '
2817 ui.warn(_('skipping already grafted revision %s '
2816 '(was grafted from %d)\n') % (r, ctx.rev()))
2818 '(was grafted from %d)\n') % (r, ctx.rev()))
2817 revs.remove(r)
2819 revs.remove(r)
2818 if not revs:
2820 if not revs:
2819 return -1
2821 return -1
2820
2822
2821 wlock = repo.wlock()
2823 wlock = repo.wlock()
2822 try:
2824 try:
2823 for pos, ctx in enumerate(repo.set("%ld", revs)):
2825 for pos, ctx in enumerate(repo.set("%ld", revs)):
2824 current = repo['.']
2826 current = repo['.']
2825
2827
2826 ui.status(_('grafting revision %s\n') % ctx.rev())
2828 ui.status(_('grafting revision %s\n') % ctx.rev())
2827 if opts.get('dry_run'):
2829 if opts.get('dry_run'):
2828 continue
2830 continue
2829
2831
2830 # we don't merge the first commit when continuing
2832 # we don't merge the first commit when continuing
2831 if not cont:
2833 if not cont:
2832 # perform the graft merge with p1(rev) as 'ancestor'
2834 # perform the graft merge with p1(rev) as 'ancestor'
2833 try:
2835 try:
2834 # ui.forcemerge is an internal variable, do not document
2836 # ui.forcemerge is an internal variable, do not document
2835 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2837 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2836 stats = mergemod.update(repo, ctx.node(), True, True, False,
2838 stats = mergemod.update(repo, ctx.node(), True, True, False,
2837 ctx.p1().node())
2839 ctx.p1().node())
2838 finally:
2840 finally:
2839 repo.ui.setconfig('ui', 'forcemerge', '')
2841 repo.ui.setconfig('ui', 'forcemerge', '')
2840 # report any conflicts
2842 # report any conflicts
2841 if stats and stats[3] > 0:
2843 if stats and stats[3] > 0:
2842 # write out state for --continue
2844 # write out state for --continue
2843 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2845 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2844 repo.opener.write('graftstate', ''.join(nodelines))
2846 repo.opener.write('graftstate', ''.join(nodelines))
2845 raise util.Abort(
2847 raise util.Abort(
2846 _("unresolved conflicts, can't continue"),
2848 _("unresolved conflicts, can't continue"),
2847 hint=_('use hg resolve and hg graft --continue'))
2849 hint=_('use hg resolve and hg graft --continue'))
2848 else:
2850 else:
2849 cont = False
2851 cont = False
2850
2852
2851 # drop the second merge parent
2853 # drop the second merge parent
2852 repo.setparents(current.node(), nullid)
2854 repo.setparents(current.node(), nullid)
2853 repo.dirstate.write()
2855 repo.dirstate.write()
2854 # fix up dirstate for copies and renames
2856 # fix up dirstate for copies and renames
2855 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2857 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2856
2858
2857 # commit
2859 # commit
2858 source = ctx.extra().get('source')
2860 source = ctx.extra().get('source')
2859 if not source:
2861 if not source:
2860 source = ctx.hex()
2862 source = ctx.hex()
2861 extra = {'source': source}
2863 extra = {'source': source}
2862 user = ctx.user()
2864 user = ctx.user()
2863 if opts.get('user'):
2865 if opts.get('user'):
2864 user = opts['user']
2866 user = opts['user']
2865 date = ctx.date()
2867 date = ctx.date()
2866 if opts.get('date'):
2868 if opts.get('date'):
2867 date = opts['date']
2869 date = opts['date']
2868 message = ctx.description()
2870 message = ctx.description()
2869 if opts.get('log'):
2871 if opts.get('log'):
2870 message += '\n(grafted from %s)' % ctx.hex()
2872 message += '\n(grafted from %s)' % ctx.hex()
2871 node = repo.commit(text=message, user=user,
2873 node = repo.commit(text=message, user=user,
2872 date=date, extra=extra, editor=editor)
2874 date=date, extra=extra, editor=editor)
2873 if node is None:
2875 if node is None:
2874 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2876 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2875 finally:
2877 finally:
2876 wlock.release()
2878 wlock.release()
2877
2879
2878 # remove state when we complete successfully
2880 # remove state when we complete successfully
2879 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2881 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2880 util.unlinkpath(repo.join('graftstate'))
2882 util.unlinkpath(repo.join('graftstate'))
2881
2883
2882 return 0
2884 return 0
2883
2885
2884 @command('grep',
2886 @command('grep',
2885 [('0', 'print0', None, _('end fields with NUL')),
2887 [('0', 'print0', None, _('end fields with NUL')),
2886 ('', 'all', None, _('print all revisions that match')),
2888 ('', 'all', None, _('print all revisions that match')),
2887 ('a', 'text', None, _('treat all files as text')),
2889 ('a', 'text', None, _('treat all files as text')),
2888 ('f', 'follow', None,
2890 ('f', 'follow', None,
2889 _('follow changeset history,'
2891 _('follow changeset history,'
2890 ' or file history across copies and renames')),
2892 ' or file history across copies and renames')),
2891 ('i', 'ignore-case', None, _('ignore case when matching')),
2893 ('i', 'ignore-case', None, _('ignore case when matching')),
2892 ('l', 'files-with-matches', None,
2894 ('l', 'files-with-matches', None,
2893 _('print only filenames and revisions that match')),
2895 _('print only filenames and revisions that match')),
2894 ('n', 'line-number', None, _('print matching line numbers')),
2896 ('n', 'line-number', None, _('print matching line numbers')),
2895 ('r', 'rev', [],
2897 ('r', 'rev', [],
2896 _('only search files changed within revision range'), _('REV')),
2898 _('only search files changed within revision range'), _('REV')),
2897 ('u', 'user', None, _('list the author (long with -v)')),
2899 ('u', 'user', None, _('list the author (long with -v)')),
2898 ('d', 'date', None, _('list the date (short with -q)')),
2900 ('d', 'date', None, _('list the date (short with -q)')),
2899 ] + walkopts,
2901 ] + walkopts,
2900 _('[OPTION]... PATTERN [FILE]...'))
2902 _('[OPTION]... PATTERN [FILE]...'))
2901 def grep(ui, repo, pattern, *pats, **opts):
2903 def grep(ui, repo, pattern, *pats, **opts):
2902 """search for a pattern in specified files and revisions
2904 """search for a pattern in specified files and revisions
2903
2905
2904 Search revisions of files for a regular expression.
2906 Search revisions of files for a regular expression.
2905
2907
2906 This command behaves differently than Unix grep. It only accepts
2908 This command behaves differently than Unix grep. It only accepts
2907 Python/Perl regexps. It searches repository history, not the
2909 Python/Perl regexps. It searches repository history, not the
2908 working directory. It always prints the revision number in which a
2910 working directory. It always prints the revision number in which a
2909 match appears.
2911 match appears.
2910
2912
2911 By default, grep only prints output for the first revision of a
2913 By default, grep only prints output for the first revision of a
2912 file in which it finds a match. To get it to print every revision
2914 file in which it finds a match. To get it to print every revision
2913 that contains a change in match status ("-" for a match that
2915 that contains a change in match status ("-" for a match that
2914 becomes a non-match, or "+" for a non-match that becomes a match),
2916 becomes a non-match, or "+" for a non-match that becomes a match),
2915 use the --all flag.
2917 use the --all flag.
2916
2918
2917 Returns 0 if a match is found, 1 otherwise.
2919 Returns 0 if a match is found, 1 otherwise.
2918 """
2920 """
2919 reflags = re.M
2921 reflags = re.M
2920 if opts.get('ignore_case'):
2922 if opts.get('ignore_case'):
2921 reflags |= re.I
2923 reflags |= re.I
2922 try:
2924 try:
2923 regexp = re.compile(pattern, reflags)
2925 regexp = re.compile(pattern, reflags)
2924 except re.error, inst:
2926 except re.error, inst:
2925 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2927 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2926 return 1
2928 return 1
2927 sep, eol = ':', '\n'
2929 sep, eol = ':', '\n'
2928 if opts.get('print0'):
2930 if opts.get('print0'):
2929 sep = eol = '\0'
2931 sep = eol = '\0'
2930
2932
2931 getfile = util.lrucachefunc(repo.file)
2933 getfile = util.lrucachefunc(repo.file)
2932
2934
2933 def matchlines(body):
2935 def matchlines(body):
2934 begin = 0
2936 begin = 0
2935 linenum = 0
2937 linenum = 0
2936 while True:
2938 while True:
2937 match = regexp.search(body, begin)
2939 match = regexp.search(body, begin)
2938 if not match:
2940 if not match:
2939 break
2941 break
2940 mstart, mend = match.span()
2942 mstart, mend = match.span()
2941 linenum += body.count('\n', begin, mstart) + 1
2943 linenum += body.count('\n', begin, mstart) + 1
2942 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2944 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2943 begin = body.find('\n', mend) + 1 or len(body) + 1
2945 begin = body.find('\n', mend) + 1 or len(body) + 1
2944 lend = begin - 1
2946 lend = begin - 1
2945 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2947 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2946
2948
2947 class linestate(object):
2949 class linestate(object):
2948 def __init__(self, line, linenum, colstart, colend):
2950 def __init__(self, line, linenum, colstart, colend):
2949 self.line = line
2951 self.line = line
2950 self.linenum = linenum
2952 self.linenum = linenum
2951 self.colstart = colstart
2953 self.colstart = colstart
2952 self.colend = colend
2954 self.colend = colend
2953
2955
2954 def __hash__(self):
2956 def __hash__(self):
2955 return hash((self.linenum, self.line))
2957 return hash((self.linenum, self.line))
2956
2958
2957 def __eq__(self, other):
2959 def __eq__(self, other):
2958 return self.line == other.line
2960 return self.line == other.line
2959
2961
2960 matches = {}
2962 matches = {}
2961 copies = {}
2963 copies = {}
2962 def grepbody(fn, rev, body):
2964 def grepbody(fn, rev, body):
2963 matches[rev].setdefault(fn, [])
2965 matches[rev].setdefault(fn, [])
2964 m = matches[rev][fn]
2966 m = matches[rev][fn]
2965 for lnum, cstart, cend, line in matchlines(body):
2967 for lnum, cstart, cend, line in matchlines(body):
2966 s = linestate(line, lnum, cstart, cend)
2968 s = linestate(line, lnum, cstart, cend)
2967 m.append(s)
2969 m.append(s)
2968
2970
2969 def difflinestates(a, b):
2971 def difflinestates(a, b):
2970 sm = difflib.SequenceMatcher(None, a, b)
2972 sm = difflib.SequenceMatcher(None, a, b)
2971 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2973 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2972 if tag == 'insert':
2974 if tag == 'insert':
2973 for i in xrange(blo, bhi):
2975 for i in xrange(blo, bhi):
2974 yield ('+', b[i])
2976 yield ('+', b[i])
2975 elif tag == 'delete':
2977 elif tag == 'delete':
2976 for i in xrange(alo, ahi):
2978 for i in xrange(alo, ahi):
2977 yield ('-', a[i])
2979 yield ('-', a[i])
2978 elif tag == 'replace':
2980 elif tag == 'replace':
2979 for i in xrange(alo, ahi):
2981 for i in xrange(alo, ahi):
2980 yield ('-', a[i])
2982 yield ('-', a[i])
2981 for i in xrange(blo, bhi):
2983 for i in xrange(blo, bhi):
2982 yield ('+', b[i])
2984 yield ('+', b[i])
2983
2985
2984 def display(fn, ctx, pstates, states):
2986 def display(fn, ctx, pstates, states):
2985 rev = ctx.rev()
2987 rev = ctx.rev()
2986 datefunc = ui.quiet and util.shortdate or util.datestr
2988 datefunc = ui.quiet and util.shortdate or util.datestr
2987 found = False
2989 found = False
2988 filerevmatches = {}
2990 filerevmatches = {}
2989 def binary():
2991 def binary():
2990 flog = getfile(fn)
2992 flog = getfile(fn)
2991 return util.binary(flog.read(ctx.filenode(fn)))
2993 return util.binary(flog.read(ctx.filenode(fn)))
2992
2994
2993 if opts.get('all'):
2995 if opts.get('all'):
2994 iter = difflinestates(pstates, states)
2996 iter = difflinestates(pstates, states)
2995 else:
2997 else:
2996 iter = [('', l) for l in states]
2998 iter = [('', l) for l in states]
2997 for change, l in iter:
2999 for change, l in iter:
2998 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3000 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
2999 before, match, after = None, None, None
3001 before, match, after = None, None, None
3000
3002
3001 if opts.get('line_number'):
3003 if opts.get('line_number'):
3002 cols.append((str(l.linenum), 'grep.linenumber'))
3004 cols.append((str(l.linenum), 'grep.linenumber'))
3003 if opts.get('all'):
3005 if opts.get('all'):
3004 cols.append((change, 'grep.change'))
3006 cols.append((change, 'grep.change'))
3005 if opts.get('user'):
3007 if opts.get('user'):
3006 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3008 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3007 if opts.get('date'):
3009 if opts.get('date'):
3008 cols.append((datefunc(ctx.date()), 'grep.date'))
3010 cols.append((datefunc(ctx.date()), 'grep.date'))
3009 if opts.get('files_with_matches'):
3011 if opts.get('files_with_matches'):
3010 c = (fn, rev)
3012 c = (fn, rev)
3011 if c in filerevmatches:
3013 if c in filerevmatches:
3012 continue
3014 continue
3013 filerevmatches[c] = 1
3015 filerevmatches[c] = 1
3014 else:
3016 else:
3015 before = l.line[:l.colstart]
3017 before = l.line[:l.colstart]
3016 match = l.line[l.colstart:l.colend]
3018 match = l.line[l.colstart:l.colend]
3017 after = l.line[l.colend:]
3019 after = l.line[l.colend:]
3018 for col, label in cols[:-1]:
3020 for col, label in cols[:-1]:
3019 ui.write(col, label=label)
3021 ui.write(col, label=label)
3020 ui.write(sep, label='grep.sep')
3022 ui.write(sep, label='grep.sep')
3021 ui.write(cols[-1][0], label=cols[-1][1])
3023 ui.write(cols[-1][0], label=cols[-1][1])
3022 if before is not None:
3024 if before is not None:
3023 ui.write(sep, label='grep.sep')
3025 ui.write(sep, label='grep.sep')
3024 if not opts.get('text') and binary():
3026 if not opts.get('text') and binary():
3025 ui.write(" Binary file matches")
3027 ui.write(" Binary file matches")
3026 else:
3028 else:
3027 ui.write(before)
3029 ui.write(before)
3028 ui.write(match, label='grep.match')
3030 ui.write(match, label='grep.match')
3029 ui.write(after)
3031 ui.write(after)
3030 ui.write(eol)
3032 ui.write(eol)
3031 found = True
3033 found = True
3032 return found
3034 return found
3033
3035
3034 skip = {}
3036 skip = {}
3035 revfiles = {}
3037 revfiles = {}
3036 matchfn = scmutil.match(repo[None], pats, opts)
3038 matchfn = scmutil.match(repo[None], pats, opts)
3037 found = False
3039 found = False
3038 follow = opts.get('follow')
3040 follow = opts.get('follow')
3039
3041
3040 def prep(ctx, fns):
3042 def prep(ctx, fns):
3041 rev = ctx.rev()
3043 rev = ctx.rev()
3042 pctx = ctx.p1()
3044 pctx = ctx.p1()
3043 parent = pctx.rev()
3045 parent = pctx.rev()
3044 matches.setdefault(rev, {})
3046 matches.setdefault(rev, {})
3045 matches.setdefault(parent, {})
3047 matches.setdefault(parent, {})
3046 files = revfiles.setdefault(rev, [])
3048 files = revfiles.setdefault(rev, [])
3047 for fn in fns:
3049 for fn in fns:
3048 flog = getfile(fn)
3050 flog = getfile(fn)
3049 try:
3051 try:
3050 fnode = ctx.filenode(fn)
3052 fnode = ctx.filenode(fn)
3051 except error.LookupError:
3053 except error.LookupError:
3052 continue
3054 continue
3053
3055
3054 copied = flog.renamed(fnode)
3056 copied = flog.renamed(fnode)
3055 copy = follow and copied and copied[0]
3057 copy = follow and copied and copied[0]
3056 if copy:
3058 if copy:
3057 copies.setdefault(rev, {})[fn] = copy
3059 copies.setdefault(rev, {})[fn] = copy
3058 if fn in skip:
3060 if fn in skip:
3059 if copy:
3061 if copy:
3060 skip[copy] = True
3062 skip[copy] = True
3061 continue
3063 continue
3062 files.append(fn)
3064 files.append(fn)
3063
3065
3064 if fn not in matches[rev]:
3066 if fn not in matches[rev]:
3065 grepbody(fn, rev, flog.read(fnode))
3067 grepbody(fn, rev, flog.read(fnode))
3066
3068
3067 pfn = copy or fn
3069 pfn = copy or fn
3068 if pfn not in matches[parent]:
3070 if pfn not in matches[parent]:
3069 try:
3071 try:
3070 fnode = pctx.filenode(pfn)
3072 fnode = pctx.filenode(pfn)
3071 grepbody(pfn, parent, flog.read(fnode))
3073 grepbody(pfn, parent, flog.read(fnode))
3072 except error.LookupError:
3074 except error.LookupError:
3073 pass
3075 pass
3074
3076
3075 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3077 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3076 rev = ctx.rev()
3078 rev = ctx.rev()
3077 parent = ctx.p1().rev()
3079 parent = ctx.p1().rev()
3078 for fn in sorted(revfiles.get(rev, [])):
3080 for fn in sorted(revfiles.get(rev, [])):
3079 states = matches[rev][fn]
3081 states = matches[rev][fn]
3080 copy = copies.get(rev, {}).get(fn)
3082 copy = copies.get(rev, {}).get(fn)
3081 if fn in skip:
3083 if fn in skip:
3082 if copy:
3084 if copy:
3083 skip[copy] = True
3085 skip[copy] = True
3084 continue
3086 continue
3085 pstates = matches.get(parent, {}).get(copy or fn, [])
3087 pstates = matches.get(parent, {}).get(copy or fn, [])
3086 if pstates or states:
3088 if pstates or states:
3087 r = display(fn, ctx, pstates, states)
3089 r = display(fn, ctx, pstates, states)
3088 found = found or r
3090 found = found or r
3089 if r and not opts.get('all'):
3091 if r and not opts.get('all'):
3090 skip[fn] = True
3092 skip[fn] = True
3091 if copy:
3093 if copy:
3092 skip[copy] = True
3094 skip[copy] = True
3093 del matches[rev]
3095 del matches[rev]
3094 del revfiles[rev]
3096 del revfiles[rev]
3095
3097
3096 return not found
3098 return not found
3097
3099
3098 @command('heads',
3100 @command('heads',
3099 [('r', 'rev', '',
3101 [('r', 'rev', '',
3100 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3102 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3101 ('t', 'topo', False, _('show topological heads only')),
3103 ('t', 'topo', False, _('show topological heads only')),
3102 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3104 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3103 ('c', 'closed', False, _('show normal and closed branch heads')),
3105 ('c', 'closed', False, _('show normal and closed branch heads')),
3104 ] + templateopts,
3106 ] + templateopts,
3105 _('[-ct] [-r STARTREV] [REV]...'))
3107 _('[-ct] [-r STARTREV] [REV]...'))
3106 def heads(ui, repo, *branchrevs, **opts):
3108 def heads(ui, repo, *branchrevs, **opts):
3107 """show current repository heads or show branch heads
3109 """show current repository heads or show branch heads
3108
3110
3109 With no arguments, show all repository branch heads.
3111 With no arguments, show all repository branch heads.
3110
3112
3111 Repository "heads" are changesets with no child changesets. They are
3113 Repository "heads" are changesets with no child changesets. They are
3112 where development generally takes place and are the usual targets
3114 where development generally takes place and are the usual targets
3113 for update and merge operations. Branch heads are changesets that have
3115 for update and merge operations. Branch heads are changesets that have
3114 no child changeset on the same branch.
3116 no child changeset on the same branch.
3115
3117
3116 If one or more REVs are given, only branch heads on the branches
3118 If one or more REVs are given, only branch heads on the branches
3117 associated with the specified changesets are shown. This means
3119 associated with the specified changesets are shown. This means
3118 that you can use :hg:`heads foo` to see the heads on a branch
3120 that you can use :hg:`heads foo` to see the heads on a branch
3119 named ``foo``.
3121 named ``foo``.
3120
3122
3121 If -c/--closed is specified, also show branch heads marked closed
3123 If -c/--closed is specified, also show branch heads marked closed
3122 (see :hg:`commit --close-branch`).
3124 (see :hg:`commit --close-branch`).
3123
3125
3124 If STARTREV is specified, only those heads that are descendants of
3126 If STARTREV is specified, only those heads that are descendants of
3125 STARTREV will be displayed.
3127 STARTREV will be displayed.
3126
3128
3127 If -t/--topo is specified, named branch mechanics will be ignored and only
3129 If -t/--topo is specified, named branch mechanics will be ignored and only
3128 changesets without children will be shown.
3130 changesets without children will be shown.
3129
3131
3130 Returns 0 if matching heads are found, 1 if not.
3132 Returns 0 if matching heads are found, 1 if not.
3131 """
3133 """
3132
3134
3133 start = None
3135 start = None
3134 if 'rev' in opts:
3136 if 'rev' in opts:
3135 start = scmutil.revsingle(repo, opts['rev'], None).node()
3137 start = scmutil.revsingle(repo, opts['rev'], None).node()
3136
3138
3137 if opts.get('topo'):
3139 if opts.get('topo'):
3138 heads = [repo[h] for h in repo.heads(start)]
3140 heads = [repo[h] for h in repo.heads(start)]
3139 else:
3141 else:
3140 heads = []
3142 heads = []
3141 for branch in repo.branchmap():
3143 for branch in repo.branchmap():
3142 heads += repo.branchheads(branch, start, opts.get('closed'))
3144 heads += repo.branchheads(branch, start, opts.get('closed'))
3143 heads = [repo[h] for h in heads]
3145 heads = [repo[h] for h in heads]
3144
3146
3145 if branchrevs:
3147 if branchrevs:
3146 branches = set(repo[br].branch() for br in branchrevs)
3148 branches = set(repo[br].branch() for br in branchrevs)
3147 heads = [h for h in heads if h.branch() in branches]
3149 heads = [h for h in heads if h.branch() in branches]
3148
3150
3149 if opts.get('active') and branchrevs:
3151 if opts.get('active') and branchrevs:
3150 dagheads = repo.heads(start)
3152 dagheads = repo.heads(start)
3151 heads = [h for h in heads if h.node() in dagheads]
3153 heads = [h for h in heads if h.node() in dagheads]
3152
3154
3153 if branchrevs:
3155 if branchrevs:
3154 haveheads = set(h.branch() for h in heads)
3156 haveheads = set(h.branch() for h in heads)
3155 if branches - haveheads:
3157 if branches - haveheads:
3156 headless = ', '.join(b for b in branches - haveheads)
3158 headless = ', '.join(b for b in branches - haveheads)
3157 msg = _('no open branch heads found on branches %s')
3159 msg = _('no open branch heads found on branches %s')
3158 if opts.get('rev'):
3160 if opts.get('rev'):
3159 msg += _(' (started at %s)') % opts['rev']
3161 msg += _(' (started at %s)') % opts['rev']
3160 ui.warn((msg + '\n') % headless)
3162 ui.warn((msg + '\n') % headless)
3161
3163
3162 if not heads:
3164 if not heads:
3163 return 1
3165 return 1
3164
3166
3165 heads = sorted(heads, key=lambda x: -x.rev())
3167 heads = sorted(heads, key=lambda x: -x.rev())
3166 displayer = cmdutil.show_changeset(ui, repo, opts)
3168 displayer = cmdutil.show_changeset(ui, repo, opts)
3167 for ctx in heads:
3169 for ctx in heads:
3168 displayer.show(ctx)
3170 displayer.show(ctx)
3169 displayer.close()
3171 displayer.close()
3170
3172
3171 @command('help',
3173 @command('help',
3172 [('e', 'extension', None, _('show only help for extensions')),
3174 [('e', 'extension', None, _('show only help for extensions')),
3173 ('c', 'command', None, _('show only help for commands')),
3175 ('c', 'command', None, _('show only help for commands')),
3174 ('k', 'keyword', '', _('show topics matching keyword')),
3176 ('k', 'keyword', '', _('show topics matching keyword')),
3175 ],
3177 ],
3176 _('[-ec] [TOPIC]'))
3178 _('[-ec] [TOPIC]'))
3177 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3179 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3178 """show help for a given topic or a help overview
3180 """show help for a given topic or a help overview
3179
3181
3180 With no arguments, print a list of commands with short help messages.
3182 With no arguments, print a list of commands with short help messages.
3181
3183
3182 Given a topic, extension, or command name, print help for that
3184 Given a topic, extension, or command name, print help for that
3183 topic.
3185 topic.
3184
3186
3185 Returns 0 if successful.
3187 Returns 0 if successful.
3186 """
3188 """
3187
3189
3188 textwidth = min(ui.termwidth(), 80) - 2
3190 textwidth = min(ui.termwidth(), 80) - 2
3189
3191
3190 def helpcmd(name):
3192 def helpcmd(name):
3191 try:
3193 try:
3192 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3194 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3193 except error.AmbiguousCommand, inst:
3195 except error.AmbiguousCommand, inst:
3194 # py3k fix: except vars can't be used outside the scope of the
3196 # py3k fix: except vars can't be used outside the scope of the
3195 # except block, nor can be used inside a lambda. python issue4617
3197 # except block, nor can be used inside a lambda. python issue4617
3196 prefix = inst.args[0]
3198 prefix = inst.args[0]
3197 select = lambda c: c.lstrip('^').startswith(prefix)
3199 select = lambda c: c.lstrip('^').startswith(prefix)
3198 rst = helplist(select)
3200 rst = helplist(select)
3199 return rst
3201 return rst
3200
3202
3201 rst = []
3203 rst = []
3202
3204
3203 # check if it's an invalid alias and display its error if it is
3205 # check if it's an invalid alias and display its error if it is
3204 if getattr(entry[0], 'badalias', False):
3206 if getattr(entry[0], 'badalias', False):
3205 if not unknowncmd:
3207 if not unknowncmd:
3206 ui.pushbuffer()
3208 ui.pushbuffer()
3207 entry[0](ui)
3209 entry[0](ui)
3208 rst.append(ui.popbuffer())
3210 rst.append(ui.popbuffer())
3209 return rst
3211 return rst
3210
3212
3211 # synopsis
3213 # synopsis
3212 if len(entry) > 2:
3214 if len(entry) > 2:
3213 if entry[2].startswith('hg'):
3215 if entry[2].startswith('hg'):
3214 rst.append("%s\n" % entry[2])
3216 rst.append("%s\n" % entry[2])
3215 else:
3217 else:
3216 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3218 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3217 else:
3219 else:
3218 rst.append('hg %s\n' % aliases[0])
3220 rst.append('hg %s\n' % aliases[0])
3219 # aliases
3221 # aliases
3220 if full and not ui.quiet and len(aliases) > 1:
3222 if full and not ui.quiet and len(aliases) > 1:
3221 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3223 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3222 rst.append('\n')
3224 rst.append('\n')
3223
3225
3224 # description
3226 # description
3225 doc = gettext(entry[0].__doc__)
3227 doc = gettext(entry[0].__doc__)
3226 if not doc:
3228 if not doc:
3227 doc = _("(no help text available)")
3229 doc = _("(no help text available)")
3228 if util.safehasattr(entry[0], 'definition'): # aliased command
3230 if util.safehasattr(entry[0], 'definition'): # aliased command
3229 if entry[0].definition.startswith('!'): # shell alias
3231 if entry[0].definition.startswith('!'): # shell alias
3230 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3232 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3231 else:
3233 else:
3232 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3234 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3233 doc = doc.splitlines(True)
3235 doc = doc.splitlines(True)
3234 if ui.quiet or not full:
3236 if ui.quiet or not full:
3235 rst.append(doc[0])
3237 rst.append(doc[0])
3236 else:
3238 else:
3237 rst.extend(doc)
3239 rst.extend(doc)
3238 rst.append('\n')
3240 rst.append('\n')
3239
3241
3240 # check if this command shadows a non-trivial (multi-line)
3242 # check if this command shadows a non-trivial (multi-line)
3241 # extension help text
3243 # extension help text
3242 try:
3244 try:
3243 mod = extensions.find(name)
3245 mod = extensions.find(name)
3244 doc = gettext(mod.__doc__) or ''
3246 doc = gettext(mod.__doc__) or ''
3245 if '\n' in doc.strip():
3247 if '\n' in doc.strip():
3246 msg = _('use "hg help -e %s" to show help for '
3248 msg = _('use "hg help -e %s" to show help for '
3247 'the %s extension') % (name, name)
3249 'the %s extension') % (name, name)
3248 rst.append('\n%s\n' % msg)
3250 rst.append('\n%s\n' % msg)
3249 except KeyError:
3251 except KeyError:
3250 pass
3252 pass
3251
3253
3252 # options
3254 # options
3253 if not ui.quiet and entry[1]:
3255 if not ui.quiet and entry[1]:
3254 rst.append('\n%s\n\n' % _("options:"))
3256 rst.append('\n%s\n\n' % _("options:"))
3255 rst.append(help.optrst(entry[1], ui.verbose))
3257 rst.append(help.optrst(entry[1], ui.verbose))
3256
3258
3257 if ui.verbose:
3259 if ui.verbose:
3258 rst.append('\n%s\n\n' % _("global options:"))
3260 rst.append('\n%s\n\n' % _("global options:"))
3259 rst.append(help.optrst(globalopts, ui.verbose))
3261 rst.append(help.optrst(globalopts, ui.verbose))
3260
3262
3261 if not ui.verbose:
3263 if not ui.verbose:
3262 if not full:
3264 if not full:
3263 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3265 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3264 % name)
3266 % name)
3265 elif not ui.quiet:
3267 elif not ui.quiet:
3266 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3268 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3267 % name)
3269 % name)
3268 return rst
3270 return rst
3269
3271
3270
3272
3271 def helplist(select=None):
3273 def helplist(select=None):
3272 # list of commands
3274 # list of commands
3273 if name == "shortlist":
3275 if name == "shortlist":
3274 header = _('basic commands:\n\n')
3276 header = _('basic commands:\n\n')
3275 else:
3277 else:
3276 header = _('list of commands:\n\n')
3278 header = _('list of commands:\n\n')
3277
3279
3278 h = {}
3280 h = {}
3279 cmds = {}
3281 cmds = {}
3280 for c, e in table.iteritems():
3282 for c, e in table.iteritems():
3281 f = c.split("|", 1)[0]
3283 f = c.split("|", 1)[0]
3282 if select and not select(f):
3284 if select and not select(f):
3283 continue
3285 continue
3284 if (not select and name != 'shortlist' and
3286 if (not select and name != 'shortlist' and
3285 e[0].__module__ != __name__):
3287 e[0].__module__ != __name__):
3286 continue
3288 continue
3287 if name == "shortlist" and not f.startswith("^"):
3289 if name == "shortlist" and not f.startswith("^"):
3288 continue
3290 continue
3289 f = f.lstrip("^")
3291 f = f.lstrip("^")
3290 if not ui.debugflag and f.startswith("debug"):
3292 if not ui.debugflag and f.startswith("debug"):
3291 continue
3293 continue
3292 doc = e[0].__doc__
3294 doc = e[0].__doc__
3293 if doc and 'DEPRECATED' in doc and not ui.verbose:
3295 if doc and 'DEPRECATED' in doc and not ui.verbose:
3294 continue
3296 continue
3295 doc = gettext(doc)
3297 doc = gettext(doc)
3296 if not doc:
3298 if not doc:
3297 doc = _("(no help text available)")
3299 doc = _("(no help text available)")
3298 h[f] = doc.splitlines()[0].rstrip()
3300 h[f] = doc.splitlines()[0].rstrip()
3299 cmds[f] = c.lstrip("^")
3301 cmds[f] = c.lstrip("^")
3300
3302
3301 rst = []
3303 rst = []
3302 if not h:
3304 if not h:
3303 if not ui.quiet:
3305 if not ui.quiet:
3304 rst.append(_('no commands defined\n'))
3306 rst.append(_('no commands defined\n'))
3305 return rst
3307 return rst
3306
3308
3307 if not ui.quiet:
3309 if not ui.quiet:
3308 rst.append(header)
3310 rst.append(header)
3309 fns = sorted(h)
3311 fns = sorted(h)
3310 for f in fns:
3312 for f in fns:
3311 if ui.verbose:
3313 if ui.verbose:
3312 commands = cmds[f].replace("|",", ")
3314 commands = cmds[f].replace("|",", ")
3313 rst.append(" :%s: %s\n" % (commands, h[f]))
3315 rst.append(" :%s: %s\n" % (commands, h[f]))
3314 else:
3316 else:
3315 rst.append(' :%s: %s\n' % (f, h[f]))
3317 rst.append(' :%s: %s\n' % (f, h[f]))
3316
3318
3317 if not name:
3319 if not name:
3318 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3320 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3319 if exts:
3321 if exts:
3320 rst.append('\n')
3322 rst.append('\n')
3321 rst.extend(exts)
3323 rst.extend(exts)
3322
3324
3323 rst.append(_("\nadditional help topics:\n\n"))
3325 rst.append(_("\nadditional help topics:\n\n"))
3324 topics = []
3326 topics = []
3325 for names, header, doc in help.helptable:
3327 for names, header, doc in help.helptable:
3326 topics.append((names[0], header))
3328 topics.append((names[0], header))
3327 for t, desc in topics:
3329 for t, desc in topics:
3328 rst.append(" :%s: %s\n" % (t, desc))
3330 rst.append(" :%s: %s\n" % (t, desc))
3329
3331
3330 optlist = []
3332 optlist = []
3331 if not ui.quiet:
3333 if not ui.quiet:
3332 if ui.verbose:
3334 if ui.verbose:
3333 optlist.append((_("global options:"), globalopts))
3335 optlist.append((_("global options:"), globalopts))
3334 if name == 'shortlist':
3336 if name == 'shortlist':
3335 optlist.append((_('use "hg help" for the full list '
3337 optlist.append((_('use "hg help" for the full list '
3336 'of commands'), ()))
3338 'of commands'), ()))
3337 else:
3339 else:
3338 if name == 'shortlist':
3340 if name == 'shortlist':
3339 msg = _('use "hg help" for the full list of commands '
3341 msg = _('use "hg help" for the full list of commands '
3340 'or "hg -v" for details')
3342 'or "hg -v" for details')
3341 elif name and not full:
3343 elif name and not full:
3342 msg = _('use "hg help %s" to show the full help '
3344 msg = _('use "hg help %s" to show the full help '
3343 'text') % name
3345 'text') % name
3344 else:
3346 else:
3345 msg = _('use "hg -v help%s" to show builtin aliases and '
3347 msg = _('use "hg -v help%s" to show builtin aliases and '
3346 'global options') % (name and " " + name or "")
3348 'global options') % (name and " " + name or "")
3347 optlist.append((msg, ()))
3349 optlist.append((msg, ()))
3348
3350
3349 if optlist:
3351 if optlist:
3350 for title, options in optlist:
3352 for title, options in optlist:
3351 rst.append('\n%s\n' % title)
3353 rst.append('\n%s\n' % title)
3352 if options:
3354 if options:
3353 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3355 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3354 return rst
3356 return rst
3355
3357
3356 def helptopic(name):
3358 def helptopic(name):
3357 for names, header, doc in help.helptable:
3359 for names, header, doc in help.helptable:
3358 if name in names:
3360 if name in names:
3359 break
3361 break
3360 else:
3362 else:
3361 raise error.UnknownCommand(name)
3363 raise error.UnknownCommand(name)
3362
3364
3363 rst = ["%s\n\n" % header]
3365 rst = ["%s\n\n" % header]
3364 # description
3366 # description
3365 if not doc:
3367 if not doc:
3366 rst.append(" %s\n" % _("(no help text available)"))
3368 rst.append(" %s\n" % _("(no help text available)"))
3367 if util.safehasattr(doc, '__call__'):
3369 if util.safehasattr(doc, '__call__'):
3368 rst += [" %s\n" % l for l in doc().splitlines()]
3370 rst += [" %s\n" % l for l in doc().splitlines()]
3369
3371
3370 try:
3372 try:
3371 cmdutil.findcmd(name, table)
3373 cmdutil.findcmd(name, table)
3372 rst.append(_('\nuse "hg help -c %s" to see help for '
3374 rst.append(_('\nuse "hg help -c %s" to see help for '
3373 'the %s command\n') % (name, name))
3375 'the %s command\n') % (name, name))
3374 except error.UnknownCommand:
3376 except error.UnknownCommand:
3375 pass
3377 pass
3376 return rst
3378 return rst
3377
3379
3378 def helpext(name):
3380 def helpext(name):
3379 try:
3381 try:
3380 mod = extensions.find(name)
3382 mod = extensions.find(name)
3381 doc = gettext(mod.__doc__) or _('no help text available')
3383 doc = gettext(mod.__doc__) or _('no help text available')
3382 except KeyError:
3384 except KeyError:
3383 mod = None
3385 mod = None
3384 doc = extensions.disabledext(name)
3386 doc = extensions.disabledext(name)
3385 if not doc:
3387 if not doc:
3386 raise error.UnknownCommand(name)
3388 raise error.UnknownCommand(name)
3387
3389
3388 if '\n' not in doc:
3390 if '\n' not in doc:
3389 head, tail = doc, ""
3391 head, tail = doc, ""
3390 else:
3392 else:
3391 head, tail = doc.split('\n', 1)
3393 head, tail = doc.split('\n', 1)
3392 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3394 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3393 if tail:
3395 if tail:
3394 rst.extend(tail.splitlines(True))
3396 rst.extend(tail.splitlines(True))
3395 rst.append('\n')
3397 rst.append('\n')
3396
3398
3397 if mod:
3399 if mod:
3398 try:
3400 try:
3399 ct = mod.cmdtable
3401 ct = mod.cmdtable
3400 except AttributeError:
3402 except AttributeError:
3401 ct = {}
3403 ct = {}
3402 modcmds = set([c.split('|', 1)[0] for c in ct])
3404 modcmds = set([c.split('|', 1)[0] for c in ct])
3403 rst.extend(helplist(modcmds.__contains__))
3405 rst.extend(helplist(modcmds.__contains__))
3404 else:
3406 else:
3405 rst.append(_('use "hg help extensions" for information on enabling '
3407 rst.append(_('use "hg help extensions" for information on enabling '
3406 'extensions\n'))
3408 'extensions\n'))
3407 return rst
3409 return rst
3408
3410
3409 def helpextcmd(name):
3411 def helpextcmd(name):
3410 cmd, ext, mod = extensions.disabledcmd(ui, name,
3412 cmd, ext, mod = extensions.disabledcmd(ui, name,
3411 ui.configbool('ui', 'strict'))
3413 ui.configbool('ui', 'strict'))
3412 doc = gettext(mod.__doc__).splitlines()[0]
3414 doc = gettext(mod.__doc__).splitlines()[0]
3413
3415
3414 rst = help.listexts(_("'%s' is provided by the following "
3416 rst = help.listexts(_("'%s' is provided by the following "
3415 "extension:") % cmd, {ext: doc}, indent=4)
3417 "extension:") % cmd, {ext: doc}, indent=4)
3416 rst.append('\n')
3418 rst.append('\n')
3417 rst.append(_('use "hg help extensions" for information on enabling '
3419 rst.append(_('use "hg help extensions" for information on enabling '
3418 'extensions\n'))
3420 'extensions\n'))
3419 return rst
3421 return rst
3420
3422
3421
3423
3422 rst = []
3424 rst = []
3423 kw = opts.get('keyword')
3425 kw = opts.get('keyword')
3424 if kw:
3426 if kw:
3425 matches = help.topicmatch(kw)
3427 matches = help.topicmatch(kw)
3426 for t, title in (('topics', _('Topics')),
3428 for t, title in (('topics', _('Topics')),
3427 ('commands', _('Commands')),
3429 ('commands', _('Commands')),
3428 ('extensions', _('Extensions')),
3430 ('extensions', _('Extensions')),
3429 ('extensioncommands', _('Extension Commands'))):
3431 ('extensioncommands', _('Extension Commands'))):
3430 if matches[t]:
3432 if matches[t]:
3431 rst.append('%s:\n\n' % title)
3433 rst.append('%s:\n\n' % title)
3432 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3434 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3433 rst.append('\n')
3435 rst.append('\n')
3434 elif name and name != 'shortlist':
3436 elif name and name != 'shortlist':
3435 i = None
3437 i = None
3436 if unknowncmd:
3438 if unknowncmd:
3437 queries = (helpextcmd,)
3439 queries = (helpextcmd,)
3438 elif opts.get('extension'):
3440 elif opts.get('extension'):
3439 queries = (helpext,)
3441 queries = (helpext,)
3440 elif opts.get('command'):
3442 elif opts.get('command'):
3441 queries = (helpcmd,)
3443 queries = (helpcmd,)
3442 else:
3444 else:
3443 queries = (helptopic, helpcmd, helpext, helpextcmd)
3445 queries = (helptopic, helpcmd, helpext, helpextcmd)
3444 for f in queries:
3446 for f in queries:
3445 try:
3447 try:
3446 rst = f(name)
3448 rst = f(name)
3447 i = None
3449 i = None
3448 break
3450 break
3449 except error.UnknownCommand, inst:
3451 except error.UnknownCommand, inst:
3450 i = inst
3452 i = inst
3451 if i:
3453 if i:
3452 raise i
3454 raise i
3453 else:
3455 else:
3454 # program name
3456 # program name
3455 if not ui.quiet:
3457 if not ui.quiet:
3456 rst = [_("Mercurial Distributed SCM\n"), '\n']
3458 rst = [_("Mercurial Distributed SCM\n"), '\n']
3457 rst.extend(helplist())
3459 rst.extend(helplist())
3458
3460
3459 keep = ui.verbose and ['verbose'] or []
3461 keep = ui.verbose and ['verbose'] or []
3460 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3462 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3461 ui.write(formatted)
3463 ui.write(formatted)
3462
3464
3463
3465
3464 @command('identify|id',
3466 @command('identify|id',
3465 [('r', 'rev', '',
3467 [('r', 'rev', '',
3466 _('identify the specified revision'), _('REV')),
3468 _('identify the specified revision'), _('REV')),
3467 ('n', 'num', None, _('show local revision number')),
3469 ('n', 'num', None, _('show local revision number')),
3468 ('i', 'id', None, _('show global revision id')),
3470 ('i', 'id', None, _('show global revision id')),
3469 ('b', 'branch', None, _('show branch')),
3471 ('b', 'branch', None, _('show branch')),
3470 ('t', 'tags', None, _('show tags')),
3472 ('t', 'tags', None, _('show tags')),
3471 ('B', 'bookmarks', None, _('show bookmarks')),
3473 ('B', 'bookmarks', None, _('show bookmarks')),
3472 ] + remoteopts,
3474 ] + remoteopts,
3473 _('[-nibtB] [-r REV] [SOURCE]'))
3475 _('[-nibtB] [-r REV] [SOURCE]'))
3474 def identify(ui, repo, source=None, rev=None,
3476 def identify(ui, repo, source=None, rev=None,
3475 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3477 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3476 """identify the working copy or specified revision
3478 """identify the working copy or specified revision
3477
3479
3478 Print a summary identifying the repository state at REV using one or
3480 Print a summary identifying the repository state at REV using one or
3479 two parent hash identifiers, followed by a "+" if the working
3481 two parent hash identifiers, followed by a "+" if the working
3480 directory has uncommitted changes, the branch name (if not default),
3482 directory has uncommitted changes, the branch name (if not default),
3481 a list of tags, and a list of bookmarks.
3483 a list of tags, and a list of bookmarks.
3482
3484
3483 When REV is not given, print a summary of the current state of the
3485 When REV is not given, print a summary of the current state of the
3484 repository.
3486 repository.
3485
3487
3486 Specifying a path to a repository root or Mercurial bundle will
3488 Specifying a path to a repository root or Mercurial bundle will
3487 cause lookup to operate on that repository/bundle.
3489 cause lookup to operate on that repository/bundle.
3488
3490
3489 .. container:: verbose
3491 .. container:: verbose
3490
3492
3491 Examples:
3493 Examples:
3492
3494
3493 - generate a build identifier for the working directory::
3495 - generate a build identifier for the working directory::
3494
3496
3495 hg id --id > build-id.dat
3497 hg id --id > build-id.dat
3496
3498
3497 - find the revision corresponding to a tag::
3499 - find the revision corresponding to a tag::
3498
3500
3499 hg id -n -r 1.3
3501 hg id -n -r 1.3
3500
3502
3501 - check the most recent revision of a remote repository::
3503 - check the most recent revision of a remote repository::
3502
3504
3503 hg id -r tip http://selenic.com/hg/
3505 hg id -r tip http://selenic.com/hg/
3504
3506
3505 Returns 0 if successful.
3507 Returns 0 if successful.
3506 """
3508 """
3507
3509
3508 if not repo and not source:
3510 if not repo and not source:
3509 raise util.Abort(_("there is no Mercurial repository here "
3511 raise util.Abort(_("there is no Mercurial repository here "
3510 "(.hg not found)"))
3512 "(.hg not found)"))
3511
3513
3512 hexfunc = ui.debugflag and hex or short
3514 hexfunc = ui.debugflag and hex or short
3513 default = not (num or id or branch or tags or bookmarks)
3515 default = not (num or id or branch or tags or bookmarks)
3514 output = []
3516 output = []
3515 revs = []
3517 revs = []
3516
3518
3517 if source:
3519 if source:
3518 source, branches = hg.parseurl(ui.expandpath(source))
3520 source, branches = hg.parseurl(ui.expandpath(source))
3519 peer = hg.peer(ui, opts, source)
3521 peer = hg.peer(ui, opts, source)
3520 repo = peer.local()
3522 repo = peer.local()
3521 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3523 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3522
3524
3523 if not repo:
3525 if not repo:
3524 if num or branch or tags:
3526 if num or branch or tags:
3525 raise util.Abort(
3527 raise util.Abort(
3526 _("can't query remote revision number, branch, or tags"))
3528 _("can't query remote revision number, branch, or tags"))
3527 if not rev and revs:
3529 if not rev and revs:
3528 rev = revs[0]
3530 rev = revs[0]
3529 if not rev:
3531 if not rev:
3530 rev = "tip"
3532 rev = "tip"
3531
3533
3532 remoterev = peer.lookup(rev)
3534 remoterev = peer.lookup(rev)
3533 if default or id:
3535 if default or id:
3534 output = [hexfunc(remoterev)]
3536 output = [hexfunc(remoterev)]
3535
3537
3536 def getbms():
3538 def getbms():
3537 bms = []
3539 bms = []
3538
3540
3539 if 'bookmarks' in peer.listkeys('namespaces'):
3541 if 'bookmarks' in peer.listkeys('namespaces'):
3540 hexremoterev = hex(remoterev)
3542 hexremoterev = hex(remoterev)
3541 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3543 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3542 if bmr == hexremoterev]
3544 if bmr == hexremoterev]
3543
3545
3544 return bms
3546 return bms
3545
3547
3546 if bookmarks:
3548 if bookmarks:
3547 output.extend(getbms())
3549 output.extend(getbms())
3548 elif default and not ui.quiet:
3550 elif default and not ui.quiet:
3549 # multiple bookmarks for a single parent separated by '/'
3551 # multiple bookmarks for a single parent separated by '/'
3550 bm = '/'.join(getbms())
3552 bm = '/'.join(getbms())
3551 if bm:
3553 if bm:
3552 output.append(bm)
3554 output.append(bm)
3553 else:
3555 else:
3554 if not rev:
3556 if not rev:
3555 ctx = repo[None]
3557 ctx = repo[None]
3556 parents = ctx.parents()
3558 parents = ctx.parents()
3557 changed = ""
3559 changed = ""
3558 if default or id or num:
3560 if default or id or num:
3559 if (util.any(repo.status())
3561 if (util.any(repo.status())
3560 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3562 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3561 changed = '+'
3563 changed = '+'
3562 if default or id:
3564 if default or id:
3563 output = ["%s%s" %
3565 output = ["%s%s" %
3564 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3566 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3565 if num:
3567 if num:
3566 output.append("%s%s" %
3568 output.append("%s%s" %
3567 ('+'.join([str(p.rev()) for p in parents]), changed))
3569 ('+'.join([str(p.rev()) for p in parents]), changed))
3568 else:
3570 else:
3569 ctx = scmutil.revsingle(repo, rev)
3571 ctx = scmutil.revsingle(repo, rev)
3570 if default or id:
3572 if default or id:
3571 output = [hexfunc(ctx.node())]
3573 output = [hexfunc(ctx.node())]
3572 if num:
3574 if num:
3573 output.append(str(ctx.rev()))
3575 output.append(str(ctx.rev()))
3574
3576
3575 if default and not ui.quiet:
3577 if default and not ui.quiet:
3576 b = ctx.branch()
3578 b = ctx.branch()
3577 if b != 'default':
3579 if b != 'default':
3578 output.append("(%s)" % b)
3580 output.append("(%s)" % b)
3579
3581
3580 # multiple tags for a single parent separated by '/'
3582 # multiple tags for a single parent separated by '/'
3581 t = '/'.join(ctx.tags())
3583 t = '/'.join(ctx.tags())
3582 if t:
3584 if t:
3583 output.append(t)
3585 output.append(t)
3584
3586
3585 # multiple bookmarks for a single parent separated by '/'
3587 # multiple bookmarks for a single parent separated by '/'
3586 bm = '/'.join(ctx.bookmarks())
3588 bm = '/'.join(ctx.bookmarks())
3587 if bm:
3589 if bm:
3588 output.append(bm)
3590 output.append(bm)
3589 else:
3591 else:
3590 if branch:
3592 if branch:
3591 output.append(ctx.branch())
3593 output.append(ctx.branch())
3592
3594
3593 if tags:
3595 if tags:
3594 output.extend(ctx.tags())
3596 output.extend(ctx.tags())
3595
3597
3596 if bookmarks:
3598 if bookmarks:
3597 output.extend(ctx.bookmarks())
3599 output.extend(ctx.bookmarks())
3598
3600
3599 ui.write("%s\n" % ' '.join(output))
3601 ui.write("%s\n" % ' '.join(output))
3600
3602
3601 @command('import|patch',
3603 @command('import|patch',
3602 [('p', 'strip', 1,
3604 [('p', 'strip', 1,
3603 _('directory strip option for patch. This has the same '
3605 _('directory strip option for patch. This has the same '
3604 'meaning as the corresponding patch option'), _('NUM')),
3606 'meaning as the corresponding patch option'), _('NUM')),
3605 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3607 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3606 ('e', 'edit', False, _('invoke editor on commit messages')),
3608 ('e', 'edit', False, _('invoke editor on commit messages')),
3607 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3609 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3608 ('', 'no-commit', None,
3610 ('', 'no-commit', None,
3609 _("don't commit, just update the working directory")),
3611 _("don't commit, just update the working directory")),
3610 ('', 'bypass', None,
3612 ('', 'bypass', None,
3611 _("apply patch without touching the working directory")),
3613 _("apply patch without touching the working directory")),
3612 ('', 'exact', None,
3614 ('', 'exact', None,
3613 _('apply patch to the nodes from which it was generated')),
3615 _('apply patch to the nodes from which it was generated')),
3614 ('', 'import-branch', None,
3616 ('', 'import-branch', None,
3615 _('use any branch information in patch (implied by --exact)'))] +
3617 _('use any branch information in patch (implied by --exact)'))] +
3616 commitopts + commitopts2 + similarityopts,
3618 commitopts + commitopts2 + similarityopts,
3617 _('[OPTION]... PATCH...'))
3619 _('[OPTION]... PATCH...'))
3618 def import_(ui, repo, patch1=None, *patches, **opts):
3620 def import_(ui, repo, patch1=None, *patches, **opts):
3619 """import an ordered set of patches
3621 """import an ordered set of patches
3620
3622
3621 Import a list of patches and commit them individually (unless
3623 Import a list of patches and commit them individually (unless
3622 --no-commit is specified).
3624 --no-commit is specified).
3623
3625
3624 If there are outstanding changes in the working directory, import
3626 If there are outstanding changes in the working directory, import
3625 will abort unless given the -f/--force flag.
3627 will abort unless given the -f/--force flag.
3626
3628
3627 You can import a patch straight from a mail message. Even patches
3629 You can import a patch straight from a mail message. Even patches
3628 as attachments work (to use the body part, it must have type
3630 as attachments work (to use the body part, it must have type
3629 text/plain or text/x-patch). From and Subject headers of email
3631 text/plain or text/x-patch). From and Subject headers of email
3630 message are used as default committer and commit message. All
3632 message are used as default committer and commit message. All
3631 text/plain body parts before first diff are added to commit
3633 text/plain body parts before first diff are added to commit
3632 message.
3634 message.
3633
3635
3634 If the imported patch was generated by :hg:`export`, user and
3636 If the imported patch was generated by :hg:`export`, user and
3635 description from patch override values from message headers and
3637 description from patch override values from message headers and
3636 body. Values given on command line with -m/--message and -u/--user
3638 body. Values given on command line with -m/--message and -u/--user
3637 override these.
3639 override these.
3638
3640
3639 If --exact is specified, import will set the working directory to
3641 If --exact is specified, import will set the working directory to
3640 the parent of each patch before applying it, and will abort if the
3642 the parent of each patch before applying it, and will abort if the
3641 resulting changeset has a different ID than the one recorded in
3643 resulting changeset has a different ID than the one recorded in
3642 the patch. This may happen due to character set problems or other
3644 the patch. This may happen due to character set problems or other
3643 deficiencies in the text patch format.
3645 deficiencies in the text patch format.
3644
3646
3645 Use --bypass to apply and commit patches directly to the
3647 Use --bypass to apply and commit patches directly to the
3646 repository, not touching the working directory. Without --exact,
3648 repository, not touching the working directory. Without --exact,
3647 patches will be applied on top of the working directory parent
3649 patches will be applied on top of the working directory parent
3648 revision.
3650 revision.
3649
3651
3650 With -s/--similarity, hg will attempt to discover renames and
3652 With -s/--similarity, hg will attempt to discover renames and
3651 copies in the patch in the same way as :hg:`addremove`.
3653 copies in the patch in the same way as :hg:`addremove`.
3652
3654
3653 To read a patch from standard input, use "-" as the patch name. If
3655 To read a patch from standard input, use "-" as the patch name. If
3654 a URL is specified, the patch will be downloaded from it.
3656 a URL is specified, the patch will be downloaded from it.
3655 See :hg:`help dates` for a list of formats valid for -d/--date.
3657 See :hg:`help dates` for a list of formats valid for -d/--date.
3656
3658
3657 .. container:: verbose
3659 .. container:: verbose
3658
3660
3659 Examples:
3661 Examples:
3660
3662
3661 - import a traditional patch from a website and detect renames::
3663 - import a traditional patch from a website and detect renames::
3662
3664
3663 hg import -s 80 http://example.com/bugfix.patch
3665 hg import -s 80 http://example.com/bugfix.patch
3664
3666
3665 - import a changeset from an hgweb server::
3667 - import a changeset from an hgweb server::
3666
3668
3667 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3669 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3668
3670
3669 - import all the patches in an Unix-style mbox::
3671 - import all the patches in an Unix-style mbox::
3670
3672
3671 hg import incoming-patches.mbox
3673 hg import incoming-patches.mbox
3672
3674
3673 - attempt to exactly restore an exported changeset (not always
3675 - attempt to exactly restore an exported changeset (not always
3674 possible)::
3676 possible)::
3675
3677
3676 hg import --exact proposed-fix.patch
3678 hg import --exact proposed-fix.patch
3677
3679
3678 Returns 0 on success.
3680 Returns 0 on success.
3679 """
3681 """
3680
3682
3681 if not patch1:
3683 if not patch1:
3682 raise util.Abort(_('need at least one patch to import'))
3684 raise util.Abort(_('need at least one patch to import'))
3683
3685
3684 patches = (patch1,) + patches
3686 patches = (patch1,) + patches
3685
3687
3686 date = opts.get('date')
3688 date = opts.get('date')
3687 if date:
3689 if date:
3688 opts['date'] = util.parsedate(date)
3690 opts['date'] = util.parsedate(date)
3689
3691
3690 editor = cmdutil.commiteditor
3692 editor = cmdutil.commiteditor
3691 if opts.get('edit'):
3693 if opts.get('edit'):
3692 editor = cmdutil.commitforceeditor
3694 editor = cmdutil.commitforceeditor
3693
3695
3694 update = not opts.get('bypass')
3696 update = not opts.get('bypass')
3695 if not update and opts.get('no_commit'):
3697 if not update and opts.get('no_commit'):
3696 raise util.Abort(_('cannot use --no-commit with --bypass'))
3698 raise util.Abort(_('cannot use --no-commit with --bypass'))
3697 try:
3699 try:
3698 sim = float(opts.get('similarity') or 0)
3700 sim = float(opts.get('similarity') or 0)
3699 except ValueError:
3701 except ValueError:
3700 raise util.Abort(_('similarity must be a number'))
3702 raise util.Abort(_('similarity must be a number'))
3701 if sim < 0 or sim > 100:
3703 if sim < 0 or sim > 100:
3702 raise util.Abort(_('similarity must be between 0 and 100'))
3704 raise util.Abort(_('similarity must be between 0 and 100'))
3703 if sim and not update:
3705 if sim and not update:
3704 raise util.Abort(_('cannot use --similarity with --bypass'))
3706 raise util.Abort(_('cannot use --similarity with --bypass'))
3705
3707
3706 if (opts.get('exact') or not opts.get('force')) and update:
3708 if (opts.get('exact') or not opts.get('force')) and update:
3707 cmdutil.bailifchanged(repo)
3709 cmdutil.bailifchanged(repo)
3708
3710
3709 base = opts["base"]
3711 base = opts["base"]
3710 strip = opts["strip"]
3712 strip = opts["strip"]
3711 wlock = lock = tr = None
3713 wlock = lock = tr = None
3712 msgs = []
3714 msgs = []
3713
3715
3714 def checkexact(repo, n, nodeid):
3716 def checkexact(repo, n, nodeid):
3715 if opts.get('exact') and hex(n) != nodeid:
3717 if opts.get('exact') and hex(n) != nodeid:
3716 repo.rollback()
3718 repo.rollback()
3717 raise util.Abort(_('patch is damaged or loses information'))
3719 raise util.Abort(_('patch is damaged or loses information'))
3718
3720
3719 def tryone(ui, hunk, parents):
3721 def tryone(ui, hunk, parents):
3720 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3722 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3721 patch.extract(ui, hunk)
3723 patch.extract(ui, hunk)
3722
3724
3723 if not tmpname:
3725 if not tmpname:
3724 return (None, None)
3726 return (None, None)
3725 msg = _('applied to working directory')
3727 msg = _('applied to working directory')
3726
3728
3727 try:
3729 try:
3728 cmdline_message = cmdutil.logmessage(ui, opts)
3730 cmdline_message = cmdutil.logmessage(ui, opts)
3729 if cmdline_message:
3731 if cmdline_message:
3730 # pickup the cmdline msg
3732 # pickup the cmdline msg
3731 message = cmdline_message
3733 message = cmdline_message
3732 elif message:
3734 elif message:
3733 # pickup the patch msg
3735 # pickup the patch msg
3734 message = message.strip()
3736 message = message.strip()
3735 else:
3737 else:
3736 # launch the editor
3738 # launch the editor
3737 message = None
3739 message = None
3738 ui.debug('message:\n%s\n' % message)
3740 ui.debug('message:\n%s\n' % message)
3739
3741
3740 if len(parents) == 1:
3742 if len(parents) == 1:
3741 parents.append(repo[nullid])
3743 parents.append(repo[nullid])
3742 if opts.get('exact'):
3744 if opts.get('exact'):
3743 if not nodeid or not p1:
3745 if not nodeid or not p1:
3744 raise util.Abort(_('not a Mercurial patch'))
3746 raise util.Abort(_('not a Mercurial patch'))
3745 p1 = repo[p1]
3747 p1 = repo[p1]
3746 p2 = repo[p2 or nullid]
3748 p2 = repo[p2 or nullid]
3747 elif p2:
3749 elif p2:
3748 try:
3750 try:
3749 p1 = repo[p1]
3751 p1 = repo[p1]
3750 p2 = repo[p2]
3752 p2 = repo[p2]
3751 # Without any options, consider p2 only if the
3753 # Without any options, consider p2 only if the
3752 # patch is being applied on top of the recorded
3754 # patch is being applied on top of the recorded
3753 # first parent.
3755 # first parent.
3754 if p1 != parents[0]:
3756 if p1 != parents[0]:
3755 p1 = parents[0]
3757 p1 = parents[0]
3756 p2 = repo[nullid]
3758 p2 = repo[nullid]
3757 except error.RepoError:
3759 except error.RepoError:
3758 p1, p2 = parents
3760 p1, p2 = parents
3759 else:
3761 else:
3760 p1, p2 = parents
3762 p1, p2 = parents
3761
3763
3762 n = None
3764 n = None
3763 if update:
3765 if update:
3764 if p1 != parents[0]:
3766 if p1 != parents[0]:
3765 hg.clean(repo, p1.node())
3767 hg.clean(repo, p1.node())
3766 if p2 != parents[1]:
3768 if p2 != parents[1]:
3767 repo.setparents(p1.node(), p2.node())
3769 repo.setparents(p1.node(), p2.node())
3768
3770
3769 if opts.get('exact') or opts.get('import_branch'):
3771 if opts.get('exact') or opts.get('import_branch'):
3770 repo.dirstate.setbranch(branch or 'default')
3772 repo.dirstate.setbranch(branch or 'default')
3771
3773
3772 files = set()
3774 files = set()
3773 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3775 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3774 eolmode=None, similarity=sim / 100.0)
3776 eolmode=None, similarity=sim / 100.0)
3775 files = list(files)
3777 files = list(files)
3776 if opts.get('no_commit'):
3778 if opts.get('no_commit'):
3777 if message:
3779 if message:
3778 msgs.append(message)
3780 msgs.append(message)
3779 else:
3781 else:
3780 if opts.get('exact') or p2:
3782 if opts.get('exact') or p2:
3781 # If you got here, you either use --force and know what
3783 # If you got here, you either use --force and know what
3782 # you are doing or used --exact or a merge patch while
3784 # you are doing or used --exact or a merge patch while
3783 # being updated to its first parent.
3785 # being updated to its first parent.
3784 m = None
3786 m = None
3785 else:
3787 else:
3786 m = scmutil.matchfiles(repo, files or [])
3788 m = scmutil.matchfiles(repo, files or [])
3787 n = repo.commit(message, opts.get('user') or user,
3789 n = repo.commit(message, opts.get('user') or user,
3788 opts.get('date') or date, match=m,
3790 opts.get('date') or date, match=m,
3789 editor=editor)
3791 editor=editor)
3790 checkexact(repo, n, nodeid)
3792 checkexact(repo, n, nodeid)
3791 else:
3793 else:
3792 if opts.get('exact') or opts.get('import_branch'):
3794 if opts.get('exact') or opts.get('import_branch'):
3793 branch = branch or 'default'
3795 branch = branch or 'default'
3794 else:
3796 else:
3795 branch = p1.branch()
3797 branch = p1.branch()
3796 store = patch.filestore()
3798 store = patch.filestore()
3797 try:
3799 try:
3798 files = set()
3800 files = set()
3799 try:
3801 try:
3800 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3802 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3801 files, eolmode=None)
3803 files, eolmode=None)
3802 except patch.PatchError, e:
3804 except patch.PatchError, e:
3803 raise util.Abort(str(e))
3805 raise util.Abort(str(e))
3804 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3806 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3805 message,
3807 message,
3806 opts.get('user') or user,
3808 opts.get('user') or user,
3807 opts.get('date') or date,
3809 opts.get('date') or date,
3808 branch, files, store,
3810 branch, files, store,
3809 editor=cmdutil.commiteditor)
3811 editor=cmdutil.commiteditor)
3810 repo.savecommitmessage(memctx.description())
3812 repo.savecommitmessage(memctx.description())
3811 n = memctx.commit()
3813 n = memctx.commit()
3812 checkexact(repo, n, nodeid)
3814 checkexact(repo, n, nodeid)
3813 finally:
3815 finally:
3814 store.close()
3816 store.close()
3815 if n:
3817 if n:
3816 # i18n: refers to a short changeset id
3818 # i18n: refers to a short changeset id
3817 msg = _('created %s') % short(n)
3819 msg = _('created %s') % short(n)
3818 return (msg, n)
3820 return (msg, n)
3819 finally:
3821 finally:
3820 os.unlink(tmpname)
3822 os.unlink(tmpname)
3821
3823
3822 try:
3824 try:
3823 try:
3825 try:
3824 wlock = repo.wlock()
3826 wlock = repo.wlock()
3825 if not opts.get('no_commit'):
3827 if not opts.get('no_commit'):
3826 lock = repo.lock()
3828 lock = repo.lock()
3827 tr = repo.transaction('import')
3829 tr = repo.transaction('import')
3828 parents = repo.parents()
3830 parents = repo.parents()
3829 for patchurl in patches:
3831 for patchurl in patches:
3830 if patchurl == '-':
3832 if patchurl == '-':
3831 ui.status(_('applying patch from stdin\n'))
3833 ui.status(_('applying patch from stdin\n'))
3832 patchfile = ui.fin
3834 patchfile = ui.fin
3833 patchurl = 'stdin' # for error message
3835 patchurl = 'stdin' # for error message
3834 else:
3836 else:
3835 patchurl = os.path.join(base, patchurl)
3837 patchurl = os.path.join(base, patchurl)
3836 ui.status(_('applying %s\n') % patchurl)
3838 ui.status(_('applying %s\n') % patchurl)
3837 patchfile = url.open(ui, patchurl)
3839 patchfile = url.open(ui, patchurl)
3838
3840
3839 haspatch = False
3841 haspatch = False
3840 for hunk in patch.split(patchfile):
3842 for hunk in patch.split(patchfile):
3841 (msg, node) = tryone(ui, hunk, parents)
3843 (msg, node) = tryone(ui, hunk, parents)
3842 if msg:
3844 if msg:
3843 haspatch = True
3845 haspatch = True
3844 ui.note(msg + '\n')
3846 ui.note(msg + '\n')
3845 if update or opts.get('exact'):
3847 if update or opts.get('exact'):
3846 parents = repo.parents()
3848 parents = repo.parents()
3847 else:
3849 else:
3848 parents = [repo[node]]
3850 parents = [repo[node]]
3849
3851
3850 if not haspatch:
3852 if not haspatch:
3851 raise util.Abort(_('%s: no diffs found') % patchurl)
3853 raise util.Abort(_('%s: no diffs found') % patchurl)
3852
3854
3853 if tr:
3855 if tr:
3854 tr.close()
3856 tr.close()
3855 if msgs:
3857 if msgs:
3856 repo.savecommitmessage('\n* * *\n'.join(msgs))
3858 repo.savecommitmessage('\n* * *\n'.join(msgs))
3857 except: # re-raises
3859 except: # re-raises
3858 # wlock.release() indirectly calls dirstate.write(): since
3860 # wlock.release() indirectly calls dirstate.write(): since
3859 # we're crashing, we do not want to change the working dir
3861 # we're crashing, we do not want to change the working dir
3860 # parent after all, so make sure it writes nothing
3862 # parent after all, so make sure it writes nothing
3861 repo.dirstate.invalidate()
3863 repo.dirstate.invalidate()
3862 raise
3864 raise
3863 finally:
3865 finally:
3864 if tr:
3866 if tr:
3865 tr.release()
3867 tr.release()
3866 release(lock, wlock)
3868 release(lock, wlock)
3867
3869
3868 @command('incoming|in',
3870 @command('incoming|in',
3869 [('f', 'force', None,
3871 [('f', 'force', None,
3870 _('run even if remote repository is unrelated')),
3872 _('run even if remote repository is unrelated')),
3871 ('n', 'newest-first', None, _('show newest record first')),
3873 ('n', 'newest-first', None, _('show newest record first')),
3872 ('', 'bundle', '',
3874 ('', 'bundle', '',
3873 _('file to store the bundles into'), _('FILE')),
3875 _('file to store the bundles into'), _('FILE')),
3874 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3876 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3875 ('B', 'bookmarks', False, _("compare bookmarks")),
3877 ('B', 'bookmarks', False, _("compare bookmarks")),
3876 ('b', 'branch', [],
3878 ('b', 'branch', [],
3877 _('a specific branch you would like to pull'), _('BRANCH')),
3879 _('a specific branch you would like to pull'), _('BRANCH')),
3878 ] + logopts + remoteopts + subrepoopts,
3880 ] + logopts + remoteopts + subrepoopts,
3879 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3881 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3880 def incoming(ui, repo, source="default", **opts):
3882 def incoming(ui, repo, source="default", **opts):
3881 """show new changesets found in source
3883 """show new changesets found in source
3882
3884
3883 Show new changesets found in the specified path/URL or the default
3885 Show new changesets found in the specified path/URL or the default
3884 pull location. These are the changesets that would have been pulled
3886 pull location. These are the changesets that would have been pulled
3885 if a pull at the time you issued this command.
3887 if a pull at the time you issued this command.
3886
3888
3887 For remote repository, using --bundle avoids downloading the
3889 For remote repository, using --bundle avoids downloading the
3888 changesets twice if the incoming is followed by a pull.
3890 changesets twice if the incoming is followed by a pull.
3889
3891
3890 See pull for valid source format details.
3892 See pull for valid source format details.
3891
3893
3892 Returns 0 if there are incoming changes, 1 otherwise.
3894 Returns 0 if there are incoming changes, 1 otherwise.
3893 """
3895 """
3894 if opts.get('graph'):
3896 if opts.get('graph'):
3895 cmdutil.checkunsupportedgraphflags([], opts)
3897 cmdutil.checkunsupportedgraphflags([], opts)
3896 def display(other, chlist, displayer):
3898 def display(other, chlist, displayer):
3897 revdag = cmdutil.graphrevs(other, chlist, opts)
3899 revdag = cmdutil.graphrevs(other, chlist, opts)
3898 showparents = [ctx.node() for ctx in repo[None].parents()]
3900 showparents = [ctx.node() for ctx in repo[None].parents()]
3899 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3901 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3900 graphmod.asciiedges)
3902 graphmod.asciiedges)
3901
3903
3902 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3904 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3903 return 0
3905 return 0
3904
3906
3905 if opts.get('bundle') and opts.get('subrepos'):
3907 if opts.get('bundle') and opts.get('subrepos'):
3906 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3908 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3907
3909
3908 if opts.get('bookmarks'):
3910 if opts.get('bookmarks'):
3909 source, branches = hg.parseurl(ui.expandpath(source),
3911 source, branches = hg.parseurl(ui.expandpath(source),
3910 opts.get('branch'))
3912 opts.get('branch'))
3911 other = hg.peer(repo, opts, source)
3913 other = hg.peer(repo, opts, source)
3912 if 'bookmarks' not in other.listkeys('namespaces'):
3914 if 'bookmarks' not in other.listkeys('namespaces'):
3913 ui.warn(_("remote doesn't support bookmarks\n"))
3915 ui.warn(_("remote doesn't support bookmarks\n"))
3914 return 0
3916 return 0
3915 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3917 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3916 return bookmarks.diff(ui, repo, other)
3918 return bookmarks.diff(ui, repo, other)
3917
3919
3918 repo._subtoppath = ui.expandpath(source)
3920 repo._subtoppath = ui.expandpath(source)
3919 try:
3921 try:
3920 return hg.incoming(ui, repo, source, opts)
3922 return hg.incoming(ui, repo, source, opts)
3921 finally:
3923 finally:
3922 del repo._subtoppath
3924 del repo._subtoppath
3923
3925
3924
3926
3925 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3927 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3926 def init(ui, dest=".", **opts):
3928 def init(ui, dest=".", **opts):
3927 """create a new repository in the given directory
3929 """create a new repository in the given directory
3928
3930
3929 Initialize a new repository in the given directory. If the given
3931 Initialize a new repository in the given directory. If the given
3930 directory does not exist, it will be created.
3932 directory does not exist, it will be created.
3931
3933
3932 If no directory is given, the current directory is used.
3934 If no directory is given, the current directory is used.
3933
3935
3934 It is possible to specify an ``ssh://`` URL as the destination.
3936 It is possible to specify an ``ssh://`` URL as the destination.
3935 See :hg:`help urls` for more information.
3937 See :hg:`help urls` for more information.
3936
3938
3937 Returns 0 on success.
3939 Returns 0 on success.
3938 """
3940 """
3939 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3941 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3940
3942
3941 @command('locate',
3943 @command('locate',
3942 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3944 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3943 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3945 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3944 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3946 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3945 ] + walkopts,
3947 ] + walkopts,
3946 _('[OPTION]... [PATTERN]...'))
3948 _('[OPTION]... [PATTERN]...'))
3947 def locate(ui, repo, *pats, **opts):
3949 def locate(ui, repo, *pats, **opts):
3948 """locate files matching specific patterns
3950 """locate files matching specific patterns
3949
3951
3950 Print files under Mercurial control in the working directory whose
3952 Print files under Mercurial control in the working directory whose
3951 names match the given patterns.
3953 names match the given patterns.
3952
3954
3953 By default, this command searches all directories in the working
3955 By default, this command searches all directories in the working
3954 directory. To search just the current directory and its
3956 directory. To search just the current directory and its
3955 subdirectories, use "--include .".
3957 subdirectories, use "--include .".
3956
3958
3957 If no patterns are given to match, this command prints the names
3959 If no patterns are given to match, this command prints the names
3958 of all files under Mercurial control in the working directory.
3960 of all files under Mercurial control in the working directory.
3959
3961
3960 If you want to feed the output of this command into the "xargs"
3962 If you want to feed the output of this command into the "xargs"
3961 command, use the -0 option to both this command and "xargs". This
3963 command, use the -0 option to both this command and "xargs". This
3962 will avoid the problem of "xargs" treating single filenames that
3964 will avoid the problem of "xargs" treating single filenames that
3963 contain whitespace as multiple filenames.
3965 contain whitespace as multiple filenames.
3964
3966
3965 Returns 0 if a match is found, 1 otherwise.
3967 Returns 0 if a match is found, 1 otherwise.
3966 """
3968 """
3967 end = opts.get('print0') and '\0' or '\n'
3969 end = opts.get('print0') and '\0' or '\n'
3968 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3970 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3969
3971
3970 ret = 1
3972 ret = 1
3971 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3973 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3972 m.bad = lambda x, y: False
3974 m.bad = lambda x, y: False
3973 for abs in repo[rev].walk(m):
3975 for abs in repo[rev].walk(m):
3974 if not rev and abs not in repo.dirstate:
3976 if not rev and abs not in repo.dirstate:
3975 continue
3977 continue
3976 if opts.get('fullpath'):
3978 if opts.get('fullpath'):
3977 ui.write(repo.wjoin(abs), end)
3979 ui.write(repo.wjoin(abs), end)
3978 else:
3980 else:
3979 ui.write(((pats and m.rel(abs)) or abs), end)
3981 ui.write(((pats and m.rel(abs)) or abs), end)
3980 ret = 0
3982 ret = 0
3981
3983
3982 return ret
3984 return ret
3983
3985
3984 @command('^log|history',
3986 @command('^log|history',
3985 [('f', 'follow', None,
3987 [('f', 'follow', None,
3986 _('follow changeset history, or file history across copies and renames')),
3988 _('follow changeset history, or file history across copies and renames')),
3987 ('', 'follow-first', None,
3989 ('', 'follow-first', None,
3988 _('only follow the first parent of merge changesets (DEPRECATED)')),
3990 _('only follow the first parent of merge changesets (DEPRECATED)')),
3989 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3991 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3990 ('C', 'copies', None, _('show copied files')),
3992 ('C', 'copies', None, _('show copied files')),
3991 ('k', 'keyword', [],
3993 ('k', 'keyword', [],
3992 _('do case-insensitive search for a given text'), _('TEXT')),
3994 _('do case-insensitive search for a given text'), _('TEXT')),
3993 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3995 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3994 ('', 'removed', None, _('include revisions where files were removed')),
3996 ('', 'removed', None, _('include revisions where files were removed')),
3995 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3997 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3996 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3998 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3997 ('', 'only-branch', [],
3999 ('', 'only-branch', [],
3998 _('show only changesets within the given named branch (DEPRECATED)'),
4000 _('show only changesets within the given named branch (DEPRECATED)'),
3999 _('BRANCH')),
4001 _('BRANCH')),
4000 ('b', 'branch', [],
4002 ('b', 'branch', [],
4001 _('show changesets within the given named branch'), _('BRANCH')),
4003 _('show changesets within the given named branch'), _('BRANCH')),
4002 ('P', 'prune', [],
4004 ('P', 'prune', [],
4003 _('do not display revision or any of its ancestors'), _('REV')),
4005 _('do not display revision or any of its ancestors'), _('REV')),
4004 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4006 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4005 ] + logopts + walkopts,
4007 ] + logopts + walkopts,
4006 _('[OPTION]... [FILE]'))
4008 _('[OPTION]... [FILE]'))
4007 def log(ui, repo, *pats, **opts):
4009 def log(ui, repo, *pats, **opts):
4008 """show revision history of entire repository or files
4010 """show revision history of entire repository or files
4009
4011
4010 Print the revision history of the specified files or the entire
4012 Print the revision history of the specified files or the entire
4011 project.
4013 project.
4012
4014
4013 If no revision range is specified, the default is ``tip:0`` unless
4015 If no revision range is specified, the default is ``tip:0`` unless
4014 --follow is set, in which case the working directory parent is
4016 --follow is set, in which case the working directory parent is
4015 used as the starting revision.
4017 used as the starting revision.
4016
4018
4017 File history is shown without following rename or copy history of
4019 File history is shown without following rename or copy history of
4018 files. Use -f/--follow with a filename to follow history across
4020 files. Use -f/--follow with a filename to follow history across
4019 renames and copies. --follow without a filename will only show
4021 renames and copies. --follow without a filename will only show
4020 ancestors or descendants of the starting revision.
4022 ancestors or descendants of the starting revision.
4021
4023
4022 By default this command prints revision number and changeset id,
4024 By default this command prints revision number and changeset id,
4023 tags, non-trivial parents, user, date and time, and a summary for
4025 tags, non-trivial parents, user, date and time, and a summary for
4024 each commit. When the -v/--verbose switch is used, the list of
4026 each commit. When the -v/--verbose switch is used, the list of
4025 changed files and full commit message are shown.
4027 changed files and full commit message are shown.
4026
4028
4027 .. note::
4029 .. note::
4028 log -p/--patch may generate unexpected diff output for merge
4030 log -p/--patch may generate unexpected diff output for merge
4029 changesets, as it will only compare the merge changeset against
4031 changesets, as it will only compare the merge changeset against
4030 its first parent. Also, only files different from BOTH parents
4032 its first parent. Also, only files different from BOTH parents
4031 will appear in files:.
4033 will appear in files:.
4032
4034
4033 .. note::
4035 .. note::
4034 for performance reasons, log FILE may omit duplicate changes
4036 for performance reasons, log FILE may omit duplicate changes
4035 made on branches and will not show deletions. To see all
4037 made on branches and will not show deletions. To see all
4036 changes including duplicates and deletions, use the --removed
4038 changes including duplicates and deletions, use the --removed
4037 switch.
4039 switch.
4038
4040
4039 .. container:: verbose
4041 .. container:: verbose
4040
4042
4041 Some examples:
4043 Some examples:
4042
4044
4043 - changesets with full descriptions and file lists::
4045 - changesets with full descriptions and file lists::
4044
4046
4045 hg log -v
4047 hg log -v
4046
4048
4047 - changesets ancestral to the working directory::
4049 - changesets ancestral to the working directory::
4048
4050
4049 hg log -f
4051 hg log -f
4050
4052
4051 - last 10 commits on the current branch::
4053 - last 10 commits on the current branch::
4052
4054
4053 hg log -l 10 -b .
4055 hg log -l 10 -b .
4054
4056
4055 - changesets showing all modifications of a file, including removals::
4057 - changesets showing all modifications of a file, including removals::
4056
4058
4057 hg log --removed file.c
4059 hg log --removed file.c
4058
4060
4059 - all changesets that touch a directory, with diffs, excluding merges::
4061 - all changesets that touch a directory, with diffs, excluding merges::
4060
4062
4061 hg log -Mp lib/
4063 hg log -Mp lib/
4062
4064
4063 - all revision numbers that match a keyword::
4065 - all revision numbers that match a keyword::
4064
4066
4065 hg log -k bug --template "{rev}\\n"
4067 hg log -k bug --template "{rev}\\n"
4066
4068
4067 - check if a given changeset is included is a tagged release::
4069 - check if a given changeset is included is a tagged release::
4068
4070
4069 hg log -r "a21ccf and ancestor(1.9)"
4071 hg log -r "a21ccf and ancestor(1.9)"
4070
4072
4071 - find all changesets by some user in a date range::
4073 - find all changesets by some user in a date range::
4072
4074
4073 hg log -k alice -d "may 2008 to jul 2008"
4075 hg log -k alice -d "may 2008 to jul 2008"
4074
4076
4075 - summary of all changesets after the last tag::
4077 - summary of all changesets after the last tag::
4076
4078
4077 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4079 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4078
4080
4079 See :hg:`help dates` for a list of formats valid for -d/--date.
4081 See :hg:`help dates` for a list of formats valid for -d/--date.
4080
4082
4081 See :hg:`help revisions` and :hg:`help revsets` for more about
4083 See :hg:`help revisions` and :hg:`help revsets` for more about
4082 specifying revisions.
4084 specifying revisions.
4083
4085
4084 See :hg:`help templates` for more about pre-packaged styles and
4086 See :hg:`help templates` for more about pre-packaged styles and
4085 specifying custom templates.
4087 specifying custom templates.
4086
4088
4087 Returns 0 on success.
4089 Returns 0 on success.
4088 """
4090 """
4089 if opts.get('graph'):
4091 if opts.get('graph'):
4090 return cmdutil.graphlog(ui, repo, *pats, **opts)
4092 return cmdutil.graphlog(ui, repo, *pats, **opts)
4091
4093
4092 matchfn = scmutil.match(repo[None], pats, opts)
4094 matchfn = scmutil.match(repo[None], pats, opts)
4093 limit = cmdutil.loglimit(opts)
4095 limit = cmdutil.loglimit(opts)
4094 count = 0
4096 count = 0
4095
4097
4096 getrenamed, endrev = None, None
4098 getrenamed, endrev = None, None
4097 if opts.get('copies'):
4099 if opts.get('copies'):
4098 if opts.get('rev'):
4100 if opts.get('rev'):
4099 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4101 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4100 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4102 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4101
4103
4102 df = False
4104 df = False
4103 if opts.get("date"):
4105 if opts.get("date"):
4104 df = util.matchdate(opts["date"])
4106 df = util.matchdate(opts["date"])
4105
4107
4106 branches = opts.get('branch', []) + opts.get('only_branch', [])
4108 branches = opts.get('branch', []) + opts.get('only_branch', [])
4107 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4109 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4108
4110
4109 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4111 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4110 def prep(ctx, fns):
4112 def prep(ctx, fns):
4111 rev = ctx.rev()
4113 rev = ctx.rev()
4112 parents = [p for p in repo.changelog.parentrevs(rev)
4114 parents = [p for p in repo.changelog.parentrevs(rev)
4113 if p != nullrev]
4115 if p != nullrev]
4114 if opts.get('no_merges') and len(parents) == 2:
4116 if opts.get('no_merges') and len(parents) == 2:
4115 return
4117 return
4116 if opts.get('only_merges') and len(parents) != 2:
4118 if opts.get('only_merges') and len(parents) != 2:
4117 return
4119 return
4118 if opts.get('branch') and ctx.branch() not in opts['branch']:
4120 if opts.get('branch') and ctx.branch() not in opts['branch']:
4119 return
4121 return
4120 if not opts.get('hidden') and ctx.hidden():
4122 if not opts.get('hidden') and ctx.hidden():
4121 return
4123 return
4122 if df and not df(ctx.date()[0]):
4124 if df and not df(ctx.date()[0]):
4123 return
4125 return
4124
4126
4125 lower = encoding.lower
4127 lower = encoding.lower
4126 if opts.get('user'):
4128 if opts.get('user'):
4127 luser = lower(ctx.user())
4129 luser = lower(ctx.user())
4128 for k in [lower(x) for x in opts['user']]:
4130 for k in [lower(x) for x in opts['user']]:
4129 if (k in luser):
4131 if (k in luser):
4130 break
4132 break
4131 else:
4133 else:
4132 return
4134 return
4133 if opts.get('keyword'):
4135 if opts.get('keyword'):
4134 luser = lower(ctx.user())
4136 luser = lower(ctx.user())
4135 ldesc = lower(ctx.description())
4137 ldesc = lower(ctx.description())
4136 lfiles = lower(" ".join(ctx.files()))
4138 lfiles = lower(" ".join(ctx.files()))
4137 for k in [lower(x) for x in opts['keyword']]:
4139 for k in [lower(x) for x in opts['keyword']]:
4138 if (k in luser or k in ldesc or k in lfiles):
4140 if (k in luser or k in ldesc or k in lfiles):
4139 break
4141 break
4140 else:
4142 else:
4141 return
4143 return
4142
4144
4143 copies = None
4145 copies = None
4144 if getrenamed is not None and rev:
4146 if getrenamed is not None and rev:
4145 copies = []
4147 copies = []
4146 for fn in ctx.files():
4148 for fn in ctx.files():
4147 rename = getrenamed(fn, rev)
4149 rename = getrenamed(fn, rev)
4148 if rename:
4150 if rename:
4149 copies.append((fn, rename[0]))
4151 copies.append((fn, rename[0]))
4150
4152
4151 revmatchfn = None
4153 revmatchfn = None
4152 if opts.get('patch') or opts.get('stat'):
4154 if opts.get('patch') or opts.get('stat'):
4153 if opts.get('follow') or opts.get('follow_first'):
4155 if opts.get('follow') or opts.get('follow_first'):
4154 # note: this might be wrong when following through merges
4156 # note: this might be wrong when following through merges
4155 revmatchfn = scmutil.match(repo[None], fns, default='path')
4157 revmatchfn = scmutil.match(repo[None], fns, default='path')
4156 else:
4158 else:
4157 revmatchfn = matchfn
4159 revmatchfn = matchfn
4158
4160
4159 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4161 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4160
4162
4161 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4163 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4162 if count == limit:
4164 if count == limit:
4163 break
4165 break
4164 if displayer.flush(ctx.rev()):
4166 if displayer.flush(ctx.rev()):
4165 count += 1
4167 count += 1
4166 displayer.close()
4168 displayer.close()
4167
4169
4168 @command('manifest',
4170 @command('manifest',
4169 [('r', 'rev', '', _('revision to display'), _('REV')),
4171 [('r', 'rev', '', _('revision to display'), _('REV')),
4170 ('', 'all', False, _("list files from all revisions"))],
4172 ('', 'all', False, _("list files from all revisions"))],
4171 _('[-r REV]'))
4173 _('[-r REV]'))
4172 def manifest(ui, repo, node=None, rev=None, **opts):
4174 def manifest(ui, repo, node=None, rev=None, **opts):
4173 """output the current or given revision of the project manifest
4175 """output the current or given revision of the project manifest
4174
4176
4175 Print a list of version controlled files for the given revision.
4177 Print a list of version controlled files for the given revision.
4176 If no revision is given, the first parent of the working directory
4178 If no revision is given, the first parent of the working directory
4177 is used, or the null revision if no revision is checked out.
4179 is used, or the null revision if no revision is checked out.
4178
4180
4179 With -v, print file permissions, symlink and executable bits.
4181 With -v, print file permissions, symlink and executable bits.
4180 With --debug, print file revision hashes.
4182 With --debug, print file revision hashes.
4181
4183
4182 If option --all is specified, the list of all files from all revisions
4184 If option --all is specified, the list of all files from all revisions
4183 is printed. This includes deleted and renamed files.
4185 is printed. This includes deleted and renamed files.
4184
4186
4185 Returns 0 on success.
4187 Returns 0 on success.
4186 """
4188 """
4187 if opts.get('all'):
4189 if opts.get('all'):
4188 if rev or node:
4190 if rev or node:
4189 raise util.Abort(_("can't specify a revision with --all"))
4191 raise util.Abort(_("can't specify a revision with --all"))
4190
4192
4191 res = []
4193 res = []
4192 prefix = "data/"
4194 prefix = "data/"
4193 suffix = ".i"
4195 suffix = ".i"
4194 plen = len(prefix)
4196 plen = len(prefix)
4195 slen = len(suffix)
4197 slen = len(suffix)
4196 lock = repo.lock()
4198 lock = repo.lock()
4197 try:
4199 try:
4198 for fn, b, size in repo.store.datafiles():
4200 for fn, b, size in repo.store.datafiles():
4199 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4201 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4200 res.append(fn[plen:-slen])
4202 res.append(fn[plen:-slen])
4201 finally:
4203 finally:
4202 lock.release()
4204 lock.release()
4203 for f in res:
4205 for f in res:
4204 ui.write("%s\n" % f)
4206 ui.write("%s\n" % f)
4205 return
4207 return
4206
4208
4207 if rev and node:
4209 if rev and node:
4208 raise util.Abort(_("please specify just one revision"))
4210 raise util.Abort(_("please specify just one revision"))
4209
4211
4210 if not node:
4212 if not node:
4211 node = rev
4213 node = rev
4212
4214
4213 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4215 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4214 ctx = scmutil.revsingle(repo, node)
4216 ctx = scmutil.revsingle(repo, node)
4215 for f in ctx:
4217 for f in ctx:
4216 if ui.debugflag:
4218 if ui.debugflag:
4217 ui.write("%40s " % hex(ctx.manifest()[f]))
4219 ui.write("%40s " % hex(ctx.manifest()[f]))
4218 if ui.verbose:
4220 if ui.verbose:
4219 ui.write(decor[ctx.flags(f)])
4221 ui.write(decor[ctx.flags(f)])
4220 ui.write("%s\n" % f)
4222 ui.write("%s\n" % f)
4221
4223
4222 @command('^merge',
4224 @command('^merge',
4223 [('f', 'force', None, _('force a merge with outstanding changes')),
4225 [('f', 'force', None, _('force a merge with outstanding changes')),
4224 ('r', 'rev', '', _('revision to merge'), _('REV')),
4226 ('r', 'rev', '', _('revision to merge'), _('REV')),
4225 ('P', 'preview', None,
4227 ('P', 'preview', None,
4226 _('review revisions to merge (no merge is performed)'))
4228 _('review revisions to merge (no merge is performed)'))
4227 ] + mergetoolopts,
4229 ] + mergetoolopts,
4228 _('[-P] [-f] [[-r] REV]'))
4230 _('[-P] [-f] [[-r] REV]'))
4229 def merge(ui, repo, node=None, **opts):
4231 def merge(ui, repo, node=None, **opts):
4230 """merge working directory with another revision
4232 """merge working directory with another revision
4231
4233
4232 The current working directory is updated with all changes made in
4234 The current working directory is updated with all changes made in
4233 the requested revision since the last common predecessor revision.
4235 the requested revision since the last common predecessor revision.
4234
4236
4235 Files that changed between either parent are marked as changed for
4237 Files that changed between either parent are marked as changed for
4236 the next commit and a commit must be performed before any further
4238 the next commit and a commit must be performed before any further
4237 updates to the repository are allowed. The next commit will have
4239 updates to the repository are allowed. The next commit will have
4238 two parents.
4240 two parents.
4239
4241
4240 ``--tool`` can be used to specify the merge tool used for file
4242 ``--tool`` can be used to specify the merge tool used for file
4241 merges. It overrides the HGMERGE environment variable and your
4243 merges. It overrides the HGMERGE environment variable and your
4242 configuration files. See :hg:`help merge-tools` for options.
4244 configuration files. See :hg:`help merge-tools` for options.
4243
4245
4244 If no revision is specified, the working directory's parent is a
4246 If no revision is specified, the working directory's parent is a
4245 head revision, and the current branch contains exactly one other
4247 head revision, and the current branch contains exactly one other
4246 head, the other head is merged with by default. Otherwise, an
4248 head, the other head is merged with by default. Otherwise, an
4247 explicit revision with which to merge with must be provided.
4249 explicit revision with which to merge with must be provided.
4248
4250
4249 :hg:`resolve` must be used to resolve unresolved files.
4251 :hg:`resolve` must be used to resolve unresolved files.
4250
4252
4251 To undo an uncommitted merge, use :hg:`update --clean .` which
4253 To undo an uncommitted merge, use :hg:`update --clean .` which
4252 will check out a clean copy of the original merge parent, losing
4254 will check out a clean copy of the original merge parent, losing
4253 all changes.
4255 all changes.
4254
4256
4255 Returns 0 on success, 1 if there are unresolved files.
4257 Returns 0 on success, 1 if there are unresolved files.
4256 """
4258 """
4257
4259
4258 if opts.get('rev') and node:
4260 if opts.get('rev') and node:
4259 raise util.Abort(_("please specify just one revision"))
4261 raise util.Abort(_("please specify just one revision"))
4260 if not node:
4262 if not node:
4261 node = opts.get('rev')
4263 node = opts.get('rev')
4262
4264
4263 if node:
4265 if node:
4264 node = scmutil.revsingle(repo, node).node()
4266 node = scmutil.revsingle(repo, node).node()
4265
4267
4266 if not node and repo._bookmarkcurrent:
4268 if not node and repo._bookmarkcurrent:
4267 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4269 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4268 curhead = repo[repo._bookmarkcurrent]
4270 curhead = repo[repo._bookmarkcurrent]
4269 if len(bmheads) == 2:
4271 if len(bmheads) == 2:
4270 if curhead == bmheads[0]:
4272 if curhead == bmheads[0]:
4271 node = bmheads[1]
4273 node = bmheads[1]
4272 else:
4274 else:
4273 node = bmheads[0]
4275 node = bmheads[0]
4274 elif len(bmheads) > 2:
4276 elif len(bmheads) > 2:
4275 raise util.Abort(_("multiple matching bookmarks to merge - "
4277 raise util.Abort(_("multiple matching bookmarks to merge - "
4276 "please merge with an explicit rev or bookmark"),
4278 "please merge with an explicit rev or bookmark"),
4277 hint=_("run 'hg heads' to see all heads"))
4279 hint=_("run 'hg heads' to see all heads"))
4278 elif len(bmheads) <= 1:
4280 elif len(bmheads) <= 1:
4279 raise util.Abort(_("no matching bookmark to merge - "
4281 raise util.Abort(_("no matching bookmark to merge - "
4280 "please merge with an explicit rev or bookmark"),
4282 "please merge with an explicit rev or bookmark"),
4281 hint=_("run 'hg heads' to see all heads"))
4283 hint=_("run 'hg heads' to see all heads"))
4282
4284
4283 if not node and not repo._bookmarkcurrent:
4285 if not node and not repo._bookmarkcurrent:
4284 branch = repo[None].branch()
4286 branch = repo[None].branch()
4285 bheads = repo.branchheads(branch)
4287 bheads = repo.branchheads(branch)
4286 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4288 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4287
4289
4288 if len(nbhs) > 2:
4290 if len(nbhs) > 2:
4289 raise util.Abort(_("branch '%s' has %d heads - "
4291 raise util.Abort(_("branch '%s' has %d heads - "
4290 "please merge with an explicit rev")
4292 "please merge with an explicit rev")
4291 % (branch, len(bheads)),
4293 % (branch, len(bheads)),
4292 hint=_("run 'hg heads .' to see heads"))
4294 hint=_("run 'hg heads .' to see heads"))
4293
4295
4294 parent = repo.dirstate.p1()
4296 parent = repo.dirstate.p1()
4295 if len(nbhs) <= 1:
4297 if len(nbhs) <= 1:
4296 if len(bheads) > 1:
4298 if len(bheads) > 1:
4297 raise util.Abort(_("heads are bookmarked - "
4299 raise util.Abort(_("heads are bookmarked - "
4298 "please merge with an explicit rev"),
4300 "please merge with an explicit rev"),
4299 hint=_("run 'hg heads' to see all heads"))
4301 hint=_("run 'hg heads' to see all heads"))
4300 if len(repo.heads()) > 1:
4302 if len(repo.heads()) > 1:
4301 raise util.Abort(_("branch '%s' has one head - "
4303 raise util.Abort(_("branch '%s' has one head - "
4302 "please merge with an explicit rev")
4304 "please merge with an explicit rev")
4303 % branch,
4305 % branch,
4304 hint=_("run 'hg heads' to see all heads"))
4306 hint=_("run 'hg heads' to see all heads"))
4305 msg, hint = _('nothing to merge'), None
4307 msg, hint = _('nothing to merge'), None
4306 if parent != repo.lookup(branch):
4308 if parent != repo.lookup(branch):
4307 hint = _("use 'hg update' instead")
4309 hint = _("use 'hg update' instead")
4308 raise util.Abort(msg, hint=hint)
4310 raise util.Abort(msg, hint=hint)
4309
4311
4310 if parent not in bheads:
4312 if parent not in bheads:
4311 raise util.Abort(_('working directory not at a head revision'),
4313 raise util.Abort(_('working directory not at a head revision'),
4312 hint=_("use 'hg update' or merge with an "
4314 hint=_("use 'hg update' or merge with an "
4313 "explicit revision"))
4315 "explicit revision"))
4314 if parent == nbhs[0]:
4316 if parent == nbhs[0]:
4315 node = nbhs[-1]
4317 node = nbhs[-1]
4316 else:
4318 else:
4317 node = nbhs[0]
4319 node = nbhs[0]
4318
4320
4319 if opts.get('preview'):
4321 if opts.get('preview'):
4320 # find nodes that are ancestors of p2 but not of p1
4322 # find nodes that are ancestors of p2 but not of p1
4321 p1 = repo.lookup('.')
4323 p1 = repo.lookup('.')
4322 p2 = repo.lookup(node)
4324 p2 = repo.lookup(node)
4323 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4325 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4324
4326
4325 displayer = cmdutil.show_changeset(ui, repo, opts)
4327 displayer = cmdutil.show_changeset(ui, repo, opts)
4326 for node in nodes:
4328 for node in nodes:
4327 displayer.show(repo[node])
4329 displayer.show(repo[node])
4328 displayer.close()
4330 displayer.close()
4329 return 0
4331 return 0
4330
4332
4331 try:
4333 try:
4332 # ui.forcemerge is an internal variable, do not document
4334 # ui.forcemerge is an internal variable, do not document
4333 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4335 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4334 return hg.merge(repo, node, force=opts.get('force'))
4336 return hg.merge(repo, node, force=opts.get('force'))
4335 finally:
4337 finally:
4336 ui.setconfig('ui', 'forcemerge', '')
4338 ui.setconfig('ui', 'forcemerge', '')
4337
4339
4338 @command('outgoing|out',
4340 @command('outgoing|out',
4339 [('f', 'force', None, _('run even when the destination is unrelated')),
4341 [('f', 'force', None, _('run even when the destination is unrelated')),
4340 ('r', 'rev', [],
4342 ('r', 'rev', [],
4341 _('a changeset intended to be included in the destination'), _('REV')),
4343 _('a changeset intended to be included in the destination'), _('REV')),
4342 ('n', 'newest-first', None, _('show newest record first')),
4344 ('n', 'newest-first', None, _('show newest record first')),
4343 ('B', 'bookmarks', False, _('compare bookmarks')),
4345 ('B', 'bookmarks', False, _('compare bookmarks')),
4344 ('b', 'branch', [], _('a specific branch you would like to push'),
4346 ('b', 'branch', [], _('a specific branch you would like to push'),
4345 _('BRANCH')),
4347 _('BRANCH')),
4346 ] + logopts + remoteopts + subrepoopts,
4348 ] + logopts + remoteopts + subrepoopts,
4347 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4349 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4348 def outgoing(ui, repo, dest=None, **opts):
4350 def outgoing(ui, repo, dest=None, **opts):
4349 """show changesets not found in the destination
4351 """show changesets not found in the destination
4350
4352
4351 Show changesets not found in the specified destination repository
4353 Show changesets not found in the specified destination repository
4352 or the default push location. These are the changesets that would
4354 or the default push location. These are the changesets that would
4353 be pushed if a push was requested.
4355 be pushed if a push was requested.
4354
4356
4355 See pull for details of valid destination formats.
4357 See pull for details of valid destination formats.
4356
4358
4357 Returns 0 if there are outgoing changes, 1 otherwise.
4359 Returns 0 if there are outgoing changes, 1 otherwise.
4358 """
4360 """
4359 if opts.get('graph'):
4361 if opts.get('graph'):
4360 cmdutil.checkunsupportedgraphflags([], opts)
4362 cmdutil.checkunsupportedgraphflags([], opts)
4361 o = hg._outgoing(ui, repo, dest, opts)
4363 o = hg._outgoing(ui, repo, dest, opts)
4362 if o is None:
4364 if o is None:
4363 return
4365 return
4364
4366
4365 revdag = cmdutil.graphrevs(repo, o, opts)
4367 revdag = cmdutil.graphrevs(repo, o, opts)
4366 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4368 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4367 showparents = [ctx.node() for ctx in repo[None].parents()]
4369 showparents = [ctx.node() for ctx in repo[None].parents()]
4368 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4370 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4369 graphmod.asciiedges)
4371 graphmod.asciiedges)
4370 return 0
4372 return 0
4371
4373
4372 if opts.get('bookmarks'):
4374 if opts.get('bookmarks'):
4373 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4375 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4374 dest, branches = hg.parseurl(dest, opts.get('branch'))
4376 dest, branches = hg.parseurl(dest, opts.get('branch'))
4375 other = hg.peer(repo, opts, dest)
4377 other = hg.peer(repo, opts, dest)
4376 if 'bookmarks' not in other.listkeys('namespaces'):
4378 if 'bookmarks' not in other.listkeys('namespaces'):
4377 ui.warn(_("remote doesn't support bookmarks\n"))
4379 ui.warn(_("remote doesn't support bookmarks\n"))
4378 return 0
4380 return 0
4379 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4381 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4380 return bookmarks.diff(ui, other, repo)
4382 return bookmarks.diff(ui, other, repo)
4381
4383
4382 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4384 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4383 try:
4385 try:
4384 return hg.outgoing(ui, repo, dest, opts)
4386 return hg.outgoing(ui, repo, dest, opts)
4385 finally:
4387 finally:
4386 del repo._subtoppath
4388 del repo._subtoppath
4387
4389
4388 @command('parents',
4390 @command('parents',
4389 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4391 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4390 ] + templateopts,
4392 ] + templateopts,
4391 _('[-r REV] [FILE]'))
4393 _('[-r REV] [FILE]'))
4392 def parents(ui, repo, file_=None, **opts):
4394 def parents(ui, repo, file_=None, **opts):
4393 """show the parents of the working directory or revision
4395 """show the parents of the working directory or revision
4394
4396
4395 Print the working directory's parent revisions. If a revision is
4397 Print the working directory's parent revisions. If a revision is
4396 given via -r/--rev, the parent of that revision will be printed.
4398 given via -r/--rev, the parent of that revision will be printed.
4397 If a file argument is given, the revision in which the file was
4399 If a file argument is given, the revision in which the file was
4398 last changed (before the working directory revision or the
4400 last changed (before the working directory revision or the
4399 argument to --rev if given) is printed.
4401 argument to --rev if given) is printed.
4400
4402
4401 Returns 0 on success.
4403 Returns 0 on success.
4402 """
4404 """
4403
4405
4404 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4406 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4405
4407
4406 if file_:
4408 if file_:
4407 m = scmutil.match(ctx, (file_,), opts)
4409 m = scmutil.match(ctx, (file_,), opts)
4408 if m.anypats() or len(m.files()) != 1:
4410 if m.anypats() or len(m.files()) != 1:
4409 raise util.Abort(_('can only specify an explicit filename'))
4411 raise util.Abort(_('can only specify an explicit filename'))
4410 file_ = m.files()[0]
4412 file_ = m.files()[0]
4411 filenodes = []
4413 filenodes = []
4412 for cp in ctx.parents():
4414 for cp in ctx.parents():
4413 if not cp:
4415 if not cp:
4414 continue
4416 continue
4415 try:
4417 try:
4416 filenodes.append(cp.filenode(file_))
4418 filenodes.append(cp.filenode(file_))
4417 except error.LookupError:
4419 except error.LookupError:
4418 pass
4420 pass
4419 if not filenodes:
4421 if not filenodes:
4420 raise util.Abort(_("'%s' not found in manifest!") % file_)
4422 raise util.Abort(_("'%s' not found in manifest!") % file_)
4421 fl = repo.file(file_)
4423 fl = repo.file(file_)
4422 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4424 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4423 else:
4425 else:
4424 p = [cp.node() for cp in ctx.parents()]
4426 p = [cp.node() for cp in ctx.parents()]
4425
4427
4426 displayer = cmdutil.show_changeset(ui, repo, opts)
4428 displayer = cmdutil.show_changeset(ui, repo, opts)
4427 for n in p:
4429 for n in p:
4428 if n != nullid:
4430 if n != nullid:
4429 displayer.show(repo[n])
4431 displayer.show(repo[n])
4430 displayer.close()
4432 displayer.close()
4431
4433
4432 @command('paths', [], _('[NAME]'))
4434 @command('paths', [], _('[NAME]'))
4433 def paths(ui, repo, search=None):
4435 def paths(ui, repo, search=None):
4434 """show aliases for remote repositories
4436 """show aliases for remote repositories
4435
4437
4436 Show definition of symbolic path name NAME. If no name is given,
4438 Show definition of symbolic path name NAME. If no name is given,
4437 show definition of all available names.
4439 show definition of all available names.
4438
4440
4439 Option -q/--quiet suppresses all output when searching for NAME
4441 Option -q/--quiet suppresses all output when searching for NAME
4440 and shows only the path names when listing all definitions.
4442 and shows only the path names when listing all definitions.
4441
4443
4442 Path names are defined in the [paths] section of your
4444 Path names are defined in the [paths] section of your
4443 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4445 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4444 repository, ``.hg/hgrc`` is used, too.
4446 repository, ``.hg/hgrc`` is used, too.
4445
4447
4446 The path names ``default`` and ``default-push`` have a special
4448 The path names ``default`` and ``default-push`` have a special
4447 meaning. When performing a push or pull operation, they are used
4449 meaning. When performing a push or pull operation, they are used
4448 as fallbacks if no location is specified on the command-line.
4450 as fallbacks if no location is specified on the command-line.
4449 When ``default-push`` is set, it will be used for push and
4451 When ``default-push`` is set, it will be used for push and
4450 ``default`` will be used for pull; otherwise ``default`` is used
4452 ``default`` will be used for pull; otherwise ``default`` is used
4451 as the fallback for both. When cloning a repository, the clone
4453 as the fallback for both. When cloning a repository, the clone
4452 source is written as ``default`` in ``.hg/hgrc``. Note that
4454 source is written as ``default`` in ``.hg/hgrc``. Note that
4453 ``default`` and ``default-push`` apply to all inbound (e.g.
4455 ``default`` and ``default-push`` apply to all inbound (e.g.
4454 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4456 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4455 :hg:`bundle`) operations.
4457 :hg:`bundle`) operations.
4456
4458
4457 See :hg:`help urls` for more information.
4459 See :hg:`help urls` for more information.
4458
4460
4459 Returns 0 on success.
4461 Returns 0 on success.
4460 """
4462 """
4461 if search:
4463 if search:
4462 for name, path in ui.configitems("paths"):
4464 for name, path in ui.configitems("paths"):
4463 if name == search:
4465 if name == search:
4464 ui.status("%s\n" % util.hidepassword(path))
4466 ui.status("%s\n" % util.hidepassword(path))
4465 return
4467 return
4466 if not ui.quiet:
4468 if not ui.quiet:
4467 ui.warn(_("not found!\n"))
4469 ui.warn(_("not found!\n"))
4468 return 1
4470 return 1
4469 else:
4471 else:
4470 for name, path in ui.configitems("paths"):
4472 for name, path in ui.configitems("paths"):
4471 if ui.quiet:
4473 if ui.quiet:
4472 ui.write("%s\n" % name)
4474 ui.write("%s\n" % name)
4473 else:
4475 else:
4474 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4476 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4475
4477
4476 @command('^phase',
4478 @command('^phase',
4477 [('p', 'public', False, _('set changeset phase to public')),
4479 [('p', 'public', False, _('set changeset phase to public')),
4478 ('d', 'draft', False, _('set changeset phase to draft')),
4480 ('d', 'draft', False, _('set changeset phase to draft')),
4479 ('s', 'secret', False, _('set changeset phase to secret')),
4481 ('s', 'secret', False, _('set changeset phase to secret')),
4480 ('f', 'force', False, _('allow to move boundary backward')),
4482 ('f', 'force', False, _('allow to move boundary backward')),
4481 ('r', 'rev', [], _('target revision'), _('REV')),
4483 ('r', 'rev', [], _('target revision'), _('REV')),
4482 ],
4484 ],
4483 _('[-p|-d|-s] [-f] [-r] REV...'))
4485 _('[-p|-d|-s] [-f] [-r] REV...'))
4484 def phase(ui, repo, *revs, **opts):
4486 def phase(ui, repo, *revs, **opts):
4485 """set or show the current phase name
4487 """set or show the current phase name
4486
4488
4487 With no argument, show the phase name of specified revisions.
4489 With no argument, show the phase name of specified revisions.
4488
4490
4489 With one of -p/--public, -d/--draft or -s/--secret, change the
4491 With one of -p/--public, -d/--draft or -s/--secret, change the
4490 phase value of the specified revisions.
4492 phase value of the specified revisions.
4491
4493
4492 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4494 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4493 lower phase to an higher phase. Phases are ordered as follows::
4495 lower phase to an higher phase. Phases are ordered as follows::
4494
4496
4495 public < draft < secret
4497 public < draft < secret
4496
4498
4497 Return 0 on success, 1 if no phases were changed or some could not
4499 Return 0 on success, 1 if no phases were changed or some could not
4498 be changed.
4500 be changed.
4499 """
4501 """
4500 # search for a unique phase argument
4502 # search for a unique phase argument
4501 targetphase = None
4503 targetphase = None
4502 for idx, name in enumerate(phases.phasenames):
4504 for idx, name in enumerate(phases.phasenames):
4503 if opts[name]:
4505 if opts[name]:
4504 if targetphase is not None:
4506 if targetphase is not None:
4505 raise util.Abort(_('only one phase can be specified'))
4507 raise util.Abort(_('only one phase can be specified'))
4506 targetphase = idx
4508 targetphase = idx
4507
4509
4508 # look for specified revision
4510 # look for specified revision
4509 revs = list(revs)
4511 revs = list(revs)
4510 revs.extend(opts['rev'])
4512 revs.extend(opts['rev'])
4511 if not revs:
4513 if not revs:
4512 raise util.Abort(_('no revisions specified'))
4514 raise util.Abort(_('no revisions specified'))
4513
4515
4514 revs = scmutil.revrange(repo, revs)
4516 revs = scmutil.revrange(repo, revs)
4515
4517
4516 lock = None
4518 lock = None
4517 ret = 0
4519 ret = 0
4518 if targetphase is None:
4520 if targetphase is None:
4519 # display
4521 # display
4520 for r in revs:
4522 for r in revs:
4521 ctx = repo[r]
4523 ctx = repo[r]
4522 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4524 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4523 else:
4525 else:
4524 lock = repo.lock()
4526 lock = repo.lock()
4525 try:
4527 try:
4526 # set phase
4528 # set phase
4527 if not revs:
4529 if not revs:
4528 raise util.Abort(_('empty revision set'))
4530 raise util.Abort(_('empty revision set'))
4529 nodes = [repo[r].node() for r in revs]
4531 nodes = [repo[r].node() for r in revs]
4530 olddata = repo._phasecache.getphaserevs(repo)[:]
4532 olddata = repo._phasecache.getphaserevs(repo)[:]
4531 phases.advanceboundary(repo, targetphase, nodes)
4533 phases.advanceboundary(repo, targetphase, nodes)
4532 if opts['force']:
4534 if opts['force']:
4533 phases.retractboundary(repo, targetphase, nodes)
4535 phases.retractboundary(repo, targetphase, nodes)
4534 finally:
4536 finally:
4535 lock.release()
4537 lock.release()
4536 newdata = repo._phasecache.getphaserevs(repo)
4538 newdata = repo._phasecache.getphaserevs(repo)
4537 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4539 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4538 rejected = [n for n in nodes
4540 rejected = [n for n in nodes
4539 if newdata[repo[n].rev()] < targetphase]
4541 if newdata[repo[n].rev()] < targetphase]
4540 if rejected:
4542 if rejected:
4541 ui.warn(_('cannot move %i changesets to a more permissive '
4543 ui.warn(_('cannot move %i changesets to a more permissive '
4542 'phase, use --force\n') % len(rejected))
4544 'phase, use --force\n') % len(rejected))
4543 ret = 1
4545 ret = 1
4544 if changes:
4546 if changes:
4545 msg = _('phase changed for %i changesets\n') % changes
4547 msg = _('phase changed for %i changesets\n') % changes
4546 if ret:
4548 if ret:
4547 ui.status(msg)
4549 ui.status(msg)
4548 else:
4550 else:
4549 ui.note(msg)
4551 ui.note(msg)
4550 else:
4552 else:
4551 ui.warn(_('no phases changed\n'))
4553 ui.warn(_('no phases changed\n'))
4552 ret = 1
4554 ret = 1
4553 return ret
4555 return ret
4554
4556
4555 def postincoming(ui, repo, modheads, optupdate, checkout):
4557 def postincoming(ui, repo, modheads, optupdate, checkout):
4556 if modheads == 0:
4558 if modheads == 0:
4557 return
4559 return
4558 if optupdate:
4560 if optupdate:
4559 movemarkfrom = repo['.'].node()
4561 movemarkfrom = repo['.'].node()
4560 try:
4562 try:
4561 ret = hg.update(repo, checkout)
4563 ret = hg.update(repo, checkout)
4562 except util.Abort, inst:
4564 except util.Abort, inst:
4563 ui.warn(_("not updating: %s\n") % str(inst))
4565 ui.warn(_("not updating: %s\n") % str(inst))
4564 return 0
4566 return 0
4565 if not ret and not checkout:
4567 if not ret and not checkout:
4566 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4568 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4567 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4569 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4568 return ret
4570 return ret
4569 if modheads > 1:
4571 if modheads > 1:
4570 currentbranchheads = len(repo.branchheads())
4572 currentbranchheads = len(repo.branchheads())
4571 if currentbranchheads == modheads:
4573 if currentbranchheads == modheads:
4572 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4574 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4573 elif currentbranchheads > 1:
4575 elif currentbranchheads > 1:
4574 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4576 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4575 "merge)\n"))
4577 "merge)\n"))
4576 else:
4578 else:
4577 ui.status(_("(run 'hg heads' to see heads)\n"))
4579 ui.status(_("(run 'hg heads' to see heads)\n"))
4578 else:
4580 else:
4579 ui.status(_("(run 'hg update' to get a working copy)\n"))
4581 ui.status(_("(run 'hg update' to get a working copy)\n"))
4580
4582
4581 @command('^pull',
4583 @command('^pull',
4582 [('u', 'update', None,
4584 [('u', 'update', None,
4583 _('update to new branch head if changesets were pulled')),
4585 _('update to new branch head if changesets were pulled')),
4584 ('f', 'force', None, _('run even when remote repository is unrelated')),
4586 ('f', 'force', None, _('run even when remote repository is unrelated')),
4585 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4587 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4586 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4588 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4587 ('b', 'branch', [], _('a specific branch you would like to pull'),
4589 ('b', 'branch', [], _('a specific branch you would like to pull'),
4588 _('BRANCH')),
4590 _('BRANCH')),
4589 ] + remoteopts,
4591 ] + remoteopts,
4590 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4592 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4591 def pull(ui, repo, source="default", **opts):
4593 def pull(ui, repo, source="default", **opts):
4592 """pull changes from the specified source
4594 """pull changes from the specified source
4593
4595
4594 Pull changes from a remote repository to a local one.
4596 Pull changes from a remote repository to a local one.
4595
4597
4596 This finds all changes from the repository at the specified path
4598 This finds all changes from the repository at the specified path
4597 or URL and adds them to a local repository (the current one unless
4599 or URL and adds them to a local repository (the current one unless
4598 -R is specified). By default, this does not update the copy of the
4600 -R is specified). By default, this does not update the copy of the
4599 project in the working directory.
4601 project in the working directory.
4600
4602
4601 Use :hg:`incoming` if you want to see what would have been added
4603 Use :hg:`incoming` if you want to see what would have been added
4602 by a pull at the time you issued this command. If you then decide
4604 by a pull at the time you issued this command. If you then decide
4603 to add those changes to the repository, you should use :hg:`pull
4605 to add those changes to the repository, you should use :hg:`pull
4604 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4606 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4605
4607
4606 If SOURCE is omitted, the 'default' path will be used.
4608 If SOURCE is omitted, the 'default' path will be used.
4607 See :hg:`help urls` for more information.
4609 See :hg:`help urls` for more information.
4608
4610
4609 Returns 0 on success, 1 if an update had unresolved files.
4611 Returns 0 on success, 1 if an update had unresolved files.
4610 """
4612 """
4611 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4613 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4612 other = hg.peer(repo, opts, source)
4614 other = hg.peer(repo, opts, source)
4613 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4615 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4614 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4616 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4615
4617
4616 if opts.get('bookmark'):
4618 if opts.get('bookmark'):
4617 if not revs:
4619 if not revs:
4618 revs = []
4620 revs = []
4619 rb = other.listkeys('bookmarks')
4621 rb = other.listkeys('bookmarks')
4620 for b in opts['bookmark']:
4622 for b in opts['bookmark']:
4621 if b not in rb:
4623 if b not in rb:
4622 raise util.Abort(_('remote bookmark %s not found!') % b)
4624 raise util.Abort(_('remote bookmark %s not found!') % b)
4623 revs.append(rb[b])
4625 revs.append(rb[b])
4624
4626
4625 if revs:
4627 if revs:
4626 try:
4628 try:
4627 revs = [other.lookup(rev) for rev in revs]
4629 revs = [other.lookup(rev) for rev in revs]
4628 except error.CapabilityError:
4630 except error.CapabilityError:
4629 err = _("other repository doesn't support revision lookup, "
4631 err = _("other repository doesn't support revision lookup, "
4630 "so a rev cannot be specified.")
4632 "so a rev cannot be specified.")
4631 raise util.Abort(err)
4633 raise util.Abort(err)
4632
4634
4633 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4635 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4634 bookmarks.updatefromremote(ui, repo, other, source)
4636 bookmarks.updatefromremote(ui, repo, other, source)
4635 if checkout:
4637 if checkout:
4636 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4638 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4637 repo._subtoppath = source
4639 repo._subtoppath = source
4638 try:
4640 try:
4639 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4641 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4640
4642
4641 finally:
4643 finally:
4642 del repo._subtoppath
4644 del repo._subtoppath
4643
4645
4644 # update specified bookmarks
4646 # update specified bookmarks
4645 if opts.get('bookmark'):
4647 if opts.get('bookmark'):
4646 for b in opts['bookmark']:
4648 for b in opts['bookmark']:
4647 # explicit pull overrides local bookmark if any
4649 # explicit pull overrides local bookmark if any
4648 ui.status(_("importing bookmark %s\n") % b)
4650 ui.status(_("importing bookmark %s\n") % b)
4649 repo._bookmarks[b] = repo[rb[b]].node()
4651 repo._bookmarks[b] = repo[rb[b]].node()
4650 bookmarks.write(repo)
4652 bookmarks.write(repo)
4651
4653
4652 return ret
4654 return ret
4653
4655
4654 @command('^push',
4656 @command('^push',
4655 [('f', 'force', None, _('force push')),
4657 [('f', 'force', None, _('force push')),
4656 ('r', 'rev', [],
4658 ('r', 'rev', [],
4657 _('a changeset intended to be included in the destination'),
4659 _('a changeset intended to be included in the destination'),
4658 _('REV')),
4660 _('REV')),
4659 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4661 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4660 ('b', 'branch', [],
4662 ('b', 'branch', [],
4661 _('a specific branch you would like to push'), _('BRANCH')),
4663 _('a specific branch you would like to push'), _('BRANCH')),
4662 ('', 'new-branch', False, _('allow pushing a new branch')),
4664 ('', 'new-branch', False, _('allow pushing a new branch')),
4663 ] + remoteopts,
4665 ] + remoteopts,
4664 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4666 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4665 def push(ui, repo, dest=None, **opts):
4667 def push(ui, repo, dest=None, **opts):
4666 """push changes to the specified destination
4668 """push changes to the specified destination
4667
4669
4668 Push changesets from the local repository to the specified
4670 Push changesets from the local repository to the specified
4669 destination.
4671 destination.
4670
4672
4671 This operation is symmetrical to pull: it is identical to a pull
4673 This operation is symmetrical to pull: it is identical to a pull
4672 in the destination repository from the current one.
4674 in the destination repository from the current one.
4673
4675
4674 By default, push will not allow creation of new heads at the
4676 By default, push will not allow creation of new heads at the
4675 destination, since multiple heads would make it unclear which head
4677 destination, since multiple heads would make it unclear which head
4676 to use. In this situation, it is recommended to pull and merge
4678 to use. In this situation, it is recommended to pull and merge
4677 before pushing.
4679 before pushing.
4678
4680
4679 Use --new-branch if you want to allow push to create a new named
4681 Use --new-branch if you want to allow push to create a new named
4680 branch that is not present at the destination. This allows you to
4682 branch that is not present at the destination. This allows you to
4681 only create a new branch without forcing other changes.
4683 only create a new branch without forcing other changes.
4682
4684
4683 Use -f/--force to override the default behavior and push all
4685 Use -f/--force to override the default behavior and push all
4684 changesets on all branches.
4686 changesets on all branches.
4685
4687
4686 If -r/--rev is used, the specified revision and all its ancestors
4688 If -r/--rev is used, the specified revision and all its ancestors
4687 will be pushed to the remote repository.
4689 will be pushed to the remote repository.
4688
4690
4689 If -B/--bookmark is used, the specified bookmarked revision, its
4691 If -B/--bookmark is used, the specified bookmarked revision, its
4690 ancestors, and the bookmark will be pushed to the remote
4692 ancestors, and the bookmark will be pushed to the remote
4691 repository.
4693 repository.
4692
4694
4693 Please see :hg:`help urls` for important details about ``ssh://``
4695 Please see :hg:`help urls` for important details about ``ssh://``
4694 URLs. If DESTINATION is omitted, a default path will be used.
4696 URLs. If DESTINATION is omitted, a default path will be used.
4695
4697
4696 Returns 0 if push was successful, 1 if nothing to push.
4698 Returns 0 if push was successful, 1 if nothing to push.
4697 """
4699 """
4698
4700
4699 if opts.get('bookmark'):
4701 if opts.get('bookmark'):
4700 for b in opts['bookmark']:
4702 for b in opts['bookmark']:
4701 # translate -B options to -r so changesets get pushed
4703 # translate -B options to -r so changesets get pushed
4702 if b in repo._bookmarks:
4704 if b in repo._bookmarks:
4703 opts.setdefault('rev', []).append(b)
4705 opts.setdefault('rev', []).append(b)
4704 else:
4706 else:
4705 # if we try to push a deleted bookmark, translate it to null
4707 # if we try to push a deleted bookmark, translate it to null
4706 # this lets simultaneous -r, -b options continue working
4708 # this lets simultaneous -r, -b options continue working
4707 opts.setdefault('rev', []).append("null")
4709 opts.setdefault('rev', []).append("null")
4708
4710
4709 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4711 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4710 dest, branches = hg.parseurl(dest, opts.get('branch'))
4712 dest, branches = hg.parseurl(dest, opts.get('branch'))
4711 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4713 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4712 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4714 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4713 other = hg.peer(repo, opts, dest)
4715 other = hg.peer(repo, opts, dest)
4714 if revs:
4716 if revs:
4715 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4717 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4716
4718
4717 repo._subtoppath = dest
4719 repo._subtoppath = dest
4718 try:
4720 try:
4719 # push subrepos depth-first for coherent ordering
4721 # push subrepos depth-first for coherent ordering
4720 c = repo['']
4722 c = repo['']
4721 subs = c.substate # only repos that are committed
4723 subs = c.substate # only repos that are committed
4722 for s in sorted(subs):
4724 for s in sorted(subs):
4723 if c.sub(s).push(opts) == 0:
4725 if c.sub(s).push(opts) == 0:
4724 return False
4726 return False
4725 finally:
4727 finally:
4726 del repo._subtoppath
4728 del repo._subtoppath
4727 result = repo.push(other, opts.get('force'), revs=revs,
4729 result = repo.push(other, opts.get('force'), revs=revs,
4728 newbranch=opts.get('new_branch'))
4730 newbranch=opts.get('new_branch'))
4729
4731
4730 result = not result
4732 result = not result
4731
4733
4732 if opts.get('bookmark'):
4734 if opts.get('bookmark'):
4733 rb = other.listkeys('bookmarks')
4735 rb = other.listkeys('bookmarks')
4734 for b in opts['bookmark']:
4736 for b in opts['bookmark']:
4735 # explicit push overrides remote bookmark if any
4737 # explicit push overrides remote bookmark if any
4736 if b in repo._bookmarks:
4738 if b in repo._bookmarks:
4737 ui.status(_("exporting bookmark %s\n") % b)
4739 ui.status(_("exporting bookmark %s\n") % b)
4738 new = repo[b].hex()
4740 new = repo[b].hex()
4739 elif b in rb:
4741 elif b in rb:
4740 ui.status(_("deleting remote bookmark %s\n") % b)
4742 ui.status(_("deleting remote bookmark %s\n") % b)
4741 new = '' # delete
4743 new = '' # delete
4742 else:
4744 else:
4743 ui.warn(_('bookmark %s does not exist on the local '
4745 ui.warn(_('bookmark %s does not exist on the local '
4744 'or remote repository!\n') % b)
4746 'or remote repository!\n') % b)
4745 return 2
4747 return 2
4746 old = rb.get(b, '')
4748 old = rb.get(b, '')
4747 r = other.pushkey('bookmarks', b, old, new)
4749 r = other.pushkey('bookmarks', b, old, new)
4748 if not r:
4750 if not r:
4749 ui.warn(_('updating bookmark %s failed!\n') % b)
4751 ui.warn(_('updating bookmark %s failed!\n') % b)
4750 if not result:
4752 if not result:
4751 result = 2
4753 result = 2
4752
4754
4753 return result
4755 return result
4754
4756
4755 @command('recover', [])
4757 @command('recover', [])
4756 def recover(ui, repo):
4758 def recover(ui, repo):
4757 """roll back an interrupted transaction
4759 """roll back an interrupted transaction
4758
4760
4759 Recover from an interrupted commit or pull.
4761 Recover from an interrupted commit or pull.
4760
4762
4761 This command tries to fix the repository status after an
4763 This command tries to fix the repository status after an
4762 interrupted operation. It should only be necessary when Mercurial
4764 interrupted operation. It should only be necessary when Mercurial
4763 suggests it.
4765 suggests it.
4764
4766
4765 Returns 0 if successful, 1 if nothing to recover or verify fails.
4767 Returns 0 if successful, 1 if nothing to recover or verify fails.
4766 """
4768 """
4767 if repo.recover():
4769 if repo.recover():
4768 return hg.verify(repo)
4770 return hg.verify(repo)
4769 return 1
4771 return 1
4770
4772
4771 @command('^remove|rm',
4773 @command('^remove|rm',
4772 [('A', 'after', None, _('record delete for missing files')),
4774 [('A', 'after', None, _('record delete for missing files')),
4773 ('f', 'force', None,
4775 ('f', 'force', None,
4774 _('remove (and delete) file even if added or modified')),
4776 _('remove (and delete) file even if added or modified')),
4775 ] + walkopts,
4777 ] + walkopts,
4776 _('[OPTION]... FILE...'))
4778 _('[OPTION]... FILE...'))
4777 def remove(ui, repo, *pats, **opts):
4779 def remove(ui, repo, *pats, **opts):
4778 """remove the specified files on the next commit
4780 """remove the specified files on the next commit
4779
4781
4780 Schedule the indicated files for removal from the current branch.
4782 Schedule the indicated files for removal from the current branch.
4781
4783
4782 This command schedules the files to be removed at the next commit.
4784 This command schedules the files to be removed at the next commit.
4783 To undo a remove before that, see :hg:`revert`. To undo added
4785 To undo a remove before that, see :hg:`revert`. To undo added
4784 files, see :hg:`forget`.
4786 files, see :hg:`forget`.
4785
4787
4786 .. container:: verbose
4788 .. container:: verbose
4787
4789
4788 -A/--after can be used to remove only files that have already
4790 -A/--after can be used to remove only files that have already
4789 been deleted, -f/--force can be used to force deletion, and -Af
4791 been deleted, -f/--force can be used to force deletion, and -Af
4790 can be used to remove files from the next revision without
4792 can be used to remove files from the next revision without
4791 deleting them from the working directory.
4793 deleting them from the working directory.
4792
4794
4793 The following table details the behavior of remove for different
4795 The following table details the behavior of remove for different
4794 file states (columns) and option combinations (rows). The file
4796 file states (columns) and option combinations (rows). The file
4795 states are Added [A], Clean [C], Modified [M] and Missing [!]
4797 states are Added [A], Clean [C], Modified [M] and Missing [!]
4796 (as reported by :hg:`status`). The actions are Warn, Remove
4798 (as reported by :hg:`status`). The actions are Warn, Remove
4797 (from branch) and Delete (from disk):
4799 (from branch) and Delete (from disk):
4798
4800
4799 ======= == == == ==
4801 ======= == == == ==
4800 A C M !
4802 A C M !
4801 ======= == == == ==
4803 ======= == == == ==
4802 none W RD W R
4804 none W RD W R
4803 -f R RD RD R
4805 -f R RD RD R
4804 -A W W W R
4806 -A W W W R
4805 -Af R R R R
4807 -Af R R R R
4806 ======= == == == ==
4808 ======= == == == ==
4807
4809
4808 Note that remove never deletes files in Added [A] state from the
4810 Note that remove never deletes files in Added [A] state from the
4809 working directory, not even if option --force is specified.
4811 working directory, not even if option --force is specified.
4810
4812
4811 Returns 0 on success, 1 if any warnings encountered.
4813 Returns 0 on success, 1 if any warnings encountered.
4812 """
4814 """
4813
4815
4814 ret = 0
4816 ret = 0
4815 after, force = opts.get('after'), opts.get('force')
4817 after, force = opts.get('after'), opts.get('force')
4816 if not pats and not after:
4818 if not pats and not after:
4817 raise util.Abort(_('no files specified'))
4819 raise util.Abort(_('no files specified'))
4818
4820
4819 m = scmutil.match(repo[None], pats, opts)
4821 m = scmutil.match(repo[None], pats, opts)
4820 s = repo.status(match=m, clean=True)
4822 s = repo.status(match=m, clean=True)
4821 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4823 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4822
4824
4823 for f in m.files():
4825 for f in m.files():
4824 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4826 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4825 if os.path.exists(m.rel(f)):
4827 if os.path.exists(m.rel(f)):
4826 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4828 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4827 ret = 1
4829 ret = 1
4828
4830
4829 if force:
4831 if force:
4830 list = modified + deleted + clean + added
4832 list = modified + deleted + clean + added
4831 elif after:
4833 elif after:
4832 list = deleted
4834 list = deleted
4833 for f in modified + added + clean:
4835 for f in modified + added + clean:
4834 ui.warn(_('not removing %s: file still exists (use -f'
4836 ui.warn(_('not removing %s: file still exists (use -f'
4835 ' to force removal)\n') % m.rel(f))
4837 ' to force removal)\n') % m.rel(f))
4836 ret = 1
4838 ret = 1
4837 else:
4839 else:
4838 list = deleted + clean
4840 list = deleted + clean
4839 for f in modified:
4841 for f in modified:
4840 ui.warn(_('not removing %s: file is modified (use -f'
4842 ui.warn(_('not removing %s: file is modified (use -f'
4841 ' to force removal)\n') % m.rel(f))
4843 ' to force removal)\n') % m.rel(f))
4842 ret = 1
4844 ret = 1
4843 for f in added:
4845 for f in added:
4844 ui.warn(_('not removing %s: file has been marked for add'
4846 ui.warn(_('not removing %s: file has been marked for add'
4845 ' (use forget to undo)\n') % m.rel(f))
4847 ' (use forget to undo)\n') % m.rel(f))
4846 ret = 1
4848 ret = 1
4847
4849
4848 for f in sorted(list):
4850 for f in sorted(list):
4849 if ui.verbose or not m.exact(f):
4851 if ui.verbose or not m.exact(f):
4850 ui.status(_('removing %s\n') % m.rel(f))
4852 ui.status(_('removing %s\n') % m.rel(f))
4851
4853
4852 wlock = repo.wlock()
4854 wlock = repo.wlock()
4853 try:
4855 try:
4854 if not after:
4856 if not after:
4855 for f in list:
4857 for f in list:
4856 if f in added:
4858 if f in added:
4857 continue # we never unlink added files on remove
4859 continue # we never unlink added files on remove
4858 try:
4860 try:
4859 util.unlinkpath(repo.wjoin(f))
4861 util.unlinkpath(repo.wjoin(f))
4860 except OSError, inst:
4862 except OSError, inst:
4861 if inst.errno != errno.ENOENT:
4863 if inst.errno != errno.ENOENT:
4862 raise
4864 raise
4863 repo[None].forget(list)
4865 repo[None].forget(list)
4864 finally:
4866 finally:
4865 wlock.release()
4867 wlock.release()
4866
4868
4867 return ret
4869 return ret
4868
4870
4869 @command('rename|move|mv',
4871 @command('rename|move|mv',
4870 [('A', 'after', None, _('record a rename that has already occurred')),
4872 [('A', 'after', None, _('record a rename that has already occurred')),
4871 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4873 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4872 ] + walkopts + dryrunopts,
4874 ] + walkopts + dryrunopts,
4873 _('[OPTION]... SOURCE... DEST'))
4875 _('[OPTION]... SOURCE... DEST'))
4874 def rename(ui, repo, *pats, **opts):
4876 def rename(ui, repo, *pats, **opts):
4875 """rename files; equivalent of copy + remove
4877 """rename files; equivalent of copy + remove
4876
4878
4877 Mark dest as copies of sources; mark sources for deletion. If dest
4879 Mark dest as copies of sources; mark sources for deletion. If dest
4878 is a directory, copies are put in that directory. If dest is a
4880 is a directory, copies are put in that directory. If dest is a
4879 file, there can only be one source.
4881 file, there can only be one source.
4880
4882
4881 By default, this command copies the contents of files as they
4883 By default, this command copies the contents of files as they
4882 exist in the working directory. If invoked with -A/--after, the
4884 exist in the working directory. If invoked with -A/--after, the
4883 operation is recorded, but no copying is performed.
4885 operation is recorded, but no copying is performed.
4884
4886
4885 This command takes effect at the next commit. To undo a rename
4887 This command takes effect at the next commit. To undo a rename
4886 before that, see :hg:`revert`.
4888 before that, see :hg:`revert`.
4887
4889
4888 Returns 0 on success, 1 if errors are encountered.
4890 Returns 0 on success, 1 if errors are encountered.
4889 """
4891 """
4890 wlock = repo.wlock(False)
4892 wlock = repo.wlock(False)
4891 try:
4893 try:
4892 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4894 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4893 finally:
4895 finally:
4894 wlock.release()
4896 wlock.release()
4895
4897
4896 @command('resolve',
4898 @command('resolve',
4897 [('a', 'all', None, _('select all unresolved files')),
4899 [('a', 'all', None, _('select all unresolved files')),
4898 ('l', 'list', None, _('list state of files needing merge')),
4900 ('l', 'list', None, _('list state of files needing merge')),
4899 ('m', 'mark', None, _('mark files as resolved')),
4901 ('m', 'mark', None, _('mark files as resolved')),
4900 ('u', 'unmark', None, _('mark files as unresolved')),
4902 ('u', 'unmark', None, _('mark files as unresolved')),
4901 ('n', 'no-status', None, _('hide status prefix'))]
4903 ('n', 'no-status', None, _('hide status prefix'))]
4902 + mergetoolopts + walkopts,
4904 + mergetoolopts + walkopts,
4903 _('[OPTION]... [FILE]...'))
4905 _('[OPTION]... [FILE]...'))
4904 def resolve(ui, repo, *pats, **opts):
4906 def resolve(ui, repo, *pats, **opts):
4905 """redo merges or set/view the merge status of files
4907 """redo merges or set/view the merge status of files
4906
4908
4907 Merges with unresolved conflicts are often the result of
4909 Merges with unresolved conflicts are often the result of
4908 non-interactive merging using the ``internal:merge`` configuration
4910 non-interactive merging using the ``internal:merge`` configuration
4909 setting, or a command-line merge tool like ``diff3``. The resolve
4911 setting, or a command-line merge tool like ``diff3``. The resolve
4910 command is used to manage the files involved in a merge, after
4912 command is used to manage the files involved in a merge, after
4911 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4913 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4912 working directory must have two parents). See :hg:`help
4914 working directory must have two parents). See :hg:`help
4913 merge-tools` for information on configuring merge tools.
4915 merge-tools` for information on configuring merge tools.
4914
4916
4915 The resolve command can be used in the following ways:
4917 The resolve command can be used in the following ways:
4916
4918
4917 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4919 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4918 files, discarding any previous merge attempts. Re-merging is not
4920 files, discarding any previous merge attempts. Re-merging is not
4919 performed for files already marked as resolved. Use ``--all/-a``
4921 performed for files already marked as resolved. Use ``--all/-a``
4920 to select all unresolved files. ``--tool`` can be used to specify
4922 to select all unresolved files. ``--tool`` can be used to specify
4921 the merge tool used for the given files. It overrides the HGMERGE
4923 the merge tool used for the given files. It overrides the HGMERGE
4922 environment variable and your configuration files. Previous file
4924 environment variable and your configuration files. Previous file
4923 contents are saved with a ``.orig`` suffix.
4925 contents are saved with a ``.orig`` suffix.
4924
4926
4925 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4927 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4926 (e.g. after having manually fixed-up the files). The default is
4928 (e.g. after having manually fixed-up the files). The default is
4927 to mark all unresolved files.
4929 to mark all unresolved files.
4928
4930
4929 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4931 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4930 default is to mark all resolved files.
4932 default is to mark all resolved files.
4931
4933
4932 - :hg:`resolve -l`: list files which had or still have conflicts.
4934 - :hg:`resolve -l`: list files which had or still have conflicts.
4933 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4935 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4934
4936
4935 Note that Mercurial will not let you commit files with unresolved
4937 Note that Mercurial will not let you commit files with unresolved
4936 merge conflicts. You must use :hg:`resolve -m ...` before you can
4938 merge conflicts. You must use :hg:`resolve -m ...` before you can
4937 commit after a conflicting merge.
4939 commit after a conflicting merge.
4938
4940
4939 Returns 0 on success, 1 if any files fail a resolve attempt.
4941 Returns 0 on success, 1 if any files fail a resolve attempt.
4940 """
4942 """
4941
4943
4942 all, mark, unmark, show, nostatus = \
4944 all, mark, unmark, show, nostatus = \
4943 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4945 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4944
4946
4945 if (show and (mark or unmark)) or (mark and unmark):
4947 if (show and (mark or unmark)) or (mark and unmark):
4946 raise util.Abort(_("too many options specified"))
4948 raise util.Abort(_("too many options specified"))
4947 if pats and all:
4949 if pats and all:
4948 raise util.Abort(_("can't specify --all and patterns"))
4950 raise util.Abort(_("can't specify --all and patterns"))
4949 if not (all or pats or show or mark or unmark):
4951 if not (all or pats or show or mark or unmark):
4950 raise util.Abort(_('no files or directories specified; '
4952 raise util.Abort(_('no files or directories specified; '
4951 'use --all to remerge all files'))
4953 'use --all to remerge all files'))
4952
4954
4953 ms = mergemod.mergestate(repo)
4955 ms = mergemod.mergestate(repo)
4954 m = scmutil.match(repo[None], pats, opts)
4956 m = scmutil.match(repo[None], pats, opts)
4955 ret = 0
4957 ret = 0
4956
4958
4957 for f in ms:
4959 for f in ms:
4958 if m(f):
4960 if m(f):
4959 if show:
4961 if show:
4960 if nostatus:
4962 if nostatus:
4961 ui.write("%s\n" % f)
4963 ui.write("%s\n" % f)
4962 else:
4964 else:
4963 ui.write("%s %s\n" % (ms[f].upper(), f),
4965 ui.write("%s %s\n" % (ms[f].upper(), f),
4964 label='resolve.' +
4966 label='resolve.' +
4965 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4967 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4966 elif mark:
4968 elif mark:
4967 ms.mark(f, "r")
4969 ms.mark(f, "r")
4968 elif unmark:
4970 elif unmark:
4969 ms.mark(f, "u")
4971 ms.mark(f, "u")
4970 else:
4972 else:
4971 wctx = repo[None]
4973 wctx = repo[None]
4972 mctx = wctx.parents()[-1]
4974 mctx = wctx.parents()[-1]
4973
4975
4974 # backup pre-resolve (merge uses .orig for its own purposes)
4976 # backup pre-resolve (merge uses .orig for its own purposes)
4975 a = repo.wjoin(f)
4977 a = repo.wjoin(f)
4976 util.copyfile(a, a + ".resolve")
4978 util.copyfile(a, a + ".resolve")
4977
4979
4978 try:
4980 try:
4979 # resolve file
4981 # resolve file
4980 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4982 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4981 if ms.resolve(f, wctx, mctx):
4983 if ms.resolve(f, wctx, mctx):
4982 ret = 1
4984 ret = 1
4983 finally:
4985 finally:
4984 ui.setconfig('ui', 'forcemerge', '')
4986 ui.setconfig('ui', 'forcemerge', '')
4985 ms.commit()
4987 ms.commit()
4986
4988
4987 # replace filemerge's .orig file with our resolve file
4989 # replace filemerge's .orig file with our resolve file
4988 util.rename(a + ".resolve", a + ".orig")
4990 util.rename(a + ".resolve", a + ".orig")
4989
4991
4990 ms.commit()
4992 ms.commit()
4991 return ret
4993 return ret
4992
4994
4993 @command('revert',
4995 @command('revert',
4994 [('a', 'all', None, _('revert all changes when no arguments given')),
4996 [('a', 'all', None, _('revert all changes when no arguments given')),
4995 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4997 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4996 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4998 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4997 ('C', 'no-backup', None, _('do not save backup copies of files')),
4999 ('C', 'no-backup', None, _('do not save backup copies of files')),
4998 ] + walkopts + dryrunopts,
5000 ] + walkopts + dryrunopts,
4999 _('[OPTION]... [-r REV] [NAME]...'))
5001 _('[OPTION]... [-r REV] [NAME]...'))
5000 def revert(ui, repo, *pats, **opts):
5002 def revert(ui, repo, *pats, **opts):
5001 """restore files to their checkout state
5003 """restore files to their checkout state
5002
5004
5003 .. note::
5005 .. note::
5004
5006
5005 To check out earlier revisions, you should use :hg:`update REV`.
5007 To check out earlier revisions, you should use :hg:`update REV`.
5006 To cancel an uncommitted merge (and lose your changes), use
5008 To cancel an uncommitted merge (and lose your changes), use
5007 :hg:`update --clean .`.
5009 :hg:`update --clean .`.
5008
5010
5009 With no revision specified, revert the specified files or directories
5011 With no revision specified, revert the specified files or directories
5010 to the contents they had in the parent of the working directory.
5012 to the contents they had in the parent of the working directory.
5011 This restores the contents of files to an unmodified
5013 This restores the contents of files to an unmodified
5012 state and unschedules adds, removes, copies, and renames. If the
5014 state and unschedules adds, removes, copies, and renames. If the
5013 working directory has two parents, you must explicitly specify a
5015 working directory has two parents, you must explicitly specify a
5014 revision.
5016 revision.
5015
5017
5016 Using the -r/--rev or -d/--date options, revert the given files or
5018 Using the -r/--rev or -d/--date options, revert the given files or
5017 directories to their states as of a specific revision. Because
5019 directories to their states as of a specific revision. Because
5018 revert does not change the working directory parents, this will
5020 revert does not change the working directory parents, this will
5019 cause these files to appear modified. This can be helpful to "back
5021 cause these files to appear modified. This can be helpful to "back
5020 out" some or all of an earlier change. See :hg:`backout` for a
5022 out" some or all of an earlier change. See :hg:`backout` for a
5021 related method.
5023 related method.
5022
5024
5023 Modified files are saved with a .orig suffix before reverting.
5025 Modified files are saved with a .orig suffix before reverting.
5024 To disable these backups, use --no-backup.
5026 To disable these backups, use --no-backup.
5025
5027
5026 See :hg:`help dates` for a list of formats valid for -d/--date.
5028 See :hg:`help dates` for a list of formats valid for -d/--date.
5027
5029
5028 Returns 0 on success.
5030 Returns 0 on success.
5029 """
5031 """
5030
5032
5031 if opts.get("date"):
5033 if opts.get("date"):
5032 if opts.get("rev"):
5034 if opts.get("rev"):
5033 raise util.Abort(_("you can't specify a revision and a date"))
5035 raise util.Abort(_("you can't specify a revision and a date"))
5034 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5036 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5035
5037
5036 parent, p2 = repo.dirstate.parents()
5038 parent, p2 = repo.dirstate.parents()
5037 if not opts.get('rev') and p2 != nullid:
5039 if not opts.get('rev') and p2 != nullid:
5038 # revert after merge is a trap for new users (issue2915)
5040 # revert after merge is a trap for new users (issue2915)
5039 raise util.Abort(_('uncommitted merge with no revision specified'),
5041 raise util.Abort(_('uncommitted merge with no revision specified'),
5040 hint=_('use "hg update" or see "hg help revert"'))
5042 hint=_('use "hg update" or see "hg help revert"'))
5041
5043
5042 ctx = scmutil.revsingle(repo, opts.get('rev'))
5044 ctx = scmutil.revsingle(repo, opts.get('rev'))
5043
5045
5044 if not pats and not opts.get('all'):
5046 if not pats and not opts.get('all'):
5045 msg = _("no files or directories specified")
5047 msg = _("no files or directories specified")
5046 if p2 != nullid:
5048 if p2 != nullid:
5047 hint = _("uncommitted merge, use --all to discard all changes,"
5049 hint = _("uncommitted merge, use --all to discard all changes,"
5048 " or 'hg update -C .' to abort the merge")
5050 " or 'hg update -C .' to abort the merge")
5049 raise util.Abort(msg, hint=hint)
5051 raise util.Abort(msg, hint=hint)
5050 dirty = util.any(repo.status())
5052 dirty = util.any(repo.status())
5051 node = ctx.node()
5053 node = ctx.node()
5052 if node != parent:
5054 if node != parent:
5053 if dirty:
5055 if dirty:
5054 hint = _("uncommitted changes, use --all to discard all"
5056 hint = _("uncommitted changes, use --all to discard all"
5055 " changes, or 'hg update %s' to update") % ctx.rev()
5057 " changes, or 'hg update %s' to update") % ctx.rev()
5056 else:
5058 else:
5057 hint = _("use --all to revert all files,"
5059 hint = _("use --all to revert all files,"
5058 " or 'hg update %s' to update") % ctx.rev()
5060 " or 'hg update %s' to update") % ctx.rev()
5059 elif dirty:
5061 elif dirty:
5060 hint = _("uncommitted changes, use --all to discard all changes")
5062 hint = _("uncommitted changes, use --all to discard all changes")
5061 else:
5063 else:
5062 hint = _("use --all to revert all files")
5064 hint = _("use --all to revert all files")
5063 raise util.Abort(msg, hint=hint)
5065 raise util.Abort(msg, hint=hint)
5064
5066
5065 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5067 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5066
5068
5067 @command('rollback', dryrunopts +
5069 @command('rollback', dryrunopts +
5068 [('f', 'force', False, _('ignore safety measures'))])
5070 [('f', 'force', False, _('ignore safety measures'))])
5069 def rollback(ui, repo, **opts):
5071 def rollback(ui, repo, **opts):
5070 """roll back the last transaction (dangerous)
5072 """roll back the last transaction (dangerous)
5071
5073
5072 This command should be used with care. There is only one level of
5074 This command should be used with care. There is only one level of
5073 rollback, and there is no way to undo a rollback. It will also
5075 rollback, and there is no way to undo a rollback. It will also
5074 restore the dirstate at the time of the last transaction, losing
5076 restore the dirstate at the time of the last transaction, losing
5075 any dirstate changes since that time. This command does not alter
5077 any dirstate changes since that time. This command does not alter
5076 the working directory.
5078 the working directory.
5077
5079
5078 Transactions are used to encapsulate the effects of all commands
5080 Transactions are used to encapsulate the effects of all commands
5079 that create new changesets or propagate existing changesets into a
5081 that create new changesets or propagate existing changesets into a
5080 repository.
5082 repository.
5081
5083
5082 .. container:: verbose
5084 .. container:: verbose
5083
5085
5084 For example, the following commands are transactional, and their
5086 For example, the following commands are transactional, and their
5085 effects can be rolled back:
5087 effects can be rolled back:
5086
5088
5087 - commit
5089 - commit
5088 - import
5090 - import
5089 - pull
5091 - pull
5090 - push (with this repository as the destination)
5092 - push (with this repository as the destination)
5091 - unbundle
5093 - unbundle
5092
5094
5093 To avoid permanent data loss, rollback will refuse to rollback a
5095 To avoid permanent data loss, rollback will refuse to rollback a
5094 commit transaction if it isn't checked out. Use --force to
5096 commit transaction if it isn't checked out. Use --force to
5095 override this protection.
5097 override this protection.
5096
5098
5097 This command is not intended for use on public repositories. Once
5099 This command is not intended for use on public repositories. Once
5098 changes are visible for pull by other users, rolling a transaction
5100 changes are visible for pull by other users, rolling a transaction
5099 back locally is ineffective (someone else may already have pulled
5101 back locally is ineffective (someone else may already have pulled
5100 the changes). Furthermore, a race is possible with readers of the
5102 the changes). Furthermore, a race is possible with readers of the
5101 repository; for example an in-progress pull from the repository
5103 repository; for example an in-progress pull from the repository
5102 may fail if a rollback is performed.
5104 may fail if a rollback is performed.
5103
5105
5104 Returns 0 on success, 1 if no rollback data is available.
5106 Returns 0 on success, 1 if no rollback data is available.
5105 """
5107 """
5106 return repo.rollback(dryrun=opts.get('dry_run'),
5108 return repo.rollback(dryrun=opts.get('dry_run'),
5107 force=opts.get('force'))
5109 force=opts.get('force'))
5108
5110
5109 @command('root', [])
5111 @command('root', [])
5110 def root(ui, repo):
5112 def root(ui, repo):
5111 """print the root (top) of the current working directory
5113 """print the root (top) of the current working directory
5112
5114
5113 Print the root directory of the current repository.
5115 Print the root directory of the current repository.
5114
5116
5115 Returns 0 on success.
5117 Returns 0 on success.
5116 """
5118 """
5117 ui.write(repo.root + "\n")
5119 ui.write(repo.root + "\n")
5118
5120
5119 @command('^serve',
5121 @command('^serve',
5120 [('A', 'accesslog', '', _('name of access log file to write to'),
5122 [('A', 'accesslog', '', _('name of access log file to write to'),
5121 _('FILE')),
5123 _('FILE')),
5122 ('d', 'daemon', None, _('run server in background')),
5124 ('d', 'daemon', None, _('run server in background')),
5123 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5125 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5124 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5126 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5125 # use string type, then we can check if something was passed
5127 # use string type, then we can check if something was passed
5126 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5128 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5127 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5129 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5128 _('ADDR')),
5130 _('ADDR')),
5129 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5131 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5130 _('PREFIX')),
5132 _('PREFIX')),
5131 ('n', 'name', '',
5133 ('n', 'name', '',
5132 _('name to show in web pages (default: working directory)'), _('NAME')),
5134 _('name to show in web pages (default: working directory)'), _('NAME')),
5133 ('', 'web-conf', '',
5135 ('', 'web-conf', '',
5134 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5136 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5135 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5137 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5136 _('FILE')),
5138 _('FILE')),
5137 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5139 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5138 ('', 'stdio', None, _('for remote clients')),
5140 ('', 'stdio', None, _('for remote clients')),
5139 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5141 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5140 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5142 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5141 ('', 'style', '', _('template style to use'), _('STYLE')),
5143 ('', 'style', '', _('template style to use'), _('STYLE')),
5142 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5144 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5143 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5145 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5144 _('[OPTION]...'))
5146 _('[OPTION]...'))
5145 def serve(ui, repo, **opts):
5147 def serve(ui, repo, **opts):
5146 """start stand-alone webserver
5148 """start stand-alone webserver
5147
5149
5148 Start a local HTTP repository browser and pull server. You can use
5150 Start a local HTTP repository browser and pull server. You can use
5149 this for ad-hoc sharing and browsing of repositories. It is
5151 this for ad-hoc sharing and browsing of repositories. It is
5150 recommended to use a real web server to serve a repository for
5152 recommended to use a real web server to serve a repository for
5151 longer periods of time.
5153 longer periods of time.
5152
5154
5153 Please note that the server does not implement access control.
5155 Please note that the server does not implement access control.
5154 This means that, by default, anybody can read from the server and
5156 This means that, by default, anybody can read from the server and
5155 nobody can write to it by default. Set the ``web.allow_push``
5157 nobody can write to it by default. Set the ``web.allow_push``
5156 option to ``*`` to allow everybody to push to the server. You
5158 option to ``*`` to allow everybody to push to the server. You
5157 should use a real web server if you need to authenticate users.
5159 should use a real web server if you need to authenticate users.
5158
5160
5159 By default, the server logs accesses to stdout and errors to
5161 By default, the server logs accesses to stdout and errors to
5160 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5162 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5161 files.
5163 files.
5162
5164
5163 To have the server choose a free port number to listen on, specify
5165 To have the server choose a free port number to listen on, specify
5164 a port number of 0; in this case, the server will print the port
5166 a port number of 0; in this case, the server will print the port
5165 number it uses.
5167 number it uses.
5166
5168
5167 Returns 0 on success.
5169 Returns 0 on success.
5168 """
5170 """
5169
5171
5170 if opts["stdio"] and opts["cmdserver"]:
5172 if opts["stdio"] and opts["cmdserver"]:
5171 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5173 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5172
5174
5173 def checkrepo():
5175 def checkrepo():
5174 if repo is None:
5176 if repo is None:
5175 raise error.RepoError(_("there is no Mercurial repository here"
5177 raise error.RepoError(_("there is no Mercurial repository here"
5176 " (.hg not found)"))
5178 " (.hg not found)"))
5177
5179
5178 if opts["stdio"]:
5180 if opts["stdio"]:
5179 checkrepo()
5181 checkrepo()
5180 s = sshserver.sshserver(ui, repo)
5182 s = sshserver.sshserver(ui, repo)
5181 s.serve_forever()
5183 s.serve_forever()
5182
5184
5183 if opts["cmdserver"]:
5185 if opts["cmdserver"]:
5184 checkrepo()
5186 checkrepo()
5185 s = commandserver.server(ui, repo, opts["cmdserver"])
5187 s = commandserver.server(ui, repo, opts["cmdserver"])
5186 return s.serve()
5188 return s.serve()
5187
5189
5188 # this way we can check if something was given in the command-line
5190 # this way we can check if something was given in the command-line
5189 if opts.get('port'):
5191 if opts.get('port'):
5190 opts['port'] = util.getport(opts.get('port'))
5192 opts['port'] = util.getport(opts.get('port'))
5191
5193
5192 baseui = repo and repo.baseui or ui
5194 baseui = repo and repo.baseui or ui
5193 optlist = ("name templates style address port prefix ipv6"
5195 optlist = ("name templates style address port prefix ipv6"
5194 " accesslog errorlog certificate encoding")
5196 " accesslog errorlog certificate encoding")
5195 for o in optlist.split():
5197 for o in optlist.split():
5196 val = opts.get(o, '')
5198 val = opts.get(o, '')
5197 if val in (None, ''): # should check against default options instead
5199 if val in (None, ''): # should check against default options instead
5198 continue
5200 continue
5199 baseui.setconfig("web", o, val)
5201 baseui.setconfig("web", o, val)
5200 if repo and repo.ui != baseui:
5202 if repo and repo.ui != baseui:
5201 repo.ui.setconfig("web", o, val)
5203 repo.ui.setconfig("web", o, val)
5202
5204
5203 o = opts.get('web_conf') or opts.get('webdir_conf')
5205 o = opts.get('web_conf') or opts.get('webdir_conf')
5204 if not o:
5206 if not o:
5205 if not repo:
5207 if not repo:
5206 raise error.RepoError(_("there is no Mercurial repository"
5208 raise error.RepoError(_("there is no Mercurial repository"
5207 " here (.hg not found)"))
5209 " here (.hg not found)"))
5208 o = repo.root
5210 o = repo.root
5209
5211
5210 app = hgweb.hgweb(o, baseui=ui)
5212 app = hgweb.hgweb(o, baseui=ui)
5211
5213
5212 class service(object):
5214 class service(object):
5213 def init(self):
5215 def init(self):
5214 util.setsignalhandler()
5216 util.setsignalhandler()
5215 self.httpd = hgweb.server.create_server(ui, app)
5217 self.httpd = hgweb.server.create_server(ui, app)
5216
5218
5217 if opts['port'] and not ui.verbose:
5219 if opts['port'] and not ui.verbose:
5218 return
5220 return
5219
5221
5220 if self.httpd.prefix:
5222 if self.httpd.prefix:
5221 prefix = self.httpd.prefix.strip('/') + '/'
5223 prefix = self.httpd.prefix.strip('/') + '/'
5222 else:
5224 else:
5223 prefix = ''
5225 prefix = ''
5224
5226
5225 port = ':%d' % self.httpd.port
5227 port = ':%d' % self.httpd.port
5226 if port == ':80':
5228 if port == ':80':
5227 port = ''
5229 port = ''
5228
5230
5229 bindaddr = self.httpd.addr
5231 bindaddr = self.httpd.addr
5230 if bindaddr == '0.0.0.0':
5232 if bindaddr == '0.0.0.0':
5231 bindaddr = '*'
5233 bindaddr = '*'
5232 elif ':' in bindaddr: # IPv6
5234 elif ':' in bindaddr: # IPv6
5233 bindaddr = '[%s]' % bindaddr
5235 bindaddr = '[%s]' % bindaddr
5234
5236
5235 fqaddr = self.httpd.fqaddr
5237 fqaddr = self.httpd.fqaddr
5236 if ':' in fqaddr:
5238 if ':' in fqaddr:
5237 fqaddr = '[%s]' % fqaddr
5239 fqaddr = '[%s]' % fqaddr
5238 if opts['port']:
5240 if opts['port']:
5239 write = ui.status
5241 write = ui.status
5240 else:
5242 else:
5241 write = ui.write
5243 write = ui.write
5242 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5244 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5243 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5245 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5244
5246
5245 def run(self):
5247 def run(self):
5246 self.httpd.serve_forever()
5248 self.httpd.serve_forever()
5247
5249
5248 service = service()
5250 service = service()
5249
5251
5250 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5252 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5251
5253
5252 @command('showconfig|debugconfig',
5254 @command('showconfig|debugconfig',
5253 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5255 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5254 _('[-u] [NAME]...'))
5256 _('[-u] [NAME]...'))
5255 def showconfig(ui, repo, *values, **opts):
5257 def showconfig(ui, repo, *values, **opts):
5256 """show combined config settings from all hgrc files
5258 """show combined config settings from all hgrc files
5257
5259
5258 With no arguments, print names and values of all config items.
5260 With no arguments, print names and values of all config items.
5259
5261
5260 With one argument of the form section.name, print just the value
5262 With one argument of the form section.name, print just the value
5261 of that config item.
5263 of that config item.
5262
5264
5263 With multiple arguments, print names and values of all config
5265 With multiple arguments, print names and values of all config
5264 items with matching section names.
5266 items with matching section names.
5265
5267
5266 With --debug, the source (filename and line number) is printed
5268 With --debug, the source (filename and line number) is printed
5267 for each config item.
5269 for each config item.
5268
5270
5269 Returns 0 on success.
5271 Returns 0 on success.
5270 """
5272 """
5271
5273
5272 for f in scmutil.rcpath():
5274 for f in scmutil.rcpath():
5273 ui.debug('read config from: %s\n' % f)
5275 ui.debug('read config from: %s\n' % f)
5274 untrusted = bool(opts.get('untrusted'))
5276 untrusted = bool(opts.get('untrusted'))
5275 if values:
5277 if values:
5276 sections = [v for v in values if '.' not in v]
5278 sections = [v for v in values if '.' not in v]
5277 items = [v for v in values if '.' in v]
5279 items = [v for v in values if '.' in v]
5278 if len(items) > 1 or items and sections:
5280 if len(items) > 1 or items and sections:
5279 raise util.Abort(_('only one config item permitted'))
5281 raise util.Abort(_('only one config item permitted'))
5280 for section, name, value in ui.walkconfig(untrusted=untrusted):
5282 for section, name, value in ui.walkconfig(untrusted=untrusted):
5281 value = str(value).replace('\n', '\\n')
5283 value = str(value).replace('\n', '\\n')
5282 sectname = section + '.' + name
5284 sectname = section + '.' + name
5283 if values:
5285 if values:
5284 for v in values:
5286 for v in values:
5285 if v == section:
5287 if v == section:
5286 ui.debug('%s: ' %
5288 ui.debug('%s: ' %
5287 ui.configsource(section, name, untrusted))
5289 ui.configsource(section, name, untrusted))
5288 ui.write('%s=%s\n' % (sectname, value))
5290 ui.write('%s=%s\n' % (sectname, value))
5289 elif v == sectname:
5291 elif v == sectname:
5290 ui.debug('%s: ' %
5292 ui.debug('%s: ' %
5291 ui.configsource(section, name, untrusted))
5293 ui.configsource(section, name, untrusted))
5292 ui.write(value, '\n')
5294 ui.write(value, '\n')
5293 else:
5295 else:
5294 ui.debug('%s: ' %
5296 ui.debug('%s: ' %
5295 ui.configsource(section, name, untrusted))
5297 ui.configsource(section, name, untrusted))
5296 ui.write('%s=%s\n' % (sectname, value))
5298 ui.write('%s=%s\n' % (sectname, value))
5297
5299
5298 @command('^status|st',
5300 @command('^status|st',
5299 [('A', 'all', None, _('show status of all files')),
5301 [('A', 'all', None, _('show status of all files')),
5300 ('m', 'modified', None, _('show only modified files')),
5302 ('m', 'modified', None, _('show only modified files')),
5301 ('a', 'added', None, _('show only added files')),
5303 ('a', 'added', None, _('show only added files')),
5302 ('r', 'removed', None, _('show only removed files')),
5304 ('r', 'removed', None, _('show only removed files')),
5303 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5305 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5304 ('c', 'clean', None, _('show only files without changes')),
5306 ('c', 'clean', None, _('show only files without changes')),
5305 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5307 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5306 ('i', 'ignored', None, _('show only ignored files')),
5308 ('i', 'ignored', None, _('show only ignored files')),
5307 ('n', 'no-status', None, _('hide status prefix')),
5309 ('n', 'no-status', None, _('hide status prefix')),
5308 ('C', 'copies', None, _('show source of copied files')),
5310 ('C', 'copies', None, _('show source of copied files')),
5309 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5311 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5310 ('', 'rev', [], _('show difference from revision'), _('REV')),
5312 ('', 'rev', [], _('show difference from revision'), _('REV')),
5311 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5313 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5312 ] + walkopts + subrepoopts,
5314 ] + walkopts + subrepoopts,
5313 _('[OPTION]... [FILE]...'))
5315 _('[OPTION]... [FILE]...'))
5314 def status(ui, repo, *pats, **opts):
5316 def status(ui, repo, *pats, **opts):
5315 """show changed files in the working directory
5317 """show changed files in the working directory
5316
5318
5317 Show status of files in the repository. If names are given, only
5319 Show status of files in the repository. If names are given, only
5318 files that match are shown. Files that are clean or ignored or
5320 files that match are shown. Files that are clean or ignored or
5319 the source of a copy/move operation, are not listed unless
5321 the source of a copy/move operation, are not listed unless
5320 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5322 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5321 Unless options described with "show only ..." are given, the
5323 Unless options described with "show only ..." are given, the
5322 options -mardu are used.
5324 options -mardu are used.
5323
5325
5324 Option -q/--quiet hides untracked (unknown and ignored) files
5326 Option -q/--quiet hides untracked (unknown and ignored) files
5325 unless explicitly requested with -u/--unknown or -i/--ignored.
5327 unless explicitly requested with -u/--unknown or -i/--ignored.
5326
5328
5327 .. note::
5329 .. note::
5328 status may appear to disagree with diff if permissions have
5330 status may appear to disagree with diff if permissions have
5329 changed or a merge has occurred. The standard diff format does
5331 changed or a merge has occurred. The standard diff format does
5330 not report permission changes and diff only reports changes
5332 not report permission changes and diff only reports changes
5331 relative to one merge parent.
5333 relative to one merge parent.
5332
5334
5333 If one revision is given, it is used as the base revision.
5335 If one revision is given, it is used as the base revision.
5334 If two revisions are given, the differences between them are
5336 If two revisions are given, the differences between them are
5335 shown. The --change option can also be used as a shortcut to list
5337 shown. The --change option can also be used as a shortcut to list
5336 the changed files of a revision from its first parent.
5338 the changed files of a revision from its first parent.
5337
5339
5338 The codes used to show the status of files are::
5340 The codes used to show the status of files are::
5339
5341
5340 M = modified
5342 M = modified
5341 A = added
5343 A = added
5342 R = removed
5344 R = removed
5343 C = clean
5345 C = clean
5344 ! = missing (deleted by non-hg command, but still tracked)
5346 ! = missing (deleted by non-hg command, but still tracked)
5345 ? = not tracked
5347 ? = not tracked
5346 I = ignored
5348 I = ignored
5347 = origin of the previous file listed as A (added)
5349 = origin of the previous file listed as A (added)
5348
5350
5349 .. container:: verbose
5351 .. container:: verbose
5350
5352
5351 Examples:
5353 Examples:
5352
5354
5353 - show changes in the working directory relative to a
5355 - show changes in the working directory relative to a
5354 changeset::
5356 changeset::
5355
5357
5356 hg status --rev 9353
5358 hg status --rev 9353
5357
5359
5358 - show all changes including copies in an existing changeset::
5360 - show all changes including copies in an existing changeset::
5359
5361
5360 hg status --copies --change 9353
5362 hg status --copies --change 9353
5361
5363
5362 - get a NUL separated list of added files, suitable for xargs::
5364 - get a NUL separated list of added files, suitable for xargs::
5363
5365
5364 hg status -an0
5366 hg status -an0
5365
5367
5366 Returns 0 on success.
5368 Returns 0 on success.
5367 """
5369 """
5368
5370
5369 revs = opts.get('rev')
5371 revs = opts.get('rev')
5370 change = opts.get('change')
5372 change = opts.get('change')
5371
5373
5372 if revs and change:
5374 if revs and change:
5373 msg = _('cannot specify --rev and --change at the same time')
5375 msg = _('cannot specify --rev and --change at the same time')
5374 raise util.Abort(msg)
5376 raise util.Abort(msg)
5375 elif change:
5377 elif change:
5376 node2 = scmutil.revsingle(repo, change, None).node()
5378 node2 = scmutil.revsingle(repo, change, None).node()
5377 node1 = repo[node2].p1().node()
5379 node1 = repo[node2].p1().node()
5378 else:
5380 else:
5379 node1, node2 = scmutil.revpair(repo, revs)
5381 node1, node2 = scmutil.revpair(repo, revs)
5380
5382
5381 cwd = (pats and repo.getcwd()) or ''
5383 cwd = (pats and repo.getcwd()) or ''
5382 end = opts.get('print0') and '\0' or '\n'
5384 end = opts.get('print0') and '\0' or '\n'
5383 copy = {}
5385 copy = {}
5384 states = 'modified added removed deleted unknown ignored clean'.split()
5386 states = 'modified added removed deleted unknown ignored clean'.split()
5385 show = [k for k in states if opts.get(k)]
5387 show = [k for k in states if opts.get(k)]
5386 if opts.get('all'):
5388 if opts.get('all'):
5387 show += ui.quiet and (states[:4] + ['clean']) or states
5389 show += ui.quiet and (states[:4] + ['clean']) or states
5388 if not show:
5390 if not show:
5389 show = ui.quiet and states[:4] or states[:5]
5391 show = ui.quiet and states[:4] or states[:5]
5390
5392
5391 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5393 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5392 'ignored' in show, 'clean' in show, 'unknown' in show,
5394 'ignored' in show, 'clean' in show, 'unknown' in show,
5393 opts.get('subrepos'))
5395 opts.get('subrepos'))
5394 changestates = zip(states, 'MAR!?IC', stat)
5396 changestates = zip(states, 'MAR!?IC', stat)
5395
5397
5396 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5398 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5397 copy = copies.pathcopies(repo[node1], repo[node2])
5399 copy = copies.pathcopies(repo[node1], repo[node2])
5398
5400
5399 fm = ui.formatter('status', opts)
5401 fm = ui.formatter('status', opts)
5400 format = '%s %s' + end
5402 format = '%s %s' + end
5401 if opts.get('no_status'):
5403 if opts.get('no_status'):
5402 format = '%.0s%s' + end
5404 format = '%.0s%s' + end
5403
5405
5404 for state, char, files in changestates:
5406 for state, char, files in changestates:
5405 if state in show:
5407 if state in show:
5406 label = 'status.' + state
5408 label = 'status.' + state
5407 for f in files:
5409 for f in files:
5408 fm.startitem()
5410 fm.startitem()
5409 fm.write("status path", format, char,
5411 fm.write("status path", format, char,
5410 repo.pathto(f, cwd), label=label)
5412 repo.pathto(f, cwd), label=label)
5411 if f in copy:
5413 if f in copy:
5412 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5414 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5413 label='status.copied')
5415 label='status.copied')
5414 fm.end()
5416 fm.end()
5415
5417
5416 @command('^summary|sum',
5418 @command('^summary|sum',
5417 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5419 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5418 def summary(ui, repo, **opts):
5420 def summary(ui, repo, **opts):
5419 """summarize working directory state
5421 """summarize working directory state
5420
5422
5421 This generates a brief summary of the working directory state,
5423 This generates a brief summary of the working directory state,
5422 including parents, branch, commit status, and available updates.
5424 including parents, branch, commit status, and available updates.
5423
5425
5424 With the --remote option, this will check the default paths for
5426 With the --remote option, this will check the default paths for
5425 incoming and outgoing changes. This can be time-consuming.
5427 incoming and outgoing changes. This can be time-consuming.
5426
5428
5427 Returns 0 on success.
5429 Returns 0 on success.
5428 """
5430 """
5429
5431
5430 ctx = repo[None]
5432 ctx = repo[None]
5431 parents = ctx.parents()
5433 parents = ctx.parents()
5432 pnode = parents[0].node()
5434 pnode = parents[0].node()
5433 marks = []
5435 marks = []
5434
5436
5435 for p in parents:
5437 for p in parents:
5436 # label with log.changeset (instead of log.parent) since this
5438 # label with log.changeset (instead of log.parent) since this
5437 # shows a working directory parent *changeset*:
5439 # shows a working directory parent *changeset*:
5438 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5440 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5439 label='log.changeset changeset.%s' % p.phasestr())
5441 label='log.changeset changeset.%s' % p.phasestr())
5440 ui.write(' '.join(p.tags()), label='log.tag')
5442 ui.write(' '.join(p.tags()), label='log.tag')
5441 if p.bookmarks():
5443 if p.bookmarks():
5442 marks.extend(p.bookmarks())
5444 marks.extend(p.bookmarks())
5443 if p.rev() == -1:
5445 if p.rev() == -1:
5444 if not len(repo):
5446 if not len(repo):
5445 ui.write(_(' (empty repository)'))
5447 ui.write(_(' (empty repository)'))
5446 else:
5448 else:
5447 ui.write(_(' (no revision checked out)'))
5449 ui.write(_(' (no revision checked out)'))
5448 ui.write('\n')
5450 ui.write('\n')
5449 if p.description():
5451 if p.description():
5450 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5452 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5451 label='log.summary')
5453 label='log.summary')
5452
5454
5453 branch = ctx.branch()
5455 branch = ctx.branch()
5454 bheads = repo.branchheads(branch)
5456 bheads = repo.branchheads(branch)
5455 m = _('branch: %s\n') % branch
5457 m = _('branch: %s\n') % branch
5456 if branch != 'default':
5458 if branch != 'default':
5457 ui.write(m, label='log.branch')
5459 ui.write(m, label='log.branch')
5458 else:
5460 else:
5459 ui.status(m, label='log.branch')
5461 ui.status(m, label='log.branch')
5460
5462
5461 if marks:
5463 if marks:
5462 current = repo._bookmarkcurrent
5464 current = repo._bookmarkcurrent
5463 ui.write(_('bookmarks:'), label='log.bookmark')
5465 ui.write(_('bookmarks:'), label='log.bookmark')
5464 if current is not None:
5466 if current is not None:
5465 try:
5467 try:
5466 marks.remove(current)
5468 marks.remove(current)
5467 ui.write(' *' + current, label='bookmarks.current')
5469 ui.write(' *' + current, label='bookmarks.current')
5468 except ValueError:
5470 except ValueError:
5469 # current bookmark not in parent ctx marks
5471 # current bookmark not in parent ctx marks
5470 pass
5472 pass
5471 for m in marks:
5473 for m in marks:
5472 ui.write(' ' + m, label='log.bookmark')
5474 ui.write(' ' + m, label='log.bookmark')
5473 ui.write('\n', label='log.bookmark')
5475 ui.write('\n', label='log.bookmark')
5474
5476
5475 st = list(repo.status(unknown=True))[:6]
5477 st = list(repo.status(unknown=True))[:6]
5476
5478
5477 c = repo.dirstate.copies()
5479 c = repo.dirstate.copies()
5478 copied, renamed = [], []
5480 copied, renamed = [], []
5479 for d, s in c.iteritems():
5481 for d, s in c.iteritems():
5480 if s in st[2]:
5482 if s in st[2]:
5481 st[2].remove(s)
5483 st[2].remove(s)
5482 renamed.append(d)
5484 renamed.append(d)
5483 else:
5485 else:
5484 copied.append(d)
5486 copied.append(d)
5485 if d in st[1]:
5487 if d in st[1]:
5486 st[1].remove(d)
5488 st[1].remove(d)
5487 st.insert(3, renamed)
5489 st.insert(3, renamed)
5488 st.insert(4, copied)
5490 st.insert(4, copied)
5489
5491
5490 ms = mergemod.mergestate(repo)
5492 ms = mergemod.mergestate(repo)
5491 st.append([f for f in ms if ms[f] == 'u'])
5493 st.append([f for f in ms if ms[f] == 'u'])
5492
5494
5493 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5495 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5494 st.append(subs)
5496 st.append(subs)
5495
5497
5496 labels = [ui.label(_('%d modified'), 'status.modified'),
5498 labels = [ui.label(_('%d modified'), 'status.modified'),
5497 ui.label(_('%d added'), 'status.added'),
5499 ui.label(_('%d added'), 'status.added'),
5498 ui.label(_('%d removed'), 'status.removed'),
5500 ui.label(_('%d removed'), 'status.removed'),
5499 ui.label(_('%d renamed'), 'status.copied'),
5501 ui.label(_('%d renamed'), 'status.copied'),
5500 ui.label(_('%d copied'), 'status.copied'),
5502 ui.label(_('%d copied'), 'status.copied'),
5501 ui.label(_('%d deleted'), 'status.deleted'),
5503 ui.label(_('%d deleted'), 'status.deleted'),
5502 ui.label(_('%d unknown'), 'status.unknown'),
5504 ui.label(_('%d unknown'), 'status.unknown'),
5503 ui.label(_('%d ignored'), 'status.ignored'),
5505 ui.label(_('%d ignored'), 'status.ignored'),
5504 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5506 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5505 ui.label(_('%d subrepos'), 'status.modified')]
5507 ui.label(_('%d subrepos'), 'status.modified')]
5506 t = []
5508 t = []
5507 for s, l in zip(st, labels):
5509 for s, l in zip(st, labels):
5508 if s:
5510 if s:
5509 t.append(l % len(s))
5511 t.append(l % len(s))
5510
5512
5511 t = ', '.join(t)
5513 t = ', '.join(t)
5512 cleanworkdir = False
5514 cleanworkdir = False
5513
5515
5514 if len(parents) > 1:
5516 if len(parents) > 1:
5515 t += _(' (merge)')
5517 t += _(' (merge)')
5516 elif branch != parents[0].branch():
5518 elif branch != parents[0].branch():
5517 t += _(' (new branch)')
5519 t += _(' (new branch)')
5518 elif (parents[0].closesbranch() and
5520 elif (parents[0].closesbranch() and
5519 pnode in repo.branchheads(branch, closed=True)):
5521 pnode in repo.branchheads(branch, closed=True)):
5520 t += _(' (head closed)')
5522 t += _(' (head closed)')
5521 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5523 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5522 t += _(' (clean)')
5524 t += _(' (clean)')
5523 cleanworkdir = True
5525 cleanworkdir = True
5524 elif pnode not in bheads:
5526 elif pnode not in bheads:
5525 t += _(' (new branch head)')
5527 t += _(' (new branch head)')
5526
5528
5527 if cleanworkdir:
5529 if cleanworkdir:
5528 ui.status(_('commit: %s\n') % t.strip())
5530 ui.status(_('commit: %s\n') % t.strip())
5529 else:
5531 else:
5530 ui.write(_('commit: %s\n') % t.strip())
5532 ui.write(_('commit: %s\n') % t.strip())
5531
5533
5532 # all ancestors of branch heads - all ancestors of parent = new csets
5534 # all ancestors of branch heads - all ancestors of parent = new csets
5533 new = [0] * len(repo)
5535 new = [0] * len(repo)
5534 cl = repo.changelog
5536 cl = repo.changelog
5535 for a in [cl.rev(n) for n in bheads]:
5537 for a in [cl.rev(n) for n in bheads]:
5536 new[a] = 1
5538 new[a] = 1
5537 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5539 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5538 new[a] = 1
5540 new[a] = 1
5539 for a in [p.rev() for p in parents]:
5541 for a in [p.rev() for p in parents]:
5540 if a >= 0:
5542 if a >= 0:
5541 new[a] = 0
5543 new[a] = 0
5542 for a in cl.ancestors([p.rev() for p in parents]):
5544 for a in cl.ancestors([p.rev() for p in parents]):
5543 new[a] = 0
5545 new[a] = 0
5544 new = sum(new)
5546 new = sum(new)
5545
5547
5546 if new == 0:
5548 if new == 0:
5547 ui.status(_('update: (current)\n'))
5549 ui.status(_('update: (current)\n'))
5548 elif pnode not in bheads:
5550 elif pnode not in bheads:
5549 ui.write(_('update: %d new changesets (update)\n') % new)
5551 ui.write(_('update: %d new changesets (update)\n') % new)
5550 else:
5552 else:
5551 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5553 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5552 (new, len(bheads)))
5554 (new, len(bheads)))
5553
5555
5554 if opts.get('remote'):
5556 if opts.get('remote'):
5555 t = []
5557 t = []
5556 source, branches = hg.parseurl(ui.expandpath('default'))
5558 source, branches = hg.parseurl(ui.expandpath('default'))
5557 other = hg.peer(repo, {}, source)
5559 other = hg.peer(repo, {}, source)
5558 revs, checkout = hg.addbranchrevs(repo, other, branches,
5560 revs, checkout = hg.addbranchrevs(repo, other, branches,
5559 opts.get('rev'))
5561 opts.get('rev'))
5560 ui.debug('comparing with %s\n' % util.hidepassword(source))
5562 ui.debug('comparing with %s\n' % util.hidepassword(source))
5561 repo.ui.pushbuffer()
5563 repo.ui.pushbuffer()
5562 commoninc = discovery.findcommonincoming(repo, other)
5564 commoninc = discovery.findcommonincoming(repo, other)
5563 _common, incoming, _rheads = commoninc
5565 _common, incoming, _rheads = commoninc
5564 repo.ui.popbuffer()
5566 repo.ui.popbuffer()
5565 if incoming:
5567 if incoming:
5566 t.append(_('1 or more incoming'))
5568 t.append(_('1 or more incoming'))
5567
5569
5568 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5570 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5569 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5571 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5570 if source != dest:
5572 if source != dest:
5571 other = hg.peer(repo, {}, dest)
5573 other = hg.peer(repo, {}, dest)
5572 commoninc = None
5574 commoninc = None
5573 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5575 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5574 repo.ui.pushbuffer()
5576 repo.ui.pushbuffer()
5575 outgoing = discovery.findcommonoutgoing(repo, other,
5577 outgoing = discovery.findcommonoutgoing(repo, other,
5576 commoninc=commoninc)
5578 commoninc=commoninc)
5577 repo.ui.popbuffer()
5579 repo.ui.popbuffer()
5578 o = outgoing.missing
5580 o = outgoing.missing
5579 if o:
5581 if o:
5580 t.append(_('%d outgoing') % len(o))
5582 t.append(_('%d outgoing') % len(o))
5581 if 'bookmarks' in other.listkeys('namespaces'):
5583 if 'bookmarks' in other.listkeys('namespaces'):
5582 lmarks = repo.listkeys('bookmarks')
5584 lmarks = repo.listkeys('bookmarks')
5583 rmarks = other.listkeys('bookmarks')
5585 rmarks = other.listkeys('bookmarks')
5584 diff = set(rmarks) - set(lmarks)
5586 diff = set(rmarks) - set(lmarks)
5585 if len(diff) > 0:
5587 if len(diff) > 0:
5586 t.append(_('%d incoming bookmarks') % len(diff))
5588 t.append(_('%d incoming bookmarks') % len(diff))
5587 diff = set(lmarks) - set(rmarks)
5589 diff = set(lmarks) - set(rmarks)
5588 if len(diff) > 0:
5590 if len(diff) > 0:
5589 t.append(_('%d outgoing bookmarks') % len(diff))
5591 t.append(_('%d outgoing bookmarks') % len(diff))
5590
5592
5591 if t:
5593 if t:
5592 ui.write(_('remote: %s\n') % (', '.join(t)))
5594 ui.write(_('remote: %s\n') % (', '.join(t)))
5593 else:
5595 else:
5594 ui.status(_('remote: (synced)\n'))
5596 ui.status(_('remote: (synced)\n'))
5595
5597
5596 @command('tag',
5598 @command('tag',
5597 [('f', 'force', None, _('force tag')),
5599 [('f', 'force', None, _('force tag')),
5598 ('l', 'local', None, _('make the tag local')),
5600 ('l', 'local', None, _('make the tag local')),
5599 ('r', 'rev', '', _('revision to tag'), _('REV')),
5601 ('r', 'rev', '', _('revision to tag'), _('REV')),
5600 ('', 'remove', None, _('remove a tag')),
5602 ('', 'remove', None, _('remove a tag')),
5601 # -l/--local is already there, commitopts cannot be used
5603 # -l/--local is already there, commitopts cannot be used
5602 ('e', 'edit', None, _('edit commit message')),
5604 ('e', 'edit', None, _('edit commit message')),
5603 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5605 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5604 ] + commitopts2,
5606 ] + commitopts2,
5605 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5607 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5606 def tag(ui, repo, name1, *names, **opts):
5608 def tag(ui, repo, name1, *names, **opts):
5607 """add one or more tags for the current or given revision
5609 """add one or more tags for the current or given revision
5608
5610
5609 Name a particular revision using <name>.
5611 Name a particular revision using <name>.
5610
5612
5611 Tags are used to name particular revisions of the repository and are
5613 Tags are used to name particular revisions of the repository and are
5612 very useful to compare different revisions, to go back to significant
5614 very useful to compare different revisions, to go back to significant
5613 earlier versions or to mark branch points as releases, etc. Changing
5615 earlier versions or to mark branch points as releases, etc. Changing
5614 an existing tag is normally disallowed; use -f/--force to override.
5616 an existing tag is normally disallowed; use -f/--force to override.
5615
5617
5616 If no revision is given, the parent of the working directory is
5618 If no revision is given, the parent of the working directory is
5617 used, or tip if no revision is checked out.
5619 used, or tip if no revision is checked out.
5618
5620
5619 To facilitate version control, distribution, and merging of tags,
5621 To facilitate version control, distribution, and merging of tags,
5620 they are stored as a file named ".hgtags" which is managed similarly
5622 they are stored as a file named ".hgtags" which is managed similarly
5621 to other project files and can be hand-edited if necessary. This
5623 to other project files and can be hand-edited if necessary. This
5622 also means that tagging creates a new commit. The file
5624 also means that tagging creates a new commit. The file
5623 ".hg/localtags" is used for local tags (not shared among
5625 ".hg/localtags" is used for local tags (not shared among
5624 repositories).
5626 repositories).
5625
5627
5626 Tag commits are usually made at the head of a branch. If the parent
5628 Tag commits are usually made at the head of a branch. If the parent
5627 of the working directory is not a branch head, :hg:`tag` aborts; use
5629 of the working directory is not a branch head, :hg:`tag` aborts; use
5628 -f/--force to force the tag commit to be based on a non-head
5630 -f/--force to force the tag commit to be based on a non-head
5629 changeset.
5631 changeset.
5630
5632
5631 See :hg:`help dates` for a list of formats valid for -d/--date.
5633 See :hg:`help dates` for a list of formats valid for -d/--date.
5632
5634
5633 Since tag names have priority over branch names during revision
5635 Since tag names have priority over branch names during revision
5634 lookup, using an existing branch name as a tag name is discouraged.
5636 lookup, using an existing branch name as a tag name is discouraged.
5635
5637
5636 Returns 0 on success.
5638 Returns 0 on success.
5637 """
5639 """
5638 wlock = lock = None
5640 wlock = lock = None
5639 try:
5641 try:
5640 wlock = repo.wlock()
5642 wlock = repo.wlock()
5641 lock = repo.lock()
5643 lock = repo.lock()
5642 rev_ = "."
5644 rev_ = "."
5643 names = [t.strip() for t in (name1,) + names]
5645 names = [t.strip() for t in (name1,) + names]
5644 if len(names) != len(set(names)):
5646 if len(names) != len(set(names)):
5645 raise util.Abort(_('tag names must be unique'))
5647 raise util.Abort(_('tag names must be unique'))
5646 for n in names:
5648 for n in names:
5647 scmutil.checknewlabel(repo, n, 'tag')
5649 scmutil.checknewlabel(repo, n, 'tag')
5648 if not n:
5650 if not n:
5649 raise util.Abort(_('tag names cannot consist entirely of '
5651 raise util.Abort(_('tag names cannot consist entirely of '
5650 'whitespace'))
5652 'whitespace'))
5651 if opts.get('rev') and opts.get('remove'):
5653 if opts.get('rev') and opts.get('remove'):
5652 raise util.Abort(_("--rev and --remove are incompatible"))
5654 raise util.Abort(_("--rev and --remove are incompatible"))
5653 if opts.get('rev'):
5655 if opts.get('rev'):
5654 rev_ = opts['rev']
5656 rev_ = opts['rev']
5655 message = opts.get('message')
5657 message = opts.get('message')
5656 if opts.get('remove'):
5658 if opts.get('remove'):
5657 expectedtype = opts.get('local') and 'local' or 'global'
5659 expectedtype = opts.get('local') and 'local' or 'global'
5658 for n in names:
5660 for n in names:
5659 if not repo.tagtype(n):
5661 if not repo.tagtype(n):
5660 raise util.Abort(_("tag '%s' does not exist") % n)
5662 raise util.Abort(_("tag '%s' does not exist") % n)
5661 if repo.tagtype(n) != expectedtype:
5663 if repo.tagtype(n) != expectedtype:
5662 if expectedtype == 'global':
5664 if expectedtype == 'global':
5663 raise util.Abort(_("tag '%s' is not a global tag") % n)
5665 raise util.Abort(_("tag '%s' is not a global tag") % n)
5664 else:
5666 else:
5665 raise util.Abort(_("tag '%s' is not a local tag") % n)
5667 raise util.Abort(_("tag '%s' is not a local tag") % n)
5666 rev_ = nullid
5668 rev_ = nullid
5667 if not message:
5669 if not message:
5668 # we don't translate commit messages
5670 # we don't translate commit messages
5669 message = 'Removed tag %s' % ', '.join(names)
5671 message = 'Removed tag %s' % ', '.join(names)
5670 elif not opts.get('force'):
5672 elif not opts.get('force'):
5671 for n in names:
5673 for n in names:
5672 if n in repo.tags():
5674 if n in repo.tags():
5673 raise util.Abort(_("tag '%s' already exists "
5675 raise util.Abort(_("tag '%s' already exists "
5674 "(use -f to force)") % n)
5676 "(use -f to force)") % n)
5675 if not opts.get('local'):
5677 if not opts.get('local'):
5676 p1, p2 = repo.dirstate.parents()
5678 p1, p2 = repo.dirstate.parents()
5677 if p2 != nullid:
5679 if p2 != nullid:
5678 raise util.Abort(_('uncommitted merge'))
5680 raise util.Abort(_('uncommitted merge'))
5679 bheads = repo.branchheads()
5681 bheads = repo.branchheads()
5680 if not opts.get('force') and bheads and p1 not in bheads:
5682 if not opts.get('force') and bheads and p1 not in bheads:
5681 raise util.Abort(_('not at a branch head (use -f to force)'))
5683 raise util.Abort(_('not at a branch head (use -f to force)'))
5682 r = scmutil.revsingle(repo, rev_).node()
5684 r = scmutil.revsingle(repo, rev_).node()
5683
5685
5684 if not message:
5686 if not message:
5685 # we don't translate commit messages
5687 # we don't translate commit messages
5686 message = ('Added tag %s for changeset %s' %
5688 message = ('Added tag %s for changeset %s' %
5687 (', '.join(names), short(r)))
5689 (', '.join(names), short(r)))
5688
5690
5689 date = opts.get('date')
5691 date = opts.get('date')
5690 if date:
5692 if date:
5691 date = util.parsedate(date)
5693 date = util.parsedate(date)
5692
5694
5693 if opts.get('edit'):
5695 if opts.get('edit'):
5694 message = ui.edit(message, ui.username())
5696 message = ui.edit(message, ui.username())
5695
5697
5696 # don't allow tagging the null rev
5698 # don't allow tagging the null rev
5697 if (not opts.get('remove') and
5699 if (not opts.get('remove') and
5698 scmutil.revsingle(repo, rev_).rev() == nullrev):
5700 scmutil.revsingle(repo, rev_).rev() == nullrev):
5699 raise util.Abort(_("null revision specified"))
5701 raise util.Abort(_("null revision specified"))
5700
5702
5701 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5703 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5702 finally:
5704 finally:
5703 release(lock, wlock)
5705 release(lock, wlock)
5704
5706
5705 @command('tags', [], '')
5707 @command('tags', [], '')
5706 def tags(ui, repo):
5708 def tags(ui, repo):
5707 """list repository tags
5709 """list repository tags
5708
5710
5709 This lists both regular and local tags. When the -v/--verbose
5711 This lists both regular and local tags. When the -v/--verbose
5710 switch is used, a third column "local" is printed for local tags.
5712 switch is used, a third column "local" is printed for local tags.
5711
5713
5712 Returns 0 on success.
5714 Returns 0 on success.
5713 """
5715 """
5714
5716
5715 hexfunc = ui.debugflag and hex or short
5717 hexfunc = ui.debugflag and hex or short
5716 tagtype = ""
5718 tagtype = ""
5717
5719
5718 for t, n in reversed(repo.tagslist()):
5720 for t, n in reversed(repo.tagslist()):
5719 if ui.quiet:
5721 if ui.quiet:
5720 ui.write("%s\n" % t, label='tags.normal')
5722 ui.write("%s\n" % t, label='tags.normal')
5721 continue
5723 continue
5722
5724
5723 hn = hexfunc(n)
5725 hn = hexfunc(n)
5724 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5726 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5725 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5727 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5726 spaces = " " * (30 - encoding.colwidth(t))
5728 spaces = " " * (30 - encoding.colwidth(t))
5727
5729
5728 tag = ui.label(t, 'tags.normal')
5730 tag = ui.label(t, 'tags.normal')
5729 if ui.verbose:
5731 if ui.verbose:
5730 if repo.tagtype(t) == 'local':
5732 if repo.tagtype(t) == 'local':
5731 tagtype = " local"
5733 tagtype = " local"
5732 tag = ui.label(t, 'tags.local')
5734 tag = ui.label(t, 'tags.local')
5733 else:
5735 else:
5734 tagtype = ""
5736 tagtype = ""
5735 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5737 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5736
5738
5737 @command('tip',
5739 @command('tip',
5738 [('p', 'patch', None, _('show patch')),
5740 [('p', 'patch', None, _('show patch')),
5739 ('g', 'git', None, _('use git extended diff format')),
5741 ('g', 'git', None, _('use git extended diff format')),
5740 ] + templateopts,
5742 ] + templateopts,
5741 _('[-p] [-g]'))
5743 _('[-p] [-g]'))
5742 def tip(ui, repo, **opts):
5744 def tip(ui, repo, **opts):
5743 """show the tip revision
5745 """show the tip revision
5744
5746
5745 The tip revision (usually just called the tip) is the changeset
5747 The tip revision (usually just called the tip) is the changeset
5746 most recently added to the repository (and therefore the most
5748 most recently added to the repository (and therefore the most
5747 recently changed head).
5749 recently changed head).
5748
5750
5749 If you have just made a commit, that commit will be the tip. If
5751 If you have just made a commit, that commit will be the tip. If
5750 you have just pulled changes from another repository, the tip of
5752 you have just pulled changes from another repository, the tip of
5751 that repository becomes the current tip. The "tip" tag is special
5753 that repository becomes the current tip. The "tip" tag is special
5752 and cannot be renamed or assigned to a different changeset.
5754 and cannot be renamed or assigned to a different changeset.
5753
5755
5754 Returns 0 on success.
5756 Returns 0 on success.
5755 """
5757 """
5756 displayer = cmdutil.show_changeset(ui, repo, opts)
5758 displayer = cmdutil.show_changeset(ui, repo, opts)
5757 displayer.show(repo[len(repo) - 1])
5759 displayer.show(repo[len(repo) - 1])
5758 displayer.close()
5760 displayer.close()
5759
5761
5760 @command('unbundle',
5762 @command('unbundle',
5761 [('u', 'update', None,
5763 [('u', 'update', None,
5762 _('update to new branch head if changesets were unbundled'))],
5764 _('update to new branch head if changesets were unbundled'))],
5763 _('[-u] FILE...'))
5765 _('[-u] FILE...'))
5764 def unbundle(ui, repo, fname1, *fnames, **opts):
5766 def unbundle(ui, repo, fname1, *fnames, **opts):
5765 """apply one or more changegroup files
5767 """apply one or more changegroup files
5766
5768
5767 Apply one or more compressed changegroup files generated by the
5769 Apply one or more compressed changegroup files generated by the
5768 bundle command.
5770 bundle command.
5769
5771
5770 Returns 0 on success, 1 if an update has unresolved files.
5772 Returns 0 on success, 1 if an update has unresolved files.
5771 """
5773 """
5772 fnames = (fname1,) + fnames
5774 fnames = (fname1,) + fnames
5773
5775
5774 lock = repo.lock()
5776 lock = repo.lock()
5775 wc = repo['.']
5777 wc = repo['.']
5776 try:
5778 try:
5777 for fname in fnames:
5779 for fname in fnames:
5778 f = url.open(ui, fname)
5780 f = url.open(ui, fname)
5779 gen = changegroup.readbundle(f, fname)
5781 gen = changegroup.readbundle(f, fname)
5780 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5782 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5781 finally:
5783 finally:
5782 lock.release()
5784 lock.release()
5783 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5785 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5784 return postincoming(ui, repo, modheads, opts.get('update'), None)
5786 return postincoming(ui, repo, modheads, opts.get('update'), None)
5785
5787
5786 @command('^update|up|checkout|co',
5788 @command('^update|up|checkout|co',
5787 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5789 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5788 ('c', 'check', None,
5790 ('c', 'check', None,
5789 _('update across branches if no uncommitted changes')),
5791 _('update across branches if no uncommitted changes')),
5790 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5792 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5791 ('r', 'rev', '', _('revision'), _('REV'))],
5793 ('r', 'rev', '', _('revision'), _('REV'))],
5792 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5794 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5793 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5795 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5794 """update working directory (or switch revisions)
5796 """update working directory (or switch revisions)
5795
5797
5796 Update the repository's working directory to the specified
5798 Update the repository's working directory to the specified
5797 changeset. If no changeset is specified, update to the tip of the
5799 changeset. If no changeset is specified, update to the tip of the
5798 current named branch and move the current bookmark (see :hg:`help
5800 current named branch and move the current bookmark (see :hg:`help
5799 bookmarks`).
5801 bookmarks`).
5800
5802
5801 Update sets the working directory's parent revision to the specified
5803 Update sets the working directory's parent revision to the specified
5802 changeset (see :hg:`help parents`).
5804 changeset (see :hg:`help parents`).
5803
5805
5804 If the changeset is not a descendant or ancestor of the working
5806 If the changeset is not a descendant or ancestor of the working
5805 directory's parent, the update is aborted. With the -c/--check
5807 directory's parent, the update is aborted. With the -c/--check
5806 option, the working directory is checked for uncommitted changes; if
5808 option, the working directory is checked for uncommitted changes; if
5807 none are found, the working directory is updated to the specified
5809 none are found, the working directory is updated to the specified
5808 changeset.
5810 changeset.
5809
5811
5810 .. container:: verbose
5812 .. container:: verbose
5811
5813
5812 The following rules apply when the working directory contains
5814 The following rules apply when the working directory contains
5813 uncommitted changes:
5815 uncommitted changes:
5814
5816
5815 1. If neither -c/--check nor -C/--clean is specified, and if
5817 1. If neither -c/--check nor -C/--clean is specified, and if
5816 the requested changeset is an ancestor or descendant of
5818 the requested changeset is an ancestor or descendant of
5817 the working directory's parent, the uncommitted changes
5819 the working directory's parent, the uncommitted changes
5818 are merged into the requested changeset and the merged
5820 are merged into the requested changeset and the merged
5819 result is left uncommitted. If the requested changeset is
5821 result is left uncommitted. If the requested changeset is
5820 not an ancestor or descendant (that is, it is on another
5822 not an ancestor or descendant (that is, it is on another
5821 branch), the update is aborted and the uncommitted changes
5823 branch), the update is aborted and the uncommitted changes
5822 are preserved.
5824 are preserved.
5823
5825
5824 2. With the -c/--check option, the update is aborted and the
5826 2. With the -c/--check option, the update is aborted and the
5825 uncommitted changes are preserved.
5827 uncommitted changes are preserved.
5826
5828
5827 3. With the -C/--clean option, uncommitted changes are discarded and
5829 3. With the -C/--clean option, uncommitted changes are discarded and
5828 the working directory is updated to the requested changeset.
5830 the working directory is updated to the requested changeset.
5829
5831
5830 To cancel an uncommitted merge (and lose your changes), use
5832 To cancel an uncommitted merge (and lose your changes), use
5831 :hg:`update --clean .`.
5833 :hg:`update --clean .`.
5832
5834
5833 Use null as the changeset to remove the working directory (like
5835 Use null as the changeset to remove the working directory (like
5834 :hg:`clone -U`).
5836 :hg:`clone -U`).
5835
5837
5836 If you want to revert just one file to an older revision, use
5838 If you want to revert just one file to an older revision, use
5837 :hg:`revert [-r REV] NAME`.
5839 :hg:`revert [-r REV] NAME`.
5838
5840
5839 See :hg:`help dates` for a list of formats valid for -d/--date.
5841 See :hg:`help dates` for a list of formats valid for -d/--date.
5840
5842
5841 Returns 0 on success, 1 if there are unresolved files.
5843 Returns 0 on success, 1 if there are unresolved files.
5842 """
5844 """
5843 if rev and node:
5845 if rev and node:
5844 raise util.Abort(_("please specify just one revision"))
5846 raise util.Abort(_("please specify just one revision"))
5845
5847
5846 if rev is None or rev == '':
5848 if rev is None or rev == '':
5847 rev = node
5849 rev = node
5848
5850
5849 # with no argument, we also move the current bookmark, if any
5851 # with no argument, we also move the current bookmark, if any
5850 movemarkfrom = None
5852 movemarkfrom = None
5851 if rev is None:
5853 if rev is None:
5852 movemarkfrom = repo['.'].node()
5854 movemarkfrom = repo['.'].node()
5853
5855
5854 # if we defined a bookmark, we have to remember the original bookmark name
5856 # if we defined a bookmark, we have to remember the original bookmark name
5855 brev = rev
5857 brev = rev
5856 rev = scmutil.revsingle(repo, rev, rev).rev()
5858 rev = scmutil.revsingle(repo, rev, rev).rev()
5857
5859
5858 if check and clean:
5860 if check and clean:
5859 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5861 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5860
5862
5861 if date:
5863 if date:
5862 if rev is not None:
5864 if rev is not None:
5863 raise util.Abort(_("you can't specify a revision and a date"))
5865 raise util.Abort(_("you can't specify a revision and a date"))
5864 rev = cmdutil.finddate(ui, repo, date)
5866 rev = cmdutil.finddate(ui, repo, date)
5865
5867
5866 if check:
5868 if check:
5867 c = repo[None]
5869 c = repo[None]
5868 if c.dirty(merge=False, branch=False):
5870 if c.dirty(merge=False, branch=False):
5869 raise util.Abort(_("uncommitted local changes"))
5871 raise util.Abort(_("uncommitted local changes"))
5870 if rev is None:
5872 if rev is None:
5871 rev = repo[repo[None].branch()].rev()
5873 rev = repo[repo[None].branch()].rev()
5872 mergemod._checkunknown(repo, repo[None], repo[rev])
5874 mergemod._checkunknown(repo, repo[None], repo[rev])
5873
5875
5874 if clean:
5876 if clean:
5875 ret = hg.clean(repo, rev)
5877 ret = hg.clean(repo, rev)
5876 else:
5878 else:
5877 ret = hg.update(repo, rev)
5879 ret = hg.update(repo, rev)
5878
5880
5879 if not ret and movemarkfrom:
5881 if not ret and movemarkfrom:
5880 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5882 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5881 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5883 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5882 elif brev in repo._bookmarks:
5884 elif brev in repo._bookmarks:
5883 bookmarks.setcurrent(repo, brev)
5885 bookmarks.setcurrent(repo, brev)
5884 elif brev:
5886 elif brev:
5885 bookmarks.unsetcurrent(repo)
5887 bookmarks.unsetcurrent(repo)
5886
5888
5887 return ret
5889 return ret
5888
5890
5889 @command('verify', [])
5891 @command('verify', [])
5890 def verify(ui, repo):
5892 def verify(ui, repo):
5891 """verify the integrity of the repository
5893 """verify the integrity of the repository
5892
5894
5893 Verify the integrity of the current repository.
5895 Verify the integrity of the current repository.
5894
5896
5895 This will perform an extensive check of the repository's
5897 This will perform an extensive check of the repository's
5896 integrity, validating the hashes and checksums of each entry in
5898 integrity, validating the hashes and checksums of each entry in
5897 the changelog, manifest, and tracked files, as well as the
5899 the changelog, manifest, and tracked files, as well as the
5898 integrity of their crosslinks and indices.
5900 integrity of their crosslinks and indices.
5899
5901
5900 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5902 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5901 for more information about recovery from corruption of the
5903 for more information about recovery from corruption of the
5902 repository.
5904 repository.
5903
5905
5904 Returns 0 on success, 1 if errors are encountered.
5906 Returns 0 on success, 1 if errors are encountered.
5905 """
5907 """
5906 return hg.verify(repo)
5908 return hg.verify(repo)
5907
5909
5908 @command('version', [])
5910 @command('version', [])
5909 def version_(ui):
5911 def version_(ui):
5910 """output version and copyright information"""
5912 """output version and copyright information"""
5911 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5913 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5912 % util.version())
5914 % util.version())
5913 ui.status(_(
5915 ui.status(_(
5914 "(see http://mercurial.selenic.com for more information)\n"
5916 "(see http://mercurial.selenic.com for more information)\n"
5915 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5917 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5916 "This is free software; see the source for copying conditions. "
5918 "This is free software; see the source for copying conditions. "
5917 "There is NO\nwarranty; "
5919 "There is NO\nwarranty; "
5918 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5920 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5919 ))
5921 ))
5920
5922
5921 norepo = ("clone init version help debugcommands debugcomplete"
5923 norepo = ("clone init version help debugcommands debugcomplete"
5922 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5924 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5923 " debugknown debuggetbundle debugbundle")
5925 " debugknown debuggetbundle debugbundle")
5924 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5926 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5925 " debugdata debugindex debugindexdot debugrevlog")
5927 " debugdata debugindex debugindexdot debugrevlog")
5926 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5928 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5927 " remove resolve status debugwalk")
5929 " remove resolve status debugwalk")
@@ -1,276 +1,276 b''
1 Show all commands except debug commands
1 Show all commands except debug commands
2 $ hg debugcomplete
2 $ hg debugcomplete
3 add
3 add
4 addremove
4 addremove
5 annotate
5 annotate
6 archive
6 archive
7 backout
7 backout
8 bisect
8 bisect
9 bookmarks
9 bookmarks
10 branch
10 branch
11 branches
11 branches
12 bundle
12 bundle
13 cat
13 cat
14 clone
14 clone
15 commit
15 commit
16 copy
16 copy
17 diff
17 diff
18 export
18 export
19 forget
19 forget
20 graft
20 graft
21 grep
21 grep
22 heads
22 heads
23 help
23 help
24 identify
24 identify
25 import
25 import
26 incoming
26 incoming
27 init
27 init
28 locate
28 locate
29 log
29 log
30 manifest
30 manifest
31 merge
31 merge
32 outgoing
32 outgoing
33 parents
33 parents
34 paths
34 paths
35 phase
35 phase
36 pull
36 pull
37 push
37 push
38 recover
38 recover
39 remove
39 remove
40 rename
40 rename
41 resolve
41 resolve
42 revert
42 revert
43 rollback
43 rollback
44 root
44 root
45 serve
45 serve
46 showconfig
46 showconfig
47 status
47 status
48 summary
48 summary
49 tag
49 tag
50 tags
50 tags
51 tip
51 tip
52 unbundle
52 unbundle
53 update
53 update
54 verify
54 verify
55 version
55 version
56
56
57 Show all commands that start with "a"
57 Show all commands that start with "a"
58 $ hg debugcomplete a
58 $ hg debugcomplete a
59 add
59 add
60 addremove
60 addremove
61 annotate
61 annotate
62 archive
62 archive
63
63
64 Do not show debug commands if there are other candidates
64 Do not show debug commands if there are other candidates
65 $ hg debugcomplete d
65 $ hg debugcomplete d
66 diff
66 diff
67
67
68 Show debug commands if there are no other candidates
68 Show debug commands if there are no other candidates
69 $ hg debugcomplete debug
69 $ hg debugcomplete debug
70 debugancestor
70 debugancestor
71 debugbuilddag
71 debugbuilddag
72 debugbundle
72 debugbundle
73 debugcheckstate
73 debugcheckstate
74 debugcommands
74 debugcommands
75 debugcomplete
75 debugcomplete
76 debugconfig
76 debugconfig
77 debugdag
77 debugdag
78 debugdata
78 debugdata
79 debugdate
79 debugdate
80 debugdiscovery
80 debugdiscovery
81 debugfileset
81 debugfileset
82 debugfsinfo
82 debugfsinfo
83 debuggetbundle
83 debuggetbundle
84 debugignore
84 debugignore
85 debugindex
85 debugindex
86 debugindexdot
86 debugindexdot
87 debuginstall
87 debuginstall
88 debugknown
88 debugknown
89 debugobsolete
89 debugobsolete
90 debugpushkey
90 debugpushkey
91 debugpvec
91 debugpvec
92 debugrebuildstate
92 debugrebuildstate
93 debugrename
93 debugrename
94 debugrevlog
94 debugrevlog
95 debugrevspec
95 debugrevspec
96 debugsetparents
96 debugsetparents
97 debugstate
97 debugstate
98 debugsub
98 debugsub
99 debugwalk
99 debugwalk
100 debugwireargs
100 debugwireargs
101
101
102 Do not show the alias of a debug command if there are other candidates
102 Do not show the alias of a debug command if there are other candidates
103 (this should hide rawcommit)
103 (this should hide rawcommit)
104 $ hg debugcomplete r
104 $ hg debugcomplete r
105 recover
105 recover
106 remove
106 remove
107 rename
107 rename
108 resolve
108 resolve
109 revert
109 revert
110 rollback
110 rollback
111 root
111 root
112 Show the alias of a debug command if there are no other candidates
112 Show the alias of a debug command if there are no other candidates
113 $ hg debugcomplete rawc
113 $ hg debugcomplete rawc
114
114
115
115
116 Show the global options
116 Show the global options
117 $ hg debugcomplete --options | sort
117 $ hg debugcomplete --options | sort
118 --config
118 --config
119 --cwd
119 --cwd
120 --debug
120 --debug
121 --debugger
121 --debugger
122 --encoding
122 --encoding
123 --encodingmode
123 --encodingmode
124 --help
124 --help
125 --noninteractive
125 --noninteractive
126 --profile
126 --profile
127 --quiet
127 --quiet
128 --repository
128 --repository
129 --time
129 --time
130 --traceback
130 --traceback
131 --verbose
131 --verbose
132 --version
132 --version
133 -R
133 -R
134 -h
134 -h
135 -q
135 -q
136 -v
136 -v
137 -y
137 -y
138
138
139 Show the options for the "serve" command
139 Show the options for the "serve" command
140 $ hg debugcomplete --options serve | sort
140 $ hg debugcomplete --options serve | sort
141 --accesslog
141 --accesslog
142 --address
142 --address
143 --certificate
143 --certificate
144 --cmdserver
144 --cmdserver
145 --config
145 --config
146 --cwd
146 --cwd
147 --daemon
147 --daemon
148 --daemon-pipefds
148 --daemon-pipefds
149 --debug
149 --debug
150 --debugger
150 --debugger
151 --encoding
151 --encoding
152 --encodingmode
152 --encodingmode
153 --errorlog
153 --errorlog
154 --help
154 --help
155 --ipv6
155 --ipv6
156 --name
156 --name
157 --noninteractive
157 --noninteractive
158 --pid-file
158 --pid-file
159 --port
159 --port
160 --prefix
160 --prefix
161 --profile
161 --profile
162 --quiet
162 --quiet
163 --repository
163 --repository
164 --stdio
164 --stdio
165 --style
165 --style
166 --templates
166 --templates
167 --time
167 --time
168 --traceback
168 --traceback
169 --verbose
169 --verbose
170 --version
170 --version
171 --web-conf
171 --web-conf
172 -6
172 -6
173 -A
173 -A
174 -E
174 -E
175 -R
175 -R
176 -a
176 -a
177 -d
177 -d
178 -h
178 -h
179 -n
179 -n
180 -p
180 -p
181 -q
181 -q
182 -t
182 -t
183 -v
183 -v
184 -y
184 -y
185
185
186 Show an error if we use --options with an ambiguous abbreviation
186 Show an error if we use --options with an ambiguous abbreviation
187 $ hg debugcomplete --options s
187 $ hg debugcomplete --options s
188 hg: command 's' is ambiguous:
188 hg: command 's' is ambiguous:
189 serve showconfig status summary
189 serve showconfig status summary
190 [255]
190 [255]
191
191
192 Show all commands + options
192 Show all commands + options
193 $ hg debugcommands
193 $ hg debugcommands
194 add: include, exclude, subrepos, dry-run
194 add: include, exclude, subrepos, dry-run
195 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
195 annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude
196 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
196 clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure
197 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
197 commit: addremove, close-branch, amend, include, exclude, message, logfile, date, user, subrepos
198 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
198 diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos
199 export: output, switch-parent, rev, text, git, nodates
199 export: output, switch-parent, rev, text, git, nodates
200 forget: include, exclude
200 forget: include, exclude
201 init: ssh, remotecmd, insecure
201 init: ssh, remotecmd, insecure
202 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
202 log: follow, follow-first, date, copies, keyword, rev, removed, only-merges, user, only-branch, branch, prune, hidden, patch, git, limit, no-merges, stat, graph, style, template, include, exclude
203 merge: force, rev, preview, tool
203 merge: force, rev, preview, tool
204 phase: public, draft, secret, force, rev
204 phase: public, draft, secret, force, rev
205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
205 pull: update, force, rev, bookmark, branch, ssh, remotecmd, insecure
206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
206 push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure
207 remove: after, force, include, exclude
207 remove: after, force, include, exclude
208 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
208 serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
209 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
209 status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos
210 summary: remote
210 summary: remote
211 update: clean, check, date, rev
211 update: clean, check, date, rev
212 addremove: similarity, include, exclude, dry-run
212 addremove: similarity, include, exclude, dry-run
213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
213 archive: no-decode, prefix, rev, type, subrepos, include, exclude
214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
214 backout: merge, parent, rev, tool, include, exclude, message, logfile, date, user
215 bisect: reset, good, bad, skip, extend, command, noupdate
215 bisect: reset, good, bad, skip, extend, command, noupdate
216 bookmarks: force, rev, delete, rename, inactive
216 bookmarks: force, rev, delete, rename, inactive
217 branch: force, clean
217 branch: force, clean
218 branches: active, closed
218 branches: active, closed
219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
219 bundle: force, rev, branch, base, all, type, ssh, remotecmd, insecure
220 cat: output, rev, decode, include, exclude
220 cat: output, rev, decode, include, exclude
221 copy: after, force, include, exclude, dry-run
221 copy: after, force, include, exclude, dry-run
222 debugancestor:
222 debugancestor:
223 debugbuilddag: mergeable-file, overwritten-file, new-file
223 debugbuilddag: mergeable-file, overwritten-file, new-file
224 debugbundle: all
224 debugbundle: all
225 debugcheckstate:
225 debugcheckstate:
226 debugcommands:
226 debugcommands:
227 debugcomplete: options
227 debugcomplete: options
228 debugdag: tags, branches, dots, spaces
228 debugdag: tags, branches, dots, spaces
229 debugdata: changelog, manifest
229 debugdata: changelog, manifest
230 debugdate: extended
230 debugdate: extended
231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
231 debugdiscovery: old, nonheads, ssh, remotecmd, insecure
232 debugfileset: rev
232 debugfileset: rev
233 debugfsinfo:
233 debugfsinfo:
234 debuggetbundle: head, common, type
234 debuggetbundle: head, common, type
235 debugignore:
235 debugignore:
236 debugindex: changelog, manifest, format
236 debugindex: changelog, manifest, format
237 debugindexdot:
237 debugindexdot:
238 debuginstall:
238 debuginstall:
239 debugknown:
239 debugknown:
240 debugobsolete: date, user
240 debugobsolete: flags, date, user
241 debugpushkey:
241 debugpushkey:
242 debugpvec:
242 debugpvec:
243 debugrebuildstate: rev
243 debugrebuildstate: rev
244 debugrename: rev
244 debugrename: rev
245 debugrevlog: changelog, manifest, dump
245 debugrevlog: changelog, manifest, dump
246 debugrevspec:
246 debugrevspec:
247 debugsetparents:
247 debugsetparents:
248 debugstate: nodates, datesort
248 debugstate: nodates, datesort
249 debugsub: rev
249 debugsub: rev
250 debugwalk: include, exclude
250 debugwalk: include, exclude
251 debugwireargs: three, four, five, ssh, remotecmd, insecure
251 debugwireargs: three, four, five, ssh, remotecmd, insecure
252 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
252 graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run
253 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
253 grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude
254 heads: rev, topo, active, closed, style, template
254 heads: rev, topo, active, closed, style, template
255 help: extension, command, keyword
255 help: extension, command, keyword
256 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
256 identify: rev, num, id, branch, tags, bookmarks, ssh, remotecmd, insecure
257 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
257 import: strip, base, edit, force, no-commit, bypass, exact, import-branch, message, logfile, date, user, similarity
258 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
258 incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
259 locate: rev, print0, fullpath, include, exclude
259 locate: rev, print0, fullpath, include, exclude
260 manifest: rev, all
260 manifest: rev, all
261 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
261 outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos
262 parents: rev, style, template
262 parents: rev, style, template
263 paths:
263 paths:
264 recover:
264 recover:
265 rename: after, force, include, exclude, dry-run
265 rename: after, force, include, exclude, dry-run
266 resolve: all, list, mark, unmark, no-status, tool, include, exclude
266 resolve: all, list, mark, unmark, no-status, tool, include, exclude
267 revert: all, date, rev, no-backup, include, exclude, dry-run
267 revert: all, date, rev, no-backup, include, exclude, dry-run
268 rollback: dry-run, force
268 rollback: dry-run, force
269 root:
269 root:
270 showconfig: untrusted
270 showconfig: untrusted
271 tag: force, local, rev, remove, edit, message, date, user
271 tag: force, local, rev, remove, edit, message, date, user
272 tags:
272 tags:
273 tip: patch, git, style, template
273 tip: patch, git, style, template
274 unbundle: update
274 unbundle: update
275 verify:
275 verify:
276 version:
276 version:
@@ -1,534 +1,534 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [extensions]
2 > [extensions]
3 > graphlog=
3 > graphlog=
4 > [phases]
4 > [phases]
5 > # public changeset are not obsolete
5 > # public changeset are not obsolete
6 > publish=false
6 > publish=false
7 > EOF
7 > EOF
8 $ mkcommit() {
8 $ mkcommit() {
9 > echo "$1" > "$1"
9 > echo "$1" > "$1"
10 > hg add "$1"
10 > hg add "$1"
11 > hg ci -m "add $1"
11 > hg ci -m "add $1"
12 > }
12 > }
13 $ getid() {
13 $ getid() {
14 > hg id --debug -ir "desc('$1')"
14 > hg id --debug -ir "desc('$1')"
15 > }
15 > }
16
16
17 $ cat > debugkeys.py <<EOF
17 $ cat > debugkeys.py <<EOF
18 > def reposetup(ui, repo):
18 > def reposetup(ui, repo):
19 > class debugkeysrepo(repo.__class__):
19 > class debugkeysrepo(repo.__class__):
20 > def listkeys(self, namespace):
20 > def listkeys(self, namespace):
21 > ui.write('listkeys %s\n' % (namespace,))
21 > ui.write('listkeys %s\n' % (namespace,))
22 > return super(debugkeysrepo, self).listkeys(namespace)
22 > return super(debugkeysrepo, self).listkeys(namespace)
23 >
23 >
24 > if repo.local():
24 > if repo.local():
25 > repo.__class__ = debugkeysrepo
25 > repo.__class__ = debugkeysrepo
26 > EOF
26 > EOF
27
27
28 $ hg init tmpa
28 $ hg init tmpa
29 $ cd tmpa
29 $ cd tmpa
30 $ mkcommit kill_me
30 $ mkcommit kill_me
31
31
32 Checking that the feature is properly disabled
32 Checking that the feature is properly disabled
33
33
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 abort: obsolete feature is not enabled on this repo
35 abort: obsolete feature is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat > ../obs.py << EOF
40 $ cat > ../obs.py << EOF
41 > import mercurial.obsolete
41 > import mercurial.obsolete
42 > mercurial.obsolete._enabled = True
42 > mercurial.obsolete._enabled = True
43 > EOF
43 > EOF
44 $ echo '[extensions]' >> $HGRCPATH
44 $ echo '[extensions]' >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
46
46
47 Killing a single changeset without replacement
47 Killing a single changeset without replacement
48
48
49 $ hg debugobsolete 0
49 $ hg debugobsolete 0
50 abort: changeset references must be full hexadecimal node identifiers
50 abort: changeset references must be full hexadecimal node identifiers
51 [255]
51 [255]
52 $ hg debugobsolete '00'
52 $ hg debugobsolete '00'
53 abort: changeset references must be full hexadecimal node identifiers
53 abort: changeset references must be full hexadecimal node identifiers
54 [255]
54 [255]
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
56 $ hg debugobsolete
56 $ hg debugobsolete
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
58 $ cd ..
58 $ cd ..
59
59
60 Killing a single changeset with replacement
60 Killing a single changeset with replacement
61
61
62 $ hg init tmpb
62 $ hg init tmpb
63 $ cd tmpb
63 $ cd tmpb
64 $ mkcommit a
64 $ mkcommit a
65 $ mkcommit b
65 $ mkcommit b
66 $ mkcommit original_c
66 $ mkcommit original_c
67 $ hg up "desc('b')"
67 $ hg up "desc('b')"
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
69 $ mkcommit new_c
69 $ mkcommit new_c
70 created new head
70 created new head
71 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
71 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
72 $ hg debugobsolete `getid original_c` `getid new_c` -d '56 12'
72 $ hg debugobsolete --flag 12 `getid original_c` `getid new_c` -d '56 12'
73 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
73 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
74 2:245bde4270cd add original_c
74 2:245bde4270cd add original_c
75 $ hg debugobsolete
75 $ hg debugobsolete
76 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
76 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
77
77
78 do it again (it read the obsstore before adding new changeset)
78 do it again (it read the obsstore before adding new changeset)
79
79
80 $ hg up '.^'
80 $ hg up '.^'
81 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
81 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
82 $ mkcommit new_2_c
82 $ mkcommit new_2_c
83 created new head
83 created new head
84 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
84 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
85 $ hg debugobsolete
85 $ hg debugobsolete
86 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
86 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
87 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
87 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
88
88
89 Register two markers with a missing node
89 Register two markers with a missing node
90
90
91 $ hg up '.^'
91 $ hg up '.^'
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 $ mkcommit new_3_c
93 $ mkcommit new_3_c
94 created new head
94 created new head
95 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
95 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
96 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
96 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
97 $ hg debugobsolete
97 $ hg debugobsolete
98 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
98 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
99 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
99 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
100 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
100 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
101 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
101 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
102
102
103 Refuse pathological nullid successors
103 Refuse pathological nullid successors
104 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
104 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
105 transaction abort!
105 transaction abort!
106 rollback completed
106 rollback completed
107 abort: bad obsolescence marker detected: invalid successors nullid
107 abort: bad obsolescence marker detected: invalid successors nullid
108 [255]
108 [255]
109
109
110 Check that graphlog detect that a changeset is obsolete:
110 Check that graphlog detect that a changeset is obsolete:
111
111
112 $ hg glog
112 $ hg glog
113 @ changeset: 5:5601fb93a350
113 @ changeset: 5:5601fb93a350
114 | tag: tip
114 | tag: tip
115 | parent: 1:7c3bad9141dc
115 | parent: 1:7c3bad9141dc
116 | user: test
116 | user: test
117 | date: Thu Jan 01 00:00:00 1970 +0000
117 | date: Thu Jan 01 00:00:00 1970 +0000
118 | summary: add new_3_c
118 | summary: add new_3_c
119 |
119 |
120 o changeset: 1:7c3bad9141dc
120 o changeset: 1:7c3bad9141dc
121 | user: test
121 | user: test
122 | date: Thu Jan 01 00:00:00 1970 +0000
122 | date: Thu Jan 01 00:00:00 1970 +0000
123 | summary: add b
123 | summary: add b
124 |
124 |
125 o changeset: 0:1f0dee641bb7
125 o changeset: 0:1f0dee641bb7
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:00 1970 +0000
127 date: Thu Jan 01 00:00:00 1970 +0000
128 summary: add a
128 summary: add a
129
129
130
130
131 Check that public changeset are not accounted as obsolete:
131 Check that public changeset are not accounted as obsolete:
132
132
133 $ hg phase --public 2
133 $ hg phase --public 2
134 $ hg --config 'extensions.graphlog=' glog
134 $ hg --config 'extensions.graphlog=' glog
135 @ changeset: 5:5601fb93a350
135 @ changeset: 5:5601fb93a350
136 | tag: tip
136 | tag: tip
137 | parent: 1:7c3bad9141dc
137 | parent: 1:7c3bad9141dc
138 | user: test
138 | user: test
139 | date: Thu Jan 01 00:00:00 1970 +0000
139 | date: Thu Jan 01 00:00:00 1970 +0000
140 | summary: add new_3_c
140 | summary: add new_3_c
141 |
141 |
142 | o changeset: 2:245bde4270cd
142 | o changeset: 2:245bde4270cd
143 |/ user: test
143 |/ user: test
144 | date: Thu Jan 01 00:00:00 1970 +0000
144 | date: Thu Jan 01 00:00:00 1970 +0000
145 | summary: add original_c
145 | summary: add original_c
146 |
146 |
147 o changeset: 1:7c3bad9141dc
147 o changeset: 1:7c3bad9141dc
148 | user: test
148 | user: test
149 | date: Thu Jan 01 00:00:00 1970 +0000
149 | date: Thu Jan 01 00:00:00 1970 +0000
150 | summary: add b
150 | summary: add b
151 |
151 |
152 o changeset: 0:1f0dee641bb7
152 o changeset: 0:1f0dee641bb7
153 user: test
153 user: test
154 date: Thu Jan 01 00:00:00 1970 +0000
154 date: Thu Jan 01 00:00:00 1970 +0000
155 summary: add a
155 summary: add a
156
156
157
157
158 And that bumped changeset are detected
158 And that bumped changeset are detected
159 --------------------------------------
159 --------------------------------------
160
160
161 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
161 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
162 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
162 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
163 the public changeset
163 the public changeset
164
164
165 $ hg log --hidden -r 'bumped()'
165 $ hg log --hidden -r 'bumped()'
166 changeset: 5:5601fb93a350
166 changeset: 5:5601fb93a350
167 tag: tip
167 tag: tip
168 parent: 1:7c3bad9141dc
168 parent: 1:7c3bad9141dc
169 user: test
169 user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: add new_3_c
171 summary: add new_3_c
172
172
173
173
174 $ cd ..
174 $ cd ..
175
175
176 Exchange Test
176 Exchange Test
177 ============================
177 ============================
178
178
179 Destination repo does not have any data
179 Destination repo does not have any data
180 ---------------------------------------
180 ---------------------------------------
181
181
182 Try to pull markers
182 Try to pull markers
183 (extinct changeset are excluded but marker are pushed)
183 (extinct changeset are excluded but marker are pushed)
184
184
185 $ hg init tmpc
185 $ hg init tmpc
186 $ cd tmpc
186 $ cd tmpc
187 $ hg pull ../tmpb
187 $ hg pull ../tmpb
188 pulling from ../tmpb
188 pulling from ../tmpb
189 requesting all changes
189 requesting all changes
190 adding changesets
190 adding changesets
191 adding manifests
191 adding manifests
192 adding file changes
192 adding file changes
193 added 4 changesets with 4 changes to 4 files (+1 heads)
193 added 4 changesets with 4 changes to 4 files (+1 heads)
194 (run 'hg heads' to see heads, 'hg merge' to merge)
194 (run 'hg heads' to see heads, 'hg merge' to merge)
195 $ hg debugobsolete
195 $ hg debugobsolete
196 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
196 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
197 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
197 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
198 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
198 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
199 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
199 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
200
200
201 Rollback//Transaction support
201 Rollback//Transaction support
202
202
203 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
203 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
204 $ hg debugobsolete
204 $ hg debugobsolete
205 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
205 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
206 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
206 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
207 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
207 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
208 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
208 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
209 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
209 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
210 $ hg rollback -n
210 $ hg rollback -n
211 repository tip rolled back to revision 3 (undo debugobsolete)
211 repository tip rolled back to revision 3 (undo debugobsolete)
212 $ hg rollback
212 $ hg rollback
213 repository tip rolled back to revision 3 (undo debugobsolete)
213 repository tip rolled back to revision 3 (undo debugobsolete)
214 $ hg debugobsolete
214 $ hg debugobsolete
215 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
215 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
216 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
216 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
217 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
217 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
218 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
218 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
219
219
220 $ cd ..
220 $ cd ..
221
221
222 Try to pull markers
222 Try to pull markers
223
223
224 $ hg init tmpd
224 $ hg init tmpd
225 $ hg -R tmpb push tmpd
225 $ hg -R tmpb push tmpd
226 pushing to tmpd
226 pushing to tmpd
227 searching for changes
227 searching for changes
228 adding changesets
228 adding changesets
229 adding manifests
229 adding manifests
230 adding file changes
230 adding file changes
231 added 4 changesets with 4 changes to 4 files (+1 heads)
231 added 4 changesets with 4 changes to 4 files (+1 heads)
232 $ hg -R tmpd debugobsolete
232 $ hg -R tmpd debugobsolete
233 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
233 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
234 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
234 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
235 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
235 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
236 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
236 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
237
237
238 Check obsolete keys are exchanged only if source has an obsolete store
238 Check obsolete keys are exchanged only if source has an obsolete store
239
239
240 $ hg init empty
240 $ hg init empty
241 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
241 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
242 pushing to tmpd
242 pushing to tmpd
243 no changes found
243 no changes found
244 listkeys phases
244 listkeys phases
245 listkeys bookmarks
245 listkeys bookmarks
246 [1]
246 [1]
247
247
248 clone support
248 clone support
249 (markers are copied and extinct changesets are included to allow hardlinks)
249 (markers are copied and extinct changesets are included to allow hardlinks)
250
250
251 $ hg clone tmpb clone-dest
251 $ hg clone tmpb clone-dest
252 updating to branch default
252 updating to branch default
253 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 $ hg -R clone-dest log -G --hidden
254 $ hg -R clone-dest log -G --hidden
255 @ changeset: 5:5601fb93a350
255 @ changeset: 5:5601fb93a350
256 | tag: tip
256 | tag: tip
257 | parent: 1:7c3bad9141dc
257 | parent: 1:7c3bad9141dc
258 | user: test
258 | user: test
259 | date: Thu Jan 01 00:00:00 1970 +0000
259 | date: Thu Jan 01 00:00:00 1970 +0000
260 | summary: add new_3_c
260 | summary: add new_3_c
261 |
261 |
262 | x changeset: 4:ca819180edb9
262 | x changeset: 4:ca819180edb9
263 |/ parent: 1:7c3bad9141dc
263 |/ parent: 1:7c3bad9141dc
264 | user: test
264 | user: test
265 | date: Thu Jan 01 00:00:00 1970 +0000
265 | date: Thu Jan 01 00:00:00 1970 +0000
266 | summary: add new_2_c
266 | summary: add new_2_c
267 |
267 |
268 | x changeset: 3:cdbce2fbb163
268 | x changeset: 3:cdbce2fbb163
269 |/ parent: 1:7c3bad9141dc
269 |/ parent: 1:7c3bad9141dc
270 | user: test
270 | user: test
271 | date: Thu Jan 01 00:00:00 1970 +0000
271 | date: Thu Jan 01 00:00:00 1970 +0000
272 | summary: add new_c
272 | summary: add new_c
273 |
273 |
274 | o changeset: 2:245bde4270cd
274 | o changeset: 2:245bde4270cd
275 |/ user: test
275 |/ user: test
276 | date: Thu Jan 01 00:00:00 1970 +0000
276 | date: Thu Jan 01 00:00:00 1970 +0000
277 | summary: add original_c
277 | summary: add original_c
278 |
278 |
279 o changeset: 1:7c3bad9141dc
279 o changeset: 1:7c3bad9141dc
280 | user: test
280 | user: test
281 | date: Thu Jan 01 00:00:00 1970 +0000
281 | date: Thu Jan 01 00:00:00 1970 +0000
282 | summary: add b
282 | summary: add b
283 |
283 |
284 o changeset: 0:1f0dee641bb7
284 o changeset: 0:1f0dee641bb7
285 user: test
285 user: test
286 date: Thu Jan 01 00:00:00 1970 +0000
286 date: Thu Jan 01 00:00:00 1970 +0000
287 summary: add a
287 summary: add a
288
288
289 $ hg -R clone-dest debugobsolete
289 $ hg -R clone-dest debugobsolete
290 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
290 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
291 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
291 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
292 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
292 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
293 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
293 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
294
294
295
295
296 Destination repo have existing data
296 Destination repo have existing data
297 ---------------------------------------
297 ---------------------------------------
298
298
299 On pull
299 On pull
300
300
301 $ hg init tmpe
301 $ hg init tmpe
302 $ cd tmpe
302 $ cd tmpe
303 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
303 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
304 $ hg pull ../tmpb
304 $ hg pull ../tmpb
305 pulling from ../tmpb
305 pulling from ../tmpb
306 requesting all changes
306 requesting all changes
307 adding changesets
307 adding changesets
308 adding manifests
308 adding manifests
309 adding file changes
309 adding file changes
310 added 4 changesets with 4 changes to 4 files (+1 heads)
310 added 4 changesets with 4 changes to 4 files (+1 heads)
311 (run 'hg heads' to see heads, 'hg merge' to merge)
311 (run 'hg heads' to see heads, 'hg merge' to merge)
312 $ hg debugobsolete
312 $ hg debugobsolete
313 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
313 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
314 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
314 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
315 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
315 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
316 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
316 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
317 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
317 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
318
318
319
319
320 On push
320 On push
321
321
322 $ hg push ../tmpc
322 $ hg push ../tmpc
323 pushing to ../tmpc
323 pushing to ../tmpc
324 searching for changes
324 searching for changes
325 no changes found
325 no changes found
326 [1]
326 [1]
327 $ hg -R ../tmpc debugobsolete
327 $ hg -R ../tmpc debugobsolete
328 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
328 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
329 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
329 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
330 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
330 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
331 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
331 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
332 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
332 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
333
333
334 detect outgoing obsolete and unstable
334 detect outgoing obsolete and unstable
335 ---------------------------------------
335 ---------------------------------------
336
336
337
337
338 $ hg glog
338 $ hg glog
339 o changeset: 3:5601fb93a350
339 o changeset: 3:5601fb93a350
340 | tag: tip
340 | tag: tip
341 | parent: 1:7c3bad9141dc
341 | parent: 1:7c3bad9141dc
342 | user: test
342 | user: test
343 | date: Thu Jan 01 00:00:00 1970 +0000
343 | date: Thu Jan 01 00:00:00 1970 +0000
344 | summary: add new_3_c
344 | summary: add new_3_c
345 |
345 |
346 | o changeset: 2:245bde4270cd
346 | o changeset: 2:245bde4270cd
347 |/ user: test
347 |/ user: test
348 | date: Thu Jan 01 00:00:00 1970 +0000
348 | date: Thu Jan 01 00:00:00 1970 +0000
349 | summary: add original_c
349 | summary: add original_c
350 |
350 |
351 o changeset: 1:7c3bad9141dc
351 o changeset: 1:7c3bad9141dc
352 | user: test
352 | user: test
353 | date: Thu Jan 01 00:00:00 1970 +0000
353 | date: Thu Jan 01 00:00:00 1970 +0000
354 | summary: add b
354 | summary: add b
355 |
355 |
356 o changeset: 0:1f0dee641bb7
356 o changeset: 0:1f0dee641bb7
357 user: test
357 user: test
358 date: Thu Jan 01 00:00:00 1970 +0000
358 date: Thu Jan 01 00:00:00 1970 +0000
359 summary: add a
359 summary: add a
360
360
361 $ hg up 'desc("new_3_c")'
361 $ hg up 'desc("new_3_c")'
362 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
362 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 $ mkcommit original_d
363 $ mkcommit original_d
364 $ mkcommit original_e
364 $ mkcommit original_e
365 $ hg debugobsolete `getid original_d` -d '0 0'
365 $ hg debugobsolete `getid original_d` -d '0 0'
366 $ hg log -r 'obsolete()'
366 $ hg log -r 'obsolete()'
367 changeset: 4:7c694bff0650
367 changeset: 4:7c694bff0650
368 user: test
368 user: test
369 date: Thu Jan 01 00:00:00 1970 +0000
369 date: Thu Jan 01 00:00:00 1970 +0000
370 summary: add original_d
370 summary: add original_d
371
371
372 $ hg glog -r '::unstable()'
372 $ hg glog -r '::unstable()'
373 @ changeset: 5:6e572121998e
373 @ changeset: 5:6e572121998e
374 | tag: tip
374 | tag: tip
375 | user: test
375 | user: test
376 | date: Thu Jan 01 00:00:00 1970 +0000
376 | date: Thu Jan 01 00:00:00 1970 +0000
377 | summary: add original_e
377 | summary: add original_e
378 |
378 |
379 x changeset: 4:7c694bff0650
379 x changeset: 4:7c694bff0650
380 | user: test
380 | user: test
381 | date: Thu Jan 01 00:00:00 1970 +0000
381 | date: Thu Jan 01 00:00:00 1970 +0000
382 | summary: add original_d
382 | summary: add original_d
383 |
383 |
384 o changeset: 3:5601fb93a350
384 o changeset: 3:5601fb93a350
385 | parent: 1:7c3bad9141dc
385 | parent: 1:7c3bad9141dc
386 | user: test
386 | user: test
387 | date: Thu Jan 01 00:00:00 1970 +0000
387 | date: Thu Jan 01 00:00:00 1970 +0000
388 | summary: add new_3_c
388 | summary: add new_3_c
389 |
389 |
390 o changeset: 1:7c3bad9141dc
390 o changeset: 1:7c3bad9141dc
391 | user: test
391 | user: test
392 | date: Thu Jan 01 00:00:00 1970 +0000
392 | date: Thu Jan 01 00:00:00 1970 +0000
393 | summary: add b
393 | summary: add b
394 |
394 |
395 o changeset: 0:1f0dee641bb7
395 o changeset: 0:1f0dee641bb7
396 user: test
396 user: test
397 date: Thu Jan 01 00:00:00 1970 +0000
397 date: Thu Jan 01 00:00:00 1970 +0000
398 summary: add a
398 summary: add a
399
399
400
400
401 refuse to push obsolete changeset
401 refuse to push obsolete changeset
402
402
403 $ hg push ../tmpc/ -r 'desc("original_d")'
403 $ hg push ../tmpc/ -r 'desc("original_d")'
404 pushing to ../tmpc/
404 pushing to ../tmpc/
405 searching for changes
405 searching for changes
406 abort: push includes an obsolete changeset: 7c694bff0650!
406 abort: push includes an obsolete changeset: 7c694bff0650!
407 [255]
407 [255]
408
408
409 refuse to push unstable changeset
409 refuse to push unstable changeset
410
410
411 $ hg push ../tmpc/
411 $ hg push ../tmpc/
412 pushing to ../tmpc/
412 pushing to ../tmpc/
413 searching for changes
413 searching for changes
414 abort: push includes an unstable changeset: 6e572121998e!
414 abort: push includes an unstable changeset: 6e572121998e!
415 [255]
415 [255]
416
416
417 Test that extinct changeset are properly detected
417 Test that extinct changeset are properly detected
418
418
419 $ hg log -r 'extinct()'
419 $ hg log -r 'extinct()'
420
420
421 Don't try to push extinct changeset
421 Don't try to push extinct changeset
422
422
423 $ hg init ../tmpf
423 $ hg init ../tmpf
424 $ hg out ../tmpf
424 $ hg out ../tmpf
425 comparing with ../tmpf
425 comparing with ../tmpf
426 searching for changes
426 searching for changes
427 changeset: 0:1f0dee641bb7
427 changeset: 0:1f0dee641bb7
428 user: test
428 user: test
429 date: Thu Jan 01 00:00:00 1970 +0000
429 date: Thu Jan 01 00:00:00 1970 +0000
430 summary: add a
430 summary: add a
431
431
432 changeset: 1:7c3bad9141dc
432 changeset: 1:7c3bad9141dc
433 user: test
433 user: test
434 date: Thu Jan 01 00:00:00 1970 +0000
434 date: Thu Jan 01 00:00:00 1970 +0000
435 summary: add b
435 summary: add b
436
436
437 changeset: 2:245bde4270cd
437 changeset: 2:245bde4270cd
438 user: test
438 user: test
439 date: Thu Jan 01 00:00:00 1970 +0000
439 date: Thu Jan 01 00:00:00 1970 +0000
440 summary: add original_c
440 summary: add original_c
441
441
442 changeset: 3:5601fb93a350
442 changeset: 3:5601fb93a350
443 parent: 1:7c3bad9141dc
443 parent: 1:7c3bad9141dc
444 user: test
444 user: test
445 date: Thu Jan 01 00:00:00 1970 +0000
445 date: Thu Jan 01 00:00:00 1970 +0000
446 summary: add new_3_c
446 summary: add new_3_c
447
447
448 changeset: 4:7c694bff0650
448 changeset: 4:7c694bff0650
449 user: test
449 user: test
450 date: Thu Jan 01 00:00:00 1970 +0000
450 date: Thu Jan 01 00:00:00 1970 +0000
451 summary: add original_d
451 summary: add original_d
452
452
453 changeset: 5:6e572121998e
453 changeset: 5:6e572121998e
454 tag: tip
454 tag: tip
455 user: test
455 user: test
456 date: Thu Jan 01 00:00:00 1970 +0000
456 date: Thu Jan 01 00:00:00 1970 +0000
457 summary: add original_e
457 summary: add original_e
458
458
459 $ hg push ../tmpf -f # -f because be push unstable too
459 $ hg push ../tmpf -f # -f because be push unstable too
460 pushing to ../tmpf
460 pushing to ../tmpf
461 searching for changes
461 searching for changes
462 adding changesets
462 adding changesets
463 adding manifests
463 adding manifests
464 adding file changes
464 adding file changes
465 added 6 changesets with 6 changes to 6 files (+1 heads)
465 added 6 changesets with 6 changes to 6 files (+1 heads)
466
466
467 no warning displayed
467 no warning displayed
468
468
469 $ hg push ../tmpf
469 $ hg push ../tmpf
470 pushing to ../tmpf
470 pushing to ../tmpf
471 searching for changes
471 searching for changes
472 no changes found
472 no changes found
473 [1]
473 [1]
474
474
475 Do not warn about new head when the new head is a successors of a remote one
475 Do not warn about new head when the new head is a successors of a remote one
476
476
477 $ hg glog
477 $ hg glog
478 @ changeset: 5:6e572121998e
478 @ changeset: 5:6e572121998e
479 | tag: tip
479 | tag: tip
480 | user: test
480 | user: test
481 | date: Thu Jan 01 00:00:00 1970 +0000
481 | date: Thu Jan 01 00:00:00 1970 +0000
482 | summary: add original_e
482 | summary: add original_e
483 |
483 |
484 x changeset: 4:7c694bff0650
484 x changeset: 4:7c694bff0650
485 | user: test
485 | user: test
486 | date: Thu Jan 01 00:00:00 1970 +0000
486 | date: Thu Jan 01 00:00:00 1970 +0000
487 | summary: add original_d
487 | summary: add original_d
488 |
488 |
489 o changeset: 3:5601fb93a350
489 o changeset: 3:5601fb93a350
490 | parent: 1:7c3bad9141dc
490 | parent: 1:7c3bad9141dc
491 | user: test
491 | user: test
492 | date: Thu Jan 01 00:00:00 1970 +0000
492 | date: Thu Jan 01 00:00:00 1970 +0000
493 | summary: add new_3_c
493 | summary: add new_3_c
494 |
494 |
495 | o changeset: 2:245bde4270cd
495 | o changeset: 2:245bde4270cd
496 |/ user: test
496 |/ user: test
497 | date: Thu Jan 01 00:00:00 1970 +0000
497 | date: Thu Jan 01 00:00:00 1970 +0000
498 | summary: add original_c
498 | summary: add original_c
499 |
499 |
500 o changeset: 1:7c3bad9141dc
500 o changeset: 1:7c3bad9141dc
501 | user: test
501 | user: test
502 | date: Thu Jan 01 00:00:00 1970 +0000
502 | date: Thu Jan 01 00:00:00 1970 +0000
503 | summary: add b
503 | summary: add b
504 |
504 |
505 o changeset: 0:1f0dee641bb7
505 o changeset: 0:1f0dee641bb7
506 user: test
506 user: test
507 date: Thu Jan 01 00:00:00 1970 +0000
507 date: Thu Jan 01 00:00:00 1970 +0000
508 summary: add a
508 summary: add a
509
509
510 $ hg up -q 'desc(new_3_c)'
510 $ hg up -q 'desc(new_3_c)'
511 $ mkcommit obsolete_e
511 $ mkcommit obsolete_e
512 created new head
512 created new head
513 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
513 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
514 $ hg push ../tmpf
514 $ hg push ../tmpf
515 pushing to ../tmpf
515 pushing to ../tmpf
516 searching for changes
516 searching for changes
517 adding changesets
517 adding changesets
518 adding manifests
518 adding manifests
519 adding file changes
519 adding file changes
520 added 1 changesets with 1 changes to 1 files (+1 heads)
520 added 1 changesets with 1 changes to 1 files (+1 heads)
521
521
522 Checking _enable=False warning if obsolete marker exists
522 Checking _enable=False warning if obsolete marker exists
523
523
524 $ echo '[extensions]' >> $HGRCPATH
524 $ echo '[extensions]' >> $HGRCPATH
525 $ echo "obs=!" >> $HGRCPATH
525 $ echo "obs=!" >> $HGRCPATH
526 $ hg log -r tip
526 $ hg log -r tip
527 obsolete feature not enabled but 7 markers found!
527 obsolete feature not enabled but 7 markers found!
528 changeset: 6:d6a026544050
528 changeset: 6:d6a026544050
529 tag: tip
529 tag: tip
530 parent: 3:5601fb93a350
530 parent: 3:5601fb93a350
531 user: test
531 user: test
532 date: Thu Jan 01 00:00:00 1970 +0000
532 date: Thu Jan 01 00:00:00 1970 +0000
533 summary: add obsolete_e
533 summary: add obsolete_e
534
534
General Comments 0
You need to be logged in to leave comments. Login now