##// END OF EJS Templates
merge: deprecate the --force option...
Florence Laguzet -
r19439:f4148c36 default
parent child Browse files
Show More
@@ -1,5890 +1,5891 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 _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, copies, error, bookmarks
12 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import patch, help, encoding, templatekw, discovery
13 import patch, help, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ('', 'hidden', False, _('consider hidden changesets')),
52 ('', 'hidden', False, _('consider hidden changesets')),
53 ]
53 ]
54
54
55 dryrunopts = [('n', 'dry-run', None,
55 dryrunopts = [('n', 'dry-run', None,
56 _('do not perform actions, just print output'))]
56 _('do not perform actions, just print output'))]
57
57
58 remoteopts = [
58 remoteopts = [
59 ('e', 'ssh', '',
59 ('e', 'ssh', '',
60 _('specify ssh command to use'), _('CMD')),
60 _('specify ssh command to use'), _('CMD')),
61 ('', 'remotecmd', '',
61 ('', 'remotecmd', '',
62 _('specify hg command to run on the remote side'), _('CMD')),
62 _('specify hg command to run on the remote side'), _('CMD')),
63 ('', 'insecure', None,
63 ('', 'insecure', None,
64 _('do not verify server certificate (ignoring web.cacerts config)')),
64 _('do not verify server certificate (ignoring web.cacerts config)')),
65 ]
65 ]
66
66
67 walkopts = [
67 walkopts = [
68 ('I', 'include', [],
68 ('I', 'include', [],
69 _('include names matching the given patterns'), _('PATTERN')),
69 _('include names matching the given patterns'), _('PATTERN')),
70 ('X', 'exclude', [],
70 ('X', 'exclude', [],
71 _('exclude names matching the given patterns'), _('PATTERN')),
71 _('exclude names matching the given patterns'), _('PATTERN')),
72 ]
72 ]
73
73
74 commitopts = [
74 commitopts = [
75 ('m', 'message', '',
75 ('m', 'message', '',
76 _('use text as commit message'), _('TEXT')),
76 _('use text as commit message'), _('TEXT')),
77 ('l', 'logfile', '',
77 ('l', 'logfile', '',
78 _('read commit message from file'), _('FILE')),
78 _('read commit message from file'), _('FILE')),
79 ]
79 ]
80
80
81 commitopts2 = [
81 commitopts2 = [
82 ('d', 'date', '',
82 ('d', 'date', '',
83 _('record the specified date as commit date'), _('DATE')),
83 _('record the specified date as commit date'), _('DATE')),
84 ('u', 'user', '',
84 ('u', 'user', '',
85 _('record the specified user as committer'), _('USER')),
85 _('record the specified user as committer'), _('USER')),
86 ]
86 ]
87
87
88 templateopts = [
88 templateopts = [
89 ('', 'style', '',
89 ('', 'style', '',
90 _('display using template map file'), _('STYLE')),
90 _('display using template map file'), _('STYLE')),
91 ('', 'template', '',
91 ('', 'template', '',
92 _('display with template'), _('TEMPLATE')),
92 _('display with template'), _('TEMPLATE')),
93 ]
93 ]
94
94
95 logopts = [
95 logopts = [
96 ('p', 'patch', None, _('show patch')),
96 ('p', 'patch', None, _('show patch')),
97 ('g', 'git', None, _('use git extended diff format')),
97 ('g', 'git', None, _('use git extended diff format')),
98 ('l', 'limit', '',
98 ('l', 'limit', '',
99 _('limit number of changes displayed'), _('NUM')),
99 _('limit number of changes displayed'), _('NUM')),
100 ('M', 'no-merges', None, _('do not show merges')),
100 ('M', 'no-merges', None, _('do not show merges')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('', 'stat', None, _('output diffstat-style summary of changes')),
102 ('G', 'graph', None, _("show the revision DAG")),
102 ('G', 'graph', None, _("show the revision DAG")),
103 ] + templateopts
103 ] + templateopts
104
104
105 diffopts = [
105 diffopts = [
106 ('a', 'text', None, _('treat all files as text')),
106 ('a', 'text', None, _('treat all files as text')),
107 ('g', 'git', None, _('use git extended diff format')),
107 ('g', 'git', None, _('use git extended diff format')),
108 ('', 'nodates', None, _('omit dates from diff headers'))
108 ('', 'nodates', None, _('omit dates from diff headers'))
109 ]
109 ]
110
110
111 diffwsopts = [
111 diffwsopts = [
112 ('w', 'ignore-all-space', None,
112 ('w', 'ignore-all-space', None,
113 _('ignore white space when comparing lines')),
113 _('ignore white space when comparing lines')),
114 ('b', 'ignore-space-change', None,
114 ('b', 'ignore-space-change', None,
115 _('ignore changes in the amount of white space')),
115 _('ignore changes in the amount of white space')),
116 ('B', 'ignore-blank-lines', None,
116 ('B', 'ignore-blank-lines', None,
117 _('ignore changes whose lines are all blank')),
117 _('ignore changes whose lines are all blank')),
118 ]
118 ]
119
119
120 diffopts2 = [
120 diffopts2 = [
121 ('p', 'show-function', None, _('show which function each change is in')),
121 ('p', 'show-function', None, _('show which function each change is in')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ('', 'reverse', None, _('produce a diff that undoes the changes')),
123 ] + diffwsopts + [
123 ] + diffwsopts + [
124 ('U', 'unified', '',
124 ('U', 'unified', '',
125 _('number of lines of context to show'), _('NUM')),
125 _('number of lines of context to show'), _('NUM')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ('', 'stat', None, _('output diffstat-style summary of changes')),
127 ]
127 ]
128
128
129 mergetoolopts = [
129 mergetoolopts = [
130 ('t', 'tool', '', _('specify merge tool')),
130 ('t', 'tool', '', _('specify merge tool')),
131 ]
131 ]
132
132
133 similarityopts = [
133 similarityopts = [
134 ('s', 'similarity', '',
134 ('s', 'similarity', '',
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
136 ]
136 ]
137
137
138 subrepoopts = [
138 subrepoopts = [
139 ('S', 'subrepos', None,
139 ('S', 'subrepos', None,
140 _('recurse into subrepositories'))
140 _('recurse into subrepositories'))
141 ]
141 ]
142
142
143 # Commands start here, listed alphabetically
143 # Commands start here, listed alphabetically
144
144
145 @command('^add',
145 @command('^add',
146 walkopts + subrepoopts + dryrunopts,
146 walkopts + subrepoopts + dryrunopts,
147 _('[OPTION]... [FILE]...'))
147 _('[OPTION]... [FILE]...'))
148 def add(ui, repo, *pats, **opts):
148 def add(ui, repo, *pats, **opts):
149 """add the specified files on the next commit
149 """add the specified files on the next commit
150
150
151 Schedule files to be version controlled and added to the
151 Schedule files to be version controlled and added to the
152 repository.
152 repository.
153
153
154 The files will be added to the repository at the next commit. To
154 The files will be added to the repository at the next commit. To
155 undo an add before that, see :hg:`forget`.
155 undo an add before that, see :hg:`forget`.
156
156
157 If no names are given, add all files to the repository.
157 If no names are given, add all files to the repository.
158
158
159 .. container:: verbose
159 .. container:: verbose
160
160
161 An example showing how new (unknown) files are added
161 An example showing how new (unknown) files are added
162 automatically by :hg:`add`::
162 automatically by :hg:`add`::
163
163
164 $ ls
164 $ ls
165 foo.c
165 foo.c
166 $ hg status
166 $ hg status
167 ? foo.c
167 ? foo.c
168 $ hg add
168 $ hg add
169 adding foo.c
169 adding foo.c
170 $ hg status
170 $ hg status
171 A foo.c
171 A foo.c
172
172
173 Returns 0 if all files are successfully added.
173 Returns 0 if all files are successfully added.
174 """
174 """
175
175
176 m = scmutil.match(repo[None], pats, opts)
176 m = scmutil.match(repo[None], pats, opts)
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
178 opts.get('subrepos'), prefix="", explicitonly=False)
178 opts.get('subrepos'), prefix="", explicitonly=False)
179 return rejected and 1 or 0
179 return rejected and 1 or 0
180
180
181 @command('addremove',
181 @command('addremove',
182 similarityopts + walkopts + dryrunopts,
182 similarityopts + walkopts + dryrunopts,
183 _('[OPTION]... [FILE]...'))
183 _('[OPTION]... [FILE]...'))
184 def addremove(ui, repo, *pats, **opts):
184 def addremove(ui, repo, *pats, **opts):
185 """add all new files, delete all missing files
185 """add all new files, delete all missing files
186
186
187 Add all new files and remove all missing files from the
187 Add all new files and remove all missing files from the
188 repository.
188 repository.
189
189
190 New files are ignored if they match any of the patterns in
190 New files are ignored if they match any of the patterns in
191 ``.hgignore``. As with add, these changes take effect at the next
191 ``.hgignore``. As with add, these changes take effect at the next
192 commit.
192 commit.
193
193
194 Use the -s/--similarity option to detect renamed files. This
194 Use the -s/--similarity option to detect renamed files. This
195 option takes a percentage between 0 (disabled) and 100 (files must
195 option takes a percentage between 0 (disabled) and 100 (files must
196 be identical) as its parameter. With a parameter greater than 0,
196 be identical) as its parameter. With a parameter greater than 0,
197 this compares every removed file with every added file and records
197 this compares every removed file with every added file and records
198 those similar enough as renames. Detecting renamed files this way
198 those similar enough as renames. Detecting renamed files this way
199 can be expensive. After using this option, :hg:`status -C` can be
199 can be expensive. After using this option, :hg:`status -C` can be
200 used to check which files were identified as moved or renamed. If
200 used to check which files were identified as moved or renamed. If
201 not specified, -s/--similarity defaults to 100 and only renames of
201 not specified, -s/--similarity defaults to 100 and only renames of
202 identical files are detected.
202 identical files are detected.
203
203
204 Returns 0 if all files are successfully added.
204 Returns 0 if all files are successfully added.
205 """
205 """
206 try:
206 try:
207 sim = float(opts.get('similarity') or 100)
207 sim = float(opts.get('similarity') or 100)
208 except ValueError:
208 except ValueError:
209 raise util.Abort(_('similarity must be a number'))
209 raise util.Abort(_('similarity must be a number'))
210 if sim < 0 or sim > 100:
210 if sim < 0 or sim > 100:
211 raise util.Abort(_('similarity must be between 0 and 100'))
211 raise util.Abort(_('similarity must be between 0 and 100'))
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
213
213
214 @command('^annotate|blame',
214 @command('^annotate|blame',
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
216 ('', 'follow', None,
216 ('', 'follow', None,
217 _('follow copies/renames and list the filename (DEPRECATED)')),
217 _('follow copies/renames and list the filename (DEPRECATED)')),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('', 'no-follow', None, _("don't follow copies and renames")),
219 ('a', 'text', None, _('treat all files as text')),
219 ('a', 'text', None, _('treat all files as text')),
220 ('u', 'user', None, _('list the author (long with -v)')),
220 ('u', 'user', None, _('list the author (long with -v)')),
221 ('f', 'file', None, _('list the filename')),
221 ('f', 'file', None, _('list the filename')),
222 ('d', 'date', None, _('list the date (short with -q)')),
222 ('d', 'date', None, _('list the date (short with -q)')),
223 ('n', 'number', None, _('list the revision number (default)')),
223 ('n', 'number', None, _('list the revision number (default)')),
224 ('c', 'changeset', None, _('list the changeset')),
224 ('c', 'changeset', None, _('list the changeset')),
225 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ('l', 'line-number', None, _('show line number at the first appearance'))
226 ] + diffwsopts + walkopts,
226 ] + diffwsopts + walkopts,
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
228 def annotate(ui, repo, *pats, **opts):
228 def annotate(ui, repo, *pats, **opts):
229 """show changeset information by line for each file
229 """show changeset information by line for each file
230
230
231 List changes in files, showing the revision id responsible for
231 List changes in files, showing the revision id responsible for
232 each line
232 each line
233
233
234 This command is useful for discovering when a change was made and
234 This command is useful for discovering when a change was made and
235 by whom.
235 by whom.
236
236
237 Without the -a/--text option, annotate will avoid processing files
237 Without the -a/--text option, annotate will avoid processing files
238 it detects as binary. With -a, annotate will annotate the file
238 it detects as binary. With -a, annotate will annotate the file
239 anyway, although the results will probably be neither useful
239 anyway, although the results will probably be neither useful
240 nor desirable.
240 nor desirable.
241
241
242 Returns 0 on success.
242 Returns 0 on success.
243 """
243 """
244 if opts.get('follow'):
244 if opts.get('follow'):
245 # --follow is deprecated and now just an alias for -f/--file
245 # --follow is deprecated and now just an alias for -f/--file
246 # to mimic the behavior of Mercurial before version 1.5
246 # to mimic the behavior of Mercurial before version 1.5
247 opts['file'] = True
247 opts['file'] = True
248
248
249 datefunc = ui.quiet and util.shortdate or util.datestr
249 datefunc = ui.quiet and util.shortdate or util.datestr
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
251
251
252 if not pats:
252 if not pats:
253 raise util.Abort(_('at least one filename or pattern is required'))
253 raise util.Abort(_('at least one filename or pattern is required'))
254
254
255 hexfn = ui.debugflag and hex or short
255 hexfn = ui.debugflag and hex or short
256
256
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
258 ('number', ' ', lambda x: str(x[0].rev())),
258 ('number', ' ', lambda x: str(x[0].rev())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('changeset', ' ', lambda x: hexfn(x[0].node())),
260 ('date', ' ', getdate),
260 ('date', ' ', getdate),
261 ('file', ' ', lambda x: x[0].path()),
261 ('file', ' ', lambda x: x[0].path()),
262 ('line_number', ':', lambda x: str(x[1])),
262 ('line_number', ':', lambda x: str(x[1])),
263 ]
263 ]
264
264
265 if (not opts.get('user') and not opts.get('changeset')
265 if (not opts.get('user') and not opts.get('changeset')
266 and not opts.get('date') and not opts.get('file')):
266 and not opts.get('date') and not opts.get('file')):
267 opts['number'] = True
267 opts['number'] = True
268
268
269 linenumber = opts.get('line_number') is not None
269 linenumber = opts.get('line_number') is not None
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
271 raise util.Abort(_('at least one of -n/-c is required for -l'))
272
272
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
275
275
276 def bad(x, y):
276 def bad(x, y):
277 raise util.Abort("%s: %s" % (x, y))
277 raise util.Abort("%s: %s" % (x, y))
278
278
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 m = scmutil.match(ctx, pats, opts)
280 m = scmutil.match(ctx, pats, opts)
281 m.bad = bad
281 m.bad = bad
282 follow = not opts.get('no_follow')
282 follow = not opts.get('no_follow')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
283 diffopts = patch.diffopts(ui, opts, section='annotate')
284 for abs in ctx.walk(m):
284 for abs in ctx.walk(m):
285 fctx = ctx[abs]
285 fctx = ctx[abs]
286 if not opts.get('text') and util.binary(fctx.data()):
286 if not opts.get('text') and util.binary(fctx.data()):
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
288 continue
288 continue
289
289
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 lines = fctx.annotate(follow=follow, linenumber=linenumber,
291 diffopts=diffopts)
291 diffopts=diffopts)
292 pieces = []
292 pieces = []
293
293
294 for f, sep in funcmap:
294 for f, sep in funcmap:
295 l = [f(n) for n, dummy in lines]
295 l = [f(n) for n, dummy in lines]
296 if l:
296 if l:
297 sized = [(x, encoding.colwidth(x)) for x in l]
297 sized = [(x, encoding.colwidth(x)) for x in l]
298 ml = max([w for x, w in sized])
298 ml = max([w for x, w in sized])
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
300 for x, w in sized])
300 for x, w in sized])
301
301
302 if pieces:
302 if pieces:
303 for p, l in zip(zip(*pieces), lines):
303 for p, l in zip(zip(*pieces), lines):
304 ui.write("%s: %s" % ("".join(p), l[1]))
304 ui.write("%s: %s" % ("".join(p), l[1]))
305
305
306 if lines and not lines[-1][1].endswith('\n'):
306 if lines and not lines[-1][1].endswith('\n'):
307 ui.write('\n')
307 ui.write('\n')
308
308
309 @command('archive',
309 @command('archive',
310 [('', 'no-decode', None, _('do not pass files through decoders')),
310 [('', 'no-decode', None, _('do not pass files through decoders')),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 ('p', 'prefix', '', _('directory prefix for files in archive'),
312 _('PREFIX')),
312 _('PREFIX')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('r', 'rev', '', _('revision to distribute'), _('REV')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
315 ] + subrepoopts + walkopts,
315 ] + subrepoopts + walkopts,
316 _('[OPTION]... DEST'))
316 _('[OPTION]... DEST'))
317 def archive(ui, repo, dest, **opts):
317 def archive(ui, repo, dest, **opts):
318 '''create an unversioned archive of a repository revision
318 '''create an unversioned archive of a repository revision
319
319
320 By default, the revision used is the parent of the working
320 By default, the revision used is the parent of the working
321 directory; use -r/--rev to specify a different revision.
321 directory; use -r/--rev to specify a different revision.
322
322
323 The archive type is automatically detected based on file
323 The archive type is automatically detected based on file
324 extension (or override using -t/--type).
324 extension (or override using -t/--type).
325
325
326 .. container:: verbose
326 .. container:: verbose
327
327
328 Examples:
328 Examples:
329
329
330 - create a zip file containing the 1.0 release::
330 - create a zip file containing the 1.0 release::
331
331
332 hg archive -r 1.0 project-1.0.zip
332 hg archive -r 1.0 project-1.0.zip
333
333
334 - create a tarball excluding .hg files::
334 - create a tarball excluding .hg files::
335
335
336 hg archive project.tar.gz -X ".hg*"
336 hg archive project.tar.gz -X ".hg*"
337
337
338 Valid types are:
338 Valid types are:
339
339
340 :``files``: a directory full of files (default)
340 :``files``: a directory full of files (default)
341 :``tar``: tar archive, uncompressed
341 :``tar``: tar archive, uncompressed
342 :``tbz2``: tar archive, compressed using bzip2
342 :``tbz2``: tar archive, compressed using bzip2
343 :``tgz``: tar archive, compressed using gzip
343 :``tgz``: tar archive, compressed using gzip
344 :``uzip``: zip archive, uncompressed
344 :``uzip``: zip archive, uncompressed
345 :``zip``: zip archive, compressed using deflate
345 :``zip``: zip archive, compressed using deflate
346
346
347 The exact name of the destination archive or directory is given
347 The exact name of the destination archive or directory is given
348 using a format string; see :hg:`help export` for details.
348 using a format string; see :hg:`help export` for details.
349
349
350 Each member added to an archive file has a directory prefix
350 Each member added to an archive file has a directory prefix
351 prepended. Use -p/--prefix to specify a format string for the
351 prepended. Use -p/--prefix to specify a format string for the
352 prefix. The default is the basename of the archive, with suffixes
352 prefix. The default is the basename of the archive, with suffixes
353 removed.
353 removed.
354
354
355 Returns 0 on success.
355 Returns 0 on success.
356 '''
356 '''
357
357
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 ctx = scmutil.revsingle(repo, opts.get('rev'))
359 if not ctx:
359 if not ctx:
360 raise util.Abort(_('no working directory: please specify a revision'))
360 raise util.Abort(_('no working directory: please specify a revision'))
361 node = ctx.node()
361 node = ctx.node()
362 dest = cmdutil.makefilename(repo, dest, node)
362 dest = cmdutil.makefilename(repo, dest, node)
363 if os.path.realpath(dest) == repo.root:
363 if os.path.realpath(dest) == repo.root:
364 raise util.Abort(_('repository root cannot be destination'))
364 raise util.Abort(_('repository root cannot be destination'))
365
365
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 kind = opts.get('type') or archival.guesskind(dest) or 'files'
367 prefix = opts.get('prefix')
367 prefix = opts.get('prefix')
368
368
369 if dest == '-':
369 if dest == '-':
370 if kind == 'files':
370 if kind == 'files':
371 raise util.Abort(_('cannot archive plain files to stdout'))
371 raise util.Abort(_('cannot archive plain files to stdout'))
372 dest = cmdutil.makefileobj(repo, dest)
372 dest = cmdutil.makefileobj(repo, dest)
373 if not prefix:
373 if not prefix:
374 prefix = os.path.basename(repo.root) + '-%h'
374 prefix = os.path.basename(repo.root) + '-%h'
375
375
376 prefix = cmdutil.makefilename(repo, prefix, node)
376 prefix = cmdutil.makefilename(repo, prefix, node)
377 matchfn = scmutil.match(ctx, [], opts)
377 matchfn = scmutil.match(ctx, [], opts)
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
379 matchfn, prefix, subrepos=opts.get('subrepos'))
379 matchfn, prefix, subrepos=opts.get('subrepos'))
380
380
381 @command('backout',
381 @command('backout',
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 [('', 'merge', None, _('merge with old dirstate parent after backout')),
383 ('', 'parent', '',
383 ('', 'parent', '',
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ('r', 'rev', '', _('revision to backout'), _('REV')),
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 ] + mergetoolopts + walkopts + commitopts + commitopts2,
387 _('[OPTION]... [-r] REV'))
387 _('[OPTION]... [-r] REV'))
388 def backout(ui, repo, node=None, rev=None, **opts):
388 def backout(ui, repo, node=None, rev=None, **opts):
389 '''reverse effect of earlier changeset
389 '''reverse effect of earlier changeset
390
390
391 Prepare a new changeset with the effect of REV undone in the
391 Prepare a new changeset with the effect of REV undone in the
392 current working directory.
392 current working directory.
393
393
394 If REV is the parent of the working directory, then this new changeset
394 If REV is the parent of the working directory, then this new changeset
395 is committed automatically. Otherwise, hg needs to merge the
395 is committed automatically. Otherwise, hg needs to merge the
396 changes and the merged result is left uncommitted.
396 changes and the merged result is left uncommitted.
397
397
398 .. note::
398 .. note::
399 backout cannot be used to fix either an unwanted or
399 backout cannot be used to fix either an unwanted or
400 incorrect merge.
400 incorrect merge.
401
401
402 .. container:: verbose
402 .. container:: verbose
403
403
404 By default, the pending changeset will have one parent,
404 By default, the pending changeset will have one parent,
405 maintaining a linear history. With --merge, the pending
405 maintaining a linear history. With --merge, the pending
406 changeset will instead have two parents: the old parent of the
406 changeset will instead have two parents: the old parent of the
407 working directory and a new child of REV that simply undoes REV.
407 working directory and a new child of REV that simply undoes REV.
408
408
409 Before version 1.7, the behavior without --merge was equivalent
409 Before version 1.7, the behavior without --merge was equivalent
410 to specifying --merge followed by :hg:`update --clean .` to
410 to specifying --merge followed by :hg:`update --clean .` to
411 cancel the merge and leave the child of REV as a head to be
411 cancel the merge and leave the child of REV as a head to be
412 merged separately.
412 merged separately.
413
413
414 See :hg:`help dates` for a list of formats valid for -d/--date.
414 See :hg:`help dates` for a list of formats valid for -d/--date.
415
415
416 Returns 0 on success.
416 Returns 0 on success.
417 '''
417 '''
418 if rev and node:
418 if rev and node:
419 raise util.Abort(_("please specify just one revision"))
419 raise util.Abort(_("please specify just one revision"))
420
420
421 if not rev:
421 if not rev:
422 rev = node
422 rev = node
423
423
424 if not rev:
424 if not rev:
425 raise util.Abort(_("please specify a revision to backout"))
425 raise util.Abort(_("please specify a revision to backout"))
426
426
427 date = opts.get('date')
427 date = opts.get('date')
428 if date:
428 if date:
429 opts['date'] = util.parsedate(date)
429 opts['date'] = util.parsedate(date)
430
430
431 cmdutil.bailifchanged(repo)
431 cmdutil.bailifchanged(repo)
432 node = scmutil.revsingle(repo, rev).node()
432 node = scmutil.revsingle(repo, rev).node()
433
433
434 op1, op2 = repo.dirstate.parents()
434 op1, op2 = repo.dirstate.parents()
435 a = repo.changelog.ancestor(op1, node)
435 a = repo.changelog.ancestor(op1, node)
436 if a != node:
436 if a != node:
437 raise util.Abort(_('cannot backout change on a different branch'))
437 raise util.Abort(_('cannot backout change on a different branch'))
438
438
439 p1, p2 = repo.changelog.parents(node)
439 p1, p2 = repo.changelog.parents(node)
440 if p1 == nullid:
440 if p1 == nullid:
441 raise util.Abort(_('cannot backout a change with no parents'))
441 raise util.Abort(_('cannot backout a change with no parents'))
442 if p2 != nullid:
442 if p2 != nullid:
443 if not opts.get('parent'):
443 if not opts.get('parent'):
444 raise util.Abort(_('cannot backout a merge changeset'))
444 raise util.Abort(_('cannot backout a merge changeset'))
445 p = repo.lookup(opts['parent'])
445 p = repo.lookup(opts['parent'])
446 if p not in (p1, p2):
446 if p not in (p1, p2):
447 raise util.Abort(_('%s is not a parent of %s') %
447 raise util.Abort(_('%s is not a parent of %s') %
448 (short(p), short(node)))
448 (short(p), short(node)))
449 parent = p
449 parent = p
450 else:
450 else:
451 if opts.get('parent'):
451 if opts.get('parent'):
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 raise util.Abort(_('cannot use --parent on non-merge changeset'))
453 parent = p1
453 parent = p1
454
454
455 # the backout should appear on the same branch
455 # the backout should appear on the same branch
456 wlock = repo.wlock()
456 wlock = repo.wlock()
457 try:
457 try:
458 branch = repo.dirstate.branch()
458 branch = repo.dirstate.branch()
459 bheads = repo.branchheads(branch)
459 bheads = repo.branchheads(branch)
460 hg.clean(repo, node, show_stats=False)
460 hg.clean(repo, node, show_stats=False)
461 repo.dirstate.setbranch(branch)
461 repo.dirstate.setbranch(branch)
462 rctx = scmutil.revsingle(repo, hex(parent))
462 rctx = scmutil.revsingle(repo, hex(parent))
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
463 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
464 if not opts.get('merge') and op1 != node:
464 if not opts.get('merge') and op1 != node:
465 try:
465 try:
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
466 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
467 return hg.update(repo, op1)
467 return hg.update(repo, op1)
468 finally:
468 finally:
469 ui.setconfig('ui', 'forcemerge', '')
469 ui.setconfig('ui', 'forcemerge', '')
470
470
471 e = cmdutil.commiteditor
471 e = cmdutil.commiteditor
472 if not opts['message'] and not opts['logfile']:
472 if not opts['message'] and not opts['logfile']:
473 # we don't translate commit messages
473 # we don't translate commit messages
474 opts['message'] = "Backed out changeset %s" % short(node)
474 opts['message'] = "Backed out changeset %s" % short(node)
475 e = cmdutil.commitforceeditor
475 e = cmdutil.commitforceeditor
476
476
477 def commitfunc(ui, repo, message, match, opts):
477 def commitfunc(ui, repo, message, match, opts):
478 return repo.commit(message, opts.get('user'), opts.get('date'),
478 return repo.commit(message, opts.get('user'), opts.get('date'),
479 match, editor=e)
479 match, editor=e)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
480 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
481 cmdutil.commitstatus(repo, newnode, branch, bheads)
482
482
483 def nice(node):
483 def nice(node):
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
484 return '%d:%s' % (repo.changelog.rev(node), short(node))
485 ui.status(_('changeset %s backs out changeset %s\n') %
485 ui.status(_('changeset %s backs out changeset %s\n') %
486 (nice(repo.changelog.tip()), nice(node)))
486 (nice(repo.changelog.tip()), nice(node)))
487 if opts.get('merge') and op1 != node:
487 if opts.get('merge') and op1 != node:
488 hg.clean(repo, op1, show_stats=False)
488 hg.clean(repo, op1, show_stats=False)
489 ui.status(_('merging with changeset %s\n')
489 ui.status(_('merging with changeset %s\n')
490 % nice(repo.changelog.tip()))
490 % nice(repo.changelog.tip()))
491 try:
491 try:
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
492 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
493 return hg.merge(repo, hex(repo.changelog.tip()))
493 return hg.merge(repo, hex(repo.changelog.tip()))
494 finally:
494 finally:
495 ui.setconfig('ui', 'forcemerge', '')
495 ui.setconfig('ui', 'forcemerge', '')
496 finally:
496 finally:
497 wlock.release()
497 wlock.release()
498 return 0
498 return 0
499
499
500 @command('bisect',
500 @command('bisect',
501 [('r', 'reset', False, _('reset bisect state')),
501 [('r', 'reset', False, _('reset bisect state')),
502 ('g', 'good', False, _('mark changeset good')),
502 ('g', 'good', False, _('mark changeset good')),
503 ('b', 'bad', False, _('mark changeset bad')),
503 ('b', 'bad', False, _('mark changeset bad')),
504 ('s', 'skip', False, _('skip testing changeset')),
504 ('s', 'skip', False, _('skip testing changeset')),
505 ('e', 'extend', False, _('extend the bisect range')),
505 ('e', 'extend', False, _('extend the bisect range')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
506 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
507 ('U', 'noupdate', False, _('do not update to target'))],
507 ('U', 'noupdate', False, _('do not update to target'))],
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
508 _("[-gbsr] [-U] [-c CMD] [REV]"))
509 def bisect(ui, repo, rev=None, extra=None, command=None,
509 def bisect(ui, repo, rev=None, extra=None, command=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
510 reset=None, good=None, bad=None, skip=None, extend=None,
511 noupdate=None):
511 noupdate=None):
512 """subdivision search of changesets
512 """subdivision search of changesets
513
513
514 This command helps to find changesets which introduce problems. To
514 This command helps to find changesets which introduce problems. To
515 use, mark the earliest changeset you know exhibits the problem as
515 use, mark the earliest changeset you know exhibits the problem as
516 bad, then mark the latest changeset which is free from the problem
516 bad, then mark the latest changeset which is free from the problem
517 as good. Bisect will update your working directory to a revision
517 as good. Bisect will update your working directory to a revision
518 for testing (unless the -U/--noupdate option is specified). Once
518 for testing (unless the -U/--noupdate option is specified). Once
519 you have performed tests, mark the working directory as good or
519 you have performed tests, mark the working directory as good or
520 bad, and bisect will either update to another candidate changeset
520 bad, and bisect will either update to another candidate changeset
521 or announce that it has found the bad revision.
521 or announce that it has found the bad revision.
522
522
523 As a shortcut, you can also use the revision argument to mark a
523 As a shortcut, you can also use the revision argument to mark a
524 revision as good or bad without checking it out first.
524 revision as good or bad without checking it out first.
525
525
526 If you supply a command, it will be used for automatic bisection.
526 If you supply a command, it will be used for automatic bisection.
527 The environment variable HG_NODE will contain the ID of the
527 The environment variable HG_NODE will contain the ID of the
528 changeset being tested. The exit status of the command will be
528 changeset being tested. The exit status of the command will be
529 used to mark revisions as good or bad: status 0 means good, 125
529 used to mark revisions as good or bad: status 0 means good, 125
530 means to skip the revision, 127 (command not found) will abort the
530 means to skip the revision, 127 (command not found) will abort the
531 bisection, and any other non-zero exit status means the revision
531 bisection, and any other non-zero exit status means the revision
532 is bad.
532 is bad.
533
533
534 .. container:: verbose
534 .. container:: verbose
535
535
536 Some examples:
536 Some examples:
537
537
538 - start a bisection with known bad revision 12, and good revision 34::
538 - start a bisection with known bad revision 12, and good revision 34::
539
539
540 hg bisect --bad 34
540 hg bisect --bad 34
541 hg bisect --good 12
541 hg bisect --good 12
542
542
543 - advance the current bisection by marking current revision as good or
543 - advance the current bisection by marking current revision as good or
544 bad::
544 bad::
545
545
546 hg bisect --good
546 hg bisect --good
547 hg bisect --bad
547 hg bisect --bad
548
548
549 - mark the current revision, or a known revision, to be skipped (e.g. if
549 - mark the current revision, or a known revision, to be skipped (e.g. if
550 that revision is not usable because of another issue)::
550 that revision is not usable because of another issue)::
551
551
552 hg bisect --skip
552 hg bisect --skip
553 hg bisect --skip 23
553 hg bisect --skip 23
554
554
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
555 - skip all revisions that do not touch directories ``foo`` or ``bar``
556
556
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
557 hg bisect --skip '!( file("path:foo") & file("path:bar") )'
558
558
559 - forget the current bisection::
559 - forget the current bisection::
560
560
561 hg bisect --reset
561 hg bisect --reset
562
562
563 - use 'make && make tests' to automatically find the first broken
563 - use 'make && make tests' to automatically find the first broken
564 revision::
564 revision::
565
565
566 hg bisect --reset
566 hg bisect --reset
567 hg bisect --bad 34
567 hg bisect --bad 34
568 hg bisect --good 12
568 hg bisect --good 12
569 hg bisect --command 'make && make tests'
569 hg bisect --command 'make && make tests'
570
570
571 - see all changesets whose states are already known in the current
571 - see all changesets whose states are already known in the current
572 bisection::
572 bisection::
573
573
574 hg log -r "bisect(pruned)"
574 hg log -r "bisect(pruned)"
575
575
576 - see the changeset currently being bisected (especially useful
576 - see the changeset currently being bisected (especially useful
577 if running with -U/--noupdate)::
577 if running with -U/--noupdate)::
578
578
579 hg log -r "bisect(current)"
579 hg log -r "bisect(current)"
580
580
581 - see all changesets that took part in the current bisection::
581 - see all changesets that took part in the current bisection::
582
582
583 hg log -r "bisect(range)"
583 hg log -r "bisect(range)"
584
584
585 - with the graphlog extension, you can even get a nice graph::
585 - with the graphlog extension, you can even get a nice graph::
586
586
587 hg log --graph -r "bisect(range)"
587 hg log --graph -r "bisect(range)"
588
588
589 See :hg:`help revsets` for more about the `bisect()` keyword.
589 See :hg:`help revsets` for more about the `bisect()` keyword.
590
590
591 Returns 0 on success.
591 Returns 0 on success.
592 """
592 """
593 def extendbisectrange(nodes, good):
593 def extendbisectrange(nodes, good):
594 # bisect is incomplete when it ends on a merge node and
594 # bisect is incomplete when it ends on a merge node and
595 # one of the parent was not checked.
595 # one of the parent was not checked.
596 parents = repo[nodes[0]].parents()
596 parents = repo[nodes[0]].parents()
597 if len(parents) > 1:
597 if len(parents) > 1:
598 side = good and state['bad'] or state['good']
598 side = good and state['bad'] or state['good']
599 num = len(set(i.node() for i in parents) & set(side))
599 num = len(set(i.node() for i in parents) & set(side))
600 if num == 1:
600 if num == 1:
601 return parents[0].ancestor(parents[1])
601 return parents[0].ancestor(parents[1])
602 return None
602 return None
603
603
604 def print_result(nodes, good):
604 def print_result(nodes, good):
605 displayer = cmdutil.show_changeset(ui, repo, {})
605 displayer = cmdutil.show_changeset(ui, repo, {})
606 if len(nodes) == 1:
606 if len(nodes) == 1:
607 # narrowed it down to a single revision
607 # narrowed it down to a single revision
608 if good:
608 if good:
609 ui.write(_("The first good revision is:\n"))
609 ui.write(_("The first good revision is:\n"))
610 else:
610 else:
611 ui.write(_("The first bad revision is:\n"))
611 ui.write(_("The first bad revision is:\n"))
612 displayer.show(repo[nodes[0]])
612 displayer.show(repo[nodes[0]])
613 extendnode = extendbisectrange(nodes, good)
613 extendnode = extendbisectrange(nodes, good)
614 if extendnode is not None:
614 if extendnode is not None:
615 ui.write(_('Not all ancestors of this changeset have been'
615 ui.write(_('Not all ancestors of this changeset have been'
616 ' checked.\nUse bisect --extend to continue the '
616 ' checked.\nUse bisect --extend to continue the '
617 'bisection from\nthe common ancestor, %s.\n')
617 'bisection from\nthe common ancestor, %s.\n')
618 % extendnode)
618 % extendnode)
619 else:
619 else:
620 # multiple possible revisions
620 # multiple possible revisions
621 if good:
621 if good:
622 ui.write(_("Due to skipped revisions, the first "
622 ui.write(_("Due to skipped revisions, the first "
623 "good revision could be any of:\n"))
623 "good revision could be any of:\n"))
624 else:
624 else:
625 ui.write(_("Due to skipped revisions, the first "
625 ui.write(_("Due to skipped revisions, the first "
626 "bad revision could be any of:\n"))
626 "bad revision could be any of:\n"))
627 for n in nodes:
627 for n in nodes:
628 displayer.show(repo[n])
628 displayer.show(repo[n])
629 displayer.close()
629 displayer.close()
630
630
631 def check_state(state, interactive=True):
631 def check_state(state, interactive=True):
632 if not state['good'] or not state['bad']:
632 if not state['good'] or not state['bad']:
633 if (good or bad or skip or reset) and interactive:
633 if (good or bad or skip or reset) and interactive:
634 return
634 return
635 if not state['good']:
635 if not state['good']:
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
636 raise util.Abort(_('cannot bisect (no known good revisions)'))
637 else:
637 else:
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
638 raise util.Abort(_('cannot bisect (no known bad revisions)'))
639 return True
639 return True
640
640
641 # backward compatibility
641 # backward compatibility
642 if rev in "good bad reset init".split():
642 if rev in "good bad reset init".split():
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
643 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
644 cmd, rev, extra = rev, extra, None
644 cmd, rev, extra = rev, extra, None
645 if cmd == "good":
645 if cmd == "good":
646 good = True
646 good = True
647 elif cmd == "bad":
647 elif cmd == "bad":
648 bad = True
648 bad = True
649 else:
649 else:
650 reset = True
650 reset = True
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
651 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
652 raise util.Abort(_('incompatible arguments'))
652 raise util.Abort(_('incompatible arguments'))
653
653
654 if reset:
654 if reset:
655 p = repo.join("bisect.state")
655 p = repo.join("bisect.state")
656 if os.path.exists(p):
656 if os.path.exists(p):
657 os.unlink(p)
657 os.unlink(p)
658 return
658 return
659
659
660 state = hbisect.load_state(repo)
660 state = hbisect.load_state(repo)
661
661
662 if command:
662 if command:
663 changesets = 1
663 changesets = 1
664 try:
664 try:
665 node = state['current'][0]
665 node = state['current'][0]
666 except LookupError:
666 except LookupError:
667 if noupdate:
667 if noupdate:
668 raise util.Abort(_('current bisect revision is unknown - '
668 raise util.Abort(_('current bisect revision is unknown - '
669 'start a new bisect to fix'))
669 'start a new bisect to fix'))
670 node, p2 = repo.dirstate.parents()
670 node, p2 = repo.dirstate.parents()
671 if p2 != nullid:
671 if p2 != nullid:
672 raise util.Abort(_('current bisect revision is a merge'))
672 raise util.Abort(_('current bisect revision is a merge'))
673 try:
673 try:
674 while changesets:
674 while changesets:
675 # update state
675 # update state
676 state['current'] = [node]
676 state['current'] = [node]
677 hbisect.save_state(repo, state)
677 hbisect.save_state(repo, state)
678 status = util.system(command,
678 status = util.system(command,
679 environ={'HG_NODE': hex(node)},
679 environ={'HG_NODE': hex(node)},
680 out=ui.fout)
680 out=ui.fout)
681 if status == 125:
681 if status == 125:
682 transition = "skip"
682 transition = "skip"
683 elif status == 0:
683 elif status == 0:
684 transition = "good"
684 transition = "good"
685 # status < 0 means process was killed
685 # status < 0 means process was killed
686 elif status == 127:
686 elif status == 127:
687 raise util.Abort(_("failed to execute %s") % command)
687 raise util.Abort(_("failed to execute %s") % command)
688 elif status < 0:
688 elif status < 0:
689 raise util.Abort(_("%s killed") % command)
689 raise util.Abort(_("%s killed") % command)
690 else:
690 else:
691 transition = "bad"
691 transition = "bad"
692 ctx = scmutil.revsingle(repo, rev, node)
692 ctx = scmutil.revsingle(repo, rev, node)
693 rev = None # clear for future iterations
693 rev = None # clear for future iterations
694 state[transition].append(ctx.node())
694 state[transition].append(ctx.node())
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
695 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
696 check_state(state, interactive=False)
696 check_state(state, interactive=False)
697 # bisect
697 # bisect
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
698 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
699 # update to next check
699 # update to next check
700 node = nodes[0]
700 node = nodes[0]
701 if not noupdate:
701 if not noupdate:
702 cmdutil.bailifchanged(repo)
702 cmdutil.bailifchanged(repo)
703 hg.clean(repo, node, show_stats=False)
703 hg.clean(repo, node, show_stats=False)
704 finally:
704 finally:
705 state['current'] = [node]
705 state['current'] = [node]
706 hbisect.save_state(repo, state)
706 hbisect.save_state(repo, state)
707 print_result(nodes, good)
707 print_result(nodes, good)
708 return
708 return
709
709
710 # update state
710 # update state
711
711
712 if rev:
712 if rev:
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
713 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
714 else:
714 else:
715 nodes = [repo.lookup('.')]
715 nodes = [repo.lookup('.')]
716
716
717 if good or bad or skip:
717 if good or bad or skip:
718 if good:
718 if good:
719 state['good'] += nodes
719 state['good'] += nodes
720 elif bad:
720 elif bad:
721 state['bad'] += nodes
721 state['bad'] += nodes
722 elif skip:
722 elif skip:
723 state['skip'] += nodes
723 state['skip'] += nodes
724 hbisect.save_state(repo, state)
724 hbisect.save_state(repo, state)
725
725
726 if not check_state(state):
726 if not check_state(state):
727 return
727 return
728
728
729 # actually bisect
729 # actually bisect
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
730 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
731 if extend:
731 if extend:
732 if not changesets:
732 if not changesets:
733 extendnode = extendbisectrange(nodes, good)
733 extendnode = extendbisectrange(nodes, good)
734 if extendnode is not None:
734 if extendnode is not None:
735 ui.write(_("Extending search to changeset %d:%s\n"
735 ui.write(_("Extending search to changeset %d:%s\n"
736 % (extendnode.rev(), extendnode)))
736 % (extendnode.rev(), extendnode)))
737 state['current'] = [extendnode.node()]
737 state['current'] = [extendnode.node()]
738 hbisect.save_state(repo, state)
738 hbisect.save_state(repo, state)
739 if noupdate:
739 if noupdate:
740 return
740 return
741 cmdutil.bailifchanged(repo)
741 cmdutil.bailifchanged(repo)
742 return hg.clean(repo, extendnode.node())
742 return hg.clean(repo, extendnode.node())
743 raise util.Abort(_("nothing to extend"))
743 raise util.Abort(_("nothing to extend"))
744
744
745 if changesets == 0:
745 if changesets == 0:
746 print_result(nodes, good)
746 print_result(nodes, good)
747 else:
747 else:
748 assert len(nodes) == 1 # only a single node can be tested next
748 assert len(nodes) == 1 # only a single node can be tested next
749 node = nodes[0]
749 node = nodes[0]
750 # compute the approximate number of remaining tests
750 # compute the approximate number of remaining tests
751 tests, size = 0, 2
751 tests, size = 0, 2
752 while size <= changesets:
752 while size <= changesets:
753 tests, size = tests + 1, size * 2
753 tests, size = tests + 1, size * 2
754 rev = repo.changelog.rev(node)
754 rev = repo.changelog.rev(node)
755 ui.write(_("Testing changeset %d:%s "
755 ui.write(_("Testing changeset %d:%s "
756 "(%d changesets remaining, ~%d tests)\n")
756 "(%d changesets remaining, ~%d tests)\n")
757 % (rev, short(node), changesets, tests))
757 % (rev, short(node), changesets, tests))
758 state['current'] = [node]
758 state['current'] = [node]
759 hbisect.save_state(repo, state)
759 hbisect.save_state(repo, state)
760 if not noupdate:
760 if not noupdate:
761 cmdutil.bailifchanged(repo)
761 cmdutil.bailifchanged(repo)
762 return hg.clean(repo, node)
762 return hg.clean(repo, node)
763
763
764 @command('bookmarks|bookmark',
764 @command('bookmarks|bookmark',
765 [('f', 'force', False, _('force')),
765 [('f', 'force', False, _('force')),
766 ('r', 'rev', '', _('revision'), _('REV')),
766 ('r', 'rev', '', _('revision'), _('REV')),
767 ('d', 'delete', False, _('delete a given bookmark')),
767 ('d', 'delete', False, _('delete a given bookmark')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
768 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
769 ('i', 'inactive', False, _('mark a bookmark inactive'))],
770 _('hg bookmarks [OPTIONS]... [NAME]...'))
770 _('hg bookmarks [OPTIONS]... [NAME]...'))
771 def bookmark(ui, repo, *names, **opts):
771 def bookmark(ui, repo, *names, **opts):
772 '''track a line of development with movable markers
772 '''track a line of development with movable markers
773
773
774 Bookmarks are pointers to certain commits that move when committing.
774 Bookmarks are pointers to certain commits that move when committing.
775 Bookmarks are local. They can be renamed, copied and deleted. It is
775 Bookmarks are local. They can be renamed, copied and deleted. It is
776 possible to use :hg:`merge NAME` to merge from a given bookmark, and
776 possible to use :hg:`merge NAME` to merge from a given bookmark, and
777 :hg:`update NAME` to update to a given bookmark.
777 :hg:`update NAME` to update to a given bookmark.
778
778
779 You can use :hg:`bookmark NAME` to set a bookmark on the working
779 You can use :hg:`bookmark NAME` to set a bookmark on the working
780 directory's parent revision with the given name. If you specify
780 directory's parent revision with the given name. If you specify
781 a revision using -r REV (where REV may be an existing bookmark),
781 a revision using -r REV (where REV may be an existing bookmark),
782 the bookmark is assigned to that revision.
782 the bookmark is assigned to that revision.
783
783
784 Bookmarks can be pushed and pulled between repositories (see :hg:`help
784 Bookmarks can be pushed and pulled between repositories (see :hg:`help
785 push` and :hg:`help pull`). This requires both the local and remote
785 push` and :hg:`help pull`). This requires both the local and remote
786 repositories to support bookmarks. For versions prior to 1.8, this means
786 repositories to support bookmarks. For versions prior to 1.8, this means
787 the bookmarks extension must be enabled.
787 the bookmarks extension must be enabled.
788
788
789 If you set a bookmark called '@', new clones of the repository will
789 If you set a bookmark called '@', new clones of the repository will
790 have that revision checked out (and the bookmark made active) by
790 have that revision checked out (and the bookmark made active) by
791 default.
791 default.
792
792
793 With -i/--inactive, the new bookmark will not be made the active
793 With -i/--inactive, the new bookmark will not be made the active
794 bookmark. If -r/--rev is given, the new bookmark will not be made
794 bookmark. If -r/--rev is given, the new bookmark will not be made
795 active even if -i/--inactive is not given. If no NAME is given, the
795 active even if -i/--inactive is not given. If no NAME is given, the
796 current active bookmark will be marked inactive.
796 current active bookmark will be marked inactive.
797 '''
797 '''
798 force = opts.get('force')
798 force = opts.get('force')
799 rev = opts.get('rev')
799 rev = opts.get('rev')
800 delete = opts.get('delete')
800 delete = opts.get('delete')
801 rename = opts.get('rename')
801 rename = opts.get('rename')
802 inactive = opts.get('inactive')
802 inactive = opts.get('inactive')
803
803
804 hexfn = ui.debugflag and hex or short
804 hexfn = ui.debugflag and hex or short
805 marks = repo._bookmarks
805 marks = repo._bookmarks
806 cur = repo.changectx('.').node()
806 cur = repo.changectx('.').node()
807
807
808 def checkformat(mark):
808 def checkformat(mark):
809 mark = mark.strip()
809 mark = mark.strip()
810 if not mark:
810 if not mark:
811 raise util.Abort(_("bookmark names cannot consist entirely of "
811 raise util.Abort(_("bookmark names cannot consist entirely of "
812 "whitespace"))
812 "whitespace"))
813 scmutil.checknewlabel(repo, mark, 'bookmark')
813 scmutil.checknewlabel(repo, mark, 'bookmark')
814 return mark
814 return mark
815
815
816 def checkconflict(repo, mark, force=False, target=None):
816 def checkconflict(repo, mark, force=False, target=None):
817 if mark in marks and not force:
817 if mark in marks and not force:
818 if target:
818 if target:
819 if marks[mark] == target and target == cur:
819 if marks[mark] == target and target == cur:
820 # re-activating a bookmark
820 # re-activating a bookmark
821 return
821 return
822 anc = repo.changelog.ancestors([repo[target].rev()])
822 anc = repo.changelog.ancestors([repo[target].rev()])
823 bmctx = repo[marks[mark]]
823 bmctx = repo[marks[mark]]
824 divs = [repo[b].node() for b in marks
824 divs = [repo[b].node() for b in marks
825 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
825 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
826
826
827 # allow resolving a single divergent bookmark even if moving
827 # allow resolving a single divergent bookmark even if moving
828 # the bookmark across branches when a revision is specified
828 # the bookmark across branches when a revision is specified
829 # that contains a divergent bookmark
829 # that contains a divergent bookmark
830 if bmctx.rev() not in anc and target in divs:
830 if bmctx.rev() not in anc and target in divs:
831 bookmarks.deletedivergent(repo, [target], mark)
831 bookmarks.deletedivergent(repo, [target], mark)
832 return
832 return
833
833
834 deletefrom = [b for b in divs
834 deletefrom = [b for b in divs
835 if repo[b].rev() in anc or b == target]
835 if repo[b].rev() in anc or b == target]
836 bookmarks.deletedivergent(repo, deletefrom, mark)
836 bookmarks.deletedivergent(repo, deletefrom, mark)
837 if bmctx.rev() in anc:
837 if bmctx.rev() in anc:
838 ui.status(_("moving bookmark '%s' forward from %s\n") %
838 ui.status(_("moving bookmark '%s' forward from %s\n") %
839 (mark, short(bmctx.node())))
839 (mark, short(bmctx.node())))
840 return
840 return
841 raise util.Abort(_("bookmark '%s' already exists "
841 raise util.Abort(_("bookmark '%s' already exists "
842 "(use -f to force)") % mark)
842 "(use -f to force)") % mark)
843 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
843 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
844 and not force):
844 and not force):
845 raise util.Abort(
845 raise util.Abort(
846 _("a bookmark cannot have the name of an existing branch"))
846 _("a bookmark cannot have the name of an existing branch"))
847
847
848 if delete and rename:
848 if delete and rename:
849 raise util.Abort(_("--delete and --rename are incompatible"))
849 raise util.Abort(_("--delete and --rename are incompatible"))
850 if delete and rev:
850 if delete and rev:
851 raise util.Abort(_("--rev is incompatible with --delete"))
851 raise util.Abort(_("--rev is incompatible with --delete"))
852 if rename and rev:
852 if rename and rev:
853 raise util.Abort(_("--rev is incompatible with --rename"))
853 raise util.Abort(_("--rev is incompatible with --rename"))
854 if not names and (delete or rev):
854 if not names and (delete or rev):
855 raise util.Abort(_("bookmark name required"))
855 raise util.Abort(_("bookmark name required"))
856
856
857 if delete:
857 if delete:
858 for mark in names:
858 for mark in names:
859 if mark not in marks:
859 if mark not in marks:
860 raise util.Abort(_("bookmark '%s' does not exist") % mark)
860 raise util.Abort(_("bookmark '%s' does not exist") % mark)
861 if mark == repo._bookmarkcurrent:
861 if mark == repo._bookmarkcurrent:
862 bookmarks.setcurrent(repo, None)
862 bookmarks.setcurrent(repo, None)
863 del marks[mark]
863 del marks[mark]
864 marks.write()
864 marks.write()
865
865
866 elif rename:
866 elif rename:
867 if not names:
867 if not names:
868 raise util.Abort(_("new bookmark name required"))
868 raise util.Abort(_("new bookmark name required"))
869 elif len(names) > 1:
869 elif len(names) > 1:
870 raise util.Abort(_("only one new bookmark name allowed"))
870 raise util.Abort(_("only one new bookmark name allowed"))
871 mark = checkformat(names[0])
871 mark = checkformat(names[0])
872 if rename not in marks:
872 if rename not in marks:
873 raise util.Abort(_("bookmark '%s' does not exist") % rename)
873 raise util.Abort(_("bookmark '%s' does not exist") % rename)
874 checkconflict(repo, mark, force)
874 checkconflict(repo, mark, force)
875 marks[mark] = marks[rename]
875 marks[mark] = marks[rename]
876 if repo._bookmarkcurrent == rename and not inactive:
876 if repo._bookmarkcurrent == rename and not inactive:
877 bookmarks.setcurrent(repo, mark)
877 bookmarks.setcurrent(repo, mark)
878 del marks[rename]
878 del marks[rename]
879 marks.write()
879 marks.write()
880
880
881 elif names:
881 elif names:
882 newact = None
882 newact = None
883 for mark in names:
883 for mark in names:
884 mark = checkformat(mark)
884 mark = checkformat(mark)
885 if newact is None:
885 if newact is None:
886 newact = mark
886 newact = mark
887 if inactive and mark == repo._bookmarkcurrent:
887 if inactive and mark == repo._bookmarkcurrent:
888 bookmarks.setcurrent(repo, None)
888 bookmarks.setcurrent(repo, None)
889 return
889 return
890 tgt = cur
890 tgt = cur
891 if rev:
891 if rev:
892 tgt = scmutil.revsingle(repo, rev).node()
892 tgt = scmutil.revsingle(repo, rev).node()
893 checkconflict(repo, mark, force, tgt)
893 checkconflict(repo, mark, force, tgt)
894 marks[mark] = tgt
894 marks[mark] = tgt
895 if not inactive and cur == marks[newact] and not rev:
895 if not inactive and cur == marks[newact] and not rev:
896 bookmarks.setcurrent(repo, newact)
896 bookmarks.setcurrent(repo, newact)
897 elif cur != tgt and newact == repo._bookmarkcurrent:
897 elif cur != tgt and newact == repo._bookmarkcurrent:
898 bookmarks.setcurrent(repo, None)
898 bookmarks.setcurrent(repo, None)
899 marks.write()
899 marks.write()
900
900
901 # Same message whether trying to deactivate the current bookmark (-i
901 # Same message whether trying to deactivate the current bookmark (-i
902 # with no NAME) or listing bookmarks
902 # with no NAME) or listing bookmarks
903 elif len(marks) == 0:
903 elif len(marks) == 0:
904 ui.status(_("no bookmarks set\n"))
904 ui.status(_("no bookmarks set\n"))
905
905
906 elif inactive:
906 elif inactive:
907 if not repo._bookmarkcurrent:
907 if not repo._bookmarkcurrent:
908 ui.status(_("no active bookmark\n"))
908 ui.status(_("no active bookmark\n"))
909 else:
909 else:
910 bookmarks.setcurrent(repo, None)
910 bookmarks.setcurrent(repo, None)
911
911
912 else: # show bookmarks
912 else: # show bookmarks
913 for bmark, n in sorted(marks.iteritems()):
913 for bmark, n in sorted(marks.iteritems()):
914 current = repo._bookmarkcurrent
914 current = repo._bookmarkcurrent
915 if bmark == current:
915 if bmark == current:
916 prefix, label = '*', 'bookmarks.current'
916 prefix, label = '*', 'bookmarks.current'
917 else:
917 else:
918 prefix, label = ' ', ''
918 prefix, label = ' ', ''
919
919
920 if ui.quiet:
920 if ui.quiet:
921 ui.write("%s\n" % bmark, label=label)
921 ui.write("%s\n" % bmark, label=label)
922 else:
922 else:
923 ui.write(" %s %-25s %d:%s\n" % (
923 ui.write(" %s %-25s %d:%s\n" % (
924 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
924 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
925 label=label)
925 label=label)
926
926
927 @command('branch',
927 @command('branch',
928 [('f', 'force', None,
928 [('f', 'force', None,
929 _('set branch name even if it shadows an existing branch')),
929 _('set branch name even if it shadows an existing branch')),
930 ('C', 'clean', None, _('reset branch name to parent branch name'))],
930 ('C', 'clean', None, _('reset branch name to parent branch name'))],
931 _('[-fC] [NAME]'))
931 _('[-fC] [NAME]'))
932 def branch(ui, repo, label=None, **opts):
932 def branch(ui, repo, label=None, **opts):
933 """set or show the current branch name
933 """set or show the current branch name
934
934
935 .. note::
935 .. note::
936 Branch names are permanent and global. Use :hg:`bookmark` to create a
936 Branch names are permanent and global. Use :hg:`bookmark` to create a
937 light-weight bookmark instead. See :hg:`help glossary` for more
937 light-weight bookmark instead. See :hg:`help glossary` for more
938 information about named branches and bookmarks.
938 information about named branches and bookmarks.
939
939
940 With no argument, show the current branch name. With one argument,
940 With no argument, show the current branch name. With one argument,
941 set the working directory branch name (the branch will not exist
941 set the working directory branch name (the branch will not exist
942 in the repository until the next commit). Standard practice
942 in the repository until the next commit). Standard practice
943 recommends that primary development take place on the 'default'
943 recommends that primary development take place on the 'default'
944 branch.
944 branch.
945
945
946 Unless -f/--force is specified, branch will not let you set a
946 Unless -f/--force is specified, branch will not let you set a
947 branch name that already exists, even if it's inactive.
947 branch name that already exists, even if it's inactive.
948
948
949 Use -C/--clean to reset the working directory branch to that of
949 Use -C/--clean to reset the working directory branch to that of
950 the parent of the working directory, negating a previous branch
950 the parent of the working directory, negating a previous branch
951 change.
951 change.
952
952
953 Use the command :hg:`update` to switch to an existing branch. Use
953 Use the command :hg:`update` to switch to an existing branch. Use
954 :hg:`commit --close-branch` to mark this branch as closed.
954 :hg:`commit --close-branch` to mark this branch as closed.
955
955
956 Returns 0 on success.
956 Returns 0 on success.
957 """
957 """
958 if label:
958 if label:
959 label = label.strip()
959 label = label.strip()
960
960
961 if not opts.get('clean') and not label:
961 if not opts.get('clean') and not label:
962 ui.write("%s\n" % repo.dirstate.branch())
962 ui.write("%s\n" % repo.dirstate.branch())
963 return
963 return
964
964
965 wlock = repo.wlock()
965 wlock = repo.wlock()
966 try:
966 try:
967 if opts.get('clean'):
967 if opts.get('clean'):
968 label = repo[None].p1().branch()
968 label = repo[None].p1().branch()
969 repo.dirstate.setbranch(label)
969 repo.dirstate.setbranch(label)
970 ui.status(_('reset working directory to branch %s\n') % label)
970 ui.status(_('reset working directory to branch %s\n') % label)
971 elif label:
971 elif label:
972 if not opts.get('force') and label in repo.branchmap():
972 if not opts.get('force') and label in repo.branchmap():
973 if label not in [p.branch() for p in repo.parents()]:
973 if label not in [p.branch() for p in repo.parents()]:
974 raise util.Abort(_('a branch of the same name already'
974 raise util.Abort(_('a branch of the same name already'
975 ' exists'),
975 ' exists'),
976 # i18n: "it" refers to an existing branch
976 # i18n: "it" refers to an existing branch
977 hint=_("use 'hg update' to switch to it"))
977 hint=_("use 'hg update' to switch to it"))
978 scmutil.checknewlabel(repo, label, 'branch')
978 scmutil.checknewlabel(repo, label, 'branch')
979 repo.dirstate.setbranch(label)
979 repo.dirstate.setbranch(label)
980 ui.status(_('marked working directory as branch %s\n') % label)
980 ui.status(_('marked working directory as branch %s\n') % label)
981 ui.status(_('(branches are permanent and global, '
981 ui.status(_('(branches are permanent and global, '
982 'did you want a bookmark?)\n'))
982 'did you want a bookmark?)\n'))
983 finally:
983 finally:
984 wlock.release()
984 wlock.release()
985
985
986 @command('branches',
986 @command('branches',
987 [('a', 'active', False, _('show only branches that have unmerged heads')),
987 [('a', 'active', False, _('show only branches that have unmerged heads')),
988 ('c', 'closed', False, _('show normal and closed branches'))],
988 ('c', 'closed', False, _('show normal and closed branches'))],
989 _('[-ac]'))
989 _('[-ac]'))
990 def branches(ui, repo, active=False, closed=False):
990 def branches(ui, repo, active=False, closed=False):
991 """list repository named branches
991 """list repository named branches
992
992
993 List the repository's named branches, indicating which ones are
993 List the repository's named branches, indicating which ones are
994 inactive. If -c/--closed is specified, also list branches which have
994 inactive. If -c/--closed is specified, also list branches which have
995 been marked closed (see :hg:`commit --close-branch`).
995 been marked closed (see :hg:`commit --close-branch`).
996
996
997 If -a/--active is specified, only show active branches. A branch
997 If -a/--active is specified, only show active branches. A branch
998 is considered active if it contains repository heads.
998 is considered active if it contains repository heads.
999
999
1000 Use the command :hg:`update` to switch to an existing branch.
1000 Use the command :hg:`update` to switch to an existing branch.
1001
1001
1002 Returns 0.
1002 Returns 0.
1003 """
1003 """
1004
1004
1005 hexfunc = ui.debugflag and hex or short
1005 hexfunc = ui.debugflag and hex or short
1006
1006
1007 activebranches = set([repo[n].branch() for n in repo.heads()])
1007 activebranches = set([repo[n].branch() for n in repo.heads()])
1008 branches = []
1008 branches = []
1009 for tag, heads in repo.branchmap().iteritems():
1009 for tag, heads in repo.branchmap().iteritems():
1010 for h in reversed(heads):
1010 for h in reversed(heads):
1011 ctx = repo[h]
1011 ctx = repo[h]
1012 isopen = not ctx.closesbranch()
1012 isopen = not ctx.closesbranch()
1013 if isopen:
1013 if isopen:
1014 tip = ctx
1014 tip = ctx
1015 break
1015 break
1016 else:
1016 else:
1017 tip = repo[heads[-1]]
1017 tip = repo[heads[-1]]
1018 isactive = tag in activebranches and isopen
1018 isactive = tag in activebranches and isopen
1019 branches.append((tip, isactive, isopen))
1019 branches.append((tip, isactive, isopen))
1020 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1020 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
1021 reverse=True)
1021 reverse=True)
1022
1022
1023 for ctx, isactive, isopen in branches:
1023 for ctx, isactive, isopen in branches:
1024 if (not active) or isactive:
1024 if (not active) or isactive:
1025 if isactive:
1025 if isactive:
1026 label = 'branches.active'
1026 label = 'branches.active'
1027 notice = ''
1027 notice = ''
1028 elif not isopen:
1028 elif not isopen:
1029 if not closed:
1029 if not closed:
1030 continue
1030 continue
1031 label = 'branches.closed'
1031 label = 'branches.closed'
1032 notice = _(' (closed)')
1032 notice = _(' (closed)')
1033 else:
1033 else:
1034 label = 'branches.inactive'
1034 label = 'branches.inactive'
1035 notice = _(' (inactive)')
1035 notice = _(' (inactive)')
1036 if ctx.branch() == repo.dirstate.branch():
1036 if ctx.branch() == repo.dirstate.branch():
1037 label = 'branches.current'
1037 label = 'branches.current'
1038 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1038 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
1039 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1039 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
1040 'log.changeset changeset.%s' % ctx.phasestr())
1040 'log.changeset changeset.%s' % ctx.phasestr())
1041 tag = ui.label(ctx.branch(), label)
1041 tag = ui.label(ctx.branch(), label)
1042 if ui.quiet:
1042 if ui.quiet:
1043 ui.write("%s\n" % tag)
1043 ui.write("%s\n" % tag)
1044 else:
1044 else:
1045 ui.write("%s %s%s\n" % (tag, rev, notice))
1045 ui.write("%s %s%s\n" % (tag, rev, notice))
1046
1046
1047 @command('bundle',
1047 @command('bundle',
1048 [('f', 'force', None, _('run even when the destination is unrelated')),
1048 [('f', 'force', None, _('run even when the destination is unrelated')),
1049 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1049 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1050 _('REV')),
1050 _('REV')),
1051 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1051 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1052 _('BRANCH')),
1052 _('BRANCH')),
1053 ('', 'base', [],
1053 ('', 'base', [],
1054 _('a base changeset assumed to be available at the destination'),
1054 _('a base changeset assumed to be available at the destination'),
1055 _('REV')),
1055 _('REV')),
1056 ('a', 'all', None, _('bundle all changesets in the repository')),
1056 ('a', 'all', None, _('bundle all changesets in the repository')),
1057 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1057 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1058 ] + remoteopts,
1058 ] + remoteopts,
1059 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1059 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1060 def bundle(ui, repo, fname, dest=None, **opts):
1060 def bundle(ui, repo, fname, dest=None, **opts):
1061 """create a changegroup file
1061 """create a changegroup file
1062
1062
1063 Generate a compressed changegroup file collecting changesets not
1063 Generate a compressed changegroup file collecting changesets not
1064 known to be in another repository.
1064 known to be in another repository.
1065
1065
1066 If you omit the destination repository, then hg assumes the
1066 If you omit the destination repository, then hg assumes the
1067 destination will have all the nodes you specify with --base
1067 destination will have all the nodes you specify with --base
1068 parameters. To create a bundle containing all changesets, use
1068 parameters. To create a bundle containing all changesets, use
1069 -a/--all (or --base null).
1069 -a/--all (or --base null).
1070
1070
1071 You can change compression method with the -t/--type option.
1071 You can change compression method with the -t/--type option.
1072 The available compression methods are: none, bzip2, and
1072 The available compression methods are: none, bzip2, and
1073 gzip (by default, bundles are compressed using bzip2).
1073 gzip (by default, bundles are compressed using bzip2).
1074
1074
1075 The bundle file can then be transferred using conventional means
1075 The bundle file can then be transferred using conventional means
1076 and applied to another repository with the unbundle or pull
1076 and applied to another repository with the unbundle or pull
1077 command. This is useful when direct push and pull are not
1077 command. This is useful when direct push and pull are not
1078 available or when exporting an entire repository is undesirable.
1078 available or when exporting an entire repository is undesirable.
1079
1079
1080 Applying bundles preserves all changeset contents including
1080 Applying bundles preserves all changeset contents including
1081 permissions, copy/rename information, and revision history.
1081 permissions, copy/rename information, and revision history.
1082
1082
1083 Returns 0 on success, 1 if no changes found.
1083 Returns 0 on success, 1 if no changes found.
1084 """
1084 """
1085 revs = None
1085 revs = None
1086 if 'rev' in opts:
1086 if 'rev' in opts:
1087 revs = scmutil.revrange(repo, opts['rev'])
1087 revs = scmutil.revrange(repo, opts['rev'])
1088
1088
1089 bundletype = opts.get('type', 'bzip2').lower()
1089 bundletype = opts.get('type', 'bzip2').lower()
1090 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1090 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1091 bundletype = btypes.get(bundletype)
1091 bundletype = btypes.get(bundletype)
1092 if bundletype not in changegroup.bundletypes:
1092 if bundletype not in changegroup.bundletypes:
1093 raise util.Abort(_('unknown bundle type specified with --type'))
1093 raise util.Abort(_('unknown bundle type specified with --type'))
1094
1094
1095 if opts.get('all'):
1095 if opts.get('all'):
1096 base = ['null']
1096 base = ['null']
1097 else:
1097 else:
1098 base = scmutil.revrange(repo, opts.get('base'))
1098 base = scmutil.revrange(repo, opts.get('base'))
1099 # TODO: get desired bundlecaps from command line.
1099 # TODO: get desired bundlecaps from command line.
1100 bundlecaps = None
1100 bundlecaps = None
1101 if base:
1101 if base:
1102 if dest:
1102 if dest:
1103 raise util.Abort(_("--base is incompatible with specifying "
1103 raise util.Abort(_("--base is incompatible with specifying "
1104 "a destination"))
1104 "a destination"))
1105 common = [repo.lookup(rev) for rev in base]
1105 common = [repo.lookup(rev) for rev in base]
1106 heads = revs and map(repo.lookup, revs) or revs
1106 heads = revs and map(repo.lookup, revs) or revs
1107 cg = repo.getbundle('bundle', heads=heads, common=common,
1107 cg = repo.getbundle('bundle', heads=heads, common=common,
1108 bundlecaps=bundlecaps)
1108 bundlecaps=bundlecaps)
1109 outgoing = None
1109 outgoing = None
1110 else:
1110 else:
1111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1111 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1112 dest, branches = hg.parseurl(dest, opts.get('branch'))
1112 dest, branches = hg.parseurl(dest, opts.get('branch'))
1113 other = hg.peer(repo, opts, dest)
1113 other = hg.peer(repo, opts, dest)
1114 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1114 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1115 heads = revs and map(repo.lookup, revs) or revs
1115 heads = revs and map(repo.lookup, revs) or revs
1116 outgoing = discovery.findcommonoutgoing(repo, other,
1116 outgoing = discovery.findcommonoutgoing(repo, other,
1117 onlyheads=heads,
1117 onlyheads=heads,
1118 force=opts.get('force'),
1118 force=opts.get('force'),
1119 portable=True)
1119 portable=True)
1120 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1120 cg = repo.getlocalbundle('bundle', outgoing, bundlecaps)
1121 if not cg:
1121 if not cg:
1122 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1122 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1123 return 1
1123 return 1
1124
1124
1125 changegroup.writebundle(cg, fname, bundletype)
1125 changegroup.writebundle(cg, fname, bundletype)
1126
1126
1127 @command('cat',
1127 @command('cat',
1128 [('o', 'output', '',
1128 [('o', 'output', '',
1129 _('print output to file with formatted name'), _('FORMAT')),
1129 _('print output to file with formatted name'), _('FORMAT')),
1130 ('r', 'rev', '', _('print the given revision'), _('REV')),
1130 ('r', 'rev', '', _('print the given revision'), _('REV')),
1131 ('', 'decode', None, _('apply any matching decode filter')),
1131 ('', 'decode', None, _('apply any matching decode filter')),
1132 ] + walkopts,
1132 ] + walkopts,
1133 _('[OPTION]... FILE...'))
1133 _('[OPTION]... FILE...'))
1134 def cat(ui, repo, file1, *pats, **opts):
1134 def cat(ui, repo, file1, *pats, **opts):
1135 """output the current or given revision of files
1135 """output the current or given revision of files
1136
1136
1137 Print the specified files as they were at the given revision. If
1137 Print the specified files as they were at the given revision. If
1138 no revision is given, the parent of the working directory is used.
1138 no revision is given, the parent of the working directory is used.
1139
1139
1140 Output may be to a file, in which case the name of the file is
1140 Output may be to a file, in which case the name of the file is
1141 given using a format string. The formatting rules are the same as
1141 given using a format string. The formatting rules are the same as
1142 for the export command, with the following additions:
1142 for the export command, with the following additions:
1143
1143
1144 :``%s``: basename of file being printed
1144 :``%s``: basename of file being printed
1145 :``%d``: dirname of file being printed, or '.' if in repository root
1145 :``%d``: dirname of file being printed, or '.' if in repository root
1146 :``%p``: root-relative path name of file being printed
1146 :``%p``: root-relative path name of file being printed
1147
1147
1148 Returns 0 on success.
1148 Returns 0 on success.
1149 """
1149 """
1150 ctx = scmutil.revsingle(repo, opts.get('rev'))
1150 ctx = scmutil.revsingle(repo, opts.get('rev'))
1151 err = 1
1151 err = 1
1152 m = scmutil.match(ctx, (file1,) + pats, opts)
1152 m = scmutil.match(ctx, (file1,) + pats, opts)
1153 for abs in ctx.walk(m):
1153 for abs in ctx.walk(m):
1154 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1154 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1155 pathname=abs)
1155 pathname=abs)
1156 data = ctx[abs].data()
1156 data = ctx[abs].data()
1157 if opts.get('decode'):
1157 if opts.get('decode'):
1158 data = repo.wwritedata(abs, data)
1158 data = repo.wwritedata(abs, data)
1159 fp.write(data)
1159 fp.write(data)
1160 fp.close()
1160 fp.close()
1161 err = 0
1161 err = 0
1162 return err
1162 return err
1163
1163
1164 @command('^clone',
1164 @command('^clone',
1165 [('U', 'noupdate', None,
1165 [('U', 'noupdate', None,
1166 _('the clone will include an empty working copy (only a repository)')),
1166 _('the clone will include an empty working copy (only a repository)')),
1167 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1167 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1168 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1168 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1169 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1169 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1170 ('', 'pull', None, _('use pull protocol to copy metadata')),
1170 ('', 'pull', None, _('use pull protocol to copy metadata')),
1171 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1171 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1172 ] + remoteopts,
1172 ] + remoteopts,
1173 _('[OPTION]... SOURCE [DEST]'))
1173 _('[OPTION]... SOURCE [DEST]'))
1174 def clone(ui, source, dest=None, **opts):
1174 def clone(ui, source, dest=None, **opts):
1175 """make a copy of an existing repository
1175 """make a copy of an existing repository
1176
1176
1177 Create a copy of an existing repository in a new directory.
1177 Create a copy of an existing repository in a new directory.
1178
1178
1179 If no destination directory name is specified, it defaults to the
1179 If no destination directory name is specified, it defaults to the
1180 basename of the source.
1180 basename of the source.
1181
1181
1182 The location of the source is added to the new repository's
1182 The location of the source is added to the new repository's
1183 ``.hg/hgrc`` file, as the default to be used for future pulls.
1183 ``.hg/hgrc`` file, as the default to be used for future pulls.
1184
1184
1185 Only local paths and ``ssh://`` URLs are supported as
1185 Only local paths and ``ssh://`` URLs are supported as
1186 destinations. For ``ssh://`` destinations, no working directory or
1186 destinations. For ``ssh://`` destinations, no working directory or
1187 ``.hg/hgrc`` will be created on the remote side.
1187 ``.hg/hgrc`` will be created on the remote side.
1188
1188
1189 To pull only a subset of changesets, specify one or more revisions
1189 To pull only a subset of changesets, specify one or more revisions
1190 identifiers with -r/--rev or branches with -b/--branch. The
1190 identifiers with -r/--rev or branches with -b/--branch. The
1191 resulting clone will contain only the specified changesets and
1191 resulting clone will contain only the specified changesets and
1192 their ancestors. These options (or 'clone src#rev dest') imply
1192 their ancestors. These options (or 'clone src#rev dest') imply
1193 --pull, even for local source repositories. Note that specifying a
1193 --pull, even for local source repositories. Note that specifying a
1194 tag will include the tagged changeset but not the changeset
1194 tag will include the tagged changeset but not the changeset
1195 containing the tag.
1195 containing the tag.
1196
1196
1197 If the source repository has a bookmark called '@' set, that
1197 If the source repository has a bookmark called '@' set, that
1198 revision will be checked out in the new repository by default.
1198 revision will be checked out in the new repository by default.
1199
1199
1200 To check out a particular version, use -u/--update, or
1200 To check out a particular version, use -u/--update, or
1201 -U/--noupdate to create a clone with no working directory.
1201 -U/--noupdate to create a clone with no working directory.
1202
1202
1203 .. container:: verbose
1203 .. container:: verbose
1204
1204
1205 For efficiency, hardlinks are used for cloning whenever the
1205 For efficiency, hardlinks are used for cloning whenever the
1206 source and destination are on the same filesystem (note this
1206 source and destination are on the same filesystem (note this
1207 applies only to the repository data, not to the working
1207 applies only to the repository data, not to the working
1208 directory). Some filesystems, such as AFS, implement hardlinking
1208 directory). Some filesystems, such as AFS, implement hardlinking
1209 incorrectly, but do not report errors. In these cases, use the
1209 incorrectly, but do not report errors. In these cases, use the
1210 --pull option to avoid hardlinking.
1210 --pull option to avoid hardlinking.
1211
1211
1212 In some cases, you can clone repositories and the working
1212 In some cases, you can clone repositories and the working
1213 directory using full hardlinks with ::
1213 directory using full hardlinks with ::
1214
1214
1215 $ cp -al REPO REPOCLONE
1215 $ cp -al REPO REPOCLONE
1216
1216
1217 This is the fastest way to clone, but it is not always safe. The
1217 This is the fastest way to clone, but it is not always safe. The
1218 operation is not atomic (making sure REPO is not modified during
1218 operation is not atomic (making sure REPO is not modified during
1219 the operation is up to you) and you have to make sure your
1219 the operation is up to you) and you have to make sure your
1220 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1220 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1221 so). Also, this is not compatible with certain extensions that
1221 so). Also, this is not compatible with certain extensions that
1222 place their metadata under the .hg directory, such as mq.
1222 place their metadata under the .hg directory, such as mq.
1223
1223
1224 Mercurial will update the working directory to the first applicable
1224 Mercurial will update the working directory to the first applicable
1225 revision from this list:
1225 revision from this list:
1226
1226
1227 a) null if -U or the source repository has no changesets
1227 a) null if -U or the source repository has no changesets
1228 b) if -u . and the source repository is local, the first parent of
1228 b) if -u . and the source repository is local, the first parent of
1229 the source repository's working directory
1229 the source repository's working directory
1230 c) the changeset specified with -u (if a branch name, this means the
1230 c) the changeset specified with -u (if a branch name, this means the
1231 latest head of that branch)
1231 latest head of that branch)
1232 d) the changeset specified with -r
1232 d) the changeset specified with -r
1233 e) the tipmost head specified with -b
1233 e) the tipmost head specified with -b
1234 f) the tipmost head specified with the url#branch source syntax
1234 f) the tipmost head specified with the url#branch source syntax
1235 g) the revision marked with the '@' bookmark, if present
1235 g) the revision marked with the '@' bookmark, if present
1236 h) the tipmost head of the default branch
1236 h) the tipmost head of the default branch
1237 i) tip
1237 i) tip
1238
1238
1239 Examples:
1239 Examples:
1240
1240
1241 - clone a remote repository to a new directory named hg/::
1241 - clone a remote repository to a new directory named hg/::
1242
1242
1243 hg clone http://selenic.com/hg
1243 hg clone http://selenic.com/hg
1244
1244
1245 - create a lightweight local clone::
1245 - create a lightweight local clone::
1246
1246
1247 hg clone project/ project-feature/
1247 hg clone project/ project-feature/
1248
1248
1249 - clone from an absolute path on an ssh server (note double-slash)::
1249 - clone from an absolute path on an ssh server (note double-slash)::
1250
1250
1251 hg clone ssh://user@server//home/projects/alpha/
1251 hg clone ssh://user@server//home/projects/alpha/
1252
1252
1253 - do a high-speed clone over a LAN while checking out a
1253 - do a high-speed clone over a LAN while checking out a
1254 specified version::
1254 specified version::
1255
1255
1256 hg clone --uncompressed http://server/repo -u 1.5
1256 hg clone --uncompressed http://server/repo -u 1.5
1257
1257
1258 - create a repository without changesets after a particular revision::
1258 - create a repository without changesets after a particular revision::
1259
1259
1260 hg clone -r 04e544 experimental/ good/
1260 hg clone -r 04e544 experimental/ good/
1261
1261
1262 - clone (and track) a particular named branch::
1262 - clone (and track) a particular named branch::
1263
1263
1264 hg clone http://selenic.com/hg#stable
1264 hg clone http://selenic.com/hg#stable
1265
1265
1266 See :hg:`help urls` for details on specifying URLs.
1266 See :hg:`help urls` for details on specifying URLs.
1267
1267
1268 Returns 0 on success.
1268 Returns 0 on success.
1269 """
1269 """
1270 if opts.get('noupdate') and opts.get('updaterev'):
1270 if opts.get('noupdate') and opts.get('updaterev'):
1271 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1271 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1272
1272
1273 r = hg.clone(ui, opts, source, dest,
1273 r = hg.clone(ui, opts, source, dest,
1274 pull=opts.get('pull'),
1274 pull=opts.get('pull'),
1275 stream=opts.get('uncompressed'),
1275 stream=opts.get('uncompressed'),
1276 rev=opts.get('rev'),
1276 rev=opts.get('rev'),
1277 update=opts.get('updaterev') or not opts.get('noupdate'),
1277 update=opts.get('updaterev') or not opts.get('noupdate'),
1278 branch=opts.get('branch'))
1278 branch=opts.get('branch'))
1279
1279
1280 return r is None
1280 return r is None
1281
1281
1282 @command('^commit|ci',
1282 @command('^commit|ci',
1283 [('A', 'addremove', None,
1283 [('A', 'addremove', None,
1284 _('mark new/missing files as added/removed before committing')),
1284 _('mark new/missing files as added/removed before committing')),
1285 ('', 'close-branch', None,
1285 ('', 'close-branch', None,
1286 _('mark a branch as closed, hiding it from the branch list')),
1286 _('mark a branch as closed, hiding it from the branch list')),
1287 ('', 'amend', None, _('amend the parent of the working dir')),
1287 ('', 'amend', None, _('amend the parent of the working dir')),
1288 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1288 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1289 _('[OPTION]... [FILE]...'))
1289 _('[OPTION]... [FILE]...'))
1290 def commit(ui, repo, *pats, **opts):
1290 def commit(ui, repo, *pats, **opts):
1291 """commit the specified files or all outstanding changes
1291 """commit the specified files or all outstanding changes
1292
1292
1293 Commit changes to the given files into the repository. Unlike a
1293 Commit changes to the given files into the repository. Unlike a
1294 centralized SCM, this operation is a local operation. See
1294 centralized SCM, this operation is a local operation. See
1295 :hg:`push` for a way to actively distribute your changes.
1295 :hg:`push` for a way to actively distribute your changes.
1296
1296
1297 If a list of files is omitted, all changes reported by :hg:`status`
1297 If a list of files is omitted, all changes reported by :hg:`status`
1298 will be committed.
1298 will be committed.
1299
1299
1300 If you are committing the result of a merge, do not provide any
1300 If you are committing the result of a merge, do not provide any
1301 filenames or -I/-X filters.
1301 filenames or -I/-X filters.
1302
1302
1303 If no commit message is specified, Mercurial starts your
1303 If no commit message is specified, Mercurial starts your
1304 configured editor where you can enter a message. In case your
1304 configured editor where you can enter a message. In case your
1305 commit fails, you will find a backup of your message in
1305 commit fails, you will find a backup of your message in
1306 ``.hg/last-message.txt``.
1306 ``.hg/last-message.txt``.
1307
1307
1308 The --amend flag can be used to amend the parent of the
1308 The --amend flag can be used to amend the parent of the
1309 working directory with a new commit that contains the changes
1309 working directory with a new commit that contains the changes
1310 in the parent in addition to those currently reported by :hg:`status`,
1310 in the parent in addition to those currently reported by :hg:`status`,
1311 if there are any. The old commit is stored in a backup bundle in
1311 if there are any. The old commit is stored in a backup bundle in
1312 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1312 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1313 on how to restore it).
1313 on how to restore it).
1314
1314
1315 Message, user and date are taken from the amended commit unless
1315 Message, user and date are taken from the amended commit unless
1316 specified. When a message isn't specified on the command line,
1316 specified. When a message isn't specified on the command line,
1317 the editor will open with the message of the amended commit.
1317 the editor will open with the message of the amended commit.
1318
1318
1319 It is not possible to amend public changesets (see :hg:`help phases`)
1319 It is not possible to amend public changesets (see :hg:`help phases`)
1320 or changesets that have children.
1320 or changesets that have children.
1321
1321
1322 See :hg:`help dates` for a list of formats valid for -d/--date.
1322 See :hg:`help dates` for a list of formats valid for -d/--date.
1323
1323
1324 Returns 0 on success, 1 if nothing changed.
1324 Returns 0 on success, 1 if nothing changed.
1325 """
1325 """
1326 if opts.get('subrepos'):
1326 if opts.get('subrepos'):
1327 if opts.get('amend'):
1327 if opts.get('amend'):
1328 raise util.Abort(_('cannot amend with --subrepos'))
1328 raise util.Abort(_('cannot amend with --subrepos'))
1329 # Let --subrepos on the command line override config setting.
1329 # Let --subrepos on the command line override config setting.
1330 ui.setconfig('ui', 'commitsubrepos', True)
1330 ui.setconfig('ui', 'commitsubrepos', True)
1331
1331
1332 if repo.vfs.exists('graftstate'):
1332 if repo.vfs.exists('graftstate'):
1333 raise util.Abort(_('cannot commit an interrupted graft operation'),
1333 raise util.Abort(_('cannot commit an interrupted graft operation'),
1334 hint=_('use "hg graft -c" to continue graft'))
1334 hint=_('use "hg graft -c" to continue graft'))
1335
1335
1336 branch = repo[None].branch()
1336 branch = repo[None].branch()
1337 bheads = repo.branchheads(branch)
1337 bheads = repo.branchheads(branch)
1338
1338
1339 extra = {}
1339 extra = {}
1340 if opts.get('close_branch'):
1340 if opts.get('close_branch'):
1341 extra['close'] = 1
1341 extra['close'] = 1
1342
1342
1343 if not bheads:
1343 if not bheads:
1344 raise util.Abort(_('can only close branch heads'))
1344 raise util.Abort(_('can only close branch heads'))
1345 elif opts.get('amend'):
1345 elif opts.get('amend'):
1346 if repo.parents()[0].p1().branch() != branch and \
1346 if repo.parents()[0].p1().branch() != branch and \
1347 repo.parents()[0].p2().branch() != branch:
1347 repo.parents()[0].p2().branch() != branch:
1348 raise util.Abort(_('can only close branch heads'))
1348 raise util.Abort(_('can only close branch heads'))
1349
1349
1350 if opts.get('amend'):
1350 if opts.get('amend'):
1351 if ui.configbool('ui', 'commitsubrepos'):
1351 if ui.configbool('ui', 'commitsubrepos'):
1352 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1352 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1353
1353
1354 old = repo['.']
1354 old = repo['.']
1355 if old.phase() == phases.public:
1355 if old.phase() == phases.public:
1356 raise util.Abort(_('cannot amend public changesets'))
1356 raise util.Abort(_('cannot amend public changesets'))
1357 if len(repo[None].parents()) > 1:
1357 if len(repo[None].parents()) > 1:
1358 raise util.Abort(_('cannot amend while merging'))
1358 raise util.Abort(_('cannot amend while merging'))
1359 if (not obsolete._enabled) and old.children():
1359 if (not obsolete._enabled) and old.children():
1360 raise util.Abort(_('cannot amend changeset with children'))
1360 raise util.Abort(_('cannot amend changeset with children'))
1361
1361
1362 e = cmdutil.commiteditor
1362 e = cmdutil.commiteditor
1363 if opts.get('force_editor'):
1363 if opts.get('force_editor'):
1364 e = cmdutil.commitforceeditor
1364 e = cmdutil.commitforceeditor
1365
1365
1366 def commitfunc(ui, repo, message, match, opts):
1366 def commitfunc(ui, repo, message, match, opts):
1367 editor = e
1367 editor = e
1368 # message contains text from -m or -l, if it's empty,
1368 # message contains text from -m or -l, if it's empty,
1369 # open the editor with the old message
1369 # open the editor with the old message
1370 if not message:
1370 if not message:
1371 message = old.description()
1371 message = old.description()
1372 editor = cmdutil.commitforceeditor
1372 editor = cmdutil.commitforceeditor
1373 return repo.commit(message,
1373 return repo.commit(message,
1374 opts.get('user') or old.user(),
1374 opts.get('user') or old.user(),
1375 opts.get('date') or old.date(),
1375 opts.get('date') or old.date(),
1376 match,
1376 match,
1377 editor=editor,
1377 editor=editor,
1378 extra=extra)
1378 extra=extra)
1379
1379
1380 current = repo._bookmarkcurrent
1380 current = repo._bookmarkcurrent
1381 marks = old.bookmarks()
1381 marks = old.bookmarks()
1382 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1382 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1383 if node == old.node():
1383 if node == old.node():
1384 ui.status(_("nothing changed\n"))
1384 ui.status(_("nothing changed\n"))
1385 return 1
1385 return 1
1386 elif marks:
1386 elif marks:
1387 ui.debug('moving bookmarks %r from %s to %s\n' %
1387 ui.debug('moving bookmarks %r from %s to %s\n' %
1388 (marks, old.hex(), hex(node)))
1388 (marks, old.hex(), hex(node)))
1389 newmarks = repo._bookmarks
1389 newmarks = repo._bookmarks
1390 for bm in marks:
1390 for bm in marks:
1391 newmarks[bm] = node
1391 newmarks[bm] = node
1392 if bm == current:
1392 if bm == current:
1393 bookmarks.setcurrent(repo, bm)
1393 bookmarks.setcurrent(repo, bm)
1394 newmarks.write()
1394 newmarks.write()
1395 else:
1395 else:
1396 e = cmdutil.commiteditor
1396 e = cmdutil.commiteditor
1397 if opts.get('force_editor'):
1397 if opts.get('force_editor'):
1398 e = cmdutil.commitforceeditor
1398 e = cmdutil.commitforceeditor
1399
1399
1400 def commitfunc(ui, repo, message, match, opts):
1400 def commitfunc(ui, repo, message, match, opts):
1401 return repo.commit(message, opts.get('user'), opts.get('date'),
1401 return repo.commit(message, opts.get('user'), opts.get('date'),
1402 match, editor=e, extra=extra)
1402 match, editor=e, extra=extra)
1403
1403
1404 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1404 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1405
1405
1406 if not node:
1406 if not node:
1407 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1407 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1408 if stat[3]:
1408 if stat[3]:
1409 ui.status(_("nothing changed (%d missing files, see "
1409 ui.status(_("nothing changed (%d missing files, see "
1410 "'hg status')\n") % len(stat[3]))
1410 "'hg status')\n") % len(stat[3]))
1411 else:
1411 else:
1412 ui.status(_("nothing changed\n"))
1412 ui.status(_("nothing changed\n"))
1413 return 1
1413 return 1
1414
1414
1415 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1415 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1416
1416
1417 @command('copy|cp',
1417 @command('copy|cp',
1418 [('A', 'after', None, _('record a copy that has already occurred')),
1418 [('A', 'after', None, _('record a copy that has already occurred')),
1419 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1419 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1420 ] + walkopts + dryrunopts,
1420 ] + walkopts + dryrunopts,
1421 _('[OPTION]... [SOURCE]... DEST'))
1421 _('[OPTION]... [SOURCE]... DEST'))
1422 def copy(ui, repo, *pats, **opts):
1422 def copy(ui, repo, *pats, **opts):
1423 """mark files as copied for the next commit
1423 """mark files as copied for the next commit
1424
1424
1425 Mark dest as having copies of source files. If dest is a
1425 Mark dest as having copies of source files. If dest is a
1426 directory, copies are put in that directory. If dest is a file,
1426 directory, copies are put in that directory. If dest is a file,
1427 the source must be a single file.
1427 the source must be a single file.
1428
1428
1429 By default, this command copies the contents of files as they
1429 By default, this command copies the contents of files as they
1430 exist in the working directory. If invoked with -A/--after, the
1430 exist in the working directory. If invoked with -A/--after, the
1431 operation is recorded, but no copying is performed.
1431 operation is recorded, but no copying is performed.
1432
1432
1433 This command takes effect with the next commit. To undo a copy
1433 This command takes effect with the next commit. To undo a copy
1434 before that, see :hg:`revert`.
1434 before that, see :hg:`revert`.
1435
1435
1436 Returns 0 on success, 1 if errors are encountered.
1436 Returns 0 on success, 1 if errors are encountered.
1437 """
1437 """
1438 wlock = repo.wlock(False)
1438 wlock = repo.wlock(False)
1439 try:
1439 try:
1440 return cmdutil.copy(ui, repo, pats, opts)
1440 return cmdutil.copy(ui, repo, pats, opts)
1441 finally:
1441 finally:
1442 wlock.release()
1442 wlock.release()
1443
1443
1444 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1444 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1445 def debugancestor(ui, repo, *args):
1445 def debugancestor(ui, repo, *args):
1446 """find the ancestor revision of two revisions in a given index"""
1446 """find the ancestor revision of two revisions in a given index"""
1447 if len(args) == 3:
1447 if len(args) == 3:
1448 index, rev1, rev2 = args
1448 index, rev1, rev2 = args
1449 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1449 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1450 lookup = r.lookup
1450 lookup = r.lookup
1451 elif len(args) == 2:
1451 elif len(args) == 2:
1452 if not repo:
1452 if not repo:
1453 raise util.Abort(_("there is no Mercurial repository here "
1453 raise util.Abort(_("there is no Mercurial repository here "
1454 "(.hg not found)"))
1454 "(.hg not found)"))
1455 rev1, rev2 = args
1455 rev1, rev2 = args
1456 r = repo.changelog
1456 r = repo.changelog
1457 lookup = repo.lookup
1457 lookup = repo.lookup
1458 else:
1458 else:
1459 raise util.Abort(_('either two or three arguments required'))
1459 raise util.Abort(_('either two or three arguments required'))
1460 a = r.ancestor(lookup(rev1), lookup(rev2))
1460 a = r.ancestor(lookup(rev1), lookup(rev2))
1461 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1461 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1462
1462
1463 @command('debugbuilddag',
1463 @command('debugbuilddag',
1464 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1464 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1465 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1465 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1466 ('n', 'new-file', None, _('add new file at each rev'))],
1466 ('n', 'new-file', None, _('add new file at each rev'))],
1467 _('[OPTION]... [TEXT]'))
1467 _('[OPTION]... [TEXT]'))
1468 def debugbuilddag(ui, repo, text=None,
1468 def debugbuilddag(ui, repo, text=None,
1469 mergeable_file=False,
1469 mergeable_file=False,
1470 overwritten_file=False,
1470 overwritten_file=False,
1471 new_file=False):
1471 new_file=False):
1472 """builds a repo with a given DAG from scratch in the current empty repo
1472 """builds a repo with a given DAG from scratch in the current empty repo
1473
1473
1474 The description of the DAG is read from stdin if not given on the
1474 The description of the DAG is read from stdin if not given on the
1475 command line.
1475 command line.
1476
1476
1477 Elements:
1477 Elements:
1478
1478
1479 - "+n" is a linear run of n nodes based on the current default parent
1479 - "+n" is a linear run of n nodes based on the current default parent
1480 - "." is a single node based on the current default parent
1480 - "." is a single node based on the current default parent
1481 - "$" resets the default parent to null (implied at the start);
1481 - "$" resets the default parent to null (implied at the start);
1482 otherwise the default parent is always the last node created
1482 otherwise the default parent is always the last node created
1483 - "<p" sets the default parent to the backref p
1483 - "<p" sets the default parent to the backref p
1484 - "*p" is a fork at parent p, which is a backref
1484 - "*p" is a fork at parent p, which is a backref
1485 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1485 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1486 - "/p2" is a merge of the preceding node and p2
1486 - "/p2" is a merge of the preceding node and p2
1487 - ":tag" defines a local tag for the preceding node
1487 - ":tag" defines a local tag for the preceding node
1488 - "@branch" sets the named branch for subsequent nodes
1488 - "@branch" sets the named branch for subsequent nodes
1489 - "#...\\n" is a comment up to the end of the line
1489 - "#...\\n" is a comment up to the end of the line
1490
1490
1491 Whitespace between the above elements is ignored.
1491 Whitespace between the above elements is ignored.
1492
1492
1493 A backref is either
1493 A backref is either
1494
1494
1495 - a number n, which references the node curr-n, where curr is the current
1495 - a number n, which references the node curr-n, where curr is the current
1496 node, or
1496 node, or
1497 - the name of a local tag you placed earlier using ":tag", or
1497 - the name of a local tag you placed earlier using ":tag", or
1498 - empty to denote the default parent.
1498 - empty to denote the default parent.
1499
1499
1500 All string valued-elements are either strictly alphanumeric, or must
1500 All string valued-elements are either strictly alphanumeric, or must
1501 be enclosed in double quotes ("..."), with "\\" as escape character.
1501 be enclosed in double quotes ("..."), with "\\" as escape character.
1502 """
1502 """
1503
1503
1504 if text is None:
1504 if text is None:
1505 ui.status(_("reading DAG from stdin\n"))
1505 ui.status(_("reading DAG from stdin\n"))
1506 text = ui.fin.read()
1506 text = ui.fin.read()
1507
1507
1508 cl = repo.changelog
1508 cl = repo.changelog
1509 if len(cl) > 0:
1509 if len(cl) > 0:
1510 raise util.Abort(_('repository is not empty'))
1510 raise util.Abort(_('repository is not empty'))
1511
1511
1512 # determine number of revs in DAG
1512 # determine number of revs in DAG
1513 total = 0
1513 total = 0
1514 for type, data in dagparser.parsedag(text):
1514 for type, data in dagparser.parsedag(text):
1515 if type == 'n':
1515 if type == 'n':
1516 total += 1
1516 total += 1
1517
1517
1518 if mergeable_file:
1518 if mergeable_file:
1519 linesperrev = 2
1519 linesperrev = 2
1520 # make a file with k lines per rev
1520 # make a file with k lines per rev
1521 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1521 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1522 initialmergedlines.append("")
1522 initialmergedlines.append("")
1523
1523
1524 tags = []
1524 tags = []
1525
1525
1526 lock = tr = None
1526 lock = tr = None
1527 try:
1527 try:
1528 lock = repo.lock()
1528 lock = repo.lock()
1529 tr = repo.transaction("builddag")
1529 tr = repo.transaction("builddag")
1530
1530
1531 at = -1
1531 at = -1
1532 atbranch = 'default'
1532 atbranch = 'default'
1533 nodeids = []
1533 nodeids = []
1534 id = 0
1534 id = 0
1535 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1535 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1536 for type, data in dagparser.parsedag(text):
1536 for type, data in dagparser.parsedag(text):
1537 if type == 'n':
1537 if type == 'n':
1538 ui.note(('node %s\n' % str(data)))
1538 ui.note(('node %s\n' % str(data)))
1539 id, ps = data
1539 id, ps = data
1540
1540
1541 files = []
1541 files = []
1542 fctxs = {}
1542 fctxs = {}
1543
1543
1544 p2 = None
1544 p2 = None
1545 if mergeable_file:
1545 if mergeable_file:
1546 fn = "mf"
1546 fn = "mf"
1547 p1 = repo[ps[0]]
1547 p1 = repo[ps[0]]
1548 if len(ps) > 1:
1548 if len(ps) > 1:
1549 p2 = repo[ps[1]]
1549 p2 = repo[ps[1]]
1550 pa = p1.ancestor(p2)
1550 pa = p1.ancestor(p2)
1551 base, local, other = [x[fn].data() for x in (pa, p1,
1551 base, local, other = [x[fn].data() for x in (pa, p1,
1552 p2)]
1552 p2)]
1553 m3 = simplemerge.Merge3Text(base, local, other)
1553 m3 = simplemerge.Merge3Text(base, local, other)
1554 ml = [l.strip() for l in m3.merge_lines()]
1554 ml = [l.strip() for l in m3.merge_lines()]
1555 ml.append("")
1555 ml.append("")
1556 elif at > 0:
1556 elif at > 0:
1557 ml = p1[fn].data().split("\n")
1557 ml = p1[fn].data().split("\n")
1558 else:
1558 else:
1559 ml = initialmergedlines
1559 ml = initialmergedlines
1560 ml[id * linesperrev] += " r%i" % id
1560 ml[id * linesperrev] += " r%i" % id
1561 mergedtext = "\n".join(ml)
1561 mergedtext = "\n".join(ml)
1562 files.append(fn)
1562 files.append(fn)
1563 fctxs[fn] = context.memfilectx(fn, mergedtext)
1563 fctxs[fn] = context.memfilectx(fn, mergedtext)
1564
1564
1565 if overwritten_file:
1565 if overwritten_file:
1566 fn = "of"
1566 fn = "of"
1567 files.append(fn)
1567 files.append(fn)
1568 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1568 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1569
1569
1570 if new_file:
1570 if new_file:
1571 fn = "nf%i" % id
1571 fn = "nf%i" % id
1572 files.append(fn)
1572 files.append(fn)
1573 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1573 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1574 if len(ps) > 1:
1574 if len(ps) > 1:
1575 if not p2:
1575 if not p2:
1576 p2 = repo[ps[1]]
1576 p2 = repo[ps[1]]
1577 for fn in p2:
1577 for fn in p2:
1578 if fn.startswith("nf"):
1578 if fn.startswith("nf"):
1579 files.append(fn)
1579 files.append(fn)
1580 fctxs[fn] = p2[fn]
1580 fctxs[fn] = p2[fn]
1581
1581
1582 def fctxfn(repo, cx, path):
1582 def fctxfn(repo, cx, path):
1583 return fctxs.get(path)
1583 return fctxs.get(path)
1584
1584
1585 if len(ps) == 0 or ps[0] < 0:
1585 if len(ps) == 0 or ps[0] < 0:
1586 pars = [None, None]
1586 pars = [None, None]
1587 elif len(ps) == 1:
1587 elif len(ps) == 1:
1588 pars = [nodeids[ps[0]], None]
1588 pars = [nodeids[ps[0]], None]
1589 else:
1589 else:
1590 pars = [nodeids[p] for p in ps]
1590 pars = [nodeids[p] for p in ps]
1591 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1591 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1592 date=(id, 0),
1592 date=(id, 0),
1593 user="debugbuilddag",
1593 user="debugbuilddag",
1594 extra={'branch': atbranch})
1594 extra={'branch': atbranch})
1595 nodeid = repo.commitctx(cx)
1595 nodeid = repo.commitctx(cx)
1596 nodeids.append(nodeid)
1596 nodeids.append(nodeid)
1597 at = id
1597 at = id
1598 elif type == 'l':
1598 elif type == 'l':
1599 id, name = data
1599 id, name = data
1600 ui.note(('tag %s\n' % name))
1600 ui.note(('tag %s\n' % name))
1601 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1601 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1602 elif type == 'a':
1602 elif type == 'a':
1603 ui.note(('branch %s\n' % data))
1603 ui.note(('branch %s\n' % data))
1604 atbranch = data
1604 atbranch = data
1605 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1605 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1606 tr.close()
1606 tr.close()
1607
1607
1608 if tags:
1608 if tags:
1609 repo.opener.write("localtags", "".join(tags))
1609 repo.opener.write("localtags", "".join(tags))
1610 finally:
1610 finally:
1611 ui.progress(_('building'), None)
1611 ui.progress(_('building'), None)
1612 release(tr, lock)
1612 release(tr, lock)
1613
1613
1614 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1614 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1615 def debugbundle(ui, bundlepath, all=None, **opts):
1615 def debugbundle(ui, bundlepath, all=None, **opts):
1616 """lists the contents of a bundle"""
1616 """lists the contents of a bundle"""
1617 f = hg.openpath(ui, bundlepath)
1617 f = hg.openpath(ui, bundlepath)
1618 try:
1618 try:
1619 gen = changegroup.readbundle(f, bundlepath)
1619 gen = changegroup.readbundle(f, bundlepath)
1620 if all:
1620 if all:
1621 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1621 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1622
1622
1623 def showchunks(named):
1623 def showchunks(named):
1624 ui.write("\n%s\n" % named)
1624 ui.write("\n%s\n" % named)
1625 chain = None
1625 chain = None
1626 while True:
1626 while True:
1627 chunkdata = gen.deltachunk(chain)
1627 chunkdata = gen.deltachunk(chain)
1628 if not chunkdata:
1628 if not chunkdata:
1629 break
1629 break
1630 node = chunkdata['node']
1630 node = chunkdata['node']
1631 p1 = chunkdata['p1']
1631 p1 = chunkdata['p1']
1632 p2 = chunkdata['p2']
1632 p2 = chunkdata['p2']
1633 cs = chunkdata['cs']
1633 cs = chunkdata['cs']
1634 deltabase = chunkdata['deltabase']
1634 deltabase = chunkdata['deltabase']
1635 delta = chunkdata['delta']
1635 delta = chunkdata['delta']
1636 ui.write("%s %s %s %s %s %s\n" %
1636 ui.write("%s %s %s %s %s %s\n" %
1637 (hex(node), hex(p1), hex(p2),
1637 (hex(node), hex(p1), hex(p2),
1638 hex(cs), hex(deltabase), len(delta)))
1638 hex(cs), hex(deltabase), len(delta)))
1639 chain = node
1639 chain = node
1640
1640
1641 chunkdata = gen.changelogheader()
1641 chunkdata = gen.changelogheader()
1642 showchunks("changelog")
1642 showchunks("changelog")
1643 chunkdata = gen.manifestheader()
1643 chunkdata = gen.manifestheader()
1644 showchunks("manifest")
1644 showchunks("manifest")
1645 while True:
1645 while True:
1646 chunkdata = gen.filelogheader()
1646 chunkdata = gen.filelogheader()
1647 if not chunkdata:
1647 if not chunkdata:
1648 break
1648 break
1649 fname = chunkdata['filename']
1649 fname = chunkdata['filename']
1650 showchunks(fname)
1650 showchunks(fname)
1651 else:
1651 else:
1652 chunkdata = gen.changelogheader()
1652 chunkdata = gen.changelogheader()
1653 chain = None
1653 chain = None
1654 while True:
1654 while True:
1655 chunkdata = gen.deltachunk(chain)
1655 chunkdata = gen.deltachunk(chain)
1656 if not chunkdata:
1656 if not chunkdata:
1657 break
1657 break
1658 node = chunkdata['node']
1658 node = chunkdata['node']
1659 ui.write("%s\n" % hex(node))
1659 ui.write("%s\n" % hex(node))
1660 chain = node
1660 chain = node
1661 finally:
1661 finally:
1662 f.close()
1662 f.close()
1663
1663
1664 @command('debugcheckstate', [], '')
1664 @command('debugcheckstate', [], '')
1665 def debugcheckstate(ui, repo):
1665 def debugcheckstate(ui, repo):
1666 """validate the correctness of the current dirstate"""
1666 """validate the correctness of the current dirstate"""
1667 parent1, parent2 = repo.dirstate.parents()
1667 parent1, parent2 = repo.dirstate.parents()
1668 m1 = repo[parent1].manifest()
1668 m1 = repo[parent1].manifest()
1669 m2 = repo[parent2].manifest()
1669 m2 = repo[parent2].manifest()
1670 errors = 0
1670 errors = 0
1671 for f in repo.dirstate:
1671 for f in repo.dirstate:
1672 state = repo.dirstate[f]
1672 state = repo.dirstate[f]
1673 if state in "nr" and f not in m1:
1673 if state in "nr" and f not in m1:
1674 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1674 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1675 errors += 1
1675 errors += 1
1676 if state in "a" and f in m1:
1676 if state in "a" and f in m1:
1677 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1677 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1678 errors += 1
1678 errors += 1
1679 if state in "m" and f not in m1 and f not in m2:
1679 if state in "m" and f not in m1 and f not in m2:
1680 ui.warn(_("%s in state %s, but not in either manifest\n") %
1680 ui.warn(_("%s in state %s, but not in either manifest\n") %
1681 (f, state))
1681 (f, state))
1682 errors += 1
1682 errors += 1
1683 for f in m1:
1683 for f in m1:
1684 state = repo.dirstate[f]
1684 state = repo.dirstate[f]
1685 if state not in "nrm":
1685 if state not in "nrm":
1686 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1686 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1687 errors += 1
1687 errors += 1
1688 if errors:
1688 if errors:
1689 error = _(".hg/dirstate inconsistent with current parent's manifest")
1689 error = _(".hg/dirstate inconsistent with current parent's manifest")
1690 raise util.Abort(error)
1690 raise util.Abort(error)
1691
1691
1692 @command('debugcommands', [], _('[COMMAND]'))
1692 @command('debugcommands', [], _('[COMMAND]'))
1693 def debugcommands(ui, cmd='', *args):
1693 def debugcommands(ui, cmd='', *args):
1694 """list all available commands and options"""
1694 """list all available commands and options"""
1695 for cmd, vals in sorted(table.iteritems()):
1695 for cmd, vals in sorted(table.iteritems()):
1696 cmd = cmd.split('|')[0].strip('^')
1696 cmd = cmd.split('|')[0].strip('^')
1697 opts = ', '.join([i[1] for i in vals[1]])
1697 opts = ', '.join([i[1] for i in vals[1]])
1698 ui.write('%s: %s\n' % (cmd, opts))
1698 ui.write('%s: %s\n' % (cmd, opts))
1699
1699
1700 @command('debugcomplete',
1700 @command('debugcomplete',
1701 [('o', 'options', None, _('show the command options'))],
1701 [('o', 'options', None, _('show the command options'))],
1702 _('[-o] CMD'))
1702 _('[-o] CMD'))
1703 def debugcomplete(ui, cmd='', **opts):
1703 def debugcomplete(ui, cmd='', **opts):
1704 """returns the completion list associated with the given command"""
1704 """returns the completion list associated with the given command"""
1705
1705
1706 if opts.get('options'):
1706 if opts.get('options'):
1707 options = []
1707 options = []
1708 otables = [globalopts]
1708 otables = [globalopts]
1709 if cmd:
1709 if cmd:
1710 aliases, entry = cmdutil.findcmd(cmd, table, False)
1710 aliases, entry = cmdutil.findcmd(cmd, table, False)
1711 otables.append(entry[1])
1711 otables.append(entry[1])
1712 for t in otables:
1712 for t in otables:
1713 for o in t:
1713 for o in t:
1714 if "(DEPRECATED)" in o[3]:
1714 if "(DEPRECATED)" in o[3]:
1715 continue
1715 continue
1716 if o[0]:
1716 if o[0]:
1717 options.append('-%s' % o[0])
1717 options.append('-%s' % o[0])
1718 options.append('--%s' % o[1])
1718 options.append('--%s' % o[1])
1719 ui.write("%s\n" % "\n".join(options))
1719 ui.write("%s\n" % "\n".join(options))
1720 return
1720 return
1721
1721
1722 cmdlist = cmdutil.findpossible(cmd, table)
1722 cmdlist = cmdutil.findpossible(cmd, table)
1723 if ui.verbose:
1723 if ui.verbose:
1724 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1724 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1725 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1725 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1726
1726
1727 @command('debugdag',
1727 @command('debugdag',
1728 [('t', 'tags', None, _('use tags as labels')),
1728 [('t', 'tags', None, _('use tags as labels')),
1729 ('b', 'branches', None, _('annotate with branch names')),
1729 ('b', 'branches', None, _('annotate with branch names')),
1730 ('', 'dots', None, _('use dots for runs')),
1730 ('', 'dots', None, _('use dots for runs')),
1731 ('s', 'spaces', None, _('separate elements by spaces'))],
1731 ('s', 'spaces', None, _('separate elements by spaces'))],
1732 _('[OPTION]... [FILE [REV]...]'))
1732 _('[OPTION]... [FILE [REV]...]'))
1733 def debugdag(ui, repo, file_=None, *revs, **opts):
1733 def debugdag(ui, repo, file_=None, *revs, **opts):
1734 """format the changelog or an index DAG as a concise textual description
1734 """format the changelog or an index DAG as a concise textual description
1735
1735
1736 If you pass a revlog index, the revlog's DAG is emitted. If you list
1736 If you pass a revlog index, the revlog's DAG is emitted. If you list
1737 revision numbers, they get labeled in the output as rN.
1737 revision numbers, they get labeled in the output as rN.
1738
1738
1739 Otherwise, the changelog DAG of the current repo is emitted.
1739 Otherwise, the changelog DAG of the current repo is emitted.
1740 """
1740 """
1741 spaces = opts.get('spaces')
1741 spaces = opts.get('spaces')
1742 dots = opts.get('dots')
1742 dots = opts.get('dots')
1743 if file_:
1743 if file_:
1744 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1744 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1745 revs = set((int(r) for r in revs))
1745 revs = set((int(r) for r in revs))
1746 def events():
1746 def events():
1747 for r in rlog:
1747 for r in rlog:
1748 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1748 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1749 if p != -1)))
1749 if p != -1)))
1750 if r in revs:
1750 if r in revs:
1751 yield 'l', (r, "r%i" % r)
1751 yield 'l', (r, "r%i" % r)
1752 elif repo:
1752 elif repo:
1753 cl = repo.changelog
1753 cl = repo.changelog
1754 tags = opts.get('tags')
1754 tags = opts.get('tags')
1755 branches = opts.get('branches')
1755 branches = opts.get('branches')
1756 if tags:
1756 if tags:
1757 labels = {}
1757 labels = {}
1758 for l, n in repo.tags().items():
1758 for l, n in repo.tags().items():
1759 labels.setdefault(cl.rev(n), []).append(l)
1759 labels.setdefault(cl.rev(n), []).append(l)
1760 def events():
1760 def events():
1761 b = "default"
1761 b = "default"
1762 for r in cl:
1762 for r in cl:
1763 if branches:
1763 if branches:
1764 newb = cl.read(cl.node(r))[5]['branch']
1764 newb = cl.read(cl.node(r))[5]['branch']
1765 if newb != b:
1765 if newb != b:
1766 yield 'a', newb
1766 yield 'a', newb
1767 b = newb
1767 b = newb
1768 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1768 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1769 if p != -1)))
1769 if p != -1)))
1770 if tags:
1770 if tags:
1771 ls = labels.get(r)
1771 ls = labels.get(r)
1772 if ls:
1772 if ls:
1773 for l in ls:
1773 for l in ls:
1774 yield 'l', (r, l)
1774 yield 'l', (r, l)
1775 else:
1775 else:
1776 raise util.Abort(_('need repo for changelog dag'))
1776 raise util.Abort(_('need repo for changelog dag'))
1777
1777
1778 for line in dagparser.dagtextlines(events(),
1778 for line in dagparser.dagtextlines(events(),
1779 addspaces=spaces,
1779 addspaces=spaces,
1780 wraplabels=True,
1780 wraplabels=True,
1781 wrapannotations=True,
1781 wrapannotations=True,
1782 wrapnonlinear=dots,
1782 wrapnonlinear=dots,
1783 usedots=dots,
1783 usedots=dots,
1784 maxlinewidth=70):
1784 maxlinewidth=70):
1785 ui.write(line)
1785 ui.write(line)
1786 ui.write("\n")
1786 ui.write("\n")
1787
1787
1788 @command('debugdata',
1788 @command('debugdata',
1789 [('c', 'changelog', False, _('open changelog')),
1789 [('c', 'changelog', False, _('open changelog')),
1790 ('m', 'manifest', False, _('open manifest'))],
1790 ('m', 'manifest', False, _('open manifest'))],
1791 _('-c|-m|FILE REV'))
1791 _('-c|-m|FILE REV'))
1792 def debugdata(ui, repo, file_, rev = None, **opts):
1792 def debugdata(ui, repo, file_, rev = None, **opts):
1793 """dump the contents of a data file revision"""
1793 """dump the contents of a data file revision"""
1794 if opts.get('changelog') or opts.get('manifest'):
1794 if opts.get('changelog') or opts.get('manifest'):
1795 file_, rev = None, file_
1795 file_, rev = None, file_
1796 elif rev is None:
1796 elif rev is None:
1797 raise error.CommandError('debugdata', _('invalid arguments'))
1797 raise error.CommandError('debugdata', _('invalid arguments'))
1798 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1798 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1799 try:
1799 try:
1800 ui.write(r.revision(r.lookup(rev)))
1800 ui.write(r.revision(r.lookup(rev)))
1801 except KeyError:
1801 except KeyError:
1802 raise util.Abort(_('invalid revision identifier %s') % rev)
1802 raise util.Abort(_('invalid revision identifier %s') % rev)
1803
1803
1804 @command('debugdate',
1804 @command('debugdate',
1805 [('e', 'extended', None, _('try extended date formats'))],
1805 [('e', 'extended', None, _('try extended date formats'))],
1806 _('[-e] DATE [RANGE]'))
1806 _('[-e] DATE [RANGE]'))
1807 def debugdate(ui, date, range=None, **opts):
1807 def debugdate(ui, date, range=None, **opts):
1808 """parse and display a date"""
1808 """parse and display a date"""
1809 if opts["extended"]:
1809 if opts["extended"]:
1810 d = util.parsedate(date, util.extendeddateformats)
1810 d = util.parsedate(date, util.extendeddateformats)
1811 else:
1811 else:
1812 d = util.parsedate(date)
1812 d = util.parsedate(date)
1813 ui.write(("internal: %s %s\n") % d)
1813 ui.write(("internal: %s %s\n") % d)
1814 ui.write(("standard: %s\n") % util.datestr(d))
1814 ui.write(("standard: %s\n") % util.datestr(d))
1815 if range:
1815 if range:
1816 m = util.matchdate(range)
1816 m = util.matchdate(range)
1817 ui.write(("match: %s\n") % m(d[0]))
1817 ui.write(("match: %s\n") % m(d[0]))
1818
1818
1819 @command('debugdiscovery',
1819 @command('debugdiscovery',
1820 [('', 'old', None, _('use old-style discovery')),
1820 [('', 'old', None, _('use old-style discovery')),
1821 ('', 'nonheads', None,
1821 ('', 'nonheads', None,
1822 _('use old-style discovery with non-heads included')),
1822 _('use old-style discovery with non-heads included')),
1823 ] + remoteopts,
1823 ] + remoteopts,
1824 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1824 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1825 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1825 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1826 """runs the changeset discovery protocol in isolation"""
1826 """runs the changeset discovery protocol in isolation"""
1827 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1827 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1828 opts.get('branch'))
1828 opts.get('branch'))
1829 remote = hg.peer(repo, opts, remoteurl)
1829 remote = hg.peer(repo, opts, remoteurl)
1830 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1830 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1831
1831
1832 # make sure tests are repeatable
1832 # make sure tests are repeatable
1833 random.seed(12323)
1833 random.seed(12323)
1834
1834
1835 def doit(localheads, remoteheads, remote=remote):
1835 def doit(localheads, remoteheads, remote=remote):
1836 if opts.get('old'):
1836 if opts.get('old'):
1837 if localheads:
1837 if localheads:
1838 raise util.Abort('cannot use localheads with old style '
1838 raise util.Abort('cannot use localheads with old style '
1839 'discovery')
1839 'discovery')
1840 if not util.safehasattr(remote, 'branches'):
1840 if not util.safehasattr(remote, 'branches'):
1841 # enable in-client legacy support
1841 # enable in-client legacy support
1842 remote = localrepo.locallegacypeer(remote.local())
1842 remote = localrepo.locallegacypeer(remote.local())
1843 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1843 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1844 force=True)
1844 force=True)
1845 common = set(common)
1845 common = set(common)
1846 if not opts.get('nonheads'):
1846 if not opts.get('nonheads'):
1847 ui.write(("unpruned common: %s\n") %
1847 ui.write(("unpruned common: %s\n") %
1848 " ".join(sorted(short(n) for n in common)))
1848 " ".join(sorted(short(n) for n in common)))
1849 dag = dagutil.revlogdag(repo.changelog)
1849 dag = dagutil.revlogdag(repo.changelog)
1850 all = dag.ancestorset(dag.internalizeall(common))
1850 all = dag.ancestorset(dag.internalizeall(common))
1851 common = dag.externalizeall(dag.headsetofconnecteds(all))
1851 common = dag.externalizeall(dag.headsetofconnecteds(all))
1852 else:
1852 else:
1853 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1853 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1854 common = set(common)
1854 common = set(common)
1855 rheads = set(hds)
1855 rheads = set(hds)
1856 lheads = set(repo.heads())
1856 lheads = set(repo.heads())
1857 ui.write(("common heads: %s\n") %
1857 ui.write(("common heads: %s\n") %
1858 " ".join(sorted(short(n) for n in common)))
1858 " ".join(sorted(short(n) for n in common)))
1859 if lheads <= common:
1859 if lheads <= common:
1860 ui.write(("local is subset\n"))
1860 ui.write(("local is subset\n"))
1861 elif rheads <= common:
1861 elif rheads <= common:
1862 ui.write(("remote is subset\n"))
1862 ui.write(("remote is subset\n"))
1863
1863
1864 serverlogs = opts.get('serverlog')
1864 serverlogs = opts.get('serverlog')
1865 if serverlogs:
1865 if serverlogs:
1866 for filename in serverlogs:
1866 for filename in serverlogs:
1867 logfile = open(filename, 'r')
1867 logfile = open(filename, 'r')
1868 try:
1868 try:
1869 line = logfile.readline()
1869 line = logfile.readline()
1870 while line:
1870 while line:
1871 parts = line.strip().split(';')
1871 parts = line.strip().split(';')
1872 op = parts[1]
1872 op = parts[1]
1873 if op == 'cg':
1873 if op == 'cg':
1874 pass
1874 pass
1875 elif op == 'cgss':
1875 elif op == 'cgss':
1876 doit(parts[2].split(' '), parts[3].split(' '))
1876 doit(parts[2].split(' '), parts[3].split(' '))
1877 elif op == 'unb':
1877 elif op == 'unb':
1878 doit(parts[3].split(' '), parts[2].split(' '))
1878 doit(parts[3].split(' '), parts[2].split(' '))
1879 line = logfile.readline()
1879 line = logfile.readline()
1880 finally:
1880 finally:
1881 logfile.close()
1881 logfile.close()
1882
1882
1883 else:
1883 else:
1884 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1884 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1885 opts.get('remote_head'))
1885 opts.get('remote_head'))
1886 localrevs = opts.get('local_head')
1886 localrevs = opts.get('local_head')
1887 doit(localrevs, remoterevs)
1887 doit(localrevs, remoterevs)
1888
1888
1889 @command('debugfileset',
1889 @command('debugfileset',
1890 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1890 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1891 _('[-r REV] FILESPEC'))
1891 _('[-r REV] FILESPEC'))
1892 def debugfileset(ui, repo, expr, **opts):
1892 def debugfileset(ui, repo, expr, **opts):
1893 '''parse and apply a fileset specification'''
1893 '''parse and apply a fileset specification'''
1894 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1894 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1895 if ui.verbose:
1895 if ui.verbose:
1896 tree = fileset.parse(expr)[0]
1896 tree = fileset.parse(expr)[0]
1897 ui.note(tree, "\n")
1897 ui.note(tree, "\n")
1898
1898
1899 for f in fileset.getfileset(ctx, expr):
1899 for f in fileset.getfileset(ctx, expr):
1900 ui.write("%s\n" % f)
1900 ui.write("%s\n" % f)
1901
1901
1902 @command('debugfsinfo', [], _('[PATH]'))
1902 @command('debugfsinfo', [], _('[PATH]'))
1903 def debugfsinfo(ui, path = "."):
1903 def debugfsinfo(ui, path = "."):
1904 """show information detected about current filesystem"""
1904 """show information detected about current filesystem"""
1905 util.writefile('.debugfsinfo', '')
1905 util.writefile('.debugfsinfo', '')
1906 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1906 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
1907 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1907 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
1908 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1908 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1909 and 'yes' or 'no'))
1909 and 'yes' or 'no'))
1910 os.unlink('.debugfsinfo')
1910 os.unlink('.debugfsinfo')
1911
1911
1912 @command('debuggetbundle',
1912 @command('debuggetbundle',
1913 [('H', 'head', [], _('id of head node'), _('ID')),
1913 [('H', 'head', [], _('id of head node'), _('ID')),
1914 ('C', 'common', [], _('id of common node'), _('ID')),
1914 ('C', 'common', [], _('id of common node'), _('ID')),
1915 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1915 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1916 _('REPO FILE [-H|-C ID]...'))
1916 _('REPO FILE [-H|-C ID]...'))
1917 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1917 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1918 """retrieves a bundle from a repo
1918 """retrieves a bundle from a repo
1919
1919
1920 Every ID must be a full-length hex node id string. Saves the bundle to the
1920 Every ID must be a full-length hex node id string. Saves the bundle to the
1921 given file.
1921 given file.
1922 """
1922 """
1923 repo = hg.peer(ui, opts, repopath)
1923 repo = hg.peer(ui, opts, repopath)
1924 if not repo.capable('getbundle'):
1924 if not repo.capable('getbundle'):
1925 raise util.Abort("getbundle() not supported by target repository")
1925 raise util.Abort("getbundle() not supported by target repository")
1926 args = {}
1926 args = {}
1927 if common:
1927 if common:
1928 args['common'] = [bin(s) for s in common]
1928 args['common'] = [bin(s) for s in common]
1929 if head:
1929 if head:
1930 args['heads'] = [bin(s) for s in head]
1930 args['heads'] = [bin(s) for s in head]
1931 # TODO: get desired bundlecaps from command line.
1931 # TODO: get desired bundlecaps from command line.
1932 args['bundlecaps'] = None
1932 args['bundlecaps'] = None
1933 bundle = repo.getbundle('debug', **args)
1933 bundle = repo.getbundle('debug', **args)
1934
1934
1935 bundletype = opts.get('type', 'bzip2').lower()
1935 bundletype = opts.get('type', 'bzip2').lower()
1936 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1936 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1937 bundletype = btypes.get(bundletype)
1937 bundletype = btypes.get(bundletype)
1938 if bundletype not in changegroup.bundletypes:
1938 if bundletype not in changegroup.bundletypes:
1939 raise util.Abort(_('unknown bundle type specified with --type'))
1939 raise util.Abort(_('unknown bundle type specified with --type'))
1940 changegroup.writebundle(bundle, bundlepath, bundletype)
1940 changegroup.writebundle(bundle, bundlepath, bundletype)
1941
1941
1942 @command('debugignore', [], '')
1942 @command('debugignore', [], '')
1943 def debugignore(ui, repo, *values, **opts):
1943 def debugignore(ui, repo, *values, **opts):
1944 """display the combined ignore pattern"""
1944 """display the combined ignore pattern"""
1945 ignore = repo.dirstate._ignore
1945 ignore = repo.dirstate._ignore
1946 includepat = getattr(ignore, 'includepat', None)
1946 includepat = getattr(ignore, 'includepat', None)
1947 if includepat is not None:
1947 if includepat is not None:
1948 ui.write("%s\n" % includepat)
1948 ui.write("%s\n" % includepat)
1949 else:
1949 else:
1950 raise util.Abort(_("no ignore patterns found"))
1950 raise util.Abort(_("no ignore patterns found"))
1951
1951
1952 @command('debugindex',
1952 @command('debugindex',
1953 [('c', 'changelog', False, _('open changelog')),
1953 [('c', 'changelog', False, _('open changelog')),
1954 ('m', 'manifest', False, _('open manifest')),
1954 ('m', 'manifest', False, _('open manifest')),
1955 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1955 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1956 _('[-f FORMAT] -c|-m|FILE'))
1956 _('[-f FORMAT] -c|-m|FILE'))
1957 def debugindex(ui, repo, file_ = None, **opts):
1957 def debugindex(ui, repo, file_ = None, **opts):
1958 """dump the contents of an index file"""
1958 """dump the contents of an index file"""
1959 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1959 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1960 format = opts.get('format', 0)
1960 format = opts.get('format', 0)
1961 if format not in (0, 1):
1961 if format not in (0, 1):
1962 raise util.Abort(_("unknown format %d") % format)
1962 raise util.Abort(_("unknown format %d") % format)
1963
1963
1964 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1964 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1965 if generaldelta:
1965 if generaldelta:
1966 basehdr = ' delta'
1966 basehdr = ' delta'
1967 else:
1967 else:
1968 basehdr = ' base'
1968 basehdr = ' base'
1969
1969
1970 if format == 0:
1970 if format == 0:
1971 ui.write(" rev offset length " + basehdr + " linkrev"
1971 ui.write(" rev offset length " + basehdr + " linkrev"
1972 " nodeid p1 p2\n")
1972 " nodeid p1 p2\n")
1973 elif format == 1:
1973 elif format == 1:
1974 ui.write(" rev flag offset length"
1974 ui.write(" rev flag offset length"
1975 " size " + basehdr + " link p1 p2"
1975 " size " + basehdr + " link p1 p2"
1976 " nodeid\n")
1976 " nodeid\n")
1977
1977
1978 for i in r:
1978 for i in r:
1979 node = r.node(i)
1979 node = r.node(i)
1980 if generaldelta:
1980 if generaldelta:
1981 base = r.deltaparent(i)
1981 base = r.deltaparent(i)
1982 else:
1982 else:
1983 base = r.chainbase(i)
1983 base = r.chainbase(i)
1984 if format == 0:
1984 if format == 0:
1985 try:
1985 try:
1986 pp = r.parents(node)
1986 pp = r.parents(node)
1987 except Exception:
1987 except Exception:
1988 pp = [nullid, nullid]
1988 pp = [nullid, nullid]
1989 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1989 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1990 i, r.start(i), r.length(i), base, r.linkrev(i),
1990 i, r.start(i), r.length(i), base, r.linkrev(i),
1991 short(node), short(pp[0]), short(pp[1])))
1991 short(node), short(pp[0]), short(pp[1])))
1992 elif format == 1:
1992 elif format == 1:
1993 pr = r.parentrevs(i)
1993 pr = r.parentrevs(i)
1994 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1994 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1995 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1995 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1996 base, r.linkrev(i), pr[0], pr[1], short(node)))
1996 base, r.linkrev(i), pr[0], pr[1], short(node)))
1997
1997
1998 @command('debugindexdot', [], _('FILE'))
1998 @command('debugindexdot', [], _('FILE'))
1999 def debugindexdot(ui, repo, file_):
1999 def debugindexdot(ui, repo, file_):
2000 """dump an index DAG as a graphviz dot file"""
2000 """dump an index DAG as a graphviz dot file"""
2001 r = None
2001 r = None
2002 if repo:
2002 if repo:
2003 filelog = repo.file(file_)
2003 filelog = repo.file(file_)
2004 if len(filelog):
2004 if len(filelog):
2005 r = filelog
2005 r = filelog
2006 if not r:
2006 if not r:
2007 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2007 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2008 ui.write(("digraph G {\n"))
2008 ui.write(("digraph G {\n"))
2009 for i in r:
2009 for i in r:
2010 node = r.node(i)
2010 node = r.node(i)
2011 pp = r.parents(node)
2011 pp = r.parents(node)
2012 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2012 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2013 if pp[1] != nullid:
2013 if pp[1] != nullid:
2014 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2014 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2015 ui.write("}\n")
2015 ui.write("}\n")
2016
2016
2017 @command('debuginstall', [], '')
2017 @command('debuginstall', [], '')
2018 def debuginstall(ui):
2018 def debuginstall(ui):
2019 '''test Mercurial installation
2019 '''test Mercurial installation
2020
2020
2021 Returns 0 on success.
2021 Returns 0 on success.
2022 '''
2022 '''
2023
2023
2024 def writetemp(contents):
2024 def writetemp(contents):
2025 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2025 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2026 f = os.fdopen(fd, "wb")
2026 f = os.fdopen(fd, "wb")
2027 f.write(contents)
2027 f.write(contents)
2028 f.close()
2028 f.close()
2029 return name
2029 return name
2030
2030
2031 problems = 0
2031 problems = 0
2032
2032
2033 # encoding
2033 # encoding
2034 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2034 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2035 try:
2035 try:
2036 encoding.fromlocal("test")
2036 encoding.fromlocal("test")
2037 except util.Abort, inst:
2037 except util.Abort, inst:
2038 ui.write(" %s\n" % inst)
2038 ui.write(" %s\n" % inst)
2039 ui.write(_(" (check that your locale is properly set)\n"))
2039 ui.write(_(" (check that your locale is properly set)\n"))
2040 problems += 1
2040 problems += 1
2041
2041
2042 # Python lib
2042 # Python lib
2043 ui.status(_("checking Python lib (%s)...\n")
2043 ui.status(_("checking Python lib (%s)...\n")
2044 % os.path.dirname(os.__file__))
2044 % os.path.dirname(os.__file__))
2045
2045
2046 # compiled modules
2046 # compiled modules
2047 ui.status(_("checking installed modules (%s)...\n")
2047 ui.status(_("checking installed modules (%s)...\n")
2048 % os.path.dirname(__file__))
2048 % os.path.dirname(__file__))
2049 try:
2049 try:
2050 import bdiff, mpatch, base85, osutil
2050 import bdiff, mpatch, base85, osutil
2051 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2051 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2052 except Exception, inst:
2052 except Exception, inst:
2053 ui.write(" %s\n" % inst)
2053 ui.write(" %s\n" % inst)
2054 ui.write(_(" One or more extensions could not be found"))
2054 ui.write(_(" One or more extensions could not be found"))
2055 ui.write(_(" (check that you compiled the extensions)\n"))
2055 ui.write(_(" (check that you compiled the extensions)\n"))
2056 problems += 1
2056 problems += 1
2057
2057
2058 # templates
2058 # templates
2059 import templater
2059 import templater
2060 p = templater.templatepath()
2060 p = templater.templatepath()
2061 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2061 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2062 try:
2062 try:
2063 templater.templater(templater.templatepath("map-cmdline.default"))
2063 templater.templater(templater.templatepath("map-cmdline.default"))
2064 except Exception, inst:
2064 except Exception, inst:
2065 ui.write(" %s\n" % inst)
2065 ui.write(" %s\n" % inst)
2066 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2066 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2067 problems += 1
2067 problems += 1
2068
2068
2069 # editor
2069 # editor
2070 ui.status(_("checking commit editor...\n"))
2070 ui.status(_("checking commit editor...\n"))
2071 editor = ui.geteditor()
2071 editor = ui.geteditor()
2072 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2072 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2073 if not cmdpath:
2073 if not cmdpath:
2074 if editor == 'vi':
2074 if editor == 'vi':
2075 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2075 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2076 ui.write(_(" (specify a commit editor in your configuration"
2076 ui.write(_(" (specify a commit editor in your configuration"
2077 " file)\n"))
2077 " file)\n"))
2078 else:
2078 else:
2079 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2079 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2080 ui.write(_(" (specify a commit editor in your configuration"
2080 ui.write(_(" (specify a commit editor in your configuration"
2081 " file)\n"))
2081 " file)\n"))
2082 problems += 1
2082 problems += 1
2083
2083
2084 # check username
2084 # check username
2085 ui.status(_("checking username...\n"))
2085 ui.status(_("checking username...\n"))
2086 try:
2086 try:
2087 ui.username()
2087 ui.username()
2088 except util.Abort, e:
2088 except util.Abort, e:
2089 ui.write(" %s\n" % e)
2089 ui.write(" %s\n" % e)
2090 ui.write(_(" (specify a username in your configuration file)\n"))
2090 ui.write(_(" (specify a username in your configuration file)\n"))
2091 problems += 1
2091 problems += 1
2092
2092
2093 if not problems:
2093 if not problems:
2094 ui.status(_("no problems detected\n"))
2094 ui.status(_("no problems detected\n"))
2095 else:
2095 else:
2096 ui.write(_("%s problems detected,"
2096 ui.write(_("%s problems detected,"
2097 " please check your install!\n") % problems)
2097 " please check your install!\n") % problems)
2098
2098
2099 return problems
2099 return problems
2100
2100
2101 @command('debugknown', [], _('REPO ID...'))
2101 @command('debugknown', [], _('REPO ID...'))
2102 def debugknown(ui, repopath, *ids, **opts):
2102 def debugknown(ui, repopath, *ids, **opts):
2103 """test whether node ids are known to a repo
2103 """test whether node ids are known to a repo
2104
2104
2105 Every ID must be a full-length hex node id string. Returns a list of 0s
2105 Every ID must be a full-length hex node id string. Returns a list of 0s
2106 and 1s indicating unknown/known.
2106 and 1s indicating unknown/known.
2107 """
2107 """
2108 repo = hg.peer(ui, opts, repopath)
2108 repo = hg.peer(ui, opts, repopath)
2109 if not repo.capable('known'):
2109 if not repo.capable('known'):
2110 raise util.Abort("known() not supported by target repository")
2110 raise util.Abort("known() not supported by target repository")
2111 flags = repo.known([bin(s) for s in ids])
2111 flags = repo.known([bin(s) for s in ids])
2112 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2112 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2113
2113
2114 @command('debuglabelcomplete', [], _('LABEL...'))
2114 @command('debuglabelcomplete', [], _('LABEL...'))
2115 def debuglabelcomplete(ui, repo, *args):
2115 def debuglabelcomplete(ui, repo, *args):
2116 '''complete "labels" - tags, open branch names, bookmark names'''
2116 '''complete "labels" - tags, open branch names, bookmark names'''
2117
2117
2118 labels = set()
2118 labels = set()
2119 labels.update(t[0] for t in repo.tagslist())
2119 labels.update(t[0] for t in repo.tagslist())
2120 labels.update(repo._bookmarks.keys())
2120 labels.update(repo._bookmarks.keys())
2121 for heads in repo.branchmap().itervalues():
2121 for heads in repo.branchmap().itervalues():
2122 for h in heads:
2122 for h in heads:
2123 ctx = repo[h]
2123 ctx = repo[h]
2124 if not ctx.closesbranch():
2124 if not ctx.closesbranch():
2125 labels.add(ctx.branch())
2125 labels.add(ctx.branch())
2126 completions = set()
2126 completions = set()
2127 if not args:
2127 if not args:
2128 args = ['']
2128 args = ['']
2129 for a in args:
2129 for a in args:
2130 completions.update(l for l in labels if l.startswith(a))
2130 completions.update(l for l in labels if l.startswith(a))
2131 ui.write('\n'.join(sorted(completions)))
2131 ui.write('\n'.join(sorted(completions)))
2132 ui.write('\n')
2132 ui.write('\n')
2133
2133
2134 @command('debugobsolete',
2134 @command('debugobsolete',
2135 [('', 'flags', 0, _('markers flag')),
2135 [('', 'flags', 0, _('markers flag')),
2136 ] + commitopts2,
2136 ] + commitopts2,
2137 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2137 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2138 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2138 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2139 """create arbitrary obsolete marker
2139 """create arbitrary obsolete marker
2140
2140
2141 With no arguments, displays the list of obsolescence markers."""
2141 With no arguments, displays the list of obsolescence markers."""
2142 def parsenodeid(s):
2142 def parsenodeid(s):
2143 try:
2143 try:
2144 # We do not use revsingle/revrange functions here to accept
2144 # We do not use revsingle/revrange functions here to accept
2145 # arbitrary node identifiers, possibly not present in the
2145 # arbitrary node identifiers, possibly not present in the
2146 # local repository.
2146 # local repository.
2147 n = bin(s)
2147 n = bin(s)
2148 if len(n) != len(nullid):
2148 if len(n) != len(nullid):
2149 raise TypeError()
2149 raise TypeError()
2150 return n
2150 return n
2151 except TypeError:
2151 except TypeError:
2152 raise util.Abort('changeset references must be full hexadecimal '
2152 raise util.Abort('changeset references must be full hexadecimal '
2153 'node identifiers')
2153 'node identifiers')
2154
2154
2155 if precursor is not None:
2155 if precursor is not None:
2156 metadata = {}
2156 metadata = {}
2157 if 'date' in opts:
2157 if 'date' in opts:
2158 metadata['date'] = opts['date']
2158 metadata['date'] = opts['date']
2159 metadata['user'] = opts['user'] or ui.username()
2159 metadata['user'] = opts['user'] or ui.username()
2160 succs = tuple(parsenodeid(succ) for succ in successors)
2160 succs = tuple(parsenodeid(succ) for succ in successors)
2161 l = repo.lock()
2161 l = repo.lock()
2162 try:
2162 try:
2163 tr = repo.transaction('debugobsolete')
2163 tr = repo.transaction('debugobsolete')
2164 try:
2164 try:
2165 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2165 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2166 opts['flags'], metadata)
2166 opts['flags'], metadata)
2167 tr.close()
2167 tr.close()
2168 finally:
2168 finally:
2169 tr.release()
2169 tr.release()
2170 finally:
2170 finally:
2171 l.release()
2171 l.release()
2172 else:
2172 else:
2173 for m in obsolete.allmarkers(repo):
2173 for m in obsolete.allmarkers(repo):
2174 ui.write(hex(m.precnode()))
2174 ui.write(hex(m.precnode()))
2175 for repl in m.succnodes():
2175 for repl in m.succnodes():
2176 ui.write(' ')
2176 ui.write(' ')
2177 ui.write(hex(repl))
2177 ui.write(hex(repl))
2178 ui.write(' %X ' % m._data[2])
2178 ui.write(' %X ' % m._data[2])
2179 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2179 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2180 sorted(m.metadata().items()))))
2180 sorted(m.metadata().items()))))
2181 ui.write('\n')
2181 ui.write('\n')
2182
2182
2183 @command('debugpathcomplete',
2183 @command('debugpathcomplete',
2184 [('f', 'full', None, _('complete an entire path')),
2184 [('f', 'full', None, _('complete an entire path')),
2185 ('n', 'normal', None, _('show only normal files')),
2185 ('n', 'normal', None, _('show only normal files')),
2186 ('a', 'added', None, _('show only added files')),
2186 ('a', 'added', None, _('show only added files')),
2187 ('r', 'removed', None, _('show only removed files'))],
2187 ('r', 'removed', None, _('show only removed files'))],
2188 _('FILESPEC...'))
2188 _('FILESPEC...'))
2189 def debugpathcomplete(ui, repo, *specs, **opts):
2189 def debugpathcomplete(ui, repo, *specs, **opts):
2190 '''complete part or all of a tracked path
2190 '''complete part or all of a tracked path
2191
2191
2192 This command supports shells that offer path name completion. It
2192 This command supports shells that offer path name completion. It
2193 currently completes only files already known to the dirstate.
2193 currently completes only files already known to the dirstate.
2194
2194
2195 Completion extends only to the next path segment unless
2195 Completion extends only to the next path segment unless
2196 --full is specified, in which case entire paths are used.'''
2196 --full is specified, in which case entire paths are used.'''
2197
2197
2198 def complete(path, acceptable):
2198 def complete(path, acceptable):
2199 dirstate = repo.dirstate
2199 dirstate = repo.dirstate
2200 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2200 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2201 rootdir = repo.root + os.sep
2201 rootdir = repo.root + os.sep
2202 if spec != repo.root and not spec.startswith(rootdir):
2202 if spec != repo.root and not spec.startswith(rootdir):
2203 return [], []
2203 return [], []
2204 if os.path.isdir(spec):
2204 if os.path.isdir(spec):
2205 spec += '/'
2205 spec += '/'
2206 spec = spec[len(rootdir):]
2206 spec = spec[len(rootdir):]
2207 fixpaths = os.sep != '/'
2207 fixpaths = os.sep != '/'
2208 if fixpaths:
2208 if fixpaths:
2209 spec = spec.replace(os.sep, '/')
2209 spec = spec.replace(os.sep, '/')
2210 speclen = len(spec)
2210 speclen = len(spec)
2211 fullpaths = opts['full']
2211 fullpaths = opts['full']
2212 files, dirs = set(), set()
2212 files, dirs = set(), set()
2213 adddir, addfile = dirs.add, files.add
2213 adddir, addfile = dirs.add, files.add
2214 for f, st in dirstate.iteritems():
2214 for f, st in dirstate.iteritems():
2215 if f.startswith(spec) and st[0] in acceptable:
2215 if f.startswith(spec) and st[0] in acceptable:
2216 if fixpaths:
2216 if fixpaths:
2217 f = f.replace('/', os.sep)
2217 f = f.replace('/', os.sep)
2218 if fullpaths:
2218 if fullpaths:
2219 addfile(f)
2219 addfile(f)
2220 continue
2220 continue
2221 s = f.find(os.sep, speclen)
2221 s = f.find(os.sep, speclen)
2222 if s >= 0:
2222 if s >= 0:
2223 adddir(f[:s + 1])
2223 adddir(f[:s + 1])
2224 else:
2224 else:
2225 addfile(f)
2225 addfile(f)
2226 return files, dirs
2226 return files, dirs
2227
2227
2228 acceptable = ''
2228 acceptable = ''
2229 if opts['normal']:
2229 if opts['normal']:
2230 acceptable += 'nm'
2230 acceptable += 'nm'
2231 if opts['added']:
2231 if opts['added']:
2232 acceptable += 'a'
2232 acceptable += 'a'
2233 if opts['removed']:
2233 if opts['removed']:
2234 acceptable += 'r'
2234 acceptable += 'r'
2235 cwd = repo.getcwd()
2235 cwd = repo.getcwd()
2236 if not specs:
2236 if not specs:
2237 specs = ['.']
2237 specs = ['.']
2238
2238
2239 files, dirs = set(), set()
2239 files, dirs = set(), set()
2240 for spec in specs:
2240 for spec in specs:
2241 f, d = complete(spec, acceptable or 'nmar')
2241 f, d = complete(spec, acceptable or 'nmar')
2242 files.update(f)
2242 files.update(f)
2243 dirs.update(d)
2243 dirs.update(d)
2244 if not files and len(dirs) == 1:
2244 if not files and len(dirs) == 1:
2245 # force the shell to consider a completion that matches one
2245 # force the shell to consider a completion that matches one
2246 # directory and zero files to be ambiguous
2246 # directory and zero files to be ambiguous
2247 dirs.add(iter(dirs).next() + '.')
2247 dirs.add(iter(dirs).next() + '.')
2248 files.update(dirs)
2248 files.update(dirs)
2249 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2249 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2250 ui.write('\n')
2250 ui.write('\n')
2251
2251
2252 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2252 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2253 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2253 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2254 '''access the pushkey key/value protocol
2254 '''access the pushkey key/value protocol
2255
2255
2256 With two args, list the keys in the given namespace.
2256 With two args, list the keys in the given namespace.
2257
2257
2258 With five args, set a key to new if it currently is set to old.
2258 With five args, set a key to new if it currently is set to old.
2259 Reports success or failure.
2259 Reports success or failure.
2260 '''
2260 '''
2261
2261
2262 target = hg.peer(ui, {}, repopath)
2262 target = hg.peer(ui, {}, repopath)
2263 if keyinfo:
2263 if keyinfo:
2264 key, old, new = keyinfo
2264 key, old, new = keyinfo
2265 r = target.pushkey(namespace, key, old, new)
2265 r = target.pushkey(namespace, key, old, new)
2266 ui.status(str(r) + '\n')
2266 ui.status(str(r) + '\n')
2267 return not r
2267 return not r
2268 else:
2268 else:
2269 for k, v in sorted(target.listkeys(namespace).iteritems()):
2269 for k, v in sorted(target.listkeys(namespace).iteritems()):
2270 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2270 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2271 v.encode('string-escape')))
2271 v.encode('string-escape')))
2272
2272
2273 @command('debugpvec', [], _('A B'))
2273 @command('debugpvec', [], _('A B'))
2274 def debugpvec(ui, repo, a, b=None):
2274 def debugpvec(ui, repo, a, b=None):
2275 ca = scmutil.revsingle(repo, a)
2275 ca = scmutil.revsingle(repo, a)
2276 cb = scmutil.revsingle(repo, b)
2276 cb = scmutil.revsingle(repo, b)
2277 pa = pvec.ctxpvec(ca)
2277 pa = pvec.ctxpvec(ca)
2278 pb = pvec.ctxpvec(cb)
2278 pb = pvec.ctxpvec(cb)
2279 if pa == pb:
2279 if pa == pb:
2280 rel = "="
2280 rel = "="
2281 elif pa > pb:
2281 elif pa > pb:
2282 rel = ">"
2282 rel = ">"
2283 elif pa < pb:
2283 elif pa < pb:
2284 rel = "<"
2284 rel = "<"
2285 elif pa | pb:
2285 elif pa | pb:
2286 rel = "|"
2286 rel = "|"
2287 ui.write(_("a: %s\n") % pa)
2287 ui.write(_("a: %s\n") % pa)
2288 ui.write(_("b: %s\n") % pb)
2288 ui.write(_("b: %s\n") % pb)
2289 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2289 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2290 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2290 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2291 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2291 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2292 pa.distance(pb), rel))
2292 pa.distance(pb), rel))
2293
2293
2294 @command('debugrebuilddirstate|debugrebuildstate',
2294 @command('debugrebuilddirstate|debugrebuildstate',
2295 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2295 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2296 _('[-r REV]'))
2296 _('[-r REV]'))
2297 def debugrebuilddirstate(ui, repo, rev):
2297 def debugrebuilddirstate(ui, repo, rev):
2298 """rebuild the dirstate as it would look like for the given revision
2298 """rebuild the dirstate as it would look like for the given revision
2299
2299
2300 If no revision is specified the first current parent will be used.
2300 If no revision is specified the first current parent will be used.
2301
2301
2302 The dirstate will be set to the files of the given revision.
2302 The dirstate will be set to the files of the given revision.
2303 The actual working directory content or existing dirstate
2303 The actual working directory content or existing dirstate
2304 information such as adds or removes is not considered.
2304 information such as adds or removes is not considered.
2305
2305
2306 One use of this command is to make the next :hg:`status` invocation
2306 One use of this command is to make the next :hg:`status` invocation
2307 check the actual file content.
2307 check the actual file content.
2308 """
2308 """
2309 ctx = scmutil.revsingle(repo, rev)
2309 ctx = scmutil.revsingle(repo, rev)
2310 wlock = repo.wlock()
2310 wlock = repo.wlock()
2311 try:
2311 try:
2312 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2312 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2313 finally:
2313 finally:
2314 wlock.release()
2314 wlock.release()
2315
2315
2316 @command('debugrename',
2316 @command('debugrename',
2317 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2317 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2318 _('[-r REV] FILE'))
2318 _('[-r REV] FILE'))
2319 def debugrename(ui, repo, file1, *pats, **opts):
2319 def debugrename(ui, repo, file1, *pats, **opts):
2320 """dump rename information"""
2320 """dump rename information"""
2321
2321
2322 ctx = scmutil.revsingle(repo, opts.get('rev'))
2322 ctx = scmutil.revsingle(repo, opts.get('rev'))
2323 m = scmutil.match(ctx, (file1,) + pats, opts)
2323 m = scmutil.match(ctx, (file1,) + pats, opts)
2324 for abs in ctx.walk(m):
2324 for abs in ctx.walk(m):
2325 fctx = ctx[abs]
2325 fctx = ctx[abs]
2326 o = fctx.filelog().renamed(fctx.filenode())
2326 o = fctx.filelog().renamed(fctx.filenode())
2327 rel = m.rel(abs)
2327 rel = m.rel(abs)
2328 if o:
2328 if o:
2329 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2329 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2330 else:
2330 else:
2331 ui.write(_("%s not renamed\n") % rel)
2331 ui.write(_("%s not renamed\n") % rel)
2332
2332
2333 @command('debugrevlog',
2333 @command('debugrevlog',
2334 [('c', 'changelog', False, _('open changelog')),
2334 [('c', 'changelog', False, _('open changelog')),
2335 ('m', 'manifest', False, _('open manifest')),
2335 ('m', 'manifest', False, _('open manifest')),
2336 ('d', 'dump', False, _('dump index data'))],
2336 ('d', 'dump', False, _('dump index data'))],
2337 _('-c|-m|FILE'))
2337 _('-c|-m|FILE'))
2338 def debugrevlog(ui, repo, file_ = None, **opts):
2338 def debugrevlog(ui, repo, file_ = None, **opts):
2339 """show data and statistics about a revlog"""
2339 """show data and statistics about a revlog"""
2340 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2340 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2341
2341
2342 if opts.get("dump"):
2342 if opts.get("dump"):
2343 numrevs = len(r)
2343 numrevs = len(r)
2344 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2344 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2345 " rawsize totalsize compression heads\n")
2345 " rawsize totalsize compression heads\n")
2346 ts = 0
2346 ts = 0
2347 heads = set()
2347 heads = set()
2348 for rev in xrange(numrevs):
2348 for rev in xrange(numrevs):
2349 dbase = r.deltaparent(rev)
2349 dbase = r.deltaparent(rev)
2350 if dbase == -1:
2350 if dbase == -1:
2351 dbase = rev
2351 dbase = rev
2352 cbase = r.chainbase(rev)
2352 cbase = r.chainbase(rev)
2353 p1, p2 = r.parentrevs(rev)
2353 p1, p2 = r.parentrevs(rev)
2354 rs = r.rawsize(rev)
2354 rs = r.rawsize(rev)
2355 ts = ts + rs
2355 ts = ts + rs
2356 heads -= set(r.parentrevs(rev))
2356 heads -= set(r.parentrevs(rev))
2357 heads.add(rev)
2357 heads.add(rev)
2358 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2358 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2359 (rev, p1, p2, r.start(rev), r.end(rev),
2359 (rev, p1, p2, r.start(rev), r.end(rev),
2360 r.start(dbase), r.start(cbase),
2360 r.start(dbase), r.start(cbase),
2361 r.start(p1), r.start(p2),
2361 r.start(p1), r.start(p2),
2362 rs, ts, ts / r.end(rev), len(heads)))
2362 rs, ts, ts / r.end(rev), len(heads)))
2363 return 0
2363 return 0
2364
2364
2365 v = r.version
2365 v = r.version
2366 format = v & 0xFFFF
2366 format = v & 0xFFFF
2367 flags = []
2367 flags = []
2368 gdelta = False
2368 gdelta = False
2369 if v & revlog.REVLOGNGINLINEDATA:
2369 if v & revlog.REVLOGNGINLINEDATA:
2370 flags.append('inline')
2370 flags.append('inline')
2371 if v & revlog.REVLOGGENERALDELTA:
2371 if v & revlog.REVLOGGENERALDELTA:
2372 gdelta = True
2372 gdelta = True
2373 flags.append('generaldelta')
2373 flags.append('generaldelta')
2374 if not flags:
2374 if not flags:
2375 flags = ['(none)']
2375 flags = ['(none)']
2376
2376
2377 nummerges = 0
2377 nummerges = 0
2378 numfull = 0
2378 numfull = 0
2379 numprev = 0
2379 numprev = 0
2380 nump1 = 0
2380 nump1 = 0
2381 nump2 = 0
2381 nump2 = 0
2382 numother = 0
2382 numother = 0
2383 nump1prev = 0
2383 nump1prev = 0
2384 nump2prev = 0
2384 nump2prev = 0
2385 chainlengths = []
2385 chainlengths = []
2386
2386
2387 datasize = [None, 0, 0L]
2387 datasize = [None, 0, 0L]
2388 fullsize = [None, 0, 0L]
2388 fullsize = [None, 0, 0L]
2389 deltasize = [None, 0, 0L]
2389 deltasize = [None, 0, 0L]
2390
2390
2391 def addsize(size, l):
2391 def addsize(size, l):
2392 if l[0] is None or size < l[0]:
2392 if l[0] is None or size < l[0]:
2393 l[0] = size
2393 l[0] = size
2394 if size > l[1]:
2394 if size > l[1]:
2395 l[1] = size
2395 l[1] = size
2396 l[2] += size
2396 l[2] += size
2397
2397
2398 numrevs = len(r)
2398 numrevs = len(r)
2399 for rev in xrange(numrevs):
2399 for rev in xrange(numrevs):
2400 p1, p2 = r.parentrevs(rev)
2400 p1, p2 = r.parentrevs(rev)
2401 delta = r.deltaparent(rev)
2401 delta = r.deltaparent(rev)
2402 if format > 0:
2402 if format > 0:
2403 addsize(r.rawsize(rev), datasize)
2403 addsize(r.rawsize(rev), datasize)
2404 if p2 != nullrev:
2404 if p2 != nullrev:
2405 nummerges += 1
2405 nummerges += 1
2406 size = r.length(rev)
2406 size = r.length(rev)
2407 if delta == nullrev:
2407 if delta == nullrev:
2408 chainlengths.append(0)
2408 chainlengths.append(0)
2409 numfull += 1
2409 numfull += 1
2410 addsize(size, fullsize)
2410 addsize(size, fullsize)
2411 else:
2411 else:
2412 chainlengths.append(chainlengths[delta] + 1)
2412 chainlengths.append(chainlengths[delta] + 1)
2413 addsize(size, deltasize)
2413 addsize(size, deltasize)
2414 if delta == rev - 1:
2414 if delta == rev - 1:
2415 numprev += 1
2415 numprev += 1
2416 if delta == p1:
2416 if delta == p1:
2417 nump1prev += 1
2417 nump1prev += 1
2418 elif delta == p2:
2418 elif delta == p2:
2419 nump2prev += 1
2419 nump2prev += 1
2420 elif delta == p1:
2420 elif delta == p1:
2421 nump1 += 1
2421 nump1 += 1
2422 elif delta == p2:
2422 elif delta == p2:
2423 nump2 += 1
2423 nump2 += 1
2424 elif delta != nullrev:
2424 elif delta != nullrev:
2425 numother += 1
2425 numother += 1
2426
2426
2427 # Adjust size min value for empty cases
2427 # Adjust size min value for empty cases
2428 for size in (datasize, fullsize, deltasize):
2428 for size in (datasize, fullsize, deltasize):
2429 if size[0] is None:
2429 if size[0] is None:
2430 size[0] = 0
2430 size[0] = 0
2431
2431
2432 numdeltas = numrevs - numfull
2432 numdeltas = numrevs - numfull
2433 numoprev = numprev - nump1prev - nump2prev
2433 numoprev = numprev - nump1prev - nump2prev
2434 totalrawsize = datasize[2]
2434 totalrawsize = datasize[2]
2435 datasize[2] /= numrevs
2435 datasize[2] /= numrevs
2436 fulltotal = fullsize[2]
2436 fulltotal = fullsize[2]
2437 fullsize[2] /= numfull
2437 fullsize[2] /= numfull
2438 deltatotal = deltasize[2]
2438 deltatotal = deltasize[2]
2439 if numrevs - numfull > 0:
2439 if numrevs - numfull > 0:
2440 deltasize[2] /= numrevs - numfull
2440 deltasize[2] /= numrevs - numfull
2441 totalsize = fulltotal + deltatotal
2441 totalsize = fulltotal + deltatotal
2442 avgchainlen = sum(chainlengths) / numrevs
2442 avgchainlen = sum(chainlengths) / numrevs
2443 compratio = totalrawsize / totalsize
2443 compratio = totalrawsize / totalsize
2444
2444
2445 basedfmtstr = '%%%dd\n'
2445 basedfmtstr = '%%%dd\n'
2446 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2446 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2447
2447
2448 def dfmtstr(max):
2448 def dfmtstr(max):
2449 return basedfmtstr % len(str(max))
2449 return basedfmtstr % len(str(max))
2450 def pcfmtstr(max, padding=0):
2450 def pcfmtstr(max, padding=0):
2451 return basepcfmtstr % (len(str(max)), ' ' * padding)
2451 return basepcfmtstr % (len(str(max)), ' ' * padding)
2452
2452
2453 def pcfmt(value, total):
2453 def pcfmt(value, total):
2454 return (value, 100 * float(value) / total)
2454 return (value, 100 * float(value) / total)
2455
2455
2456 ui.write(('format : %d\n') % format)
2456 ui.write(('format : %d\n') % format)
2457 ui.write(('flags : %s\n') % ', '.join(flags))
2457 ui.write(('flags : %s\n') % ', '.join(flags))
2458
2458
2459 ui.write('\n')
2459 ui.write('\n')
2460 fmt = pcfmtstr(totalsize)
2460 fmt = pcfmtstr(totalsize)
2461 fmt2 = dfmtstr(totalsize)
2461 fmt2 = dfmtstr(totalsize)
2462 ui.write(('revisions : ') + fmt2 % numrevs)
2462 ui.write(('revisions : ') + fmt2 % numrevs)
2463 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2463 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2464 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2464 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2465 ui.write(('revisions : ') + fmt2 % numrevs)
2465 ui.write(('revisions : ') + fmt2 % numrevs)
2466 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2466 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2467 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2467 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2468 ui.write(('revision size : ') + fmt2 % totalsize)
2468 ui.write(('revision size : ') + fmt2 % totalsize)
2469 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2469 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2470 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2470 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2471
2471
2472 ui.write('\n')
2472 ui.write('\n')
2473 fmt = dfmtstr(max(avgchainlen, compratio))
2473 fmt = dfmtstr(max(avgchainlen, compratio))
2474 ui.write(('avg chain length : ') + fmt % avgchainlen)
2474 ui.write(('avg chain length : ') + fmt % avgchainlen)
2475 ui.write(('compression ratio : ') + fmt % compratio)
2475 ui.write(('compression ratio : ') + fmt % compratio)
2476
2476
2477 if format > 0:
2477 if format > 0:
2478 ui.write('\n')
2478 ui.write('\n')
2479 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2479 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2480 % tuple(datasize))
2480 % tuple(datasize))
2481 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2481 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2482 % tuple(fullsize))
2482 % tuple(fullsize))
2483 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2483 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2484 % tuple(deltasize))
2484 % tuple(deltasize))
2485
2485
2486 if numdeltas > 0:
2486 if numdeltas > 0:
2487 ui.write('\n')
2487 ui.write('\n')
2488 fmt = pcfmtstr(numdeltas)
2488 fmt = pcfmtstr(numdeltas)
2489 fmt2 = pcfmtstr(numdeltas, 4)
2489 fmt2 = pcfmtstr(numdeltas, 4)
2490 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2490 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2491 if numprev > 0:
2491 if numprev > 0:
2492 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2492 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2493 numprev))
2493 numprev))
2494 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2494 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2495 numprev))
2495 numprev))
2496 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2496 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2497 numprev))
2497 numprev))
2498 if gdelta:
2498 if gdelta:
2499 ui.write(('deltas against p1 : ')
2499 ui.write(('deltas against p1 : ')
2500 + fmt % pcfmt(nump1, numdeltas))
2500 + fmt % pcfmt(nump1, numdeltas))
2501 ui.write(('deltas against p2 : ')
2501 ui.write(('deltas against p2 : ')
2502 + fmt % pcfmt(nump2, numdeltas))
2502 + fmt % pcfmt(nump2, numdeltas))
2503 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2503 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2504 numdeltas))
2504 numdeltas))
2505
2505
2506 @command('debugrevspec', [], ('REVSPEC'))
2506 @command('debugrevspec', [], ('REVSPEC'))
2507 def debugrevspec(ui, repo, expr):
2507 def debugrevspec(ui, repo, expr):
2508 """parse and apply a revision specification
2508 """parse and apply a revision specification
2509
2509
2510 Use --verbose to print the parsed tree before and after aliases
2510 Use --verbose to print the parsed tree before and after aliases
2511 expansion.
2511 expansion.
2512 """
2512 """
2513 if ui.verbose:
2513 if ui.verbose:
2514 tree = revset.parse(expr)[0]
2514 tree = revset.parse(expr)[0]
2515 ui.note(revset.prettyformat(tree), "\n")
2515 ui.note(revset.prettyformat(tree), "\n")
2516 newtree = revset.findaliases(ui, tree)
2516 newtree = revset.findaliases(ui, tree)
2517 if newtree != tree:
2517 if newtree != tree:
2518 ui.note(revset.prettyformat(newtree), "\n")
2518 ui.note(revset.prettyformat(newtree), "\n")
2519 func = revset.match(ui, expr)
2519 func = revset.match(ui, expr)
2520 for c in func(repo, range(len(repo))):
2520 for c in func(repo, range(len(repo))):
2521 ui.write("%s\n" % c)
2521 ui.write("%s\n" % c)
2522
2522
2523 @command('debugsetparents', [], _('REV1 [REV2]'))
2523 @command('debugsetparents', [], _('REV1 [REV2]'))
2524 def debugsetparents(ui, repo, rev1, rev2=None):
2524 def debugsetparents(ui, repo, rev1, rev2=None):
2525 """manually set the parents of the current working directory
2525 """manually set the parents of the current working directory
2526
2526
2527 This is useful for writing repository conversion tools, but should
2527 This is useful for writing repository conversion tools, but should
2528 be used with care.
2528 be used with care.
2529
2529
2530 Returns 0 on success.
2530 Returns 0 on success.
2531 """
2531 """
2532
2532
2533 r1 = scmutil.revsingle(repo, rev1).node()
2533 r1 = scmutil.revsingle(repo, rev1).node()
2534 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2534 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2535
2535
2536 wlock = repo.wlock()
2536 wlock = repo.wlock()
2537 try:
2537 try:
2538 repo.setparents(r1, r2)
2538 repo.setparents(r1, r2)
2539 finally:
2539 finally:
2540 wlock.release()
2540 wlock.release()
2541
2541
2542 @command('debugdirstate|debugstate',
2542 @command('debugdirstate|debugstate',
2543 [('', 'nodates', None, _('do not display the saved mtime')),
2543 [('', 'nodates', None, _('do not display the saved mtime')),
2544 ('', 'datesort', None, _('sort by saved mtime'))],
2544 ('', 'datesort', None, _('sort by saved mtime'))],
2545 _('[OPTION]...'))
2545 _('[OPTION]...'))
2546 def debugstate(ui, repo, nodates=None, datesort=None):
2546 def debugstate(ui, repo, nodates=None, datesort=None):
2547 """show the contents of the current dirstate"""
2547 """show the contents of the current dirstate"""
2548 timestr = ""
2548 timestr = ""
2549 showdate = not nodates
2549 showdate = not nodates
2550 if datesort:
2550 if datesort:
2551 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2551 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2552 else:
2552 else:
2553 keyfunc = None # sort by filename
2553 keyfunc = None # sort by filename
2554 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2554 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2555 if showdate:
2555 if showdate:
2556 if ent[3] == -1:
2556 if ent[3] == -1:
2557 # Pad or slice to locale representation
2557 # Pad or slice to locale representation
2558 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2558 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2559 time.localtime(0)))
2559 time.localtime(0)))
2560 timestr = 'unset'
2560 timestr = 'unset'
2561 timestr = (timestr[:locale_len] +
2561 timestr = (timestr[:locale_len] +
2562 ' ' * (locale_len - len(timestr)))
2562 ' ' * (locale_len - len(timestr)))
2563 else:
2563 else:
2564 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2564 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2565 time.localtime(ent[3]))
2565 time.localtime(ent[3]))
2566 if ent[1] & 020000:
2566 if ent[1] & 020000:
2567 mode = 'lnk'
2567 mode = 'lnk'
2568 else:
2568 else:
2569 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2569 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2570 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2570 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2571 for f in repo.dirstate.copies():
2571 for f in repo.dirstate.copies():
2572 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2572 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2573
2573
2574 @command('debugsub',
2574 @command('debugsub',
2575 [('r', 'rev', '',
2575 [('r', 'rev', '',
2576 _('revision to check'), _('REV'))],
2576 _('revision to check'), _('REV'))],
2577 _('[-r REV] [REV]'))
2577 _('[-r REV] [REV]'))
2578 def debugsub(ui, repo, rev=None):
2578 def debugsub(ui, repo, rev=None):
2579 ctx = scmutil.revsingle(repo, rev, None)
2579 ctx = scmutil.revsingle(repo, rev, None)
2580 for k, v in sorted(ctx.substate.items()):
2580 for k, v in sorted(ctx.substate.items()):
2581 ui.write(('path %s\n') % k)
2581 ui.write(('path %s\n') % k)
2582 ui.write((' source %s\n') % v[0])
2582 ui.write((' source %s\n') % v[0])
2583 ui.write((' revision %s\n') % v[1])
2583 ui.write((' revision %s\n') % v[1])
2584
2584
2585 @command('debugsuccessorssets',
2585 @command('debugsuccessorssets',
2586 [],
2586 [],
2587 _('[REV]'))
2587 _('[REV]'))
2588 def debugsuccessorssets(ui, repo, *revs):
2588 def debugsuccessorssets(ui, repo, *revs):
2589 """show set of successors for revision
2589 """show set of successors for revision
2590
2590
2591 A successors set of changeset A is a consistent group of revisions that
2591 A successors set of changeset A is a consistent group of revisions that
2592 succeed A. It contains non-obsolete changesets only.
2592 succeed A. It contains non-obsolete changesets only.
2593
2593
2594 In most cases a changeset A has a single successors set containing a single
2594 In most cases a changeset A has a single successors set containing a single
2595 successor (changeset A replaced by A').
2595 successor (changeset A replaced by A').
2596
2596
2597 A changeset that is made obsolete with no successors are called "pruned".
2597 A changeset that is made obsolete with no successors are called "pruned".
2598 Such changesets have no successors sets at all.
2598 Such changesets have no successors sets at all.
2599
2599
2600 A changeset that has been "split" will have a successors set containing
2600 A changeset that has been "split" will have a successors set containing
2601 more than one successor.
2601 more than one successor.
2602
2602
2603 A changeset that has been rewritten in multiple different ways is called
2603 A changeset that has been rewritten in multiple different ways is called
2604 "divergent". Such changesets have multiple successor sets (each of which
2604 "divergent". Such changesets have multiple successor sets (each of which
2605 may also be split, i.e. have multiple successors).
2605 may also be split, i.e. have multiple successors).
2606
2606
2607 Results are displayed as follows::
2607 Results are displayed as follows::
2608
2608
2609 <rev1>
2609 <rev1>
2610 <successors-1A>
2610 <successors-1A>
2611 <rev2>
2611 <rev2>
2612 <successors-2A>
2612 <successors-2A>
2613 <successors-2B1> <successors-2B2> <successors-2B3>
2613 <successors-2B1> <successors-2B2> <successors-2B3>
2614
2614
2615 Here rev2 has two possible (i.e. divergent) successors sets. The first
2615 Here rev2 has two possible (i.e. divergent) successors sets. The first
2616 holds one element, whereas the second holds three (i.e. the changeset has
2616 holds one element, whereas the second holds three (i.e. the changeset has
2617 been split).
2617 been split).
2618 """
2618 """
2619 # passed to successorssets caching computation from one call to another
2619 # passed to successorssets caching computation from one call to another
2620 cache = {}
2620 cache = {}
2621 ctx2str = str
2621 ctx2str = str
2622 node2str = short
2622 node2str = short
2623 if ui.debug():
2623 if ui.debug():
2624 def ctx2str(ctx):
2624 def ctx2str(ctx):
2625 return ctx.hex()
2625 return ctx.hex()
2626 node2str = hex
2626 node2str = hex
2627 for rev in scmutil.revrange(repo, revs):
2627 for rev in scmutil.revrange(repo, revs):
2628 ctx = repo[rev]
2628 ctx = repo[rev]
2629 ui.write('%s\n'% ctx2str(ctx))
2629 ui.write('%s\n'% ctx2str(ctx))
2630 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2630 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2631 if succsset:
2631 if succsset:
2632 ui.write(' ')
2632 ui.write(' ')
2633 ui.write(node2str(succsset[0]))
2633 ui.write(node2str(succsset[0]))
2634 for node in succsset[1:]:
2634 for node in succsset[1:]:
2635 ui.write(' ')
2635 ui.write(' ')
2636 ui.write(node2str(node))
2636 ui.write(node2str(node))
2637 ui.write('\n')
2637 ui.write('\n')
2638
2638
2639 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2639 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2640 def debugwalk(ui, repo, *pats, **opts):
2640 def debugwalk(ui, repo, *pats, **opts):
2641 """show how files match on given patterns"""
2641 """show how files match on given patterns"""
2642 m = scmutil.match(repo[None], pats, opts)
2642 m = scmutil.match(repo[None], pats, opts)
2643 items = list(repo.walk(m))
2643 items = list(repo.walk(m))
2644 if not items:
2644 if not items:
2645 return
2645 return
2646 f = lambda fn: fn
2646 f = lambda fn: fn
2647 if ui.configbool('ui', 'slash') and os.sep != '/':
2647 if ui.configbool('ui', 'slash') and os.sep != '/':
2648 f = lambda fn: util.normpath(fn)
2648 f = lambda fn: util.normpath(fn)
2649 fmt = 'f %%-%ds %%-%ds %%s' % (
2649 fmt = 'f %%-%ds %%-%ds %%s' % (
2650 max([len(abs) for abs in items]),
2650 max([len(abs) for abs in items]),
2651 max([len(m.rel(abs)) for abs in items]))
2651 max([len(m.rel(abs)) for abs in items]))
2652 for abs in items:
2652 for abs in items:
2653 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2653 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2654 ui.write("%s\n" % line.rstrip())
2654 ui.write("%s\n" % line.rstrip())
2655
2655
2656 @command('debugwireargs',
2656 @command('debugwireargs',
2657 [('', 'three', '', 'three'),
2657 [('', 'three', '', 'three'),
2658 ('', 'four', '', 'four'),
2658 ('', 'four', '', 'four'),
2659 ('', 'five', '', 'five'),
2659 ('', 'five', '', 'five'),
2660 ] + remoteopts,
2660 ] + remoteopts,
2661 _('REPO [OPTIONS]... [ONE [TWO]]'))
2661 _('REPO [OPTIONS]... [ONE [TWO]]'))
2662 def debugwireargs(ui, repopath, *vals, **opts):
2662 def debugwireargs(ui, repopath, *vals, **opts):
2663 repo = hg.peer(ui, opts, repopath)
2663 repo = hg.peer(ui, opts, repopath)
2664 for opt in remoteopts:
2664 for opt in remoteopts:
2665 del opts[opt[1]]
2665 del opts[opt[1]]
2666 args = {}
2666 args = {}
2667 for k, v in opts.iteritems():
2667 for k, v in opts.iteritems():
2668 if v:
2668 if v:
2669 args[k] = v
2669 args[k] = v
2670 # run twice to check that we don't mess up the stream for the next command
2670 # run twice to check that we don't mess up the stream for the next command
2671 res1 = repo.debugwireargs(*vals, **args)
2671 res1 = repo.debugwireargs(*vals, **args)
2672 res2 = repo.debugwireargs(*vals, **args)
2672 res2 = repo.debugwireargs(*vals, **args)
2673 ui.write("%s\n" % res1)
2673 ui.write("%s\n" % res1)
2674 if res1 != res2:
2674 if res1 != res2:
2675 ui.warn("%s\n" % res2)
2675 ui.warn("%s\n" % res2)
2676
2676
2677 @command('^diff',
2677 @command('^diff',
2678 [('r', 'rev', [], _('revision'), _('REV')),
2678 [('r', 'rev', [], _('revision'), _('REV')),
2679 ('c', 'change', '', _('change made by revision'), _('REV'))
2679 ('c', 'change', '', _('change made by revision'), _('REV'))
2680 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2680 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2681 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2681 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2682 def diff(ui, repo, *pats, **opts):
2682 def diff(ui, repo, *pats, **opts):
2683 """diff repository (or selected files)
2683 """diff repository (or selected files)
2684
2684
2685 Show differences between revisions for the specified files.
2685 Show differences between revisions for the specified files.
2686
2686
2687 Differences between files are shown using the unified diff format.
2687 Differences between files are shown using the unified diff format.
2688
2688
2689 .. note::
2689 .. note::
2690 diff may generate unexpected results for merges, as it will
2690 diff may generate unexpected results for merges, as it will
2691 default to comparing against the working directory's first
2691 default to comparing against the working directory's first
2692 parent changeset if no revisions are specified.
2692 parent changeset if no revisions are specified.
2693
2693
2694 When two revision arguments are given, then changes are shown
2694 When two revision arguments are given, then changes are shown
2695 between those revisions. If only one revision is specified then
2695 between those revisions. If only one revision is specified then
2696 that revision is compared to the working directory, and, when no
2696 that revision is compared to the working directory, and, when no
2697 revisions are specified, the working directory files are compared
2697 revisions are specified, the working directory files are compared
2698 to its parent.
2698 to its parent.
2699
2699
2700 Alternatively you can specify -c/--change with a revision to see
2700 Alternatively you can specify -c/--change with a revision to see
2701 the changes in that changeset relative to its first parent.
2701 the changes in that changeset relative to its first parent.
2702
2702
2703 Without the -a/--text option, diff will avoid generating diffs of
2703 Without the -a/--text option, diff will avoid generating diffs of
2704 files it detects as binary. With -a, diff will generate a diff
2704 files it detects as binary. With -a, diff will generate a diff
2705 anyway, probably with undesirable results.
2705 anyway, probably with undesirable results.
2706
2706
2707 Use the -g/--git option to generate diffs in the git extended diff
2707 Use the -g/--git option to generate diffs in the git extended diff
2708 format. For more information, read :hg:`help diffs`.
2708 format. For more information, read :hg:`help diffs`.
2709
2709
2710 .. container:: verbose
2710 .. container:: verbose
2711
2711
2712 Examples:
2712 Examples:
2713
2713
2714 - compare a file in the current working directory to its parent::
2714 - compare a file in the current working directory to its parent::
2715
2715
2716 hg diff foo.c
2716 hg diff foo.c
2717
2717
2718 - compare two historical versions of a directory, with rename info::
2718 - compare two historical versions of a directory, with rename info::
2719
2719
2720 hg diff --git -r 1.0:1.2 lib/
2720 hg diff --git -r 1.0:1.2 lib/
2721
2721
2722 - get change stats relative to the last change on some date::
2722 - get change stats relative to the last change on some date::
2723
2723
2724 hg diff --stat -r "date('may 2')"
2724 hg diff --stat -r "date('may 2')"
2725
2725
2726 - diff all newly-added files that contain a keyword::
2726 - diff all newly-added files that contain a keyword::
2727
2727
2728 hg diff "set:added() and grep(GNU)"
2728 hg diff "set:added() and grep(GNU)"
2729
2729
2730 - compare a revision and its parents::
2730 - compare a revision and its parents::
2731
2731
2732 hg diff -c 9353 # compare against first parent
2732 hg diff -c 9353 # compare against first parent
2733 hg diff -r 9353^:9353 # same using revset syntax
2733 hg diff -r 9353^:9353 # same using revset syntax
2734 hg diff -r 9353^2:9353 # compare against the second parent
2734 hg diff -r 9353^2:9353 # compare against the second parent
2735
2735
2736 Returns 0 on success.
2736 Returns 0 on success.
2737 """
2737 """
2738
2738
2739 revs = opts.get('rev')
2739 revs = opts.get('rev')
2740 change = opts.get('change')
2740 change = opts.get('change')
2741 stat = opts.get('stat')
2741 stat = opts.get('stat')
2742 reverse = opts.get('reverse')
2742 reverse = opts.get('reverse')
2743
2743
2744 if revs and change:
2744 if revs and change:
2745 msg = _('cannot specify --rev and --change at the same time')
2745 msg = _('cannot specify --rev and --change at the same time')
2746 raise util.Abort(msg)
2746 raise util.Abort(msg)
2747 elif change:
2747 elif change:
2748 node2 = scmutil.revsingle(repo, change, None).node()
2748 node2 = scmutil.revsingle(repo, change, None).node()
2749 node1 = repo[node2].p1().node()
2749 node1 = repo[node2].p1().node()
2750 else:
2750 else:
2751 node1, node2 = scmutil.revpair(repo, revs)
2751 node1, node2 = scmutil.revpair(repo, revs)
2752
2752
2753 if reverse:
2753 if reverse:
2754 node1, node2 = node2, node1
2754 node1, node2 = node2, node1
2755
2755
2756 diffopts = patch.diffopts(ui, opts)
2756 diffopts = patch.diffopts(ui, opts)
2757 m = scmutil.match(repo[node2], pats, opts)
2757 m = scmutil.match(repo[node2], pats, opts)
2758 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2758 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2759 listsubrepos=opts.get('subrepos'))
2759 listsubrepos=opts.get('subrepos'))
2760
2760
2761 @command('^export',
2761 @command('^export',
2762 [('o', 'output', '',
2762 [('o', 'output', '',
2763 _('print output to file with formatted name'), _('FORMAT')),
2763 _('print output to file with formatted name'), _('FORMAT')),
2764 ('', 'switch-parent', None, _('diff against the second parent')),
2764 ('', 'switch-parent', None, _('diff against the second parent')),
2765 ('r', 'rev', [], _('revisions to export'), _('REV')),
2765 ('r', 'rev', [], _('revisions to export'), _('REV')),
2766 ] + diffopts,
2766 ] + diffopts,
2767 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2767 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2768 def export(ui, repo, *changesets, **opts):
2768 def export(ui, repo, *changesets, **opts):
2769 """dump the header and diffs for one or more changesets
2769 """dump the header and diffs for one or more changesets
2770
2770
2771 Print the changeset header and diffs for one or more revisions.
2771 Print the changeset header and diffs for one or more revisions.
2772 If no revision is given, the parent of the working directory is used.
2772 If no revision is given, the parent of the working directory is used.
2773
2773
2774 The information shown in the changeset header is: author, date,
2774 The information shown in the changeset header is: author, date,
2775 branch name (if non-default), changeset hash, parent(s) and commit
2775 branch name (if non-default), changeset hash, parent(s) and commit
2776 comment.
2776 comment.
2777
2777
2778 .. note::
2778 .. note::
2779 export may generate unexpected diff output for merge
2779 export may generate unexpected diff output for merge
2780 changesets, as it will compare the merge changeset against its
2780 changesets, as it will compare the merge changeset against its
2781 first parent only.
2781 first parent only.
2782
2782
2783 Output may be to a file, in which case the name of the file is
2783 Output may be to a file, in which case the name of the file is
2784 given using a format string. The formatting rules are as follows:
2784 given using a format string. The formatting rules are as follows:
2785
2785
2786 :``%%``: literal "%" character
2786 :``%%``: literal "%" character
2787 :``%H``: changeset hash (40 hexadecimal digits)
2787 :``%H``: changeset hash (40 hexadecimal digits)
2788 :``%N``: number of patches being generated
2788 :``%N``: number of patches being generated
2789 :``%R``: changeset revision number
2789 :``%R``: changeset revision number
2790 :``%b``: basename of the exporting repository
2790 :``%b``: basename of the exporting repository
2791 :``%h``: short-form changeset hash (12 hexadecimal digits)
2791 :``%h``: short-form changeset hash (12 hexadecimal digits)
2792 :``%m``: first line of the commit message (only alphanumeric characters)
2792 :``%m``: first line of the commit message (only alphanumeric characters)
2793 :``%n``: zero-padded sequence number, starting at 1
2793 :``%n``: zero-padded sequence number, starting at 1
2794 :``%r``: zero-padded changeset revision number
2794 :``%r``: zero-padded changeset revision number
2795
2795
2796 Without the -a/--text option, export will avoid generating diffs
2796 Without the -a/--text option, export will avoid generating diffs
2797 of files it detects as binary. With -a, export will generate a
2797 of files it detects as binary. With -a, export will generate a
2798 diff anyway, probably with undesirable results.
2798 diff anyway, probably with undesirable results.
2799
2799
2800 Use the -g/--git option to generate diffs in the git extended diff
2800 Use the -g/--git option to generate diffs in the git extended diff
2801 format. See :hg:`help diffs` for more information.
2801 format. See :hg:`help diffs` for more information.
2802
2802
2803 With the --switch-parent option, the diff will be against the
2803 With the --switch-parent option, the diff will be against the
2804 second parent. It can be useful to review a merge.
2804 second parent. It can be useful to review a merge.
2805
2805
2806 .. container:: verbose
2806 .. container:: verbose
2807
2807
2808 Examples:
2808 Examples:
2809
2809
2810 - use export and import to transplant a bugfix to the current
2810 - use export and import to transplant a bugfix to the current
2811 branch::
2811 branch::
2812
2812
2813 hg export -r 9353 | hg import -
2813 hg export -r 9353 | hg import -
2814
2814
2815 - export all the changesets between two revisions to a file with
2815 - export all the changesets between two revisions to a file with
2816 rename information::
2816 rename information::
2817
2817
2818 hg export --git -r 123:150 > changes.txt
2818 hg export --git -r 123:150 > changes.txt
2819
2819
2820 - split outgoing changes into a series of patches with
2820 - split outgoing changes into a series of patches with
2821 descriptive names::
2821 descriptive names::
2822
2822
2823 hg export -r "outgoing()" -o "%n-%m.patch"
2823 hg export -r "outgoing()" -o "%n-%m.patch"
2824
2824
2825 Returns 0 on success.
2825 Returns 0 on success.
2826 """
2826 """
2827 changesets += tuple(opts.get('rev', []))
2827 changesets += tuple(opts.get('rev', []))
2828 if not changesets:
2828 if not changesets:
2829 changesets = ['.']
2829 changesets = ['.']
2830 revs = scmutil.revrange(repo, changesets)
2830 revs = scmutil.revrange(repo, changesets)
2831 if not revs:
2831 if not revs:
2832 raise util.Abort(_("export requires at least one changeset"))
2832 raise util.Abort(_("export requires at least one changeset"))
2833 if len(revs) > 1:
2833 if len(revs) > 1:
2834 ui.note(_('exporting patches:\n'))
2834 ui.note(_('exporting patches:\n'))
2835 else:
2835 else:
2836 ui.note(_('exporting patch:\n'))
2836 ui.note(_('exporting patch:\n'))
2837 cmdutil.export(repo, revs, template=opts.get('output'),
2837 cmdutil.export(repo, revs, template=opts.get('output'),
2838 switch_parent=opts.get('switch_parent'),
2838 switch_parent=opts.get('switch_parent'),
2839 opts=patch.diffopts(ui, opts))
2839 opts=patch.diffopts(ui, opts))
2840
2840
2841 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2841 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2842 def forget(ui, repo, *pats, **opts):
2842 def forget(ui, repo, *pats, **opts):
2843 """forget the specified files on the next commit
2843 """forget the specified files on the next commit
2844
2844
2845 Mark the specified files so they will no longer be tracked
2845 Mark the specified files so they will no longer be tracked
2846 after the next commit.
2846 after the next commit.
2847
2847
2848 This only removes files from the current branch, not from the
2848 This only removes files from the current branch, not from the
2849 entire project history, and it does not delete them from the
2849 entire project history, and it does not delete them from the
2850 working directory.
2850 working directory.
2851
2851
2852 To undo a forget before the next commit, see :hg:`add`.
2852 To undo a forget before the next commit, see :hg:`add`.
2853
2853
2854 .. container:: verbose
2854 .. container:: verbose
2855
2855
2856 Examples:
2856 Examples:
2857
2857
2858 - forget newly-added binary files::
2858 - forget newly-added binary files::
2859
2859
2860 hg forget "set:added() and binary()"
2860 hg forget "set:added() and binary()"
2861
2861
2862 - forget files that would be excluded by .hgignore::
2862 - forget files that would be excluded by .hgignore::
2863
2863
2864 hg forget "set:hgignore()"
2864 hg forget "set:hgignore()"
2865
2865
2866 Returns 0 on success.
2866 Returns 0 on success.
2867 """
2867 """
2868
2868
2869 if not pats:
2869 if not pats:
2870 raise util.Abort(_('no files specified'))
2870 raise util.Abort(_('no files specified'))
2871
2871
2872 m = scmutil.match(repo[None], pats, opts)
2872 m = scmutil.match(repo[None], pats, opts)
2873 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2873 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2874 return rejected and 1 or 0
2874 return rejected and 1 or 0
2875
2875
2876 @command(
2876 @command(
2877 'graft',
2877 'graft',
2878 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2878 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2879 ('c', 'continue', False, _('resume interrupted graft')),
2879 ('c', 'continue', False, _('resume interrupted graft')),
2880 ('e', 'edit', False, _('invoke editor on commit messages')),
2880 ('e', 'edit', False, _('invoke editor on commit messages')),
2881 ('', 'log', None, _('append graft info to log message')),
2881 ('', 'log', None, _('append graft info to log message')),
2882 ('D', 'currentdate', False,
2882 ('D', 'currentdate', False,
2883 _('record the current date as commit date')),
2883 _('record the current date as commit date')),
2884 ('U', 'currentuser', False,
2884 ('U', 'currentuser', False,
2885 _('record the current user as committer'), _('DATE'))]
2885 _('record the current user as committer'), _('DATE'))]
2886 + commitopts2 + mergetoolopts + dryrunopts,
2886 + commitopts2 + mergetoolopts + dryrunopts,
2887 _('[OPTION]... [-r] REV...'))
2887 _('[OPTION]... [-r] REV...'))
2888 def graft(ui, repo, *revs, **opts):
2888 def graft(ui, repo, *revs, **opts):
2889 '''copy changes from other branches onto the current branch
2889 '''copy changes from other branches onto the current branch
2890
2890
2891 This command uses Mercurial's merge logic to copy individual
2891 This command uses Mercurial's merge logic to copy individual
2892 changes from other branches without merging branches in the
2892 changes from other branches without merging branches in the
2893 history graph. This is sometimes known as 'backporting' or
2893 history graph. This is sometimes known as 'backporting' or
2894 'cherry-picking'. By default, graft will copy user, date, and
2894 'cherry-picking'. By default, graft will copy user, date, and
2895 description from the source changesets.
2895 description from the source changesets.
2896
2896
2897 Changesets that are ancestors of the current revision, that have
2897 Changesets that are ancestors of the current revision, that have
2898 already been grafted, or that are merges will be skipped.
2898 already been grafted, or that are merges will be skipped.
2899
2899
2900 If --log is specified, log messages will have a comment appended
2900 If --log is specified, log messages will have a comment appended
2901 of the form::
2901 of the form::
2902
2902
2903 (grafted from CHANGESETHASH)
2903 (grafted from CHANGESETHASH)
2904
2904
2905 If a graft merge results in conflicts, the graft process is
2905 If a graft merge results in conflicts, the graft process is
2906 interrupted so that the current merge can be manually resolved.
2906 interrupted so that the current merge can be manually resolved.
2907 Once all conflicts are addressed, the graft process can be
2907 Once all conflicts are addressed, the graft process can be
2908 continued with the -c/--continue option.
2908 continued with the -c/--continue option.
2909
2909
2910 .. note::
2910 .. note::
2911 The -c/--continue option does not reapply earlier options.
2911 The -c/--continue option does not reapply earlier options.
2912
2912
2913 .. container:: verbose
2913 .. container:: verbose
2914
2914
2915 Examples:
2915 Examples:
2916
2916
2917 - copy a single change to the stable branch and edit its description::
2917 - copy a single change to the stable branch and edit its description::
2918
2918
2919 hg update stable
2919 hg update stable
2920 hg graft --edit 9393
2920 hg graft --edit 9393
2921
2921
2922 - graft a range of changesets with one exception, updating dates::
2922 - graft a range of changesets with one exception, updating dates::
2923
2923
2924 hg graft -D "2085::2093 and not 2091"
2924 hg graft -D "2085::2093 and not 2091"
2925
2925
2926 - continue a graft after resolving conflicts::
2926 - continue a graft after resolving conflicts::
2927
2927
2928 hg graft -c
2928 hg graft -c
2929
2929
2930 - show the source of a grafted changeset::
2930 - show the source of a grafted changeset::
2931
2931
2932 hg log --debug -r .
2932 hg log --debug -r .
2933
2933
2934 Returns 0 on successful completion.
2934 Returns 0 on successful completion.
2935 '''
2935 '''
2936
2936
2937 revs = list(revs)
2937 revs = list(revs)
2938 revs.extend(opts['rev'])
2938 revs.extend(opts['rev'])
2939
2939
2940 if not opts.get('user') and opts.get('currentuser'):
2940 if not opts.get('user') and opts.get('currentuser'):
2941 opts['user'] = ui.username()
2941 opts['user'] = ui.username()
2942 if not opts.get('date') and opts.get('currentdate'):
2942 if not opts.get('date') and opts.get('currentdate'):
2943 opts['date'] = "%d %d" % util.makedate()
2943 opts['date'] = "%d %d" % util.makedate()
2944
2944
2945 editor = None
2945 editor = None
2946 if opts.get('edit'):
2946 if opts.get('edit'):
2947 editor = cmdutil.commitforceeditor
2947 editor = cmdutil.commitforceeditor
2948
2948
2949 cont = False
2949 cont = False
2950 if opts['continue']:
2950 if opts['continue']:
2951 cont = True
2951 cont = True
2952 if revs:
2952 if revs:
2953 raise util.Abort(_("can't specify --continue and revisions"))
2953 raise util.Abort(_("can't specify --continue and revisions"))
2954 # read in unfinished revisions
2954 # read in unfinished revisions
2955 try:
2955 try:
2956 nodes = repo.opener.read('graftstate').splitlines()
2956 nodes = repo.opener.read('graftstate').splitlines()
2957 revs = [repo[node].rev() for node in nodes]
2957 revs = [repo[node].rev() for node in nodes]
2958 except IOError, inst:
2958 except IOError, inst:
2959 if inst.errno != errno.ENOENT:
2959 if inst.errno != errno.ENOENT:
2960 raise
2960 raise
2961 raise util.Abort(_("no graft state found, can't continue"))
2961 raise util.Abort(_("no graft state found, can't continue"))
2962 else:
2962 else:
2963 cmdutil.bailifchanged(repo)
2963 cmdutil.bailifchanged(repo)
2964 if not revs:
2964 if not revs:
2965 raise util.Abort(_('no revisions specified'))
2965 raise util.Abort(_('no revisions specified'))
2966 revs = scmutil.revrange(repo, revs)
2966 revs = scmutil.revrange(repo, revs)
2967
2967
2968 # check for merges
2968 # check for merges
2969 for rev in repo.revs('%ld and merge()', revs):
2969 for rev in repo.revs('%ld and merge()', revs):
2970 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2970 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2971 revs.remove(rev)
2971 revs.remove(rev)
2972 if not revs:
2972 if not revs:
2973 return -1
2973 return -1
2974
2974
2975 # check for ancestors of dest branch
2975 # check for ancestors of dest branch
2976 crev = repo['.'].rev()
2976 crev = repo['.'].rev()
2977 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2977 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2978 # don't mutate while iterating, create a copy
2978 # don't mutate while iterating, create a copy
2979 for rev in list(revs):
2979 for rev in list(revs):
2980 if rev in ancestors:
2980 if rev in ancestors:
2981 ui.warn(_('skipping ancestor revision %s\n') % rev)
2981 ui.warn(_('skipping ancestor revision %s\n') % rev)
2982 revs.remove(rev)
2982 revs.remove(rev)
2983 if not revs:
2983 if not revs:
2984 return -1
2984 return -1
2985
2985
2986 # analyze revs for earlier grafts
2986 # analyze revs for earlier grafts
2987 ids = {}
2987 ids = {}
2988 for ctx in repo.set("%ld", revs):
2988 for ctx in repo.set("%ld", revs):
2989 ids[ctx.hex()] = ctx.rev()
2989 ids[ctx.hex()] = ctx.rev()
2990 n = ctx.extra().get('source')
2990 n = ctx.extra().get('source')
2991 if n:
2991 if n:
2992 ids[n] = ctx.rev()
2992 ids[n] = ctx.rev()
2993
2993
2994 # check ancestors for earlier grafts
2994 # check ancestors for earlier grafts
2995 ui.debug('scanning for duplicate grafts\n')
2995 ui.debug('scanning for duplicate grafts\n')
2996
2996
2997 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2997 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2998 ctx = repo[rev]
2998 ctx = repo[rev]
2999 n = ctx.extra().get('source')
2999 n = ctx.extra().get('source')
3000 if n in ids:
3000 if n in ids:
3001 r = repo[n].rev()
3001 r = repo[n].rev()
3002 if r in revs:
3002 if r in revs:
3003 ui.warn(_('skipping already grafted revision %s\n') % r)
3003 ui.warn(_('skipping already grafted revision %s\n') % r)
3004 revs.remove(r)
3004 revs.remove(r)
3005 elif ids[n] in revs:
3005 elif ids[n] in revs:
3006 ui.warn(_('skipping already grafted revision %s '
3006 ui.warn(_('skipping already grafted revision %s '
3007 '(same origin %d)\n') % (ids[n], r))
3007 '(same origin %d)\n') % (ids[n], r))
3008 revs.remove(ids[n])
3008 revs.remove(ids[n])
3009 elif ctx.hex() in ids:
3009 elif ctx.hex() in ids:
3010 r = ids[ctx.hex()]
3010 r = ids[ctx.hex()]
3011 ui.warn(_('skipping already grafted revision %s '
3011 ui.warn(_('skipping already grafted revision %s '
3012 '(was grafted from %d)\n') % (r, rev))
3012 '(was grafted from %d)\n') % (r, rev))
3013 revs.remove(r)
3013 revs.remove(r)
3014 if not revs:
3014 if not revs:
3015 return -1
3015 return -1
3016
3016
3017 wlock = repo.wlock()
3017 wlock = repo.wlock()
3018 try:
3018 try:
3019 current = repo['.']
3019 current = repo['.']
3020 for pos, ctx in enumerate(repo.set("%ld", revs)):
3020 for pos, ctx in enumerate(repo.set("%ld", revs)):
3021
3021
3022 ui.status(_('grafting revision %s\n') % ctx.rev())
3022 ui.status(_('grafting revision %s\n') % ctx.rev())
3023 if opts.get('dry_run'):
3023 if opts.get('dry_run'):
3024 continue
3024 continue
3025
3025
3026 source = ctx.extra().get('source')
3026 source = ctx.extra().get('source')
3027 if not source:
3027 if not source:
3028 source = ctx.hex()
3028 source = ctx.hex()
3029 extra = {'source': source}
3029 extra = {'source': source}
3030 user = ctx.user()
3030 user = ctx.user()
3031 if opts.get('user'):
3031 if opts.get('user'):
3032 user = opts['user']
3032 user = opts['user']
3033 date = ctx.date()
3033 date = ctx.date()
3034 if opts.get('date'):
3034 if opts.get('date'):
3035 date = opts['date']
3035 date = opts['date']
3036 message = ctx.description()
3036 message = ctx.description()
3037 if opts.get('log'):
3037 if opts.get('log'):
3038 message += '\n(grafted from %s)' % ctx.hex()
3038 message += '\n(grafted from %s)' % ctx.hex()
3039
3039
3040 # we don't merge the first commit when continuing
3040 # we don't merge the first commit when continuing
3041 if not cont:
3041 if not cont:
3042 # perform the graft merge with p1(rev) as 'ancestor'
3042 # perform the graft merge with p1(rev) as 'ancestor'
3043 try:
3043 try:
3044 # ui.forcemerge is an internal variable, do not document
3044 # ui.forcemerge is an internal variable, do not document
3045 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3045 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3046 stats = mergemod.update(repo, ctx.node(), True, True, False,
3046 stats = mergemod.update(repo, ctx.node(), True, True, False,
3047 ctx.p1().node())
3047 ctx.p1().node())
3048 finally:
3048 finally:
3049 repo.ui.setconfig('ui', 'forcemerge', '')
3049 repo.ui.setconfig('ui', 'forcemerge', '')
3050 # report any conflicts
3050 # report any conflicts
3051 if stats and stats[3] > 0:
3051 if stats and stats[3] > 0:
3052 # write out state for --continue
3052 # write out state for --continue
3053 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3053 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3054 repo.opener.write('graftstate', ''.join(nodelines))
3054 repo.opener.write('graftstate', ''.join(nodelines))
3055 raise util.Abort(
3055 raise util.Abort(
3056 _("unresolved conflicts, can't continue"),
3056 _("unresolved conflicts, can't continue"),
3057 hint=_('use hg resolve and hg graft --continue'))
3057 hint=_('use hg resolve and hg graft --continue'))
3058 else:
3058 else:
3059 cont = False
3059 cont = False
3060
3060
3061 # drop the second merge parent
3061 # drop the second merge parent
3062 repo.setparents(current.node(), nullid)
3062 repo.setparents(current.node(), nullid)
3063 repo.dirstate.write()
3063 repo.dirstate.write()
3064 # fix up dirstate for copies and renames
3064 # fix up dirstate for copies and renames
3065 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3065 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3066
3066
3067 # commit
3067 # commit
3068 node = repo.commit(text=message, user=user,
3068 node = repo.commit(text=message, user=user,
3069 date=date, extra=extra, editor=editor)
3069 date=date, extra=extra, editor=editor)
3070 if node is None:
3070 if node is None:
3071 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3071 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3072 else:
3072 else:
3073 current = repo[node]
3073 current = repo[node]
3074 finally:
3074 finally:
3075 wlock.release()
3075 wlock.release()
3076
3076
3077 # remove state when we complete successfully
3077 # remove state when we complete successfully
3078 if not opts.get('dry_run'):
3078 if not opts.get('dry_run'):
3079 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3079 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3080
3080
3081 return 0
3081 return 0
3082
3082
3083 @command('grep',
3083 @command('grep',
3084 [('0', 'print0', None, _('end fields with NUL')),
3084 [('0', 'print0', None, _('end fields with NUL')),
3085 ('', 'all', None, _('print all revisions that match')),
3085 ('', 'all', None, _('print all revisions that match')),
3086 ('a', 'text', None, _('treat all files as text')),
3086 ('a', 'text', None, _('treat all files as text')),
3087 ('f', 'follow', None,
3087 ('f', 'follow', None,
3088 _('follow changeset history,'
3088 _('follow changeset history,'
3089 ' or file history across copies and renames')),
3089 ' or file history across copies and renames')),
3090 ('i', 'ignore-case', None, _('ignore case when matching')),
3090 ('i', 'ignore-case', None, _('ignore case when matching')),
3091 ('l', 'files-with-matches', None,
3091 ('l', 'files-with-matches', None,
3092 _('print only filenames and revisions that match')),
3092 _('print only filenames and revisions that match')),
3093 ('n', 'line-number', None, _('print matching line numbers')),
3093 ('n', 'line-number', None, _('print matching line numbers')),
3094 ('r', 'rev', [],
3094 ('r', 'rev', [],
3095 _('only search files changed within revision range'), _('REV')),
3095 _('only search files changed within revision range'), _('REV')),
3096 ('u', 'user', None, _('list the author (long with -v)')),
3096 ('u', 'user', None, _('list the author (long with -v)')),
3097 ('d', 'date', None, _('list the date (short with -q)')),
3097 ('d', 'date', None, _('list the date (short with -q)')),
3098 ] + walkopts,
3098 ] + walkopts,
3099 _('[OPTION]... PATTERN [FILE]...'))
3099 _('[OPTION]... PATTERN [FILE]...'))
3100 def grep(ui, repo, pattern, *pats, **opts):
3100 def grep(ui, repo, pattern, *pats, **opts):
3101 """search for a pattern in specified files and revisions
3101 """search for a pattern in specified files and revisions
3102
3102
3103 Search revisions of files for a regular expression.
3103 Search revisions of files for a regular expression.
3104
3104
3105 This command behaves differently than Unix grep. It only accepts
3105 This command behaves differently than Unix grep. It only accepts
3106 Python/Perl regexps. It searches repository history, not the
3106 Python/Perl regexps. It searches repository history, not the
3107 working directory. It always prints the revision number in which a
3107 working directory. It always prints the revision number in which a
3108 match appears.
3108 match appears.
3109
3109
3110 By default, grep only prints output for the first revision of a
3110 By default, grep only prints output for the first revision of a
3111 file in which it finds a match. To get it to print every revision
3111 file in which it finds a match. To get it to print every revision
3112 that contains a change in match status ("-" for a match that
3112 that contains a change in match status ("-" for a match that
3113 becomes a non-match, or "+" for a non-match that becomes a match),
3113 becomes a non-match, or "+" for a non-match that becomes a match),
3114 use the --all flag.
3114 use the --all flag.
3115
3115
3116 Returns 0 if a match is found, 1 otherwise.
3116 Returns 0 if a match is found, 1 otherwise.
3117 """
3117 """
3118 reflags = re.M
3118 reflags = re.M
3119 if opts.get('ignore_case'):
3119 if opts.get('ignore_case'):
3120 reflags |= re.I
3120 reflags |= re.I
3121 try:
3121 try:
3122 regexp = util.compilere(pattern, reflags)
3122 regexp = util.compilere(pattern, reflags)
3123 except re.error, inst:
3123 except re.error, inst:
3124 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3124 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3125 return 1
3125 return 1
3126 sep, eol = ':', '\n'
3126 sep, eol = ':', '\n'
3127 if opts.get('print0'):
3127 if opts.get('print0'):
3128 sep = eol = '\0'
3128 sep = eol = '\0'
3129
3129
3130 getfile = util.lrucachefunc(repo.file)
3130 getfile = util.lrucachefunc(repo.file)
3131
3131
3132 def matchlines(body):
3132 def matchlines(body):
3133 begin = 0
3133 begin = 0
3134 linenum = 0
3134 linenum = 0
3135 while begin < len(body):
3135 while begin < len(body):
3136 match = regexp.search(body, begin)
3136 match = regexp.search(body, begin)
3137 if not match:
3137 if not match:
3138 break
3138 break
3139 mstart, mend = match.span()
3139 mstart, mend = match.span()
3140 linenum += body.count('\n', begin, mstart) + 1
3140 linenum += body.count('\n', begin, mstart) + 1
3141 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3141 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3142 begin = body.find('\n', mend) + 1 or len(body) + 1
3142 begin = body.find('\n', mend) + 1 or len(body) + 1
3143 lend = begin - 1
3143 lend = begin - 1
3144 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3144 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3145
3145
3146 class linestate(object):
3146 class linestate(object):
3147 def __init__(self, line, linenum, colstart, colend):
3147 def __init__(self, line, linenum, colstart, colend):
3148 self.line = line
3148 self.line = line
3149 self.linenum = linenum
3149 self.linenum = linenum
3150 self.colstart = colstart
3150 self.colstart = colstart
3151 self.colend = colend
3151 self.colend = colend
3152
3152
3153 def __hash__(self):
3153 def __hash__(self):
3154 return hash((self.linenum, self.line))
3154 return hash((self.linenum, self.line))
3155
3155
3156 def __eq__(self, other):
3156 def __eq__(self, other):
3157 return self.line == other.line
3157 return self.line == other.line
3158
3158
3159 matches = {}
3159 matches = {}
3160 copies = {}
3160 copies = {}
3161 def grepbody(fn, rev, body):
3161 def grepbody(fn, rev, body):
3162 matches[rev].setdefault(fn, [])
3162 matches[rev].setdefault(fn, [])
3163 m = matches[rev][fn]
3163 m = matches[rev][fn]
3164 for lnum, cstart, cend, line in matchlines(body):
3164 for lnum, cstart, cend, line in matchlines(body):
3165 s = linestate(line, lnum, cstart, cend)
3165 s = linestate(line, lnum, cstart, cend)
3166 m.append(s)
3166 m.append(s)
3167
3167
3168 def difflinestates(a, b):
3168 def difflinestates(a, b):
3169 sm = difflib.SequenceMatcher(None, a, b)
3169 sm = difflib.SequenceMatcher(None, a, b)
3170 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3170 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3171 if tag == 'insert':
3171 if tag == 'insert':
3172 for i in xrange(blo, bhi):
3172 for i in xrange(blo, bhi):
3173 yield ('+', b[i])
3173 yield ('+', b[i])
3174 elif tag == 'delete':
3174 elif tag == 'delete':
3175 for i in xrange(alo, ahi):
3175 for i in xrange(alo, ahi):
3176 yield ('-', a[i])
3176 yield ('-', a[i])
3177 elif tag == 'replace':
3177 elif tag == 'replace':
3178 for i in xrange(alo, ahi):
3178 for i in xrange(alo, ahi):
3179 yield ('-', a[i])
3179 yield ('-', a[i])
3180 for i in xrange(blo, bhi):
3180 for i in xrange(blo, bhi):
3181 yield ('+', b[i])
3181 yield ('+', b[i])
3182
3182
3183 def display(fn, ctx, pstates, states):
3183 def display(fn, ctx, pstates, states):
3184 rev = ctx.rev()
3184 rev = ctx.rev()
3185 datefunc = ui.quiet and util.shortdate or util.datestr
3185 datefunc = ui.quiet and util.shortdate or util.datestr
3186 found = False
3186 found = False
3187 filerevmatches = {}
3187 filerevmatches = {}
3188 def binary():
3188 def binary():
3189 flog = getfile(fn)
3189 flog = getfile(fn)
3190 return util.binary(flog.read(ctx.filenode(fn)))
3190 return util.binary(flog.read(ctx.filenode(fn)))
3191
3191
3192 if opts.get('all'):
3192 if opts.get('all'):
3193 iter = difflinestates(pstates, states)
3193 iter = difflinestates(pstates, states)
3194 else:
3194 else:
3195 iter = [('', l) for l in states]
3195 iter = [('', l) for l in states]
3196 for change, l in iter:
3196 for change, l in iter:
3197 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3197 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3198 before, match, after = None, None, None
3198 before, match, after = None, None, None
3199
3199
3200 if opts.get('line_number'):
3200 if opts.get('line_number'):
3201 cols.append((str(l.linenum), 'grep.linenumber'))
3201 cols.append((str(l.linenum), 'grep.linenumber'))
3202 if opts.get('all'):
3202 if opts.get('all'):
3203 cols.append((change, 'grep.change'))
3203 cols.append((change, 'grep.change'))
3204 if opts.get('user'):
3204 if opts.get('user'):
3205 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3205 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3206 if opts.get('date'):
3206 if opts.get('date'):
3207 cols.append((datefunc(ctx.date()), 'grep.date'))
3207 cols.append((datefunc(ctx.date()), 'grep.date'))
3208 if opts.get('files_with_matches'):
3208 if opts.get('files_with_matches'):
3209 c = (fn, rev)
3209 c = (fn, rev)
3210 if c in filerevmatches:
3210 if c in filerevmatches:
3211 continue
3211 continue
3212 filerevmatches[c] = 1
3212 filerevmatches[c] = 1
3213 else:
3213 else:
3214 before = l.line[:l.colstart]
3214 before = l.line[:l.colstart]
3215 match = l.line[l.colstart:l.colend]
3215 match = l.line[l.colstart:l.colend]
3216 after = l.line[l.colend:]
3216 after = l.line[l.colend:]
3217 for col, label in cols[:-1]:
3217 for col, label in cols[:-1]:
3218 ui.write(col, label=label)
3218 ui.write(col, label=label)
3219 ui.write(sep, label='grep.sep')
3219 ui.write(sep, label='grep.sep')
3220 ui.write(cols[-1][0], label=cols[-1][1])
3220 ui.write(cols[-1][0], label=cols[-1][1])
3221 if before is not None:
3221 if before is not None:
3222 ui.write(sep, label='grep.sep')
3222 ui.write(sep, label='grep.sep')
3223 if not opts.get('text') and binary():
3223 if not opts.get('text') and binary():
3224 ui.write(" Binary file matches")
3224 ui.write(" Binary file matches")
3225 else:
3225 else:
3226 ui.write(before)
3226 ui.write(before)
3227 ui.write(match, label='grep.match')
3227 ui.write(match, label='grep.match')
3228 ui.write(after)
3228 ui.write(after)
3229 ui.write(eol)
3229 ui.write(eol)
3230 found = True
3230 found = True
3231 return found
3231 return found
3232
3232
3233 skip = {}
3233 skip = {}
3234 revfiles = {}
3234 revfiles = {}
3235 matchfn = scmutil.match(repo[None], pats, opts)
3235 matchfn = scmutil.match(repo[None], pats, opts)
3236 found = False
3236 found = False
3237 follow = opts.get('follow')
3237 follow = opts.get('follow')
3238
3238
3239 def prep(ctx, fns):
3239 def prep(ctx, fns):
3240 rev = ctx.rev()
3240 rev = ctx.rev()
3241 pctx = ctx.p1()
3241 pctx = ctx.p1()
3242 parent = pctx.rev()
3242 parent = pctx.rev()
3243 matches.setdefault(rev, {})
3243 matches.setdefault(rev, {})
3244 matches.setdefault(parent, {})
3244 matches.setdefault(parent, {})
3245 files = revfiles.setdefault(rev, [])
3245 files = revfiles.setdefault(rev, [])
3246 for fn in fns:
3246 for fn in fns:
3247 flog = getfile(fn)
3247 flog = getfile(fn)
3248 try:
3248 try:
3249 fnode = ctx.filenode(fn)
3249 fnode = ctx.filenode(fn)
3250 except error.LookupError:
3250 except error.LookupError:
3251 continue
3251 continue
3252
3252
3253 copied = flog.renamed(fnode)
3253 copied = flog.renamed(fnode)
3254 copy = follow and copied and copied[0]
3254 copy = follow and copied and copied[0]
3255 if copy:
3255 if copy:
3256 copies.setdefault(rev, {})[fn] = copy
3256 copies.setdefault(rev, {})[fn] = copy
3257 if fn in skip:
3257 if fn in skip:
3258 if copy:
3258 if copy:
3259 skip[copy] = True
3259 skip[copy] = True
3260 continue
3260 continue
3261 files.append(fn)
3261 files.append(fn)
3262
3262
3263 if fn not in matches[rev]:
3263 if fn not in matches[rev]:
3264 grepbody(fn, rev, flog.read(fnode))
3264 grepbody(fn, rev, flog.read(fnode))
3265
3265
3266 pfn = copy or fn
3266 pfn = copy or fn
3267 if pfn not in matches[parent]:
3267 if pfn not in matches[parent]:
3268 try:
3268 try:
3269 fnode = pctx.filenode(pfn)
3269 fnode = pctx.filenode(pfn)
3270 grepbody(pfn, parent, flog.read(fnode))
3270 grepbody(pfn, parent, flog.read(fnode))
3271 except error.LookupError:
3271 except error.LookupError:
3272 pass
3272 pass
3273
3273
3274 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3274 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3275 rev = ctx.rev()
3275 rev = ctx.rev()
3276 parent = ctx.p1().rev()
3276 parent = ctx.p1().rev()
3277 for fn in sorted(revfiles.get(rev, [])):
3277 for fn in sorted(revfiles.get(rev, [])):
3278 states = matches[rev][fn]
3278 states = matches[rev][fn]
3279 copy = copies.get(rev, {}).get(fn)
3279 copy = copies.get(rev, {}).get(fn)
3280 if fn in skip:
3280 if fn in skip:
3281 if copy:
3281 if copy:
3282 skip[copy] = True
3282 skip[copy] = True
3283 continue
3283 continue
3284 pstates = matches.get(parent, {}).get(copy or fn, [])
3284 pstates = matches.get(parent, {}).get(copy or fn, [])
3285 if pstates or states:
3285 if pstates or states:
3286 r = display(fn, ctx, pstates, states)
3286 r = display(fn, ctx, pstates, states)
3287 found = found or r
3287 found = found or r
3288 if r and not opts.get('all'):
3288 if r and not opts.get('all'):
3289 skip[fn] = True
3289 skip[fn] = True
3290 if copy:
3290 if copy:
3291 skip[copy] = True
3291 skip[copy] = True
3292 del matches[rev]
3292 del matches[rev]
3293 del revfiles[rev]
3293 del revfiles[rev]
3294
3294
3295 return not found
3295 return not found
3296
3296
3297 @command('heads',
3297 @command('heads',
3298 [('r', 'rev', '',
3298 [('r', 'rev', '',
3299 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3299 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3300 ('t', 'topo', False, _('show topological heads only')),
3300 ('t', 'topo', False, _('show topological heads only')),
3301 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3301 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3302 ('c', 'closed', False, _('show normal and closed branch heads')),
3302 ('c', 'closed', False, _('show normal and closed branch heads')),
3303 ] + templateopts,
3303 ] + templateopts,
3304 _('[-ct] [-r STARTREV] [REV]...'))
3304 _('[-ct] [-r STARTREV] [REV]...'))
3305 def heads(ui, repo, *branchrevs, **opts):
3305 def heads(ui, repo, *branchrevs, **opts):
3306 """show current repository heads or show branch heads
3306 """show current repository heads or show branch heads
3307
3307
3308 With no arguments, show all repository branch heads.
3308 With no arguments, show all repository branch heads.
3309
3309
3310 Repository "heads" are changesets with no child changesets. They are
3310 Repository "heads" are changesets with no child changesets. They are
3311 where development generally takes place and are the usual targets
3311 where development generally takes place and are the usual targets
3312 for update and merge operations. Branch heads are changesets that have
3312 for update and merge operations. Branch heads are changesets that have
3313 no child changeset on the same branch.
3313 no child changeset on the same branch.
3314
3314
3315 If one or more REVs are given, only branch heads on the branches
3315 If one or more REVs are given, only branch heads on the branches
3316 associated with the specified changesets are shown. This means
3316 associated with the specified changesets are shown. This means
3317 that you can use :hg:`heads foo` to see the heads on a branch
3317 that you can use :hg:`heads foo` to see the heads on a branch
3318 named ``foo``.
3318 named ``foo``.
3319
3319
3320 If -c/--closed is specified, also show branch heads marked closed
3320 If -c/--closed is specified, also show branch heads marked closed
3321 (see :hg:`commit --close-branch`).
3321 (see :hg:`commit --close-branch`).
3322
3322
3323 If STARTREV is specified, only those heads that are descendants of
3323 If STARTREV is specified, only those heads that are descendants of
3324 STARTREV will be displayed.
3324 STARTREV will be displayed.
3325
3325
3326 If -t/--topo is specified, named branch mechanics will be ignored and only
3326 If -t/--topo is specified, named branch mechanics will be ignored and only
3327 changesets without children will be shown.
3327 changesets without children will be shown.
3328
3328
3329 Returns 0 if matching heads are found, 1 if not.
3329 Returns 0 if matching heads are found, 1 if not.
3330 """
3330 """
3331
3331
3332 start = None
3332 start = None
3333 if 'rev' in opts:
3333 if 'rev' in opts:
3334 start = scmutil.revsingle(repo, opts['rev'], None).node()
3334 start = scmutil.revsingle(repo, opts['rev'], None).node()
3335
3335
3336 if opts.get('topo'):
3336 if opts.get('topo'):
3337 heads = [repo[h] for h in repo.heads(start)]
3337 heads = [repo[h] for h in repo.heads(start)]
3338 else:
3338 else:
3339 heads = []
3339 heads = []
3340 for branch in repo.branchmap():
3340 for branch in repo.branchmap():
3341 heads += repo.branchheads(branch, start, opts.get('closed'))
3341 heads += repo.branchheads(branch, start, opts.get('closed'))
3342 heads = [repo[h] for h in heads]
3342 heads = [repo[h] for h in heads]
3343
3343
3344 if branchrevs:
3344 if branchrevs:
3345 branches = set(repo[br].branch() for br in branchrevs)
3345 branches = set(repo[br].branch() for br in branchrevs)
3346 heads = [h for h in heads if h.branch() in branches]
3346 heads = [h for h in heads if h.branch() in branches]
3347
3347
3348 if opts.get('active') and branchrevs:
3348 if opts.get('active') and branchrevs:
3349 dagheads = repo.heads(start)
3349 dagheads = repo.heads(start)
3350 heads = [h for h in heads if h.node() in dagheads]
3350 heads = [h for h in heads if h.node() in dagheads]
3351
3351
3352 if branchrevs:
3352 if branchrevs:
3353 haveheads = set(h.branch() for h in heads)
3353 haveheads = set(h.branch() for h in heads)
3354 if branches - haveheads:
3354 if branches - haveheads:
3355 headless = ', '.join(b for b in branches - haveheads)
3355 headless = ', '.join(b for b in branches - haveheads)
3356 msg = _('no open branch heads found on branches %s')
3356 msg = _('no open branch heads found on branches %s')
3357 if opts.get('rev'):
3357 if opts.get('rev'):
3358 msg += _(' (started at %s)') % opts['rev']
3358 msg += _(' (started at %s)') % opts['rev']
3359 ui.warn((msg + '\n') % headless)
3359 ui.warn((msg + '\n') % headless)
3360
3360
3361 if not heads:
3361 if not heads:
3362 return 1
3362 return 1
3363
3363
3364 heads = sorted(heads, key=lambda x: -x.rev())
3364 heads = sorted(heads, key=lambda x: -x.rev())
3365 displayer = cmdutil.show_changeset(ui, repo, opts)
3365 displayer = cmdutil.show_changeset(ui, repo, opts)
3366 for ctx in heads:
3366 for ctx in heads:
3367 displayer.show(ctx)
3367 displayer.show(ctx)
3368 displayer.close()
3368 displayer.close()
3369
3369
3370 @command('help',
3370 @command('help',
3371 [('e', 'extension', None, _('show only help for extensions')),
3371 [('e', 'extension', None, _('show only help for extensions')),
3372 ('c', 'command', None, _('show only help for commands')),
3372 ('c', 'command', None, _('show only help for commands')),
3373 ('k', 'keyword', '', _('show topics matching keyword')),
3373 ('k', 'keyword', '', _('show topics matching keyword')),
3374 ],
3374 ],
3375 _('[-ec] [TOPIC]'))
3375 _('[-ec] [TOPIC]'))
3376 def help_(ui, name=None, **opts):
3376 def help_(ui, name=None, **opts):
3377 """show help for a given topic or a help overview
3377 """show help for a given topic or a help overview
3378
3378
3379 With no arguments, print a list of commands with short help messages.
3379 With no arguments, print a list of commands with short help messages.
3380
3380
3381 Given a topic, extension, or command name, print help for that
3381 Given a topic, extension, or command name, print help for that
3382 topic.
3382 topic.
3383
3383
3384 Returns 0 if successful.
3384 Returns 0 if successful.
3385 """
3385 """
3386
3386
3387 textwidth = min(ui.termwidth(), 80) - 2
3387 textwidth = min(ui.termwidth(), 80) - 2
3388
3388
3389 keep = ui.verbose and ['verbose'] or []
3389 keep = ui.verbose and ['verbose'] or []
3390 text = help.help_(ui, name, **opts)
3390 text = help.help_(ui, name, **opts)
3391
3391
3392 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3392 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3393 if 'verbose' in pruned:
3393 if 'verbose' in pruned:
3394 keep.append('omitted')
3394 keep.append('omitted')
3395 else:
3395 else:
3396 keep.append('notomitted')
3396 keep.append('notomitted')
3397 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3397 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3398 ui.write(formatted)
3398 ui.write(formatted)
3399
3399
3400
3400
3401 @command('identify|id',
3401 @command('identify|id',
3402 [('r', 'rev', '',
3402 [('r', 'rev', '',
3403 _('identify the specified revision'), _('REV')),
3403 _('identify the specified revision'), _('REV')),
3404 ('n', 'num', None, _('show local revision number')),
3404 ('n', 'num', None, _('show local revision number')),
3405 ('i', 'id', None, _('show global revision id')),
3405 ('i', 'id', None, _('show global revision id')),
3406 ('b', 'branch', None, _('show branch')),
3406 ('b', 'branch', None, _('show branch')),
3407 ('t', 'tags', None, _('show tags')),
3407 ('t', 'tags', None, _('show tags')),
3408 ('B', 'bookmarks', None, _('show bookmarks')),
3408 ('B', 'bookmarks', None, _('show bookmarks')),
3409 ] + remoteopts,
3409 ] + remoteopts,
3410 _('[-nibtB] [-r REV] [SOURCE]'))
3410 _('[-nibtB] [-r REV] [SOURCE]'))
3411 def identify(ui, repo, source=None, rev=None,
3411 def identify(ui, repo, source=None, rev=None,
3412 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3412 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3413 """identify the working copy or specified revision
3413 """identify the working copy or specified revision
3414
3414
3415 Print a summary identifying the repository state at REV using one or
3415 Print a summary identifying the repository state at REV using one or
3416 two parent hash identifiers, followed by a "+" if the working
3416 two parent hash identifiers, followed by a "+" if the working
3417 directory has uncommitted changes, the branch name (if not default),
3417 directory has uncommitted changes, the branch name (if not default),
3418 a list of tags, and a list of bookmarks.
3418 a list of tags, and a list of bookmarks.
3419
3419
3420 When REV is not given, print a summary of the current state of the
3420 When REV is not given, print a summary of the current state of the
3421 repository.
3421 repository.
3422
3422
3423 Specifying a path to a repository root or Mercurial bundle will
3423 Specifying a path to a repository root or Mercurial bundle will
3424 cause lookup to operate on that repository/bundle.
3424 cause lookup to operate on that repository/bundle.
3425
3425
3426 .. container:: verbose
3426 .. container:: verbose
3427
3427
3428 Examples:
3428 Examples:
3429
3429
3430 - generate a build identifier for the working directory::
3430 - generate a build identifier for the working directory::
3431
3431
3432 hg id --id > build-id.dat
3432 hg id --id > build-id.dat
3433
3433
3434 - find the revision corresponding to a tag::
3434 - find the revision corresponding to a tag::
3435
3435
3436 hg id -n -r 1.3
3436 hg id -n -r 1.3
3437
3437
3438 - check the most recent revision of a remote repository::
3438 - check the most recent revision of a remote repository::
3439
3439
3440 hg id -r tip http://selenic.com/hg/
3440 hg id -r tip http://selenic.com/hg/
3441
3441
3442 Returns 0 if successful.
3442 Returns 0 if successful.
3443 """
3443 """
3444
3444
3445 if not repo and not source:
3445 if not repo and not source:
3446 raise util.Abort(_("there is no Mercurial repository here "
3446 raise util.Abort(_("there is no Mercurial repository here "
3447 "(.hg not found)"))
3447 "(.hg not found)"))
3448
3448
3449 hexfunc = ui.debugflag and hex or short
3449 hexfunc = ui.debugflag and hex or short
3450 default = not (num or id or branch or tags or bookmarks)
3450 default = not (num or id or branch or tags or bookmarks)
3451 output = []
3451 output = []
3452 revs = []
3452 revs = []
3453
3453
3454 if source:
3454 if source:
3455 source, branches = hg.parseurl(ui.expandpath(source))
3455 source, branches = hg.parseurl(ui.expandpath(source))
3456 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3456 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3457 repo = peer.local()
3457 repo = peer.local()
3458 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3458 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3459
3459
3460 if not repo:
3460 if not repo:
3461 if num or branch or tags:
3461 if num or branch or tags:
3462 raise util.Abort(
3462 raise util.Abort(
3463 _("can't query remote revision number, branch, or tags"))
3463 _("can't query remote revision number, branch, or tags"))
3464 if not rev and revs:
3464 if not rev and revs:
3465 rev = revs[0]
3465 rev = revs[0]
3466 if not rev:
3466 if not rev:
3467 rev = "tip"
3467 rev = "tip"
3468
3468
3469 remoterev = peer.lookup(rev)
3469 remoterev = peer.lookup(rev)
3470 if default or id:
3470 if default or id:
3471 output = [hexfunc(remoterev)]
3471 output = [hexfunc(remoterev)]
3472
3472
3473 def getbms():
3473 def getbms():
3474 bms = []
3474 bms = []
3475
3475
3476 if 'bookmarks' in peer.listkeys('namespaces'):
3476 if 'bookmarks' in peer.listkeys('namespaces'):
3477 hexremoterev = hex(remoterev)
3477 hexremoterev = hex(remoterev)
3478 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3478 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3479 if bmr == hexremoterev]
3479 if bmr == hexremoterev]
3480
3480
3481 return sorted(bms)
3481 return sorted(bms)
3482
3482
3483 if bookmarks:
3483 if bookmarks:
3484 output.extend(getbms())
3484 output.extend(getbms())
3485 elif default and not ui.quiet:
3485 elif default and not ui.quiet:
3486 # multiple bookmarks for a single parent separated by '/'
3486 # multiple bookmarks for a single parent separated by '/'
3487 bm = '/'.join(getbms())
3487 bm = '/'.join(getbms())
3488 if bm:
3488 if bm:
3489 output.append(bm)
3489 output.append(bm)
3490 else:
3490 else:
3491 if not rev:
3491 if not rev:
3492 ctx = repo[None]
3492 ctx = repo[None]
3493 parents = ctx.parents()
3493 parents = ctx.parents()
3494 changed = ""
3494 changed = ""
3495 if default or id or num:
3495 if default or id or num:
3496 if (util.any(repo.status())
3496 if (util.any(repo.status())
3497 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3497 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3498 changed = '+'
3498 changed = '+'
3499 if default or id:
3499 if default or id:
3500 output = ["%s%s" %
3500 output = ["%s%s" %
3501 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3501 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3502 if num:
3502 if num:
3503 output.append("%s%s" %
3503 output.append("%s%s" %
3504 ('+'.join([str(p.rev()) for p in parents]), changed))
3504 ('+'.join([str(p.rev()) for p in parents]), changed))
3505 else:
3505 else:
3506 ctx = scmutil.revsingle(repo, rev)
3506 ctx = scmutil.revsingle(repo, rev)
3507 if default or id:
3507 if default or id:
3508 output = [hexfunc(ctx.node())]
3508 output = [hexfunc(ctx.node())]
3509 if num:
3509 if num:
3510 output.append(str(ctx.rev()))
3510 output.append(str(ctx.rev()))
3511
3511
3512 if default and not ui.quiet:
3512 if default and not ui.quiet:
3513 b = ctx.branch()
3513 b = ctx.branch()
3514 if b != 'default':
3514 if b != 'default':
3515 output.append("(%s)" % b)
3515 output.append("(%s)" % b)
3516
3516
3517 # multiple tags for a single parent separated by '/'
3517 # multiple tags for a single parent separated by '/'
3518 t = '/'.join(ctx.tags())
3518 t = '/'.join(ctx.tags())
3519 if t:
3519 if t:
3520 output.append(t)
3520 output.append(t)
3521
3521
3522 # multiple bookmarks for a single parent separated by '/'
3522 # multiple bookmarks for a single parent separated by '/'
3523 bm = '/'.join(ctx.bookmarks())
3523 bm = '/'.join(ctx.bookmarks())
3524 if bm:
3524 if bm:
3525 output.append(bm)
3525 output.append(bm)
3526 else:
3526 else:
3527 if branch:
3527 if branch:
3528 output.append(ctx.branch())
3528 output.append(ctx.branch())
3529
3529
3530 if tags:
3530 if tags:
3531 output.extend(ctx.tags())
3531 output.extend(ctx.tags())
3532
3532
3533 if bookmarks:
3533 if bookmarks:
3534 output.extend(ctx.bookmarks())
3534 output.extend(ctx.bookmarks())
3535
3535
3536 ui.write("%s\n" % ' '.join(output))
3536 ui.write("%s\n" % ' '.join(output))
3537
3537
3538 @command('import|patch',
3538 @command('import|patch',
3539 [('p', 'strip', 1,
3539 [('p', 'strip', 1,
3540 _('directory strip option for patch. This has the same '
3540 _('directory strip option for patch. This has the same '
3541 'meaning as the corresponding patch option'), _('NUM')),
3541 'meaning as the corresponding patch option'), _('NUM')),
3542 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3542 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3543 ('e', 'edit', False, _('invoke editor on commit messages')),
3543 ('e', 'edit', False, _('invoke editor on commit messages')),
3544 ('f', 'force', None,
3544 ('f', 'force', None,
3545 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3545 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
3546 ('', 'no-commit', None,
3546 ('', 'no-commit', None,
3547 _("don't commit, just update the working directory")),
3547 _("don't commit, just update the working directory")),
3548 ('', 'bypass', None,
3548 ('', 'bypass', None,
3549 _("apply patch without touching the working directory")),
3549 _("apply patch without touching the working directory")),
3550 ('', 'exact', None,
3550 ('', 'exact', None,
3551 _('apply patch to the nodes from which it was generated')),
3551 _('apply patch to the nodes from which it was generated')),
3552 ('', 'import-branch', None,
3552 ('', 'import-branch', None,
3553 _('use any branch information in patch (implied by --exact)'))] +
3553 _('use any branch information in patch (implied by --exact)'))] +
3554 commitopts + commitopts2 + similarityopts,
3554 commitopts + commitopts2 + similarityopts,
3555 _('[OPTION]... PATCH...'))
3555 _('[OPTION]... PATCH...'))
3556 def import_(ui, repo, patch1=None, *patches, **opts):
3556 def import_(ui, repo, patch1=None, *patches, **opts):
3557 """import an ordered set of patches
3557 """import an ordered set of patches
3558
3558
3559 Import a list of patches and commit them individually (unless
3559 Import a list of patches and commit them individually (unless
3560 --no-commit is specified).
3560 --no-commit is specified).
3561
3561
3562 Because import first applies changes to the working directory,
3562 Because import first applies changes to the working directory,
3563 import will abort if there are outstanding changes.
3563 import will abort if there are outstanding changes.
3564
3564
3565 You can import a patch straight from a mail message. Even patches
3565 You can import a patch straight from a mail message. Even patches
3566 as attachments work (to use the body part, it must have type
3566 as attachments work (to use the body part, it must have type
3567 text/plain or text/x-patch). From and Subject headers of email
3567 text/plain or text/x-patch). From and Subject headers of email
3568 message are used as default committer and commit message. All
3568 message are used as default committer and commit message. All
3569 text/plain body parts before first diff are added to commit
3569 text/plain body parts before first diff are added to commit
3570 message.
3570 message.
3571
3571
3572 If the imported patch was generated by :hg:`export`, user and
3572 If the imported patch was generated by :hg:`export`, user and
3573 description from patch override values from message headers and
3573 description from patch override values from message headers and
3574 body. Values given on command line with -m/--message and -u/--user
3574 body. Values given on command line with -m/--message and -u/--user
3575 override these.
3575 override these.
3576
3576
3577 If --exact is specified, import will set the working directory to
3577 If --exact is specified, import will set the working directory to
3578 the parent of each patch before applying it, and will abort if the
3578 the parent of each patch before applying it, and will abort if the
3579 resulting changeset has a different ID than the one recorded in
3579 resulting changeset has a different ID than the one recorded in
3580 the patch. This may happen due to character set problems or other
3580 the patch. This may happen due to character set problems or other
3581 deficiencies in the text patch format.
3581 deficiencies in the text patch format.
3582
3582
3583 Use --bypass to apply and commit patches directly to the
3583 Use --bypass to apply and commit patches directly to the
3584 repository, not touching the working directory. Without --exact,
3584 repository, not touching the working directory. Without --exact,
3585 patches will be applied on top of the working directory parent
3585 patches will be applied on top of the working directory parent
3586 revision.
3586 revision.
3587
3587
3588 With -s/--similarity, hg will attempt to discover renames and
3588 With -s/--similarity, hg will attempt to discover renames and
3589 copies in the patch in the same way as :hg:`addremove`.
3589 copies in the patch in the same way as :hg:`addremove`.
3590
3590
3591 To read a patch from standard input, use "-" as the patch name. If
3591 To read a patch from standard input, use "-" as the patch name. If
3592 a URL is specified, the patch will be downloaded from it.
3592 a URL is specified, the patch will be downloaded from it.
3593 See :hg:`help dates` for a list of formats valid for -d/--date.
3593 See :hg:`help dates` for a list of formats valid for -d/--date.
3594
3594
3595 .. container:: verbose
3595 .. container:: verbose
3596
3596
3597 Examples:
3597 Examples:
3598
3598
3599 - import a traditional patch from a website and detect renames::
3599 - import a traditional patch from a website and detect renames::
3600
3600
3601 hg import -s 80 http://example.com/bugfix.patch
3601 hg import -s 80 http://example.com/bugfix.patch
3602
3602
3603 - import a changeset from an hgweb server::
3603 - import a changeset from an hgweb server::
3604
3604
3605 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3605 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3606
3606
3607 - import all the patches in an Unix-style mbox::
3607 - import all the patches in an Unix-style mbox::
3608
3608
3609 hg import incoming-patches.mbox
3609 hg import incoming-patches.mbox
3610
3610
3611 - attempt to exactly restore an exported changeset (not always
3611 - attempt to exactly restore an exported changeset (not always
3612 possible)::
3612 possible)::
3613
3613
3614 hg import --exact proposed-fix.patch
3614 hg import --exact proposed-fix.patch
3615
3615
3616 Returns 0 on success.
3616 Returns 0 on success.
3617 """
3617 """
3618
3618
3619 if not patch1:
3619 if not patch1:
3620 raise util.Abort(_('need at least one patch to import'))
3620 raise util.Abort(_('need at least one patch to import'))
3621
3621
3622 patches = (patch1,) + patches
3622 patches = (patch1,) + patches
3623
3623
3624 date = opts.get('date')
3624 date = opts.get('date')
3625 if date:
3625 if date:
3626 opts['date'] = util.parsedate(date)
3626 opts['date'] = util.parsedate(date)
3627
3627
3628 editor = cmdutil.commiteditor
3628 editor = cmdutil.commiteditor
3629 if opts.get('edit'):
3629 if opts.get('edit'):
3630 editor = cmdutil.commitforceeditor
3630 editor = cmdutil.commitforceeditor
3631
3631
3632 update = not opts.get('bypass')
3632 update = not opts.get('bypass')
3633 if not update and opts.get('no_commit'):
3633 if not update and opts.get('no_commit'):
3634 raise util.Abort(_('cannot use --no-commit with --bypass'))
3634 raise util.Abort(_('cannot use --no-commit with --bypass'))
3635 try:
3635 try:
3636 sim = float(opts.get('similarity') or 0)
3636 sim = float(opts.get('similarity') or 0)
3637 except ValueError:
3637 except ValueError:
3638 raise util.Abort(_('similarity must be a number'))
3638 raise util.Abort(_('similarity must be a number'))
3639 if sim < 0 or sim > 100:
3639 if sim < 0 or sim > 100:
3640 raise util.Abort(_('similarity must be between 0 and 100'))
3640 raise util.Abort(_('similarity must be between 0 and 100'))
3641 if sim and not update:
3641 if sim and not update:
3642 raise util.Abort(_('cannot use --similarity with --bypass'))
3642 raise util.Abort(_('cannot use --similarity with --bypass'))
3643
3643
3644 if (opts.get('exact') or not opts.get('force')) and update:
3644 if (opts.get('exact') or not opts.get('force')) and update:
3645 cmdutil.bailifchanged(repo)
3645 cmdutil.bailifchanged(repo)
3646
3646
3647 base = opts["base"]
3647 base = opts["base"]
3648 strip = opts["strip"]
3648 strip = opts["strip"]
3649 wlock = lock = tr = None
3649 wlock = lock = tr = None
3650 msgs = []
3650 msgs = []
3651
3651
3652 def tryone(ui, hunk, parents):
3652 def tryone(ui, hunk, parents):
3653 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3653 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3654 patch.extract(ui, hunk)
3654 patch.extract(ui, hunk)
3655
3655
3656 if not tmpname:
3656 if not tmpname:
3657 return (None, None)
3657 return (None, None)
3658 msg = _('applied to working directory')
3658 msg = _('applied to working directory')
3659
3659
3660 try:
3660 try:
3661 cmdline_message = cmdutil.logmessage(ui, opts)
3661 cmdline_message = cmdutil.logmessage(ui, opts)
3662 if cmdline_message:
3662 if cmdline_message:
3663 # pickup the cmdline msg
3663 # pickup the cmdline msg
3664 message = cmdline_message
3664 message = cmdline_message
3665 elif message:
3665 elif message:
3666 # pickup the patch msg
3666 # pickup the patch msg
3667 message = message.strip()
3667 message = message.strip()
3668 else:
3668 else:
3669 # launch the editor
3669 # launch the editor
3670 message = None
3670 message = None
3671 ui.debug('message:\n%s\n' % message)
3671 ui.debug('message:\n%s\n' % message)
3672
3672
3673 if len(parents) == 1:
3673 if len(parents) == 1:
3674 parents.append(repo[nullid])
3674 parents.append(repo[nullid])
3675 if opts.get('exact'):
3675 if opts.get('exact'):
3676 if not nodeid or not p1:
3676 if not nodeid or not p1:
3677 raise util.Abort(_('not a Mercurial patch'))
3677 raise util.Abort(_('not a Mercurial patch'))
3678 p1 = repo[p1]
3678 p1 = repo[p1]
3679 p2 = repo[p2 or nullid]
3679 p2 = repo[p2 or nullid]
3680 elif p2:
3680 elif p2:
3681 try:
3681 try:
3682 p1 = repo[p1]
3682 p1 = repo[p1]
3683 p2 = repo[p2]
3683 p2 = repo[p2]
3684 # Without any options, consider p2 only if the
3684 # Without any options, consider p2 only if the
3685 # patch is being applied on top of the recorded
3685 # patch is being applied on top of the recorded
3686 # first parent.
3686 # first parent.
3687 if p1 != parents[0]:
3687 if p1 != parents[0]:
3688 p1 = parents[0]
3688 p1 = parents[0]
3689 p2 = repo[nullid]
3689 p2 = repo[nullid]
3690 except error.RepoError:
3690 except error.RepoError:
3691 p1, p2 = parents
3691 p1, p2 = parents
3692 else:
3692 else:
3693 p1, p2 = parents
3693 p1, p2 = parents
3694
3694
3695 n = None
3695 n = None
3696 if update:
3696 if update:
3697 if p1 != parents[0]:
3697 if p1 != parents[0]:
3698 hg.clean(repo, p1.node())
3698 hg.clean(repo, p1.node())
3699 if p2 != parents[1]:
3699 if p2 != parents[1]:
3700 repo.setparents(p1.node(), p2.node())
3700 repo.setparents(p1.node(), p2.node())
3701
3701
3702 if opts.get('exact') or opts.get('import_branch'):
3702 if opts.get('exact') or opts.get('import_branch'):
3703 repo.dirstate.setbranch(branch or 'default')
3703 repo.dirstate.setbranch(branch or 'default')
3704
3704
3705 files = set()
3705 files = set()
3706 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3706 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3707 eolmode=None, similarity=sim / 100.0)
3707 eolmode=None, similarity=sim / 100.0)
3708 files = list(files)
3708 files = list(files)
3709 if opts.get('no_commit'):
3709 if opts.get('no_commit'):
3710 if message:
3710 if message:
3711 msgs.append(message)
3711 msgs.append(message)
3712 else:
3712 else:
3713 if opts.get('exact') or p2:
3713 if opts.get('exact') or p2:
3714 # If you got here, you either use --force and know what
3714 # If you got here, you either use --force and know what
3715 # you are doing or used --exact or a merge patch while
3715 # you are doing or used --exact or a merge patch while
3716 # being updated to its first parent.
3716 # being updated to its first parent.
3717 m = None
3717 m = None
3718 else:
3718 else:
3719 m = scmutil.matchfiles(repo, files or [])
3719 m = scmutil.matchfiles(repo, files or [])
3720 n = repo.commit(message, opts.get('user') or user,
3720 n = repo.commit(message, opts.get('user') or user,
3721 opts.get('date') or date, match=m,
3721 opts.get('date') or date, match=m,
3722 editor=editor)
3722 editor=editor)
3723 else:
3723 else:
3724 if opts.get('exact') or opts.get('import_branch'):
3724 if opts.get('exact') or opts.get('import_branch'):
3725 branch = branch or 'default'
3725 branch = branch or 'default'
3726 else:
3726 else:
3727 branch = p1.branch()
3727 branch = p1.branch()
3728 store = patch.filestore()
3728 store = patch.filestore()
3729 try:
3729 try:
3730 files = set()
3730 files = set()
3731 try:
3731 try:
3732 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3732 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3733 files, eolmode=None)
3733 files, eolmode=None)
3734 except patch.PatchError, e:
3734 except patch.PatchError, e:
3735 raise util.Abort(str(e))
3735 raise util.Abort(str(e))
3736 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3736 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3737 message,
3737 message,
3738 opts.get('user') or user,
3738 opts.get('user') or user,
3739 opts.get('date') or date,
3739 opts.get('date') or date,
3740 branch, files, store,
3740 branch, files, store,
3741 editor=cmdutil.commiteditor)
3741 editor=cmdutil.commiteditor)
3742 repo.savecommitmessage(memctx.description())
3742 repo.savecommitmessage(memctx.description())
3743 n = memctx.commit()
3743 n = memctx.commit()
3744 finally:
3744 finally:
3745 store.close()
3745 store.close()
3746 if opts.get('exact') and hex(n) != nodeid:
3746 if opts.get('exact') and hex(n) != nodeid:
3747 raise util.Abort(_('patch is damaged or loses information'))
3747 raise util.Abort(_('patch is damaged or loses information'))
3748 if n:
3748 if n:
3749 # i18n: refers to a short changeset id
3749 # i18n: refers to a short changeset id
3750 msg = _('created %s') % short(n)
3750 msg = _('created %s') % short(n)
3751 return (msg, n)
3751 return (msg, n)
3752 finally:
3752 finally:
3753 os.unlink(tmpname)
3753 os.unlink(tmpname)
3754
3754
3755 try:
3755 try:
3756 try:
3756 try:
3757 wlock = repo.wlock()
3757 wlock = repo.wlock()
3758 if not opts.get('no_commit'):
3758 if not opts.get('no_commit'):
3759 lock = repo.lock()
3759 lock = repo.lock()
3760 tr = repo.transaction('import')
3760 tr = repo.transaction('import')
3761 parents = repo.parents()
3761 parents = repo.parents()
3762 for patchurl in patches:
3762 for patchurl in patches:
3763 if patchurl == '-':
3763 if patchurl == '-':
3764 ui.status(_('applying patch from stdin\n'))
3764 ui.status(_('applying patch from stdin\n'))
3765 patchfile = ui.fin
3765 patchfile = ui.fin
3766 patchurl = 'stdin' # for error message
3766 patchurl = 'stdin' # for error message
3767 else:
3767 else:
3768 patchurl = os.path.join(base, patchurl)
3768 patchurl = os.path.join(base, patchurl)
3769 ui.status(_('applying %s\n') % patchurl)
3769 ui.status(_('applying %s\n') % patchurl)
3770 patchfile = hg.openpath(ui, patchurl)
3770 patchfile = hg.openpath(ui, patchurl)
3771
3771
3772 haspatch = False
3772 haspatch = False
3773 for hunk in patch.split(patchfile):
3773 for hunk in patch.split(patchfile):
3774 (msg, node) = tryone(ui, hunk, parents)
3774 (msg, node) = tryone(ui, hunk, parents)
3775 if msg:
3775 if msg:
3776 haspatch = True
3776 haspatch = True
3777 ui.note(msg + '\n')
3777 ui.note(msg + '\n')
3778 if update or opts.get('exact'):
3778 if update or opts.get('exact'):
3779 parents = repo.parents()
3779 parents = repo.parents()
3780 else:
3780 else:
3781 parents = [repo[node]]
3781 parents = [repo[node]]
3782
3782
3783 if not haspatch:
3783 if not haspatch:
3784 raise util.Abort(_('%s: no diffs found') % patchurl)
3784 raise util.Abort(_('%s: no diffs found') % patchurl)
3785
3785
3786 if tr:
3786 if tr:
3787 tr.close()
3787 tr.close()
3788 if msgs:
3788 if msgs:
3789 repo.savecommitmessage('\n* * *\n'.join(msgs))
3789 repo.savecommitmessage('\n* * *\n'.join(msgs))
3790 except: # re-raises
3790 except: # re-raises
3791 # wlock.release() indirectly calls dirstate.write(): since
3791 # wlock.release() indirectly calls dirstate.write(): since
3792 # we're crashing, we do not want to change the working dir
3792 # we're crashing, we do not want to change the working dir
3793 # parent after all, so make sure it writes nothing
3793 # parent after all, so make sure it writes nothing
3794 repo.dirstate.invalidate()
3794 repo.dirstate.invalidate()
3795 raise
3795 raise
3796 finally:
3796 finally:
3797 if tr:
3797 if tr:
3798 tr.release()
3798 tr.release()
3799 release(lock, wlock)
3799 release(lock, wlock)
3800
3800
3801 @command('incoming|in',
3801 @command('incoming|in',
3802 [('f', 'force', None,
3802 [('f', 'force', None,
3803 _('run even if remote repository is unrelated')),
3803 _('run even if remote repository is unrelated')),
3804 ('n', 'newest-first', None, _('show newest record first')),
3804 ('n', 'newest-first', None, _('show newest record first')),
3805 ('', 'bundle', '',
3805 ('', 'bundle', '',
3806 _('file to store the bundles into'), _('FILE')),
3806 _('file to store the bundles into'), _('FILE')),
3807 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3807 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3808 ('B', 'bookmarks', False, _("compare bookmarks")),
3808 ('B', 'bookmarks', False, _("compare bookmarks")),
3809 ('b', 'branch', [],
3809 ('b', 'branch', [],
3810 _('a specific branch you would like to pull'), _('BRANCH')),
3810 _('a specific branch you would like to pull'), _('BRANCH')),
3811 ] + logopts + remoteopts + subrepoopts,
3811 ] + logopts + remoteopts + subrepoopts,
3812 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3812 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3813 def incoming(ui, repo, source="default", **opts):
3813 def incoming(ui, repo, source="default", **opts):
3814 """show new changesets found in source
3814 """show new changesets found in source
3815
3815
3816 Show new changesets found in the specified path/URL or the default
3816 Show new changesets found in the specified path/URL or the default
3817 pull location. These are the changesets that would have been pulled
3817 pull location. These are the changesets that would have been pulled
3818 if a pull at the time you issued this command.
3818 if a pull at the time you issued this command.
3819
3819
3820 For remote repository, using --bundle avoids downloading the
3820 For remote repository, using --bundle avoids downloading the
3821 changesets twice if the incoming is followed by a pull.
3821 changesets twice if the incoming is followed by a pull.
3822
3822
3823 See pull for valid source format details.
3823 See pull for valid source format details.
3824
3824
3825 Returns 0 if there are incoming changes, 1 otherwise.
3825 Returns 0 if there are incoming changes, 1 otherwise.
3826 """
3826 """
3827 if opts.get('graph'):
3827 if opts.get('graph'):
3828 cmdutil.checkunsupportedgraphflags([], opts)
3828 cmdutil.checkunsupportedgraphflags([], opts)
3829 def display(other, chlist, displayer):
3829 def display(other, chlist, displayer):
3830 revdag = cmdutil.graphrevs(other, chlist, opts)
3830 revdag = cmdutil.graphrevs(other, chlist, opts)
3831 showparents = [ctx.node() for ctx in repo[None].parents()]
3831 showparents = [ctx.node() for ctx in repo[None].parents()]
3832 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3832 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3833 graphmod.asciiedges)
3833 graphmod.asciiedges)
3834
3834
3835 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3835 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3836 return 0
3836 return 0
3837
3837
3838 if opts.get('bundle') and opts.get('subrepos'):
3838 if opts.get('bundle') and opts.get('subrepos'):
3839 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3839 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3840
3840
3841 if opts.get('bookmarks'):
3841 if opts.get('bookmarks'):
3842 source, branches = hg.parseurl(ui.expandpath(source),
3842 source, branches = hg.parseurl(ui.expandpath(source),
3843 opts.get('branch'))
3843 opts.get('branch'))
3844 other = hg.peer(repo, opts, source)
3844 other = hg.peer(repo, opts, source)
3845 if 'bookmarks' not in other.listkeys('namespaces'):
3845 if 'bookmarks' not in other.listkeys('namespaces'):
3846 ui.warn(_("remote doesn't support bookmarks\n"))
3846 ui.warn(_("remote doesn't support bookmarks\n"))
3847 return 0
3847 return 0
3848 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3848 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3849 return bookmarks.diff(ui, repo, other)
3849 return bookmarks.diff(ui, repo, other)
3850
3850
3851 repo._subtoppath = ui.expandpath(source)
3851 repo._subtoppath = ui.expandpath(source)
3852 try:
3852 try:
3853 return hg.incoming(ui, repo, source, opts)
3853 return hg.incoming(ui, repo, source, opts)
3854 finally:
3854 finally:
3855 del repo._subtoppath
3855 del repo._subtoppath
3856
3856
3857
3857
3858 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3858 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3859 def init(ui, dest=".", **opts):
3859 def init(ui, dest=".", **opts):
3860 """create a new repository in the given directory
3860 """create a new repository in the given directory
3861
3861
3862 Initialize a new repository in the given directory. If the given
3862 Initialize a new repository in the given directory. If the given
3863 directory does not exist, it will be created.
3863 directory does not exist, it will be created.
3864
3864
3865 If no directory is given, the current directory is used.
3865 If no directory is given, the current directory is used.
3866
3866
3867 It is possible to specify an ``ssh://`` URL as the destination.
3867 It is possible to specify an ``ssh://`` URL as the destination.
3868 See :hg:`help urls` for more information.
3868 See :hg:`help urls` for more information.
3869
3869
3870 Returns 0 on success.
3870 Returns 0 on success.
3871 """
3871 """
3872 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3872 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3873
3873
3874 @command('locate',
3874 @command('locate',
3875 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3875 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3876 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3876 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3877 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3877 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3878 ] + walkopts,
3878 ] + walkopts,
3879 _('[OPTION]... [PATTERN]...'))
3879 _('[OPTION]... [PATTERN]...'))
3880 def locate(ui, repo, *pats, **opts):
3880 def locate(ui, repo, *pats, **opts):
3881 """locate files matching specific patterns
3881 """locate files matching specific patterns
3882
3882
3883 Print files under Mercurial control in the working directory whose
3883 Print files under Mercurial control in the working directory whose
3884 names match the given patterns.
3884 names match the given patterns.
3885
3885
3886 By default, this command searches all directories in the working
3886 By default, this command searches all directories in the working
3887 directory. To search just the current directory and its
3887 directory. To search just the current directory and its
3888 subdirectories, use "--include .".
3888 subdirectories, use "--include .".
3889
3889
3890 If no patterns are given to match, this command prints the names
3890 If no patterns are given to match, this command prints the names
3891 of all files under Mercurial control in the working directory.
3891 of all files under Mercurial control in the working directory.
3892
3892
3893 If you want to feed the output of this command into the "xargs"
3893 If you want to feed the output of this command into the "xargs"
3894 command, use the -0 option to both this command and "xargs". This
3894 command, use the -0 option to both this command and "xargs". This
3895 will avoid the problem of "xargs" treating single filenames that
3895 will avoid the problem of "xargs" treating single filenames that
3896 contain whitespace as multiple filenames.
3896 contain whitespace as multiple filenames.
3897
3897
3898 Returns 0 if a match is found, 1 otherwise.
3898 Returns 0 if a match is found, 1 otherwise.
3899 """
3899 """
3900 end = opts.get('print0') and '\0' or '\n'
3900 end = opts.get('print0') and '\0' or '\n'
3901 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3901 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3902
3902
3903 ret = 1
3903 ret = 1
3904 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3904 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3905 m.bad = lambda x, y: False
3905 m.bad = lambda x, y: False
3906 for abs in repo[rev].walk(m):
3906 for abs in repo[rev].walk(m):
3907 if not rev and abs not in repo.dirstate:
3907 if not rev and abs not in repo.dirstate:
3908 continue
3908 continue
3909 if opts.get('fullpath'):
3909 if opts.get('fullpath'):
3910 ui.write(repo.wjoin(abs), end)
3910 ui.write(repo.wjoin(abs), end)
3911 else:
3911 else:
3912 ui.write(((pats and m.rel(abs)) or abs), end)
3912 ui.write(((pats and m.rel(abs)) or abs), end)
3913 ret = 0
3913 ret = 0
3914
3914
3915 return ret
3915 return ret
3916
3916
3917 @command('^log|history',
3917 @command('^log|history',
3918 [('f', 'follow', None,
3918 [('f', 'follow', None,
3919 _('follow changeset history, or file history across copies and renames')),
3919 _('follow changeset history, or file history across copies and renames')),
3920 ('', 'follow-first', None,
3920 ('', 'follow-first', None,
3921 _('only follow the first parent of merge changesets (DEPRECATED)')),
3921 _('only follow the first parent of merge changesets (DEPRECATED)')),
3922 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3922 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3923 ('C', 'copies', None, _('show copied files')),
3923 ('C', 'copies', None, _('show copied files')),
3924 ('k', 'keyword', [],
3924 ('k', 'keyword', [],
3925 _('do case-insensitive search for a given text'), _('TEXT')),
3925 _('do case-insensitive search for a given text'), _('TEXT')),
3926 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3926 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3927 ('', 'removed', None, _('include revisions where files were removed')),
3927 ('', 'removed', None, _('include revisions where files were removed')),
3928 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3928 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3929 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3929 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3930 ('', 'only-branch', [],
3930 ('', 'only-branch', [],
3931 _('show only changesets within the given named branch (DEPRECATED)'),
3931 _('show only changesets within the given named branch (DEPRECATED)'),
3932 _('BRANCH')),
3932 _('BRANCH')),
3933 ('b', 'branch', [],
3933 ('b', 'branch', [],
3934 _('show changesets within the given named branch'), _('BRANCH')),
3934 _('show changesets within the given named branch'), _('BRANCH')),
3935 ('P', 'prune', [],
3935 ('P', 'prune', [],
3936 _('do not display revision or any of its ancestors'), _('REV')),
3936 _('do not display revision or any of its ancestors'), _('REV')),
3937 ] + logopts + walkopts,
3937 ] + logopts + walkopts,
3938 _('[OPTION]... [FILE]'))
3938 _('[OPTION]... [FILE]'))
3939 def log(ui, repo, *pats, **opts):
3939 def log(ui, repo, *pats, **opts):
3940 """show revision history of entire repository or files
3940 """show revision history of entire repository or files
3941
3941
3942 Print the revision history of the specified files or the entire
3942 Print the revision history of the specified files or the entire
3943 project.
3943 project.
3944
3944
3945 If no revision range is specified, the default is ``tip:0`` unless
3945 If no revision range is specified, the default is ``tip:0`` unless
3946 --follow is set, in which case the working directory parent is
3946 --follow is set, in which case the working directory parent is
3947 used as the starting revision.
3947 used as the starting revision.
3948
3948
3949 File history is shown without following rename or copy history of
3949 File history is shown without following rename or copy history of
3950 files. Use -f/--follow with a filename to follow history across
3950 files. Use -f/--follow with a filename to follow history across
3951 renames and copies. --follow without a filename will only show
3951 renames and copies. --follow without a filename will only show
3952 ancestors or descendants of the starting revision.
3952 ancestors or descendants of the starting revision.
3953
3953
3954 By default this command prints revision number and changeset id,
3954 By default this command prints revision number and changeset id,
3955 tags, non-trivial parents, user, date and time, and a summary for
3955 tags, non-trivial parents, user, date and time, and a summary for
3956 each commit. When the -v/--verbose switch is used, the list of
3956 each commit. When the -v/--verbose switch is used, the list of
3957 changed files and full commit message are shown.
3957 changed files and full commit message are shown.
3958
3958
3959 .. note::
3959 .. note::
3960 log -p/--patch may generate unexpected diff output for merge
3960 log -p/--patch may generate unexpected diff output for merge
3961 changesets, as it will only compare the merge changeset against
3961 changesets, as it will only compare the merge changeset against
3962 its first parent. Also, only files different from BOTH parents
3962 its first parent. Also, only files different from BOTH parents
3963 will appear in files:.
3963 will appear in files:.
3964
3964
3965 .. note::
3965 .. note::
3966 for performance reasons, log FILE may omit duplicate changes
3966 for performance reasons, log FILE may omit duplicate changes
3967 made on branches and will not show deletions. To see all
3967 made on branches and will not show deletions. To see all
3968 changes including duplicates and deletions, use the --removed
3968 changes including duplicates and deletions, use the --removed
3969 switch.
3969 switch.
3970
3970
3971 .. container:: verbose
3971 .. container:: verbose
3972
3972
3973 Some examples:
3973 Some examples:
3974
3974
3975 - changesets with full descriptions and file lists::
3975 - changesets with full descriptions and file lists::
3976
3976
3977 hg log -v
3977 hg log -v
3978
3978
3979 - changesets ancestral to the working directory::
3979 - changesets ancestral to the working directory::
3980
3980
3981 hg log -f
3981 hg log -f
3982
3982
3983 - last 10 commits on the current branch::
3983 - last 10 commits on the current branch::
3984
3984
3985 hg log -l 10 -b .
3985 hg log -l 10 -b .
3986
3986
3987 - changesets showing all modifications of a file, including removals::
3987 - changesets showing all modifications of a file, including removals::
3988
3988
3989 hg log --removed file.c
3989 hg log --removed file.c
3990
3990
3991 - all changesets that touch a directory, with diffs, excluding merges::
3991 - all changesets that touch a directory, with diffs, excluding merges::
3992
3992
3993 hg log -Mp lib/
3993 hg log -Mp lib/
3994
3994
3995 - all revision numbers that match a keyword::
3995 - all revision numbers that match a keyword::
3996
3996
3997 hg log -k bug --template "{rev}\\n"
3997 hg log -k bug --template "{rev}\\n"
3998
3998
3999 - check if a given changeset is included is a tagged release::
3999 - check if a given changeset is included is a tagged release::
4000
4000
4001 hg log -r "a21ccf and ancestor(1.9)"
4001 hg log -r "a21ccf and ancestor(1.9)"
4002
4002
4003 - find all changesets by some user in a date range::
4003 - find all changesets by some user in a date range::
4004
4004
4005 hg log -k alice -d "may 2008 to jul 2008"
4005 hg log -k alice -d "may 2008 to jul 2008"
4006
4006
4007 - summary of all changesets after the last tag::
4007 - summary of all changesets after the last tag::
4008
4008
4009 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4009 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4010
4010
4011 See :hg:`help dates` for a list of formats valid for -d/--date.
4011 See :hg:`help dates` for a list of formats valid for -d/--date.
4012
4012
4013 See :hg:`help revisions` and :hg:`help revsets` for more about
4013 See :hg:`help revisions` and :hg:`help revsets` for more about
4014 specifying revisions.
4014 specifying revisions.
4015
4015
4016 See :hg:`help templates` for more about pre-packaged styles and
4016 See :hg:`help templates` for more about pre-packaged styles and
4017 specifying custom templates.
4017 specifying custom templates.
4018
4018
4019 Returns 0 on success.
4019 Returns 0 on success.
4020 """
4020 """
4021 if opts.get('graph'):
4021 if opts.get('graph'):
4022 return cmdutil.graphlog(ui, repo, *pats, **opts)
4022 return cmdutil.graphlog(ui, repo, *pats, **opts)
4023
4023
4024 matchfn = scmutil.match(repo[None], pats, opts)
4024 matchfn = scmutil.match(repo[None], pats, opts)
4025 limit = cmdutil.loglimit(opts)
4025 limit = cmdutil.loglimit(opts)
4026 count = 0
4026 count = 0
4027
4027
4028 getrenamed, endrev = None, None
4028 getrenamed, endrev = None, None
4029 if opts.get('copies'):
4029 if opts.get('copies'):
4030 if opts.get('rev'):
4030 if opts.get('rev'):
4031 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4031 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4032 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4032 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4033
4033
4034 df = False
4034 df = False
4035 if opts.get("date"):
4035 if opts.get("date"):
4036 df = util.matchdate(opts["date"])
4036 df = util.matchdate(opts["date"])
4037
4037
4038 branches = opts.get('branch', []) + opts.get('only_branch', [])
4038 branches = opts.get('branch', []) + opts.get('only_branch', [])
4039 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4039 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4040
4040
4041 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4041 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4042 def prep(ctx, fns):
4042 def prep(ctx, fns):
4043 rev = ctx.rev()
4043 rev = ctx.rev()
4044 parents = [p for p in repo.changelog.parentrevs(rev)
4044 parents = [p for p in repo.changelog.parentrevs(rev)
4045 if p != nullrev]
4045 if p != nullrev]
4046 if opts.get('no_merges') and len(parents) == 2:
4046 if opts.get('no_merges') and len(parents) == 2:
4047 return
4047 return
4048 if opts.get('only_merges') and len(parents) != 2:
4048 if opts.get('only_merges') and len(parents) != 2:
4049 return
4049 return
4050 if opts.get('branch') and ctx.branch() not in opts['branch']:
4050 if opts.get('branch') and ctx.branch() not in opts['branch']:
4051 return
4051 return
4052 if df and not df(ctx.date()[0]):
4052 if df and not df(ctx.date()[0]):
4053 return
4053 return
4054
4054
4055 lower = encoding.lower
4055 lower = encoding.lower
4056 if opts.get('user'):
4056 if opts.get('user'):
4057 luser = lower(ctx.user())
4057 luser = lower(ctx.user())
4058 for k in [lower(x) for x in opts['user']]:
4058 for k in [lower(x) for x in opts['user']]:
4059 if (k in luser):
4059 if (k in luser):
4060 break
4060 break
4061 else:
4061 else:
4062 return
4062 return
4063 if opts.get('keyword'):
4063 if opts.get('keyword'):
4064 luser = lower(ctx.user())
4064 luser = lower(ctx.user())
4065 ldesc = lower(ctx.description())
4065 ldesc = lower(ctx.description())
4066 lfiles = lower(" ".join(ctx.files()))
4066 lfiles = lower(" ".join(ctx.files()))
4067 for k in [lower(x) for x in opts['keyword']]:
4067 for k in [lower(x) for x in opts['keyword']]:
4068 if (k in luser or k in ldesc or k in lfiles):
4068 if (k in luser or k in ldesc or k in lfiles):
4069 break
4069 break
4070 else:
4070 else:
4071 return
4071 return
4072
4072
4073 copies = None
4073 copies = None
4074 if getrenamed is not None and rev:
4074 if getrenamed is not None and rev:
4075 copies = []
4075 copies = []
4076 for fn in ctx.files():
4076 for fn in ctx.files():
4077 rename = getrenamed(fn, rev)
4077 rename = getrenamed(fn, rev)
4078 if rename:
4078 if rename:
4079 copies.append((fn, rename[0]))
4079 copies.append((fn, rename[0]))
4080
4080
4081 revmatchfn = None
4081 revmatchfn = None
4082 if opts.get('patch') or opts.get('stat'):
4082 if opts.get('patch') or opts.get('stat'):
4083 if opts.get('follow') or opts.get('follow_first'):
4083 if opts.get('follow') or opts.get('follow_first'):
4084 # note: this might be wrong when following through merges
4084 # note: this might be wrong when following through merges
4085 revmatchfn = scmutil.match(repo[None], fns, default='path')
4085 revmatchfn = scmutil.match(repo[None], fns, default='path')
4086 else:
4086 else:
4087 revmatchfn = matchfn
4087 revmatchfn = matchfn
4088
4088
4089 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4089 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4090
4090
4091 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4091 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4092 if displayer.flush(ctx.rev()):
4092 if displayer.flush(ctx.rev()):
4093 count += 1
4093 count += 1
4094 if count == limit:
4094 if count == limit:
4095 break
4095 break
4096 displayer.close()
4096 displayer.close()
4097
4097
4098 @command('manifest',
4098 @command('manifest',
4099 [('r', 'rev', '', _('revision to display'), _('REV')),
4099 [('r', 'rev', '', _('revision to display'), _('REV')),
4100 ('', 'all', False, _("list files from all revisions"))],
4100 ('', 'all', False, _("list files from all revisions"))],
4101 _('[-r REV]'))
4101 _('[-r REV]'))
4102 def manifest(ui, repo, node=None, rev=None, **opts):
4102 def manifest(ui, repo, node=None, rev=None, **opts):
4103 """output the current or given revision of the project manifest
4103 """output the current or given revision of the project manifest
4104
4104
4105 Print a list of version controlled files for the given revision.
4105 Print a list of version controlled files for the given revision.
4106 If no revision is given, the first parent of the working directory
4106 If no revision is given, the first parent of the working directory
4107 is used, or the null revision if no revision is checked out.
4107 is used, or the null revision if no revision is checked out.
4108
4108
4109 With -v, print file permissions, symlink and executable bits.
4109 With -v, print file permissions, symlink and executable bits.
4110 With --debug, print file revision hashes.
4110 With --debug, print file revision hashes.
4111
4111
4112 If option --all is specified, the list of all files from all revisions
4112 If option --all is specified, the list of all files from all revisions
4113 is printed. This includes deleted and renamed files.
4113 is printed. This includes deleted and renamed files.
4114
4114
4115 Returns 0 on success.
4115 Returns 0 on success.
4116 """
4116 """
4117
4117
4118 fm = ui.formatter('manifest', opts)
4118 fm = ui.formatter('manifest', opts)
4119
4119
4120 if opts.get('all'):
4120 if opts.get('all'):
4121 if rev or node:
4121 if rev or node:
4122 raise util.Abort(_("can't specify a revision with --all"))
4122 raise util.Abort(_("can't specify a revision with --all"))
4123
4123
4124 res = []
4124 res = []
4125 prefix = "data/"
4125 prefix = "data/"
4126 suffix = ".i"
4126 suffix = ".i"
4127 plen = len(prefix)
4127 plen = len(prefix)
4128 slen = len(suffix)
4128 slen = len(suffix)
4129 lock = repo.lock()
4129 lock = repo.lock()
4130 try:
4130 try:
4131 for fn, b, size in repo.store.datafiles():
4131 for fn, b, size in repo.store.datafiles():
4132 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4132 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4133 res.append(fn[plen:-slen])
4133 res.append(fn[plen:-slen])
4134 finally:
4134 finally:
4135 lock.release()
4135 lock.release()
4136 for f in res:
4136 for f in res:
4137 fm.startitem()
4137 fm.startitem()
4138 fm.write("path", '%s\n', f)
4138 fm.write("path", '%s\n', f)
4139 fm.end()
4139 fm.end()
4140 return
4140 return
4141
4141
4142 if rev and node:
4142 if rev and node:
4143 raise util.Abort(_("please specify just one revision"))
4143 raise util.Abort(_("please specify just one revision"))
4144
4144
4145 if not node:
4145 if not node:
4146 node = rev
4146 node = rev
4147
4147
4148 char = {'l': '@', 'x': '*', '': ''}
4148 char = {'l': '@', 'x': '*', '': ''}
4149 mode = {'l': '644', 'x': '755', '': '644'}
4149 mode = {'l': '644', 'x': '755', '': '644'}
4150 ctx = scmutil.revsingle(repo, node)
4150 ctx = scmutil.revsingle(repo, node)
4151 mf = ctx.manifest()
4151 mf = ctx.manifest()
4152 for f in ctx:
4152 for f in ctx:
4153 fm.startitem()
4153 fm.startitem()
4154 fl = ctx[f].flags()
4154 fl = ctx[f].flags()
4155 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4155 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4156 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4156 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4157 fm.write('path', '%s\n', f)
4157 fm.write('path', '%s\n', f)
4158 fm.end()
4158 fm.end()
4159
4159
4160 @command('^merge',
4160 @command('^merge',
4161 [('f', 'force', None, _('force a merge with outstanding changes')),
4161 [('f', 'force', None,
4162 _('force a merge including outstanding changes (DEPRECATED)')),
4162 ('r', 'rev', '', _('revision to merge'), _('REV')),
4163 ('r', 'rev', '', _('revision to merge'), _('REV')),
4163 ('P', 'preview', None,
4164 ('P', 'preview', None,
4164 _('review revisions to merge (no merge is performed)'))
4165 _('review revisions to merge (no merge is performed)'))
4165 ] + mergetoolopts,
4166 ] + mergetoolopts,
4166 _('[-P] [-f] [[-r] REV]'))
4167 _('[-P] [-f] [[-r] REV]'))
4167 def merge(ui, repo, node=None, **opts):
4168 def merge(ui, repo, node=None, **opts):
4168 """merge working directory with another revision
4169 """merge working directory with another revision
4169
4170
4170 The current working directory is updated with all changes made in
4171 The current working directory is updated with all changes made in
4171 the requested revision since the last common predecessor revision.
4172 the requested revision since the last common predecessor revision.
4172
4173
4173 Files that changed between either parent are marked as changed for
4174 Files that changed between either parent are marked as changed for
4174 the next commit and a commit must be performed before any further
4175 the next commit and a commit must be performed before any further
4175 updates to the repository are allowed. The next commit will have
4176 updates to the repository are allowed. The next commit will have
4176 two parents.
4177 two parents.
4177
4178
4178 ``--tool`` can be used to specify the merge tool used for file
4179 ``--tool`` can be used to specify the merge tool used for file
4179 merges. It overrides the HGMERGE environment variable and your
4180 merges. It overrides the HGMERGE environment variable and your
4180 configuration files. See :hg:`help merge-tools` for options.
4181 configuration files. See :hg:`help merge-tools` for options.
4181
4182
4182 If no revision is specified, the working directory's parent is a
4183 If no revision is specified, the working directory's parent is a
4183 head revision, and the current branch contains exactly one other
4184 head revision, and the current branch contains exactly one other
4184 head, the other head is merged with by default. Otherwise, an
4185 head, the other head is merged with by default. Otherwise, an
4185 explicit revision with which to merge with must be provided.
4186 explicit revision with which to merge with must be provided.
4186
4187
4187 :hg:`resolve` must be used to resolve unresolved files.
4188 :hg:`resolve` must be used to resolve unresolved files.
4188
4189
4189 To undo an uncommitted merge, use :hg:`update --clean .` which
4190 To undo an uncommitted merge, use :hg:`update --clean .` which
4190 will check out a clean copy of the original merge parent, losing
4191 will check out a clean copy of the original merge parent, losing
4191 all changes.
4192 all changes.
4192
4193
4193 Returns 0 on success, 1 if there are unresolved files.
4194 Returns 0 on success, 1 if there are unresolved files.
4194 """
4195 """
4195
4196
4196 if opts.get('rev') and node:
4197 if opts.get('rev') and node:
4197 raise util.Abort(_("please specify just one revision"))
4198 raise util.Abort(_("please specify just one revision"))
4198 if not node:
4199 if not node:
4199 node = opts.get('rev')
4200 node = opts.get('rev')
4200
4201
4201 if node:
4202 if node:
4202 node = scmutil.revsingle(repo, node).node()
4203 node = scmutil.revsingle(repo, node).node()
4203
4204
4204 if not node and repo._bookmarkcurrent:
4205 if not node and repo._bookmarkcurrent:
4205 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4206 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4206 curhead = repo[repo._bookmarkcurrent].node()
4207 curhead = repo[repo._bookmarkcurrent].node()
4207 if len(bmheads) == 2:
4208 if len(bmheads) == 2:
4208 if curhead == bmheads[0]:
4209 if curhead == bmheads[0]:
4209 node = bmheads[1]
4210 node = bmheads[1]
4210 else:
4211 else:
4211 node = bmheads[0]
4212 node = bmheads[0]
4212 elif len(bmheads) > 2:
4213 elif len(bmheads) > 2:
4213 raise util.Abort(_("multiple matching bookmarks to merge - "
4214 raise util.Abort(_("multiple matching bookmarks to merge - "
4214 "please merge with an explicit rev or bookmark"),
4215 "please merge with an explicit rev or bookmark"),
4215 hint=_("run 'hg heads' to see all heads"))
4216 hint=_("run 'hg heads' to see all heads"))
4216 elif len(bmheads) <= 1:
4217 elif len(bmheads) <= 1:
4217 raise util.Abort(_("no matching bookmark to merge - "
4218 raise util.Abort(_("no matching bookmark to merge - "
4218 "please merge with an explicit rev or bookmark"),
4219 "please merge with an explicit rev or bookmark"),
4219 hint=_("run 'hg heads' to see all heads"))
4220 hint=_("run 'hg heads' to see all heads"))
4220
4221
4221 if not node and not repo._bookmarkcurrent:
4222 if not node and not repo._bookmarkcurrent:
4222 branch = repo[None].branch()
4223 branch = repo[None].branch()
4223 bheads = repo.branchheads(branch)
4224 bheads = repo.branchheads(branch)
4224 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4225 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4225
4226
4226 if len(nbhs) > 2:
4227 if len(nbhs) > 2:
4227 raise util.Abort(_("branch '%s' has %d heads - "
4228 raise util.Abort(_("branch '%s' has %d heads - "
4228 "please merge with an explicit rev")
4229 "please merge with an explicit rev")
4229 % (branch, len(bheads)),
4230 % (branch, len(bheads)),
4230 hint=_("run 'hg heads .' to see heads"))
4231 hint=_("run 'hg heads .' to see heads"))
4231
4232
4232 parent = repo.dirstate.p1()
4233 parent = repo.dirstate.p1()
4233 if len(nbhs) <= 1:
4234 if len(nbhs) <= 1:
4234 if len(bheads) > 1:
4235 if len(bheads) > 1:
4235 raise util.Abort(_("heads are bookmarked - "
4236 raise util.Abort(_("heads are bookmarked - "
4236 "please merge with an explicit rev"),
4237 "please merge with an explicit rev"),
4237 hint=_("run 'hg heads' to see all heads"))
4238 hint=_("run 'hg heads' to see all heads"))
4238 if len(repo.heads()) > 1:
4239 if len(repo.heads()) > 1:
4239 raise util.Abort(_("branch '%s' has one head - "
4240 raise util.Abort(_("branch '%s' has one head - "
4240 "please merge with an explicit rev")
4241 "please merge with an explicit rev")
4241 % branch,
4242 % branch,
4242 hint=_("run 'hg heads' to see all heads"))
4243 hint=_("run 'hg heads' to see all heads"))
4243 msg, hint = _('nothing to merge'), None
4244 msg, hint = _('nothing to merge'), None
4244 if parent != repo.lookup(branch):
4245 if parent != repo.lookup(branch):
4245 hint = _("use 'hg update' instead")
4246 hint = _("use 'hg update' instead")
4246 raise util.Abort(msg, hint=hint)
4247 raise util.Abort(msg, hint=hint)
4247
4248
4248 if parent not in bheads:
4249 if parent not in bheads:
4249 raise util.Abort(_('working directory not at a head revision'),
4250 raise util.Abort(_('working directory not at a head revision'),
4250 hint=_("use 'hg update' or merge with an "
4251 hint=_("use 'hg update' or merge with an "
4251 "explicit revision"))
4252 "explicit revision"))
4252 if parent == nbhs[0]:
4253 if parent == nbhs[0]:
4253 node = nbhs[-1]
4254 node = nbhs[-1]
4254 else:
4255 else:
4255 node = nbhs[0]
4256 node = nbhs[0]
4256
4257
4257 if opts.get('preview'):
4258 if opts.get('preview'):
4258 # find nodes that are ancestors of p2 but not of p1
4259 # find nodes that are ancestors of p2 but not of p1
4259 p1 = repo.lookup('.')
4260 p1 = repo.lookup('.')
4260 p2 = repo.lookup(node)
4261 p2 = repo.lookup(node)
4261 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4262 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4262
4263
4263 displayer = cmdutil.show_changeset(ui, repo, opts)
4264 displayer = cmdutil.show_changeset(ui, repo, opts)
4264 for node in nodes:
4265 for node in nodes:
4265 displayer.show(repo[node])
4266 displayer.show(repo[node])
4266 displayer.close()
4267 displayer.close()
4267 return 0
4268 return 0
4268
4269
4269 try:
4270 try:
4270 # ui.forcemerge is an internal variable, do not document
4271 # ui.forcemerge is an internal variable, do not document
4271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4272 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4272 return hg.merge(repo, node, force=opts.get('force'))
4273 return hg.merge(repo, node, force=opts.get('force'))
4273 finally:
4274 finally:
4274 ui.setconfig('ui', 'forcemerge', '')
4275 ui.setconfig('ui', 'forcemerge', '')
4275
4276
4276 @command('outgoing|out',
4277 @command('outgoing|out',
4277 [('f', 'force', None, _('run even when the destination is unrelated')),
4278 [('f', 'force', None, _('run even when the destination is unrelated')),
4278 ('r', 'rev', [],
4279 ('r', 'rev', [],
4279 _('a changeset intended to be included in the destination'), _('REV')),
4280 _('a changeset intended to be included in the destination'), _('REV')),
4280 ('n', 'newest-first', None, _('show newest record first')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4281 ('B', 'bookmarks', False, _('compare bookmarks')),
4282 ('B', 'bookmarks', False, _('compare bookmarks')),
4282 ('b', 'branch', [], _('a specific branch you would like to push'),
4283 ('b', 'branch', [], _('a specific branch you would like to push'),
4283 _('BRANCH')),
4284 _('BRANCH')),
4284 ] + logopts + remoteopts + subrepoopts,
4285 ] + logopts + remoteopts + subrepoopts,
4285 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4286 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4286 def outgoing(ui, repo, dest=None, **opts):
4287 def outgoing(ui, repo, dest=None, **opts):
4287 """show changesets not found in the destination
4288 """show changesets not found in the destination
4288
4289
4289 Show changesets not found in the specified destination repository
4290 Show changesets not found in the specified destination repository
4290 or the default push location. These are the changesets that would
4291 or the default push location. These are the changesets that would
4291 be pushed if a push was requested.
4292 be pushed if a push was requested.
4292
4293
4293 See pull for details of valid destination formats.
4294 See pull for details of valid destination formats.
4294
4295
4295 Returns 0 if there are outgoing changes, 1 otherwise.
4296 Returns 0 if there are outgoing changes, 1 otherwise.
4296 """
4297 """
4297 if opts.get('graph'):
4298 if opts.get('graph'):
4298 cmdutil.checkunsupportedgraphflags([], opts)
4299 cmdutil.checkunsupportedgraphflags([], opts)
4299 o = hg._outgoing(ui, repo, dest, opts)
4300 o = hg._outgoing(ui, repo, dest, opts)
4300 if o is None:
4301 if o is None:
4301 return
4302 return
4302
4303
4303 revdag = cmdutil.graphrevs(repo, o, opts)
4304 revdag = cmdutil.graphrevs(repo, o, opts)
4304 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4305 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4305 showparents = [ctx.node() for ctx in repo[None].parents()]
4306 showparents = [ctx.node() for ctx in repo[None].parents()]
4306 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4307 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4307 graphmod.asciiedges)
4308 graphmod.asciiedges)
4308 return 0
4309 return 0
4309
4310
4310 if opts.get('bookmarks'):
4311 if opts.get('bookmarks'):
4311 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4312 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4312 dest, branches = hg.parseurl(dest, opts.get('branch'))
4313 dest, branches = hg.parseurl(dest, opts.get('branch'))
4313 other = hg.peer(repo, opts, dest)
4314 other = hg.peer(repo, opts, dest)
4314 if 'bookmarks' not in other.listkeys('namespaces'):
4315 if 'bookmarks' not in other.listkeys('namespaces'):
4315 ui.warn(_("remote doesn't support bookmarks\n"))
4316 ui.warn(_("remote doesn't support bookmarks\n"))
4316 return 0
4317 return 0
4317 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4318 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4318 return bookmarks.diff(ui, other, repo)
4319 return bookmarks.diff(ui, other, repo)
4319
4320
4320 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4321 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4321 try:
4322 try:
4322 return hg.outgoing(ui, repo, dest, opts)
4323 return hg.outgoing(ui, repo, dest, opts)
4323 finally:
4324 finally:
4324 del repo._subtoppath
4325 del repo._subtoppath
4325
4326
4326 @command('parents',
4327 @command('parents',
4327 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4328 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4328 ] + templateopts,
4329 ] + templateopts,
4329 _('[-r REV] [FILE]'))
4330 _('[-r REV] [FILE]'))
4330 def parents(ui, repo, file_=None, **opts):
4331 def parents(ui, repo, file_=None, **opts):
4331 """show the parents of the working directory or revision
4332 """show the parents of the working directory or revision
4332
4333
4333 Print the working directory's parent revisions. If a revision is
4334 Print the working directory's parent revisions. If a revision is
4334 given via -r/--rev, the parent of that revision will be printed.
4335 given via -r/--rev, the parent of that revision will be printed.
4335 If a file argument is given, the revision in which the file was
4336 If a file argument is given, the revision in which the file was
4336 last changed (before the working directory revision or the
4337 last changed (before the working directory revision or the
4337 argument to --rev if given) is printed.
4338 argument to --rev if given) is printed.
4338
4339
4339 Returns 0 on success.
4340 Returns 0 on success.
4340 """
4341 """
4341
4342
4342 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4343 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4343
4344
4344 if file_:
4345 if file_:
4345 m = scmutil.match(ctx, (file_,), opts)
4346 m = scmutil.match(ctx, (file_,), opts)
4346 if m.anypats() or len(m.files()) != 1:
4347 if m.anypats() or len(m.files()) != 1:
4347 raise util.Abort(_('can only specify an explicit filename'))
4348 raise util.Abort(_('can only specify an explicit filename'))
4348 file_ = m.files()[0]
4349 file_ = m.files()[0]
4349 filenodes = []
4350 filenodes = []
4350 for cp in ctx.parents():
4351 for cp in ctx.parents():
4351 if not cp:
4352 if not cp:
4352 continue
4353 continue
4353 try:
4354 try:
4354 filenodes.append(cp.filenode(file_))
4355 filenodes.append(cp.filenode(file_))
4355 except error.LookupError:
4356 except error.LookupError:
4356 pass
4357 pass
4357 if not filenodes:
4358 if not filenodes:
4358 raise util.Abort(_("'%s' not found in manifest!") % file_)
4359 raise util.Abort(_("'%s' not found in manifest!") % file_)
4359 p = []
4360 p = []
4360 for fn in filenodes:
4361 for fn in filenodes:
4361 fctx = repo.filectx(file_, fileid=fn)
4362 fctx = repo.filectx(file_, fileid=fn)
4362 p.append(fctx.node())
4363 p.append(fctx.node())
4363 else:
4364 else:
4364 p = [cp.node() for cp in ctx.parents()]
4365 p = [cp.node() for cp in ctx.parents()]
4365
4366
4366 displayer = cmdutil.show_changeset(ui, repo, opts)
4367 displayer = cmdutil.show_changeset(ui, repo, opts)
4367 for n in p:
4368 for n in p:
4368 if n != nullid:
4369 if n != nullid:
4369 displayer.show(repo[n])
4370 displayer.show(repo[n])
4370 displayer.close()
4371 displayer.close()
4371
4372
4372 @command('paths', [], _('[NAME]'))
4373 @command('paths', [], _('[NAME]'))
4373 def paths(ui, repo, search=None):
4374 def paths(ui, repo, search=None):
4374 """show aliases for remote repositories
4375 """show aliases for remote repositories
4375
4376
4376 Show definition of symbolic path name NAME. If no name is given,
4377 Show definition of symbolic path name NAME. If no name is given,
4377 show definition of all available names.
4378 show definition of all available names.
4378
4379
4379 Option -q/--quiet suppresses all output when searching for NAME
4380 Option -q/--quiet suppresses all output when searching for NAME
4380 and shows only the path names when listing all definitions.
4381 and shows only the path names when listing all definitions.
4381
4382
4382 Path names are defined in the [paths] section of your
4383 Path names are defined in the [paths] section of your
4383 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4384 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4384 repository, ``.hg/hgrc`` is used, too.
4385 repository, ``.hg/hgrc`` is used, too.
4385
4386
4386 The path names ``default`` and ``default-push`` have a special
4387 The path names ``default`` and ``default-push`` have a special
4387 meaning. When performing a push or pull operation, they are used
4388 meaning. When performing a push or pull operation, they are used
4388 as fallbacks if no location is specified on the command-line.
4389 as fallbacks if no location is specified on the command-line.
4389 When ``default-push`` is set, it will be used for push and
4390 When ``default-push`` is set, it will be used for push and
4390 ``default`` will be used for pull; otherwise ``default`` is used
4391 ``default`` will be used for pull; otherwise ``default`` is used
4391 as the fallback for both. When cloning a repository, the clone
4392 as the fallback for both. When cloning a repository, the clone
4392 source is written as ``default`` in ``.hg/hgrc``. Note that
4393 source is written as ``default`` in ``.hg/hgrc``. Note that
4393 ``default`` and ``default-push`` apply to all inbound (e.g.
4394 ``default`` and ``default-push`` apply to all inbound (e.g.
4394 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4395 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4395 :hg:`bundle`) operations.
4396 :hg:`bundle`) operations.
4396
4397
4397 See :hg:`help urls` for more information.
4398 See :hg:`help urls` for more information.
4398
4399
4399 Returns 0 on success.
4400 Returns 0 on success.
4400 """
4401 """
4401 if search:
4402 if search:
4402 for name, path in ui.configitems("paths"):
4403 for name, path in ui.configitems("paths"):
4403 if name == search:
4404 if name == search:
4404 ui.status("%s\n" % util.hidepassword(path))
4405 ui.status("%s\n" % util.hidepassword(path))
4405 return
4406 return
4406 if not ui.quiet:
4407 if not ui.quiet:
4407 ui.warn(_("not found!\n"))
4408 ui.warn(_("not found!\n"))
4408 return 1
4409 return 1
4409 else:
4410 else:
4410 for name, path in ui.configitems("paths"):
4411 for name, path in ui.configitems("paths"):
4411 if ui.quiet:
4412 if ui.quiet:
4412 ui.write("%s\n" % name)
4413 ui.write("%s\n" % name)
4413 else:
4414 else:
4414 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4415 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4415
4416
4416 @command('phase',
4417 @command('phase',
4417 [('p', 'public', False, _('set changeset phase to public')),
4418 [('p', 'public', False, _('set changeset phase to public')),
4418 ('d', 'draft', False, _('set changeset phase to draft')),
4419 ('d', 'draft', False, _('set changeset phase to draft')),
4419 ('s', 'secret', False, _('set changeset phase to secret')),
4420 ('s', 'secret', False, _('set changeset phase to secret')),
4420 ('f', 'force', False, _('allow to move boundary backward')),
4421 ('f', 'force', False, _('allow to move boundary backward')),
4421 ('r', 'rev', [], _('target revision'), _('REV')),
4422 ('r', 'rev', [], _('target revision'), _('REV')),
4422 ],
4423 ],
4423 _('[-p|-d|-s] [-f] [-r] REV...'))
4424 _('[-p|-d|-s] [-f] [-r] REV...'))
4424 def phase(ui, repo, *revs, **opts):
4425 def phase(ui, repo, *revs, **opts):
4425 """set or show the current phase name
4426 """set or show the current phase name
4426
4427
4427 With no argument, show the phase name of specified revisions.
4428 With no argument, show the phase name of specified revisions.
4428
4429
4429 With one of -p/--public, -d/--draft or -s/--secret, change the
4430 With one of -p/--public, -d/--draft or -s/--secret, change the
4430 phase value of the specified revisions.
4431 phase value of the specified revisions.
4431
4432
4432 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4433 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4433 lower phase to an higher phase. Phases are ordered as follows::
4434 lower phase to an higher phase. Phases are ordered as follows::
4434
4435
4435 public < draft < secret
4436 public < draft < secret
4436
4437
4437 Return 0 on success, 1 if no phases were changed or some could not
4438 Return 0 on success, 1 if no phases were changed or some could not
4438 be changed.
4439 be changed.
4439 """
4440 """
4440 # search for a unique phase argument
4441 # search for a unique phase argument
4441 targetphase = None
4442 targetphase = None
4442 for idx, name in enumerate(phases.phasenames):
4443 for idx, name in enumerate(phases.phasenames):
4443 if opts[name]:
4444 if opts[name]:
4444 if targetphase is not None:
4445 if targetphase is not None:
4445 raise util.Abort(_('only one phase can be specified'))
4446 raise util.Abort(_('only one phase can be specified'))
4446 targetphase = idx
4447 targetphase = idx
4447
4448
4448 # look for specified revision
4449 # look for specified revision
4449 revs = list(revs)
4450 revs = list(revs)
4450 revs.extend(opts['rev'])
4451 revs.extend(opts['rev'])
4451 if not revs:
4452 if not revs:
4452 raise util.Abort(_('no revisions specified'))
4453 raise util.Abort(_('no revisions specified'))
4453
4454
4454 revs = scmutil.revrange(repo, revs)
4455 revs = scmutil.revrange(repo, revs)
4455
4456
4456 lock = None
4457 lock = None
4457 ret = 0
4458 ret = 0
4458 if targetphase is None:
4459 if targetphase is None:
4459 # display
4460 # display
4460 for r in revs:
4461 for r in revs:
4461 ctx = repo[r]
4462 ctx = repo[r]
4462 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4463 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4463 else:
4464 else:
4464 lock = repo.lock()
4465 lock = repo.lock()
4465 try:
4466 try:
4466 # set phase
4467 # set phase
4467 if not revs:
4468 if not revs:
4468 raise util.Abort(_('empty revision set'))
4469 raise util.Abort(_('empty revision set'))
4469 nodes = [repo[r].node() for r in revs]
4470 nodes = [repo[r].node() for r in revs]
4470 olddata = repo._phasecache.getphaserevs(repo)[:]
4471 olddata = repo._phasecache.getphaserevs(repo)[:]
4471 phases.advanceboundary(repo, targetphase, nodes)
4472 phases.advanceboundary(repo, targetphase, nodes)
4472 if opts['force']:
4473 if opts['force']:
4473 phases.retractboundary(repo, targetphase, nodes)
4474 phases.retractboundary(repo, targetphase, nodes)
4474 finally:
4475 finally:
4475 lock.release()
4476 lock.release()
4476 # moving revision from public to draft may hide them
4477 # moving revision from public to draft may hide them
4477 # We have to check result on an unfiltered repository
4478 # We have to check result on an unfiltered repository
4478 unfi = repo.unfiltered()
4479 unfi = repo.unfiltered()
4479 newdata = repo._phasecache.getphaserevs(unfi)
4480 newdata = repo._phasecache.getphaserevs(unfi)
4480 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4481 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4481 cl = unfi.changelog
4482 cl = unfi.changelog
4482 rejected = [n for n in nodes
4483 rejected = [n for n in nodes
4483 if newdata[cl.rev(n)] < targetphase]
4484 if newdata[cl.rev(n)] < targetphase]
4484 if rejected:
4485 if rejected:
4485 ui.warn(_('cannot move %i changesets to a more permissive '
4486 ui.warn(_('cannot move %i changesets to a more permissive '
4486 'phase, use --force\n') % len(rejected))
4487 'phase, use --force\n') % len(rejected))
4487 ret = 1
4488 ret = 1
4488 if changes:
4489 if changes:
4489 msg = _('phase changed for %i changesets\n') % changes
4490 msg = _('phase changed for %i changesets\n') % changes
4490 if ret:
4491 if ret:
4491 ui.status(msg)
4492 ui.status(msg)
4492 else:
4493 else:
4493 ui.note(msg)
4494 ui.note(msg)
4494 else:
4495 else:
4495 ui.warn(_('no phases changed\n'))
4496 ui.warn(_('no phases changed\n'))
4496 ret = 1
4497 ret = 1
4497 return ret
4498 return ret
4498
4499
4499 def postincoming(ui, repo, modheads, optupdate, checkout):
4500 def postincoming(ui, repo, modheads, optupdate, checkout):
4500 if modheads == 0:
4501 if modheads == 0:
4501 return
4502 return
4502 if optupdate:
4503 if optupdate:
4503 movemarkfrom = repo['.'].node()
4504 movemarkfrom = repo['.'].node()
4504 try:
4505 try:
4505 ret = hg.update(repo, checkout)
4506 ret = hg.update(repo, checkout)
4506 except util.Abort, inst:
4507 except util.Abort, inst:
4507 ui.warn(_("not updating: %s\n") % str(inst))
4508 ui.warn(_("not updating: %s\n") % str(inst))
4508 return 0
4509 return 0
4509 if not ret and not checkout:
4510 if not ret and not checkout:
4510 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4511 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4511 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4512 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4512 return ret
4513 return ret
4513 if modheads > 1:
4514 if modheads > 1:
4514 currentbranchheads = len(repo.branchheads())
4515 currentbranchheads = len(repo.branchheads())
4515 if currentbranchheads == modheads:
4516 if currentbranchheads == modheads:
4516 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4517 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4517 elif currentbranchheads > 1:
4518 elif currentbranchheads > 1:
4518 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4519 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4519 "merge)\n"))
4520 "merge)\n"))
4520 else:
4521 else:
4521 ui.status(_("(run 'hg heads' to see heads)\n"))
4522 ui.status(_("(run 'hg heads' to see heads)\n"))
4522 else:
4523 else:
4523 ui.status(_("(run 'hg update' to get a working copy)\n"))
4524 ui.status(_("(run 'hg update' to get a working copy)\n"))
4524
4525
4525 @command('^pull',
4526 @command('^pull',
4526 [('u', 'update', None,
4527 [('u', 'update', None,
4527 _('update to new branch head if changesets were pulled')),
4528 _('update to new branch head if changesets were pulled')),
4528 ('f', 'force', None, _('run even when remote repository is unrelated')),
4529 ('f', 'force', None, _('run even when remote repository is unrelated')),
4529 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4530 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4530 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4531 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4531 ('b', 'branch', [], _('a specific branch you would like to pull'),
4532 ('b', 'branch', [], _('a specific branch you would like to pull'),
4532 _('BRANCH')),
4533 _('BRANCH')),
4533 ] + remoteopts,
4534 ] + remoteopts,
4534 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4535 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4535 def pull(ui, repo, source="default", **opts):
4536 def pull(ui, repo, source="default", **opts):
4536 """pull changes from the specified source
4537 """pull changes from the specified source
4537
4538
4538 Pull changes from a remote repository to a local one.
4539 Pull changes from a remote repository to a local one.
4539
4540
4540 This finds all changes from the repository at the specified path
4541 This finds all changes from the repository at the specified path
4541 or URL and adds them to a local repository (the current one unless
4542 or URL and adds them to a local repository (the current one unless
4542 -R is specified). By default, this does not update the copy of the
4543 -R is specified). By default, this does not update the copy of the
4543 project in the working directory.
4544 project in the working directory.
4544
4545
4545 Use :hg:`incoming` if you want to see what would have been added
4546 Use :hg:`incoming` if you want to see what would have been added
4546 by a pull at the time you issued this command. If you then decide
4547 by a pull at the time you issued this command. If you then decide
4547 to add those changes to the repository, you should use :hg:`pull
4548 to add those changes to the repository, you should use :hg:`pull
4548 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4549 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4549
4550
4550 If SOURCE is omitted, the 'default' path will be used.
4551 If SOURCE is omitted, the 'default' path will be used.
4551 See :hg:`help urls` for more information.
4552 See :hg:`help urls` for more information.
4552
4553
4553 Returns 0 on success, 1 if an update had unresolved files.
4554 Returns 0 on success, 1 if an update had unresolved files.
4554 """
4555 """
4555 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4556 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4556 other = hg.peer(repo, opts, source)
4557 other = hg.peer(repo, opts, source)
4557 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4558 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4558 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4559 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4559
4560
4560 remotebookmarks = other.listkeys('bookmarks')
4561 remotebookmarks = other.listkeys('bookmarks')
4561
4562
4562 if opts.get('bookmark'):
4563 if opts.get('bookmark'):
4563 if not revs:
4564 if not revs:
4564 revs = []
4565 revs = []
4565 for b in opts['bookmark']:
4566 for b in opts['bookmark']:
4566 if b not in remotebookmarks:
4567 if b not in remotebookmarks:
4567 raise util.Abort(_('remote bookmark %s not found!') % b)
4568 raise util.Abort(_('remote bookmark %s not found!') % b)
4568 revs.append(remotebookmarks[b])
4569 revs.append(remotebookmarks[b])
4569
4570
4570 if revs:
4571 if revs:
4571 try:
4572 try:
4572 revs = [other.lookup(rev) for rev in revs]
4573 revs = [other.lookup(rev) for rev in revs]
4573 except error.CapabilityError:
4574 except error.CapabilityError:
4574 err = _("other repository doesn't support revision lookup, "
4575 err = _("other repository doesn't support revision lookup, "
4575 "so a rev cannot be specified.")
4576 "so a rev cannot be specified.")
4576 raise util.Abort(err)
4577 raise util.Abort(err)
4577
4578
4578 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4579 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4579 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4580 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4580 if checkout:
4581 if checkout:
4581 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4582 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4582 repo._subtoppath = source
4583 repo._subtoppath = source
4583 try:
4584 try:
4584 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4585 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4585
4586
4586 finally:
4587 finally:
4587 del repo._subtoppath
4588 del repo._subtoppath
4588
4589
4589 # update specified bookmarks
4590 # update specified bookmarks
4590 if opts.get('bookmark'):
4591 if opts.get('bookmark'):
4591 marks = repo._bookmarks
4592 marks = repo._bookmarks
4592 for b in opts['bookmark']:
4593 for b in opts['bookmark']:
4593 # explicit pull overrides local bookmark if any
4594 # explicit pull overrides local bookmark if any
4594 ui.status(_("importing bookmark %s\n") % b)
4595 ui.status(_("importing bookmark %s\n") % b)
4595 marks[b] = repo[remotebookmarks[b]].node()
4596 marks[b] = repo[remotebookmarks[b]].node()
4596 marks.write()
4597 marks.write()
4597
4598
4598 return ret
4599 return ret
4599
4600
4600 @command('^push',
4601 @command('^push',
4601 [('f', 'force', None, _('force push')),
4602 [('f', 'force', None, _('force push')),
4602 ('r', 'rev', [],
4603 ('r', 'rev', [],
4603 _('a changeset intended to be included in the destination'),
4604 _('a changeset intended to be included in the destination'),
4604 _('REV')),
4605 _('REV')),
4605 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4606 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4606 ('b', 'branch', [],
4607 ('b', 'branch', [],
4607 _('a specific branch you would like to push'), _('BRANCH')),
4608 _('a specific branch you would like to push'), _('BRANCH')),
4608 ('', 'new-branch', False, _('allow pushing a new branch')),
4609 ('', 'new-branch', False, _('allow pushing a new branch')),
4609 ] + remoteopts,
4610 ] + remoteopts,
4610 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4611 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4611 def push(ui, repo, dest=None, **opts):
4612 def push(ui, repo, dest=None, **opts):
4612 """push changes to the specified destination
4613 """push changes to the specified destination
4613
4614
4614 Push changesets from the local repository to the specified
4615 Push changesets from the local repository to the specified
4615 destination.
4616 destination.
4616
4617
4617 This operation is symmetrical to pull: it is identical to a pull
4618 This operation is symmetrical to pull: it is identical to a pull
4618 in the destination repository from the current one.
4619 in the destination repository from the current one.
4619
4620
4620 By default, push will not allow creation of new heads at the
4621 By default, push will not allow creation of new heads at the
4621 destination, since multiple heads would make it unclear which head
4622 destination, since multiple heads would make it unclear which head
4622 to use. In this situation, it is recommended to pull and merge
4623 to use. In this situation, it is recommended to pull and merge
4623 before pushing.
4624 before pushing.
4624
4625
4625 Use --new-branch if you want to allow push to create a new named
4626 Use --new-branch if you want to allow push to create a new named
4626 branch that is not present at the destination. This allows you to
4627 branch that is not present at the destination. This allows you to
4627 only create a new branch without forcing other changes.
4628 only create a new branch without forcing other changes.
4628
4629
4629 Use -f/--force to override the default behavior and push all
4630 Use -f/--force to override the default behavior and push all
4630 changesets on all branches.
4631 changesets on all branches.
4631
4632
4632 If -r/--rev is used, the specified revision and all its ancestors
4633 If -r/--rev is used, the specified revision and all its ancestors
4633 will be pushed to the remote repository.
4634 will be pushed to the remote repository.
4634
4635
4635 If -B/--bookmark is used, the specified bookmarked revision, its
4636 If -B/--bookmark is used, the specified bookmarked revision, its
4636 ancestors, and the bookmark will be pushed to the remote
4637 ancestors, and the bookmark will be pushed to the remote
4637 repository.
4638 repository.
4638
4639
4639 Please see :hg:`help urls` for important details about ``ssh://``
4640 Please see :hg:`help urls` for important details about ``ssh://``
4640 URLs. If DESTINATION is omitted, a default path will be used.
4641 URLs. If DESTINATION is omitted, a default path will be used.
4641
4642
4642 Returns 0 if push was successful, 1 if nothing to push.
4643 Returns 0 if push was successful, 1 if nothing to push.
4643 """
4644 """
4644
4645
4645 if opts.get('bookmark'):
4646 if opts.get('bookmark'):
4646 for b in opts['bookmark']:
4647 for b in opts['bookmark']:
4647 # translate -B options to -r so changesets get pushed
4648 # translate -B options to -r so changesets get pushed
4648 if b in repo._bookmarks:
4649 if b in repo._bookmarks:
4649 opts.setdefault('rev', []).append(b)
4650 opts.setdefault('rev', []).append(b)
4650 else:
4651 else:
4651 # if we try to push a deleted bookmark, translate it to null
4652 # if we try to push a deleted bookmark, translate it to null
4652 # this lets simultaneous -r, -b options continue working
4653 # this lets simultaneous -r, -b options continue working
4653 opts.setdefault('rev', []).append("null")
4654 opts.setdefault('rev', []).append("null")
4654
4655
4655 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4656 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4656 dest, branches = hg.parseurl(dest, opts.get('branch'))
4657 dest, branches = hg.parseurl(dest, opts.get('branch'))
4657 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4658 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4658 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4659 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4659 other = hg.peer(repo, opts, dest)
4660 other = hg.peer(repo, opts, dest)
4660 if revs:
4661 if revs:
4661 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4662 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4662
4663
4663 repo._subtoppath = dest
4664 repo._subtoppath = dest
4664 try:
4665 try:
4665 # push subrepos depth-first for coherent ordering
4666 # push subrepos depth-first for coherent ordering
4666 c = repo['']
4667 c = repo['']
4667 subs = c.substate # only repos that are committed
4668 subs = c.substate # only repos that are committed
4668 for s in sorted(subs):
4669 for s in sorted(subs):
4669 if c.sub(s).push(opts) == 0:
4670 if c.sub(s).push(opts) == 0:
4670 return False
4671 return False
4671 finally:
4672 finally:
4672 del repo._subtoppath
4673 del repo._subtoppath
4673 result = repo.push(other, opts.get('force'), revs=revs,
4674 result = repo.push(other, opts.get('force'), revs=revs,
4674 newbranch=opts.get('new_branch'))
4675 newbranch=opts.get('new_branch'))
4675
4676
4676 result = not result
4677 result = not result
4677
4678
4678 if opts.get('bookmark'):
4679 if opts.get('bookmark'):
4679 rb = other.listkeys('bookmarks')
4680 rb = other.listkeys('bookmarks')
4680 for b in opts['bookmark']:
4681 for b in opts['bookmark']:
4681 # explicit push overrides remote bookmark if any
4682 # explicit push overrides remote bookmark if any
4682 if b in repo._bookmarks:
4683 if b in repo._bookmarks:
4683 ui.status(_("exporting bookmark %s\n") % b)
4684 ui.status(_("exporting bookmark %s\n") % b)
4684 new = repo[b].hex()
4685 new = repo[b].hex()
4685 elif b in rb:
4686 elif b in rb:
4686 ui.status(_("deleting remote bookmark %s\n") % b)
4687 ui.status(_("deleting remote bookmark %s\n") % b)
4687 new = '' # delete
4688 new = '' # delete
4688 else:
4689 else:
4689 ui.warn(_('bookmark %s does not exist on the local '
4690 ui.warn(_('bookmark %s does not exist on the local '
4690 'or remote repository!\n') % b)
4691 'or remote repository!\n') % b)
4691 return 2
4692 return 2
4692 old = rb.get(b, '')
4693 old = rb.get(b, '')
4693 r = other.pushkey('bookmarks', b, old, new)
4694 r = other.pushkey('bookmarks', b, old, new)
4694 if not r:
4695 if not r:
4695 ui.warn(_('updating bookmark %s failed!\n') % b)
4696 ui.warn(_('updating bookmark %s failed!\n') % b)
4696 if not result:
4697 if not result:
4697 result = 2
4698 result = 2
4698
4699
4699 return result
4700 return result
4700
4701
4701 @command('recover', [])
4702 @command('recover', [])
4702 def recover(ui, repo):
4703 def recover(ui, repo):
4703 """roll back an interrupted transaction
4704 """roll back an interrupted transaction
4704
4705
4705 Recover from an interrupted commit or pull.
4706 Recover from an interrupted commit or pull.
4706
4707
4707 This command tries to fix the repository status after an
4708 This command tries to fix the repository status after an
4708 interrupted operation. It should only be necessary when Mercurial
4709 interrupted operation. It should only be necessary when Mercurial
4709 suggests it.
4710 suggests it.
4710
4711
4711 Returns 0 if successful, 1 if nothing to recover or verify fails.
4712 Returns 0 if successful, 1 if nothing to recover or verify fails.
4712 """
4713 """
4713 if repo.recover():
4714 if repo.recover():
4714 return hg.verify(repo)
4715 return hg.verify(repo)
4715 return 1
4716 return 1
4716
4717
4717 @command('^remove|rm',
4718 @command('^remove|rm',
4718 [('A', 'after', None, _('record delete for missing files')),
4719 [('A', 'after', None, _('record delete for missing files')),
4719 ('f', 'force', None,
4720 ('f', 'force', None,
4720 _('remove (and delete) file even if added or modified')),
4721 _('remove (and delete) file even if added or modified')),
4721 ] + walkopts,
4722 ] + walkopts,
4722 _('[OPTION]... FILE...'))
4723 _('[OPTION]... FILE...'))
4723 def remove(ui, repo, *pats, **opts):
4724 def remove(ui, repo, *pats, **opts):
4724 """remove the specified files on the next commit
4725 """remove the specified files on the next commit
4725
4726
4726 Schedule the indicated files for removal from the current branch.
4727 Schedule the indicated files for removal from the current branch.
4727
4728
4728 This command schedules the files to be removed at the next commit.
4729 This command schedules the files to be removed at the next commit.
4729 To undo a remove before that, see :hg:`revert`. To undo added
4730 To undo a remove before that, see :hg:`revert`. To undo added
4730 files, see :hg:`forget`.
4731 files, see :hg:`forget`.
4731
4732
4732 .. container:: verbose
4733 .. container:: verbose
4733
4734
4734 -A/--after can be used to remove only files that have already
4735 -A/--after can be used to remove only files that have already
4735 been deleted, -f/--force can be used to force deletion, and -Af
4736 been deleted, -f/--force can be used to force deletion, and -Af
4736 can be used to remove files from the next revision without
4737 can be used to remove files from the next revision without
4737 deleting them from the working directory.
4738 deleting them from the working directory.
4738
4739
4739 The following table details the behavior of remove for different
4740 The following table details the behavior of remove for different
4740 file states (columns) and option combinations (rows). The file
4741 file states (columns) and option combinations (rows). The file
4741 states are Added [A], Clean [C], Modified [M] and Missing [!]
4742 states are Added [A], Clean [C], Modified [M] and Missing [!]
4742 (as reported by :hg:`status`). The actions are Warn, Remove
4743 (as reported by :hg:`status`). The actions are Warn, Remove
4743 (from branch) and Delete (from disk):
4744 (from branch) and Delete (from disk):
4744
4745
4745 ======= == == == ==
4746 ======= == == == ==
4746 A C M !
4747 A C M !
4747 ======= == == == ==
4748 ======= == == == ==
4748 none W RD W R
4749 none W RD W R
4749 -f R RD RD R
4750 -f R RD RD R
4750 -A W W W R
4751 -A W W W R
4751 -Af R R R R
4752 -Af R R R R
4752 ======= == == == ==
4753 ======= == == == ==
4753
4754
4754 Note that remove never deletes files in Added [A] state from the
4755 Note that remove never deletes files in Added [A] state from the
4755 working directory, not even if option --force is specified.
4756 working directory, not even if option --force is specified.
4756
4757
4757 Returns 0 on success, 1 if any warnings encountered.
4758 Returns 0 on success, 1 if any warnings encountered.
4758 """
4759 """
4759
4760
4760 ret = 0
4761 ret = 0
4761 after, force = opts.get('after'), opts.get('force')
4762 after, force = opts.get('after'), opts.get('force')
4762 if not pats and not after:
4763 if not pats and not after:
4763 raise util.Abort(_('no files specified'))
4764 raise util.Abort(_('no files specified'))
4764
4765
4765 m = scmutil.match(repo[None], pats, opts)
4766 m = scmutil.match(repo[None], pats, opts)
4766 s = repo.status(match=m, clean=True)
4767 s = repo.status(match=m, clean=True)
4767 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4768 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4768
4769
4769 # warn about failure to delete explicit files/dirs
4770 # warn about failure to delete explicit files/dirs
4770 wctx = repo[None]
4771 wctx = repo[None]
4771 for f in m.files():
4772 for f in m.files():
4772 if f in repo.dirstate or f in wctx.dirs():
4773 if f in repo.dirstate or f in wctx.dirs():
4773 continue
4774 continue
4774 if os.path.exists(m.rel(f)):
4775 if os.path.exists(m.rel(f)):
4775 if os.path.isdir(m.rel(f)):
4776 if os.path.isdir(m.rel(f)):
4776 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4777 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4777 else:
4778 else:
4778 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4779 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4779 # missing files will generate a warning elsewhere
4780 # missing files will generate a warning elsewhere
4780 ret = 1
4781 ret = 1
4781
4782
4782 if force:
4783 if force:
4783 list = modified + deleted + clean + added
4784 list = modified + deleted + clean + added
4784 elif after:
4785 elif after:
4785 list = deleted
4786 list = deleted
4786 for f in modified + added + clean:
4787 for f in modified + added + clean:
4787 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4788 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4788 ret = 1
4789 ret = 1
4789 else:
4790 else:
4790 list = deleted + clean
4791 list = deleted + clean
4791 for f in modified:
4792 for f in modified:
4792 ui.warn(_('not removing %s: file is modified (use -f'
4793 ui.warn(_('not removing %s: file is modified (use -f'
4793 ' to force removal)\n') % m.rel(f))
4794 ' to force removal)\n') % m.rel(f))
4794 ret = 1
4795 ret = 1
4795 for f in added:
4796 for f in added:
4796 ui.warn(_('not removing %s: file has been marked for add'
4797 ui.warn(_('not removing %s: file has been marked for add'
4797 ' (use forget to undo)\n') % m.rel(f))
4798 ' (use forget to undo)\n') % m.rel(f))
4798 ret = 1
4799 ret = 1
4799
4800
4800 for f in sorted(list):
4801 for f in sorted(list):
4801 if ui.verbose or not m.exact(f):
4802 if ui.verbose or not m.exact(f):
4802 ui.status(_('removing %s\n') % m.rel(f))
4803 ui.status(_('removing %s\n') % m.rel(f))
4803
4804
4804 wlock = repo.wlock()
4805 wlock = repo.wlock()
4805 try:
4806 try:
4806 if not after:
4807 if not after:
4807 for f in list:
4808 for f in list:
4808 if f in added:
4809 if f in added:
4809 continue # we never unlink added files on remove
4810 continue # we never unlink added files on remove
4810 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4811 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4811 repo[None].forget(list)
4812 repo[None].forget(list)
4812 finally:
4813 finally:
4813 wlock.release()
4814 wlock.release()
4814
4815
4815 return ret
4816 return ret
4816
4817
4817 @command('rename|move|mv',
4818 @command('rename|move|mv',
4818 [('A', 'after', None, _('record a rename that has already occurred')),
4819 [('A', 'after', None, _('record a rename that has already occurred')),
4819 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4820 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4820 ] + walkopts + dryrunopts,
4821 ] + walkopts + dryrunopts,
4821 _('[OPTION]... SOURCE... DEST'))
4822 _('[OPTION]... SOURCE... DEST'))
4822 def rename(ui, repo, *pats, **opts):
4823 def rename(ui, repo, *pats, **opts):
4823 """rename files; equivalent of copy + remove
4824 """rename files; equivalent of copy + remove
4824
4825
4825 Mark dest as copies of sources; mark sources for deletion. If dest
4826 Mark dest as copies of sources; mark sources for deletion. If dest
4826 is a directory, copies are put in that directory. If dest is a
4827 is a directory, copies are put in that directory. If dest is a
4827 file, there can only be one source.
4828 file, there can only be one source.
4828
4829
4829 By default, this command copies the contents of files as they
4830 By default, this command copies the contents of files as they
4830 exist in the working directory. If invoked with -A/--after, the
4831 exist in the working directory. If invoked with -A/--after, the
4831 operation is recorded, but no copying is performed.
4832 operation is recorded, but no copying is performed.
4832
4833
4833 This command takes effect at the next commit. To undo a rename
4834 This command takes effect at the next commit. To undo a rename
4834 before that, see :hg:`revert`.
4835 before that, see :hg:`revert`.
4835
4836
4836 Returns 0 on success, 1 if errors are encountered.
4837 Returns 0 on success, 1 if errors are encountered.
4837 """
4838 """
4838 wlock = repo.wlock(False)
4839 wlock = repo.wlock(False)
4839 try:
4840 try:
4840 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4841 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4841 finally:
4842 finally:
4842 wlock.release()
4843 wlock.release()
4843
4844
4844 @command('resolve',
4845 @command('resolve',
4845 [('a', 'all', None, _('select all unresolved files')),
4846 [('a', 'all', None, _('select all unresolved files')),
4846 ('l', 'list', None, _('list state of files needing merge')),
4847 ('l', 'list', None, _('list state of files needing merge')),
4847 ('m', 'mark', None, _('mark files as resolved')),
4848 ('m', 'mark', None, _('mark files as resolved')),
4848 ('u', 'unmark', None, _('mark files as unresolved')),
4849 ('u', 'unmark', None, _('mark files as unresolved')),
4849 ('n', 'no-status', None, _('hide status prefix'))]
4850 ('n', 'no-status', None, _('hide status prefix'))]
4850 + mergetoolopts + walkopts,
4851 + mergetoolopts + walkopts,
4851 _('[OPTION]... [FILE]...'))
4852 _('[OPTION]... [FILE]...'))
4852 def resolve(ui, repo, *pats, **opts):
4853 def resolve(ui, repo, *pats, **opts):
4853 """redo merges or set/view the merge status of files
4854 """redo merges or set/view the merge status of files
4854
4855
4855 Merges with unresolved conflicts are often the result of
4856 Merges with unresolved conflicts are often the result of
4856 non-interactive merging using the ``internal:merge`` configuration
4857 non-interactive merging using the ``internal:merge`` configuration
4857 setting, or a command-line merge tool like ``diff3``. The resolve
4858 setting, or a command-line merge tool like ``diff3``. The resolve
4858 command is used to manage the files involved in a merge, after
4859 command is used to manage the files involved in a merge, after
4859 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4860 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4860 working directory must have two parents). See :hg:`help
4861 working directory must have two parents). See :hg:`help
4861 merge-tools` for information on configuring merge tools.
4862 merge-tools` for information on configuring merge tools.
4862
4863
4863 The resolve command can be used in the following ways:
4864 The resolve command can be used in the following ways:
4864
4865
4865 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4866 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4866 files, discarding any previous merge attempts. Re-merging is not
4867 files, discarding any previous merge attempts. Re-merging is not
4867 performed for files already marked as resolved. Use ``--all/-a``
4868 performed for files already marked as resolved. Use ``--all/-a``
4868 to select all unresolved files. ``--tool`` can be used to specify
4869 to select all unresolved files. ``--tool`` can be used to specify
4869 the merge tool used for the given files. It overrides the HGMERGE
4870 the merge tool used for the given files. It overrides the HGMERGE
4870 environment variable and your configuration files. Previous file
4871 environment variable and your configuration files. Previous file
4871 contents are saved with a ``.orig`` suffix.
4872 contents are saved with a ``.orig`` suffix.
4872
4873
4873 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4874 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4874 (e.g. after having manually fixed-up the files). The default is
4875 (e.g. after having manually fixed-up the files). The default is
4875 to mark all unresolved files.
4876 to mark all unresolved files.
4876
4877
4877 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4878 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4878 default is to mark all resolved files.
4879 default is to mark all resolved files.
4879
4880
4880 - :hg:`resolve -l`: list files which had or still have conflicts.
4881 - :hg:`resolve -l`: list files which had or still have conflicts.
4881 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4882 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4882
4883
4883 Note that Mercurial will not let you commit files with unresolved
4884 Note that Mercurial will not let you commit files with unresolved
4884 merge conflicts. You must use :hg:`resolve -m ...` before you can
4885 merge conflicts. You must use :hg:`resolve -m ...` before you can
4885 commit after a conflicting merge.
4886 commit after a conflicting merge.
4886
4887
4887 Returns 0 on success, 1 if any files fail a resolve attempt.
4888 Returns 0 on success, 1 if any files fail a resolve attempt.
4888 """
4889 """
4889
4890
4890 all, mark, unmark, show, nostatus = \
4891 all, mark, unmark, show, nostatus = \
4891 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4892 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4892
4893
4893 if (show and (mark or unmark)) or (mark and unmark):
4894 if (show and (mark or unmark)) or (mark and unmark):
4894 raise util.Abort(_("too many options specified"))
4895 raise util.Abort(_("too many options specified"))
4895 if pats and all:
4896 if pats and all:
4896 raise util.Abort(_("can't specify --all and patterns"))
4897 raise util.Abort(_("can't specify --all and patterns"))
4897 if not (all or pats or show or mark or unmark):
4898 if not (all or pats or show or mark or unmark):
4898 raise util.Abort(_('no files or directories specified; '
4899 raise util.Abort(_('no files or directories specified; '
4899 'use --all to remerge all files'))
4900 'use --all to remerge all files'))
4900
4901
4901 ms = mergemod.mergestate(repo)
4902 ms = mergemod.mergestate(repo)
4902 m = scmutil.match(repo[None], pats, opts)
4903 m = scmutil.match(repo[None], pats, opts)
4903 ret = 0
4904 ret = 0
4904
4905
4905 for f in ms:
4906 for f in ms:
4906 if m(f):
4907 if m(f):
4907 if show:
4908 if show:
4908 if nostatus:
4909 if nostatus:
4909 ui.write("%s\n" % f)
4910 ui.write("%s\n" % f)
4910 else:
4911 else:
4911 ui.write("%s %s\n" % (ms[f].upper(), f),
4912 ui.write("%s %s\n" % (ms[f].upper(), f),
4912 label='resolve.' +
4913 label='resolve.' +
4913 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4914 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4914 elif mark:
4915 elif mark:
4915 ms.mark(f, "r")
4916 ms.mark(f, "r")
4916 elif unmark:
4917 elif unmark:
4917 ms.mark(f, "u")
4918 ms.mark(f, "u")
4918 else:
4919 else:
4919 wctx = repo[None]
4920 wctx = repo[None]
4920 mctx = wctx.parents()[-1]
4921 mctx = wctx.parents()[-1]
4921
4922
4922 # backup pre-resolve (merge uses .orig for its own purposes)
4923 # backup pre-resolve (merge uses .orig for its own purposes)
4923 a = repo.wjoin(f)
4924 a = repo.wjoin(f)
4924 util.copyfile(a, a + ".resolve")
4925 util.copyfile(a, a + ".resolve")
4925
4926
4926 try:
4927 try:
4927 # resolve file
4928 # resolve file
4928 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4929 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4929 if ms.resolve(f, wctx, mctx):
4930 if ms.resolve(f, wctx, mctx):
4930 ret = 1
4931 ret = 1
4931 finally:
4932 finally:
4932 ui.setconfig('ui', 'forcemerge', '')
4933 ui.setconfig('ui', 'forcemerge', '')
4933 ms.commit()
4934 ms.commit()
4934
4935
4935 # replace filemerge's .orig file with our resolve file
4936 # replace filemerge's .orig file with our resolve file
4936 util.rename(a + ".resolve", a + ".orig")
4937 util.rename(a + ".resolve", a + ".orig")
4937
4938
4938 ms.commit()
4939 ms.commit()
4939 return ret
4940 return ret
4940
4941
4941 @command('revert',
4942 @command('revert',
4942 [('a', 'all', None, _('revert all changes when no arguments given')),
4943 [('a', 'all', None, _('revert all changes when no arguments given')),
4943 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4944 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4944 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4945 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4945 ('C', 'no-backup', None, _('do not save backup copies of files')),
4946 ('C', 'no-backup', None, _('do not save backup copies of files')),
4946 ] + walkopts + dryrunopts,
4947 ] + walkopts + dryrunopts,
4947 _('[OPTION]... [-r REV] [NAME]...'))
4948 _('[OPTION]... [-r REV] [NAME]...'))
4948 def revert(ui, repo, *pats, **opts):
4949 def revert(ui, repo, *pats, **opts):
4949 """restore files to their checkout state
4950 """restore files to their checkout state
4950
4951
4951 .. note::
4952 .. note::
4952 To check out earlier revisions, you should use :hg:`update REV`.
4953 To check out earlier revisions, you should use :hg:`update REV`.
4953 To cancel an uncommitted merge (and lose your changes),
4954 To cancel an uncommitted merge (and lose your changes),
4954 use :hg:`update --clean .`.
4955 use :hg:`update --clean .`.
4955
4956
4956 With no revision specified, revert the specified files or directories
4957 With no revision specified, revert the specified files or directories
4957 to the contents they had in the parent of the working directory.
4958 to the contents they had in the parent of the working directory.
4958 This restores the contents of files to an unmodified
4959 This restores the contents of files to an unmodified
4959 state and unschedules adds, removes, copies, and renames. If the
4960 state and unschedules adds, removes, copies, and renames. If the
4960 working directory has two parents, you must explicitly specify a
4961 working directory has two parents, you must explicitly specify a
4961 revision.
4962 revision.
4962
4963
4963 Using the -r/--rev or -d/--date options, revert the given files or
4964 Using the -r/--rev or -d/--date options, revert the given files or
4964 directories to their states as of a specific revision. Because
4965 directories to their states as of a specific revision. Because
4965 revert does not change the working directory parents, this will
4966 revert does not change the working directory parents, this will
4966 cause these files to appear modified. This can be helpful to "back
4967 cause these files to appear modified. This can be helpful to "back
4967 out" some or all of an earlier change. See :hg:`backout` for a
4968 out" some or all of an earlier change. See :hg:`backout` for a
4968 related method.
4969 related method.
4969
4970
4970 Modified files are saved with a .orig suffix before reverting.
4971 Modified files are saved with a .orig suffix before reverting.
4971 To disable these backups, use --no-backup.
4972 To disable these backups, use --no-backup.
4972
4973
4973 See :hg:`help dates` for a list of formats valid for -d/--date.
4974 See :hg:`help dates` for a list of formats valid for -d/--date.
4974
4975
4975 Returns 0 on success.
4976 Returns 0 on success.
4976 """
4977 """
4977
4978
4978 if opts.get("date"):
4979 if opts.get("date"):
4979 if opts.get("rev"):
4980 if opts.get("rev"):
4980 raise util.Abort(_("you can't specify a revision and a date"))
4981 raise util.Abort(_("you can't specify a revision and a date"))
4981 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4982 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4982
4983
4983 parent, p2 = repo.dirstate.parents()
4984 parent, p2 = repo.dirstate.parents()
4984 if not opts.get('rev') and p2 != nullid:
4985 if not opts.get('rev') and p2 != nullid:
4985 # revert after merge is a trap for new users (issue2915)
4986 # revert after merge is a trap for new users (issue2915)
4986 raise util.Abort(_('uncommitted merge with no revision specified'),
4987 raise util.Abort(_('uncommitted merge with no revision specified'),
4987 hint=_('use "hg update" or see "hg help revert"'))
4988 hint=_('use "hg update" or see "hg help revert"'))
4988
4989
4989 ctx = scmutil.revsingle(repo, opts.get('rev'))
4990 ctx = scmutil.revsingle(repo, opts.get('rev'))
4990
4991
4991 if not pats and not opts.get('all'):
4992 if not pats and not opts.get('all'):
4992 msg = _("no files or directories specified")
4993 msg = _("no files or directories specified")
4993 if p2 != nullid:
4994 if p2 != nullid:
4994 hint = _("uncommitted merge, use --all to discard all changes,"
4995 hint = _("uncommitted merge, use --all to discard all changes,"
4995 " or 'hg update -C .' to abort the merge")
4996 " or 'hg update -C .' to abort the merge")
4996 raise util.Abort(msg, hint=hint)
4997 raise util.Abort(msg, hint=hint)
4997 dirty = util.any(repo.status())
4998 dirty = util.any(repo.status())
4998 node = ctx.node()
4999 node = ctx.node()
4999 if node != parent:
5000 if node != parent:
5000 if dirty:
5001 if dirty:
5001 hint = _("uncommitted changes, use --all to discard all"
5002 hint = _("uncommitted changes, use --all to discard all"
5002 " changes, or 'hg update %s' to update") % ctx.rev()
5003 " changes, or 'hg update %s' to update") % ctx.rev()
5003 else:
5004 else:
5004 hint = _("use --all to revert all files,"
5005 hint = _("use --all to revert all files,"
5005 " or 'hg update %s' to update") % ctx.rev()
5006 " or 'hg update %s' to update") % ctx.rev()
5006 elif dirty:
5007 elif dirty:
5007 hint = _("uncommitted changes, use --all to discard all changes")
5008 hint = _("uncommitted changes, use --all to discard all changes")
5008 else:
5009 else:
5009 hint = _("use --all to revert all files")
5010 hint = _("use --all to revert all files")
5010 raise util.Abort(msg, hint=hint)
5011 raise util.Abort(msg, hint=hint)
5011
5012
5012 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5013 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5013
5014
5014 @command('rollback', dryrunopts +
5015 @command('rollback', dryrunopts +
5015 [('f', 'force', False, _('ignore safety measures'))])
5016 [('f', 'force', False, _('ignore safety measures'))])
5016 def rollback(ui, repo, **opts):
5017 def rollback(ui, repo, **opts):
5017 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5018 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5018
5019
5019 Please use :hg:`commit --amend` instead of rollback to correct
5020 Please use :hg:`commit --amend` instead of rollback to correct
5020 mistakes in the last commit.
5021 mistakes in the last commit.
5021
5022
5022 This command should be used with care. There is only one level of
5023 This command should be used with care. There is only one level of
5023 rollback, and there is no way to undo a rollback. It will also
5024 rollback, and there is no way to undo a rollback. It will also
5024 restore the dirstate at the time of the last transaction, losing
5025 restore the dirstate at the time of the last transaction, losing
5025 any dirstate changes since that time. This command does not alter
5026 any dirstate changes since that time. This command does not alter
5026 the working directory.
5027 the working directory.
5027
5028
5028 Transactions are used to encapsulate the effects of all commands
5029 Transactions are used to encapsulate the effects of all commands
5029 that create new changesets or propagate existing changesets into a
5030 that create new changesets or propagate existing changesets into a
5030 repository.
5031 repository.
5031
5032
5032 .. container:: verbose
5033 .. container:: verbose
5033
5034
5034 For example, the following commands are transactional, and their
5035 For example, the following commands are transactional, and their
5035 effects can be rolled back:
5036 effects can be rolled back:
5036
5037
5037 - commit
5038 - commit
5038 - import
5039 - import
5039 - pull
5040 - pull
5040 - push (with this repository as the destination)
5041 - push (with this repository as the destination)
5041 - unbundle
5042 - unbundle
5042
5043
5043 To avoid permanent data loss, rollback will refuse to rollback a
5044 To avoid permanent data loss, rollback will refuse to rollback a
5044 commit transaction if it isn't checked out. Use --force to
5045 commit transaction if it isn't checked out. Use --force to
5045 override this protection.
5046 override this protection.
5046
5047
5047 This command is not intended for use on public repositories. Once
5048 This command is not intended for use on public repositories. Once
5048 changes are visible for pull by other users, rolling a transaction
5049 changes are visible for pull by other users, rolling a transaction
5049 back locally is ineffective (someone else may already have pulled
5050 back locally is ineffective (someone else may already have pulled
5050 the changes). Furthermore, a race is possible with readers of the
5051 the changes). Furthermore, a race is possible with readers of the
5051 repository; for example an in-progress pull from the repository
5052 repository; for example an in-progress pull from the repository
5052 may fail if a rollback is performed.
5053 may fail if a rollback is performed.
5053
5054
5054 Returns 0 on success, 1 if no rollback data is available.
5055 Returns 0 on success, 1 if no rollback data is available.
5055 """
5056 """
5056 return repo.rollback(dryrun=opts.get('dry_run'),
5057 return repo.rollback(dryrun=opts.get('dry_run'),
5057 force=opts.get('force'))
5058 force=opts.get('force'))
5058
5059
5059 @command('root', [])
5060 @command('root', [])
5060 def root(ui, repo):
5061 def root(ui, repo):
5061 """print the root (top) of the current working directory
5062 """print the root (top) of the current working directory
5062
5063
5063 Print the root directory of the current repository.
5064 Print the root directory of the current repository.
5064
5065
5065 Returns 0 on success.
5066 Returns 0 on success.
5066 """
5067 """
5067 ui.write(repo.root + "\n")
5068 ui.write(repo.root + "\n")
5068
5069
5069 @command('^serve',
5070 @command('^serve',
5070 [('A', 'accesslog', '', _('name of access log file to write to'),
5071 [('A', 'accesslog', '', _('name of access log file to write to'),
5071 _('FILE')),
5072 _('FILE')),
5072 ('d', 'daemon', None, _('run server in background')),
5073 ('d', 'daemon', None, _('run server in background')),
5073 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5074 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5074 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5075 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5075 # use string type, then we can check if something was passed
5076 # use string type, then we can check if something was passed
5076 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5077 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5077 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5078 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5078 _('ADDR')),
5079 _('ADDR')),
5079 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5080 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5080 _('PREFIX')),
5081 _('PREFIX')),
5081 ('n', 'name', '',
5082 ('n', 'name', '',
5082 _('name to show in web pages (default: working directory)'), _('NAME')),
5083 _('name to show in web pages (default: working directory)'), _('NAME')),
5083 ('', 'web-conf', '',
5084 ('', 'web-conf', '',
5084 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5085 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5085 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5086 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5086 _('FILE')),
5087 _('FILE')),
5087 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5088 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5088 ('', 'stdio', None, _('for remote clients')),
5089 ('', 'stdio', None, _('for remote clients')),
5089 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5090 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5090 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5091 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5091 ('', 'style', '', _('template style to use'), _('STYLE')),
5092 ('', 'style', '', _('template style to use'), _('STYLE')),
5092 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5093 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5093 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5094 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5094 _('[OPTION]...'))
5095 _('[OPTION]...'))
5095 def serve(ui, repo, **opts):
5096 def serve(ui, repo, **opts):
5096 """start stand-alone webserver
5097 """start stand-alone webserver
5097
5098
5098 Start a local HTTP repository browser and pull server. You can use
5099 Start a local HTTP repository browser and pull server. You can use
5099 this for ad-hoc sharing and browsing of repositories. It is
5100 this for ad-hoc sharing and browsing of repositories. It is
5100 recommended to use a real web server to serve a repository for
5101 recommended to use a real web server to serve a repository for
5101 longer periods of time.
5102 longer periods of time.
5102
5103
5103 Please note that the server does not implement access control.
5104 Please note that the server does not implement access control.
5104 This means that, by default, anybody can read from the server and
5105 This means that, by default, anybody can read from the server and
5105 nobody can write to it by default. Set the ``web.allow_push``
5106 nobody can write to it by default. Set the ``web.allow_push``
5106 option to ``*`` to allow everybody to push to the server. You
5107 option to ``*`` to allow everybody to push to the server. You
5107 should use a real web server if you need to authenticate users.
5108 should use a real web server if you need to authenticate users.
5108
5109
5109 By default, the server logs accesses to stdout and errors to
5110 By default, the server logs accesses to stdout and errors to
5110 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5111 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5111 files.
5112 files.
5112
5113
5113 To have the server choose a free port number to listen on, specify
5114 To have the server choose a free port number to listen on, specify
5114 a port number of 0; in this case, the server will print the port
5115 a port number of 0; in this case, the server will print the port
5115 number it uses.
5116 number it uses.
5116
5117
5117 Returns 0 on success.
5118 Returns 0 on success.
5118 """
5119 """
5119
5120
5120 if opts["stdio"] and opts["cmdserver"]:
5121 if opts["stdio"] and opts["cmdserver"]:
5121 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5122 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5122
5123
5123 def checkrepo():
5124 def checkrepo():
5124 if repo is None:
5125 if repo is None:
5125 raise error.RepoError(_("there is no Mercurial repository here"
5126 raise error.RepoError(_("there is no Mercurial repository here"
5126 " (.hg not found)"))
5127 " (.hg not found)"))
5127
5128
5128 if opts["stdio"]:
5129 if opts["stdio"]:
5129 checkrepo()
5130 checkrepo()
5130 s = sshserver.sshserver(ui, repo)
5131 s = sshserver.sshserver(ui, repo)
5131 s.serve_forever()
5132 s.serve_forever()
5132
5133
5133 if opts["cmdserver"]:
5134 if opts["cmdserver"]:
5134 checkrepo()
5135 checkrepo()
5135 s = commandserver.server(ui, repo, opts["cmdserver"])
5136 s = commandserver.server(ui, repo, opts["cmdserver"])
5136 return s.serve()
5137 return s.serve()
5137
5138
5138 # this way we can check if something was given in the command-line
5139 # this way we can check if something was given in the command-line
5139 if opts.get('port'):
5140 if opts.get('port'):
5140 opts['port'] = util.getport(opts.get('port'))
5141 opts['port'] = util.getport(opts.get('port'))
5141
5142
5142 baseui = repo and repo.baseui or ui
5143 baseui = repo and repo.baseui or ui
5143 optlist = ("name templates style address port prefix ipv6"
5144 optlist = ("name templates style address port prefix ipv6"
5144 " accesslog errorlog certificate encoding")
5145 " accesslog errorlog certificate encoding")
5145 for o in optlist.split():
5146 for o in optlist.split():
5146 val = opts.get(o, '')
5147 val = opts.get(o, '')
5147 if val in (None, ''): # should check against default options instead
5148 if val in (None, ''): # should check against default options instead
5148 continue
5149 continue
5149 baseui.setconfig("web", o, val)
5150 baseui.setconfig("web", o, val)
5150 if repo and repo.ui != baseui:
5151 if repo and repo.ui != baseui:
5151 repo.ui.setconfig("web", o, val)
5152 repo.ui.setconfig("web", o, val)
5152
5153
5153 o = opts.get('web_conf') or opts.get('webdir_conf')
5154 o = opts.get('web_conf') or opts.get('webdir_conf')
5154 if not o:
5155 if not o:
5155 if not repo:
5156 if not repo:
5156 raise error.RepoError(_("there is no Mercurial repository"
5157 raise error.RepoError(_("there is no Mercurial repository"
5157 " here (.hg not found)"))
5158 " here (.hg not found)"))
5158 o = repo
5159 o = repo
5159
5160
5160 app = hgweb.hgweb(o, baseui=baseui)
5161 app = hgweb.hgweb(o, baseui=baseui)
5161
5162
5162 class service(object):
5163 class service(object):
5163 def init(self):
5164 def init(self):
5164 util.setsignalhandler()
5165 util.setsignalhandler()
5165 self.httpd = hgweb.server.create_server(ui, app)
5166 self.httpd = hgweb.server.create_server(ui, app)
5166
5167
5167 if opts['port'] and not ui.verbose:
5168 if opts['port'] and not ui.verbose:
5168 return
5169 return
5169
5170
5170 if self.httpd.prefix:
5171 if self.httpd.prefix:
5171 prefix = self.httpd.prefix.strip('/') + '/'
5172 prefix = self.httpd.prefix.strip('/') + '/'
5172 else:
5173 else:
5173 prefix = ''
5174 prefix = ''
5174
5175
5175 port = ':%d' % self.httpd.port
5176 port = ':%d' % self.httpd.port
5176 if port == ':80':
5177 if port == ':80':
5177 port = ''
5178 port = ''
5178
5179
5179 bindaddr = self.httpd.addr
5180 bindaddr = self.httpd.addr
5180 if bindaddr == '0.0.0.0':
5181 if bindaddr == '0.0.0.0':
5181 bindaddr = '*'
5182 bindaddr = '*'
5182 elif ':' in bindaddr: # IPv6
5183 elif ':' in bindaddr: # IPv6
5183 bindaddr = '[%s]' % bindaddr
5184 bindaddr = '[%s]' % bindaddr
5184
5185
5185 fqaddr = self.httpd.fqaddr
5186 fqaddr = self.httpd.fqaddr
5186 if ':' in fqaddr:
5187 if ':' in fqaddr:
5187 fqaddr = '[%s]' % fqaddr
5188 fqaddr = '[%s]' % fqaddr
5188 if opts['port']:
5189 if opts['port']:
5189 write = ui.status
5190 write = ui.status
5190 else:
5191 else:
5191 write = ui.write
5192 write = ui.write
5192 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5193 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5193 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5194 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5194
5195
5195 def run(self):
5196 def run(self):
5196 self.httpd.serve_forever()
5197 self.httpd.serve_forever()
5197
5198
5198 service = service()
5199 service = service()
5199
5200
5200 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5201 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5201
5202
5202 @command('showconfig|debugconfig',
5203 @command('showconfig|debugconfig',
5203 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5204 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5204 _('[-u] [NAME]...'))
5205 _('[-u] [NAME]...'))
5205 def showconfig(ui, repo, *values, **opts):
5206 def showconfig(ui, repo, *values, **opts):
5206 """show combined config settings from all hgrc files
5207 """show combined config settings from all hgrc files
5207
5208
5208 With no arguments, print names and values of all config items.
5209 With no arguments, print names and values of all config items.
5209
5210
5210 With one argument of the form section.name, print just the value
5211 With one argument of the form section.name, print just the value
5211 of that config item.
5212 of that config item.
5212
5213
5213 With multiple arguments, print names and values of all config
5214 With multiple arguments, print names and values of all config
5214 items with matching section names.
5215 items with matching section names.
5215
5216
5216 With --debug, the source (filename and line number) is printed
5217 With --debug, the source (filename and line number) is printed
5217 for each config item.
5218 for each config item.
5218
5219
5219 Returns 0 on success.
5220 Returns 0 on success.
5220 """
5221 """
5221
5222
5222 for f in scmutil.rcpath():
5223 for f in scmutil.rcpath():
5223 ui.debug('read config from: %s\n' % f)
5224 ui.debug('read config from: %s\n' % f)
5224 untrusted = bool(opts.get('untrusted'))
5225 untrusted = bool(opts.get('untrusted'))
5225 if values:
5226 if values:
5226 sections = [v for v in values if '.' not in v]
5227 sections = [v for v in values if '.' not in v]
5227 items = [v for v in values if '.' in v]
5228 items = [v for v in values if '.' in v]
5228 if len(items) > 1 or items and sections:
5229 if len(items) > 1 or items and sections:
5229 raise util.Abort(_('only one config item permitted'))
5230 raise util.Abort(_('only one config item permitted'))
5230 for section, name, value in ui.walkconfig(untrusted=untrusted):
5231 for section, name, value in ui.walkconfig(untrusted=untrusted):
5231 value = str(value).replace('\n', '\\n')
5232 value = str(value).replace('\n', '\\n')
5232 sectname = section + '.' + name
5233 sectname = section + '.' + name
5233 if values:
5234 if values:
5234 for v in values:
5235 for v in values:
5235 if v == section:
5236 if v == section:
5236 ui.debug('%s: ' %
5237 ui.debug('%s: ' %
5237 ui.configsource(section, name, untrusted))
5238 ui.configsource(section, name, untrusted))
5238 ui.write('%s=%s\n' % (sectname, value))
5239 ui.write('%s=%s\n' % (sectname, value))
5239 elif v == sectname:
5240 elif v == sectname:
5240 ui.debug('%s: ' %
5241 ui.debug('%s: ' %
5241 ui.configsource(section, name, untrusted))
5242 ui.configsource(section, name, untrusted))
5242 ui.write(value, '\n')
5243 ui.write(value, '\n')
5243 else:
5244 else:
5244 ui.debug('%s: ' %
5245 ui.debug('%s: ' %
5245 ui.configsource(section, name, untrusted))
5246 ui.configsource(section, name, untrusted))
5246 ui.write('%s=%s\n' % (sectname, value))
5247 ui.write('%s=%s\n' % (sectname, value))
5247
5248
5248 @command('^status|st',
5249 @command('^status|st',
5249 [('A', 'all', None, _('show status of all files')),
5250 [('A', 'all', None, _('show status of all files')),
5250 ('m', 'modified', None, _('show only modified files')),
5251 ('m', 'modified', None, _('show only modified files')),
5251 ('a', 'added', None, _('show only added files')),
5252 ('a', 'added', None, _('show only added files')),
5252 ('r', 'removed', None, _('show only removed files')),
5253 ('r', 'removed', None, _('show only removed files')),
5253 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5254 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5254 ('c', 'clean', None, _('show only files without changes')),
5255 ('c', 'clean', None, _('show only files without changes')),
5255 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5256 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5256 ('i', 'ignored', None, _('show only ignored files')),
5257 ('i', 'ignored', None, _('show only ignored files')),
5257 ('n', 'no-status', None, _('hide status prefix')),
5258 ('n', 'no-status', None, _('hide status prefix')),
5258 ('C', 'copies', None, _('show source of copied files')),
5259 ('C', 'copies', None, _('show source of copied files')),
5259 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5260 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5260 ('', 'rev', [], _('show difference from revision'), _('REV')),
5261 ('', 'rev', [], _('show difference from revision'), _('REV')),
5261 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5262 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5262 ] + walkopts + subrepoopts,
5263 ] + walkopts + subrepoopts,
5263 _('[OPTION]... [FILE]...'))
5264 _('[OPTION]... [FILE]...'))
5264 def status(ui, repo, *pats, **opts):
5265 def status(ui, repo, *pats, **opts):
5265 """show changed files in the working directory
5266 """show changed files in the working directory
5266
5267
5267 Show status of files in the repository. If names are given, only
5268 Show status of files in the repository. If names are given, only
5268 files that match are shown. Files that are clean or ignored or
5269 files that match are shown. Files that are clean or ignored or
5269 the source of a copy/move operation, are not listed unless
5270 the source of a copy/move operation, are not listed unless
5270 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5271 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5271 Unless options described with "show only ..." are given, the
5272 Unless options described with "show only ..." are given, the
5272 options -mardu are used.
5273 options -mardu are used.
5273
5274
5274 Option -q/--quiet hides untracked (unknown and ignored) files
5275 Option -q/--quiet hides untracked (unknown and ignored) files
5275 unless explicitly requested with -u/--unknown or -i/--ignored.
5276 unless explicitly requested with -u/--unknown or -i/--ignored.
5276
5277
5277 .. note::
5278 .. note::
5278 status may appear to disagree with diff if permissions have
5279 status may appear to disagree with diff if permissions have
5279 changed or a merge has occurred. The standard diff format does
5280 changed or a merge has occurred. The standard diff format does
5280 not report permission changes and diff only reports changes
5281 not report permission changes and diff only reports changes
5281 relative to one merge parent.
5282 relative to one merge parent.
5282
5283
5283 If one revision is given, it is used as the base revision.
5284 If one revision is given, it is used as the base revision.
5284 If two revisions are given, the differences between them are
5285 If two revisions are given, the differences between them are
5285 shown. The --change option can also be used as a shortcut to list
5286 shown. The --change option can also be used as a shortcut to list
5286 the changed files of a revision from its first parent.
5287 the changed files of a revision from its first parent.
5287
5288
5288 The codes used to show the status of files are::
5289 The codes used to show the status of files are::
5289
5290
5290 M = modified
5291 M = modified
5291 A = added
5292 A = added
5292 R = removed
5293 R = removed
5293 C = clean
5294 C = clean
5294 ! = missing (deleted by non-hg command, but still tracked)
5295 ! = missing (deleted by non-hg command, but still tracked)
5295 ? = not tracked
5296 ? = not tracked
5296 I = ignored
5297 I = ignored
5297 = origin of the previous file listed as A (added)
5298 = origin of the previous file listed as A (added)
5298
5299
5299 .. container:: verbose
5300 .. container:: verbose
5300
5301
5301 Examples:
5302 Examples:
5302
5303
5303 - show changes in the working directory relative to a
5304 - show changes in the working directory relative to a
5304 changeset::
5305 changeset::
5305
5306
5306 hg status --rev 9353
5307 hg status --rev 9353
5307
5308
5308 - show all changes including copies in an existing changeset::
5309 - show all changes including copies in an existing changeset::
5309
5310
5310 hg status --copies --change 9353
5311 hg status --copies --change 9353
5311
5312
5312 - get a NUL separated list of added files, suitable for xargs::
5313 - get a NUL separated list of added files, suitable for xargs::
5313
5314
5314 hg status -an0
5315 hg status -an0
5315
5316
5316 Returns 0 on success.
5317 Returns 0 on success.
5317 """
5318 """
5318
5319
5319 revs = opts.get('rev')
5320 revs = opts.get('rev')
5320 change = opts.get('change')
5321 change = opts.get('change')
5321
5322
5322 if revs and change:
5323 if revs and change:
5323 msg = _('cannot specify --rev and --change at the same time')
5324 msg = _('cannot specify --rev and --change at the same time')
5324 raise util.Abort(msg)
5325 raise util.Abort(msg)
5325 elif change:
5326 elif change:
5326 node2 = scmutil.revsingle(repo, change, None).node()
5327 node2 = scmutil.revsingle(repo, change, None).node()
5327 node1 = repo[node2].p1().node()
5328 node1 = repo[node2].p1().node()
5328 else:
5329 else:
5329 node1, node2 = scmutil.revpair(repo, revs)
5330 node1, node2 = scmutil.revpair(repo, revs)
5330
5331
5331 cwd = (pats and repo.getcwd()) or ''
5332 cwd = (pats and repo.getcwd()) or ''
5332 end = opts.get('print0') and '\0' or '\n'
5333 end = opts.get('print0') and '\0' or '\n'
5333 copy = {}
5334 copy = {}
5334 states = 'modified added removed deleted unknown ignored clean'.split()
5335 states = 'modified added removed deleted unknown ignored clean'.split()
5335 show = [k for k in states if opts.get(k)]
5336 show = [k for k in states if opts.get(k)]
5336 if opts.get('all'):
5337 if opts.get('all'):
5337 show += ui.quiet and (states[:4] + ['clean']) or states
5338 show += ui.quiet and (states[:4] + ['clean']) or states
5338 if not show:
5339 if not show:
5339 show = ui.quiet and states[:4] or states[:5]
5340 show = ui.quiet and states[:4] or states[:5]
5340
5341
5341 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5342 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5342 'ignored' in show, 'clean' in show, 'unknown' in show,
5343 'ignored' in show, 'clean' in show, 'unknown' in show,
5343 opts.get('subrepos'))
5344 opts.get('subrepos'))
5344 changestates = zip(states, 'MAR!?IC', stat)
5345 changestates = zip(states, 'MAR!?IC', stat)
5345
5346
5346 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5347 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5347 copy = copies.pathcopies(repo[node1], repo[node2])
5348 copy = copies.pathcopies(repo[node1], repo[node2])
5348
5349
5349 fm = ui.formatter('status', opts)
5350 fm = ui.formatter('status', opts)
5350 fmt = '%s' + end
5351 fmt = '%s' + end
5351 showchar = not opts.get('no_status')
5352 showchar = not opts.get('no_status')
5352
5353
5353 for state, char, files in changestates:
5354 for state, char, files in changestates:
5354 if state in show:
5355 if state in show:
5355 label = 'status.' + state
5356 label = 'status.' + state
5356 for f in files:
5357 for f in files:
5357 fm.startitem()
5358 fm.startitem()
5358 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5359 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5359 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5360 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5360 if f in copy:
5361 if f in copy:
5361 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5362 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5362 label='status.copied')
5363 label='status.copied')
5363 fm.end()
5364 fm.end()
5364
5365
5365 @command('^summary|sum',
5366 @command('^summary|sum',
5366 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5367 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5367 def summary(ui, repo, **opts):
5368 def summary(ui, repo, **opts):
5368 """summarize working directory state
5369 """summarize working directory state
5369
5370
5370 This generates a brief summary of the working directory state,
5371 This generates a brief summary of the working directory state,
5371 including parents, branch, commit status, and available updates.
5372 including parents, branch, commit status, and available updates.
5372
5373
5373 With the --remote option, this will check the default paths for
5374 With the --remote option, this will check the default paths for
5374 incoming and outgoing changes. This can be time-consuming.
5375 incoming and outgoing changes. This can be time-consuming.
5375
5376
5376 Returns 0 on success.
5377 Returns 0 on success.
5377 """
5378 """
5378
5379
5379 ctx = repo[None]
5380 ctx = repo[None]
5380 parents = ctx.parents()
5381 parents = ctx.parents()
5381 pnode = parents[0].node()
5382 pnode = parents[0].node()
5382 marks = []
5383 marks = []
5383
5384
5384 for p in parents:
5385 for p in parents:
5385 # label with log.changeset (instead of log.parent) since this
5386 # label with log.changeset (instead of log.parent) since this
5386 # shows a working directory parent *changeset*:
5387 # shows a working directory parent *changeset*:
5387 # i18n: column positioning for "hg summary"
5388 # i18n: column positioning for "hg summary"
5388 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5389 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5389 label='log.changeset changeset.%s' % p.phasestr())
5390 label='log.changeset changeset.%s' % p.phasestr())
5390 ui.write(' '.join(p.tags()), label='log.tag')
5391 ui.write(' '.join(p.tags()), label='log.tag')
5391 if p.bookmarks():
5392 if p.bookmarks():
5392 marks.extend(p.bookmarks())
5393 marks.extend(p.bookmarks())
5393 if p.rev() == -1:
5394 if p.rev() == -1:
5394 if not len(repo):
5395 if not len(repo):
5395 ui.write(_(' (empty repository)'))
5396 ui.write(_(' (empty repository)'))
5396 else:
5397 else:
5397 ui.write(_(' (no revision checked out)'))
5398 ui.write(_(' (no revision checked out)'))
5398 ui.write('\n')
5399 ui.write('\n')
5399 if p.description():
5400 if p.description():
5400 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5401 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5401 label='log.summary')
5402 label='log.summary')
5402
5403
5403 branch = ctx.branch()
5404 branch = ctx.branch()
5404 bheads = repo.branchheads(branch)
5405 bheads = repo.branchheads(branch)
5405 # i18n: column positioning for "hg summary"
5406 # i18n: column positioning for "hg summary"
5406 m = _('branch: %s\n') % branch
5407 m = _('branch: %s\n') % branch
5407 if branch != 'default':
5408 if branch != 'default':
5408 ui.write(m, label='log.branch')
5409 ui.write(m, label='log.branch')
5409 else:
5410 else:
5410 ui.status(m, label='log.branch')
5411 ui.status(m, label='log.branch')
5411
5412
5412 if marks:
5413 if marks:
5413 current = repo._bookmarkcurrent
5414 current = repo._bookmarkcurrent
5414 # i18n: column positioning for "hg summary"
5415 # i18n: column positioning for "hg summary"
5415 ui.write(_('bookmarks:'), label='log.bookmark')
5416 ui.write(_('bookmarks:'), label='log.bookmark')
5416 if current is not None:
5417 if current is not None:
5417 if current in marks:
5418 if current in marks:
5418 ui.write(' *' + current, label='bookmarks.current')
5419 ui.write(' *' + current, label='bookmarks.current')
5419 marks.remove(current)
5420 marks.remove(current)
5420 else:
5421 else:
5421 ui.write(' [%s]' % current, label='bookmarks.current')
5422 ui.write(' [%s]' % current, label='bookmarks.current')
5422 for m in marks:
5423 for m in marks:
5423 ui.write(' ' + m, label='log.bookmark')
5424 ui.write(' ' + m, label='log.bookmark')
5424 ui.write('\n', label='log.bookmark')
5425 ui.write('\n', label='log.bookmark')
5425
5426
5426 st = list(repo.status(unknown=True))[:6]
5427 st = list(repo.status(unknown=True))[:6]
5427
5428
5428 c = repo.dirstate.copies()
5429 c = repo.dirstate.copies()
5429 copied, renamed = [], []
5430 copied, renamed = [], []
5430 for d, s in c.iteritems():
5431 for d, s in c.iteritems():
5431 if s in st[2]:
5432 if s in st[2]:
5432 st[2].remove(s)
5433 st[2].remove(s)
5433 renamed.append(d)
5434 renamed.append(d)
5434 else:
5435 else:
5435 copied.append(d)
5436 copied.append(d)
5436 if d in st[1]:
5437 if d in st[1]:
5437 st[1].remove(d)
5438 st[1].remove(d)
5438 st.insert(3, renamed)
5439 st.insert(3, renamed)
5439 st.insert(4, copied)
5440 st.insert(4, copied)
5440
5441
5441 ms = mergemod.mergestate(repo)
5442 ms = mergemod.mergestate(repo)
5442 st.append([f for f in ms if ms[f] == 'u'])
5443 st.append([f for f in ms if ms[f] == 'u'])
5443
5444
5444 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5445 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5445 st.append(subs)
5446 st.append(subs)
5446
5447
5447 labels = [ui.label(_('%d modified'), 'status.modified'),
5448 labels = [ui.label(_('%d modified'), 'status.modified'),
5448 ui.label(_('%d added'), 'status.added'),
5449 ui.label(_('%d added'), 'status.added'),
5449 ui.label(_('%d removed'), 'status.removed'),
5450 ui.label(_('%d removed'), 'status.removed'),
5450 ui.label(_('%d renamed'), 'status.copied'),
5451 ui.label(_('%d renamed'), 'status.copied'),
5451 ui.label(_('%d copied'), 'status.copied'),
5452 ui.label(_('%d copied'), 'status.copied'),
5452 ui.label(_('%d deleted'), 'status.deleted'),
5453 ui.label(_('%d deleted'), 'status.deleted'),
5453 ui.label(_('%d unknown'), 'status.unknown'),
5454 ui.label(_('%d unknown'), 'status.unknown'),
5454 ui.label(_('%d ignored'), 'status.ignored'),
5455 ui.label(_('%d ignored'), 'status.ignored'),
5455 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5456 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5456 ui.label(_('%d subrepos'), 'status.modified')]
5457 ui.label(_('%d subrepos'), 'status.modified')]
5457 t = []
5458 t = []
5458 for s, l in zip(st, labels):
5459 for s, l in zip(st, labels):
5459 if s:
5460 if s:
5460 t.append(l % len(s))
5461 t.append(l % len(s))
5461
5462
5462 t = ', '.join(t)
5463 t = ', '.join(t)
5463 cleanworkdir = False
5464 cleanworkdir = False
5464
5465
5465 if len(parents) > 1:
5466 if len(parents) > 1:
5466 t += _(' (merge)')
5467 t += _(' (merge)')
5467 elif branch != parents[0].branch():
5468 elif branch != parents[0].branch():
5468 t += _(' (new branch)')
5469 t += _(' (new branch)')
5469 elif (parents[0].closesbranch() and
5470 elif (parents[0].closesbranch() and
5470 pnode in repo.branchheads(branch, closed=True)):
5471 pnode in repo.branchheads(branch, closed=True)):
5471 t += _(' (head closed)')
5472 t += _(' (head closed)')
5472 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5473 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5473 t += _(' (clean)')
5474 t += _(' (clean)')
5474 cleanworkdir = True
5475 cleanworkdir = True
5475 elif pnode not in bheads:
5476 elif pnode not in bheads:
5476 t += _(' (new branch head)')
5477 t += _(' (new branch head)')
5477
5478
5478 if cleanworkdir:
5479 if cleanworkdir:
5479 # i18n: column positioning for "hg summary"
5480 # i18n: column positioning for "hg summary"
5480 ui.status(_('commit: %s\n') % t.strip())
5481 ui.status(_('commit: %s\n') % t.strip())
5481 else:
5482 else:
5482 # i18n: column positioning for "hg summary"
5483 # i18n: column positioning for "hg summary"
5483 ui.write(_('commit: %s\n') % t.strip())
5484 ui.write(_('commit: %s\n') % t.strip())
5484
5485
5485 # all ancestors of branch heads - all ancestors of parent = new csets
5486 # all ancestors of branch heads - all ancestors of parent = new csets
5486 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5487 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5487 bheads))
5488 bheads))
5488
5489
5489 if new == 0:
5490 if new == 0:
5490 # i18n: column positioning for "hg summary"
5491 # i18n: column positioning for "hg summary"
5491 ui.status(_('update: (current)\n'))
5492 ui.status(_('update: (current)\n'))
5492 elif pnode not in bheads:
5493 elif pnode not in bheads:
5493 # i18n: column positioning for "hg summary"
5494 # i18n: column positioning for "hg summary"
5494 ui.write(_('update: %d new changesets (update)\n') % new)
5495 ui.write(_('update: %d new changesets (update)\n') % new)
5495 else:
5496 else:
5496 # i18n: column positioning for "hg summary"
5497 # i18n: column positioning for "hg summary"
5497 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5498 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5498 (new, len(bheads)))
5499 (new, len(bheads)))
5499
5500
5500 cmdutil.summaryhooks(ui, repo)
5501 cmdutil.summaryhooks(ui, repo)
5501
5502
5502 if opts.get('remote'):
5503 if opts.get('remote'):
5503 t = []
5504 t = []
5504 source, branches = hg.parseurl(ui.expandpath('default'))
5505 source, branches = hg.parseurl(ui.expandpath('default'))
5505 sbranch = branches[0]
5506 sbranch = branches[0]
5506 other = hg.peer(repo, {}, source)
5507 other = hg.peer(repo, {}, source)
5507 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5508 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5508 if revs:
5509 if revs:
5509 revs = [other.lookup(rev) for rev in revs]
5510 revs = [other.lookup(rev) for rev in revs]
5510 ui.debug('comparing with %s\n' % util.hidepassword(source))
5511 ui.debug('comparing with %s\n' % util.hidepassword(source))
5511 repo.ui.pushbuffer()
5512 repo.ui.pushbuffer()
5512 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5513 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5513 _common, incoming, _rheads = commoninc
5514 _common, incoming, _rheads = commoninc
5514 repo.ui.popbuffer()
5515 repo.ui.popbuffer()
5515 if incoming:
5516 if incoming:
5516 t.append(_('1 or more incoming'))
5517 t.append(_('1 or more incoming'))
5517
5518
5518 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5519 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5519 dbranch = branches[0]
5520 dbranch = branches[0]
5520 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5521 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5521 if source != dest:
5522 if source != dest:
5522 other = hg.peer(repo, {}, dest)
5523 other = hg.peer(repo, {}, dest)
5523 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5524 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5524 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5525 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5525 commoninc = None
5526 commoninc = None
5526 if revs:
5527 if revs:
5527 revs = [repo.lookup(rev) for rev in revs]
5528 revs = [repo.lookup(rev) for rev in revs]
5528 repo.ui.pushbuffer()
5529 repo.ui.pushbuffer()
5529 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5530 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5530 commoninc=commoninc)
5531 commoninc=commoninc)
5531 repo.ui.popbuffer()
5532 repo.ui.popbuffer()
5532 o = outgoing.missing
5533 o = outgoing.missing
5533 if o:
5534 if o:
5534 t.append(_('%d outgoing') % len(o))
5535 t.append(_('%d outgoing') % len(o))
5535 if 'bookmarks' in other.listkeys('namespaces'):
5536 if 'bookmarks' in other.listkeys('namespaces'):
5536 lmarks = repo.listkeys('bookmarks')
5537 lmarks = repo.listkeys('bookmarks')
5537 rmarks = other.listkeys('bookmarks')
5538 rmarks = other.listkeys('bookmarks')
5538 diff = set(rmarks) - set(lmarks)
5539 diff = set(rmarks) - set(lmarks)
5539 if len(diff) > 0:
5540 if len(diff) > 0:
5540 t.append(_('%d incoming bookmarks') % len(diff))
5541 t.append(_('%d incoming bookmarks') % len(diff))
5541 diff = set(lmarks) - set(rmarks)
5542 diff = set(lmarks) - set(rmarks)
5542 if len(diff) > 0:
5543 if len(diff) > 0:
5543 t.append(_('%d outgoing bookmarks') % len(diff))
5544 t.append(_('%d outgoing bookmarks') % len(diff))
5544
5545
5545 if t:
5546 if t:
5546 # i18n: column positioning for "hg summary"
5547 # i18n: column positioning for "hg summary"
5547 ui.write(_('remote: %s\n') % (', '.join(t)))
5548 ui.write(_('remote: %s\n') % (', '.join(t)))
5548 else:
5549 else:
5549 # i18n: column positioning for "hg summary"
5550 # i18n: column positioning for "hg summary"
5550 ui.status(_('remote: (synced)\n'))
5551 ui.status(_('remote: (synced)\n'))
5551
5552
5552 @command('tag',
5553 @command('tag',
5553 [('f', 'force', None, _('force tag')),
5554 [('f', 'force', None, _('force tag')),
5554 ('l', 'local', None, _('make the tag local')),
5555 ('l', 'local', None, _('make the tag local')),
5555 ('r', 'rev', '', _('revision to tag'), _('REV')),
5556 ('r', 'rev', '', _('revision to tag'), _('REV')),
5556 ('', 'remove', None, _('remove a tag')),
5557 ('', 'remove', None, _('remove a tag')),
5557 # -l/--local is already there, commitopts cannot be used
5558 # -l/--local is already there, commitopts cannot be used
5558 ('e', 'edit', None, _('edit commit message')),
5559 ('e', 'edit', None, _('edit commit message')),
5559 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5560 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5560 ] + commitopts2,
5561 ] + commitopts2,
5561 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5562 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5562 def tag(ui, repo, name1, *names, **opts):
5563 def tag(ui, repo, name1, *names, **opts):
5563 """add one or more tags for the current or given revision
5564 """add one or more tags for the current or given revision
5564
5565
5565 Name a particular revision using <name>.
5566 Name a particular revision using <name>.
5566
5567
5567 Tags are used to name particular revisions of the repository and are
5568 Tags are used to name particular revisions of the repository and are
5568 very useful to compare different revisions, to go back to significant
5569 very useful to compare different revisions, to go back to significant
5569 earlier versions or to mark branch points as releases, etc. Changing
5570 earlier versions or to mark branch points as releases, etc. Changing
5570 an existing tag is normally disallowed; use -f/--force to override.
5571 an existing tag is normally disallowed; use -f/--force to override.
5571
5572
5572 If no revision is given, the parent of the working directory is
5573 If no revision is given, the parent of the working directory is
5573 used.
5574 used.
5574
5575
5575 To facilitate version control, distribution, and merging of tags,
5576 To facilitate version control, distribution, and merging of tags,
5576 they are stored as a file named ".hgtags" which is managed similarly
5577 they are stored as a file named ".hgtags" which is managed similarly
5577 to other project files and can be hand-edited if necessary. This
5578 to other project files and can be hand-edited if necessary. This
5578 also means that tagging creates a new commit. The file
5579 also means that tagging creates a new commit. The file
5579 ".hg/localtags" is used for local tags (not shared among
5580 ".hg/localtags" is used for local tags (not shared among
5580 repositories).
5581 repositories).
5581
5582
5582 Tag commits are usually made at the head of a branch. If the parent
5583 Tag commits are usually made at the head of a branch. If the parent
5583 of the working directory is not a branch head, :hg:`tag` aborts; use
5584 of the working directory is not a branch head, :hg:`tag` aborts; use
5584 -f/--force to force the tag commit to be based on a non-head
5585 -f/--force to force the tag commit to be based on a non-head
5585 changeset.
5586 changeset.
5586
5587
5587 See :hg:`help dates` for a list of formats valid for -d/--date.
5588 See :hg:`help dates` for a list of formats valid for -d/--date.
5588
5589
5589 Since tag names have priority over branch names during revision
5590 Since tag names have priority over branch names during revision
5590 lookup, using an existing branch name as a tag name is discouraged.
5591 lookup, using an existing branch name as a tag name is discouraged.
5591
5592
5592 Returns 0 on success.
5593 Returns 0 on success.
5593 """
5594 """
5594 wlock = lock = None
5595 wlock = lock = None
5595 try:
5596 try:
5596 wlock = repo.wlock()
5597 wlock = repo.wlock()
5597 lock = repo.lock()
5598 lock = repo.lock()
5598 rev_ = "."
5599 rev_ = "."
5599 names = [t.strip() for t in (name1,) + names]
5600 names = [t.strip() for t in (name1,) + names]
5600 if len(names) != len(set(names)):
5601 if len(names) != len(set(names)):
5601 raise util.Abort(_('tag names must be unique'))
5602 raise util.Abort(_('tag names must be unique'))
5602 for n in names:
5603 for n in names:
5603 scmutil.checknewlabel(repo, n, 'tag')
5604 scmutil.checknewlabel(repo, n, 'tag')
5604 if not n:
5605 if not n:
5605 raise util.Abort(_('tag names cannot consist entirely of '
5606 raise util.Abort(_('tag names cannot consist entirely of '
5606 'whitespace'))
5607 'whitespace'))
5607 if opts.get('rev') and opts.get('remove'):
5608 if opts.get('rev') and opts.get('remove'):
5608 raise util.Abort(_("--rev and --remove are incompatible"))
5609 raise util.Abort(_("--rev and --remove are incompatible"))
5609 if opts.get('rev'):
5610 if opts.get('rev'):
5610 rev_ = opts['rev']
5611 rev_ = opts['rev']
5611 message = opts.get('message')
5612 message = opts.get('message')
5612 if opts.get('remove'):
5613 if opts.get('remove'):
5613 expectedtype = opts.get('local') and 'local' or 'global'
5614 expectedtype = opts.get('local') and 'local' or 'global'
5614 for n in names:
5615 for n in names:
5615 if not repo.tagtype(n):
5616 if not repo.tagtype(n):
5616 raise util.Abort(_("tag '%s' does not exist") % n)
5617 raise util.Abort(_("tag '%s' does not exist") % n)
5617 if repo.tagtype(n) != expectedtype:
5618 if repo.tagtype(n) != expectedtype:
5618 if expectedtype == 'global':
5619 if expectedtype == 'global':
5619 raise util.Abort(_("tag '%s' is not a global tag") % n)
5620 raise util.Abort(_("tag '%s' is not a global tag") % n)
5620 else:
5621 else:
5621 raise util.Abort(_("tag '%s' is not a local tag") % n)
5622 raise util.Abort(_("tag '%s' is not a local tag") % n)
5622 rev_ = nullid
5623 rev_ = nullid
5623 if not message:
5624 if not message:
5624 # we don't translate commit messages
5625 # we don't translate commit messages
5625 message = 'Removed tag %s' % ', '.join(names)
5626 message = 'Removed tag %s' % ', '.join(names)
5626 elif not opts.get('force'):
5627 elif not opts.get('force'):
5627 for n in names:
5628 for n in names:
5628 if n in repo.tags():
5629 if n in repo.tags():
5629 raise util.Abort(_("tag '%s' already exists "
5630 raise util.Abort(_("tag '%s' already exists "
5630 "(use -f to force)") % n)
5631 "(use -f to force)") % n)
5631 if not opts.get('local'):
5632 if not opts.get('local'):
5632 p1, p2 = repo.dirstate.parents()
5633 p1, p2 = repo.dirstate.parents()
5633 if p2 != nullid:
5634 if p2 != nullid:
5634 raise util.Abort(_('uncommitted merge'))
5635 raise util.Abort(_('uncommitted merge'))
5635 bheads = repo.branchheads()
5636 bheads = repo.branchheads()
5636 if not opts.get('force') and bheads and p1 not in bheads:
5637 if not opts.get('force') and bheads and p1 not in bheads:
5637 raise util.Abort(_('not at a branch head (use -f to force)'))
5638 raise util.Abort(_('not at a branch head (use -f to force)'))
5638 r = scmutil.revsingle(repo, rev_).node()
5639 r = scmutil.revsingle(repo, rev_).node()
5639
5640
5640 if not message:
5641 if not message:
5641 # we don't translate commit messages
5642 # we don't translate commit messages
5642 message = ('Added tag %s for changeset %s' %
5643 message = ('Added tag %s for changeset %s' %
5643 (', '.join(names), short(r)))
5644 (', '.join(names), short(r)))
5644
5645
5645 date = opts.get('date')
5646 date = opts.get('date')
5646 if date:
5647 if date:
5647 date = util.parsedate(date)
5648 date = util.parsedate(date)
5648
5649
5649 if opts.get('edit'):
5650 if opts.get('edit'):
5650 message = ui.edit(message, ui.username())
5651 message = ui.edit(message, ui.username())
5651
5652
5652 # don't allow tagging the null rev
5653 # don't allow tagging the null rev
5653 if (not opts.get('remove') and
5654 if (not opts.get('remove') and
5654 scmutil.revsingle(repo, rev_).rev() == nullrev):
5655 scmutil.revsingle(repo, rev_).rev() == nullrev):
5655 raise util.Abort(_("cannot tag null revision"))
5656 raise util.Abort(_("cannot tag null revision"))
5656
5657
5657 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5658 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5658 finally:
5659 finally:
5659 release(lock, wlock)
5660 release(lock, wlock)
5660
5661
5661 @command('tags', [], '')
5662 @command('tags', [], '')
5662 def tags(ui, repo, **opts):
5663 def tags(ui, repo, **opts):
5663 """list repository tags
5664 """list repository tags
5664
5665
5665 This lists both regular and local tags. When the -v/--verbose
5666 This lists both regular and local tags. When the -v/--verbose
5666 switch is used, a third column "local" is printed for local tags.
5667 switch is used, a third column "local" is printed for local tags.
5667
5668
5668 Returns 0 on success.
5669 Returns 0 on success.
5669 """
5670 """
5670
5671
5671 fm = ui.formatter('tags', opts)
5672 fm = ui.formatter('tags', opts)
5672 hexfunc = ui.debugflag and hex or short
5673 hexfunc = ui.debugflag and hex or short
5673 tagtype = ""
5674 tagtype = ""
5674
5675
5675 for t, n in reversed(repo.tagslist()):
5676 for t, n in reversed(repo.tagslist()):
5676 hn = hexfunc(n)
5677 hn = hexfunc(n)
5677 label = 'tags.normal'
5678 label = 'tags.normal'
5678 tagtype = ''
5679 tagtype = ''
5679 if repo.tagtype(t) == 'local':
5680 if repo.tagtype(t) == 'local':
5680 label = 'tags.local'
5681 label = 'tags.local'
5681 tagtype = 'local'
5682 tagtype = 'local'
5682
5683
5683 fm.startitem()
5684 fm.startitem()
5684 fm.write('tag', '%s', t, label=label)
5685 fm.write('tag', '%s', t, label=label)
5685 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5686 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5686 fm.condwrite(not ui.quiet, 'rev id', fmt,
5687 fm.condwrite(not ui.quiet, 'rev id', fmt,
5687 repo.changelog.rev(n), hn, label=label)
5688 repo.changelog.rev(n), hn, label=label)
5688 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5689 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5689 tagtype, label=label)
5690 tagtype, label=label)
5690 fm.plain('\n')
5691 fm.plain('\n')
5691 fm.end()
5692 fm.end()
5692
5693
5693 @command('tip',
5694 @command('tip',
5694 [('p', 'patch', None, _('show patch')),
5695 [('p', 'patch', None, _('show patch')),
5695 ('g', 'git', None, _('use git extended diff format')),
5696 ('g', 'git', None, _('use git extended diff format')),
5696 ] + templateopts,
5697 ] + templateopts,
5697 _('[-p] [-g]'))
5698 _('[-p] [-g]'))
5698 def tip(ui, repo, **opts):
5699 def tip(ui, repo, **opts):
5699 """show the tip revision (DEPRECATED)
5700 """show the tip revision (DEPRECATED)
5700
5701
5701 The tip revision (usually just called the tip) is the changeset
5702 The tip revision (usually just called the tip) is the changeset
5702 most recently added to the repository (and therefore the most
5703 most recently added to the repository (and therefore the most
5703 recently changed head).
5704 recently changed head).
5704
5705
5705 If you have just made a commit, that commit will be the tip. If
5706 If you have just made a commit, that commit will be the tip. If
5706 you have just pulled changes from another repository, the tip of
5707 you have just pulled changes from another repository, the tip of
5707 that repository becomes the current tip. The "tip" tag is special
5708 that repository becomes the current tip. The "tip" tag is special
5708 and cannot be renamed or assigned to a different changeset.
5709 and cannot be renamed or assigned to a different changeset.
5709
5710
5710 This command is deprecated, please use :hg:`heads` instead.
5711 This command is deprecated, please use :hg:`heads` instead.
5711
5712
5712 Returns 0 on success.
5713 Returns 0 on success.
5713 """
5714 """
5714 displayer = cmdutil.show_changeset(ui, repo, opts)
5715 displayer = cmdutil.show_changeset(ui, repo, opts)
5715 displayer.show(repo['tip'])
5716 displayer.show(repo['tip'])
5716 displayer.close()
5717 displayer.close()
5717
5718
5718 @command('unbundle',
5719 @command('unbundle',
5719 [('u', 'update', None,
5720 [('u', 'update', None,
5720 _('update to new branch head if changesets were unbundled'))],
5721 _('update to new branch head if changesets were unbundled'))],
5721 _('[-u] FILE...'))
5722 _('[-u] FILE...'))
5722 def unbundle(ui, repo, fname1, *fnames, **opts):
5723 def unbundle(ui, repo, fname1, *fnames, **opts):
5723 """apply one or more changegroup files
5724 """apply one or more changegroup files
5724
5725
5725 Apply one or more compressed changegroup files generated by the
5726 Apply one or more compressed changegroup files generated by the
5726 bundle command.
5727 bundle command.
5727
5728
5728 Returns 0 on success, 1 if an update has unresolved files.
5729 Returns 0 on success, 1 if an update has unresolved files.
5729 """
5730 """
5730 fnames = (fname1,) + fnames
5731 fnames = (fname1,) + fnames
5731
5732
5732 lock = repo.lock()
5733 lock = repo.lock()
5733 wc = repo['.']
5734 wc = repo['.']
5734 try:
5735 try:
5735 for fname in fnames:
5736 for fname in fnames:
5736 f = hg.openpath(ui, fname)
5737 f = hg.openpath(ui, fname)
5737 gen = changegroup.readbundle(f, fname)
5738 gen = changegroup.readbundle(f, fname)
5738 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5739 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5739 finally:
5740 finally:
5740 lock.release()
5741 lock.release()
5741 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5742 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5742 return postincoming(ui, repo, modheads, opts.get('update'), None)
5743 return postincoming(ui, repo, modheads, opts.get('update'), None)
5743
5744
5744 @command('^update|up|checkout|co',
5745 @command('^update|up|checkout|co',
5745 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5746 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5746 ('c', 'check', None,
5747 ('c', 'check', None,
5747 _('update across branches if no uncommitted changes')),
5748 _('update across branches if no uncommitted changes')),
5748 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5749 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5749 ('r', 'rev', '', _('revision'), _('REV'))],
5750 ('r', 'rev', '', _('revision'), _('REV'))],
5750 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5751 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5751 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5752 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5752 """update working directory (or switch revisions)
5753 """update working directory (or switch revisions)
5753
5754
5754 Update the repository's working directory to the specified
5755 Update the repository's working directory to the specified
5755 changeset. If no changeset is specified, update to the tip of the
5756 changeset. If no changeset is specified, update to the tip of the
5756 current named branch and move the current bookmark (see :hg:`help
5757 current named branch and move the current bookmark (see :hg:`help
5757 bookmarks`).
5758 bookmarks`).
5758
5759
5759 Update sets the working directory's parent revision to the specified
5760 Update sets the working directory's parent revision to the specified
5760 changeset (see :hg:`help parents`).
5761 changeset (see :hg:`help parents`).
5761
5762
5762 If the changeset is not a descendant or ancestor of the working
5763 If the changeset is not a descendant or ancestor of the working
5763 directory's parent, the update is aborted. With the -c/--check
5764 directory's parent, the update is aborted. With the -c/--check
5764 option, the working directory is checked for uncommitted changes; if
5765 option, the working directory is checked for uncommitted changes; if
5765 none are found, the working directory is updated to the specified
5766 none are found, the working directory is updated to the specified
5766 changeset.
5767 changeset.
5767
5768
5768 .. container:: verbose
5769 .. container:: verbose
5769
5770
5770 The following rules apply when the working directory contains
5771 The following rules apply when the working directory contains
5771 uncommitted changes:
5772 uncommitted changes:
5772
5773
5773 1. If neither -c/--check nor -C/--clean is specified, and if
5774 1. If neither -c/--check nor -C/--clean is specified, and if
5774 the requested changeset is an ancestor or descendant of
5775 the requested changeset is an ancestor or descendant of
5775 the working directory's parent, the uncommitted changes
5776 the working directory's parent, the uncommitted changes
5776 are merged into the requested changeset and the merged
5777 are merged into the requested changeset and the merged
5777 result is left uncommitted. If the requested changeset is
5778 result is left uncommitted. If the requested changeset is
5778 not an ancestor or descendant (that is, it is on another
5779 not an ancestor or descendant (that is, it is on another
5779 branch), the update is aborted and the uncommitted changes
5780 branch), the update is aborted and the uncommitted changes
5780 are preserved.
5781 are preserved.
5781
5782
5782 2. With the -c/--check option, the update is aborted and the
5783 2. With the -c/--check option, the update is aborted and the
5783 uncommitted changes are preserved.
5784 uncommitted changes are preserved.
5784
5785
5785 3. With the -C/--clean option, uncommitted changes are discarded and
5786 3. With the -C/--clean option, uncommitted changes are discarded and
5786 the working directory is updated to the requested changeset.
5787 the working directory is updated to the requested changeset.
5787
5788
5788 To cancel an uncommitted merge (and lose your changes), use
5789 To cancel an uncommitted merge (and lose your changes), use
5789 :hg:`update --clean .`.
5790 :hg:`update --clean .`.
5790
5791
5791 Use null as the changeset to remove the working directory (like
5792 Use null as the changeset to remove the working directory (like
5792 :hg:`clone -U`).
5793 :hg:`clone -U`).
5793
5794
5794 If you want to revert just one file to an older revision, use
5795 If you want to revert just one file to an older revision, use
5795 :hg:`revert [-r REV] NAME`.
5796 :hg:`revert [-r REV] NAME`.
5796
5797
5797 See :hg:`help dates` for a list of formats valid for -d/--date.
5798 See :hg:`help dates` for a list of formats valid for -d/--date.
5798
5799
5799 Returns 0 on success, 1 if there are unresolved files.
5800 Returns 0 on success, 1 if there are unresolved files.
5800 """
5801 """
5801 if rev and node:
5802 if rev and node:
5802 raise util.Abort(_("please specify just one revision"))
5803 raise util.Abort(_("please specify just one revision"))
5803
5804
5804 if rev is None or rev == '':
5805 if rev is None or rev == '':
5805 rev = node
5806 rev = node
5806
5807
5807 # with no argument, we also move the current bookmark, if any
5808 # with no argument, we also move the current bookmark, if any
5808 movemarkfrom = None
5809 movemarkfrom = None
5809 if rev is None:
5810 if rev is None:
5810 curmark = repo._bookmarkcurrent
5811 curmark = repo._bookmarkcurrent
5811 if bookmarks.iscurrent(repo):
5812 if bookmarks.iscurrent(repo):
5812 movemarkfrom = repo['.'].node()
5813 movemarkfrom = repo['.'].node()
5813 elif curmark:
5814 elif curmark:
5814 ui.status(_("updating to active bookmark %s\n") % curmark)
5815 ui.status(_("updating to active bookmark %s\n") % curmark)
5815 rev = curmark
5816 rev = curmark
5816
5817
5817 # if we defined a bookmark, we have to remember the original bookmark name
5818 # if we defined a bookmark, we have to remember the original bookmark name
5818 brev = rev
5819 brev = rev
5819 rev = scmutil.revsingle(repo, rev, rev).rev()
5820 rev = scmutil.revsingle(repo, rev, rev).rev()
5820
5821
5821 if check and clean:
5822 if check and clean:
5822 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5823 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5823
5824
5824 if date:
5825 if date:
5825 if rev is not None:
5826 if rev is not None:
5826 raise util.Abort(_("you can't specify a revision and a date"))
5827 raise util.Abort(_("you can't specify a revision and a date"))
5827 rev = cmdutil.finddate(ui, repo, date)
5828 rev = cmdutil.finddate(ui, repo, date)
5828
5829
5829 if check:
5830 if check:
5830 c = repo[None]
5831 c = repo[None]
5831 if c.dirty(merge=False, branch=False, missing=True):
5832 if c.dirty(merge=False, branch=False, missing=True):
5832 raise util.Abort(_("uncommitted local changes"))
5833 raise util.Abort(_("uncommitted local changes"))
5833 if rev is None:
5834 if rev is None:
5834 rev = repo[repo[None].branch()].rev()
5835 rev = repo[repo[None].branch()].rev()
5835 mergemod._checkunknown(repo, repo[None], repo[rev])
5836 mergemod._checkunknown(repo, repo[None], repo[rev])
5836
5837
5837 if clean:
5838 if clean:
5838 ret = hg.clean(repo, rev)
5839 ret = hg.clean(repo, rev)
5839 else:
5840 else:
5840 ret = hg.update(repo, rev)
5841 ret = hg.update(repo, rev)
5841
5842
5842 if not ret and movemarkfrom:
5843 if not ret and movemarkfrom:
5843 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5844 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5844 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5845 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5845 elif brev in repo._bookmarks:
5846 elif brev in repo._bookmarks:
5846 bookmarks.setcurrent(repo, brev)
5847 bookmarks.setcurrent(repo, brev)
5847 elif brev:
5848 elif brev:
5848 bookmarks.unsetcurrent(repo)
5849 bookmarks.unsetcurrent(repo)
5849
5850
5850 return ret
5851 return ret
5851
5852
5852 @command('verify', [])
5853 @command('verify', [])
5853 def verify(ui, repo):
5854 def verify(ui, repo):
5854 """verify the integrity of the repository
5855 """verify the integrity of the repository
5855
5856
5856 Verify the integrity of the current repository.
5857 Verify the integrity of the current repository.
5857
5858
5858 This will perform an extensive check of the repository's
5859 This will perform an extensive check of the repository's
5859 integrity, validating the hashes and checksums of each entry in
5860 integrity, validating the hashes and checksums of each entry in
5860 the changelog, manifest, and tracked files, as well as the
5861 the changelog, manifest, and tracked files, as well as the
5861 integrity of their crosslinks and indices.
5862 integrity of their crosslinks and indices.
5862
5863
5863 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5864 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5864 for more information about recovery from corruption of the
5865 for more information about recovery from corruption of the
5865 repository.
5866 repository.
5866
5867
5867 Returns 0 on success, 1 if errors are encountered.
5868 Returns 0 on success, 1 if errors are encountered.
5868 """
5869 """
5869 return hg.verify(repo)
5870 return hg.verify(repo)
5870
5871
5871 @command('version', [])
5872 @command('version', [])
5872 def version_(ui):
5873 def version_(ui):
5873 """output version and copyright information"""
5874 """output version and copyright information"""
5874 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5875 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5875 % util.version())
5876 % util.version())
5876 ui.status(_(
5877 ui.status(_(
5877 "(see http://mercurial.selenic.com for more information)\n"
5878 "(see http://mercurial.selenic.com for more information)\n"
5878 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5879 "\nCopyright (C) 2005-2013 Matt Mackall and others\n"
5879 "This is free software; see the source for copying conditions. "
5880 "This is free software; see the source for copying conditions. "
5880 "There is NO\nwarranty; "
5881 "There is NO\nwarranty; "
5881 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5882 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5882 ))
5883 ))
5883
5884
5884 norepo = ("clone init version help debugcommands debugcomplete"
5885 norepo = ("clone init version help debugcommands debugcomplete"
5885 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5886 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5886 " debugknown debuggetbundle debugbundle")
5887 " debugknown debuggetbundle debugbundle")
5887 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5888 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5888 " debugdata debugindex debugindexdot debugrevlog")
5889 " debugdata debugindex debugindexdot debugrevlog")
5889 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5890 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5890 " remove resolve status debugwalk")
5891 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now