##// END OF EJS Templates
cat: remove incorrect reference to tip
Matt Mackall -
r19400:61c93ef8 default
parent child Browse files
Show More
@@ -1,5885 +1,5884 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 or tip if no revision is checked out.
1140
1139
1141 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
1142 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
1143 for the export command, with the following additions:
1142 for the export command, with the following additions:
1144
1143
1145 :``%s``: basename of file being printed
1144 :``%s``: basename of file being printed
1146 :``%d``: dirname of file being printed, or '.' if in repository root
1145 :``%d``: dirname of file being printed, or '.' if in repository root
1147 :``%p``: root-relative path name of file being printed
1146 :``%p``: root-relative path name of file being printed
1148
1147
1149 Returns 0 on success.
1148 Returns 0 on success.
1150 """
1149 """
1151 ctx = scmutil.revsingle(repo, opts.get('rev'))
1150 ctx = scmutil.revsingle(repo, opts.get('rev'))
1152 err = 1
1151 err = 1
1153 m = scmutil.match(ctx, (file1,) + pats, opts)
1152 m = scmutil.match(ctx, (file1,) + pats, opts)
1154 for abs in ctx.walk(m):
1153 for abs in ctx.walk(m):
1155 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1154 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1156 pathname=abs)
1155 pathname=abs)
1157 data = ctx[abs].data()
1156 data = ctx[abs].data()
1158 if opts.get('decode'):
1157 if opts.get('decode'):
1159 data = repo.wwritedata(abs, data)
1158 data = repo.wwritedata(abs, data)
1160 fp.write(data)
1159 fp.write(data)
1161 fp.close()
1160 fp.close()
1162 err = 0
1161 err = 0
1163 return err
1162 return err
1164
1163
1165 @command('^clone',
1164 @command('^clone',
1166 [('U', 'noupdate', None,
1165 [('U', 'noupdate', None,
1167 _('the clone will include an empty working copy (only a repository)')),
1166 _('the clone will include an empty working copy (only a repository)')),
1168 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1167 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1169 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1168 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1170 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1169 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1171 ('', 'pull', None, _('use pull protocol to copy metadata')),
1170 ('', 'pull', None, _('use pull protocol to copy metadata')),
1172 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1171 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1173 ] + remoteopts,
1172 ] + remoteopts,
1174 _('[OPTION]... SOURCE [DEST]'))
1173 _('[OPTION]... SOURCE [DEST]'))
1175 def clone(ui, source, dest=None, **opts):
1174 def clone(ui, source, dest=None, **opts):
1176 """make a copy of an existing repository
1175 """make a copy of an existing repository
1177
1176
1178 Create a copy of an existing repository in a new directory.
1177 Create a copy of an existing repository in a new directory.
1179
1178
1180 If no destination directory name is specified, it defaults to the
1179 If no destination directory name is specified, it defaults to the
1181 basename of the source.
1180 basename of the source.
1182
1181
1183 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
1184 ``.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.
1185
1184
1186 Only local paths and ``ssh://`` URLs are supported as
1185 Only local paths and ``ssh://`` URLs are supported as
1187 destinations. For ``ssh://`` destinations, no working directory or
1186 destinations. For ``ssh://`` destinations, no working directory or
1188 ``.hg/hgrc`` will be created on the remote side.
1187 ``.hg/hgrc`` will be created on the remote side.
1189
1188
1190 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
1191 identifiers with -r/--rev or branches with -b/--branch. The
1190 identifiers with -r/--rev or branches with -b/--branch. The
1192 resulting clone will contain only the specified changesets and
1191 resulting clone will contain only the specified changesets and
1193 their ancestors. These options (or 'clone src#rev dest') imply
1192 their ancestors. These options (or 'clone src#rev dest') imply
1194 --pull, even for local source repositories. Note that specifying a
1193 --pull, even for local source repositories. Note that specifying a
1195 tag will include the tagged changeset but not the changeset
1194 tag will include the tagged changeset but not the changeset
1196 containing the tag.
1195 containing the tag.
1197
1196
1198 If the source repository has a bookmark called '@' set, that
1197 If the source repository has a bookmark called '@' set, that
1199 revision will be checked out in the new repository by default.
1198 revision will be checked out in the new repository by default.
1200
1199
1201 To check out a particular version, use -u/--update, or
1200 To check out a particular version, use -u/--update, or
1202 -U/--noupdate to create a clone with no working directory.
1201 -U/--noupdate to create a clone with no working directory.
1203
1202
1204 .. container:: verbose
1203 .. container:: verbose
1205
1204
1206 For efficiency, hardlinks are used for cloning whenever the
1205 For efficiency, hardlinks are used for cloning whenever the
1207 source and destination are on the same filesystem (note this
1206 source and destination are on the same filesystem (note this
1208 applies only to the repository data, not to the working
1207 applies only to the repository data, not to the working
1209 directory). Some filesystems, such as AFS, implement hardlinking
1208 directory). Some filesystems, such as AFS, implement hardlinking
1210 incorrectly, but do not report errors. In these cases, use the
1209 incorrectly, but do not report errors. In these cases, use the
1211 --pull option to avoid hardlinking.
1210 --pull option to avoid hardlinking.
1212
1211
1213 In some cases, you can clone repositories and the working
1212 In some cases, you can clone repositories and the working
1214 directory using full hardlinks with ::
1213 directory using full hardlinks with ::
1215
1214
1216 $ cp -al REPO REPOCLONE
1215 $ cp -al REPO REPOCLONE
1217
1216
1218 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
1219 operation is not atomic (making sure REPO is not modified during
1218 operation is not atomic (making sure REPO is not modified during
1220 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
1221 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1220 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1222 so). Also, this is not compatible with certain extensions that
1221 so). Also, this is not compatible with certain extensions that
1223 place their metadata under the .hg directory, such as mq.
1222 place their metadata under the .hg directory, such as mq.
1224
1223
1225 Mercurial will update the working directory to the first applicable
1224 Mercurial will update the working directory to the first applicable
1226 revision from this list:
1225 revision from this list:
1227
1226
1228 a) null if -U or the source repository has no changesets
1227 a) null if -U or the source repository has no changesets
1229 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
1230 the source repository's working directory
1229 the source repository's working directory
1231 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
1232 latest head of that branch)
1231 latest head of that branch)
1233 d) the changeset specified with -r
1232 d) the changeset specified with -r
1234 e) the tipmost head specified with -b
1233 e) the tipmost head specified with -b
1235 f) the tipmost head specified with the url#branch source syntax
1234 f) the tipmost head specified with the url#branch source syntax
1236 g) the revision marked with the '@' bookmark, if present
1235 g) the revision marked with the '@' bookmark, if present
1237 h) the tipmost head of the default branch
1236 h) the tipmost head of the default branch
1238 i) tip
1237 i) tip
1239
1238
1240 Examples:
1239 Examples:
1241
1240
1242 - clone a remote repository to a new directory named hg/::
1241 - clone a remote repository to a new directory named hg/::
1243
1242
1244 hg clone http://selenic.com/hg
1243 hg clone http://selenic.com/hg
1245
1244
1246 - create a lightweight local clone::
1245 - create a lightweight local clone::
1247
1246
1248 hg clone project/ project-feature/
1247 hg clone project/ project-feature/
1249
1248
1250 - 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)::
1251
1250
1252 hg clone ssh://user@server//home/projects/alpha/
1251 hg clone ssh://user@server//home/projects/alpha/
1253
1252
1254 - 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
1255 specified version::
1254 specified version::
1256
1255
1257 hg clone --uncompressed http://server/repo -u 1.5
1256 hg clone --uncompressed http://server/repo -u 1.5
1258
1257
1259 - create a repository without changesets after a particular revision::
1258 - create a repository without changesets after a particular revision::
1260
1259
1261 hg clone -r 04e544 experimental/ good/
1260 hg clone -r 04e544 experimental/ good/
1262
1261
1263 - clone (and track) a particular named branch::
1262 - clone (and track) a particular named branch::
1264
1263
1265 hg clone http://selenic.com/hg#stable
1264 hg clone http://selenic.com/hg#stable
1266
1265
1267 See :hg:`help urls` for details on specifying URLs.
1266 See :hg:`help urls` for details on specifying URLs.
1268
1267
1269 Returns 0 on success.
1268 Returns 0 on success.
1270 """
1269 """
1271 if opts.get('noupdate') and opts.get('updaterev'):
1270 if opts.get('noupdate') and opts.get('updaterev'):
1272 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1271 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1273
1272
1274 r = hg.clone(ui, opts, source, dest,
1273 r = hg.clone(ui, opts, source, dest,
1275 pull=opts.get('pull'),
1274 pull=opts.get('pull'),
1276 stream=opts.get('uncompressed'),
1275 stream=opts.get('uncompressed'),
1277 rev=opts.get('rev'),
1276 rev=opts.get('rev'),
1278 update=opts.get('updaterev') or not opts.get('noupdate'),
1277 update=opts.get('updaterev') or not opts.get('noupdate'),
1279 branch=opts.get('branch'))
1278 branch=opts.get('branch'))
1280
1279
1281 return r is None
1280 return r is None
1282
1281
1283 @command('^commit|ci',
1282 @command('^commit|ci',
1284 [('A', 'addremove', None,
1283 [('A', 'addremove', None,
1285 _('mark new/missing files as added/removed before committing')),
1284 _('mark new/missing files as added/removed before committing')),
1286 ('', 'close-branch', None,
1285 ('', 'close-branch', None,
1287 _('mark a branch as closed, hiding it from the branch list')),
1286 _('mark a branch as closed, hiding it from the branch list')),
1288 ('', 'amend', None, _('amend the parent of the working dir')),
1287 ('', 'amend', None, _('amend the parent of the working dir')),
1289 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1288 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1290 _('[OPTION]... [FILE]...'))
1289 _('[OPTION]... [FILE]...'))
1291 def commit(ui, repo, *pats, **opts):
1290 def commit(ui, repo, *pats, **opts):
1292 """commit the specified files or all outstanding changes
1291 """commit the specified files or all outstanding changes
1293
1292
1294 Commit changes to the given files into the repository. Unlike a
1293 Commit changes to the given files into the repository. Unlike a
1295 centralized SCM, this operation is a local operation. See
1294 centralized SCM, this operation is a local operation. See
1296 :hg:`push` for a way to actively distribute your changes.
1295 :hg:`push` for a way to actively distribute your changes.
1297
1296
1298 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`
1299 will be committed.
1298 will be committed.
1300
1299
1301 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
1302 filenames or -I/-X filters.
1301 filenames or -I/-X filters.
1303
1302
1304 If no commit message is specified, Mercurial starts your
1303 If no commit message is specified, Mercurial starts your
1305 configured editor where you can enter a message. In case your
1304 configured editor where you can enter a message. In case your
1306 commit fails, you will find a backup of your message in
1305 commit fails, you will find a backup of your message in
1307 ``.hg/last-message.txt``.
1306 ``.hg/last-message.txt``.
1308
1307
1309 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
1310 working directory with a new commit that contains the changes
1309 working directory with a new commit that contains the changes
1311 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`,
1312 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
1313 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1312 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1314 on how to restore it).
1313 on how to restore it).
1315
1314
1316 Message, user and date are taken from the amended commit unless
1315 Message, user and date are taken from the amended commit unless
1317 specified. When a message isn't specified on the command line,
1316 specified. When a message isn't specified on the command line,
1318 the editor will open with the message of the amended commit.
1317 the editor will open with the message of the amended commit.
1319
1318
1320 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`)
1321 or changesets that have children.
1320 or changesets that have children.
1322
1321
1323 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.
1324
1323
1325 Returns 0 on success, 1 if nothing changed.
1324 Returns 0 on success, 1 if nothing changed.
1326 """
1325 """
1327 if opts.get('subrepos'):
1326 if opts.get('subrepos'):
1328 if opts.get('amend'):
1327 if opts.get('amend'):
1329 raise util.Abort(_('cannot amend with --subrepos'))
1328 raise util.Abort(_('cannot amend with --subrepos'))
1330 # Let --subrepos on the command line override config setting.
1329 # Let --subrepos on the command line override config setting.
1331 ui.setconfig('ui', 'commitsubrepos', True)
1330 ui.setconfig('ui', 'commitsubrepos', True)
1332
1331
1333 if repo.vfs.exists('graftstate'):
1332 if repo.vfs.exists('graftstate'):
1334 raise util.Abort(_('cannot commit an interrupted graft operation'),
1333 raise util.Abort(_('cannot commit an interrupted graft operation'),
1335 hint=_('use "hg graft -c" to continue graft'))
1334 hint=_('use "hg graft -c" to continue graft'))
1336
1335
1337 branch = repo[None].branch()
1336 branch = repo[None].branch()
1338 bheads = repo.branchheads(branch)
1337 bheads = repo.branchheads(branch)
1339
1338
1340 extra = {}
1339 extra = {}
1341 if opts.get('close_branch'):
1340 if opts.get('close_branch'):
1342 extra['close'] = 1
1341 extra['close'] = 1
1343
1342
1344 if not bheads:
1343 if not bheads:
1345 raise util.Abort(_('can only close branch heads'))
1344 raise util.Abort(_('can only close branch heads'))
1346 elif opts.get('amend'):
1345 elif opts.get('amend'):
1347 if repo.parents()[0].p1().branch() != branch and \
1346 if repo.parents()[0].p1().branch() != branch and \
1348 repo.parents()[0].p2().branch() != branch:
1347 repo.parents()[0].p2().branch() != branch:
1349 raise util.Abort(_('can only close branch heads'))
1348 raise util.Abort(_('can only close branch heads'))
1350
1349
1351 if opts.get('amend'):
1350 if opts.get('amend'):
1352 if ui.configbool('ui', 'commitsubrepos'):
1351 if ui.configbool('ui', 'commitsubrepos'):
1353 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1352 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1354
1353
1355 old = repo['.']
1354 old = repo['.']
1356 if old.phase() == phases.public:
1355 if old.phase() == phases.public:
1357 raise util.Abort(_('cannot amend public changesets'))
1356 raise util.Abort(_('cannot amend public changesets'))
1358 if len(repo[None].parents()) > 1:
1357 if len(repo[None].parents()) > 1:
1359 raise util.Abort(_('cannot amend while merging'))
1358 raise util.Abort(_('cannot amend while merging'))
1360 if (not obsolete._enabled) and old.children():
1359 if (not obsolete._enabled) and old.children():
1361 raise util.Abort(_('cannot amend changeset with children'))
1360 raise util.Abort(_('cannot amend changeset with children'))
1362
1361
1363 e = cmdutil.commiteditor
1362 e = cmdutil.commiteditor
1364 if opts.get('force_editor'):
1363 if opts.get('force_editor'):
1365 e = cmdutil.commitforceeditor
1364 e = cmdutil.commitforceeditor
1366
1365
1367 def commitfunc(ui, repo, message, match, opts):
1366 def commitfunc(ui, repo, message, match, opts):
1368 editor = e
1367 editor = e
1369 # message contains text from -m or -l, if it's empty,
1368 # message contains text from -m or -l, if it's empty,
1370 # open the editor with the old message
1369 # open the editor with the old message
1371 if not message:
1370 if not message:
1372 message = old.description()
1371 message = old.description()
1373 editor = cmdutil.commitforceeditor
1372 editor = cmdutil.commitforceeditor
1374 return repo.commit(message,
1373 return repo.commit(message,
1375 opts.get('user') or old.user(),
1374 opts.get('user') or old.user(),
1376 opts.get('date') or old.date(),
1375 opts.get('date') or old.date(),
1377 match,
1376 match,
1378 editor=editor,
1377 editor=editor,
1379 extra=extra)
1378 extra=extra)
1380
1379
1381 current = repo._bookmarkcurrent
1380 current = repo._bookmarkcurrent
1382 marks = old.bookmarks()
1381 marks = old.bookmarks()
1383 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1382 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1384 if node == old.node():
1383 if node == old.node():
1385 ui.status(_("nothing changed\n"))
1384 ui.status(_("nothing changed\n"))
1386 return 1
1385 return 1
1387 elif marks:
1386 elif marks:
1388 ui.debug('moving bookmarks %r from %s to %s\n' %
1387 ui.debug('moving bookmarks %r from %s to %s\n' %
1389 (marks, old.hex(), hex(node)))
1388 (marks, old.hex(), hex(node)))
1390 newmarks = repo._bookmarks
1389 newmarks = repo._bookmarks
1391 for bm in marks:
1390 for bm in marks:
1392 newmarks[bm] = node
1391 newmarks[bm] = node
1393 if bm == current:
1392 if bm == current:
1394 bookmarks.setcurrent(repo, bm)
1393 bookmarks.setcurrent(repo, bm)
1395 newmarks.write()
1394 newmarks.write()
1396 else:
1395 else:
1397 e = cmdutil.commiteditor
1396 e = cmdutil.commiteditor
1398 if opts.get('force_editor'):
1397 if opts.get('force_editor'):
1399 e = cmdutil.commitforceeditor
1398 e = cmdutil.commitforceeditor
1400
1399
1401 def commitfunc(ui, repo, message, match, opts):
1400 def commitfunc(ui, repo, message, match, opts):
1402 return repo.commit(message, opts.get('user'), opts.get('date'),
1401 return repo.commit(message, opts.get('user'), opts.get('date'),
1403 match, editor=e, extra=extra)
1402 match, editor=e, extra=extra)
1404
1403
1405 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1404 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1406
1405
1407 if not node:
1406 if not node:
1408 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1407 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1409 if stat[3]:
1408 if stat[3]:
1410 ui.status(_("nothing changed (%d missing files, see "
1409 ui.status(_("nothing changed (%d missing files, see "
1411 "'hg status')\n") % len(stat[3]))
1410 "'hg status')\n") % len(stat[3]))
1412 else:
1411 else:
1413 ui.status(_("nothing changed\n"))
1412 ui.status(_("nothing changed\n"))
1414 return 1
1413 return 1
1415
1414
1416 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1415 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1417
1416
1418 @command('copy|cp',
1417 @command('copy|cp',
1419 [('A', 'after', None, _('record a copy that has already occurred')),
1418 [('A', 'after', None, _('record a copy that has already occurred')),
1420 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1419 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1421 ] + walkopts + dryrunopts,
1420 ] + walkopts + dryrunopts,
1422 _('[OPTION]... [SOURCE]... DEST'))
1421 _('[OPTION]... [SOURCE]... DEST'))
1423 def copy(ui, repo, *pats, **opts):
1422 def copy(ui, repo, *pats, **opts):
1424 """mark files as copied for the next commit
1423 """mark files as copied for the next commit
1425
1424
1426 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
1427 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,
1428 the source must be a single file.
1427 the source must be a single file.
1429
1428
1430 By default, this command copies the contents of files as they
1429 By default, this command copies the contents of files as they
1431 exist in the working directory. If invoked with -A/--after, the
1430 exist in the working directory. If invoked with -A/--after, the
1432 operation is recorded, but no copying is performed.
1431 operation is recorded, but no copying is performed.
1433
1432
1434 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
1435 before that, see :hg:`revert`.
1434 before that, see :hg:`revert`.
1436
1435
1437 Returns 0 on success, 1 if errors are encountered.
1436 Returns 0 on success, 1 if errors are encountered.
1438 """
1437 """
1439 wlock = repo.wlock(False)
1438 wlock = repo.wlock(False)
1440 try:
1439 try:
1441 return cmdutil.copy(ui, repo, pats, opts)
1440 return cmdutil.copy(ui, repo, pats, opts)
1442 finally:
1441 finally:
1443 wlock.release()
1442 wlock.release()
1444
1443
1445 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1444 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1446 def debugancestor(ui, repo, *args):
1445 def debugancestor(ui, repo, *args):
1447 """find the ancestor revision of two revisions in a given index"""
1446 """find the ancestor revision of two revisions in a given index"""
1448 if len(args) == 3:
1447 if len(args) == 3:
1449 index, rev1, rev2 = args
1448 index, rev1, rev2 = args
1450 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1449 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1451 lookup = r.lookup
1450 lookup = r.lookup
1452 elif len(args) == 2:
1451 elif len(args) == 2:
1453 if not repo:
1452 if not repo:
1454 raise util.Abort(_("there is no Mercurial repository here "
1453 raise util.Abort(_("there is no Mercurial repository here "
1455 "(.hg not found)"))
1454 "(.hg not found)"))
1456 rev1, rev2 = args
1455 rev1, rev2 = args
1457 r = repo.changelog
1456 r = repo.changelog
1458 lookup = repo.lookup
1457 lookup = repo.lookup
1459 else:
1458 else:
1460 raise util.Abort(_('either two or three arguments required'))
1459 raise util.Abort(_('either two or three arguments required'))
1461 a = r.ancestor(lookup(rev1), lookup(rev2))
1460 a = r.ancestor(lookup(rev1), lookup(rev2))
1462 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1461 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1463
1462
1464 @command('debugbuilddag',
1463 @command('debugbuilddag',
1465 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1464 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1466 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1465 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1467 ('n', 'new-file', None, _('add new file at each rev'))],
1466 ('n', 'new-file', None, _('add new file at each rev'))],
1468 _('[OPTION]... [TEXT]'))
1467 _('[OPTION]... [TEXT]'))
1469 def debugbuilddag(ui, repo, text=None,
1468 def debugbuilddag(ui, repo, text=None,
1470 mergeable_file=False,
1469 mergeable_file=False,
1471 overwritten_file=False,
1470 overwritten_file=False,
1472 new_file=False):
1471 new_file=False):
1473 """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
1474
1473
1475 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
1476 command line.
1475 command line.
1477
1476
1478 Elements:
1477 Elements:
1479
1478
1480 - "+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
1481 - "." is a single node based on the current default parent
1480 - "." is a single node based on the current default parent
1482 - "$" resets the default parent to null (implied at the start);
1481 - "$" resets the default parent to null (implied at the start);
1483 otherwise the default parent is always the last node created
1482 otherwise the default parent is always the last node created
1484 - "<p" sets the default parent to the backref p
1483 - "<p" sets the default parent to the backref p
1485 - "*p" is a fork at parent p, which is a backref
1484 - "*p" is a fork at parent p, which is a backref
1486 - "*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
1487 - "/p2" is a merge of the preceding node and p2
1486 - "/p2" is a merge of the preceding node and p2
1488 - ":tag" defines a local tag for the preceding node
1487 - ":tag" defines a local tag for the preceding node
1489 - "@branch" sets the named branch for subsequent nodes
1488 - "@branch" sets the named branch for subsequent nodes
1490 - "#...\\n" is a comment up to the end of the line
1489 - "#...\\n" is a comment up to the end of the line
1491
1490
1492 Whitespace between the above elements is ignored.
1491 Whitespace between the above elements is ignored.
1493
1492
1494 A backref is either
1493 A backref is either
1495
1494
1496 - 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
1497 node, or
1496 node, or
1498 - 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
1499 - empty to denote the default parent.
1498 - empty to denote the default parent.
1500
1499
1501 All string valued-elements are either strictly alphanumeric, or must
1500 All string valued-elements are either strictly alphanumeric, or must
1502 be enclosed in double quotes ("..."), with "\\" as escape character.
1501 be enclosed in double quotes ("..."), with "\\" as escape character.
1503 """
1502 """
1504
1503
1505 if text is None:
1504 if text is None:
1506 ui.status(_("reading DAG from stdin\n"))
1505 ui.status(_("reading DAG from stdin\n"))
1507 text = ui.fin.read()
1506 text = ui.fin.read()
1508
1507
1509 cl = repo.changelog
1508 cl = repo.changelog
1510 if len(cl) > 0:
1509 if len(cl) > 0:
1511 raise util.Abort(_('repository is not empty'))
1510 raise util.Abort(_('repository is not empty'))
1512
1511
1513 # determine number of revs in DAG
1512 # determine number of revs in DAG
1514 total = 0
1513 total = 0
1515 for type, data in dagparser.parsedag(text):
1514 for type, data in dagparser.parsedag(text):
1516 if type == 'n':
1515 if type == 'n':
1517 total += 1
1516 total += 1
1518
1517
1519 if mergeable_file:
1518 if mergeable_file:
1520 linesperrev = 2
1519 linesperrev = 2
1521 # make a file with k lines per rev
1520 # make a file with k lines per rev
1522 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1521 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1523 initialmergedlines.append("")
1522 initialmergedlines.append("")
1524
1523
1525 tags = []
1524 tags = []
1526
1525
1527 lock = tr = None
1526 lock = tr = None
1528 try:
1527 try:
1529 lock = repo.lock()
1528 lock = repo.lock()
1530 tr = repo.transaction("builddag")
1529 tr = repo.transaction("builddag")
1531
1530
1532 at = -1
1531 at = -1
1533 atbranch = 'default'
1532 atbranch = 'default'
1534 nodeids = []
1533 nodeids = []
1535 id = 0
1534 id = 0
1536 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1535 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1537 for type, data in dagparser.parsedag(text):
1536 for type, data in dagparser.parsedag(text):
1538 if type == 'n':
1537 if type == 'n':
1539 ui.note(('node %s\n' % str(data)))
1538 ui.note(('node %s\n' % str(data)))
1540 id, ps = data
1539 id, ps = data
1541
1540
1542 files = []
1541 files = []
1543 fctxs = {}
1542 fctxs = {}
1544
1543
1545 p2 = None
1544 p2 = None
1546 if mergeable_file:
1545 if mergeable_file:
1547 fn = "mf"
1546 fn = "mf"
1548 p1 = repo[ps[0]]
1547 p1 = repo[ps[0]]
1549 if len(ps) > 1:
1548 if len(ps) > 1:
1550 p2 = repo[ps[1]]
1549 p2 = repo[ps[1]]
1551 pa = p1.ancestor(p2)
1550 pa = p1.ancestor(p2)
1552 base, local, other = [x[fn].data() for x in (pa, p1,
1551 base, local, other = [x[fn].data() for x in (pa, p1,
1553 p2)]
1552 p2)]
1554 m3 = simplemerge.Merge3Text(base, local, other)
1553 m3 = simplemerge.Merge3Text(base, local, other)
1555 ml = [l.strip() for l in m3.merge_lines()]
1554 ml = [l.strip() for l in m3.merge_lines()]
1556 ml.append("")
1555 ml.append("")
1557 elif at > 0:
1556 elif at > 0:
1558 ml = p1[fn].data().split("\n")
1557 ml = p1[fn].data().split("\n")
1559 else:
1558 else:
1560 ml = initialmergedlines
1559 ml = initialmergedlines
1561 ml[id * linesperrev] += " r%i" % id
1560 ml[id * linesperrev] += " r%i" % id
1562 mergedtext = "\n".join(ml)
1561 mergedtext = "\n".join(ml)
1563 files.append(fn)
1562 files.append(fn)
1564 fctxs[fn] = context.memfilectx(fn, mergedtext)
1563 fctxs[fn] = context.memfilectx(fn, mergedtext)
1565
1564
1566 if overwritten_file:
1565 if overwritten_file:
1567 fn = "of"
1566 fn = "of"
1568 files.append(fn)
1567 files.append(fn)
1569 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1568 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1570
1569
1571 if new_file:
1570 if new_file:
1572 fn = "nf%i" % id
1571 fn = "nf%i" % id
1573 files.append(fn)
1572 files.append(fn)
1574 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1573 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1575 if len(ps) > 1:
1574 if len(ps) > 1:
1576 if not p2:
1575 if not p2:
1577 p2 = repo[ps[1]]
1576 p2 = repo[ps[1]]
1578 for fn in p2:
1577 for fn in p2:
1579 if fn.startswith("nf"):
1578 if fn.startswith("nf"):
1580 files.append(fn)
1579 files.append(fn)
1581 fctxs[fn] = p2[fn]
1580 fctxs[fn] = p2[fn]
1582
1581
1583 def fctxfn(repo, cx, path):
1582 def fctxfn(repo, cx, path):
1584 return fctxs.get(path)
1583 return fctxs.get(path)
1585
1584
1586 if len(ps) == 0 or ps[0] < 0:
1585 if len(ps) == 0 or ps[0] < 0:
1587 pars = [None, None]
1586 pars = [None, None]
1588 elif len(ps) == 1:
1587 elif len(ps) == 1:
1589 pars = [nodeids[ps[0]], None]
1588 pars = [nodeids[ps[0]], None]
1590 else:
1589 else:
1591 pars = [nodeids[p] for p in ps]
1590 pars = [nodeids[p] for p in ps]
1592 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1591 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1593 date=(id, 0),
1592 date=(id, 0),
1594 user="debugbuilddag",
1593 user="debugbuilddag",
1595 extra={'branch': atbranch})
1594 extra={'branch': atbranch})
1596 nodeid = repo.commitctx(cx)
1595 nodeid = repo.commitctx(cx)
1597 nodeids.append(nodeid)
1596 nodeids.append(nodeid)
1598 at = id
1597 at = id
1599 elif type == 'l':
1598 elif type == 'l':
1600 id, name = data
1599 id, name = data
1601 ui.note(('tag %s\n' % name))
1600 ui.note(('tag %s\n' % name))
1602 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1601 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1603 elif type == 'a':
1602 elif type == 'a':
1604 ui.note(('branch %s\n' % data))
1603 ui.note(('branch %s\n' % data))
1605 atbranch = data
1604 atbranch = data
1606 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1605 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1607 tr.close()
1606 tr.close()
1608
1607
1609 if tags:
1608 if tags:
1610 repo.opener.write("localtags", "".join(tags))
1609 repo.opener.write("localtags", "".join(tags))
1611 finally:
1610 finally:
1612 ui.progress(_('building'), None)
1611 ui.progress(_('building'), None)
1613 release(tr, lock)
1612 release(tr, lock)
1614
1613
1615 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1614 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1616 def debugbundle(ui, bundlepath, all=None, **opts):
1615 def debugbundle(ui, bundlepath, all=None, **opts):
1617 """lists the contents of a bundle"""
1616 """lists the contents of a bundle"""
1618 f = hg.openpath(ui, bundlepath)
1617 f = hg.openpath(ui, bundlepath)
1619 try:
1618 try:
1620 gen = changegroup.readbundle(f, bundlepath)
1619 gen = changegroup.readbundle(f, bundlepath)
1621 if all:
1620 if all:
1622 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"))
1623
1622
1624 def showchunks(named):
1623 def showchunks(named):
1625 ui.write("\n%s\n" % named)
1624 ui.write("\n%s\n" % named)
1626 chain = None
1625 chain = None
1627 while True:
1626 while True:
1628 chunkdata = gen.deltachunk(chain)
1627 chunkdata = gen.deltachunk(chain)
1629 if not chunkdata:
1628 if not chunkdata:
1630 break
1629 break
1631 node = chunkdata['node']
1630 node = chunkdata['node']
1632 p1 = chunkdata['p1']
1631 p1 = chunkdata['p1']
1633 p2 = chunkdata['p2']
1632 p2 = chunkdata['p2']
1634 cs = chunkdata['cs']
1633 cs = chunkdata['cs']
1635 deltabase = chunkdata['deltabase']
1634 deltabase = chunkdata['deltabase']
1636 delta = chunkdata['delta']
1635 delta = chunkdata['delta']
1637 ui.write("%s %s %s %s %s %s\n" %
1636 ui.write("%s %s %s %s %s %s\n" %
1638 (hex(node), hex(p1), hex(p2),
1637 (hex(node), hex(p1), hex(p2),
1639 hex(cs), hex(deltabase), len(delta)))
1638 hex(cs), hex(deltabase), len(delta)))
1640 chain = node
1639 chain = node
1641
1640
1642 chunkdata = gen.changelogheader()
1641 chunkdata = gen.changelogheader()
1643 showchunks("changelog")
1642 showchunks("changelog")
1644 chunkdata = gen.manifestheader()
1643 chunkdata = gen.manifestheader()
1645 showchunks("manifest")
1644 showchunks("manifest")
1646 while True:
1645 while True:
1647 chunkdata = gen.filelogheader()
1646 chunkdata = gen.filelogheader()
1648 if not chunkdata:
1647 if not chunkdata:
1649 break
1648 break
1650 fname = chunkdata['filename']
1649 fname = chunkdata['filename']
1651 showchunks(fname)
1650 showchunks(fname)
1652 else:
1651 else:
1653 chunkdata = gen.changelogheader()
1652 chunkdata = gen.changelogheader()
1654 chain = None
1653 chain = None
1655 while True:
1654 while True:
1656 chunkdata = gen.deltachunk(chain)
1655 chunkdata = gen.deltachunk(chain)
1657 if not chunkdata:
1656 if not chunkdata:
1658 break
1657 break
1659 node = chunkdata['node']
1658 node = chunkdata['node']
1660 ui.write("%s\n" % hex(node))
1659 ui.write("%s\n" % hex(node))
1661 chain = node
1660 chain = node
1662 finally:
1661 finally:
1663 f.close()
1662 f.close()
1664
1663
1665 @command('debugcheckstate', [], '')
1664 @command('debugcheckstate', [], '')
1666 def debugcheckstate(ui, repo):
1665 def debugcheckstate(ui, repo):
1667 """validate the correctness of the current dirstate"""
1666 """validate the correctness of the current dirstate"""
1668 parent1, parent2 = repo.dirstate.parents()
1667 parent1, parent2 = repo.dirstate.parents()
1669 m1 = repo[parent1].manifest()
1668 m1 = repo[parent1].manifest()
1670 m2 = repo[parent2].manifest()
1669 m2 = repo[parent2].manifest()
1671 errors = 0
1670 errors = 0
1672 for f in repo.dirstate:
1671 for f in repo.dirstate:
1673 state = repo.dirstate[f]
1672 state = repo.dirstate[f]
1674 if state in "nr" and f not in m1:
1673 if state in "nr" and f not in m1:
1675 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))
1676 errors += 1
1675 errors += 1
1677 if state in "a" and f in m1:
1676 if state in "a" and f in m1:
1678 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))
1679 errors += 1
1678 errors += 1
1680 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:
1681 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") %
1682 (f, state))
1681 (f, state))
1683 errors += 1
1682 errors += 1
1684 for f in m1:
1683 for f in m1:
1685 state = repo.dirstate[f]
1684 state = repo.dirstate[f]
1686 if state not in "nrm":
1685 if state not in "nrm":
1687 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))
1688 errors += 1
1687 errors += 1
1689 if errors:
1688 if errors:
1690 error = _(".hg/dirstate inconsistent with current parent's manifest")
1689 error = _(".hg/dirstate inconsistent with current parent's manifest")
1691 raise util.Abort(error)
1690 raise util.Abort(error)
1692
1691
1693 @command('debugcommands', [], _('[COMMAND]'))
1692 @command('debugcommands', [], _('[COMMAND]'))
1694 def debugcommands(ui, cmd='', *args):
1693 def debugcommands(ui, cmd='', *args):
1695 """list all available commands and options"""
1694 """list all available commands and options"""
1696 for cmd, vals in sorted(table.iteritems()):
1695 for cmd, vals in sorted(table.iteritems()):
1697 cmd = cmd.split('|')[0].strip('^')
1696 cmd = cmd.split('|')[0].strip('^')
1698 opts = ', '.join([i[1] for i in vals[1]])
1697 opts = ', '.join([i[1] for i in vals[1]])
1699 ui.write('%s: %s\n' % (cmd, opts))
1698 ui.write('%s: %s\n' % (cmd, opts))
1700
1699
1701 @command('debugcomplete',
1700 @command('debugcomplete',
1702 [('o', 'options', None, _('show the command options'))],
1701 [('o', 'options', None, _('show the command options'))],
1703 _('[-o] CMD'))
1702 _('[-o] CMD'))
1704 def debugcomplete(ui, cmd='', **opts):
1703 def debugcomplete(ui, cmd='', **opts):
1705 """returns the completion list associated with the given command"""
1704 """returns the completion list associated with the given command"""
1706
1705
1707 if opts.get('options'):
1706 if opts.get('options'):
1708 options = []
1707 options = []
1709 otables = [globalopts]
1708 otables = [globalopts]
1710 if cmd:
1709 if cmd:
1711 aliases, entry = cmdutil.findcmd(cmd, table, False)
1710 aliases, entry = cmdutil.findcmd(cmd, table, False)
1712 otables.append(entry[1])
1711 otables.append(entry[1])
1713 for t in otables:
1712 for t in otables:
1714 for o in t:
1713 for o in t:
1715 if "(DEPRECATED)" in o[3]:
1714 if "(DEPRECATED)" in o[3]:
1716 continue
1715 continue
1717 if o[0]:
1716 if o[0]:
1718 options.append('-%s' % o[0])
1717 options.append('-%s' % o[0])
1719 options.append('--%s' % o[1])
1718 options.append('--%s' % o[1])
1720 ui.write("%s\n" % "\n".join(options))
1719 ui.write("%s\n" % "\n".join(options))
1721 return
1720 return
1722
1721
1723 cmdlist = cmdutil.findpossible(cmd, table)
1722 cmdlist = cmdutil.findpossible(cmd, table)
1724 if ui.verbose:
1723 if ui.verbose:
1725 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1724 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1726 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1725 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1727
1726
1728 @command('debugdag',
1727 @command('debugdag',
1729 [('t', 'tags', None, _('use tags as labels')),
1728 [('t', 'tags', None, _('use tags as labels')),
1730 ('b', 'branches', None, _('annotate with branch names')),
1729 ('b', 'branches', None, _('annotate with branch names')),
1731 ('', 'dots', None, _('use dots for runs')),
1730 ('', 'dots', None, _('use dots for runs')),
1732 ('s', 'spaces', None, _('separate elements by spaces'))],
1731 ('s', 'spaces', None, _('separate elements by spaces'))],
1733 _('[OPTION]... [FILE [REV]...]'))
1732 _('[OPTION]... [FILE [REV]...]'))
1734 def debugdag(ui, repo, file_=None, *revs, **opts):
1733 def debugdag(ui, repo, file_=None, *revs, **opts):
1735 """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
1736
1735
1737 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
1738 revision numbers, they get labeled in the output as rN.
1737 revision numbers, they get labeled in the output as rN.
1739
1738
1740 Otherwise, the changelog DAG of the current repo is emitted.
1739 Otherwise, the changelog DAG of the current repo is emitted.
1741 """
1740 """
1742 spaces = opts.get('spaces')
1741 spaces = opts.get('spaces')
1743 dots = opts.get('dots')
1742 dots = opts.get('dots')
1744 if file_:
1743 if file_:
1745 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1744 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1746 revs = set((int(r) for r in revs))
1745 revs = set((int(r) for r in revs))
1747 def events():
1746 def events():
1748 for r in rlog:
1747 for r in rlog:
1749 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)
1750 if p != -1)))
1749 if p != -1)))
1751 if r in revs:
1750 if r in revs:
1752 yield 'l', (r, "r%i" % r)
1751 yield 'l', (r, "r%i" % r)
1753 elif repo:
1752 elif repo:
1754 cl = repo.changelog
1753 cl = repo.changelog
1755 tags = opts.get('tags')
1754 tags = opts.get('tags')
1756 branches = opts.get('branches')
1755 branches = opts.get('branches')
1757 if tags:
1756 if tags:
1758 labels = {}
1757 labels = {}
1759 for l, n in repo.tags().items():
1758 for l, n in repo.tags().items():
1760 labels.setdefault(cl.rev(n), []).append(l)
1759 labels.setdefault(cl.rev(n), []).append(l)
1761 def events():
1760 def events():
1762 b = "default"
1761 b = "default"
1763 for r in cl:
1762 for r in cl:
1764 if branches:
1763 if branches:
1765 newb = cl.read(cl.node(r))[5]['branch']
1764 newb = cl.read(cl.node(r))[5]['branch']
1766 if newb != b:
1765 if newb != b:
1767 yield 'a', newb
1766 yield 'a', newb
1768 b = newb
1767 b = newb
1769 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)
1770 if p != -1)))
1769 if p != -1)))
1771 if tags:
1770 if tags:
1772 ls = labels.get(r)
1771 ls = labels.get(r)
1773 if ls:
1772 if ls:
1774 for l in ls:
1773 for l in ls:
1775 yield 'l', (r, l)
1774 yield 'l', (r, l)
1776 else:
1775 else:
1777 raise util.Abort(_('need repo for changelog dag'))
1776 raise util.Abort(_('need repo for changelog dag'))
1778
1777
1779 for line in dagparser.dagtextlines(events(),
1778 for line in dagparser.dagtextlines(events(),
1780 addspaces=spaces,
1779 addspaces=spaces,
1781 wraplabels=True,
1780 wraplabels=True,
1782 wrapannotations=True,
1781 wrapannotations=True,
1783 wrapnonlinear=dots,
1782 wrapnonlinear=dots,
1784 usedots=dots,
1783 usedots=dots,
1785 maxlinewidth=70):
1784 maxlinewidth=70):
1786 ui.write(line)
1785 ui.write(line)
1787 ui.write("\n")
1786 ui.write("\n")
1788
1787
1789 @command('debugdata',
1788 @command('debugdata',
1790 [('c', 'changelog', False, _('open changelog')),
1789 [('c', 'changelog', False, _('open changelog')),
1791 ('m', 'manifest', False, _('open manifest'))],
1790 ('m', 'manifest', False, _('open manifest'))],
1792 _('-c|-m|FILE REV'))
1791 _('-c|-m|FILE REV'))
1793 def debugdata(ui, repo, file_, rev = None, **opts):
1792 def debugdata(ui, repo, file_, rev = None, **opts):
1794 """dump the contents of a data file revision"""
1793 """dump the contents of a data file revision"""
1795 if opts.get('changelog') or opts.get('manifest'):
1794 if opts.get('changelog') or opts.get('manifest'):
1796 file_, rev = None, file_
1795 file_, rev = None, file_
1797 elif rev is None:
1796 elif rev is None:
1798 raise error.CommandError('debugdata', _('invalid arguments'))
1797 raise error.CommandError('debugdata', _('invalid arguments'))
1799 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1798 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1800 try:
1799 try:
1801 ui.write(r.revision(r.lookup(rev)))
1800 ui.write(r.revision(r.lookup(rev)))
1802 except KeyError:
1801 except KeyError:
1803 raise util.Abort(_('invalid revision identifier %s') % rev)
1802 raise util.Abort(_('invalid revision identifier %s') % rev)
1804
1803
1805 @command('debugdate',
1804 @command('debugdate',
1806 [('e', 'extended', None, _('try extended date formats'))],
1805 [('e', 'extended', None, _('try extended date formats'))],
1807 _('[-e] DATE [RANGE]'))
1806 _('[-e] DATE [RANGE]'))
1808 def debugdate(ui, date, range=None, **opts):
1807 def debugdate(ui, date, range=None, **opts):
1809 """parse and display a date"""
1808 """parse and display a date"""
1810 if opts["extended"]:
1809 if opts["extended"]:
1811 d = util.parsedate(date, util.extendeddateformats)
1810 d = util.parsedate(date, util.extendeddateformats)
1812 else:
1811 else:
1813 d = util.parsedate(date)
1812 d = util.parsedate(date)
1814 ui.write(("internal: %s %s\n") % d)
1813 ui.write(("internal: %s %s\n") % d)
1815 ui.write(("standard: %s\n") % util.datestr(d))
1814 ui.write(("standard: %s\n") % util.datestr(d))
1816 if range:
1815 if range:
1817 m = util.matchdate(range)
1816 m = util.matchdate(range)
1818 ui.write(("match: %s\n") % m(d[0]))
1817 ui.write(("match: %s\n") % m(d[0]))
1819
1818
1820 @command('debugdiscovery',
1819 @command('debugdiscovery',
1821 [('', 'old', None, _('use old-style discovery')),
1820 [('', 'old', None, _('use old-style discovery')),
1822 ('', 'nonheads', None,
1821 ('', 'nonheads', None,
1823 _('use old-style discovery with non-heads included')),
1822 _('use old-style discovery with non-heads included')),
1824 ] + remoteopts,
1823 ] + remoteopts,
1825 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1824 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1826 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1825 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1827 """runs the changeset discovery protocol in isolation"""
1826 """runs the changeset discovery protocol in isolation"""
1828 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1827 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1829 opts.get('branch'))
1828 opts.get('branch'))
1830 remote = hg.peer(repo, opts, remoteurl)
1829 remote = hg.peer(repo, opts, remoteurl)
1831 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1830 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1832
1831
1833 # make sure tests are repeatable
1832 # make sure tests are repeatable
1834 random.seed(12323)
1833 random.seed(12323)
1835
1834
1836 def doit(localheads, remoteheads, remote=remote):
1835 def doit(localheads, remoteheads, remote=remote):
1837 if opts.get('old'):
1836 if opts.get('old'):
1838 if localheads:
1837 if localheads:
1839 raise util.Abort('cannot use localheads with old style '
1838 raise util.Abort('cannot use localheads with old style '
1840 'discovery')
1839 'discovery')
1841 if not util.safehasattr(remote, 'branches'):
1840 if not util.safehasattr(remote, 'branches'):
1842 # enable in-client legacy support
1841 # enable in-client legacy support
1843 remote = localrepo.locallegacypeer(remote.local())
1842 remote = localrepo.locallegacypeer(remote.local())
1844 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1843 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1845 force=True)
1844 force=True)
1846 common = set(common)
1845 common = set(common)
1847 if not opts.get('nonheads'):
1846 if not opts.get('nonheads'):
1848 ui.write(("unpruned common: %s\n") %
1847 ui.write(("unpruned common: %s\n") %
1849 " ".join(sorted(short(n) for n in common)))
1848 " ".join(sorted(short(n) for n in common)))
1850 dag = dagutil.revlogdag(repo.changelog)
1849 dag = dagutil.revlogdag(repo.changelog)
1851 all = dag.ancestorset(dag.internalizeall(common))
1850 all = dag.ancestorset(dag.internalizeall(common))
1852 common = dag.externalizeall(dag.headsetofconnecteds(all))
1851 common = dag.externalizeall(dag.headsetofconnecteds(all))
1853 else:
1852 else:
1854 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1853 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1855 common = set(common)
1854 common = set(common)
1856 rheads = set(hds)
1855 rheads = set(hds)
1857 lheads = set(repo.heads())
1856 lheads = set(repo.heads())
1858 ui.write(("common heads: %s\n") %
1857 ui.write(("common heads: %s\n") %
1859 " ".join(sorted(short(n) for n in common)))
1858 " ".join(sorted(short(n) for n in common)))
1860 if lheads <= common:
1859 if lheads <= common:
1861 ui.write(("local is subset\n"))
1860 ui.write(("local is subset\n"))
1862 elif rheads <= common:
1861 elif rheads <= common:
1863 ui.write(("remote is subset\n"))
1862 ui.write(("remote is subset\n"))
1864
1863
1865 serverlogs = opts.get('serverlog')
1864 serverlogs = opts.get('serverlog')
1866 if serverlogs:
1865 if serverlogs:
1867 for filename in serverlogs:
1866 for filename in serverlogs:
1868 logfile = open(filename, 'r')
1867 logfile = open(filename, 'r')
1869 try:
1868 try:
1870 line = logfile.readline()
1869 line = logfile.readline()
1871 while line:
1870 while line:
1872 parts = line.strip().split(';')
1871 parts = line.strip().split(';')
1873 op = parts[1]
1872 op = parts[1]
1874 if op == 'cg':
1873 if op == 'cg':
1875 pass
1874 pass
1876 elif op == 'cgss':
1875 elif op == 'cgss':
1877 doit(parts[2].split(' '), parts[3].split(' '))
1876 doit(parts[2].split(' '), parts[3].split(' '))
1878 elif op == 'unb':
1877 elif op == 'unb':
1879 doit(parts[3].split(' '), parts[2].split(' '))
1878 doit(parts[3].split(' '), parts[2].split(' '))
1880 line = logfile.readline()
1879 line = logfile.readline()
1881 finally:
1880 finally:
1882 logfile.close()
1881 logfile.close()
1883
1882
1884 else:
1883 else:
1885 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1884 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1886 opts.get('remote_head'))
1885 opts.get('remote_head'))
1887 localrevs = opts.get('local_head')
1886 localrevs = opts.get('local_head')
1888 doit(localrevs, remoterevs)
1887 doit(localrevs, remoterevs)
1889
1888
1890 @command('debugfileset',
1889 @command('debugfileset',
1891 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1890 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1892 _('[-r REV] FILESPEC'))
1891 _('[-r REV] FILESPEC'))
1893 def debugfileset(ui, repo, expr, **opts):
1892 def debugfileset(ui, repo, expr, **opts):
1894 '''parse and apply a fileset specification'''
1893 '''parse and apply a fileset specification'''
1895 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1894 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1896 if ui.verbose:
1895 if ui.verbose:
1897 tree = fileset.parse(expr)[0]
1896 tree = fileset.parse(expr)[0]
1898 ui.note(tree, "\n")
1897 ui.note(tree, "\n")
1899
1898
1900 for f in fileset.getfileset(ctx, expr):
1899 for f in fileset.getfileset(ctx, expr):
1901 ui.write("%s\n" % f)
1900 ui.write("%s\n" % f)
1902
1901
1903 @command('debugfsinfo', [], _('[PATH]'))
1902 @command('debugfsinfo', [], _('[PATH]'))
1904 def debugfsinfo(ui, path = "."):
1903 def debugfsinfo(ui, path = "."):
1905 """show information detected about current filesystem"""
1904 """show information detected about current filesystem"""
1906 util.writefile('.debugfsinfo', '')
1905 util.writefile('.debugfsinfo', '')
1907 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'))
1908 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'))
1909 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1908 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
1910 and 'yes' or 'no'))
1909 and 'yes' or 'no'))
1911 os.unlink('.debugfsinfo')
1910 os.unlink('.debugfsinfo')
1912
1911
1913 @command('debuggetbundle',
1912 @command('debuggetbundle',
1914 [('H', 'head', [], _('id of head node'), _('ID')),
1913 [('H', 'head', [], _('id of head node'), _('ID')),
1915 ('C', 'common', [], _('id of common node'), _('ID')),
1914 ('C', 'common', [], _('id of common node'), _('ID')),
1916 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1915 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1917 _('REPO FILE [-H|-C ID]...'))
1916 _('REPO FILE [-H|-C ID]...'))
1918 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1917 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1919 """retrieves a bundle from a repo
1918 """retrieves a bundle from a repo
1920
1919
1921 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
1922 given file.
1921 given file.
1923 """
1922 """
1924 repo = hg.peer(ui, opts, repopath)
1923 repo = hg.peer(ui, opts, repopath)
1925 if not repo.capable('getbundle'):
1924 if not repo.capable('getbundle'):
1926 raise util.Abort("getbundle() not supported by target repository")
1925 raise util.Abort("getbundle() not supported by target repository")
1927 args = {}
1926 args = {}
1928 if common:
1927 if common:
1929 args['common'] = [bin(s) for s in common]
1928 args['common'] = [bin(s) for s in common]
1930 if head:
1929 if head:
1931 args['heads'] = [bin(s) for s in head]
1930 args['heads'] = [bin(s) for s in head]
1932 # TODO: get desired bundlecaps from command line.
1931 # TODO: get desired bundlecaps from command line.
1933 args['bundlecaps'] = None
1932 args['bundlecaps'] = None
1934 bundle = repo.getbundle('debug', **args)
1933 bundle = repo.getbundle('debug', **args)
1935
1934
1936 bundletype = opts.get('type', 'bzip2').lower()
1935 bundletype = opts.get('type', 'bzip2').lower()
1937 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1936 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1938 bundletype = btypes.get(bundletype)
1937 bundletype = btypes.get(bundletype)
1939 if bundletype not in changegroup.bundletypes:
1938 if bundletype not in changegroup.bundletypes:
1940 raise util.Abort(_('unknown bundle type specified with --type'))
1939 raise util.Abort(_('unknown bundle type specified with --type'))
1941 changegroup.writebundle(bundle, bundlepath, bundletype)
1940 changegroup.writebundle(bundle, bundlepath, bundletype)
1942
1941
1943 @command('debugignore', [], '')
1942 @command('debugignore', [], '')
1944 def debugignore(ui, repo, *values, **opts):
1943 def debugignore(ui, repo, *values, **opts):
1945 """display the combined ignore pattern"""
1944 """display the combined ignore pattern"""
1946 ignore = repo.dirstate._ignore
1945 ignore = repo.dirstate._ignore
1947 includepat = getattr(ignore, 'includepat', None)
1946 includepat = getattr(ignore, 'includepat', None)
1948 if includepat is not None:
1947 if includepat is not None:
1949 ui.write("%s\n" % includepat)
1948 ui.write("%s\n" % includepat)
1950 else:
1949 else:
1951 raise util.Abort(_("no ignore patterns found"))
1950 raise util.Abort(_("no ignore patterns found"))
1952
1951
1953 @command('debugindex',
1952 @command('debugindex',
1954 [('c', 'changelog', False, _('open changelog')),
1953 [('c', 'changelog', False, _('open changelog')),
1955 ('m', 'manifest', False, _('open manifest')),
1954 ('m', 'manifest', False, _('open manifest')),
1956 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1955 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1957 _('[-f FORMAT] -c|-m|FILE'))
1956 _('[-f FORMAT] -c|-m|FILE'))
1958 def debugindex(ui, repo, file_ = None, **opts):
1957 def debugindex(ui, repo, file_ = None, **opts):
1959 """dump the contents of an index file"""
1958 """dump the contents of an index file"""
1960 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1959 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1961 format = opts.get('format', 0)
1960 format = opts.get('format', 0)
1962 if format not in (0, 1):
1961 if format not in (0, 1):
1963 raise util.Abort(_("unknown format %d") % format)
1962 raise util.Abort(_("unknown format %d") % format)
1964
1963
1965 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1964 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1966 if generaldelta:
1965 if generaldelta:
1967 basehdr = ' delta'
1966 basehdr = ' delta'
1968 else:
1967 else:
1969 basehdr = ' base'
1968 basehdr = ' base'
1970
1969
1971 if format == 0:
1970 if format == 0:
1972 ui.write(" rev offset length " + basehdr + " linkrev"
1971 ui.write(" rev offset length " + basehdr + " linkrev"
1973 " nodeid p1 p2\n")
1972 " nodeid p1 p2\n")
1974 elif format == 1:
1973 elif format == 1:
1975 ui.write(" rev flag offset length"
1974 ui.write(" rev flag offset length"
1976 " size " + basehdr + " link p1 p2"
1975 " size " + basehdr + " link p1 p2"
1977 " nodeid\n")
1976 " nodeid\n")
1978
1977
1979 for i in r:
1978 for i in r:
1980 node = r.node(i)
1979 node = r.node(i)
1981 if generaldelta:
1980 if generaldelta:
1982 base = r.deltaparent(i)
1981 base = r.deltaparent(i)
1983 else:
1982 else:
1984 base = r.chainbase(i)
1983 base = r.chainbase(i)
1985 if format == 0:
1984 if format == 0:
1986 try:
1985 try:
1987 pp = r.parents(node)
1986 pp = r.parents(node)
1988 except Exception:
1987 except Exception:
1989 pp = [nullid, nullid]
1988 pp = [nullid, nullid]
1990 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1989 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1991 i, r.start(i), r.length(i), base, r.linkrev(i),
1990 i, r.start(i), r.length(i), base, r.linkrev(i),
1992 short(node), short(pp[0]), short(pp[1])))
1991 short(node), short(pp[0]), short(pp[1])))
1993 elif format == 1:
1992 elif format == 1:
1994 pr = r.parentrevs(i)
1993 pr = r.parentrevs(i)
1995 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" % (
1996 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),
1997 base, r.linkrev(i), pr[0], pr[1], short(node)))
1996 base, r.linkrev(i), pr[0], pr[1], short(node)))
1998
1997
1999 @command('debugindexdot', [], _('FILE'))
1998 @command('debugindexdot', [], _('FILE'))
2000 def debugindexdot(ui, repo, file_):
1999 def debugindexdot(ui, repo, file_):
2001 """dump an index DAG as a graphviz dot file"""
2000 """dump an index DAG as a graphviz dot file"""
2002 r = None
2001 r = None
2003 if repo:
2002 if repo:
2004 filelog = repo.file(file_)
2003 filelog = repo.file(file_)
2005 if len(filelog):
2004 if len(filelog):
2006 r = filelog
2005 r = filelog
2007 if not r:
2006 if not r:
2008 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2007 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2009 ui.write(("digraph G {\n"))
2008 ui.write(("digraph G {\n"))
2010 for i in r:
2009 for i in r:
2011 node = r.node(i)
2010 node = r.node(i)
2012 pp = r.parents(node)
2011 pp = r.parents(node)
2013 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2012 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2014 if pp[1] != nullid:
2013 if pp[1] != nullid:
2015 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2014 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2016 ui.write("}\n")
2015 ui.write("}\n")
2017
2016
2018 @command('debuginstall', [], '')
2017 @command('debuginstall', [], '')
2019 def debuginstall(ui):
2018 def debuginstall(ui):
2020 '''test Mercurial installation
2019 '''test Mercurial installation
2021
2020
2022 Returns 0 on success.
2021 Returns 0 on success.
2023 '''
2022 '''
2024
2023
2025 def writetemp(contents):
2024 def writetemp(contents):
2026 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2025 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2027 f = os.fdopen(fd, "wb")
2026 f = os.fdopen(fd, "wb")
2028 f.write(contents)
2027 f.write(contents)
2029 f.close()
2028 f.close()
2030 return name
2029 return name
2031
2030
2032 problems = 0
2031 problems = 0
2033
2032
2034 # encoding
2033 # encoding
2035 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2034 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2036 try:
2035 try:
2037 encoding.fromlocal("test")
2036 encoding.fromlocal("test")
2038 except util.Abort, inst:
2037 except util.Abort, inst:
2039 ui.write(" %s\n" % inst)
2038 ui.write(" %s\n" % inst)
2040 ui.write(_(" (check that your locale is properly set)\n"))
2039 ui.write(_(" (check that your locale is properly set)\n"))
2041 problems += 1
2040 problems += 1
2042
2041
2043 # Python lib
2042 # Python lib
2044 ui.status(_("checking Python lib (%s)...\n")
2043 ui.status(_("checking Python lib (%s)...\n")
2045 % os.path.dirname(os.__file__))
2044 % os.path.dirname(os.__file__))
2046
2045
2047 # compiled modules
2046 # compiled modules
2048 ui.status(_("checking installed modules (%s)...\n")
2047 ui.status(_("checking installed modules (%s)...\n")
2049 % os.path.dirname(__file__))
2048 % os.path.dirname(__file__))
2050 try:
2049 try:
2051 import bdiff, mpatch, base85, osutil
2050 import bdiff, mpatch, base85, osutil
2052 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2051 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2053 except Exception, inst:
2052 except Exception, inst:
2054 ui.write(" %s\n" % inst)
2053 ui.write(" %s\n" % inst)
2055 ui.write(_(" One or more extensions could not be found"))
2054 ui.write(_(" One or more extensions could not be found"))
2056 ui.write(_(" (check that you compiled the extensions)\n"))
2055 ui.write(_(" (check that you compiled the extensions)\n"))
2057 problems += 1
2056 problems += 1
2058
2057
2059 # templates
2058 # templates
2060 import templater
2059 import templater
2061 p = templater.templatepath()
2060 p = templater.templatepath()
2062 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2061 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2063 try:
2062 try:
2064 templater.templater(templater.templatepath("map-cmdline.default"))
2063 templater.templater(templater.templatepath("map-cmdline.default"))
2065 except Exception, inst:
2064 except Exception, inst:
2066 ui.write(" %s\n" % inst)
2065 ui.write(" %s\n" % inst)
2067 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2066 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2068 problems += 1
2067 problems += 1
2069
2068
2070 # editor
2069 # editor
2071 ui.status(_("checking commit editor...\n"))
2070 ui.status(_("checking commit editor...\n"))
2072 editor = ui.geteditor()
2071 editor = ui.geteditor()
2073 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2072 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2074 if not cmdpath:
2073 if not cmdpath:
2075 if editor == 'vi':
2074 if editor == 'vi':
2076 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"))
2077 ui.write(_(" (specify a commit editor in your configuration"
2076 ui.write(_(" (specify a commit editor in your configuration"
2078 " file)\n"))
2077 " file)\n"))
2079 else:
2078 else:
2080 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2079 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2081 ui.write(_(" (specify a commit editor in your configuration"
2080 ui.write(_(" (specify a commit editor in your configuration"
2082 " file)\n"))
2081 " file)\n"))
2083 problems += 1
2082 problems += 1
2084
2083
2085 # check username
2084 # check username
2086 ui.status(_("checking username...\n"))
2085 ui.status(_("checking username...\n"))
2087 try:
2086 try:
2088 ui.username()
2087 ui.username()
2089 except util.Abort, e:
2088 except util.Abort, e:
2090 ui.write(" %s\n" % e)
2089 ui.write(" %s\n" % e)
2091 ui.write(_(" (specify a username in your configuration file)\n"))
2090 ui.write(_(" (specify a username in your configuration file)\n"))
2092 problems += 1
2091 problems += 1
2093
2092
2094 if not problems:
2093 if not problems:
2095 ui.status(_("no problems detected\n"))
2094 ui.status(_("no problems detected\n"))
2096 else:
2095 else:
2097 ui.write(_("%s problems detected,"
2096 ui.write(_("%s problems detected,"
2098 " please check your install!\n") % problems)
2097 " please check your install!\n") % problems)
2099
2098
2100 return problems
2099 return problems
2101
2100
2102 @command('debugknown', [], _('REPO ID...'))
2101 @command('debugknown', [], _('REPO ID...'))
2103 def debugknown(ui, repopath, *ids, **opts):
2102 def debugknown(ui, repopath, *ids, **opts):
2104 """test whether node ids are known to a repo
2103 """test whether node ids are known to a repo
2105
2104
2106 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
2107 and 1s indicating unknown/known.
2106 and 1s indicating unknown/known.
2108 """
2107 """
2109 repo = hg.peer(ui, opts, repopath)
2108 repo = hg.peer(ui, opts, repopath)
2110 if not repo.capable('known'):
2109 if not repo.capable('known'):
2111 raise util.Abort("known() not supported by target repository")
2110 raise util.Abort("known() not supported by target repository")
2112 flags = repo.known([bin(s) for s in ids])
2111 flags = repo.known([bin(s) for s in ids])
2113 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])))
2114
2113
2115 @command('debuglabelcomplete', [], _('LABEL...'))
2114 @command('debuglabelcomplete', [], _('LABEL...'))
2116 def debuglabelcomplete(ui, repo, *args):
2115 def debuglabelcomplete(ui, repo, *args):
2117 '''complete "labels" - tags, open branch names, bookmark names'''
2116 '''complete "labels" - tags, open branch names, bookmark names'''
2118
2117
2119 labels = set()
2118 labels = set()
2120 labels.update(t[0] for t in repo.tagslist())
2119 labels.update(t[0] for t in repo.tagslist())
2121 labels.update(repo._bookmarks.keys())
2120 labels.update(repo._bookmarks.keys())
2122 for heads in repo.branchmap().itervalues():
2121 for heads in repo.branchmap().itervalues():
2123 for h in heads:
2122 for h in heads:
2124 ctx = repo[h]
2123 ctx = repo[h]
2125 if not ctx.closesbranch():
2124 if not ctx.closesbranch():
2126 labels.add(ctx.branch())
2125 labels.add(ctx.branch())
2127 completions = set()
2126 completions = set()
2128 if not args:
2127 if not args:
2129 args = ['']
2128 args = ['']
2130 for a in args:
2129 for a in args:
2131 completions.update(l for l in labels if l.startswith(a))
2130 completions.update(l for l in labels if l.startswith(a))
2132 ui.write('\n'.join(sorted(completions)))
2131 ui.write('\n'.join(sorted(completions)))
2133 ui.write('\n')
2132 ui.write('\n')
2134
2133
2135 @command('debugobsolete',
2134 @command('debugobsolete',
2136 [('', 'flags', 0, _('markers flag')),
2135 [('', 'flags', 0, _('markers flag')),
2137 ] + commitopts2,
2136 ] + commitopts2,
2138 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2137 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2139 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2138 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2140 """create arbitrary obsolete marker
2139 """create arbitrary obsolete marker
2141
2140
2142 With no arguments, displays the list of obsolescence markers."""
2141 With no arguments, displays the list of obsolescence markers."""
2143 def parsenodeid(s):
2142 def parsenodeid(s):
2144 try:
2143 try:
2145 # We do not use revsingle/revrange functions here to accept
2144 # We do not use revsingle/revrange functions here to accept
2146 # arbitrary node identifiers, possibly not present in the
2145 # arbitrary node identifiers, possibly not present in the
2147 # local repository.
2146 # local repository.
2148 n = bin(s)
2147 n = bin(s)
2149 if len(n) != len(nullid):
2148 if len(n) != len(nullid):
2150 raise TypeError()
2149 raise TypeError()
2151 return n
2150 return n
2152 except TypeError:
2151 except TypeError:
2153 raise util.Abort('changeset references must be full hexadecimal '
2152 raise util.Abort('changeset references must be full hexadecimal '
2154 'node identifiers')
2153 'node identifiers')
2155
2154
2156 if precursor is not None:
2155 if precursor is not None:
2157 metadata = {}
2156 metadata = {}
2158 if 'date' in opts:
2157 if 'date' in opts:
2159 metadata['date'] = opts['date']
2158 metadata['date'] = opts['date']
2160 metadata['user'] = opts['user'] or ui.username()
2159 metadata['user'] = opts['user'] or ui.username()
2161 succs = tuple(parsenodeid(succ) for succ in successors)
2160 succs = tuple(parsenodeid(succ) for succ in successors)
2162 l = repo.lock()
2161 l = repo.lock()
2163 try:
2162 try:
2164 tr = repo.transaction('debugobsolete')
2163 tr = repo.transaction('debugobsolete')
2165 try:
2164 try:
2166 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2165 repo.obsstore.create(tr, parsenodeid(precursor), succs,
2167 opts['flags'], metadata)
2166 opts['flags'], metadata)
2168 tr.close()
2167 tr.close()
2169 finally:
2168 finally:
2170 tr.release()
2169 tr.release()
2171 finally:
2170 finally:
2172 l.release()
2171 l.release()
2173 else:
2172 else:
2174 for m in obsolete.allmarkers(repo):
2173 for m in obsolete.allmarkers(repo):
2175 ui.write(hex(m.precnode()))
2174 ui.write(hex(m.precnode()))
2176 for repl in m.succnodes():
2175 for repl in m.succnodes():
2177 ui.write(' ')
2176 ui.write(' ')
2178 ui.write(hex(repl))
2177 ui.write(hex(repl))
2179 ui.write(' %X ' % m._data[2])
2178 ui.write(' %X ' % m._data[2])
2180 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2179 ui.write('{%s}' % (', '.join('%r: %r' % t for t in
2181 sorted(m.metadata().items()))))
2180 sorted(m.metadata().items()))))
2182 ui.write('\n')
2181 ui.write('\n')
2183
2182
2184 @command('debugpathcomplete',
2183 @command('debugpathcomplete',
2185 [('f', 'full', None, _('complete an entire path')),
2184 [('f', 'full', None, _('complete an entire path')),
2186 ('n', 'normal', None, _('show only normal files')),
2185 ('n', 'normal', None, _('show only normal files')),
2187 ('a', 'added', None, _('show only added files')),
2186 ('a', 'added', None, _('show only added files')),
2188 ('r', 'removed', None, _('show only removed files'))],
2187 ('r', 'removed', None, _('show only removed files'))],
2189 _('FILESPEC...'))
2188 _('FILESPEC...'))
2190 def debugpathcomplete(ui, repo, *specs, **opts):
2189 def debugpathcomplete(ui, repo, *specs, **opts):
2191 '''complete part or all of a tracked path
2190 '''complete part or all of a tracked path
2192
2191
2193 This command supports shells that offer path name completion. It
2192 This command supports shells that offer path name completion. It
2194 currently completes only files already known to the dirstate.
2193 currently completes only files already known to the dirstate.
2195
2194
2196 Completion extends only to the next path segment unless
2195 Completion extends only to the next path segment unless
2197 --full is specified, in which case entire paths are used.'''
2196 --full is specified, in which case entire paths are used.'''
2198
2197
2199 def complete(path, acceptable):
2198 def complete(path, acceptable):
2200 dirstate = repo.dirstate
2199 dirstate = repo.dirstate
2201 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2200 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2202 rootdir = repo.root + os.sep
2201 rootdir = repo.root + os.sep
2203 if spec != repo.root and not spec.startswith(rootdir):
2202 if spec != repo.root and not spec.startswith(rootdir):
2204 return [], []
2203 return [], []
2205 if os.path.isdir(spec):
2204 if os.path.isdir(spec):
2206 spec += '/'
2205 spec += '/'
2207 spec = spec[len(rootdir):]
2206 spec = spec[len(rootdir):]
2208 fixpaths = os.sep != '/'
2207 fixpaths = os.sep != '/'
2209 if fixpaths:
2208 if fixpaths:
2210 spec = spec.replace(os.sep, '/')
2209 spec = spec.replace(os.sep, '/')
2211 speclen = len(spec)
2210 speclen = len(spec)
2212 fullpaths = opts['full']
2211 fullpaths = opts['full']
2213 files, dirs = set(), set()
2212 files, dirs = set(), set()
2214 adddir, addfile = dirs.add, files.add
2213 adddir, addfile = dirs.add, files.add
2215 for f, st in dirstate.iteritems():
2214 for f, st in dirstate.iteritems():
2216 if f.startswith(spec) and st[0] in acceptable:
2215 if f.startswith(spec) and st[0] in acceptable:
2217 if fixpaths:
2216 if fixpaths:
2218 f = f.replace('/', os.sep)
2217 f = f.replace('/', os.sep)
2219 if fullpaths:
2218 if fullpaths:
2220 addfile(f)
2219 addfile(f)
2221 continue
2220 continue
2222 s = f.find(os.sep, speclen)
2221 s = f.find(os.sep, speclen)
2223 if s >= 0:
2222 if s >= 0:
2224 adddir(f[:s + 1])
2223 adddir(f[:s + 1])
2225 else:
2224 else:
2226 addfile(f)
2225 addfile(f)
2227 return files, dirs
2226 return files, dirs
2228
2227
2229 acceptable = ''
2228 acceptable = ''
2230 if opts['normal']:
2229 if opts['normal']:
2231 acceptable += 'nm'
2230 acceptable += 'nm'
2232 if opts['added']:
2231 if opts['added']:
2233 acceptable += 'a'
2232 acceptable += 'a'
2234 if opts['removed']:
2233 if opts['removed']:
2235 acceptable += 'r'
2234 acceptable += 'r'
2236 cwd = repo.getcwd()
2235 cwd = repo.getcwd()
2237 if not specs:
2236 if not specs:
2238 specs = ['.']
2237 specs = ['.']
2239
2238
2240 files, dirs = set(), set()
2239 files, dirs = set(), set()
2241 for spec in specs:
2240 for spec in specs:
2242 f, d = complete(spec, acceptable or 'nmar')
2241 f, d = complete(spec, acceptable or 'nmar')
2243 files.update(f)
2242 files.update(f)
2244 dirs.update(d)
2243 dirs.update(d)
2245 if not files and len(dirs) == 1:
2244 if not files and len(dirs) == 1:
2246 # force the shell to consider a completion that matches one
2245 # force the shell to consider a completion that matches one
2247 # directory and zero files to be ambiguous
2246 # directory and zero files to be ambiguous
2248 dirs.add(iter(dirs).next() + '.')
2247 dirs.add(iter(dirs).next() + '.')
2249 files.update(dirs)
2248 files.update(dirs)
2250 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)))
2251 ui.write('\n')
2250 ui.write('\n')
2252
2251
2253 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2252 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2254 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2253 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2255 '''access the pushkey key/value protocol
2254 '''access the pushkey key/value protocol
2256
2255
2257 With two args, list the keys in the given namespace.
2256 With two args, list the keys in the given namespace.
2258
2257
2259 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.
2260 Reports success or failure.
2259 Reports success or failure.
2261 '''
2260 '''
2262
2261
2263 target = hg.peer(ui, {}, repopath)
2262 target = hg.peer(ui, {}, repopath)
2264 if keyinfo:
2263 if keyinfo:
2265 key, old, new = keyinfo
2264 key, old, new = keyinfo
2266 r = target.pushkey(namespace, key, old, new)
2265 r = target.pushkey(namespace, key, old, new)
2267 ui.status(str(r) + '\n')
2266 ui.status(str(r) + '\n')
2268 return not r
2267 return not r
2269 else:
2268 else:
2270 for k, v in sorted(target.listkeys(namespace).iteritems()):
2269 for k, v in sorted(target.listkeys(namespace).iteritems()):
2271 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2270 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2272 v.encode('string-escape')))
2271 v.encode('string-escape')))
2273
2272
2274 @command('debugpvec', [], _('A B'))
2273 @command('debugpvec', [], _('A B'))
2275 def debugpvec(ui, repo, a, b=None):
2274 def debugpvec(ui, repo, a, b=None):
2276 ca = scmutil.revsingle(repo, a)
2275 ca = scmutil.revsingle(repo, a)
2277 cb = scmutil.revsingle(repo, b)
2276 cb = scmutil.revsingle(repo, b)
2278 pa = pvec.ctxpvec(ca)
2277 pa = pvec.ctxpvec(ca)
2279 pb = pvec.ctxpvec(cb)
2278 pb = pvec.ctxpvec(cb)
2280 if pa == pb:
2279 if pa == pb:
2281 rel = "="
2280 rel = "="
2282 elif pa > pb:
2281 elif pa > pb:
2283 rel = ">"
2282 rel = ">"
2284 elif pa < pb:
2283 elif pa < pb:
2285 rel = "<"
2284 rel = "<"
2286 elif pa | pb:
2285 elif pa | pb:
2287 rel = "|"
2286 rel = "|"
2288 ui.write(_("a: %s\n") % pa)
2287 ui.write(_("a: %s\n") % pa)
2289 ui.write(_("b: %s\n") % pb)
2288 ui.write(_("b: %s\n") % pb)
2290 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))
2291 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2290 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2292 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2291 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2293 pa.distance(pb), rel))
2292 pa.distance(pb), rel))
2294
2293
2295 @command('debugrebuilddirstate|debugrebuildstate',
2294 @command('debugrebuilddirstate|debugrebuildstate',
2296 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2295 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2297 _('[-r REV]'))
2296 _('[-r REV]'))
2298 def debugrebuilddirstate(ui, repo, rev):
2297 def debugrebuilddirstate(ui, repo, rev):
2299 """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
2300
2299
2301 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.
2302
2301
2303 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.
2304 The actual working directory content or existing dirstate
2303 The actual working directory content or existing dirstate
2305 information such as adds or removes is not considered.
2304 information such as adds or removes is not considered.
2306
2305
2307 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
2308 check the actual file content.
2307 check the actual file content.
2309 """
2308 """
2310 ctx = scmutil.revsingle(repo, rev)
2309 ctx = scmutil.revsingle(repo, rev)
2311 wlock = repo.wlock()
2310 wlock = repo.wlock()
2312 try:
2311 try:
2313 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2312 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2314 finally:
2313 finally:
2315 wlock.release()
2314 wlock.release()
2316
2315
2317 @command('debugrename',
2316 @command('debugrename',
2318 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2317 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2319 _('[-r REV] FILE'))
2318 _('[-r REV] FILE'))
2320 def debugrename(ui, repo, file1, *pats, **opts):
2319 def debugrename(ui, repo, file1, *pats, **opts):
2321 """dump rename information"""
2320 """dump rename information"""
2322
2321
2323 ctx = scmutil.revsingle(repo, opts.get('rev'))
2322 ctx = scmutil.revsingle(repo, opts.get('rev'))
2324 m = scmutil.match(ctx, (file1,) + pats, opts)
2323 m = scmutil.match(ctx, (file1,) + pats, opts)
2325 for abs in ctx.walk(m):
2324 for abs in ctx.walk(m):
2326 fctx = ctx[abs]
2325 fctx = ctx[abs]
2327 o = fctx.filelog().renamed(fctx.filenode())
2326 o = fctx.filelog().renamed(fctx.filenode())
2328 rel = m.rel(abs)
2327 rel = m.rel(abs)
2329 if o:
2328 if o:
2330 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])))
2331 else:
2330 else:
2332 ui.write(_("%s not renamed\n") % rel)
2331 ui.write(_("%s not renamed\n") % rel)
2333
2332
2334 @command('debugrevlog',
2333 @command('debugrevlog',
2335 [('c', 'changelog', False, _('open changelog')),
2334 [('c', 'changelog', False, _('open changelog')),
2336 ('m', 'manifest', False, _('open manifest')),
2335 ('m', 'manifest', False, _('open manifest')),
2337 ('d', 'dump', False, _('dump index data'))],
2336 ('d', 'dump', False, _('dump index data'))],
2338 _('-c|-m|FILE'))
2337 _('-c|-m|FILE'))
2339 def debugrevlog(ui, repo, file_ = None, **opts):
2338 def debugrevlog(ui, repo, file_ = None, **opts):
2340 """show data and statistics about a revlog"""
2339 """show data and statistics about a revlog"""
2341 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2340 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2342
2341
2343 if opts.get("dump"):
2342 if opts.get("dump"):
2344 numrevs = len(r)
2343 numrevs = len(r)
2345 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2344 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2346 " rawsize totalsize compression heads\n")
2345 " rawsize totalsize compression heads\n")
2347 ts = 0
2346 ts = 0
2348 heads = set()
2347 heads = set()
2349 for rev in xrange(numrevs):
2348 for rev in xrange(numrevs):
2350 dbase = r.deltaparent(rev)
2349 dbase = r.deltaparent(rev)
2351 if dbase == -1:
2350 if dbase == -1:
2352 dbase = rev
2351 dbase = rev
2353 cbase = r.chainbase(rev)
2352 cbase = r.chainbase(rev)
2354 p1, p2 = r.parentrevs(rev)
2353 p1, p2 = r.parentrevs(rev)
2355 rs = r.rawsize(rev)
2354 rs = r.rawsize(rev)
2356 ts = ts + rs
2355 ts = ts + rs
2357 heads -= set(r.parentrevs(rev))
2356 heads -= set(r.parentrevs(rev))
2358 heads.add(rev)
2357 heads.add(rev)
2359 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" %
2360 (rev, p1, p2, r.start(rev), r.end(rev),
2359 (rev, p1, p2, r.start(rev), r.end(rev),
2361 r.start(dbase), r.start(cbase),
2360 r.start(dbase), r.start(cbase),
2362 r.start(p1), r.start(p2),
2361 r.start(p1), r.start(p2),
2363 rs, ts, ts / r.end(rev), len(heads)))
2362 rs, ts, ts / r.end(rev), len(heads)))
2364 return 0
2363 return 0
2365
2364
2366 v = r.version
2365 v = r.version
2367 format = v & 0xFFFF
2366 format = v & 0xFFFF
2368 flags = []
2367 flags = []
2369 gdelta = False
2368 gdelta = False
2370 if v & revlog.REVLOGNGINLINEDATA:
2369 if v & revlog.REVLOGNGINLINEDATA:
2371 flags.append('inline')
2370 flags.append('inline')
2372 if v & revlog.REVLOGGENERALDELTA:
2371 if v & revlog.REVLOGGENERALDELTA:
2373 gdelta = True
2372 gdelta = True
2374 flags.append('generaldelta')
2373 flags.append('generaldelta')
2375 if not flags:
2374 if not flags:
2376 flags = ['(none)']
2375 flags = ['(none)']
2377
2376
2378 nummerges = 0
2377 nummerges = 0
2379 numfull = 0
2378 numfull = 0
2380 numprev = 0
2379 numprev = 0
2381 nump1 = 0
2380 nump1 = 0
2382 nump2 = 0
2381 nump2 = 0
2383 numother = 0
2382 numother = 0
2384 nump1prev = 0
2383 nump1prev = 0
2385 nump2prev = 0
2384 nump2prev = 0
2386 chainlengths = []
2385 chainlengths = []
2387
2386
2388 datasize = [None, 0, 0L]
2387 datasize = [None, 0, 0L]
2389 fullsize = [None, 0, 0L]
2388 fullsize = [None, 0, 0L]
2390 deltasize = [None, 0, 0L]
2389 deltasize = [None, 0, 0L]
2391
2390
2392 def addsize(size, l):
2391 def addsize(size, l):
2393 if l[0] is None or size < l[0]:
2392 if l[0] is None or size < l[0]:
2394 l[0] = size
2393 l[0] = size
2395 if size > l[1]:
2394 if size > l[1]:
2396 l[1] = size
2395 l[1] = size
2397 l[2] += size
2396 l[2] += size
2398
2397
2399 numrevs = len(r)
2398 numrevs = len(r)
2400 for rev in xrange(numrevs):
2399 for rev in xrange(numrevs):
2401 p1, p2 = r.parentrevs(rev)
2400 p1, p2 = r.parentrevs(rev)
2402 delta = r.deltaparent(rev)
2401 delta = r.deltaparent(rev)
2403 if format > 0:
2402 if format > 0:
2404 addsize(r.rawsize(rev), datasize)
2403 addsize(r.rawsize(rev), datasize)
2405 if p2 != nullrev:
2404 if p2 != nullrev:
2406 nummerges += 1
2405 nummerges += 1
2407 size = r.length(rev)
2406 size = r.length(rev)
2408 if delta == nullrev:
2407 if delta == nullrev:
2409 chainlengths.append(0)
2408 chainlengths.append(0)
2410 numfull += 1
2409 numfull += 1
2411 addsize(size, fullsize)
2410 addsize(size, fullsize)
2412 else:
2411 else:
2413 chainlengths.append(chainlengths[delta] + 1)
2412 chainlengths.append(chainlengths[delta] + 1)
2414 addsize(size, deltasize)
2413 addsize(size, deltasize)
2415 if delta == rev - 1:
2414 if delta == rev - 1:
2416 numprev += 1
2415 numprev += 1
2417 if delta == p1:
2416 if delta == p1:
2418 nump1prev += 1
2417 nump1prev += 1
2419 elif delta == p2:
2418 elif delta == p2:
2420 nump2prev += 1
2419 nump2prev += 1
2421 elif delta == p1:
2420 elif delta == p1:
2422 nump1 += 1
2421 nump1 += 1
2423 elif delta == p2:
2422 elif delta == p2:
2424 nump2 += 1
2423 nump2 += 1
2425 elif delta != nullrev:
2424 elif delta != nullrev:
2426 numother += 1
2425 numother += 1
2427
2426
2428 # Adjust size min value for empty cases
2427 # Adjust size min value for empty cases
2429 for size in (datasize, fullsize, deltasize):
2428 for size in (datasize, fullsize, deltasize):
2430 if size[0] is None:
2429 if size[0] is None:
2431 size[0] = 0
2430 size[0] = 0
2432
2431
2433 numdeltas = numrevs - numfull
2432 numdeltas = numrevs - numfull
2434 numoprev = numprev - nump1prev - nump2prev
2433 numoprev = numprev - nump1prev - nump2prev
2435 totalrawsize = datasize[2]
2434 totalrawsize = datasize[2]
2436 datasize[2] /= numrevs
2435 datasize[2] /= numrevs
2437 fulltotal = fullsize[2]
2436 fulltotal = fullsize[2]
2438 fullsize[2] /= numfull
2437 fullsize[2] /= numfull
2439 deltatotal = deltasize[2]
2438 deltatotal = deltasize[2]
2440 if numrevs - numfull > 0:
2439 if numrevs - numfull > 0:
2441 deltasize[2] /= numrevs - numfull
2440 deltasize[2] /= numrevs - numfull
2442 totalsize = fulltotal + deltatotal
2441 totalsize = fulltotal + deltatotal
2443 avgchainlen = sum(chainlengths) / numrevs
2442 avgchainlen = sum(chainlengths) / numrevs
2444 compratio = totalrawsize / totalsize
2443 compratio = totalrawsize / totalsize
2445
2444
2446 basedfmtstr = '%%%dd\n'
2445 basedfmtstr = '%%%dd\n'
2447 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2446 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2448
2447
2449 def dfmtstr(max):
2448 def dfmtstr(max):
2450 return basedfmtstr % len(str(max))
2449 return basedfmtstr % len(str(max))
2451 def pcfmtstr(max, padding=0):
2450 def pcfmtstr(max, padding=0):
2452 return basepcfmtstr % (len(str(max)), ' ' * padding)
2451 return basepcfmtstr % (len(str(max)), ' ' * padding)
2453
2452
2454 def pcfmt(value, total):
2453 def pcfmt(value, total):
2455 return (value, 100 * float(value) / total)
2454 return (value, 100 * float(value) / total)
2456
2455
2457 ui.write(('format : %d\n') % format)
2456 ui.write(('format : %d\n') % format)
2458 ui.write(('flags : %s\n') % ', '.join(flags))
2457 ui.write(('flags : %s\n') % ', '.join(flags))
2459
2458
2460 ui.write('\n')
2459 ui.write('\n')
2461 fmt = pcfmtstr(totalsize)
2460 fmt = pcfmtstr(totalsize)
2462 fmt2 = dfmtstr(totalsize)
2461 fmt2 = dfmtstr(totalsize)
2463 ui.write(('revisions : ') + fmt2 % numrevs)
2462 ui.write(('revisions : ') + fmt2 % numrevs)
2464 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2463 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2465 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2464 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2466 ui.write(('revisions : ') + fmt2 % numrevs)
2465 ui.write(('revisions : ') + fmt2 % numrevs)
2467 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2466 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2468 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2467 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2469 ui.write(('revision size : ') + fmt2 % totalsize)
2468 ui.write(('revision size : ') + fmt2 % totalsize)
2470 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2469 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2471 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2470 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2472
2471
2473 ui.write('\n')
2472 ui.write('\n')
2474 fmt = dfmtstr(max(avgchainlen, compratio))
2473 fmt = dfmtstr(max(avgchainlen, compratio))
2475 ui.write(('avg chain length : ') + fmt % avgchainlen)
2474 ui.write(('avg chain length : ') + fmt % avgchainlen)
2476 ui.write(('compression ratio : ') + fmt % compratio)
2475 ui.write(('compression ratio : ') + fmt % compratio)
2477
2476
2478 if format > 0:
2477 if format > 0:
2479 ui.write('\n')
2478 ui.write('\n')
2480 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')
2481 % tuple(datasize))
2480 % tuple(datasize))
2482 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')
2483 % tuple(fullsize))
2482 % tuple(fullsize))
2484 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2483 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2485 % tuple(deltasize))
2484 % tuple(deltasize))
2486
2485
2487 if numdeltas > 0:
2486 if numdeltas > 0:
2488 ui.write('\n')
2487 ui.write('\n')
2489 fmt = pcfmtstr(numdeltas)
2488 fmt = pcfmtstr(numdeltas)
2490 fmt2 = pcfmtstr(numdeltas, 4)
2489 fmt2 = pcfmtstr(numdeltas, 4)
2491 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2490 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2492 if numprev > 0:
2491 if numprev > 0:
2493 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2492 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2494 numprev))
2493 numprev))
2495 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2494 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2496 numprev))
2495 numprev))
2497 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2496 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2498 numprev))
2497 numprev))
2499 if gdelta:
2498 if gdelta:
2500 ui.write(('deltas against p1 : ')
2499 ui.write(('deltas against p1 : ')
2501 + fmt % pcfmt(nump1, numdeltas))
2500 + fmt % pcfmt(nump1, numdeltas))
2502 ui.write(('deltas against p2 : ')
2501 ui.write(('deltas against p2 : ')
2503 + fmt % pcfmt(nump2, numdeltas))
2502 + fmt % pcfmt(nump2, numdeltas))
2504 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2503 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2505 numdeltas))
2504 numdeltas))
2506
2505
2507 @command('debugrevspec', [], ('REVSPEC'))
2506 @command('debugrevspec', [], ('REVSPEC'))
2508 def debugrevspec(ui, repo, expr):
2507 def debugrevspec(ui, repo, expr):
2509 """parse and apply a revision specification
2508 """parse and apply a revision specification
2510
2509
2511 Use --verbose to print the parsed tree before and after aliases
2510 Use --verbose to print the parsed tree before and after aliases
2512 expansion.
2511 expansion.
2513 """
2512 """
2514 if ui.verbose:
2513 if ui.verbose:
2515 tree = revset.parse(expr)[0]
2514 tree = revset.parse(expr)[0]
2516 ui.note(revset.prettyformat(tree), "\n")
2515 ui.note(revset.prettyformat(tree), "\n")
2517 newtree = revset.findaliases(ui, tree)
2516 newtree = revset.findaliases(ui, tree)
2518 if newtree != tree:
2517 if newtree != tree:
2519 ui.note(revset.prettyformat(newtree), "\n")
2518 ui.note(revset.prettyformat(newtree), "\n")
2520 func = revset.match(ui, expr)
2519 func = revset.match(ui, expr)
2521 for c in func(repo, range(len(repo))):
2520 for c in func(repo, range(len(repo))):
2522 ui.write("%s\n" % c)
2521 ui.write("%s\n" % c)
2523
2522
2524 @command('debugsetparents', [], _('REV1 [REV2]'))
2523 @command('debugsetparents', [], _('REV1 [REV2]'))
2525 def debugsetparents(ui, repo, rev1, rev2=None):
2524 def debugsetparents(ui, repo, rev1, rev2=None):
2526 """manually set the parents of the current working directory
2525 """manually set the parents of the current working directory
2527
2526
2528 This is useful for writing repository conversion tools, but should
2527 This is useful for writing repository conversion tools, but should
2529 be used with care.
2528 be used with care.
2530
2529
2531 Returns 0 on success.
2530 Returns 0 on success.
2532 """
2531 """
2533
2532
2534 r1 = scmutil.revsingle(repo, rev1).node()
2533 r1 = scmutil.revsingle(repo, rev1).node()
2535 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2534 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2536
2535
2537 wlock = repo.wlock()
2536 wlock = repo.wlock()
2538 try:
2537 try:
2539 repo.setparents(r1, r2)
2538 repo.setparents(r1, r2)
2540 finally:
2539 finally:
2541 wlock.release()
2540 wlock.release()
2542
2541
2543 @command('debugdirstate|debugstate',
2542 @command('debugdirstate|debugstate',
2544 [('', 'nodates', None, _('do not display the saved mtime')),
2543 [('', 'nodates', None, _('do not display the saved mtime')),
2545 ('', 'datesort', None, _('sort by saved mtime'))],
2544 ('', 'datesort', None, _('sort by saved mtime'))],
2546 _('[OPTION]...'))
2545 _('[OPTION]...'))
2547 def debugstate(ui, repo, nodates=None, datesort=None):
2546 def debugstate(ui, repo, nodates=None, datesort=None):
2548 """show the contents of the current dirstate"""
2547 """show the contents of the current dirstate"""
2549 timestr = ""
2548 timestr = ""
2550 showdate = not nodates
2549 showdate = not nodates
2551 if datesort:
2550 if datesort:
2552 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
2553 else:
2552 else:
2554 keyfunc = None # sort by filename
2553 keyfunc = None # sort by filename
2555 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2554 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2556 if showdate:
2555 if showdate:
2557 if ent[3] == -1:
2556 if ent[3] == -1:
2558 # Pad or slice to locale representation
2557 # Pad or slice to locale representation
2559 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2558 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2560 time.localtime(0)))
2559 time.localtime(0)))
2561 timestr = 'unset'
2560 timestr = 'unset'
2562 timestr = (timestr[:locale_len] +
2561 timestr = (timestr[:locale_len] +
2563 ' ' * (locale_len - len(timestr)))
2562 ' ' * (locale_len - len(timestr)))
2564 else:
2563 else:
2565 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2564 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2566 time.localtime(ent[3]))
2565 time.localtime(ent[3]))
2567 if ent[1] & 020000:
2566 if ent[1] & 020000:
2568 mode = 'lnk'
2567 mode = 'lnk'
2569 else:
2568 else:
2570 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2569 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2571 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_))
2572 for f in repo.dirstate.copies():
2571 for f in repo.dirstate.copies():
2573 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2572 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2574
2573
2575 @command('debugsub',
2574 @command('debugsub',
2576 [('r', 'rev', '',
2575 [('r', 'rev', '',
2577 _('revision to check'), _('REV'))],
2576 _('revision to check'), _('REV'))],
2578 _('[-r REV] [REV]'))
2577 _('[-r REV] [REV]'))
2579 def debugsub(ui, repo, rev=None):
2578 def debugsub(ui, repo, rev=None):
2580 ctx = scmutil.revsingle(repo, rev, None)
2579 ctx = scmutil.revsingle(repo, rev, None)
2581 for k, v in sorted(ctx.substate.items()):
2580 for k, v in sorted(ctx.substate.items()):
2582 ui.write(('path %s\n') % k)
2581 ui.write(('path %s\n') % k)
2583 ui.write((' source %s\n') % v[0])
2582 ui.write((' source %s\n') % v[0])
2584 ui.write((' revision %s\n') % v[1])
2583 ui.write((' revision %s\n') % v[1])
2585
2584
2586 @command('debugsuccessorssets',
2585 @command('debugsuccessorssets',
2587 [],
2586 [],
2588 _('[REV]'))
2587 _('[REV]'))
2589 def debugsuccessorssets(ui, repo, *revs):
2588 def debugsuccessorssets(ui, repo, *revs):
2590 """show set of successors for revision
2589 """show set of successors for revision
2591
2590
2592 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
2593 succeed A. It contains non-obsolete changesets only.
2592 succeed A. It contains non-obsolete changesets only.
2594
2593
2595 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
2596 successor (changeset A replaced by A').
2595 successor (changeset A replaced by A').
2597
2596
2598 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".
2599 Such changesets have no successors sets at all.
2598 Such changesets have no successors sets at all.
2600
2599
2601 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
2602 more than one successor.
2601 more than one successor.
2603
2602
2604 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
2605 "divergent". Such changesets have multiple successor sets (each of which
2604 "divergent". Such changesets have multiple successor sets (each of which
2606 may also be split, i.e. have multiple successors).
2605 may also be split, i.e. have multiple successors).
2607
2606
2608 Results are displayed as follows::
2607 Results are displayed as follows::
2609
2608
2610 <rev1>
2609 <rev1>
2611 <successors-1A>
2610 <successors-1A>
2612 <rev2>
2611 <rev2>
2613 <successors-2A>
2612 <successors-2A>
2614 <successors-2B1> <successors-2B2> <successors-2B3>
2613 <successors-2B1> <successors-2B2> <successors-2B3>
2615
2614
2616 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
2617 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
2618 been split).
2617 been split).
2619 """
2618 """
2620 # passed to successorssets caching computation from one call to another
2619 # passed to successorssets caching computation from one call to another
2621 cache = {}
2620 cache = {}
2622 ctx2str = str
2621 ctx2str = str
2623 node2str = short
2622 node2str = short
2624 if ui.debug():
2623 if ui.debug():
2625 def ctx2str(ctx):
2624 def ctx2str(ctx):
2626 return ctx.hex()
2625 return ctx.hex()
2627 node2str = hex
2626 node2str = hex
2628 for rev in scmutil.revrange(repo, revs):
2627 for rev in scmutil.revrange(repo, revs):
2629 ctx = repo[rev]
2628 ctx = repo[rev]
2630 ui.write('%s\n'% ctx2str(ctx))
2629 ui.write('%s\n'% ctx2str(ctx))
2631 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2630 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2632 if succsset:
2631 if succsset:
2633 ui.write(' ')
2632 ui.write(' ')
2634 ui.write(node2str(succsset[0]))
2633 ui.write(node2str(succsset[0]))
2635 for node in succsset[1:]:
2634 for node in succsset[1:]:
2636 ui.write(' ')
2635 ui.write(' ')
2637 ui.write(node2str(node))
2636 ui.write(node2str(node))
2638 ui.write('\n')
2637 ui.write('\n')
2639
2638
2640 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2639 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2641 def debugwalk(ui, repo, *pats, **opts):
2640 def debugwalk(ui, repo, *pats, **opts):
2642 """show how files match on given patterns"""
2641 """show how files match on given patterns"""
2643 m = scmutil.match(repo[None], pats, opts)
2642 m = scmutil.match(repo[None], pats, opts)
2644 items = list(repo.walk(m))
2643 items = list(repo.walk(m))
2645 if not items:
2644 if not items:
2646 return
2645 return
2647 f = lambda fn: fn
2646 f = lambda fn: fn
2648 if ui.configbool('ui', 'slash') and os.sep != '/':
2647 if ui.configbool('ui', 'slash') and os.sep != '/':
2649 f = lambda fn: util.normpath(fn)
2648 f = lambda fn: util.normpath(fn)
2650 fmt = 'f %%-%ds %%-%ds %%s' % (
2649 fmt = 'f %%-%ds %%-%ds %%s' % (
2651 max([len(abs) for abs in items]),
2650 max([len(abs) for abs in items]),
2652 max([len(m.rel(abs)) for abs in items]))
2651 max([len(m.rel(abs)) for abs in items]))
2653 for abs in items:
2652 for abs in items:
2654 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 '')
2655 ui.write("%s\n" % line.rstrip())
2654 ui.write("%s\n" % line.rstrip())
2656
2655
2657 @command('debugwireargs',
2656 @command('debugwireargs',
2658 [('', 'three', '', 'three'),
2657 [('', 'three', '', 'three'),
2659 ('', 'four', '', 'four'),
2658 ('', 'four', '', 'four'),
2660 ('', 'five', '', 'five'),
2659 ('', 'five', '', 'five'),
2661 ] + remoteopts,
2660 ] + remoteopts,
2662 _('REPO [OPTIONS]... [ONE [TWO]]'))
2661 _('REPO [OPTIONS]... [ONE [TWO]]'))
2663 def debugwireargs(ui, repopath, *vals, **opts):
2662 def debugwireargs(ui, repopath, *vals, **opts):
2664 repo = hg.peer(ui, opts, repopath)
2663 repo = hg.peer(ui, opts, repopath)
2665 for opt in remoteopts:
2664 for opt in remoteopts:
2666 del opts[opt[1]]
2665 del opts[opt[1]]
2667 args = {}
2666 args = {}
2668 for k, v in opts.iteritems():
2667 for k, v in opts.iteritems():
2669 if v:
2668 if v:
2670 args[k] = v
2669 args[k] = v
2671 # 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
2672 res1 = repo.debugwireargs(*vals, **args)
2671 res1 = repo.debugwireargs(*vals, **args)
2673 res2 = repo.debugwireargs(*vals, **args)
2672 res2 = repo.debugwireargs(*vals, **args)
2674 ui.write("%s\n" % res1)
2673 ui.write("%s\n" % res1)
2675 if res1 != res2:
2674 if res1 != res2:
2676 ui.warn("%s\n" % res2)
2675 ui.warn("%s\n" % res2)
2677
2676
2678 @command('^diff',
2677 @command('^diff',
2679 [('r', 'rev', [], _('revision'), _('REV')),
2678 [('r', 'rev', [], _('revision'), _('REV')),
2680 ('c', 'change', '', _('change made by revision'), _('REV'))
2679 ('c', 'change', '', _('change made by revision'), _('REV'))
2681 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2680 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2682 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2681 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2683 def diff(ui, repo, *pats, **opts):
2682 def diff(ui, repo, *pats, **opts):
2684 """diff repository (or selected files)
2683 """diff repository (or selected files)
2685
2684
2686 Show differences between revisions for the specified files.
2685 Show differences between revisions for the specified files.
2687
2686
2688 Differences between files are shown using the unified diff format.
2687 Differences between files are shown using the unified diff format.
2689
2688
2690 .. note::
2689 .. note::
2691 diff may generate unexpected results for merges, as it will
2690 diff may generate unexpected results for merges, as it will
2692 default to comparing against the working directory's first
2691 default to comparing against the working directory's first
2693 parent changeset if no revisions are specified.
2692 parent changeset if no revisions are specified.
2694
2693
2695 When two revision arguments are given, then changes are shown
2694 When two revision arguments are given, then changes are shown
2696 between those revisions. If only one revision is specified then
2695 between those revisions. If only one revision is specified then
2697 that revision is compared to the working directory, and, when no
2696 that revision is compared to the working directory, and, when no
2698 revisions are specified, the working directory files are compared
2697 revisions are specified, the working directory files are compared
2699 to its parent.
2698 to its parent.
2700
2699
2701 Alternatively you can specify -c/--change with a revision to see
2700 Alternatively you can specify -c/--change with a revision to see
2702 the changes in that changeset relative to its first parent.
2701 the changes in that changeset relative to its first parent.
2703
2702
2704 Without the -a/--text option, diff will avoid generating diffs of
2703 Without the -a/--text option, diff will avoid generating diffs of
2705 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
2706 anyway, probably with undesirable results.
2705 anyway, probably with undesirable results.
2707
2706
2708 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
2709 format. For more information, read :hg:`help diffs`.
2708 format. For more information, read :hg:`help diffs`.
2710
2709
2711 .. container:: verbose
2710 .. container:: verbose
2712
2711
2713 Examples:
2712 Examples:
2714
2713
2715 - compare a file in the current working directory to its parent::
2714 - compare a file in the current working directory to its parent::
2716
2715
2717 hg diff foo.c
2716 hg diff foo.c
2718
2717
2719 - compare two historical versions of a directory, with rename info::
2718 - compare two historical versions of a directory, with rename info::
2720
2719
2721 hg diff --git -r 1.0:1.2 lib/
2720 hg diff --git -r 1.0:1.2 lib/
2722
2721
2723 - get change stats relative to the last change on some date::
2722 - get change stats relative to the last change on some date::
2724
2723
2725 hg diff --stat -r "date('may 2')"
2724 hg diff --stat -r "date('may 2')"
2726
2725
2727 - diff all newly-added files that contain a keyword::
2726 - diff all newly-added files that contain a keyword::
2728
2727
2729 hg diff "set:added() and grep(GNU)"
2728 hg diff "set:added() and grep(GNU)"
2730
2729
2731 - compare a revision and its parents::
2730 - compare a revision and its parents::
2732
2731
2733 hg diff -c 9353 # compare against first parent
2732 hg diff -c 9353 # compare against first parent
2734 hg diff -r 9353^:9353 # same using revset syntax
2733 hg diff -r 9353^:9353 # same using revset syntax
2735 hg diff -r 9353^2:9353 # compare against the second parent
2734 hg diff -r 9353^2:9353 # compare against the second parent
2736
2735
2737 Returns 0 on success.
2736 Returns 0 on success.
2738 """
2737 """
2739
2738
2740 revs = opts.get('rev')
2739 revs = opts.get('rev')
2741 change = opts.get('change')
2740 change = opts.get('change')
2742 stat = opts.get('stat')
2741 stat = opts.get('stat')
2743 reverse = opts.get('reverse')
2742 reverse = opts.get('reverse')
2744
2743
2745 if revs and change:
2744 if revs and change:
2746 msg = _('cannot specify --rev and --change at the same time')
2745 msg = _('cannot specify --rev and --change at the same time')
2747 raise util.Abort(msg)
2746 raise util.Abort(msg)
2748 elif change:
2747 elif change:
2749 node2 = scmutil.revsingle(repo, change, None).node()
2748 node2 = scmutil.revsingle(repo, change, None).node()
2750 node1 = repo[node2].p1().node()
2749 node1 = repo[node2].p1().node()
2751 else:
2750 else:
2752 node1, node2 = scmutil.revpair(repo, revs)
2751 node1, node2 = scmutil.revpair(repo, revs)
2753
2752
2754 if reverse:
2753 if reverse:
2755 node1, node2 = node2, node1
2754 node1, node2 = node2, node1
2756
2755
2757 diffopts = patch.diffopts(ui, opts)
2756 diffopts = patch.diffopts(ui, opts)
2758 m = scmutil.match(repo[node2], pats, opts)
2757 m = scmutil.match(repo[node2], pats, opts)
2759 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2758 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2760 listsubrepos=opts.get('subrepos'))
2759 listsubrepos=opts.get('subrepos'))
2761
2760
2762 @command('^export',
2761 @command('^export',
2763 [('o', 'output', '',
2762 [('o', 'output', '',
2764 _('print output to file with formatted name'), _('FORMAT')),
2763 _('print output to file with formatted name'), _('FORMAT')),
2765 ('', 'switch-parent', None, _('diff against the second parent')),
2764 ('', 'switch-parent', None, _('diff against the second parent')),
2766 ('r', 'rev', [], _('revisions to export'), _('REV')),
2765 ('r', 'rev', [], _('revisions to export'), _('REV')),
2767 ] + diffopts,
2766 ] + diffopts,
2768 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2767 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
2769 def export(ui, repo, *changesets, **opts):
2768 def export(ui, repo, *changesets, **opts):
2770 """dump the header and diffs for one or more changesets
2769 """dump the header and diffs for one or more changesets
2771
2770
2772 Print the changeset header and diffs for one or more revisions.
2771 Print the changeset header and diffs for one or more revisions.
2773 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.
2774
2773
2775 The information shown in the changeset header is: author, date,
2774 The information shown in the changeset header is: author, date,
2776 branch name (if non-default), changeset hash, parent(s) and commit
2775 branch name (if non-default), changeset hash, parent(s) and commit
2777 comment.
2776 comment.
2778
2777
2779 .. note::
2778 .. note::
2780 export may generate unexpected diff output for merge
2779 export may generate unexpected diff output for merge
2781 changesets, as it will compare the merge changeset against its
2780 changesets, as it will compare the merge changeset against its
2782 first parent only.
2781 first parent only.
2783
2782
2784 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
2785 given using a format string. The formatting rules are as follows:
2784 given using a format string. The formatting rules are as follows:
2786
2785
2787 :``%%``: literal "%" character
2786 :``%%``: literal "%" character
2788 :``%H``: changeset hash (40 hexadecimal digits)
2787 :``%H``: changeset hash (40 hexadecimal digits)
2789 :``%N``: number of patches being generated
2788 :``%N``: number of patches being generated
2790 :``%R``: changeset revision number
2789 :``%R``: changeset revision number
2791 :``%b``: basename of the exporting repository
2790 :``%b``: basename of the exporting repository
2792 :``%h``: short-form changeset hash (12 hexadecimal digits)
2791 :``%h``: short-form changeset hash (12 hexadecimal digits)
2793 :``%m``: first line of the commit message (only alphanumeric characters)
2792 :``%m``: first line of the commit message (only alphanumeric characters)
2794 :``%n``: zero-padded sequence number, starting at 1
2793 :``%n``: zero-padded sequence number, starting at 1
2795 :``%r``: zero-padded changeset revision number
2794 :``%r``: zero-padded changeset revision number
2796
2795
2797 Without the -a/--text option, export will avoid generating diffs
2796 Without the -a/--text option, export will avoid generating diffs
2798 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
2799 diff anyway, probably with undesirable results.
2798 diff anyway, probably with undesirable results.
2800
2799
2801 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
2802 format. See :hg:`help diffs` for more information.
2801 format. See :hg:`help diffs` for more information.
2803
2802
2804 With the --switch-parent option, the diff will be against the
2803 With the --switch-parent option, the diff will be against the
2805 second parent. It can be useful to review a merge.
2804 second parent. It can be useful to review a merge.
2806
2805
2807 .. container:: verbose
2806 .. container:: verbose
2808
2807
2809 Examples:
2808 Examples:
2810
2809
2811 - use export and import to transplant a bugfix to the current
2810 - use export and import to transplant a bugfix to the current
2812 branch::
2811 branch::
2813
2812
2814 hg export -r 9353 | hg import -
2813 hg export -r 9353 | hg import -
2815
2814
2816 - export all the changesets between two revisions to a file with
2815 - export all the changesets between two revisions to a file with
2817 rename information::
2816 rename information::
2818
2817
2819 hg export --git -r 123:150 > changes.txt
2818 hg export --git -r 123:150 > changes.txt
2820
2819
2821 - split outgoing changes into a series of patches with
2820 - split outgoing changes into a series of patches with
2822 descriptive names::
2821 descriptive names::
2823
2822
2824 hg export -r "outgoing()" -o "%n-%m.patch"
2823 hg export -r "outgoing()" -o "%n-%m.patch"
2825
2824
2826 Returns 0 on success.
2825 Returns 0 on success.
2827 """
2826 """
2828 changesets += tuple(opts.get('rev', []))
2827 changesets += tuple(opts.get('rev', []))
2829 if not changesets:
2828 if not changesets:
2830 changesets = ['.']
2829 changesets = ['.']
2831 revs = scmutil.revrange(repo, changesets)
2830 revs = scmutil.revrange(repo, changesets)
2832 if not revs:
2831 if not revs:
2833 raise util.Abort(_("export requires at least one changeset"))
2832 raise util.Abort(_("export requires at least one changeset"))
2834 if len(revs) > 1:
2833 if len(revs) > 1:
2835 ui.note(_('exporting patches:\n'))
2834 ui.note(_('exporting patches:\n'))
2836 else:
2835 else:
2837 ui.note(_('exporting patch:\n'))
2836 ui.note(_('exporting patch:\n'))
2838 cmdutil.export(repo, revs, template=opts.get('output'),
2837 cmdutil.export(repo, revs, template=opts.get('output'),
2839 switch_parent=opts.get('switch_parent'),
2838 switch_parent=opts.get('switch_parent'),
2840 opts=patch.diffopts(ui, opts))
2839 opts=patch.diffopts(ui, opts))
2841
2840
2842 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2841 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2843 def forget(ui, repo, *pats, **opts):
2842 def forget(ui, repo, *pats, **opts):
2844 """forget the specified files on the next commit
2843 """forget the specified files on the next commit
2845
2844
2846 Mark the specified files so they will no longer be tracked
2845 Mark the specified files so they will no longer be tracked
2847 after the next commit.
2846 after the next commit.
2848
2847
2849 This only removes files from the current branch, not from the
2848 This only removes files from the current branch, not from the
2850 entire project history, and it does not delete them from the
2849 entire project history, and it does not delete them from the
2851 working directory.
2850 working directory.
2852
2851
2853 To undo a forget before the next commit, see :hg:`add`.
2852 To undo a forget before the next commit, see :hg:`add`.
2854
2853
2855 .. container:: verbose
2854 .. container:: verbose
2856
2855
2857 Examples:
2856 Examples:
2858
2857
2859 - forget newly-added binary files::
2858 - forget newly-added binary files::
2860
2859
2861 hg forget "set:added() and binary()"
2860 hg forget "set:added() and binary()"
2862
2861
2863 - forget files that would be excluded by .hgignore::
2862 - forget files that would be excluded by .hgignore::
2864
2863
2865 hg forget "set:hgignore()"
2864 hg forget "set:hgignore()"
2866
2865
2867 Returns 0 on success.
2866 Returns 0 on success.
2868 """
2867 """
2869
2868
2870 if not pats:
2869 if not pats:
2871 raise util.Abort(_('no files specified'))
2870 raise util.Abort(_('no files specified'))
2872
2871
2873 m = scmutil.match(repo[None], pats, opts)
2872 m = scmutil.match(repo[None], pats, opts)
2874 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2873 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2875 return rejected and 1 or 0
2874 return rejected and 1 or 0
2876
2875
2877 @command(
2876 @command(
2878 'graft',
2877 'graft',
2879 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2878 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2880 ('c', 'continue', False, _('resume interrupted graft')),
2879 ('c', 'continue', False, _('resume interrupted graft')),
2881 ('e', 'edit', False, _('invoke editor on commit messages')),
2880 ('e', 'edit', False, _('invoke editor on commit messages')),
2882 ('', 'log', None, _('append graft info to log message')),
2881 ('', 'log', None, _('append graft info to log message')),
2883 ('D', 'currentdate', False,
2882 ('D', 'currentdate', False,
2884 _('record the current date as commit date')),
2883 _('record the current date as commit date')),
2885 ('U', 'currentuser', False,
2884 ('U', 'currentuser', False,
2886 _('record the current user as committer'), _('DATE'))]
2885 _('record the current user as committer'), _('DATE'))]
2887 + commitopts2 + mergetoolopts + dryrunopts,
2886 + commitopts2 + mergetoolopts + dryrunopts,
2888 _('[OPTION]... [-r] REV...'))
2887 _('[OPTION]... [-r] REV...'))
2889 def graft(ui, repo, *revs, **opts):
2888 def graft(ui, repo, *revs, **opts):
2890 '''copy changes from other branches onto the current branch
2889 '''copy changes from other branches onto the current branch
2891
2890
2892 This command uses Mercurial's merge logic to copy individual
2891 This command uses Mercurial's merge logic to copy individual
2893 changes from other branches without merging branches in the
2892 changes from other branches without merging branches in the
2894 history graph. This is sometimes known as 'backporting' or
2893 history graph. This is sometimes known as 'backporting' or
2895 'cherry-picking'. By default, graft will copy user, date, and
2894 'cherry-picking'. By default, graft will copy user, date, and
2896 description from the source changesets.
2895 description from the source changesets.
2897
2896
2898 Changesets that are ancestors of the current revision, that have
2897 Changesets that are ancestors of the current revision, that have
2899 already been grafted, or that are merges will be skipped.
2898 already been grafted, or that are merges will be skipped.
2900
2899
2901 If --log is specified, log messages will have a comment appended
2900 If --log is specified, log messages will have a comment appended
2902 of the form::
2901 of the form::
2903
2902
2904 (grafted from CHANGESETHASH)
2903 (grafted from CHANGESETHASH)
2905
2904
2906 If a graft merge results in conflicts, the graft process is
2905 If a graft merge results in conflicts, the graft process is
2907 interrupted so that the current merge can be manually resolved.
2906 interrupted so that the current merge can be manually resolved.
2908 Once all conflicts are addressed, the graft process can be
2907 Once all conflicts are addressed, the graft process can be
2909 continued with the -c/--continue option.
2908 continued with the -c/--continue option.
2910
2909
2911 .. note::
2910 .. note::
2912 The -c/--continue option does not reapply earlier options.
2911 The -c/--continue option does not reapply earlier options.
2913
2912
2914 .. container:: verbose
2913 .. container:: verbose
2915
2914
2916 Examples:
2915 Examples:
2917
2916
2918 - 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::
2919
2918
2920 hg update stable
2919 hg update stable
2921 hg graft --edit 9393
2920 hg graft --edit 9393
2922
2921
2923 - graft a range of changesets with one exception, updating dates::
2922 - graft a range of changesets with one exception, updating dates::
2924
2923
2925 hg graft -D "2085::2093 and not 2091"
2924 hg graft -D "2085::2093 and not 2091"
2926
2925
2927 - continue a graft after resolving conflicts::
2926 - continue a graft after resolving conflicts::
2928
2927
2929 hg graft -c
2928 hg graft -c
2930
2929
2931 - show the source of a grafted changeset::
2930 - show the source of a grafted changeset::
2932
2931
2933 hg log --debug -r tip
2932 hg log --debug -r tip
2934
2933
2935 Returns 0 on successful completion.
2934 Returns 0 on successful completion.
2936 '''
2935 '''
2937
2936
2938 revs = list(revs)
2937 revs = list(revs)
2939 revs.extend(opts['rev'])
2938 revs.extend(opts['rev'])
2940
2939
2941 if not opts.get('user') and opts.get('currentuser'):
2940 if not opts.get('user') and opts.get('currentuser'):
2942 opts['user'] = ui.username()
2941 opts['user'] = ui.username()
2943 if not opts.get('date') and opts.get('currentdate'):
2942 if not opts.get('date') and opts.get('currentdate'):
2944 opts['date'] = "%d %d" % util.makedate()
2943 opts['date'] = "%d %d" % util.makedate()
2945
2944
2946 editor = None
2945 editor = None
2947 if opts.get('edit'):
2946 if opts.get('edit'):
2948 editor = cmdutil.commitforceeditor
2947 editor = cmdutil.commitforceeditor
2949
2948
2950 cont = False
2949 cont = False
2951 if opts['continue']:
2950 if opts['continue']:
2952 cont = True
2951 cont = True
2953 if revs:
2952 if revs:
2954 raise util.Abort(_("can't specify --continue and revisions"))
2953 raise util.Abort(_("can't specify --continue and revisions"))
2955 # read in unfinished revisions
2954 # read in unfinished revisions
2956 try:
2955 try:
2957 nodes = repo.opener.read('graftstate').splitlines()
2956 nodes = repo.opener.read('graftstate').splitlines()
2958 revs = [repo[node].rev() for node in nodes]
2957 revs = [repo[node].rev() for node in nodes]
2959 except IOError, inst:
2958 except IOError, inst:
2960 if inst.errno != errno.ENOENT:
2959 if inst.errno != errno.ENOENT:
2961 raise
2960 raise
2962 raise util.Abort(_("no graft state found, can't continue"))
2961 raise util.Abort(_("no graft state found, can't continue"))
2963 else:
2962 else:
2964 cmdutil.bailifchanged(repo)
2963 cmdutil.bailifchanged(repo)
2965 if not revs:
2964 if not revs:
2966 raise util.Abort(_('no revisions specified'))
2965 raise util.Abort(_('no revisions specified'))
2967 revs = scmutil.revrange(repo, revs)
2966 revs = scmutil.revrange(repo, revs)
2968
2967
2969 # check for merges
2968 # check for merges
2970 for rev in repo.revs('%ld and merge()', revs):
2969 for rev in repo.revs('%ld and merge()', revs):
2971 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2970 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2972 revs.remove(rev)
2971 revs.remove(rev)
2973 if not revs:
2972 if not revs:
2974 return -1
2973 return -1
2975
2974
2976 # check for ancestors of dest branch
2975 # check for ancestors of dest branch
2977 crev = repo['.'].rev()
2976 crev = repo['.'].rev()
2978 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2977 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2979 # don't mutate while iterating, create a copy
2978 # don't mutate while iterating, create a copy
2980 for rev in list(revs):
2979 for rev in list(revs):
2981 if rev in ancestors:
2980 if rev in ancestors:
2982 ui.warn(_('skipping ancestor revision %s\n') % rev)
2981 ui.warn(_('skipping ancestor revision %s\n') % rev)
2983 revs.remove(rev)
2982 revs.remove(rev)
2984 if not revs:
2983 if not revs:
2985 return -1
2984 return -1
2986
2985
2987 # analyze revs for earlier grafts
2986 # analyze revs for earlier grafts
2988 ids = {}
2987 ids = {}
2989 for ctx in repo.set("%ld", revs):
2988 for ctx in repo.set("%ld", revs):
2990 ids[ctx.hex()] = ctx.rev()
2989 ids[ctx.hex()] = ctx.rev()
2991 n = ctx.extra().get('source')
2990 n = ctx.extra().get('source')
2992 if n:
2991 if n:
2993 ids[n] = ctx.rev()
2992 ids[n] = ctx.rev()
2994
2993
2995 # check ancestors for earlier grafts
2994 # check ancestors for earlier grafts
2996 ui.debug('scanning for duplicate grafts\n')
2995 ui.debug('scanning for duplicate grafts\n')
2997
2996
2998 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2997 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2999 ctx = repo[rev]
2998 ctx = repo[rev]
3000 n = ctx.extra().get('source')
2999 n = ctx.extra().get('source')
3001 if n in ids:
3000 if n in ids:
3002 r = repo[n].rev()
3001 r = repo[n].rev()
3003 if r in revs:
3002 if r in revs:
3004 ui.warn(_('skipping already grafted revision %s\n') % r)
3003 ui.warn(_('skipping already grafted revision %s\n') % r)
3005 revs.remove(r)
3004 revs.remove(r)
3006 elif ids[n] in revs:
3005 elif ids[n] in revs:
3007 ui.warn(_('skipping already grafted revision %s '
3006 ui.warn(_('skipping already grafted revision %s '
3008 '(same origin %d)\n') % (ids[n], r))
3007 '(same origin %d)\n') % (ids[n], r))
3009 revs.remove(ids[n])
3008 revs.remove(ids[n])
3010 elif ctx.hex() in ids:
3009 elif ctx.hex() in ids:
3011 r = ids[ctx.hex()]
3010 r = ids[ctx.hex()]
3012 ui.warn(_('skipping already grafted revision %s '
3011 ui.warn(_('skipping already grafted revision %s '
3013 '(was grafted from %d)\n') % (r, rev))
3012 '(was grafted from %d)\n') % (r, rev))
3014 revs.remove(r)
3013 revs.remove(r)
3015 if not revs:
3014 if not revs:
3016 return -1
3015 return -1
3017
3016
3018 wlock = repo.wlock()
3017 wlock = repo.wlock()
3019 try:
3018 try:
3020 current = repo['.']
3019 current = repo['.']
3021 for pos, ctx in enumerate(repo.set("%ld", revs)):
3020 for pos, ctx in enumerate(repo.set("%ld", revs)):
3022
3021
3023 ui.status(_('grafting revision %s\n') % ctx.rev())
3022 ui.status(_('grafting revision %s\n') % ctx.rev())
3024 if opts.get('dry_run'):
3023 if opts.get('dry_run'):
3025 continue
3024 continue
3026
3025
3027 source = ctx.extra().get('source')
3026 source = ctx.extra().get('source')
3028 if not source:
3027 if not source:
3029 source = ctx.hex()
3028 source = ctx.hex()
3030 extra = {'source': source}
3029 extra = {'source': source}
3031 user = ctx.user()
3030 user = ctx.user()
3032 if opts.get('user'):
3031 if opts.get('user'):
3033 user = opts['user']
3032 user = opts['user']
3034 date = ctx.date()
3033 date = ctx.date()
3035 if opts.get('date'):
3034 if opts.get('date'):
3036 date = opts['date']
3035 date = opts['date']
3037 message = ctx.description()
3036 message = ctx.description()
3038 if opts.get('log'):
3037 if opts.get('log'):
3039 message += '\n(grafted from %s)' % ctx.hex()
3038 message += '\n(grafted from %s)' % ctx.hex()
3040
3039
3041 # we don't merge the first commit when continuing
3040 # we don't merge the first commit when continuing
3042 if not cont:
3041 if not cont:
3043 # perform the graft merge with p1(rev) as 'ancestor'
3042 # perform the graft merge with p1(rev) as 'ancestor'
3044 try:
3043 try:
3045 # ui.forcemerge is an internal variable, do not document
3044 # ui.forcemerge is an internal variable, do not document
3046 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3045 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3047 stats = mergemod.update(repo, ctx.node(), True, True, False,
3046 stats = mergemod.update(repo, ctx.node(), True, True, False,
3048 ctx.p1().node())
3047 ctx.p1().node())
3049 finally:
3048 finally:
3050 repo.ui.setconfig('ui', 'forcemerge', '')
3049 repo.ui.setconfig('ui', 'forcemerge', '')
3051 # report any conflicts
3050 # report any conflicts
3052 if stats and stats[3] > 0:
3051 if stats and stats[3] > 0:
3053 # write out state for --continue
3052 # write out state for --continue
3054 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3053 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3055 repo.opener.write('graftstate', ''.join(nodelines))
3054 repo.opener.write('graftstate', ''.join(nodelines))
3056 raise util.Abort(
3055 raise util.Abort(
3057 _("unresolved conflicts, can't continue"),
3056 _("unresolved conflicts, can't continue"),
3058 hint=_('use hg resolve and hg graft --continue'))
3057 hint=_('use hg resolve and hg graft --continue'))
3059 else:
3058 else:
3060 cont = False
3059 cont = False
3061
3060
3062 # drop the second merge parent
3061 # drop the second merge parent
3063 repo.setparents(current.node(), nullid)
3062 repo.setparents(current.node(), nullid)
3064 repo.dirstate.write()
3063 repo.dirstate.write()
3065 # fix up dirstate for copies and renames
3064 # fix up dirstate for copies and renames
3066 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3065 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3067
3066
3068 # commit
3067 # commit
3069 node = repo.commit(text=message, user=user,
3068 node = repo.commit(text=message, user=user,
3070 date=date, extra=extra, editor=editor)
3069 date=date, extra=extra, editor=editor)
3071 if node is None:
3070 if node is None:
3072 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3071 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3073 else:
3072 else:
3074 current = repo[node]
3073 current = repo[node]
3075 finally:
3074 finally:
3076 wlock.release()
3075 wlock.release()
3077
3076
3078 # remove state when we complete successfully
3077 # remove state when we complete successfully
3079 if not opts.get('dry_run'):
3078 if not opts.get('dry_run'):
3080 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3079 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3081
3080
3082 return 0
3081 return 0
3083
3082
3084 @command('grep',
3083 @command('grep',
3085 [('0', 'print0', None, _('end fields with NUL')),
3084 [('0', 'print0', None, _('end fields with NUL')),
3086 ('', 'all', None, _('print all revisions that match')),
3085 ('', 'all', None, _('print all revisions that match')),
3087 ('a', 'text', None, _('treat all files as text')),
3086 ('a', 'text', None, _('treat all files as text')),
3088 ('f', 'follow', None,
3087 ('f', 'follow', None,
3089 _('follow changeset history,'
3088 _('follow changeset history,'
3090 ' or file history across copies and renames')),
3089 ' or file history across copies and renames')),
3091 ('i', 'ignore-case', None, _('ignore case when matching')),
3090 ('i', 'ignore-case', None, _('ignore case when matching')),
3092 ('l', 'files-with-matches', None,
3091 ('l', 'files-with-matches', None,
3093 _('print only filenames and revisions that match')),
3092 _('print only filenames and revisions that match')),
3094 ('n', 'line-number', None, _('print matching line numbers')),
3093 ('n', 'line-number', None, _('print matching line numbers')),
3095 ('r', 'rev', [],
3094 ('r', 'rev', [],
3096 _('only search files changed within revision range'), _('REV')),
3095 _('only search files changed within revision range'), _('REV')),
3097 ('u', 'user', None, _('list the author (long with -v)')),
3096 ('u', 'user', None, _('list the author (long with -v)')),
3098 ('d', 'date', None, _('list the date (short with -q)')),
3097 ('d', 'date', None, _('list the date (short with -q)')),
3099 ] + walkopts,
3098 ] + walkopts,
3100 _('[OPTION]... PATTERN [FILE]...'))
3099 _('[OPTION]... PATTERN [FILE]...'))
3101 def grep(ui, repo, pattern, *pats, **opts):
3100 def grep(ui, repo, pattern, *pats, **opts):
3102 """search for a pattern in specified files and revisions
3101 """search for a pattern in specified files and revisions
3103
3102
3104 Search revisions of files for a regular expression.
3103 Search revisions of files for a regular expression.
3105
3104
3106 This command behaves differently than Unix grep. It only accepts
3105 This command behaves differently than Unix grep. It only accepts
3107 Python/Perl regexps. It searches repository history, not the
3106 Python/Perl regexps. It searches repository history, not the
3108 working directory. It always prints the revision number in which a
3107 working directory. It always prints the revision number in which a
3109 match appears.
3108 match appears.
3110
3109
3111 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
3112 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
3113 that contains a change in match status ("-" for a match that
3112 that contains a change in match status ("-" for a match that
3114 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),
3115 use the --all flag.
3114 use the --all flag.
3116
3115
3117 Returns 0 if a match is found, 1 otherwise.
3116 Returns 0 if a match is found, 1 otherwise.
3118 """
3117 """
3119 reflags = re.M
3118 reflags = re.M
3120 if opts.get('ignore_case'):
3119 if opts.get('ignore_case'):
3121 reflags |= re.I
3120 reflags |= re.I
3122 try:
3121 try:
3123 regexp = util.compilere(pattern, reflags)
3122 regexp = util.compilere(pattern, reflags)
3124 except re.error, inst:
3123 except re.error, inst:
3125 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3124 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3126 return 1
3125 return 1
3127 sep, eol = ':', '\n'
3126 sep, eol = ':', '\n'
3128 if opts.get('print0'):
3127 if opts.get('print0'):
3129 sep = eol = '\0'
3128 sep = eol = '\0'
3130
3129
3131 getfile = util.lrucachefunc(repo.file)
3130 getfile = util.lrucachefunc(repo.file)
3132
3131
3133 def matchlines(body):
3132 def matchlines(body):
3134 begin = 0
3133 begin = 0
3135 linenum = 0
3134 linenum = 0
3136 while begin < len(body):
3135 while begin < len(body):
3137 match = regexp.search(body, begin)
3136 match = regexp.search(body, begin)
3138 if not match:
3137 if not match:
3139 break
3138 break
3140 mstart, mend = match.span()
3139 mstart, mend = match.span()
3141 linenum += body.count('\n', begin, mstart) + 1
3140 linenum += body.count('\n', begin, mstart) + 1
3142 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3141 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3143 begin = body.find('\n', mend) + 1 or len(body) + 1
3142 begin = body.find('\n', mend) + 1 or len(body) + 1
3144 lend = begin - 1
3143 lend = begin - 1
3145 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3144 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3146
3145
3147 class linestate(object):
3146 class linestate(object):
3148 def __init__(self, line, linenum, colstart, colend):
3147 def __init__(self, line, linenum, colstart, colend):
3149 self.line = line
3148 self.line = line
3150 self.linenum = linenum
3149 self.linenum = linenum
3151 self.colstart = colstart
3150 self.colstart = colstart
3152 self.colend = colend
3151 self.colend = colend
3153
3152
3154 def __hash__(self):
3153 def __hash__(self):
3155 return hash((self.linenum, self.line))
3154 return hash((self.linenum, self.line))
3156
3155
3157 def __eq__(self, other):
3156 def __eq__(self, other):
3158 return self.line == other.line
3157 return self.line == other.line
3159
3158
3160 matches = {}
3159 matches = {}
3161 copies = {}
3160 copies = {}
3162 def grepbody(fn, rev, body):
3161 def grepbody(fn, rev, body):
3163 matches[rev].setdefault(fn, [])
3162 matches[rev].setdefault(fn, [])
3164 m = matches[rev][fn]
3163 m = matches[rev][fn]
3165 for lnum, cstart, cend, line in matchlines(body):
3164 for lnum, cstart, cend, line in matchlines(body):
3166 s = linestate(line, lnum, cstart, cend)
3165 s = linestate(line, lnum, cstart, cend)
3167 m.append(s)
3166 m.append(s)
3168
3167
3169 def difflinestates(a, b):
3168 def difflinestates(a, b):
3170 sm = difflib.SequenceMatcher(None, a, b)
3169 sm = difflib.SequenceMatcher(None, a, b)
3171 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3170 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3172 if tag == 'insert':
3171 if tag == 'insert':
3173 for i in xrange(blo, bhi):
3172 for i in xrange(blo, bhi):
3174 yield ('+', b[i])
3173 yield ('+', b[i])
3175 elif tag == 'delete':
3174 elif tag == 'delete':
3176 for i in xrange(alo, ahi):
3175 for i in xrange(alo, ahi):
3177 yield ('-', a[i])
3176 yield ('-', a[i])
3178 elif tag == 'replace':
3177 elif tag == 'replace':
3179 for i in xrange(alo, ahi):
3178 for i in xrange(alo, ahi):
3180 yield ('-', a[i])
3179 yield ('-', a[i])
3181 for i in xrange(blo, bhi):
3180 for i in xrange(blo, bhi):
3182 yield ('+', b[i])
3181 yield ('+', b[i])
3183
3182
3184 def display(fn, ctx, pstates, states):
3183 def display(fn, ctx, pstates, states):
3185 rev = ctx.rev()
3184 rev = ctx.rev()
3186 datefunc = ui.quiet and util.shortdate or util.datestr
3185 datefunc = ui.quiet and util.shortdate or util.datestr
3187 found = False
3186 found = False
3188 filerevmatches = {}
3187 filerevmatches = {}
3189 def binary():
3188 def binary():
3190 flog = getfile(fn)
3189 flog = getfile(fn)
3191 return util.binary(flog.read(ctx.filenode(fn)))
3190 return util.binary(flog.read(ctx.filenode(fn)))
3192
3191
3193 if opts.get('all'):
3192 if opts.get('all'):
3194 iter = difflinestates(pstates, states)
3193 iter = difflinestates(pstates, states)
3195 else:
3194 else:
3196 iter = [('', l) for l in states]
3195 iter = [('', l) for l in states]
3197 for change, l in iter:
3196 for change, l in iter:
3198 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3197 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3199 before, match, after = None, None, None
3198 before, match, after = None, None, None
3200
3199
3201 if opts.get('line_number'):
3200 if opts.get('line_number'):
3202 cols.append((str(l.linenum), 'grep.linenumber'))
3201 cols.append((str(l.linenum), 'grep.linenumber'))
3203 if opts.get('all'):
3202 if opts.get('all'):
3204 cols.append((change, 'grep.change'))
3203 cols.append((change, 'grep.change'))
3205 if opts.get('user'):
3204 if opts.get('user'):
3206 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3205 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3207 if opts.get('date'):
3206 if opts.get('date'):
3208 cols.append((datefunc(ctx.date()), 'grep.date'))
3207 cols.append((datefunc(ctx.date()), 'grep.date'))
3209 if opts.get('files_with_matches'):
3208 if opts.get('files_with_matches'):
3210 c = (fn, rev)
3209 c = (fn, rev)
3211 if c in filerevmatches:
3210 if c in filerevmatches:
3212 continue
3211 continue
3213 filerevmatches[c] = 1
3212 filerevmatches[c] = 1
3214 else:
3213 else:
3215 before = l.line[:l.colstart]
3214 before = l.line[:l.colstart]
3216 match = l.line[l.colstart:l.colend]
3215 match = l.line[l.colstart:l.colend]
3217 after = l.line[l.colend:]
3216 after = l.line[l.colend:]
3218 for col, label in cols[:-1]:
3217 for col, label in cols[:-1]:
3219 ui.write(col, label=label)
3218 ui.write(col, label=label)
3220 ui.write(sep, label='grep.sep')
3219 ui.write(sep, label='grep.sep')
3221 ui.write(cols[-1][0], label=cols[-1][1])
3220 ui.write(cols[-1][0], label=cols[-1][1])
3222 if before is not None:
3221 if before is not None:
3223 ui.write(sep, label='grep.sep')
3222 ui.write(sep, label='grep.sep')
3224 if not opts.get('text') and binary():
3223 if not opts.get('text') and binary():
3225 ui.write(" Binary file matches")
3224 ui.write(" Binary file matches")
3226 else:
3225 else:
3227 ui.write(before)
3226 ui.write(before)
3228 ui.write(match, label='grep.match')
3227 ui.write(match, label='grep.match')
3229 ui.write(after)
3228 ui.write(after)
3230 ui.write(eol)
3229 ui.write(eol)
3231 found = True
3230 found = True
3232 return found
3231 return found
3233
3232
3234 skip = {}
3233 skip = {}
3235 revfiles = {}
3234 revfiles = {}
3236 matchfn = scmutil.match(repo[None], pats, opts)
3235 matchfn = scmutil.match(repo[None], pats, opts)
3237 found = False
3236 found = False
3238 follow = opts.get('follow')
3237 follow = opts.get('follow')
3239
3238
3240 def prep(ctx, fns):
3239 def prep(ctx, fns):
3241 rev = ctx.rev()
3240 rev = ctx.rev()
3242 pctx = ctx.p1()
3241 pctx = ctx.p1()
3243 parent = pctx.rev()
3242 parent = pctx.rev()
3244 matches.setdefault(rev, {})
3243 matches.setdefault(rev, {})
3245 matches.setdefault(parent, {})
3244 matches.setdefault(parent, {})
3246 files = revfiles.setdefault(rev, [])
3245 files = revfiles.setdefault(rev, [])
3247 for fn in fns:
3246 for fn in fns:
3248 flog = getfile(fn)
3247 flog = getfile(fn)
3249 try:
3248 try:
3250 fnode = ctx.filenode(fn)
3249 fnode = ctx.filenode(fn)
3251 except error.LookupError:
3250 except error.LookupError:
3252 continue
3251 continue
3253
3252
3254 copied = flog.renamed(fnode)
3253 copied = flog.renamed(fnode)
3255 copy = follow and copied and copied[0]
3254 copy = follow and copied and copied[0]
3256 if copy:
3255 if copy:
3257 copies.setdefault(rev, {})[fn] = copy
3256 copies.setdefault(rev, {})[fn] = copy
3258 if fn in skip:
3257 if fn in skip:
3259 if copy:
3258 if copy:
3260 skip[copy] = True
3259 skip[copy] = True
3261 continue
3260 continue
3262 files.append(fn)
3261 files.append(fn)
3263
3262
3264 if fn not in matches[rev]:
3263 if fn not in matches[rev]:
3265 grepbody(fn, rev, flog.read(fnode))
3264 grepbody(fn, rev, flog.read(fnode))
3266
3265
3267 pfn = copy or fn
3266 pfn = copy or fn
3268 if pfn not in matches[parent]:
3267 if pfn not in matches[parent]:
3269 try:
3268 try:
3270 fnode = pctx.filenode(pfn)
3269 fnode = pctx.filenode(pfn)
3271 grepbody(pfn, parent, flog.read(fnode))
3270 grepbody(pfn, parent, flog.read(fnode))
3272 except error.LookupError:
3271 except error.LookupError:
3273 pass
3272 pass
3274
3273
3275 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3274 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3276 rev = ctx.rev()
3275 rev = ctx.rev()
3277 parent = ctx.p1().rev()
3276 parent = ctx.p1().rev()
3278 for fn in sorted(revfiles.get(rev, [])):
3277 for fn in sorted(revfiles.get(rev, [])):
3279 states = matches[rev][fn]
3278 states = matches[rev][fn]
3280 copy = copies.get(rev, {}).get(fn)
3279 copy = copies.get(rev, {}).get(fn)
3281 if fn in skip:
3280 if fn in skip:
3282 if copy:
3281 if copy:
3283 skip[copy] = True
3282 skip[copy] = True
3284 continue
3283 continue
3285 pstates = matches.get(parent, {}).get(copy or fn, [])
3284 pstates = matches.get(parent, {}).get(copy or fn, [])
3286 if pstates or states:
3285 if pstates or states:
3287 r = display(fn, ctx, pstates, states)
3286 r = display(fn, ctx, pstates, states)
3288 found = found or r
3287 found = found or r
3289 if r and not opts.get('all'):
3288 if r and not opts.get('all'):
3290 skip[fn] = True
3289 skip[fn] = True
3291 if copy:
3290 if copy:
3292 skip[copy] = True
3291 skip[copy] = True
3293 del matches[rev]
3292 del matches[rev]
3294 del revfiles[rev]
3293 del revfiles[rev]
3295
3294
3296 return not found
3295 return not found
3297
3296
3298 @command('heads',
3297 @command('heads',
3299 [('r', 'rev', '',
3298 [('r', 'rev', '',
3300 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3299 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3301 ('t', 'topo', False, _('show topological heads only')),
3300 ('t', 'topo', False, _('show topological heads only')),
3302 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3301 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3303 ('c', 'closed', False, _('show normal and closed branch heads')),
3302 ('c', 'closed', False, _('show normal and closed branch heads')),
3304 ] + templateopts,
3303 ] + templateopts,
3305 _('[-ct] [-r STARTREV] [REV]...'))
3304 _('[-ct] [-r STARTREV] [REV]...'))
3306 def heads(ui, repo, *branchrevs, **opts):
3305 def heads(ui, repo, *branchrevs, **opts):
3307 """show current repository heads or show branch heads
3306 """show current repository heads or show branch heads
3308
3307
3309 With no arguments, show all repository branch heads.
3308 With no arguments, show all repository branch heads.
3310
3309
3311 Repository "heads" are changesets with no child changesets. They are
3310 Repository "heads" are changesets with no child changesets. They are
3312 where development generally takes place and are the usual targets
3311 where development generally takes place and are the usual targets
3313 for update and merge operations. Branch heads are changesets that have
3312 for update and merge operations. Branch heads are changesets that have
3314 no child changeset on the same branch.
3313 no child changeset on the same branch.
3315
3314
3316 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
3317 associated with the specified changesets are shown. This means
3316 associated with the specified changesets are shown. This means
3318 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
3319 named ``foo``.
3318 named ``foo``.
3320
3319
3321 If -c/--closed is specified, also show branch heads marked closed
3320 If -c/--closed is specified, also show branch heads marked closed
3322 (see :hg:`commit --close-branch`).
3321 (see :hg:`commit --close-branch`).
3323
3322
3324 If STARTREV is specified, only those heads that are descendants of
3323 If STARTREV is specified, only those heads that are descendants of
3325 STARTREV will be displayed.
3324 STARTREV will be displayed.
3326
3325
3327 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
3328 changesets without children will be shown.
3327 changesets without children will be shown.
3329
3328
3330 Returns 0 if matching heads are found, 1 if not.
3329 Returns 0 if matching heads are found, 1 if not.
3331 """
3330 """
3332
3331
3333 start = None
3332 start = None
3334 if 'rev' in opts:
3333 if 'rev' in opts:
3335 start = scmutil.revsingle(repo, opts['rev'], None).node()
3334 start = scmutil.revsingle(repo, opts['rev'], None).node()
3336
3335
3337 if opts.get('topo'):
3336 if opts.get('topo'):
3338 heads = [repo[h] for h in repo.heads(start)]
3337 heads = [repo[h] for h in repo.heads(start)]
3339 else:
3338 else:
3340 heads = []
3339 heads = []
3341 for branch in repo.branchmap():
3340 for branch in repo.branchmap():
3342 heads += repo.branchheads(branch, start, opts.get('closed'))
3341 heads += repo.branchheads(branch, start, opts.get('closed'))
3343 heads = [repo[h] for h in heads]
3342 heads = [repo[h] for h in heads]
3344
3343
3345 if branchrevs:
3344 if branchrevs:
3346 branches = set(repo[br].branch() for br in branchrevs)
3345 branches = set(repo[br].branch() for br in branchrevs)
3347 heads = [h for h in heads if h.branch() in branches]
3346 heads = [h for h in heads if h.branch() in branches]
3348
3347
3349 if opts.get('active') and branchrevs:
3348 if opts.get('active') and branchrevs:
3350 dagheads = repo.heads(start)
3349 dagheads = repo.heads(start)
3351 heads = [h for h in heads if h.node() in dagheads]
3350 heads = [h for h in heads if h.node() in dagheads]
3352
3351
3353 if branchrevs:
3352 if branchrevs:
3354 haveheads = set(h.branch() for h in heads)
3353 haveheads = set(h.branch() for h in heads)
3355 if branches - haveheads:
3354 if branches - haveheads:
3356 headless = ', '.join(b for b in branches - haveheads)
3355 headless = ', '.join(b for b in branches - haveheads)
3357 msg = _('no open branch heads found on branches %s')
3356 msg = _('no open branch heads found on branches %s')
3358 if opts.get('rev'):
3357 if opts.get('rev'):
3359 msg += _(' (started at %s)') % opts['rev']
3358 msg += _(' (started at %s)') % opts['rev']
3360 ui.warn((msg + '\n') % headless)
3359 ui.warn((msg + '\n') % headless)
3361
3360
3362 if not heads:
3361 if not heads:
3363 return 1
3362 return 1
3364
3363
3365 heads = sorted(heads, key=lambda x: -x.rev())
3364 heads = sorted(heads, key=lambda x: -x.rev())
3366 displayer = cmdutil.show_changeset(ui, repo, opts)
3365 displayer = cmdutil.show_changeset(ui, repo, opts)
3367 for ctx in heads:
3366 for ctx in heads:
3368 displayer.show(ctx)
3367 displayer.show(ctx)
3369 displayer.close()
3368 displayer.close()
3370
3369
3371 @command('help',
3370 @command('help',
3372 [('e', 'extension', None, _('show only help for extensions')),
3371 [('e', 'extension', None, _('show only help for extensions')),
3373 ('c', 'command', None, _('show only help for commands')),
3372 ('c', 'command', None, _('show only help for commands')),
3374 ('k', 'keyword', '', _('show topics matching keyword')),
3373 ('k', 'keyword', '', _('show topics matching keyword')),
3375 ],
3374 ],
3376 _('[-ec] [TOPIC]'))
3375 _('[-ec] [TOPIC]'))
3377 def help_(ui, name=None, **opts):
3376 def help_(ui, name=None, **opts):
3378 """show help for a given topic or a help overview
3377 """show help for a given topic or a help overview
3379
3378
3380 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.
3381
3380
3382 Given a topic, extension, or command name, print help for that
3381 Given a topic, extension, or command name, print help for that
3383 topic.
3382 topic.
3384
3383
3385 Returns 0 if successful.
3384 Returns 0 if successful.
3386 """
3385 """
3387
3386
3388 textwidth = min(ui.termwidth(), 80) - 2
3387 textwidth = min(ui.termwidth(), 80) - 2
3389
3388
3390 keep = ui.verbose and ['verbose'] or []
3389 keep = ui.verbose and ['verbose'] or []
3391 text = help.help_(ui, name, **opts)
3390 text = help.help_(ui, name, **opts)
3392
3391
3393 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3392 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3394 if 'verbose' in pruned:
3393 if 'verbose' in pruned:
3395 keep.append('omitted')
3394 keep.append('omitted')
3396 else:
3395 else:
3397 keep.append('notomitted')
3396 keep.append('notomitted')
3398 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3397 formatted, pruned = minirst.format(text, textwidth, keep=keep)
3399 ui.write(formatted)
3398 ui.write(formatted)
3400
3399
3401
3400
3402 @command('identify|id',
3401 @command('identify|id',
3403 [('r', 'rev', '',
3402 [('r', 'rev', '',
3404 _('identify the specified revision'), _('REV')),
3403 _('identify the specified revision'), _('REV')),
3405 ('n', 'num', None, _('show local revision number')),
3404 ('n', 'num', None, _('show local revision number')),
3406 ('i', 'id', None, _('show global revision id')),
3405 ('i', 'id', None, _('show global revision id')),
3407 ('b', 'branch', None, _('show branch')),
3406 ('b', 'branch', None, _('show branch')),
3408 ('t', 'tags', None, _('show tags')),
3407 ('t', 'tags', None, _('show tags')),
3409 ('B', 'bookmarks', None, _('show bookmarks')),
3408 ('B', 'bookmarks', None, _('show bookmarks')),
3410 ] + remoteopts,
3409 ] + remoteopts,
3411 _('[-nibtB] [-r REV] [SOURCE]'))
3410 _('[-nibtB] [-r REV] [SOURCE]'))
3412 def identify(ui, repo, source=None, rev=None,
3411 def identify(ui, repo, source=None, rev=None,
3413 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3412 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3414 """identify the working copy or specified revision
3413 """identify the working copy or specified revision
3415
3414
3416 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
3417 two parent hash identifiers, followed by a "+" if the working
3416 two parent hash identifiers, followed by a "+" if the working
3418 directory has uncommitted changes, the branch name (if not default),
3417 directory has uncommitted changes, the branch name (if not default),
3419 a list of tags, and a list of bookmarks.
3418 a list of tags, and a list of bookmarks.
3420
3419
3421 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
3422 repository.
3421 repository.
3423
3422
3424 Specifying a path to a repository root or Mercurial bundle will
3423 Specifying a path to a repository root or Mercurial bundle will
3425 cause lookup to operate on that repository/bundle.
3424 cause lookup to operate on that repository/bundle.
3426
3425
3427 .. container:: verbose
3426 .. container:: verbose
3428
3427
3429 Examples:
3428 Examples:
3430
3429
3431 - generate a build identifier for the working directory::
3430 - generate a build identifier for the working directory::
3432
3431
3433 hg id --id > build-id.dat
3432 hg id --id > build-id.dat
3434
3433
3435 - find the revision corresponding to a tag::
3434 - find the revision corresponding to a tag::
3436
3435
3437 hg id -n -r 1.3
3436 hg id -n -r 1.3
3438
3437
3439 - check the most recent revision of a remote repository::
3438 - check the most recent revision of a remote repository::
3440
3439
3441 hg id -r tip http://selenic.com/hg/
3440 hg id -r tip http://selenic.com/hg/
3442
3441
3443 Returns 0 if successful.
3442 Returns 0 if successful.
3444 """
3443 """
3445
3444
3446 if not repo and not source:
3445 if not repo and not source:
3447 raise util.Abort(_("there is no Mercurial repository here "
3446 raise util.Abort(_("there is no Mercurial repository here "
3448 "(.hg not found)"))
3447 "(.hg not found)"))
3449
3448
3450 hexfunc = ui.debugflag and hex or short
3449 hexfunc = ui.debugflag and hex or short
3451 default = not (num or id or branch or tags or bookmarks)
3450 default = not (num or id or branch or tags or bookmarks)
3452 output = []
3451 output = []
3453 revs = []
3452 revs = []
3454
3453
3455 if source:
3454 if source:
3456 source, branches = hg.parseurl(ui.expandpath(source))
3455 source, branches = hg.parseurl(ui.expandpath(source))
3457 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
3458 repo = peer.local()
3457 repo = peer.local()
3459 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3458 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3460
3459
3461 if not repo:
3460 if not repo:
3462 if num or branch or tags:
3461 if num or branch or tags:
3463 raise util.Abort(
3462 raise util.Abort(
3464 _("can't query remote revision number, branch, or tags"))
3463 _("can't query remote revision number, branch, or tags"))
3465 if not rev and revs:
3464 if not rev and revs:
3466 rev = revs[0]
3465 rev = revs[0]
3467 if not rev:
3466 if not rev:
3468 rev = "tip"
3467 rev = "tip"
3469
3468
3470 remoterev = peer.lookup(rev)
3469 remoterev = peer.lookup(rev)
3471 if default or id:
3470 if default or id:
3472 output = [hexfunc(remoterev)]
3471 output = [hexfunc(remoterev)]
3473
3472
3474 def getbms():
3473 def getbms():
3475 bms = []
3474 bms = []
3476
3475
3477 if 'bookmarks' in peer.listkeys('namespaces'):
3476 if 'bookmarks' in peer.listkeys('namespaces'):
3478 hexremoterev = hex(remoterev)
3477 hexremoterev = hex(remoterev)
3479 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3478 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3480 if bmr == hexremoterev]
3479 if bmr == hexremoterev]
3481
3480
3482 return sorted(bms)
3481 return sorted(bms)
3483
3482
3484 if bookmarks:
3483 if bookmarks:
3485 output.extend(getbms())
3484 output.extend(getbms())
3486 elif default and not ui.quiet:
3485 elif default and not ui.quiet:
3487 # multiple bookmarks for a single parent separated by '/'
3486 # multiple bookmarks for a single parent separated by '/'
3488 bm = '/'.join(getbms())
3487 bm = '/'.join(getbms())
3489 if bm:
3488 if bm:
3490 output.append(bm)
3489 output.append(bm)
3491 else:
3490 else:
3492 if not rev:
3491 if not rev:
3493 ctx = repo[None]
3492 ctx = repo[None]
3494 parents = ctx.parents()
3493 parents = ctx.parents()
3495 changed = ""
3494 changed = ""
3496 if default or id or num:
3495 if default or id or num:
3497 if (util.any(repo.status())
3496 if (util.any(repo.status())
3498 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)):
3499 changed = '+'
3498 changed = '+'
3500 if default or id:
3499 if default or id:
3501 output = ["%s%s" %
3500 output = ["%s%s" %
3502 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3501 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3503 if num:
3502 if num:
3504 output.append("%s%s" %
3503 output.append("%s%s" %
3505 ('+'.join([str(p.rev()) for p in parents]), changed))
3504 ('+'.join([str(p.rev()) for p in parents]), changed))
3506 else:
3505 else:
3507 ctx = scmutil.revsingle(repo, rev)
3506 ctx = scmutil.revsingle(repo, rev)
3508 if default or id:
3507 if default or id:
3509 output = [hexfunc(ctx.node())]
3508 output = [hexfunc(ctx.node())]
3510 if num:
3509 if num:
3511 output.append(str(ctx.rev()))
3510 output.append(str(ctx.rev()))
3512
3511
3513 if default and not ui.quiet:
3512 if default and not ui.quiet:
3514 b = ctx.branch()
3513 b = ctx.branch()
3515 if b != 'default':
3514 if b != 'default':
3516 output.append("(%s)" % b)
3515 output.append("(%s)" % b)
3517
3516
3518 # multiple tags for a single parent separated by '/'
3517 # multiple tags for a single parent separated by '/'
3519 t = '/'.join(ctx.tags())
3518 t = '/'.join(ctx.tags())
3520 if t:
3519 if t:
3521 output.append(t)
3520 output.append(t)
3522
3521
3523 # multiple bookmarks for a single parent separated by '/'
3522 # multiple bookmarks for a single parent separated by '/'
3524 bm = '/'.join(ctx.bookmarks())
3523 bm = '/'.join(ctx.bookmarks())
3525 if bm:
3524 if bm:
3526 output.append(bm)
3525 output.append(bm)
3527 else:
3526 else:
3528 if branch:
3527 if branch:
3529 output.append(ctx.branch())
3528 output.append(ctx.branch())
3530
3529
3531 if tags:
3530 if tags:
3532 output.extend(ctx.tags())
3531 output.extend(ctx.tags())
3533
3532
3534 if bookmarks:
3533 if bookmarks:
3535 output.extend(ctx.bookmarks())
3534 output.extend(ctx.bookmarks())
3536
3535
3537 ui.write("%s\n" % ' '.join(output))
3536 ui.write("%s\n" % ' '.join(output))
3538
3537
3539 @command('import|patch',
3538 @command('import|patch',
3540 [('p', 'strip', 1,
3539 [('p', 'strip', 1,
3541 _('directory strip option for patch. This has the same '
3540 _('directory strip option for patch. This has the same '
3542 'meaning as the corresponding patch option'), _('NUM')),
3541 'meaning as the corresponding patch option'), _('NUM')),
3543 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3542 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3544 ('e', 'edit', False, _('invoke editor on commit messages')),
3543 ('e', 'edit', False, _('invoke editor on commit messages')),
3545 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3544 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3546 ('', 'no-commit', None,
3545 ('', 'no-commit', None,
3547 _("don't commit, just update the working directory")),
3546 _("don't commit, just update the working directory")),
3548 ('', 'bypass', None,
3547 ('', 'bypass', None,
3549 _("apply patch without touching the working directory")),
3548 _("apply patch without touching the working directory")),
3550 ('', 'exact', None,
3549 ('', 'exact', None,
3551 _('apply patch to the nodes from which it was generated')),
3550 _('apply patch to the nodes from which it was generated')),
3552 ('', 'import-branch', None,
3551 ('', 'import-branch', None,
3553 _('use any branch information in patch (implied by --exact)'))] +
3552 _('use any branch information in patch (implied by --exact)'))] +
3554 commitopts + commitopts2 + similarityopts,
3553 commitopts + commitopts2 + similarityopts,
3555 _('[OPTION]... PATCH...'))
3554 _('[OPTION]... PATCH...'))
3556 def import_(ui, repo, patch1=None, *patches, **opts):
3555 def import_(ui, repo, patch1=None, *patches, **opts):
3557 """import an ordered set of patches
3556 """import an ordered set of patches
3558
3557
3559 Import a list of patches and commit them individually (unless
3558 Import a list of patches and commit them individually (unless
3560 --no-commit is specified).
3559 --no-commit is specified).
3561
3560
3562 If there are outstanding changes in the working directory, import
3561 If there are outstanding changes in the working directory, import
3563 will abort unless given the -f/--force flag.
3562 will abort unless given the -f/--force flag.
3564
3563
3565 You can import a patch straight from a mail message. Even patches
3564 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
3565 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
3566 text/plain or text/x-patch). From and Subject headers of email
3568 message are used as default committer and commit message. All
3567 message are used as default committer and commit message. All
3569 text/plain body parts before first diff are added to commit
3568 text/plain body parts before first diff are added to commit
3570 message.
3569 message.
3571
3570
3572 If the imported patch was generated by :hg:`export`, user and
3571 If the imported patch was generated by :hg:`export`, user and
3573 description from patch override values from message headers and
3572 description from patch override values from message headers and
3574 body. Values given on command line with -m/--message and -u/--user
3573 body. Values given on command line with -m/--message and -u/--user
3575 override these.
3574 override these.
3576
3575
3577 If --exact is specified, import will set the working directory to
3576 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
3577 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
3578 resulting changeset has a different ID than the one recorded in
3580 the patch. This may happen due to character set problems or other
3579 the patch. This may happen due to character set problems or other
3581 deficiencies in the text patch format.
3580 deficiencies in the text patch format.
3582
3581
3583 Use --bypass to apply and commit patches directly to the
3582 Use --bypass to apply and commit patches directly to the
3584 repository, not touching the working directory. Without --exact,
3583 repository, not touching the working directory. Without --exact,
3585 patches will be applied on top of the working directory parent
3584 patches will be applied on top of the working directory parent
3586 revision.
3585 revision.
3587
3586
3588 With -s/--similarity, hg will attempt to discover renames and
3587 With -s/--similarity, hg will attempt to discover renames and
3589 copies in the patch in the same way as :hg:`addremove`.
3588 copies in the patch in the same way as :hg:`addremove`.
3590
3589
3591 To read a patch from standard input, use "-" as the patch name. If
3590 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.
3591 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.
3592 See :hg:`help dates` for a list of formats valid for -d/--date.
3594
3593
3595 .. container:: verbose
3594 .. container:: verbose
3596
3595
3597 Examples:
3596 Examples:
3598
3597
3599 - import a traditional patch from a website and detect renames::
3598 - import a traditional patch from a website and detect renames::
3600
3599
3601 hg import -s 80 http://example.com/bugfix.patch
3600 hg import -s 80 http://example.com/bugfix.patch
3602
3601
3603 - import a changeset from an hgweb server::
3602 - import a changeset from an hgweb server::
3604
3603
3605 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3604 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3606
3605
3607 - import all the patches in an Unix-style mbox::
3606 - import all the patches in an Unix-style mbox::
3608
3607
3609 hg import incoming-patches.mbox
3608 hg import incoming-patches.mbox
3610
3609
3611 - attempt to exactly restore an exported changeset (not always
3610 - attempt to exactly restore an exported changeset (not always
3612 possible)::
3611 possible)::
3613
3612
3614 hg import --exact proposed-fix.patch
3613 hg import --exact proposed-fix.patch
3615
3614
3616 Returns 0 on success.
3615 Returns 0 on success.
3617 """
3616 """
3618
3617
3619 if not patch1:
3618 if not patch1:
3620 raise util.Abort(_('need at least one patch to import'))
3619 raise util.Abort(_('need at least one patch to import'))
3621
3620
3622 patches = (patch1,) + patches
3621 patches = (patch1,) + patches
3623
3622
3624 date = opts.get('date')
3623 date = opts.get('date')
3625 if date:
3624 if date:
3626 opts['date'] = util.parsedate(date)
3625 opts['date'] = util.parsedate(date)
3627
3626
3628 editor = cmdutil.commiteditor
3627 editor = cmdutil.commiteditor
3629 if opts.get('edit'):
3628 if opts.get('edit'):
3630 editor = cmdutil.commitforceeditor
3629 editor = cmdutil.commitforceeditor
3631
3630
3632 update = not opts.get('bypass')
3631 update = not opts.get('bypass')
3633 if not update and opts.get('no_commit'):
3632 if not update and opts.get('no_commit'):
3634 raise util.Abort(_('cannot use --no-commit with --bypass'))
3633 raise util.Abort(_('cannot use --no-commit with --bypass'))
3635 try:
3634 try:
3636 sim = float(opts.get('similarity') or 0)
3635 sim = float(opts.get('similarity') or 0)
3637 except ValueError:
3636 except ValueError:
3638 raise util.Abort(_('similarity must be a number'))
3637 raise util.Abort(_('similarity must be a number'))
3639 if sim < 0 or sim > 100:
3638 if sim < 0 or sim > 100:
3640 raise util.Abort(_('similarity must be between 0 and 100'))
3639 raise util.Abort(_('similarity must be between 0 and 100'))
3641 if sim and not update:
3640 if sim and not update:
3642 raise util.Abort(_('cannot use --similarity with --bypass'))
3641 raise util.Abort(_('cannot use --similarity with --bypass'))
3643
3642
3644 if (opts.get('exact') or not opts.get('force')) and update:
3643 if (opts.get('exact') or not opts.get('force')) and update:
3645 cmdutil.bailifchanged(repo)
3644 cmdutil.bailifchanged(repo)
3646
3645
3647 base = opts["base"]
3646 base = opts["base"]
3648 strip = opts["strip"]
3647 strip = opts["strip"]
3649 wlock = lock = tr = None
3648 wlock = lock = tr = None
3650 msgs = []
3649 msgs = []
3651
3650
3652 def tryone(ui, hunk, parents):
3651 def tryone(ui, hunk, parents):
3653 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3652 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3654 patch.extract(ui, hunk)
3653 patch.extract(ui, hunk)
3655
3654
3656 if not tmpname:
3655 if not tmpname:
3657 return (None, None)
3656 return (None, None)
3658 msg = _('applied to working directory')
3657 msg = _('applied to working directory')
3659
3658
3660 try:
3659 try:
3661 cmdline_message = cmdutil.logmessage(ui, opts)
3660 cmdline_message = cmdutil.logmessage(ui, opts)
3662 if cmdline_message:
3661 if cmdline_message:
3663 # pickup the cmdline msg
3662 # pickup the cmdline msg
3664 message = cmdline_message
3663 message = cmdline_message
3665 elif message:
3664 elif message:
3666 # pickup the patch msg
3665 # pickup the patch msg
3667 message = message.strip()
3666 message = message.strip()
3668 else:
3667 else:
3669 # launch the editor
3668 # launch the editor
3670 message = None
3669 message = None
3671 ui.debug('message:\n%s\n' % message)
3670 ui.debug('message:\n%s\n' % message)
3672
3671
3673 if len(parents) == 1:
3672 if len(parents) == 1:
3674 parents.append(repo[nullid])
3673 parents.append(repo[nullid])
3675 if opts.get('exact'):
3674 if opts.get('exact'):
3676 if not nodeid or not p1:
3675 if not nodeid or not p1:
3677 raise util.Abort(_('not a Mercurial patch'))
3676 raise util.Abort(_('not a Mercurial patch'))
3678 p1 = repo[p1]
3677 p1 = repo[p1]
3679 p2 = repo[p2 or nullid]
3678 p2 = repo[p2 or nullid]
3680 elif p2:
3679 elif p2:
3681 try:
3680 try:
3682 p1 = repo[p1]
3681 p1 = repo[p1]
3683 p2 = repo[p2]
3682 p2 = repo[p2]
3684 # Without any options, consider p2 only if the
3683 # Without any options, consider p2 only if the
3685 # patch is being applied on top of the recorded
3684 # patch is being applied on top of the recorded
3686 # first parent.
3685 # first parent.
3687 if p1 != parents[0]:
3686 if p1 != parents[0]:
3688 p1 = parents[0]
3687 p1 = parents[0]
3689 p2 = repo[nullid]
3688 p2 = repo[nullid]
3690 except error.RepoError:
3689 except error.RepoError:
3691 p1, p2 = parents
3690 p1, p2 = parents
3692 else:
3691 else:
3693 p1, p2 = parents
3692 p1, p2 = parents
3694
3693
3695 n = None
3694 n = None
3696 if update:
3695 if update:
3697 if p1 != parents[0]:
3696 if p1 != parents[0]:
3698 hg.clean(repo, p1.node())
3697 hg.clean(repo, p1.node())
3699 if p2 != parents[1]:
3698 if p2 != parents[1]:
3700 repo.setparents(p1.node(), p2.node())
3699 repo.setparents(p1.node(), p2.node())
3701
3700
3702 if opts.get('exact') or opts.get('import_branch'):
3701 if opts.get('exact') or opts.get('import_branch'):
3703 repo.dirstate.setbranch(branch or 'default')
3702 repo.dirstate.setbranch(branch or 'default')
3704
3703
3705 files = set()
3704 files = set()
3706 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3705 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3707 eolmode=None, similarity=sim / 100.0)
3706 eolmode=None, similarity=sim / 100.0)
3708 files = list(files)
3707 files = list(files)
3709 if opts.get('no_commit'):
3708 if opts.get('no_commit'):
3710 if message:
3709 if message:
3711 msgs.append(message)
3710 msgs.append(message)
3712 else:
3711 else:
3713 if opts.get('exact') or p2:
3712 if opts.get('exact') or p2:
3714 # If you got here, you either use --force and know what
3713 # If you got here, you either use --force and know what
3715 # you are doing or used --exact or a merge patch while
3714 # you are doing or used --exact or a merge patch while
3716 # being updated to its first parent.
3715 # being updated to its first parent.
3717 m = None
3716 m = None
3718 else:
3717 else:
3719 m = scmutil.matchfiles(repo, files or [])
3718 m = scmutil.matchfiles(repo, files or [])
3720 n = repo.commit(message, opts.get('user') or user,
3719 n = repo.commit(message, opts.get('user') or user,
3721 opts.get('date') or date, match=m,
3720 opts.get('date') or date, match=m,
3722 editor=editor)
3721 editor=editor)
3723 else:
3722 else:
3724 if opts.get('exact') or opts.get('import_branch'):
3723 if opts.get('exact') or opts.get('import_branch'):
3725 branch = branch or 'default'
3724 branch = branch or 'default'
3726 else:
3725 else:
3727 branch = p1.branch()
3726 branch = p1.branch()
3728 store = patch.filestore()
3727 store = patch.filestore()
3729 try:
3728 try:
3730 files = set()
3729 files = set()
3731 try:
3730 try:
3732 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3731 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3733 files, eolmode=None)
3732 files, eolmode=None)
3734 except patch.PatchError, e:
3733 except patch.PatchError, e:
3735 raise util.Abort(str(e))
3734 raise util.Abort(str(e))
3736 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3735 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3737 message,
3736 message,
3738 opts.get('user') or user,
3737 opts.get('user') or user,
3739 opts.get('date') or date,
3738 opts.get('date') or date,
3740 branch, files, store,
3739 branch, files, store,
3741 editor=cmdutil.commiteditor)
3740 editor=cmdutil.commiteditor)
3742 repo.savecommitmessage(memctx.description())
3741 repo.savecommitmessage(memctx.description())
3743 n = memctx.commit()
3742 n = memctx.commit()
3744 finally:
3743 finally:
3745 store.close()
3744 store.close()
3746 if opts.get('exact') and hex(n) != nodeid:
3745 if opts.get('exact') and hex(n) != nodeid:
3747 raise util.Abort(_('patch is damaged or loses information'))
3746 raise util.Abort(_('patch is damaged or loses information'))
3748 if n:
3747 if n:
3749 # i18n: refers to a short changeset id
3748 # i18n: refers to a short changeset id
3750 msg = _('created %s') % short(n)
3749 msg = _('created %s') % short(n)
3751 return (msg, n)
3750 return (msg, n)
3752 finally:
3751 finally:
3753 os.unlink(tmpname)
3752 os.unlink(tmpname)
3754
3753
3755 try:
3754 try:
3756 try:
3755 try:
3757 wlock = repo.wlock()
3756 wlock = repo.wlock()
3758 if not opts.get('no_commit'):
3757 if not opts.get('no_commit'):
3759 lock = repo.lock()
3758 lock = repo.lock()
3760 tr = repo.transaction('import')
3759 tr = repo.transaction('import')
3761 parents = repo.parents()
3760 parents = repo.parents()
3762 for patchurl in patches:
3761 for patchurl in patches:
3763 if patchurl == '-':
3762 if patchurl == '-':
3764 ui.status(_('applying patch from stdin\n'))
3763 ui.status(_('applying patch from stdin\n'))
3765 patchfile = ui.fin
3764 patchfile = ui.fin
3766 patchurl = 'stdin' # for error message
3765 patchurl = 'stdin' # for error message
3767 else:
3766 else:
3768 patchurl = os.path.join(base, patchurl)
3767 patchurl = os.path.join(base, patchurl)
3769 ui.status(_('applying %s\n') % patchurl)
3768 ui.status(_('applying %s\n') % patchurl)
3770 patchfile = hg.openpath(ui, patchurl)
3769 patchfile = hg.openpath(ui, patchurl)
3771
3770
3772 haspatch = False
3771 haspatch = False
3773 for hunk in patch.split(patchfile):
3772 for hunk in patch.split(patchfile):
3774 (msg, node) = tryone(ui, hunk, parents)
3773 (msg, node) = tryone(ui, hunk, parents)
3775 if msg:
3774 if msg:
3776 haspatch = True
3775 haspatch = True
3777 ui.note(msg + '\n')
3776 ui.note(msg + '\n')
3778 if update or opts.get('exact'):
3777 if update or opts.get('exact'):
3779 parents = repo.parents()
3778 parents = repo.parents()
3780 else:
3779 else:
3781 parents = [repo[node]]
3780 parents = [repo[node]]
3782
3781
3783 if not haspatch:
3782 if not haspatch:
3784 raise util.Abort(_('%s: no diffs found') % patchurl)
3783 raise util.Abort(_('%s: no diffs found') % patchurl)
3785
3784
3786 if tr:
3785 if tr:
3787 tr.close()
3786 tr.close()
3788 if msgs:
3787 if msgs:
3789 repo.savecommitmessage('\n* * *\n'.join(msgs))
3788 repo.savecommitmessage('\n* * *\n'.join(msgs))
3790 except: # re-raises
3789 except: # re-raises
3791 # wlock.release() indirectly calls dirstate.write(): since
3790 # wlock.release() indirectly calls dirstate.write(): since
3792 # we're crashing, we do not want to change the working dir
3791 # we're crashing, we do not want to change the working dir
3793 # parent after all, so make sure it writes nothing
3792 # parent after all, so make sure it writes nothing
3794 repo.dirstate.invalidate()
3793 repo.dirstate.invalidate()
3795 raise
3794 raise
3796 finally:
3795 finally:
3797 if tr:
3796 if tr:
3798 tr.release()
3797 tr.release()
3799 release(lock, wlock)
3798 release(lock, wlock)
3800
3799
3801 @command('incoming|in',
3800 @command('incoming|in',
3802 [('f', 'force', None,
3801 [('f', 'force', None,
3803 _('run even if remote repository is unrelated')),
3802 _('run even if remote repository is unrelated')),
3804 ('n', 'newest-first', None, _('show newest record first')),
3803 ('n', 'newest-first', None, _('show newest record first')),
3805 ('', 'bundle', '',
3804 ('', 'bundle', '',
3806 _('file to store the bundles into'), _('FILE')),
3805 _('file to store the bundles into'), _('FILE')),
3807 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3806 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3808 ('B', 'bookmarks', False, _("compare bookmarks")),
3807 ('B', 'bookmarks', False, _("compare bookmarks")),
3809 ('b', 'branch', [],
3808 ('b', 'branch', [],
3810 _('a specific branch you would like to pull'), _('BRANCH')),
3809 _('a specific branch you would like to pull'), _('BRANCH')),
3811 ] + logopts + remoteopts + subrepoopts,
3810 ] + logopts + remoteopts + subrepoopts,
3812 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3811 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3813 def incoming(ui, repo, source="default", **opts):
3812 def incoming(ui, repo, source="default", **opts):
3814 """show new changesets found in source
3813 """show new changesets found in source
3815
3814
3816 Show new changesets found in the specified path/URL or the default
3815 Show new changesets found in the specified path/URL or the default
3817 pull location. These are the changesets that would have been pulled
3816 pull location. These are the changesets that would have been pulled
3818 if a pull at the time you issued this command.
3817 if a pull at the time you issued this command.
3819
3818
3820 For remote repository, using --bundle avoids downloading the
3819 For remote repository, using --bundle avoids downloading the
3821 changesets twice if the incoming is followed by a pull.
3820 changesets twice if the incoming is followed by a pull.
3822
3821
3823 See pull for valid source format details.
3822 See pull for valid source format details.
3824
3823
3825 Returns 0 if there are incoming changes, 1 otherwise.
3824 Returns 0 if there are incoming changes, 1 otherwise.
3826 """
3825 """
3827 if opts.get('graph'):
3826 if opts.get('graph'):
3828 cmdutil.checkunsupportedgraphflags([], opts)
3827 cmdutil.checkunsupportedgraphflags([], opts)
3829 def display(other, chlist, displayer):
3828 def display(other, chlist, displayer):
3830 revdag = cmdutil.graphrevs(other, chlist, opts)
3829 revdag = cmdutil.graphrevs(other, chlist, opts)
3831 showparents = [ctx.node() for ctx in repo[None].parents()]
3830 showparents = [ctx.node() for ctx in repo[None].parents()]
3832 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3831 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3833 graphmod.asciiedges)
3832 graphmod.asciiedges)
3834
3833
3835 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3834 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3836 return 0
3835 return 0
3837
3836
3838 if opts.get('bundle') and opts.get('subrepos'):
3837 if opts.get('bundle') and opts.get('subrepos'):
3839 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3838 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3840
3839
3841 if opts.get('bookmarks'):
3840 if opts.get('bookmarks'):
3842 source, branches = hg.parseurl(ui.expandpath(source),
3841 source, branches = hg.parseurl(ui.expandpath(source),
3843 opts.get('branch'))
3842 opts.get('branch'))
3844 other = hg.peer(repo, opts, source)
3843 other = hg.peer(repo, opts, source)
3845 if 'bookmarks' not in other.listkeys('namespaces'):
3844 if 'bookmarks' not in other.listkeys('namespaces'):
3846 ui.warn(_("remote doesn't support bookmarks\n"))
3845 ui.warn(_("remote doesn't support bookmarks\n"))
3847 return 0
3846 return 0
3848 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3847 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3849 return bookmarks.diff(ui, repo, other)
3848 return bookmarks.diff(ui, repo, other)
3850
3849
3851 repo._subtoppath = ui.expandpath(source)
3850 repo._subtoppath = ui.expandpath(source)
3852 try:
3851 try:
3853 return hg.incoming(ui, repo, source, opts)
3852 return hg.incoming(ui, repo, source, opts)
3854 finally:
3853 finally:
3855 del repo._subtoppath
3854 del repo._subtoppath
3856
3855
3857
3856
3858 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3857 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3859 def init(ui, dest=".", **opts):
3858 def init(ui, dest=".", **opts):
3860 """create a new repository in the given directory
3859 """create a new repository in the given directory
3861
3860
3862 Initialize a new repository in the given directory. If the given
3861 Initialize a new repository in the given directory. If the given
3863 directory does not exist, it will be created.
3862 directory does not exist, it will be created.
3864
3863
3865 If no directory is given, the current directory is used.
3864 If no directory is given, the current directory is used.
3866
3865
3867 It is possible to specify an ``ssh://`` URL as the destination.
3866 It is possible to specify an ``ssh://`` URL as the destination.
3868 See :hg:`help urls` for more information.
3867 See :hg:`help urls` for more information.
3869
3868
3870 Returns 0 on success.
3869 Returns 0 on success.
3871 """
3870 """
3872 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3871 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3873
3872
3874 @command('locate',
3873 @command('locate',
3875 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3874 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3876 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3875 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3877 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3876 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3878 ] + walkopts,
3877 ] + walkopts,
3879 _('[OPTION]... [PATTERN]...'))
3878 _('[OPTION]... [PATTERN]...'))
3880 def locate(ui, repo, *pats, **opts):
3879 def locate(ui, repo, *pats, **opts):
3881 """locate files matching specific patterns
3880 """locate files matching specific patterns
3882
3881
3883 Print files under Mercurial control in the working directory whose
3882 Print files under Mercurial control in the working directory whose
3884 names match the given patterns.
3883 names match the given patterns.
3885
3884
3886 By default, this command searches all directories in the working
3885 By default, this command searches all directories in the working
3887 directory. To search just the current directory and its
3886 directory. To search just the current directory and its
3888 subdirectories, use "--include .".
3887 subdirectories, use "--include .".
3889
3888
3890 If no patterns are given to match, this command prints the names
3889 If no patterns are given to match, this command prints the names
3891 of all files under Mercurial control in the working directory.
3890 of all files under Mercurial control in the working directory.
3892
3891
3893 If you want to feed the output of this command into the "xargs"
3892 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
3893 command, use the -0 option to both this command and "xargs". This
3895 will avoid the problem of "xargs" treating single filenames that
3894 will avoid the problem of "xargs" treating single filenames that
3896 contain whitespace as multiple filenames.
3895 contain whitespace as multiple filenames.
3897
3896
3898 Returns 0 if a match is found, 1 otherwise.
3897 Returns 0 if a match is found, 1 otherwise.
3899 """
3898 """
3900 end = opts.get('print0') and '\0' or '\n'
3899 end = opts.get('print0') and '\0' or '\n'
3901 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3900 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3902
3901
3903 ret = 1
3902 ret = 1
3904 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3903 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3905 m.bad = lambda x, y: False
3904 m.bad = lambda x, y: False
3906 for abs in repo[rev].walk(m):
3905 for abs in repo[rev].walk(m):
3907 if not rev and abs not in repo.dirstate:
3906 if not rev and abs not in repo.dirstate:
3908 continue
3907 continue
3909 if opts.get('fullpath'):
3908 if opts.get('fullpath'):
3910 ui.write(repo.wjoin(abs), end)
3909 ui.write(repo.wjoin(abs), end)
3911 else:
3910 else:
3912 ui.write(((pats and m.rel(abs)) or abs), end)
3911 ui.write(((pats and m.rel(abs)) or abs), end)
3913 ret = 0
3912 ret = 0
3914
3913
3915 return ret
3914 return ret
3916
3915
3917 @command('^log|history',
3916 @command('^log|history',
3918 [('f', 'follow', None,
3917 [('f', 'follow', None,
3919 _('follow changeset history, or file history across copies and renames')),
3918 _('follow changeset history, or file history across copies and renames')),
3920 ('', 'follow-first', None,
3919 ('', 'follow-first', None,
3921 _('only follow the first parent of merge changesets (DEPRECATED)')),
3920 _('only follow the first parent of merge changesets (DEPRECATED)')),
3922 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3921 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3923 ('C', 'copies', None, _('show copied files')),
3922 ('C', 'copies', None, _('show copied files')),
3924 ('k', 'keyword', [],
3923 ('k', 'keyword', [],
3925 _('do case-insensitive search for a given text'), _('TEXT')),
3924 _('do case-insensitive search for a given text'), _('TEXT')),
3926 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3925 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3927 ('', 'removed', None, _('include revisions where files were removed')),
3926 ('', 'removed', None, _('include revisions where files were removed')),
3928 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3927 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3929 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3928 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3930 ('', 'only-branch', [],
3929 ('', 'only-branch', [],
3931 _('show only changesets within the given named branch (DEPRECATED)'),
3930 _('show only changesets within the given named branch (DEPRECATED)'),
3932 _('BRANCH')),
3931 _('BRANCH')),
3933 ('b', 'branch', [],
3932 ('b', 'branch', [],
3934 _('show changesets within the given named branch'), _('BRANCH')),
3933 _('show changesets within the given named branch'), _('BRANCH')),
3935 ('P', 'prune', [],
3934 ('P', 'prune', [],
3936 _('do not display revision or any of its ancestors'), _('REV')),
3935 _('do not display revision or any of its ancestors'), _('REV')),
3937 ] + logopts + walkopts,
3936 ] + logopts + walkopts,
3938 _('[OPTION]... [FILE]'))
3937 _('[OPTION]... [FILE]'))
3939 def log(ui, repo, *pats, **opts):
3938 def log(ui, repo, *pats, **opts):
3940 """show revision history of entire repository or files
3939 """show revision history of entire repository or files
3941
3940
3942 Print the revision history of the specified files or the entire
3941 Print the revision history of the specified files or the entire
3943 project.
3942 project.
3944
3943
3945 If no revision range is specified, the default is ``tip:0`` unless
3944 If no revision range is specified, the default is ``tip:0`` unless
3946 --follow is set, in which case the working directory parent is
3945 --follow is set, in which case the working directory parent is
3947 used as the starting revision.
3946 used as the starting revision.
3948
3947
3949 File history is shown without following rename or copy history of
3948 File history is shown without following rename or copy history of
3950 files. Use -f/--follow with a filename to follow history across
3949 files. Use -f/--follow with a filename to follow history across
3951 renames and copies. --follow without a filename will only show
3950 renames and copies. --follow without a filename will only show
3952 ancestors or descendants of the starting revision.
3951 ancestors or descendants of the starting revision.
3953
3952
3954 By default this command prints revision number and changeset id,
3953 By default this command prints revision number and changeset id,
3955 tags, non-trivial parents, user, date and time, and a summary for
3954 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
3955 each commit. When the -v/--verbose switch is used, the list of
3957 changed files and full commit message are shown.
3956 changed files and full commit message are shown.
3958
3957
3959 .. note::
3958 .. note::
3960 log -p/--patch may generate unexpected diff output for merge
3959 log -p/--patch may generate unexpected diff output for merge
3961 changesets, as it will only compare the merge changeset against
3960 changesets, as it will only compare the merge changeset against
3962 its first parent. Also, only files different from BOTH parents
3961 its first parent. Also, only files different from BOTH parents
3963 will appear in files:.
3962 will appear in files:.
3964
3963
3965 .. note::
3964 .. note::
3966 for performance reasons, log FILE may omit duplicate changes
3965 for performance reasons, log FILE may omit duplicate changes
3967 made on branches and will not show deletions. To see all
3966 made on branches and will not show deletions. To see all
3968 changes including duplicates and deletions, use the --removed
3967 changes including duplicates and deletions, use the --removed
3969 switch.
3968 switch.
3970
3969
3971 .. container:: verbose
3970 .. container:: verbose
3972
3971
3973 Some examples:
3972 Some examples:
3974
3973
3975 - changesets with full descriptions and file lists::
3974 - changesets with full descriptions and file lists::
3976
3975
3977 hg log -v
3976 hg log -v
3978
3977
3979 - changesets ancestral to the working directory::
3978 - changesets ancestral to the working directory::
3980
3979
3981 hg log -f
3980 hg log -f
3982
3981
3983 - last 10 commits on the current branch::
3982 - last 10 commits on the current branch::
3984
3983
3985 hg log -l 10 -b .
3984 hg log -l 10 -b .
3986
3985
3987 - changesets showing all modifications of a file, including removals::
3986 - changesets showing all modifications of a file, including removals::
3988
3987
3989 hg log --removed file.c
3988 hg log --removed file.c
3990
3989
3991 - all changesets that touch a directory, with diffs, excluding merges::
3990 - all changesets that touch a directory, with diffs, excluding merges::
3992
3991
3993 hg log -Mp lib/
3992 hg log -Mp lib/
3994
3993
3995 - all revision numbers that match a keyword::
3994 - all revision numbers that match a keyword::
3996
3995
3997 hg log -k bug --template "{rev}\\n"
3996 hg log -k bug --template "{rev}\\n"
3998
3997
3999 - check if a given changeset is included is a tagged release::
3998 - check if a given changeset is included is a tagged release::
4000
3999
4001 hg log -r "a21ccf and ancestor(1.9)"
4000 hg log -r "a21ccf and ancestor(1.9)"
4002
4001
4003 - find all changesets by some user in a date range::
4002 - find all changesets by some user in a date range::
4004
4003
4005 hg log -k alice -d "may 2008 to jul 2008"
4004 hg log -k alice -d "may 2008 to jul 2008"
4006
4005
4007 - summary of all changesets after the last tag::
4006 - summary of all changesets after the last tag::
4008
4007
4009 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4008 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4010
4009
4011 See :hg:`help dates` for a list of formats valid for -d/--date.
4010 See :hg:`help dates` for a list of formats valid for -d/--date.
4012
4011
4013 See :hg:`help revisions` and :hg:`help revsets` for more about
4012 See :hg:`help revisions` and :hg:`help revsets` for more about
4014 specifying revisions.
4013 specifying revisions.
4015
4014
4016 See :hg:`help templates` for more about pre-packaged styles and
4015 See :hg:`help templates` for more about pre-packaged styles and
4017 specifying custom templates.
4016 specifying custom templates.
4018
4017
4019 Returns 0 on success.
4018 Returns 0 on success.
4020 """
4019 """
4021 if opts.get('graph'):
4020 if opts.get('graph'):
4022 return cmdutil.graphlog(ui, repo, *pats, **opts)
4021 return cmdutil.graphlog(ui, repo, *pats, **opts)
4023
4022
4024 matchfn = scmutil.match(repo[None], pats, opts)
4023 matchfn = scmutil.match(repo[None], pats, opts)
4025 limit = cmdutil.loglimit(opts)
4024 limit = cmdutil.loglimit(opts)
4026 count = 0
4025 count = 0
4027
4026
4028 getrenamed, endrev = None, None
4027 getrenamed, endrev = None, None
4029 if opts.get('copies'):
4028 if opts.get('copies'):
4030 if opts.get('rev'):
4029 if opts.get('rev'):
4031 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4030 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4032 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4031 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4033
4032
4034 df = False
4033 df = False
4035 if opts.get("date"):
4034 if opts.get("date"):
4036 df = util.matchdate(opts["date"])
4035 df = util.matchdate(opts["date"])
4037
4036
4038 branches = opts.get('branch', []) + opts.get('only_branch', [])
4037 branches = opts.get('branch', []) + opts.get('only_branch', [])
4039 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4038 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4040
4039
4041 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4040 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4042 def prep(ctx, fns):
4041 def prep(ctx, fns):
4043 rev = ctx.rev()
4042 rev = ctx.rev()
4044 parents = [p for p in repo.changelog.parentrevs(rev)
4043 parents = [p for p in repo.changelog.parentrevs(rev)
4045 if p != nullrev]
4044 if p != nullrev]
4046 if opts.get('no_merges') and len(parents) == 2:
4045 if opts.get('no_merges') and len(parents) == 2:
4047 return
4046 return
4048 if opts.get('only_merges') and len(parents) != 2:
4047 if opts.get('only_merges') and len(parents) != 2:
4049 return
4048 return
4050 if opts.get('branch') and ctx.branch() not in opts['branch']:
4049 if opts.get('branch') and ctx.branch() not in opts['branch']:
4051 return
4050 return
4052 if df and not df(ctx.date()[0]):
4051 if df and not df(ctx.date()[0]):
4053 return
4052 return
4054
4053
4055 lower = encoding.lower
4054 lower = encoding.lower
4056 if opts.get('user'):
4055 if opts.get('user'):
4057 luser = lower(ctx.user())
4056 luser = lower(ctx.user())
4058 for k in [lower(x) for x in opts['user']]:
4057 for k in [lower(x) for x in opts['user']]:
4059 if (k in luser):
4058 if (k in luser):
4060 break
4059 break
4061 else:
4060 else:
4062 return
4061 return
4063 if opts.get('keyword'):
4062 if opts.get('keyword'):
4064 luser = lower(ctx.user())
4063 luser = lower(ctx.user())
4065 ldesc = lower(ctx.description())
4064 ldesc = lower(ctx.description())
4066 lfiles = lower(" ".join(ctx.files()))
4065 lfiles = lower(" ".join(ctx.files()))
4067 for k in [lower(x) for x in opts['keyword']]:
4066 for k in [lower(x) for x in opts['keyword']]:
4068 if (k in luser or k in ldesc or k in lfiles):
4067 if (k in luser or k in ldesc or k in lfiles):
4069 break
4068 break
4070 else:
4069 else:
4071 return
4070 return
4072
4071
4073 copies = None
4072 copies = None
4074 if getrenamed is not None and rev:
4073 if getrenamed is not None and rev:
4075 copies = []
4074 copies = []
4076 for fn in ctx.files():
4075 for fn in ctx.files():
4077 rename = getrenamed(fn, rev)
4076 rename = getrenamed(fn, rev)
4078 if rename:
4077 if rename:
4079 copies.append((fn, rename[0]))
4078 copies.append((fn, rename[0]))
4080
4079
4081 revmatchfn = None
4080 revmatchfn = None
4082 if opts.get('patch') or opts.get('stat'):
4081 if opts.get('patch') or opts.get('stat'):
4083 if opts.get('follow') or opts.get('follow_first'):
4082 if opts.get('follow') or opts.get('follow_first'):
4084 # note: this might be wrong when following through merges
4083 # note: this might be wrong when following through merges
4085 revmatchfn = scmutil.match(repo[None], fns, default='path')
4084 revmatchfn = scmutil.match(repo[None], fns, default='path')
4086 else:
4085 else:
4087 revmatchfn = matchfn
4086 revmatchfn = matchfn
4088
4087
4089 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4088 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4090
4089
4091 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4090 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4092 if displayer.flush(ctx.rev()):
4091 if displayer.flush(ctx.rev()):
4093 count += 1
4092 count += 1
4094 if count == limit:
4093 if count == limit:
4095 break
4094 break
4096 displayer.close()
4095 displayer.close()
4097
4096
4098 @command('manifest',
4097 @command('manifest',
4099 [('r', 'rev', '', _('revision to display'), _('REV')),
4098 [('r', 'rev', '', _('revision to display'), _('REV')),
4100 ('', 'all', False, _("list files from all revisions"))],
4099 ('', 'all', False, _("list files from all revisions"))],
4101 _('[-r REV]'))
4100 _('[-r REV]'))
4102 def manifest(ui, repo, node=None, rev=None, **opts):
4101 def manifest(ui, repo, node=None, rev=None, **opts):
4103 """output the current or given revision of the project manifest
4102 """output the current or given revision of the project manifest
4104
4103
4105 Print a list of version controlled files for the given revision.
4104 Print a list of version controlled files for the given revision.
4106 If no revision is given, the first parent of the working directory
4105 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.
4106 is used, or the null revision if no revision is checked out.
4108
4107
4109 With -v, print file permissions, symlink and executable bits.
4108 With -v, print file permissions, symlink and executable bits.
4110 With --debug, print file revision hashes.
4109 With --debug, print file revision hashes.
4111
4110
4112 If option --all is specified, the list of all files from all revisions
4111 If option --all is specified, the list of all files from all revisions
4113 is printed. This includes deleted and renamed files.
4112 is printed. This includes deleted and renamed files.
4114
4113
4115 Returns 0 on success.
4114 Returns 0 on success.
4116 """
4115 """
4117
4116
4118 fm = ui.formatter('manifest', opts)
4117 fm = ui.formatter('manifest', opts)
4119
4118
4120 if opts.get('all'):
4119 if opts.get('all'):
4121 if rev or node:
4120 if rev or node:
4122 raise util.Abort(_("can't specify a revision with --all"))
4121 raise util.Abort(_("can't specify a revision with --all"))
4123
4122
4124 res = []
4123 res = []
4125 prefix = "data/"
4124 prefix = "data/"
4126 suffix = ".i"
4125 suffix = ".i"
4127 plen = len(prefix)
4126 plen = len(prefix)
4128 slen = len(suffix)
4127 slen = len(suffix)
4129 lock = repo.lock()
4128 lock = repo.lock()
4130 try:
4129 try:
4131 for fn, b, size in repo.store.datafiles():
4130 for fn, b, size in repo.store.datafiles():
4132 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4131 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4133 res.append(fn[plen:-slen])
4132 res.append(fn[plen:-slen])
4134 finally:
4133 finally:
4135 lock.release()
4134 lock.release()
4136 for f in res:
4135 for f in res:
4137 fm.startitem()
4136 fm.startitem()
4138 fm.write("path", '%s\n', f)
4137 fm.write("path", '%s\n', f)
4139 fm.end()
4138 fm.end()
4140 return
4139 return
4141
4140
4142 if rev and node:
4141 if rev and node:
4143 raise util.Abort(_("please specify just one revision"))
4142 raise util.Abort(_("please specify just one revision"))
4144
4143
4145 if not node:
4144 if not node:
4146 node = rev
4145 node = rev
4147
4146
4148 char = {'l': '@', 'x': '*', '': ''}
4147 char = {'l': '@', 'x': '*', '': ''}
4149 mode = {'l': '644', 'x': '755', '': '644'}
4148 mode = {'l': '644', 'x': '755', '': '644'}
4150 ctx = scmutil.revsingle(repo, node)
4149 ctx = scmutil.revsingle(repo, node)
4151 mf = ctx.manifest()
4150 mf = ctx.manifest()
4152 for f in ctx:
4151 for f in ctx:
4153 fm.startitem()
4152 fm.startitem()
4154 fl = ctx[f].flags()
4153 fl = ctx[f].flags()
4155 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4154 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4156 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4155 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4157 fm.write('path', '%s\n', f)
4156 fm.write('path', '%s\n', f)
4158 fm.end()
4157 fm.end()
4159
4158
4160 @command('^merge',
4159 @command('^merge',
4161 [('f', 'force', None, _('force a merge with outstanding changes')),
4160 [('f', 'force', None, _('force a merge with outstanding changes')),
4162 ('r', 'rev', '', _('revision to merge'), _('REV')),
4161 ('r', 'rev', '', _('revision to merge'), _('REV')),
4163 ('P', 'preview', None,
4162 ('P', 'preview', None,
4164 _('review revisions to merge (no merge is performed)'))
4163 _('review revisions to merge (no merge is performed)'))
4165 ] + mergetoolopts,
4164 ] + mergetoolopts,
4166 _('[-P] [-f] [[-r] REV]'))
4165 _('[-P] [-f] [[-r] REV]'))
4167 def merge(ui, repo, node=None, **opts):
4166 def merge(ui, repo, node=None, **opts):
4168 """merge working directory with another revision
4167 """merge working directory with another revision
4169
4168
4170 The current working directory is updated with all changes made in
4169 The current working directory is updated with all changes made in
4171 the requested revision since the last common predecessor revision.
4170 the requested revision since the last common predecessor revision.
4172
4171
4173 Files that changed between either parent are marked as changed for
4172 Files that changed between either parent are marked as changed for
4174 the next commit and a commit must be performed before any further
4173 the next commit and a commit must be performed before any further
4175 updates to the repository are allowed. The next commit will have
4174 updates to the repository are allowed. The next commit will have
4176 two parents.
4175 two parents.
4177
4176
4178 ``--tool`` can be used to specify the merge tool used for file
4177 ``--tool`` can be used to specify the merge tool used for file
4179 merges. It overrides the HGMERGE environment variable and your
4178 merges. It overrides the HGMERGE environment variable and your
4180 configuration files. See :hg:`help merge-tools` for options.
4179 configuration files. See :hg:`help merge-tools` for options.
4181
4180
4182 If no revision is specified, the working directory's parent is a
4181 If no revision is specified, the working directory's parent is a
4183 head revision, and the current branch contains exactly one other
4182 head revision, and the current branch contains exactly one other
4184 head, the other head is merged with by default. Otherwise, an
4183 head, the other head is merged with by default. Otherwise, an
4185 explicit revision with which to merge with must be provided.
4184 explicit revision with which to merge with must be provided.
4186
4185
4187 :hg:`resolve` must be used to resolve unresolved files.
4186 :hg:`resolve` must be used to resolve unresolved files.
4188
4187
4189 To undo an uncommitted merge, use :hg:`update --clean .` which
4188 To undo an uncommitted merge, use :hg:`update --clean .` which
4190 will check out a clean copy of the original merge parent, losing
4189 will check out a clean copy of the original merge parent, losing
4191 all changes.
4190 all changes.
4192
4191
4193 Returns 0 on success, 1 if there are unresolved files.
4192 Returns 0 on success, 1 if there are unresolved files.
4194 """
4193 """
4195
4194
4196 if opts.get('rev') and node:
4195 if opts.get('rev') and node:
4197 raise util.Abort(_("please specify just one revision"))
4196 raise util.Abort(_("please specify just one revision"))
4198 if not node:
4197 if not node:
4199 node = opts.get('rev')
4198 node = opts.get('rev')
4200
4199
4201 if node:
4200 if node:
4202 node = scmutil.revsingle(repo, node).node()
4201 node = scmutil.revsingle(repo, node).node()
4203
4202
4204 if not node and repo._bookmarkcurrent:
4203 if not node and repo._bookmarkcurrent:
4205 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4204 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4206 curhead = repo[repo._bookmarkcurrent].node()
4205 curhead = repo[repo._bookmarkcurrent].node()
4207 if len(bmheads) == 2:
4206 if len(bmheads) == 2:
4208 if curhead == bmheads[0]:
4207 if curhead == bmheads[0]:
4209 node = bmheads[1]
4208 node = bmheads[1]
4210 else:
4209 else:
4211 node = bmheads[0]
4210 node = bmheads[0]
4212 elif len(bmheads) > 2:
4211 elif len(bmheads) > 2:
4213 raise util.Abort(_("multiple matching bookmarks to merge - "
4212 raise util.Abort(_("multiple matching bookmarks to merge - "
4214 "please merge with an explicit rev or bookmark"),
4213 "please merge with an explicit rev or bookmark"),
4215 hint=_("run 'hg heads' to see all heads"))
4214 hint=_("run 'hg heads' to see all heads"))
4216 elif len(bmheads) <= 1:
4215 elif len(bmheads) <= 1:
4217 raise util.Abort(_("no matching bookmark to merge - "
4216 raise util.Abort(_("no matching bookmark to merge - "
4218 "please merge with an explicit rev or bookmark"),
4217 "please merge with an explicit rev or bookmark"),
4219 hint=_("run 'hg heads' to see all heads"))
4218 hint=_("run 'hg heads' to see all heads"))
4220
4219
4221 if not node and not repo._bookmarkcurrent:
4220 if not node and not repo._bookmarkcurrent:
4222 branch = repo[None].branch()
4221 branch = repo[None].branch()
4223 bheads = repo.branchheads(branch)
4222 bheads = repo.branchheads(branch)
4224 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4223 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4225
4224
4226 if len(nbhs) > 2:
4225 if len(nbhs) > 2:
4227 raise util.Abort(_("branch '%s' has %d heads - "
4226 raise util.Abort(_("branch '%s' has %d heads - "
4228 "please merge with an explicit rev")
4227 "please merge with an explicit rev")
4229 % (branch, len(bheads)),
4228 % (branch, len(bheads)),
4230 hint=_("run 'hg heads .' to see heads"))
4229 hint=_("run 'hg heads .' to see heads"))
4231
4230
4232 parent = repo.dirstate.p1()
4231 parent = repo.dirstate.p1()
4233 if len(nbhs) <= 1:
4232 if len(nbhs) <= 1:
4234 if len(bheads) > 1:
4233 if len(bheads) > 1:
4235 raise util.Abort(_("heads are bookmarked - "
4234 raise util.Abort(_("heads are bookmarked - "
4236 "please merge with an explicit rev"),
4235 "please merge with an explicit rev"),
4237 hint=_("run 'hg heads' to see all heads"))
4236 hint=_("run 'hg heads' to see all heads"))
4238 if len(repo.heads()) > 1:
4237 if len(repo.heads()) > 1:
4239 raise util.Abort(_("branch '%s' has one head - "
4238 raise util.Abort(_("branch '%s' has one head - "
4240 "please merge with an explicit rev")
4239 "please merge with an explicit rev")
4241 % branch,
4240 % branch,
4242 hint=_("run 'hg heads' to see all heads"))
4241 hint=_("run 'hg heads' to see all heads"))
4243 msg, hint = _('nothing to merge'), None
4242 msg, hint = _('nothing to merge'), None
4244 if parent != repo.lookup(branch):
4243 if parent != repo.lookup(branch):
4245 hint = _("use 'hg update' instead")
4244 hint = _("use 'hg update' instead")
4246 raise util.Abort(msg, hint=hint)
4245 raise util.Abort(msg, hint=hint)
4247
4246
4248 if parent not in bheads:
4247 if parent not in bheads:
4249 raise util.Abort(_('working directory not at a head revision'),
4248 raise util.Abort(_('working directory not at a head revision'),
4250 hint=_("use 'hg update' or merge with an "
4249 hint=_("use 'hg update' or merge with an "
4251 "explicit revision"))
4250 "explicit revision"))
4252 if parent == nbhs[0]:
4251 if parent == nbhs[0]:
4253 node = nbhs[-1]
4252 node = nbhs[-1]
4254 else:
4253 else:
4255 node = nbhs[0]
4254 node = nbhs[0]
4256
4255
4257 if opts.get('preview'):
4256 if opts.get('preview'):
4258 # find nodes that are ancestors of p2 but not of p1
4257 # find nodes that are ancestors of p2 but not of p1
4259 p1 = repo.lookup('.')
4258 p1 = repo.lookup('.')
4260 p2 = repo.lookup(node)
4259 p2 = repo.lookup(node)
4261 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4260 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4262
4261
4263 displayer = cmdutil.show_changeset(ui, repo, opts)
4262 displayer = cmdutil.show_changeset(ui, repo, opts)
4264 for node in nodes:
4263 for node in nodes:
4265 displayer.show(repo[node])
4264 displayer.show(repo[node])
4266 displayer.close()
4265 displayer.close()
4267 return 0
4266 return 0
4268
4267
4269 try:
4268 try:
4270 # ui.forcemerge is an internal variable, do not document
4269 # ui.forcemerge is an internal variable, do not document
4271 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4270 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4272 return hg.merge(repo, node, force=opts.get('force'))
4271 return hg.merge(repo, node, force=opts.get('force'))
4273 finally:
4272 finally:
4274 ui.setconfig('ui', 'forcemerge', '')
4273 ui.setconfig('ui', 'forcemerge', '')
4275
4274
4276 @command('outgoing|out',
4275 @command('outgoing|out',
4277 [('f', 'force', None, _('run even when the destination is unrelated')),
4276 [('f', 'force', None, _('run even when the destination is unrelated')),
4278 ('r', 'rev', [],
4277 ('r', 'rev', [],
4279 _('a changeset intended to be included in the destination'), _('REV')),
4278 _('a changeset intended to be included in the destination'), _('REV')),
4280 ('n', 'newest-first', None, _('show newest record first')),
4279 ('n', 'newest-first', None, _('show newest record first')),
4281 ('B', 'bookmarks', False, _('compare bookmarks')),
4280 ('B', 'bookmarks', False, _('compare bookmarks')),
4282 ('b', 'branch', [], _('a specific branch you would like to push'),
4281 ('b', 'branch', [], _('a specific branch you would like to push'),
4283 _('BRANCH')),
4282 _('BRANCH')),
4284 ] + logopts + remoteopts + subrepoopts,
4283 ] + logopts + remoteopts + subrepoopts,
4285 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4284 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4286 def outgoing(ui, repo, dest=None, **opts):
4285 def outgoing(ui, repo, dest=None, **opts):
4287 """show changesets not found in the destination
4286 """show changesets not found in the destination
4288
4287
4289 Show changesets not found in the specified destination repository
4288 Show changesets not found in the specified destination repository
4290 or the default push location. These are the changesets that would
4289 or the default push location. These are the changesets that would
4291 be pushed if a push was requested.
4290 be pushed if a push was requested.
4292
4291
4293 See pull for details of valid destination formats.
4292 See pull for details of valid destination formats.
4294
4293
4295 Returns 0 if there are outgoing changes, 1 otherwise.
4294 Returns 0 if there are outgoing changes, 1 otherwise.
4296 """
4295 """
4297 if opts.get('graph'):
4296 if opts.get('graph'):
4298 cmdutil.checkunsupportedgraphflags([], opts)
4297 cmdutil.checkunsupportedgraphflags([], opts)
4299 o = hg._outgoing(ui, repo, dest, opts)
4298 o = hg._outgoing(ui, repo, dest, opts)
4300 if o is None:
4299 if o is None:
4301 return
4300 return
4302
4301
4303 revdag = cmdutil.graphrevs(repo, o, opts)
4302 revdag = cmdutil.graphrevs(repo, o, opts)
4304 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4303 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4305 showparents = [ctx.node() for ctx in repo[None].parents()]
4304 showparents = [ctx.node() for ctx in repo[None].parents()]
4306 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4305 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4307 graphmod.asciiedges)
4306 graphmod.asciiedges)
4308 return 0
4307 return 0
4309
4308
4310 if opts.get('bookmarks'):
4309 if opts.get('bookmarks'):
4311 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4310 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4312 dest, branches = hg.parseurl(dest, opts.get('branch'))
4311 dest, branches = hg.parseurl(dest, opts.get('branch'))
4313 other = hg.peer(repo, opts, dest)
4312 other = hg.peer(repo, opts, dest)
4314 if 'bookmarks' not in other.listkeys('namespaces'):
4313 if 'bookmarks' not in other.listkeys('namespaces'):
4315 ui.warn(_("remote doesn't support bookmarks\n"))
4314 ui.warn(_("remote doesn't support bookmarks\n"))
4316 return 0
4315 return 0
4317 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4316 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4318 return bookmarks.diff(ui, other, repo)
4317 return bookmarks.diff(ui, other, repo)
4319
4318
4320 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4319 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4321 try:
4320 try:
4322 return hg.outgoing(ui, repo, dest, opts)
4321 return hg.outgoing(ui, repo, dest, opts)
4323 finally:
4322 finally:
4324 del repo._subtoppath
4323 del repo._subtoppath
4325
4324
4326 @command('parents',
4325 @command('parents',
4327 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4326 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4328 ] + templateopts,
4327 ] + templateopts,
4329 _('[-r REV] [FILE]'))
4328 _('[-r REV] [FILE]'))
4330 def parents(ui, repo, file_=None, **opts):
4329 def parents(ui, repo, file_=None, **opts):
4331 """show the parents of the working directory or revision
4330 """show the parents of the working directory or revision
4332
4331
4333 Print the working directory's parent revisions. If a revision is
4332 Print the working directory's parent revisions. If a revision is
4334 given via -r/--rev, the parent of that revision will be printed.
4333 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
4334 If a file argument is given, the revision in which the file was
4336 last changed (before the working directory revision or the
4335 last changed (before the working directory revision or the
4337 argument to --rev if given) is printed.
4336 argument to --rev if given) is printed.
4338
4337
4339 Returns 0 on success.
4338 Returns 0 on success.
4340 """
4339 """
4341
4340
4342 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4341 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4343
4342
4344 if file_:
4343 if file_:
4345 m = scmutil.match(ctx, (file_,), opts)
4344 m = scmutil.match(ctx, (file_,), opts)
4346 if m.anypats() or len(m.files()) != 1:
4345 if m.anypats() or len(m.files()) != 1:
4347 raise util.Abort(_('can only specify an explicit filename'))
4346 raise util.Abort(_('can only specify an explicit filename'))
4348 file_ = m.files()[0]
4347 file_ = m.files()[0]
4349 filenodes = []
4348 filenodes = []
4350 for cp in ctx.parents():
4349 for cp in ctx.parents():
4351 if not cp:
4350 if not cp:
4352 continue
4351 continue
4353 try:
4352 try:
4354 filenodes.append(cp.filenode(file_))
4353 filenodes.append(cp.filenode(file_))
4355 except error.LookupError:
4354 except error.LookupError:
4356 pass
4355 pass
4357 if not filenodes:
4356 if not filenodes:
4358 raise util.Abort(_("'%s' not found in manifest!") % file_)
4357 raise util.Abort(_("'%s' not found in manifest!") % file_)
4359 p = []
4358 p = []
4360 for fn in filenodes:
4359 for fn in filenodes:
4361 fctx = repo.filectx(file_, fileid=fn)
4360 fctx = repo.filectx(file_, fileid=fn)
4362 p.append(fctx.node())
4361 p.append(fctx.node())
4363 else:
4362 else:
4364 p = [cp.node() for cp in ctx.parents()]
4363 p = [cp.node() for cp in ctx.parents()]
4365
4364
4366 displayer = cmdutil.show_changeset(ui, repo, opts)
4365 displayer = cmdutil.show_changeset(ui, repo, opts)
4367 for n in p:
4366 for n in p:
4368 if n != nullid:
4367 if n != nullid:
4369 displayer.show(repo[n])
4368 displayer.show(repo[n])
4370 displayer.close()
4369 displayer.close()
4371
4370
4372 @command('paths', [], _('[NAME]'))
4371 @command('paths', [], _('[NAME]'))
4373 def paths(ui, repo, search=None):
4372 def paths(ui, repo, search=None):
4374 """show aliases for remote repositories
4373 """show aliases for remote repositories
4375
4374
4376 Show definition of symbolic path name NAME. If no name is given,
4375 Show definition of symbolic path name NAME. If no name is given,
4377 show definition of all available names.
4376 show definition of all available names.
4378
4377
4379 Option -q/--quiet suppresses all output when searching for NAME
4378 Option -q/--quiet suppresses all output when searching for NAME
4380 and shows only the path names when listing all definitions.
4379 and shows only the path names when listing all definitions.
4381
4380
4382 Path names are defined in the [paths] section of your
4381 Path names are defined in the [paths] section of your
4383 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4382 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4384 repository, ``.hg/hgrc`` is used, too.
4383 repository, ``.hg/hgrc`` is used, too.
4385
4384
4386 The path names ``default`` and ``default-push`` have a special
4385 The path names ``default`` and ``default-push`` have a special
4387 meaning. When performing a push or pull operation, they are used
4386 meaning. When performing a push or pull operation, they are used
4388 as fallbacks if no location is specified on the command-line.
4387 as fallbacks if no location is specified on the command-line.
4389 When ``default-push`` is set, it will be used for push and
4388 When ``default-push`` is set, it will be used for push and
4390 ``default`` will be used for pull; otherwise ``default`` is used
4389 ``default`` will be used for pull; otherwise ``default`` is used
4391 as the fallback for both. When cloning a repository, the clone
4390 as the fallback for both. When cloning a repository, the clone
4392 source is written as ``default`` in ``.hg/hgrc``. Note that
4391 source is written as ``default`` in ``.hg/hgrc``. Note that
4393 ``default`` and ``default-push`` apply to all inbound (e.g.
4392 ``default`` and ``default-push`` apply to all inbound (e.g.
4394 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4393 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4395 :hg:`bundle`) operations.
4394 :hg:`bundle`) operations.
4396
4395
4397 See :hg:`help urls` for more information.
4396 See :hg:`help urls` for more information.
4398
4397
4399 Returns 0 on success.
4398 Returns 0 on success.
4400 """
4399 """
4401 if search:
4400 if search:
4402 for name, path in ui.configitems("paths"):
4401 for name, path in ui.configitems("paths"):
4403 if name == search:
4402 if name == search:
4404 ui.status("%s\n" % util.hidepassword(path))
4403 ui.status("%s\n" % util.hidepassword(path))
4405 return
4404 return
4406 if not ui.quiet:
4405 if not ui.quiet:
4407 ui.warn(_("not found!\n"))
4406 ui.warn(_("not found!\n"))
4408 return 1
4407 return 1
4409 else:
4408 else:
4410 for name, path in ui.configitems("paths"):
4409 for name, path in ui.configitems("paths"):
4411 if ui.quiet:
4410 if ui.quiet:
4412 ui.write("%s\n" % name)
4411 ui.write("%s\n" % name)
4413 else:
4412 else:
4414 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4413 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4415
4414
4416 @command('phase',
4415 @command('phase',
4417 [('p', 'public', False, _('set changeset phase to public')),
4416 [('p', 'public', False, _('set changeset phase to public')),
4418 ('d', 'draft', False, _('set changeset phase to draft')),
4417 ('d', 'draft', False, _('set changeset phase to draft')),
4419 ('s', 'secret', False, _('set changeset phase to secret')),
4418 ('s', 'secret', False, _('set changeset phase to secret')),
4420 ('f', 'force', False, _('allow to move boundary backward')),
4419 ('f', 'force', False, _('allow to move boundary backward')),
4421 ('r', 'rev', [], _('target revision'), _('REV')),
4420 ('r', 'rev', [], _('target revision'), _('REV')),
4422 ],
4421 ],
4423 _('[-p|-d|-s] [-f] [-r] REV...'))
4422 _('[-p|-d|-s] [-f] [-r] REV...'))
4424 def phase(ui, repo, *revs, **opts):
4423 def phase(ui, repo, *revs, **opts):
4425 """set or show the current phase name
4424 """set or show the current phase name
4426
4425
4427 With no argument, show the phase name of specified revisions.
4426 With no argument, show the phase name of specified revisions.
4428
4427
4429 With one of -p/--public, -d/--draft or -s/--secret, change the
4428 With one of -p/--public, -d/--draft or -s/--secret, change the
4430 phase value of the specified revisions.
4429 phase value of the specified revisions.
4431
4430
4432 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4431 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::
4432 lower phase to an higher phase. Phases are ordered as follows::
4434
4433
4435 public < draft < secret
4434 public < draft < secret
4436
4435
4437 Return 0 on success, 1 if no phases were changed or some could not
4436 Return 0 on success, 1 if no phases were changed or some could not
4438 be changed.
4437 be changed.
4439 """
4438 """
4440 # search for a unique phase argument
4439 # search for a unique phase argument
4441 targetphase = None
4440 targetphase = None
4442 for idx, name in enumerate(phases.phasenames):
4441 for idx, name in enumerate(phases.phasenames):
4443 if opts[name]:
4442 if opts[name]:
4444 if targetphase is not None:
4443 if targetphase is not None:
4445 raise util.Abort(_('only one phase can be specified'))
4444 raise util.Abort(_('only one phase can be specified'))
4446 targetphase = idx
4445 targetphase = idx
4447
4446
4448 # look for specified revision
4447 # look for specified revision
4449 revs = list(revs)
4448 revs = list(revs)
4450 revs.extend(opts['rev'])
4449 revs.extend(opts['rev'])
4451 if not revs:
4450 if not revs:
4452 raise util.Abort(_('no revisions specified'))
4451 raise util.Abort(_('no revisions specified'))
4453
4452
4454 revs = scmutil.revrange(repo, revs)
4453 revs = scmutil.revrange(repo, revs)
4455
4454
4456 lock = None
4455 lock = None
4457 ret = 0
4456 ret = 0
4458 if targetphase is None:
4457 if targetphase is None:
4459 # display
4458 # display
4460 for r in revs:
4459 for r in revs:
4461 ctx = repo[r]
4460 ctx = repo[r]
4462 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4461 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4463 else:
4462 else:
4464 lock = repo.lock()
4463 lock = repo.lock()
4465 try:
4464 try:
4466 # set phase
4465 # set phase
4467 if not revs:
4466 if not revs:
4468 raise util.Abort(_('empty revision set'))
4467 raise util.Abort(_('empty revision set'))
4469 nodes = [repo[r].node() for r in revs]
4468 nodes = [repo[r].node() for r in revs]
4470 olddata = repo._phasecache.getphaserevs(repo)[:]
4469 olddata = repo._phasecache.getphaserevs(repo)[:]
4471 phases.advanceboundary(repo, targetphase, nodes)
4470 phases.advanceboundary(repo, targetphase, nodes)
4472 if opts['force']:
4471 if opts['force']:
4473 phases.retractboundary(repo, targetphase, nodes)
4472 phases.retractboundary(repo, targetphase, nodes)
4474 finally:
4473 finally:
4475 lock.release()
4474 lock.release()
4476 # moving revision from public to draft may hide them
4475 # moving revision from public to draft may hide them
4477 # We have to check result on an unfiltered repository
4476 # We have to check result on an unfiltered repository
4478 unfi = repo.unfiltered()
4477 unfi = repo.unfiltered()
4479 newdata = repo._phasecache.getphaserevs(unfi)
4478 newdata = repo._phasecache.getphaserevs(unfi)
4480 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4479 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4481 cl = unfi.changelog
4480 cl = unfi.changelog
4482 rejected = [n for n in nodes
4481 rejected = [n for n in nodes
4483 if newdata[cl.rev(n)] < targetphase]
4482 if newdata[cl.rev(n)] < targetphase]
4484 if rejected:
4483 if rejected:
4485 ui.warn(_('cannot move %i changesets to a more permissive '
4484 ui.warn(_('cannot move %i changesets to a more permissive '
4486 'phase, use --force\n') % len(rejected))
4485 'phase, use --force\n') % len(rejected))
4487 ret = 1
4486 ret = 1
4488 if changes:
4487 if changes:
4489 msg = _('phase changed for %i changesets\n') % changes
4488 msg = _('phase changed for %i changesets\n') % changes
4490 if ret:
4489 if ret:
4491 ui.status(msg)
4490 ui.status(msg)
4492 else:
4491 else:
4493 ui.note(msg)
4492 ui.note(msg)
4494 else:
4493 else:
4495 ui.warn(_('no phases changed\n'))
4494 ui.warn(_('no phases changed\n'))
4496 ret = 1
4495 ret = 1
4497 return ret
4496 return ret
4498
4497
4499 def postincoming(ui, repo, modheads, optupdate, checkout):
4498 def postincoming(ui, repo, modheads, optupdate, checkout):
4500 if modheads == 0:
4499 if modheads == 0:
4501 return
4500 return
4502 if optupdate:
4501 if optupdate:
4503 movemarkfrom = repo['.'].node()
4502 movemarkfrom = repo['.'].node()
4504 try:
4503 try:
4505 ret = hg.update(repo, checkout)
4504 ret = hg.update(repo, checkout)
4506 except util.Abort, inst:
4505 except util.Abort, inst:
4507 ui.warn(_("not updating: %s\n") % str(inst))
4506 ui.warn(_("not updating: %s\n") % str(inst))
4508 return 0
4507 return 0
4509 if not ret and not checkout:
4508 if not ret and not checkout:
4510 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4509 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4511 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4510 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4512 return ret
4511 return ret
4513 if modheads > 1:
4512 if modheads > 1:
4514 currentbranchheads = len(repo.branchheads())
4513 currentbranchheads = len(repo.branchheads())
4515 if currentbranchheads == modheads:
4514 if currentbranchheads == modheads:
4516 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4515 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4517 elif currentbranchheads > 1:
4516 elif currentbranchheads > 1:
4518 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4517 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4519 "merge)\n"))
4518 "merge)\n"))
4520 else:
4519 else:
4521 ui.status(_("(run 'hg heads' to see heads)\n"))
4520 ui.status(_("(run 'hg heads' to see heads)\n"))
4522 else:
4521 else:
4523 ui.status(_("(run 'hg update' to get a working copy)\n"))
4522 ui.status(_("(run 'hg update' to get a working copy)\n"))
4524
4523
4525 @command('^pull',
4524 @command('^pull',
4526 [('u', 'update', None,
4525 [('u', 'update', None,
4527 _('update to new branch head if changesets were pulled')),
4526 _('update to new branch head if changesets were pulled')),
4528 ('f', 'force', None, _('run even when remote repository is unrelated')),
4527 ('f', 'force', None, _('run even when remote repository is unrelated')),
4529 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4528 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4530 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4529 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4531 ('b', 'branch', [], _('a specific branch you would like to pull'),
4530 ('b', 'branch', [], _('a specific branch you would like to pull'),
4532 _('BRANCH')),
4531 _('BRANCH')),
4533 ] + remoteopts,
4532 ] + remoteopts,
4534 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4533 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4535 def pull(ui, repo, source="default", **opts):
4534 def pull(ui, repo, source="default", **opts):
4536 """pull changes from the specified source
4535 """pull changes from the specified source
4537
4536
4538 Pull changes from a remote repository to a local one.
4537 Pull changes from a remote repository to a local one.
4539
4538
4540 This finds all changes from the repository at the specified path
4539 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
4540 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
4541 -R is specified). By default, this does not update the copy of the
4543 project in the working directory.
4542 project in the working directory.
4544
4543
4545 Use :hg:`incoming` if you want to see what would have been added
4544 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
4545 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
4546 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`.
4547 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4549
4548
4550 If SOURCE is omitted, the 'default' path will be used.
4549 If SOURCE is omitted, the 'default' path will be used.
4551 See :hg:`help urls` for more information.
4550 See :hg:`help urls` for more information.
4552
4551
4553 Returns 0 on success, 1 if an update had unresolved files.
4552 Returns 0 on success, 1 if an update had unresolved files.
4554 """
4553 """
4555 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4554 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4556 other = hg.peer(repo, opts, source)
4555 other = hg.peer(repo, opts, source)
4557 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4556 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4558 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4557 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4559
4558
4560 remotebookmarks = other.listkeys('bookmarks')
4559 remotebookmarks = other.listkeys('bookmarks')
4561
4560
4562 if opts.get('bookmark'):
4561 if opts.get('bookmark'):
4563 if not revs:
4562 if not revs:
4564 revs = []
4563 revs = []
4565 for b in opts['bookmark']:
4564 for b in opts['bookmark']:
4566 if b not in remotebookmarks:
4565 if b not in remotebookmarks:
4567 raise util.Abort(_('remote bookmark %s not found!') % b)
4566 raise util.Abort(_('remote bookmark %s not found!') % b)
4568 revs.append(remotebookmarks[b])
4567 revs.append(remotebookmarks[b])
4569
4568
4570 if revs:
4569 if revs:
4571 try:
4570 try:
4572 revs = [other.lookup(rev) for rev in revs]
4571 revs = [other.lookup(rev) for rev in revs]
4573 except error.CapabilityError:
4572 except error.CapabilityError:
4574 err = _("other repository doesn't support revision lookup, "
4573 err = _("other repository doesn't support revision lookup, "
4575 "so a rev cannot be specified.")
4574 "so a rev cannot be specified.")
4576 raise util.Abort(err)
4575 raise util.Abort(err)
4577
4576
4578 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4577 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4579 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4578 bookmarks.updatefromremote(ui, repo, remotebookmarks, source)
4580 if checkout:
4579 if checkout:
4581 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4580 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4582 repo._subtoppath = source
4581 repo._subtoppath = source
4583 try:
4582 try:
4584 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4583 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4585
4584
4586 finally:
4585 finally:
4587 del repo._subtoppath
4586 del repo._subtoppath
4588
4587
4589 # update specified bookmarks
4588 # update specified bookmarks
4590 if opts.get('bookmark'):
4589 if opts.get('bookmark'):
4591 marks = repo._bookmarks
4590 marks = repo._bookmarks
4592 for b in opts['bookmark']:
4591 for b in opts['bookmark']:
4593 # explicit pull overrides local bookmark if any
4592 # explicit pull overrides local bookmark if any
4594 ui.status(_("importing bookmark %s\n") % b)
4593 ui.status(_("importing bookmark %s\n") % b)
4595 marks[b] = repo[remotebookmarks[b]].node()
4594 marks[b] = repo[remotebookmarks[b]].node()
4596 marks.write()
4595 marks.write()
4597
4596
4598 return ret
4597 return ret
4599
4598
4600 @command('^push',
4599 @command('^push',
4601 [('f', 'force', None, _('force push')),
4600 [('f', 'force', None, _('force push')),
4602 ('r', 'rev', [],
4601 ('r', 'rev', [],
4603 _('a changeset intended to be included in the destination'),
4602 _('a changeset intended to be included in the destination'),
4604 _('REV')),
4603 _('REV')),
4605 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4604 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4606 ('b', 'branch', [],
4605 ('b', 'branch', [],
4607 _('a specific branch you would like to push'), _('BRANCH')),
4606 _('a specific branch you would like to push'), _('BRANCH')),
4608 ('', 'new-branch', False, _('allow pushing a new branch')),
4607 ('', 'new-branch', False, _('allow pushing a new branch')),
4609 ] + remoteopts,
4608 ] + remoteopts,
4610 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4609 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4611 def push(ui, repo, dest=None, **opts):
4610 def push(ui, repo, dest=None, **opts):
4612 """push changes to the specified destination
4611 """push changes to the specified destination
4613
4612
4614 Push changesets from the local repository to the specified
4613 Push changesets from the local repository to the specified
4615 destination.
4614 destination.
4616
4615
4617 This operation is symmetrical to pull: it is identical to a pull
4616 This operation is symmetrical to pull: it is identical to a pull
4618 in the destination repository from the current one.
4617 in the destination repository from the current one.
4619
4618
4620 By default, push will not allow creation of new heads at the
4619 By default, push will not allow creation of new heads at the
4621 destination, since multiple heads would make it unclear which head
4620 destination, since multiple heads would make it unclear which head
4622 to use. In this situation, it is recommended to pull and merge
4621 to use. In this situation, it is recommended to pull and merge
4623 before pushing.
4622 before pushing.
4624
4623
4625 Use --new-branch if you want to allow push to create a new named
4624 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
4625 branch that is not present at the destination. This allows you to
4627 only create a new branch without forcing other changes.
4626 only create a new branch without forcing other changes.
4628
4627
4629 Use -f/--force to override the default behavior and push all
4628 Use -f/--force to override the default behavior and push all
4630 changesets on all branches.
4629 changesets on all branches.
4631
4630
4632 If -r/--rev is used, the specified revision and all its ancestors
4631 If -r/--rev is used, the specified revision and all its ancestors
4633 will be pushed to the remote repository.
4632 will be pushed to the remote repository.
4634
4633
4635 If -B/--bookmark is used, the specified bookmarked revision, its
4634 If -B/--bookmark is used, the specified bookmarked revision, its
4636 ancestors, and the bookmark will be pushed to the remote
4635 ancestors, and the bookmark will be pushed to the remote
4637 repository.
4636 repository.
4638
4637
4639 Please see :hg:`help urls` for important details about ``ssh://``
4638 Please see :hg:`help urls` for important details about ``ssh://``
4640 URLs. If DESTINATION is omitted, a default path will be used.
4639 URLs. If DESTINATION is omitted, a default path will be used.
4641
4640
4642 Returns 0 if push was successful, 1 if nothing to push.
4641 Returns 0 if push was successful, 1 if nothing to push.
4643 """
4642 """
4644
4643
4645 if opts.get('bookmark'):
4644 if opts.get('bookmark'):
4646 for b in opts['bookmark']:
4645 for b in opts['bookmark']:
4647 # translate -B options to -r so changesets get pushed
4646 # translate -B options to -r so changesets get pushed
4648 if b in repo._bookmarks:
4647 if b in repo._bookmarks:
4649 opts.setdefault('rev', []).append(b)
4648 opts.setdefault('rev', []).append(b)
4650 else:
4649 else:
4651 # if we try to push a deleted bookmark, translate it to null
4650 # if we try to push a deleted bookmark, translate it to null
4652 # this lets simultaneous -r, -b options continue working
4651 # this lets simultaneous -r, -b options continue working
4653 opts.setdefault('rev', []).append("null")
4652 opts.setdefault('rev', []).append("null")
4654
4653
4655 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4654 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4656 dest, branches = hg.parseurl(dest, opts.get('branch'))
4655 dest, branches = hg.parseurl(dest, opts.get('branch'))
4657 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4656 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4658 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4657 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4659 other = hg.peer(repo, opts, dest)
4658 other = hg.peer(repo, opts, dest)
4660 if revs:
4659 if revs:
4661 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4660 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4662
4661
4663 repo._subtoppath = dest
4662 repo._subtoppath = dest
4664 try:
4663 try:
4665 # push subrepos depth-first for coherent ordering
4664 # push subrepos depth-first for coherent ordering
4666 c = repo['']
4665 c = repo['']
4667 subs = c.substate # only repos that are committed
4666 subs = c.substate # only repos that are committed
4668 for s in sorted(subs):
4667 for s in sorted(subs):
4669 if c.sub(s).push(opts) == 0:
4668 if c.sub(s).push(opts) == 0:
4670 return False
4669 return False
4671 finally:
4670 finally:
4672 del repo._subtoppath
4671 del repo._subtoppath
4673 result = repo.push(other, opts.get('force'), revs=revs,
4672 result = repo.push(other, opts.get('force'), revs=revs,
4674 newbranch=opts.get('new_branch'))
4673 newbranch=opts.get('new_branch'))
4675
4674
4676 result = not result
4675 result = not result
4677
4676
4678 if opts.get('bookmark'):
4677 if opts.get('bookmark'):
4679 rb = other.listkeys('bookmarks')
4678 rb = other.listkeys('bookmarks')
4680 for b in opts['bookmark']:
4679 for b in opts['bookmark']:
4681 # explicit push overrides remote bookmark if any
4680 # explicit push overrides remote bookmark if any
4682 if b in repo._bookmarks:
4681 if b in repo._bookmarks:
4683 ui.status(_("exporting bookmark %s\n") % b)
4682 ui.status(_("exporting bookmark %s\n") % b)
4684 new = repo[b].hex()
4683 new = repo[b].hex()
4685 elif b in rb:
4684 elif b in rb:
4686 ui.status(_("deleting remote bookmark %s\n") % b)
4685 ui.status(_("deleting remote bookmark %s\n") % b)
4687 new = '' # delete
4686 new = '' # delete
4688 else:
4687 else:
4689 ui.warn(_('bookmark %s does not exist on the local '
4688 ui.warn(_('bookmark %s does not exist on the local '
4690 'or remote repository!\n') % b)
4689 'or remote repository!\n') % b)
4691 return 2
4690 return 2
4692 old = rb.get(b, '')
4691 old = rb.get(b, '')
4693 r = other.pushkey('bookmarks', b, old, new)
4692 r = other.pushkey('bookmarks', b, old, new)
4694 if not r:
4693 if not r:
4695 ui.warn(_('updating bookmark %s failed!\n') % b)
4694 ui.warn(_('updating bookmark %s failed!\n') % b)
4696 if not result:
4695 if not result:
4697 result = 2
4696 result = 2
4698
4697
4699 return result
4698 return result
4700
4699
4701 @command('recover', [])
4700 @command('recover', [])
4702 def recover(ui, repo):
4701 def recover(ui, repo):
4703 """roll back an interrupted transaction
4702 """roll back an interrupted transaction
4704
4703
4705 Recover from an interrupted commit or pull.
4704 Recover from an interrupted commit or pull.
4706
4705
4707 This command tries to fix the repository status after an
4706 This command tries to fix the repository status after an
4708 interrupted operation. It should only be necessary when Mercurial
4707 interrupted operation. It should only be necessary when Mercurial
4709 suggests it.
4708 suggests it.
4710
4709
4711 Returns 0 if successful, 1 if nothing to recover or verify fails.
4710 Returns 0 if successful, 1 if nothing to recover or verify fails.
4712 """
4711 """
4713 if repo.recover():
4712 if repo.recover():
4714 return hg.verify(repo)
4713 return hg.verify(repo)
4715 return 1
4714 return 1
4716
4715
4717 @command('^remove|rm',
4716 @command('^remove|rm',
4718 [('A', 'after', None, _('record delete for missing files')),
4717 [('A', 'after', None, _('record delete for missing files')),
4719 ('f', 'force', None,
4718 ('f', 'force', None,
4720 _('remove (and delete) file even if added or modified')),
4719 _('remove (and delete) file even if added or modified')),
4721 ] + walkopts,
4720 ] + walkopts,
4722 _('[OPTION]... FILE...'))
4721 _('[OPTION]... FILE...'))
4723 def remove(ui, repo, *pats, **opts):
4722 def remove(ui, repo, *pats, **opts):
4724 """remove the specified files on the next commit
4723 """remove the specified files on the next commit
4725
4724
4726 Schedule the indicated files for removal from the current branch.
4725 Schedule the indicated files for removal from the current branch.
4727
4726
4728 This command schedules the files to be removed at the next commit.
4727 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
4728 To undo a remove before that, see :hg:`revert`. To undo added
4730 files, see :hg:`forget`.
4729 files, see :hg:`forget`.
4731
4730
4732 .. container:: verbose
4731 .. container:: verbose
4733
4732
4734 -A/--after can be used to remove only files that have already
4733 -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
4734 been deleted, -f/--force can be used to force deletion, and -Af
4736 can be used to remove files from the next revision without
4735 can be used to remove files from the next revision without
4737 deleting them from the working directory.
4736 deleting them from the working directory.
4738
4737
4739 The following table details the behavior of remove for different
4738 The following table details the behavior of remove for different
4740 file states (columns) and option combinations (rows). The file
4739 file states (columns) and option combinations (rows). The file
4741 states are Added [A], Clean [C], Modified [M] and Missing [!]
4740 states are Added [A], Clean [C], Modified [M] and Missing [!]
4742 (as reported by :hg:`status`). The actions are Warn, Remove
4741 (as reported by :hg:`status`). The actions are Warn, Remove
4743 (from branch) and Delete (from disk):
4742 (from branch) and Delete (from disk):
4744
4743
4745 ======= == == == ==
4744 ======= == == == ==
4746 A C M !
4745 A C M !
4747 ======= == == == ==
4746 ======= == == == ==
4748 none W RD W R
4747 none W RD W R
4749 -f R RD RD R
4748 -f R RD RD R
4750 -A W W W R
4749 -A W W W R
4751 -Af R R R R
4750 -Af R R R R
4752 ======= == == == ==
4751 ======= == == == ==
4753
4752
4754 Note that remove never deletes files in Added [A] state from the
4753 Note that remove never deletes files in Added [A] state from the
4755 working directory, not even if option --force is specified.
4754 working directory, not even if option --force is specified.
4756
4755
4757 Returns 0 on success, 1 if any warnings encountered.
4756 Returns 0 on success, 1 if any warnings encountered.
4758 """
4757 """
4759
4758
4760 ret = 0
4759 ret = 0
4761 after, force = opts.get('after'), opts.get('force')
4760 after, force = opts.get('after'), opts.get('force')
4762 if not pats and not after:
4761 if not pats and not after:
4763 raise util.Abort(_('no files specified'))
4762 raise util.Abort(_('no files specified'))
4764
4763
4765 m = scmutil.match(repo[None], pats, opts)
4764 m = scmutil.match(repo[None], pats, opts)
4766 s = repo.status(match=m, clean=True)
4765 s = repo.status(match=m, clean=True)
4767 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4766 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4768
4767
4769 # warn about failure to delete explicit files/dirs
4768 # warn about failure to delete explicit files/dirs
4770 wctx = repo[None]
4769 wctx = repo[None]
4771 for f in m.files():
4770 for f in m.files():
4772 if f in repo.dirstate or f in wctx.dirs():
4771 if f in repo.dirstate or f in wctx.dirs():
4773 continue
4772 continue
4774 if os.path.exists(m.rel(f)):
4773 if os.path.exists(m.rel(f)):
4775 if os.path.isdir(m.rel(f)):
4774 if os.path.isdir(m.rel(f)):
4776 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4775 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
4777 else:
4776 else:
4778 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4777 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4779 # missing files will generate a warning elsewhere
4778 # missing files will generate a warning elsewhere
4780 ret = 1
4779 ret = 1
4781
4780
4782 if force:
4781 if force:
4783 list = modified + deleted + clean + added
4782 list = modified + deleted + clean + added
4784 elif after:
4783 elif after:
4785 list = deleted
4784 list = deleted
4786 for f in modified + added + clean:
4785 for f in modified + added + clean:
4787 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4786 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
4788 ret = 1
4787 ret = 1
4789 else:
4788 else:
4790 list = deleted + clean
4789 list = deleted + clean
4791 for f in modified:
4790 for f in modified:
4792 ui.warn(_('not removing %s: file is modified (use -f'
4791 ui.warn(_('not removing %s: file is modified (use -f'
4793 ' to force removal)\n') % m.rel(f))
4792 ' to force removal)\n') % m.rel(f))
4794 ret = 1
4793 ret = 1
4795 for f in added:
4794 for f in added:
4796 ui.warn(_('not removing %s: file has been marked for add'
4795 ui.warn(_('not removing %s: file has been marked for add'
4797 ' (use forget to undo)\n') % m.rel(f))
4796 ' (use forget to undo)\n') % m.rel(f))
4798 ret = 1
4797 ret = 1
4799
4798
4800 for f in sorted(list):
4799 for f in sorted(list):
4801 if ui.verbose or not m.exact(f):
4800 if ui.verbose or not m.exact(f):
4802 ui.status(_('removing %s\n') % m.rel(f))
4801 ui.status(_('removing %s\n') % m.rel(f))
4803
4802
4804 wlock = repo.wlock()
4803 wlock = repo.wlock()
4805 try:
4804 try:
4806 if not after:
4805 if not after:
4807 for f in list:
4806 for f in list:
4808 if f in added:
4807 if f in added:
4809 continue # we never unlink added files on remove
4808 continue # we never unlink added files on remove
4810 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4809 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
4811 repo[None].forget(list)
4810 repo[None].forget(list)
4812 finally:
4811 finally:
4813 wlock.release()
4812 wlock.release()
4814
4813
4815 return ret
4814 return ret
4816
4815
4817 @command('rename|move|mv',
4816 @command('rename|move|mv',
4818 [('A', 'after', None, _('record a rename that has already occurred')),
4817 [('A', 'after', None, _('record a rename that has already occurred')),
4819 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4818 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4820 ] + walkopts + dryrunopts,
4819 ] + walkopts + dryrunopts,
4821 _('[OPTION]... SOURCE... DEST'))
4820 _('[OPTION]... SOURCE... DEST'))
4822 def rename(ui, repo, *pats, **opts):
4821 def rename(ui, repo, *pats, **opts):
4823 """rename files; equivalent of copy + remove
4822 """rename files; equivalent of copy + remove
4824
4823
4825 Mark dest as copies of sources; mark sources for deletion. If dest
4824 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
4825 is a directory, copies are put in that directory. If dest is a
4827 file, there can only be one source.
4826 file, there can only be one source.
4828
4827
4829 By default, this command copies the contents of files as they
4828 By default, this command copies the contents of files as they
4830 exist in the working directory. If invoked with -A/--after, the
4829 exist in the working directory. If invoked with -A/--after, the
4831 operation is recorded, but no copying is performed.
4830 operation is recorded, but no copying is performed.
4832
4831
4833 This command takes effect at the next commit. To undo a rename
4832 This command takes effect at the next commit. To undo a rename
4834 before that, see :hg:`revert`.
4833 before that, see :hg:`revert`.
4835
4834
4836 Returns 0 on success, 1 if errors are encountered.
4835 Returns 0 on success, 1 if errors are encountered.
4837 """
4836 """
4838 wlock = repo.wlock(False)
4837 wlock = repo.wlock(False)
4839 try:
4838 try:
4840 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4839 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4841 finally:
4840 finally:
4842 wlock.release()
4841 wlock.release()
4843
4842
4844 @command('resolve',
4843 @command('resolve',
4845 [('a', 'all', None, _('select all unresolved files')),
4844 [('a', 'all', None, _('select all unresolved files')),
4846 ('l', 'list', None, _('list state of files needing merge')),
4845 ('l', 'list', None, _('list state of files needing merge')),
4847 ('m', 'mark', None, _('mark files as resolved')),
4846 ('m', 'mark', None, _('mark files as resolved')),
4848 ('u', 'unmark', None, _('mark files as unresolved')),
4847 ('u', 'unmark', None, _('mark files as unresolved')),
4849 ('n', 'no-status', None, _('hide status prefix'))]
4848 ('n', 'no-status', None, _('hide status prefix'))]
4850 + mergetoolopts + walkopts,
4849 + mergetoolopts + walkopts,
4851 _('[OPTION]... [FILE]...'))
4850 _('[OPTION]... [FILE]...'))
4852 def resolve(ui, repo, *pats, **opts):
4851 def resolve(ui, repo, *pats, **opts):
4853 """redo merges or set/view the merge status of files
4852 """redo merges or set/view the merge status of files
4854
4853
4855 Merges with unresolved conflicts are often the result of
4854 Merges with unresolved conflicts are often the result of
4856 non-interactive merging using the ``internal:merge`` configuration
4855 non-interactive merging using the ``internal:merge`` configuration
4857 setting, or a command-line merge tool like ``diff3``. The resolve
4856 setting, or a command-line merge tool like ``diff3``. The resolve
4858 command is used to manage the files involved in a merge, after
4857 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
4858 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4860 working directory must have two parents). See :hg:`help
4859 working directory must have two parents). See :hg:`help
4861 merge-tools` for information on configuring merge tools.
4860 merge-tools` for information on configuring merge tools.
4862
4861
4863 The resolve command can be used in the following ways:
4862 The resolve command can be used in the following ways:
4864
4863
4865 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4864 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4866 files, discarding any previous merge attempts. Re-merging is not
4865 files, discarding any previous merge attempts. Re-merging is not
4867 performed for files already marked as resolved. Use ``--all/-a``
4866 performed for files already marked as resolved. Use ``--all/-a``
4868 to select all unresolved files. ``--tool`` can be used to specify
4867 to select all unresolved files. ``--tool`` can be used to specify
4869 the merge tool used for the given files. It overrides the HGMERGE
4868 the merge tool used for the given files. It overrides the HGMERGE
4870 environment variable and your configuration files. Previous file
4869 environment variable and your configuration files. Previous file
4871 contents are saved with a ``.orig`` suffix.
4870 contents are saved with a ``.orig`` suffix.
4872
4871
4873 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4872 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4874 (e.g. after having manually fixed-up the files). The default is
4873 (e.g. after having manually fixed-up the files). The default is
4875 to mark all unresolved files.
4874 to mark all unresolved files.
4876
4875
4877 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4876 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4878 default is to mark all resolved files.
4877 default is to mark all resolved files.
4879
4878
4880 - :hg:`resolve -l`: list files which had or still have conflicts.
4879 - :hg:`resolve -l`: list files which had or still have conflicts.
4881 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4880 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4882
4881
4883 Note that Mercurial will not let you commit files with unresolved
4882 Note that Mercurial will not let you commit files with unresolved
4884 merge conflicts. You must use :hg:`resolve -m ...` before you can
4883 merge conflicts. You must use :hg:`resolve -m ...` before you can
4885 commit after a conflicting merge.
4884 commit after a conflicting merge.
4886
4885
4887 Returns 0 on success, 1 if any files fail a resolve attempt.
4886 Returns 0 on success, 1 if any files fail a resolve attempt.
4888 """
4887 """
4889
4888
4890 all, mark, unmark, show, nostatus = \
4889 all, mark, unmark, show, nostatus = \
4891 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4890 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4892
4891
4893 if (show and (mark or unmark)) or (mark and unmark):
4892 if (show and (mark or unmark)) or (mark and unmark):
4894 raise util.Abort(_("too many options specified"))
4893 raise util.Abort(_("too many options specified"))
4895 if pats and all:
4894 if pats and all:
4896 raise util.Abort(_("can't specify --all and patterns"))
4895 raise util.Abort(_("can't specify --all and patterns"))
4897 if not (all or pats or show or mark or unmark):
4896 if not (all or pats or show or mark or unmark):
4898 raise util.Abort(_('no files or directories specified; '
4897 raise util.Abort(_('no files or directories specified; '
4899 'use --all to remerge all files'))
4898 'use --all to remerge all files'))
4900
4899
4901 ms = mergemod.mergestate(repo)
4900 ms = mergemod.mergestate(repo)
4902 m = scmutil.match(repo[None], pats, opts)
4901 m = scmutil.match(repo[None], pats, opts)
4903 ret = 0
4902 ret = 0
4904
4903
4905 for f in ms:
4904 for f in ms:
4906 if m(f):
4905 if m(f):
4907 if show:
4906 if show:
4908 if nostatus:
4907 if nostatus:
4909 ui.write("%s\n" % f)
4908 ui.write("%s\n" % f)
4910 else:
4909 else:
4911 ui.write("%s %s\n" % (ms[f].upper(), f),
4910 ui.write("%s %s\n" % (ms[f].upper(), f),
4912 label='resolve.' +
4911 label='resolve.' +
4913 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4912 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4914 elif mark:
4913 elif mark:
4915 ms.mark(f, "r")
4914 ms.mark(f, "r")
4916 elif unmark:
4915 elif unmark:
4917 ms.mark(f, "u")
4916 ms.mark(f, "u")
4918 else:
4917 else:
4919 wctx = repo[None]
4918 wctx = repo[None]
4920 mctx = wctx.parents()[-1]
4919 mctx = wctx.parents()[-1]
4921
4920
4922 # backup pre-resolve (merge uses .orig for its own purposes)
4921 # backup pre-resolve (merge uses .orig for its own purposes)
4923 a = repo.wjoin(f)
4922 a = repo.wjoin(f)
4924 util.copyfile(a, a + ".resolve")
4923 util.copyfile(a, a + ".resolve")
4925
4924
4926 try:
4925 try:
4927 # resolve file
4926 # resolve file
4928 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4927 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4929 if ms.resolve(f, wctx, mctx):
4928 if ms.resolve(f, wctx, mctx):
4930 ret = 1
4929 ret = 1
4931 finally:
4930 finally:
4932 ui.setconfig('ui', 'forcemerge', '')
4931 ui.setconfig('ui', 'forcemerge', '')
4933 ms.commit()
4932 ms.commit()
4934
4933
4935 # replace filemerge's .orig file with our resolve file
4934 # replace filemerge's .orig file with our resolve file
4936 util.rename(a + ".resolve", a + ".orig")
4935 util.rename(a + ".resolve", a + ".orig")
4937
4936
4938 ms.commit()
4937 ms.commit()
4939 return ret
4938 return ret
4940
4939
4941 @command('revert',
4940 @command('revert',
4942 [('a', 'all', None, _('revert all changes when no arguments given')),
4941 [('a', 'all', None, _('revert all changes when no arguments given')),
4943 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4942 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4944 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4943 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4945 ('C', 'no-backup', None, _('do not save backup copies of files')),
4944 ('C', 'no-backup', None, _('do not save backup copies of files')),
4946 ] + walkopts + dryrunopts,
4945 ] + walkopts + dryrunopts,
4947 _('[OPTION]... [-r REV] [NAME]...'))
4946 _('[OPTION]... [-r REV] [NAME]...'))
4948 def revert(ui, repo, *pats, **opts):
4947 def revert(ui, repo, *pats, **opts):
4949 """restore files to their checkout state
4948 """restore files to their checkout state
4950
4949
4951 .. note::
4950 .. note::
4952 To check out earlier revisions, you should use :hg:`update REV`.
4951 To check out earlier revisions, you should use :hg:`update REV`.
4953 To cancel an uncommitted merge (and lose your changes),
4952 To cancel an uncommitted merge (and lose your changes),
4954 use :hg:`update --clean .`.
4953 use :hg:`update --clean .`.
4955
4954
4956 With no revision specified, revert the specified files or directories
4955 With no revision specified, revert the specified files or directories
4957 to the contents they had in the parent of the working directory.
4956 to the contents they had in the parent of the working directory.
4958 This restores the contents of files to an unmodified
4957 This restores the contents of files to an unmodified
4959 state and unschedules adds, removes, copies, and renames. If the
4958 state and unschedules adds, removes, copies, and renames. If the
4960 working directory has two parents, you must explicitly specify a
4959 working directory has two parents, you must explicitly specify a
4961 revision.
4960 revision.
4962
4961
4963 Using the -r/--rev or -d/--date options, revert the given files or
4962 Using the -r/--rev or -d/--date options, revert the given files or
4964 directories to their states as of a specific revision. Because
4963 directories to their states as of a specific revision. Because
4965 revert does not change the working directory parents, this will
4964 revert does not change the working directory parents, this will
4966 cause these files to appear modified. This can be helpful to "back
4965 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
4966 out" some or all of an earlier change. See :hg:`backout` for a
4968 related method.
4967 related method.
4969
4968
4970 Modified files are saved with a .orig suffix before reverting.
4969 Modified files are saved with a .orig suffix before reverting.
4971 To disable these backups, use --no-backup.
4970 To disable these backups, use --no-backup.
4972
4971
4973 See :hg:`help dates` for a list of formats valid for -d/--date.
4972 See :hg:`help dates` for a list of formats valid for -d/--date.
4974
4973
4975 Returns 0 on success.
4974 Returns 0 on success.
4976 """
4975 """
4977
4976
4978 if opts.get("date"):
4977 if opts.get("date"):
4979 if opts.get("rev"):
4978 if opts.get("rev"):
4980 raise util.Abort(_("you can't specify a revision and a date"))
4979 raise util.Abort(_("you can't specify a revision and a date"))
4981 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4980 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4982
4981
4983 parent, p2 = repo.dirstate.parents()
4982 parent, p2 = repo.dirstate.parents()
4984 if not opts.get('rev') and p2 != nullid:
4983 if not opts.get('rev') and p2 != nullid:
4985 # revert after merge is a trap for new users (issue2915)
4984 # revert after merge is a trap for new users (issue2915)
4986 raise util.Abort(_('uncommitted merge with no revision specified'),
4985 raise util.Abort(_('uncommitted merge with no revision specified'),
4987 hint=_('use "hg update" or see "hg help revert"'))
4986 hint=_('use "hg update" or see "hg help revert"'))
4988
4987
4989 ctx = scmutil.revsingle(repo, opts.get('rev'))
4988 ctx = scmutil.revsingle(repo, opts.get('rev'))
4990
4989
4991 if not pats and not opts.get('all'):
4990 if not pats and not opts.get('all'):
4992 msg = _("no files or directories specified")
4991 msg = _("no files or directories specified")
4993 if p2 != nullid:
4992 if p2 != nullid:
4994 hint = _("uncommitted merge, use --all to discard all changes,"
4993 hint = _("uncommitted merge, use --all to discard all changes,"
4995 " or 'hg update -C .' to abort the merge")
4994 " or 'hg update -C .' to abort the merge")
4996 raise util.Abort(msg, hint=hint)
4995 raise util.Abort(msg, hint=hint)
4997 dirty = util.any(repo.status())
4996 dirty = util.any(repo.status())
4998 node = ctx.node()
4997 node = ctx.node()
4999 if node != parent:
4998 if node != parent:
5000 if dirty:
4999 if dirty:
5001 hint = _("uncommitted changes, use --all to discard all"
5000 hint = _("uncommitted changes, use --all to discard all"
5002 " changes, or 'hg update %s' to update") % ctx.rev()
5001 " changes, or 'hg update %s' to update") % ctx.rev()
5003 else:
5002 else:
5004 hint = _("use --all to revert all files,"
5003 hint = _("use --all to revert all files,"
5005 " or 'hg update %s' to update") % ctx.rev()
5004 " or 'hg update %s' to update") % ctx.rev()
5006 elif dirty:
5005 elif dirty:
5007 hint = _("uncommitted changes, use --all to discard all changes")
5006 hint = _("uncommitted changes, use --all to discard all changes")
5008 else:
5007 else:
5009 hint = _("use --all to revert all files")
5008 hint = _("use --all to revert all files")
5010 raise util.Abort(msg, hint=hint)
5009 raise util.Abort(msg, hint=hint)
5011
5010
5012 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5011 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5013
5012
5014 @command('rollback', dryrunopts +
5013 @command('rollback', dryrunopts +
5015 [('f', 'force', False, _('ignore safety measures'))])
5014 [('f', 'force', False, _('ignore safety measures'))])
5016 def rollback(ui, repo, **opts):
5015 def rollback(ui, repo, **opts):
5017 """roll back the last transaction (dangerous)
5016 """roll back the last transaction (dangerous)
5018
5017
5019 This command should be used with care. There is only one level of
5018 This command should be used with care. There is only one level of
5020 rollback, and there is no way to undo a rollback. It will also
5019 rollback, and there is no way to undo a rollback. It will also
5021 restore the dirstate at the time of the last transaction, losing
5020 restore the dirstate at the time of the last transaction, losing
5022 any dirstate changes since that time. This command does not alter
5021 any dirstate changes since that time. This command does not alter
5023 the working directory.
5022 the working directory.
5024
5023
5025 Transactions are used to encapsulate the effects of all commands
5024 Transactions are used to encapsulate the effects of all commands
5026 that create new changesets or propagate existing changesets into a
5025 that create new changesets or propagate existing changesets into a
5027 repository.
5026 repository.
5028
5027
5029 .. container:: verbose
5028 .. container:: verbose
5030
5029
5031 For example, the following commands are transactional, and their
5030 For example, the following commands are transactional, and their
5032 effects can be rolled back:
5031 effects can be rolled back:
5033
5032
5034 - commit
5033 - commit
5035 - import
5034 - import
5036 - pull
5035 - pull
5037 - push (with this repository as the destination)
5036 - push (with this repository as the destination)
5038 - unbundle
5037 - unbundle
5039
5038
5040 To avoid permanent data loss, rollback will refuse to rollback a
5039 To avoid permanent data loss, rollback will refuse to rollback a
5041 commit transaction if it isn't checked out. Use --force to
5040 commit transaction if it isn't checked out. Use --force to
5042 override this protection.
5041 override this protection.
5043
5042
5044 This command is not intended for use on public repositories. Once
5043 This command is not intended for use on public repositories. Once
5045 changes are visible for pull by other users, rolling a transaction
5044 changes are visible for pull by other users, rolling a transaction
5046 back locally is ineffective (someone else may already have pulled
5045 back locally is ineffective (someone else may already have pulled
5047 the changes). Furthermore, a race is possible with readers of the
5046 the changes). Furthermore, a race is possible with readers of the
5048 repository; for example an in-progress pull from the repository
5047 repository; for example an in-progress pull from the repository
5049 may fail if a rollback is performed.
5048 may fail if a rollback is performed.
5050
5049
5051 Returns 0 on success, 1 if no rollback data is available.
5050 Returns 0 on success, 1 if no rollback data is available.
5052 """
5051 """
5053 return repo.rollback(dryrun=opts.get('dry_run'),
5052 return repo.rollback(dryrun=opts.get('dry_run'),
5054 force=opts.get('force'))
5053 force=opts.get('force'))
5055
5054
5056 @command('root', [])
5055 @command('root', [])
5057 def root(ui, repo):
5056 def root(ui, repo):
5058 """print the root (top) of the current working directory
5057 """print the root (top) of the current working directory
5059
5058
5060 Print the root directory of the current repository.
5059 Print the root directory of the current repository.
5061
5060
5062 Returns 0 on success.
5061 Returns 0 on success.
5063 """
5062 """
5064 ui.write(repo.root + "\n")
5063 ui.write(repo.root + "\n")
5065
5064
5066 @command('^serve',
5065 @command('^serve',
5067 [('A', 'accesslog', '', _('name of access log file to write to'),
5066 [('A', 'accesslog', '', _('name of access log file to write to'),
5068 _('FILE')),
5067 _('FILE')),
5069 ('d', 'daemon', None, _('run server in background')),
5068 ('d', 'daemon', None, _('run server in background')),
5070 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5069 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5071 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5070 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5072 # use string type, then we can check if something was passed
5071 # use string type, then we can check if something was passed
5073 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5072 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5074 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5073 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5075 _('ADDR')),
5074 _('ADDR')),
5076 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5075 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5077 _('PREFIX')),
5076 _('PREFIX')),
5078 ('n', 'name', '',
5077 ('n', 'name', '',
5079 _('name to show in web pages (default: working directory)'), _('NAME')),
5078 _('name to show in web pages (default: working directory)'), _('NAME')),
5080 ('', 'web-conf', '',
5079 ('', 'web-conf', '',
5081 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5080 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5082 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5081 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5083 _('FILE')),
5082 _('FILE')),
5084 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5083 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5085 ('', 'stdio', None, _('for remote clients')),
5084 ('', 'stdio', None, _('for remote clients')),
5086 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5085 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5087 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5086 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5088 ('', 'style', '', _('template style to use'), _('STYLE')),
5087 ('', 'style', '', _('template style to use'), _('STYLE')),
5089 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5088 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5090 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5089 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5091 _('[OPTION]...'))
5090 _('[OPTION]...'))
5092 def serve(ui, repo, **opts):
5091 def serve(ui, repo, **opts):
5093 """start stand-alone webserver
5092 """start stand-alone webserver
5094
5093
5095 Start a local HTTP repository browser and pull server. You can use
5094 Start a local HTTP repository browser and pull server. You can use
5096 this for ad-hoc sharing and browsing of repositories. It is
5095 this for ad-hoc sharing and browsing of repositories. It is
5097 recommended to use a real web server to serve a repository for
5096 recommended to use a real web server to serve a repository for
5098 longer periods of time.
5097 longer periods of time.
5099
5098
5100 Please note that the server does not implement access control.
5099 Please note that the server does not implement access control.
5101 This means that, by default, anybody can read from the server and
5100 This means that, by default, anybody can read from the server and
5102 nobody can write to it by default. Set the ``web.allow_push``
5101 nobody can write to it by default. Set the ``web.allow_push``
5103 option to ``*`` to allow everybody to push to the server. You
5102 option to ``*`` to allow everybody to push to the server. You
5104 should use a real web server if you need to authenticate users.
5103 should use a real web server if you need to authenticate users.
5105
5104
5106 By default, the server logs accesses to stdout and errors to
5105 By default, the server logs accesses to stdout and errors to
5107 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5106 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5108 files.
5107 files.
5109
5108
5110 To have the server choose a free port number to listen on, specify
5109 To have the server choose a free port number to listen on, specify
5111 a port number of 0; in this case, the server will print the port
5110 a port number of 0; in this case, the server will print the port
5112 number it uses.
5111 number it uses.
5113
5112
5114 Returns 0 on success.
5113 Returns 0 on success.
5115 """
5114 """
5116
5115
5117 if opts["stdio"] and opts["cmdserver"]:
5116 if opts["stdio"] and opts["cmdserver"]:
5118 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5117 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5119
5118
5120 def checkrepo():
5119 def checkrepo():
5121 if repo is None:
5120 if repo is None:
5122 raise error.RepoError(_("there is no Mercurial repository here"
5121 raise error.RepoError(_("there is no Mercurial repository here"
5123 " (.hg not found)"))
5122 " (.hg not found)"))
5124
5123
5125 if opts["stdio"]:
5124 if opts["stdio"]:
5126 checkrepo()
5125 checkrepo()
5127 s = sshserver.sshserver(ui, repo)
5126 s = sshserver.sshserver(ui, repo)
5128 s.serve_forever()
5127 s.serve_forever()
5129
5128
5130 if opts["cmdserver"]:
5129 if opts["cmdserver"]:
5131 checkrepo()
5130 checkrepo()
5132 s = commandserver.server(ui, repo, opts["cmdserver"])
5131 s = commandserver.server(ui, repo, opts["cmdserver"])
5133 return s.serve()
5132 return s.serve()
5134
5133
5135 # this way we can check if something was given in the command-line
5134 # this way we can check if something was given in the command-line
5136 if opts.get('port'):
5135 if opts.get('port'):
5137 opts['port'] = util.getport(opts.get('port'))
5136 opts['port'] = util.getport(opts.get('port'))
5138
5137
5139 baseui = repo and repo.baseui or ui
5138 baseui = repo and repo.baseui or ui
5140 optlist = ("name templates style address port prefix ipv6"
5139 optlist = ("name templates style address port prefix ipv6"
5141 " accesslog errorlog certificate encoding")
5140 " accesslog errorlog certificate encoding")
5142 for o in optlist.split():
5141 for o in optlist.split():
5143 val = opts.get(o, '')
5142 val = opts.get(o, '')
5144 if val in (None, ''): # should check against default options instead
5143 if val in (None, ''): # should check against default options instead
5145 continue
5144 continue
5146 baseui.setconfig("web", o, val)
5145 baseui.setconfig("web", o, val)
5147 if repo and repo.ui != baseui:
5146 if repo and repo.ui != baseui:
5148 repo.ui.setconfig("web", o, val)
5147 repo.ui.setconfig("web", o, val)
5149
5148
5150 o = opts.get('web_conf') or opts.get('webdir_conf')
5149 o = opts.get('web_conf') or opts.get('webdir_conf')
5151 if not o:
5150 if not o:
5152 if not repo:
5151 if not repo:
5153 raise error.RepoError(_("there is no Mercurial repository"
5152 raise error.RepoError(_("there is no Mercurial repository"
5154 " here (.hg not found)"))
5153 " here (.hg not found)"))
5155 o = repo
5154 o = repo
5156
5155
5157 app = hgweb.hgweb(o, baseui=baseui)
5156 app = hgweb.hgweb(o, baseui=baseui)
5158
5157
5159 class service(object):
5158 class service(object):
5160 def init(self):
5159 def init(self):
5161 util.setsignalhandler()
5160 util.setsignalhandler()
5162 self.httpd = hgweb.server.create_server(ui, app)
5161 self.httpd = hgweb.server.create_server(ui, app)
5163
5162
5164 if opts['port'] and not ui.verbose:
5163 if opts['port'] and not ui.verbose:
5165 return
5164 return
5166
5165
5167 if self.httpd.prefix:
5166 if self.httpd.prefix:
5168 prefix = self.httpd.prefix.strip('/') + '/'
5167 prefix = self.httpd.prefix.strip('/') + '/'
5169 else:
5168 else:
5170 prefix = ''
5169 prefix = ''
5171
5170
5172 port = ':%d' % self.httpd.port
5171 port = ':%d' % self.httpd.port
5173 if port == ':80':
5172 if port == ':80':
5174 port = ''
5173 port = ''
5175
5174
5176 bindaddr = self.httpd.addr
5175 bindaddr = self.httpd.addr
5177 if bindaddr == '0.0.0.0':
5176 if bindaddr == '0.0.0.0':
5178 bindaddr = '*'
5177 bindaddr = '*'
5179 elif ':' in bindaddr: # IPv6
5178 elif ':' in bindaddr: # IPv6
5180 bindaddr = '[%s]' % bindaddr
5179 bindaddr = '[%s]' % bindaddr
5181
5180
5182 fqaddr = self.httpd.fqaddr
5181 fqaddr = self.httpd.fqaddr
5183 if ':' in fqaddr:
5182 if ':' in fqaddr:
5184 fqaddr = '[%s]' % fqaddr
5183 fqaddr = '[%s]' % fqaddr
5185 if opts['port']:
5184 if opts['port']:
5186 write = ui.status
5185 write = ui.status
5187 else:
5186 else:
5188 write = ui.write
5187 write = ui.write
5189 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5188 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5190 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5189 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5191
5190
5192 def run(self):
5191 def run(self):
5193 self.httpd.serve_forever()
5192 self.httpd.serve_forever()
5194
5193
5195 service = service()
5194 service = service()
5196
5195
5197 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5196 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5198
5197
5199 @command('showconfig|debugconfig',
5198 @command('showconfig|debugconfig',
5200 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5199 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5201 _('[-u] [NAME]...'))
5200 _('[-u] [NAME]...'))
5202 def showconfig(ui, repo, *values, **opts):
5201 def showconfig(ui, repo, *values, **opts):
5203 """show combined config settings from all hgrc files
5202 """show combined config settings from all hgrc files
5204
5203
5205 With no arguments, print names and values of all config items.
5204 With no arguments, print names and values of all config items.
5206
5205
5207 With one argument of the form section.name, print just the value
5206 With one argument of the form section.name, print just the value
5208 of that config item.
5207 of that config item.
5209
5208
5210 With multiple arguments, print names and values of all config
5209 With multiple arguments, print names and values of all config
5211 items with matching section names.
5210 items with matching section names.
5212
5211
5213 With --debug, the source (filename and line number) is printed
5212 With --debug, the source (filename and line number) is printed
5214 for each config item.
5213 for each config item.
5215
5214
5216 Returns 0 on success.
5215 Returns 0 on success.
5217 """
5216 """
5218
5217
5219 for f in scmutil.rcpath():
5218 for f in scmutil.rcpath():
5220 ui.debug('read config from: %s\n' % f)
5219 ui.debug('read config from: %s\n' % f)
5221 untrusted = bool(opts.get('untrusted'))
5220 untrusted = bool(opts.get('untrusted'))
5222 if values:
5221 if values:
5223 sections = [v for v in values if '.' not in v]
5222 sections = [v for v in values if '.' not in v]
5224 items = [v for v in values if '.' in v]
5223 items = [v for v in values if '.' in v]
5225 if len(items) > 1 or items and sections:
5224 if len(items) > 1 or items and sections:
5226 raise util.Abort(_('only one config item permitted'))
5225 raise util.Abort(_('only one config item permitted'))
5227 for section, name, value in ui.walkconfig(untrusted=untrusted):
5226 for section, name, value in ui.walkconfig(untrusted=untrusted):
5228 value = str(value).replace('\n', '\\n')
5227 value = str(value).replace('\n', '\\n')
5229 sectname = section + '.' + name
5228 sectname = section + '.' + name
5230 if values:
5229 if values:
5231 for v in values:
5230 for v in values:
5232 if v == section:
5231 if v == section:
5233 ui.debug('%s: ' %
5232 ui.debug('%s: ' %
5234 ui.configsource(section, name, untrusted))
5233 ui.configsource(section, name, untrusted))
5235 ui.write('%s=%s\n' % (sectname, value))
5234 ui.write('%s=%s\n' % (sectname, value))
5236 elif v == sectname:
5235 elif v == sectname:
5237 ui.debug('%s: ' %
5236 ui.debug('%s: ' %
5238 ui.configsource(section, name, untrusted))
5237 ui.configsource(section, name, untrusted))
5239 ui.write(value, '\n')
5238 ui.write(value, '\n')
5240 else:
5239 else:
5241 ui.debug('%s: ' %
5240 ui.debug('%s: ' %
5242 ui.configsource(section, name, untrusted))
5241 ui.configsource(section, name, untrusted))
5243 ui.write('%s=%s\n' % (sectname, value))
5242 ui.write('%s=%s\n' % (sectname, value))
5244
5243
5245 @command('^status|st',
5244 @command('^status|st',
5246 [('A', 'all', None, _('show status of all files')),
5245 [('A', 'all', None, _('show status of all files')),
5247 ('m', 'modified', None, _('show only modified files')),
5246 ('m', 'modified', None, _('show only modified files')),
5248 ('a', 'added', None, _('show only added files')),
5247 ('a', 'added', None, _('show only added files')),
5249 ('r', 'removed', None, _('show only removed files')),
5248 ('r', 'removed', None, _('show only removed files')),
5250 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5249 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5251 ('c', 'clean', None, _('show only files without changes')),
5250 ('c', 'clean', None, _('show only files without changes')),
5252 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5251 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5253 ('i', 'ignored', None, _('show only ignored files')),
5252 ('i', 'ignored', None, _('show only ignored files')),
5254 ('n', 'no-status', None, _('hide status prefix')),
5253 ('n', 'no-status', None, _('hide status prefix')),
5255 ('C', 'copies', None, _('show source of copied files')),
5254 ('C', 'copies', None, _('show source of copied files')),
5256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5255 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5257 ('', 'rev', [], _('show difference from revision'), _('REV')),
5256 ('', 'rev', [], _('show difference from revision'), _('REV')),
5258 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5257 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5259 ] + walkopts + subrepoopts,
5258 ] + walkopts + subrepoopts,
5260 _('[OPTION]... [FILE]...'))
5259 _('[OPTION]... [FILE]...'))
5261 def status(ui, repo, *pats, **opts):
5260 def status(ui, repo, *pats, **opts):
5262 """show changed files in the working directory
5261 """show changed files in the working directory
5263
5262
5264 Show status of files in the repository. If names are given, only
5263 Show status of files in the repository. If names are given, only
5265 files that match are shown. Files that are clean or ignored or
5264 files that match are shown. Files that are clean or ignored or
5266 the source of a copy/move operation, are not listed unless
5265 the source of a copy/move operation, are not listed unless
5267 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5266 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5268 Unless options described with "show only ..." are given, the
5267 Unless options described with "show only ..." are given, the
5269 options -mardu are used.
5268 options -mardu are used.
5270
5269
5271 Option -q/--quiet hides untracked (unknown and ignored) files
5270 Option -q/--quiet hides untracked (unknown and ignored) files
5272 unless explicitly requested with -u/--unknown or -i/--ignored.
5271 unless explicitly requested with -u/--unknown or -i/--ignored.
5273
5272
5274 .. note::
5273 .. note::
5275 status may appear to disagree with diff if permissions have
5274 status may appear to disagree with diff if permissions have
5276 changed or a merge has occurred. The standard diff format does
5275 changed or a merge has occurred. The standard diff format does
5277 not report permission changes and diff only reports changes
5276 not report permission changes and diff only reports changes
5278 relative to one merge parent.
5277 relative to one merge parent.
5279
5278
5280 If one revision is given, it is used as the base revision.
5279 If one revision is given, it is used as the base revision.
5281 If two revisions are given, the differences between them are
5280 If two revisions are given, the differences between them are
5282 shown. The --change option can also be used as a shortcut to list
5281 shown. The --change option can also be used as a shortcut to list
5283 the changed files of a revision from its first parent.
5282 the changed files of a revision from its first parent.
5284
5283
5285 The codes used to show the status of files are::
5284 The codes used to show the status of files are::
5286
5285
5287 M = modified
5286 M = modified
5288 A = added
5287 A = added
5289 R = removed
5288 R = removed
5290 C = clean
5289 C = clean
5291 ! = missing (deleted by non-hg command, but still tracked)
5290 ! = missing (deleted by non-hg command, but still tracked)
5292 ? = not tracked
5291 ? = not tracked
5293 I = ignored
5292 I = ignored
5294 = origin of the previous file listed as A (added)
5293 = origin of the previous file listed as A (added)
5295
5294
5296 .. container:: verbose
5295 .. container:: verbose
5297
5296
5298 Examples:
5297 Examples:
5299
5298
5300 - show changes in the working directory relative to a
5299 - show changes in the working directory relative to a
5301 changeset::
5300 changeset::
5302
5301
5303 hg status --rev 9353
5302 hg status --rev 9353
5304
5303
5305 - show all changes including copies in an existing changeset::
5304 - show all changes including copies in an existing changeset::
5306
5305
5307 hg status --copies --change 9353
5306 hg status --copies --change 9353
5308
5307
5309 - get a NUL separated list of added files, suitable for xargs::
5308 - get a NUL separated list of added files, suitable for xargs::
5310
5309
5311 hg status -an0
5310 hg status -an0
5312
5311
5313 Returns 0 on success.
5312 Returns 0 on success.
5314 """
5313 """
5315
5314
5316 revs = opts.get('rev')
5315 revs = opts.get('rev')
5317 change = opts.get('change')
5316 change = opts.get('change')
5318
5317
5319 if revs and change:
5318 if revs and change:
5320 msg = _('cannot specify --rev and --change at the same time')
5319 msg = _('cannot specify --rev and --change at the same time')
5321 raise util.Abort(msg)
5320 raise util.Abort(msg)
5322 elif change:
5321 elif change:
5323 node2 = scmutil.revsingle(repo, change, None).node()
5322 node2 = scmutil.revsingle(repo, change, None).node()
5324 node1 = repo[node2].p1().node()
5323 node1 = repo[node2].p1().node()
5325 else:
5324 else:
5326 node1, node2 = scmutil.revpair(repo, revs)
5325 node1, node2 = scmutil.revpair(repo, revs)
5327
5326
5328 cwd = (pats and repo.getcwd()) or ''
5327 cwd = (pats and repo.getcwd()) or ''
5329 end = opts.get('print0') and '\0' or '\n'
5328 end = opts.get('print0') and '\0' or '\n'
5330 copy = {}
5329 copy = {}
5331 states = 'modified added removed deleted unknown ignored clean'.split()
5330 states = 'modified added removed deleted unknown ignored clean'.split()
5332 show = [k for k in states if opts.get(k)]
5331 show = [k for k in states if opts.get(k)]
5333 if opts.get('all'):
5332 if opts.get('all'):
5334 show += ui.quiet and (states[:4] + ['clean']) or states
5333 show += ui.quiet and (states[:4] + ['clean']) or states
5335 if not show:
5334 if not show:
5336 show = ui.quiet and states[:4] or states[:5]
5335 show = ui.quiet and states[:4] or states[:5]
5337
5336
5338 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5337 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5339 'ignored' in show, 'clean' in show, 'unknown' in show,
5338 'ignored' in show, 'clean' in show, 'unknown' in show,
5340 opts.get('subrepos'))
5339 opts.get('subrepos'))
5341 changestates = zip(states, 'MAR!?IC', stat)
5340 changestates = zip(states, 'MAR!?IC', stat)
5342
5341
5343 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5342 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5344 copy = copies.pathcopies(repo[node1], repo[node2])
5343 copy = copies.pathcopies(repo[node1], repo[node2])
5345
5344
5346 fm = ui.formatter('status', opts)
5345 fm = ui.formatter('status', opts)
5347 fmt = '%s' + end
5346 fmt = '%s' + end
5348 showchar = not opts.get('no_status')
5347 showchar = not opts.get('no_status')
5349
5348
5350 for state, char, files in changestates:
5349 for state, char, files in changestates:
5351 if state in show:
5350 if state in show:
5352 label = 'status.' + state
5351 label = 'status.' + state
5353 for f in files:
5352 for f in files:
5354 fm.startitem()
5353 fm.startitem()
5355 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5354 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5356 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5355 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5357 if f in copy:
5356 if f in copy:
5358 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5357 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5359 label='status.copied')
5358 label='status.copied')
5360 fm.end()
5359 fm.end()
5361
5360
5362 @command('^summary|sum',
5361 @command('^summary|sum',
5363 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5362 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5364 def summary(ui, repo, **opts):
5363 def summary(ui, repo, **opts):
5365 """summarize working directory state
5364 """summarize working directory state
5366
5365
5367 This generates a brief summary of the working directory state,
5366 This generates a brief summary of the working directory state,
5368 including parents, branch, commit status, and available updates.
5367 including parents, branch, commit status, and available updates.
5369
5368
5370 With the --remote option, this will check the default paths for
5369 With the --remote option, this will check the default paths for
5371 incoming and outgoing changes. This can be time-consuming.
5370 incoming and outgoing changes. This can be time-consuming.
5372
5371
5373 Returns 0 on success.
5372 Returns 0 on success.
5374 """
5373 """
5375
5374
5376 ctx = repo[None]
5375 ctx = repo[None]
5377 parents = ctx.parents()
5376 parents = ctx.parents()
5378 pnode = parents[0].node()
5377 pnode = parents[0].node()
5379 marks = []
5378 marks = []
5380
5379
5381 for p in parents:
5380 for p in parents:
5382 # label with log.changeset (instead of log.parent) since this
5381 # label with log.changeset (instead of log.parent) since this
5383 # shows a working directory parent *changeset*:
5382 # shows a working directory parent *changeset*:
5384 # i18n: column positioning for "hg summary"
5383 # i18n: column positioning for "hg summary"
5385 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5384 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5386 label='log.changeset changeset.%s' % p.phasestr())
5385 label='log.changeset changeset.%s' % p.phasestr())
5387 ui.write(' '.join(p.tags()), label='log.tag')
5386 ui.write(' '.join(p.tags()), label='log.tag')
5388 if p.bookmarks():
5387 if p.bookmarks():
5389 marks.extend(p.bookmarks())
5388 marks.extend(p.bookmarks())
5390 if p.rev() == -1:
5389 if p.rev() == -1:
5391 if not len(repo):
5390 if not len(repo):
5392 ui.write(_(' (empty repository)'))
5391 ui.write(_(' (empty repository)'))
5393 else:
5392 else:
5394 ui.write(_(' (no revision checked out)'))
5393 ui.write(_(' (no revision checked out)'))
5395 ui.write('\n')
5394 ui.write('\n')
5396 if p.description():
5395 if p.description():
5397 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5396 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5398 label='log.summary')
5397 label='log.summary')
5399
5398
5400 branch = ctx.branch()
5399 branch = ctx.branch()
5401 bheads = repo.branchheads(branch)
5400 bheads = repo.branchheads(branch)
5402 # i18n: column positioning for "hg summary"
5401 # i18n: column positioning for "hg summary"
5403 m = _('branch: %s\n') % branch
5402 m = _('branch: %s\n') % branch
5404 if branch != 'default':
5403 if branch != 'default':
5405 ui.write(m, label='log.branch')
5404 ui.write(m, label='log.branch')
5406 else:
5405 else:
5407 ui.status(m, label='log.branch')
5406 ui.status(m, label='log.branch')
5408
5407
5409 if marks:
5408 if marks:
5410 current = repo._bookmarkcurrent
5409 current = repo._bookmarkcurrent
5411 # i18n: column positioning for "hg summary"
5410 # i18n: column positioning for "hg summary"
5412 ui.write(_('bookmarks:'), label='log.bookmark')
5411 ui.write(_('bookmarks:'), label='log.bookmark')
5413 if current is not None:
5412 if current is not None:
5414 if current in marks:
5413 if current in marks:
5415 ui.write(' *' + current, label='bookmarks.current')
5414 ui.write(' *' + current, label='bookmarks.current')
5416 marks.remove(current)
5415 marks.remove(current)
5417 else:
5416 else:
5418 ui.write(' [%s]' % current, label='bookmarks.current')
5417 ui.write(' [%s]' % current, label='bookmarks.current')
5419 for m in marks:
5418 for m in marks:
5420 ui.write(' ' + m, label='log.bookmark')
5419 ui.write(' ' + m, label='log.bookmark')
5421 ui.write('\n', label='log.bookmark')
5420 ui.write('\n', label='log.bookmark')
5422
5421
5423 st = list(repo.status(unknown=True))[:6]
5422 st = list(repo.status(unknown=True))[:6]
5424
5423
5425 c = repo.dirstate.copies()
5424 c = repo.dirstate.copies()
5426 copied, renamed = [], []
5425 copied, renamed = [], []
5427 for d, s in c.iteritems():
5426 for d, s in c.iteritems():
5428 if s in st[2]:
5427 if s in st[2]:
5429 st[2].remove(s)
5428 st[2].remove(s)
5430 renamed.append(d)
5429 renamed.append(d)
5431 else:
5430 else:
5432 copied.append(d)
5431 copied.append(d)
5433 if d in st[1]:
5432 if d in st[1]:
5434 st[1].remove(d)
5433 st[1].remove(d)
5435 st.insert(3, renamed)
5434 st.insert(3, renamed)
5436 st.insert(4, copied)
5435 st.insert(4, copied)
5437
5436
5438 ms = mergemod.mergestate(repo)
5437 ms = mergemod.mergestate(repo)
5439 st.append([f for f in ms if ms[f] == 'u'])
5438 st.append([f for f in ms if ms[f] == 'u'])
5440
5439
5441 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5440 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5442 st.append(subs)
5441 st.append(subs)
5443
5442
5444 labels = [ui.label(_('%d modified'), 'status.modified'),
5443 labels = [ui.label(_('%d modified'), 'status.modified'),
5445 ui.label(_('%d added'), 'status.added'),
5444 ui.label(_('%d added'), 'status.added'),
5446 ui.label(_('%d removed'), 'status.removed'),
5445 ui.label(_('%d removed'), 'status.removed'),
5447 ui.label(_('%d renamed'), 'status.copied'),
5446 ui.label(_('%d renamed'), 'status.copied'),
5448 ui.label(_('%d copied'), 'status.copied'),
5447 ui.label(_('%d copied'), 'status.copied'),
5449 ui.label(_('%d deleted'), 'status.deleted'),
5448 ui.label(_('%d deleted'), 'status.deleted'),
5450 ui.label(_('%d unknown'), 'status.unknown'),
5449 ui.label(_('%d unknown'), 'status.unknown'),
5451 ui.label(_('%d ignored'), 'status.ignored'),
5450 ui.label(_('%d ignored'), 'status.ignored'),
5452 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5451 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5453 ui.label(_('%d subrepos'), 'status.modified')]
5452 ui.label(_('%d subrepos'), 'status.modified')]
5454 t = []
5453 t = []
5455 for s, l in zip(st, labels):
5454 for s, l in zip(st, labels):
5456 if s:
5455 if s:
5457 t.append(l % len(s))
5456 t.append(l % len(s))
5458
5457
5459 t = ', '.join(t)
5458 t = ', '.join(t)
5460 cleanworkdir = False
5459 cleanworkdir = False
5461
5460
5462 if len(parents) > 1:
5461 if len(parents) > 1:
5463 t += _(' (merge)')
5462 t += _(' (merge)')
5464 elif branch != parents[0].branch():
5463 elif branch != parents[0].branch():
5465 t += _(' (new branch)')
5464 t += _(' (new branch)')
5466 elif (parents[0].closesbranch() and
5465 elif (parents[0].closesbranch() and
5467 pnode in repo.branchheads(branch, closed=True)):
5466 pnode in repo.branchheads(branch, closed=True)):
5468 t += _(' (head closed)')
5467 t += _(' (head closed)')
5469 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5468 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5470 t += _(' (clean)')
5469 t += _(' (clean)')
5471 cleanworkdir = True
5470 cleanworkdir = True
5472 elif pnode not in bheads:
5471 elif pnode not in bheads:
5473 t += _(' (new branch head)')
5472 t += _(' (new branch head)')
5474
5473
5475 if cleanworkdir:
5474 if cleanworkdir:
5476 # i18n: column positioning for "hg summary"
5475 # i18n: column positioning for "hg summary"
5477 ui.status(_('commit: %s\n') % t.strip())
5476 ui.status(_('commit: %s\n') % t.strip())
5478 else:
5477 else:
5479 # i18n: column positioning for "hg summary"
5478 # i18n: column positioning for "hg summary"
5480 ui.write(_('commit: %s\n') % t.strip())
5479 ui.write(_('commit: %s\n') % t.strip())
5481
5480
5482 # all ancestors of branch heads - all ancestors of parent = new csets
5481 # all ancestors of branch heads - all ancestors of parent = new csets
5483 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5482 new = len(repo.changelog.findmissing([ctx.node() for ctx in parents],
5484 bheads))
5483 bheads))
5485
5484
5486 if new == 0:
5485 if new == 0:
5487 # i18n: column positioning for "hg summary"
5486 # i18n: column positioning for "hg summary"
5488 ui.status(_('update: (current)\n'))
5487 ui.status(_('update: (current)\n'))
5489 elif pnode not in bheads:
5488 elif pnode not in bheads:
5490 # i18n: column positioning for "hg summary"
5489 # i18n: column positioning for "hg summary"
5491 ui.write(_('update: %d new changesets (update)\n') % new)
5490 ui.write(_('update: %d new changesets (update)\n') % new)
5492 else:
5491 else:
5493 # i18n: column positioning for "hg summary"
5492 # i18n: column positioning for "hg summary"
5494 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5493 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5495 (new, len(bheads)))
5494 (new, len(bheads)))
5496
5495
5497 cmdutil.summaryhooks(ui, repo)
5496 cmdutil.summaryhooks(ui, repo)
5498
5497
5499 if opts.get('remote'):
5498 if opts.get('remote'):
5500 t = []
5499 t = []
5501 source, branches = hg.parseurl(ui.expandpath('default'))
5500 source, branches = hg.parseurl(ui.expandpath('default'))
5502 sbranch = branches[0]
5501 sbranch = branches[0]
5503 other = hg.peer(repo, {}, source)
5502 other = hg.peer(repo, {}, source)
5504 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5503 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5505 if revs:
5504 if revs:
5506 revs = [other.lookup(rev) for rev in revs]
5505 revs = [other.lookup(rev) for rev in revs]
5507 ui.debug('comparing with %s\n' % util.hidepassword(source))
5506 ui.debug('comparing with %s\n' % util.hidepassword(source))
5508 repo.ui.pushbuffer()
5507 repo.ui.pushbuffer()
5509 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5508 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5510 _common, incoming, _rheads = commoninc
5509 _common, incoming, _rheads = commoninc
5511 repo.ui.popbuffer()
5510 repo.ui.popbuffer()
5512 if incoming:
5511 if incoming:
5513 t.append(_('1 or more incoming'))
5512 t.append(_('1 or more incoming'))
5514
5513
5515 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5514 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5516 dbranch = branches[0]
5515 dbranch = branches[0]
5517 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5516 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5518 if source != dest:
5517 if source != dest:
5519 other = hg.peer(repo, {}, dest)
5518 other = hg.peer(repo, {}, dest)
5520 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5519 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5521 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5520 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5522 commoninc = None
5521 commoninc = None
5523 if revs:
5522 if revs:
5524 revs = [repo.lookup(rev) for rev in revs]
5523 revs = [repo.lookup(rev) for rev in revs]
5525 repo.ui.pushbuffer()
5524 repo.ui.pushbuffer()
5526 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5525 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs,
5527 commoninc=commoninc)
5526 commoninc=commoninc)
5528 repo.ui.popbuffer()
5527 repo.ui.popbuffer()
5529 o = outgoing.missing
5528 o = outgoing.missing
5530 if o:
5529 if o:
5531 t.append(_('%d outgoing') % len(o))
5530 t.append(_('%d outgoing') % len(o))
5532 if 'bookmarks' in other.listkeys('namespaces'):
5531 if 'bookmarks' in other.listkeys('namespaces'):
5533 lmarks = repo.listkeys('bookmarks')
5532 lmarks = repo.listkeys('bookmarks')
5534 rmarks = other.listkeys('bookmarks')
5533 rmarks = other.listkeys('bookmarks')
5535 diff = set(rmarks) - set(lmarks)
5534 diff = set(rmarks) - set(lmarks)
5536 if len(diff) > 0:
5535 if len(diff) > 0:
5537 t.append(_('%d incoming bookmarks') % len(diff))
5536 t.append(_('%d incoming bookmarks') % len(diff))
5538 diff = set(lmarks) - set(rmarks)
5537 diff = set(lmarks) - set(rmarks)
5539 if len(diff) > 0:
5538 if len(diff) > 0:
5540 t.append(_('%d outgoing bookmarks') % len(diff))
5539 t.append(_('%d outgoing bookmarks') % len(diff))
5541
5540
5542 if t:
5541 if t:
5543 # i18n: column positioning for "hg summary"
5542 # i18n: column positioning for "hg summary"
5544 ui.write(_('remote: %s\n') % (', '.join(t)))
5543 ui.write(_('remote: %s\n') % (', '.join(t)))
5545 else:
5544 else:
5546 # i18n: column positioning for "hg summary"
5545 # i18n: column positioning for "hg summary"
5547 ui.status(_('remote: (synced)\n'))
5546 ui.status(_('remote: (synced)\n'))
5548
5547
5549 @command('tag',
5548 @command('tag',
5550 [('f', 'force', None, _('force tag')),
5549 [('f', 'force', None, _('force tag')),
5551 ('l', 'local', None, _('make the tag local')),
5550 ('l', 'local', None, _('make the tag local')),
5552 ('r', 'rev', '', _('revision to tag'), _('REV')),
5551 ('r', 'rev', '', _('revision to tag'), _('REV')),
5553 ('', 'remove', None, _('remove a tag')),
5552 ('', 'remove', None, _('remove a tag')),
5554 # -l/--local is already there, commitopts cannot be used
5553 # -l/--local is already there, commitopts cannot be used
5555 ('e', 'edit', None, _('edit commit message')),
5554 ('e', 'edit', None, _('edit commit message')),
5556 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5555 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5557 ] + commitopts2,
5556 ] + commitopts2,
5558 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5557 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5559 def tag(ui, repo, name1, *names, **opts):
5558 def tag(ui, repo, name1, *names, **opts):
5560 """add one or more tags for the current or given revision
5559 """add one or more tags for the current or given revision
5561
5560
5562 Name a particular revision using <name>.
5561 Name a particular revision using <name>.
5563
5562
5564 Tags are used to name particular revisions of the repository and are
5563 Tags are used to name particular revisions of the repository and are
5565 very useful to compare different revisions, to go back to significant
5564 very useful to compare different revisions, to go back to significant
5566 earlier versions or to mark branch points as releases, etc. Changing
5565 earlier versions or to mark branch points as releases, etc. Changing
5567 an existing tag is normally disallowed; use -f/--force to override.
5566 an existing tag is normally disallowed; use -f/--force to override.
5568
5567
5569 If no revision is given, the parent of the working directory is
5568 If no revision is given, the parent of the working directory is
5570 used, or tip if no revision is checked out.
5569 used, or tip if no revision is checked out.
5571
5570
5572 To facilitate version control, distribution, and merging of tags,
5571 To facilitate version control, distribution, and merging of tags,
5573 they are stored as a file named ".hgtags" which is managed similarly
5572 they are stored as a file named ".hgtags" which is managed similarly
5574 to other project files and can be hand-edited if necessary. This
5573 to other project files and can be hand-edited if necessary. This
5575 also means that tagging creates a new commit. The file
5574 also means that tagging creates a new commit. The file
5576 ".hg/localtags" is used for local tags (not shared among
5575 ".hg/localtags" is used for local tags (not shared among
5577 repositories).
5576 repositories).
5578
5577
5579 Tag commits are usually made at the head of a branch. If the parent
5578 Tag commits are usually made at the head of a branch. If the parent
5580 of the working directory is not a branch head, :hg:`tag` aborts; use
5579 of the working directory is not a branch head, :hg:`tag` aborts; use
5581 -f/--force to force the tag commit to be based on a non-head
5580 -f/--force to force the tag commit to be based on a non-head
5582 changeset.
5581 changeset.
5583
5582
5584 See :hg:`help dates` for a list of formats valid for -d/--date.
5583 See :hg:`help dates` for a list of formats valid for -d/--date.
5585
5584
5586 Since tag names have priority over branch names during revision
5585 Since tag names have priority over branch names during revision
5587 lookup, using an existing branch name as a tag name is discouraged.
5586 lookup, using an existing branch name as a tag name is discouraged.
5588
5587
5589 Returns 0 on success.
5588 Returns 0 on success.
5590 """
5589 """
5591 wlock = lock = None
5590 wlock = lock = None
5592 try:
5591 try:
5593 wlock = repo.wlock()
5592 wlock = repo.wlock()
5594 lock = repo.lock()
5593 lock = repo.lock()
5595 rev_ = "."
5594 rev_ = "."
5596 names = [t.strip() for t in (name1,) + names]
5595 names = [t.strip() for t in (name1,) + names]
5597 if len(names) != len(set(names)):
5596 if len(names) != len(set(names)):
5598 raise util.Abort(_('tag names must be unique'))
5597 raise util.Abort(_('tag names must be unique'))
5599 for n in names:
5598 for n in names:
5600 scmutil.checknewlabel(repo, n, 'tag')
5599 scmutil.checknewlabel(repo, n, 'tag')
5601 if not n:
5600 if not n:
5602 raise util.Abort(_('tag names cannot consist entirely of '
5601 raise util.Abort(_('tag names cannot consist entirely of '
5603 'whitespace'))
5602 'whitespace'))
5604 if opts.get('rev') and opts.get('remove'):
5603 if opts.get('rev') and opts.get('remove'):
5605 raise util.Abort(_("--rev and --remove are incompatible"))
5604 raise util.Abort(_("--rev and --remove are incompatible"))
5606 if opts.get('rev'):
5605 if opts.get('rev'):
5607 rev_ = opts['rev']
5606 rev_ = opts['rev']
5608 message = opts.get('message')
5607 message = opts.get('message')
5609 if opts.get('remove'):
5608 if opts.get('remove'):
5610 expectedtype = opts.get('local') and 'local' or 'global'
5609 expectedtype = opts.get('local') and 'local' or 'global'
5611 for n in names:
5610 for n in names:
5612 if not repo.tagtype(n):
5611 if not repo.tagtype(n):
5613 raise util.Abort(_("tag '%s' does not exist") % n)
5612 raise util.Abort(_("tag '%s' does not exist") % n)
5614 if repo.tagtype(n) != expectedtype:
5613 if repo.tagtype(n) != expectedtype:
5615 if expectedtype == 'global':
5614 if expectedtype == 'global':
5616 raise util.Abort(_("tag '%s' is not a global tag") % n)
5615 raise util.Abort(_("tag '%s' is not a global tag") % n)
5617 else:
5616 else:
5618 raise util.Abort(_("tag '%s' is not a local tag") % n)
5617 raise util.Abort(_("tag '%s' is not a local tag") % n)
5619 rev_ = nullid
5618 rev_ = nullid
5620 if not message:
5619 if not message:
5621 # we don't translate commit messages
5620 # we don't translate commit messages
5622 message = 'Removed tag %s' % ', '.join(names)
5621 message = 'Removed tag %s' % ', '.join(names)
5623 elif not opts.get('force'):
5622 elif not opts.get('force'):
5624 for n in names:
5623 for n in names:
5625 if n in repo.tags():
5624 if n in repo.tags():
5626 raise util.Abort(_("tag '%s' already exists "
5625 raise util.Abort(_("tag '%s' already exists "
5627 "(use -f to force)") % n)
5626 "(use -f to force)") % n)
5628 if not opts.get('local'):
5627 if not opts.get('local'):
5629 p1, p2 = repo.dirstate.parents()
5628 p1, p2 = repo.dirstate.parents()
5630 if p2 != nullid:
5629 if p2 != nullid:
5631 raise util.Abort(_('uncommitted merge'))
5630 raise util.Abort(_('uncommitted merge'))
5632 bheads = repo.branchheads()
5631 bheads = repo.branchheads()
5633 if not opts.get('force') and bheads and p1 not in bheads:
5632 if not opts.get('force') and bheads and p1 not in bheads:
5634 raise util.Abort(_('not at a branch head (use -f to force)'))
5633 raise util.Abort(_('not at a branch head (use -f to force)'))
5635 r = scmutil.revsingle(repo, rev_).node()
5634 r = scmutil.revsingle(repo, rev_).node()
5636
5635
5637 if not message:
5636 if not message:
5638 # we don't translate commit messages
5637 # we don't translate commit messages
5639 message = ('Added tag %s for changeset %s' %
5638 message = ('Added tag %s for changeset %s' %
5640 (', '.join(names), short(r)))
5639 (', '.join(names), short(r)))
5641
5640
5642 date = opts.get('date')
5641 date = opts.get('date')
5643 if date:
5642 if date:
5644 date = util.parsedate(date)
5643 date = util.parsedate(date)
5645
5644
5646 if opts.get('edit'):
5645 if opts.get('edit'):
5647 message = ui.edit(message, ui.username())
5646 message = ui.edit(message, ui.username())
5648
5647
5649 # don't allow tagging the null rev
5648 # don't allow tagging the null rev
5650 if (not opts.get('remove') and
5649 if (not opts.get('remove') and
5651 scmutil.revsingle(repo, rev_).rev() == nullrev):
5650 scmutil.revsingle(repo, rev_).rev() == nullrev):
5652 raise util.Abort(_("cannot tag null revision"))
5651 raise util.Abort(_("cannot tag null revision"))
5653
5652
5654 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5653 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5655 finally:
5654 finally:
5656 release(lock, wlock)
5655 release(lock, wlock)
5657
5656
5658 @command('tags', [], '')
5657 @command('tags', [], '')
5659 def tags(ui, repo, **opts):
5658 def tags(ui, repo, **opts):
5660 """list repository tags
5659 """list repository tags
5661
5660
5662 This lists both regular and local tags. When the -v/--verbose
5661 This lists both regular and local tags. When the -v/--verbose
5663 switch is used, a third column "local" is printed for local tags.
5662 switch is used, a third column "local" is printed for local tags.
5664
5663
5665 Returns 0 on success.
5664 Returns 0 on success.
5666 """
5665 """
5667
5666
5668 fm = ui.formatter('tags', opts)
5667 fm = ui.formatter('tags', opts)
5669 hexfunc = ui.debugflag and hex or short
5668 hexfunc = ui.debugflag and hex or short
5670 tagtype = ""
5669 tagtype = ""
5671
5670
5672 for t, n in reversed(repo.tagslist()):
5671 for t, n in reversed(repo.tagslist()):
5673 hn = hexfunc(n)
5672 hn = hexfunc(n)
5674 label = 'tags.normal'
5673 label = 'tags.normal'
5675 tagtype = ''
5674 tagtype = ''
5676 if repo.tagtype(t) == 'local':
5675 if repo.tagtype(t) == 'local':
5677 label = 'tags.local'
5676 label = 'tags.local'
5678 tagtype = 'local'
5677 tagtype = 'local'
5679
5678
5680 fm.startitem()
5679 fm.startitem()
5681 fm.write('tag', '%s', t, label=label)
5680 fm.write('tag', '%s', t, label=label)
5682 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5681 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5683 fm.condwrite(not ui.quiet, 'rev id', fmt,
5682 fm.condwrite(not ui.quiet, 'rev id', fmt,
5684 repo.changelog.rev(n), hn, label=label)
5683 repo.changelog.rev(n), hn, label=label)
5685 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5684 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5686 tagtype, label=label)
5685 tagtype, label=label)
5687 fm.plain('\n')
5686 fm.plain('\n')
5688 fm.end()
5687 fm.end()
5689
5688
5690 @command('tip',
5689 @command('tip',
5691 [('p', 'patch', None, _('show patch')),
5690 [('p', 'patch', None, _('show patch')),
5692 ('g', 'git', None, _('use git extended diff format')),
5691 ('g', 'git', None, _('use git extended diff format')),
5693 ] + templateopts,
5692 ] + templateopts,
5694 _('[-p] [-g]'))
5693 _('[-p] [-g]'))
5695 def tip(ui, repo, **opts):
5694 def tip(ui, repo, **opts):
5696 """show the tip revision
5695 """show the tip revision
5697
5696
5698 The tip revision (usually just called the tip) is the changeset
5697 The tip revision (usually just called the tip) is the changeset
5699 most recently added to the repository (and therefore the most
5698 most recently added to the repository (and therefore the most
5700 recently changed head).
5699 recently changed head).
5701
5700
5702 If you have just made a commit, that commit will be the tip. If
5701 If you have just made a commit, that commit will be the tip. If
5703 you have just pulled changes from another repository, the tip of
5702 you have just pulled changes from another repository, the tip of
5704 that repository becomes the current tip. The "tip" tag is special
5703 that repository becomes the current tip. The "tip" tag is special
5705 and cannot be renamed or assigned to a different changeset.
5704 and cannot be renamed or assigned to a different changeset.
5706
5705
5707 Returns 0 on success.
5706 Returns 0 on success.
5708 """
5707 """
5709 displayer = cmdutil.show_changeset(ui, repo, opts)
5708 displayer = cmdutil.show_changeset(ui, repo, opts)
5710 displayer.show(repo['tip'])
5709 displayer.show(repo['tip'])
5711 displayer.close()
5710 displayer.close()
5712
5711
5713 @command('unbundle',
5712 @command('unbundle',
5714 [('u', 'update', None,
5713 [('u', 'update', None,
5715 _('update to new branch head if changesets were unbundled'))],
5714 _('update to new branch head if changesets were unbundled'))],
5716 _('[-u] FILE...'))
5715 _('[-u] FILE...'))
5717 def unbundle(ui, repo, fname1, *fnames, **opts):
5716 def unbundle(ui, repo, fname1, *fnames, **opts):
5718 """apply one or more changegroup files
5717 """apply one or more changegroup files
5719
5718
5720 Apply one or more compressed changegroup files generated by the
5719 Apply one or more compressed changegroup files generated by the
5721 bundle command.
5720 bundle command.
5722
5721
5723 Returns 0 on success, 1 if an update has unresolved files.
5722 Returns 0 on success, 1 if an update has unresolved files.
5724 """
5723 """
5725 fnames = (fname1,) + fnames
5724 fnames = (fname1,) + fnames
5726
5725
5727 lock = repo.lock()
5726 lock = repo.lock()
5728 wc = repo['.']
5727 wc = repo['.']
5729 try:
5728 try:
5730 for fname in fnames:
5729 for fname in fnames:
5731 f = hg.openpath(ui, fname)
5730 f = hg.openpath(ui, fname)
5732 gen = changegroup.readbundle(f, fname)
5731 gen = changegroup.readbundle(f, fname)
5733 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5732 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5734 finally:
5733 finally:
5735 lock.release()
5734 lock.release()
5736 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5735 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5737 return postincoming(ui, repo, modheads, opts.get('update'), None)
5736 return postincoming(ui, repo, modheads, opts.get('update'), None)
5738
5737
5739 @command('^update|up|checkout|co',
5738 @command('^update|up|checkout|co',
5740 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5739 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5741 ('c', 'check', None,
5740 ('c', 'check', None,
5742 _('update across branches if no uncommitted changes')),
5741 _('update across branches if no uncommitted changes')),
5743 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5742 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5744 ('r', 'rev', '', _('revision'), _('REV'))],
5743 ('r', 'rev', '', _('revision'), _('REV'))],
5745 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5744 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5746 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5745 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5747 """update working directory (or switch revisions)
5746 """update working directory (or switch revisions)
5748
5747
5749 Update the repository's working directory to the specified
5748 Update the repository's working directory to the specified
5750 changeset. If no changeset is specified, update to the tip of the
5749 changeset. If no changeset is specified, update to the tip of the
5751 current named branch and move the current bookmark (see :hg:`help
5750 current named branch and move the current bookmark (see :hg:`help
5752 bookmarks`).
5751 bookmarks`).
5753
5752
5754 Update sets the working directory's parent revision to the specified
5753 Update sets the working directory's parent revision to the specified
5755 changeset (see :hg:`help parents`).
5754 changeset (see :hg:`help parents`).
5756
5755
5757 If the changeset is not a descendant or ancestor of the working
5756 If the changeset is not a descendant or ancestor of the working
5758 directory's parent, the update is aborted. With the -c/--check
5757 directory's parent, the update is aborted. With the -c/--check
5759 option, the working directory is checked for uncommitted changes; if
5758 option, the working directory is checked for uncommitted changes; if
5760 none are found, the working directory is updated to the specified
5759 none are found, the working directory is updated to the specified
5761 changeset.
5760 changeset.
5762
5761
5763 .. container:: verbose
5762 .. container:: verbose
5764
5763
5765 The following rules apply when the working directory contains
5764 The following rules apply when the working directory contains
5766 uncommitted changes:
5765 uncommitted changes:
5767
5766
5768 1. If neither -c/--check nor -C/--clean is specified, and if
5767 1. If neither -c/--check nor -C/--clean is specified, and if
5769 the requested changeset is an ancestor or descendant of
5768 the requested changeset is an ancestor or descendant of
5770 the working directory's parent, the uncommitted changes
5769 the working directory's parent, the uncommitted changes
5771 are merged into the requested changeset and the merged
5770 are merged into the requested changeset and the merged
5772 result is left uncommitted. If the requested changeset is
5771 result is left uncommitted. If the requested changeset is
5773 not an ancestor or descendant (that is, it is on another
5772 not an ancestor or descendant (that is, it is on another
5774 branch), the update is aborted and the uncommitted changes
5773 branch), the update is aborted and the uncommitted changes
5775 are preserved.
5774 are preserved.
5776
5775
5777 2. With the -c/--check option, the update is aborted and the
5776 2. With the -c/--check option, the update is aborted and the
5778 uncommitted changes are preserved.
5777 uncommitted changes are preserved.
5779
5778
5780 3. With the -C/--clean option, uncommitted changes are discarded and
5779 3. With the -C/--clean option, uncommitted changes are discarded and
5781 the working directory is updated to the requested changeset.
5780 the working directory is updated to the requested changeset.
5782
5781
5783 To cancel an uncommitted merge (and lose your changes), use
5782 To cancel an uncommitted merge (and lose your changes), use
5784 :hg:`update --clean .`.
5783 :hg:`update --clean .`.
5785
5784
5786 Use null as the changeset to remove the working directory (like
5785 Use null as the changeset to remove the working directory (like
5787 :hg:`clone -U`).
5786 :hg:`clone -U`).
5788
5787
5789 If you want to revert just one file to an older revision, use
5788 If you want to revert just one file to an older revision, use
5790 :hg:`revert [-r REV] NAME`.
5789 :hg:`revert [-r REV] NAME`.
5791
5790
5792 See :hg:`help dates` for a list of formats valid for -d/--date.
5791 See :hg:`help dates` for a list of formats valid for -d/--date.
5793
5792
5794 Returns 0 on success, 1 if there are unresolved files.
5793 Returns 0 on success, 1 if there are unresolved files.
5795 """
5794 """
5796 if rev and node:
5795 if rev and node:
5797 raise util.Abort(_("please specify just one revision"))
5796 raise util.Abort(_("please specify just one revision"))
5798
5797
5799 if rev is None or rev == '':
5798 if rev is None or rev == '':
5800 rev = node
5799 rev = node
5801
5800
5802 # with no argument, we also move the current bookmark, if any
5801 # with no argument, we also move the current bookmark, if any
5803 movemarkfrom = None
5802 movemarkfrom = None
5804 if rev is None:
5803 if rev is None:
5805 curmark = repo._bookmarkcurrent
5804 curmark = repo._bookmarkcurrent
5806 if bookmarks.iscurrent(repo):
5805 if bookmarks.iscurrent(repo):
5807 movemarkfrom = repo['.'].node()
5806 movemarkfrom = repo['.'].node()
5808 elif curmark:
5807 elif curmark:
5809 ui.status(_("updating to active bookmark %s\n") % curmark)
5808 ui.status(_("updating to active bookmark %s\n") % curmark)
5810 rev = curmark
5809 rev = curmark
5811
5810
5812 # if we defined a bookmark, we have to remember the original bookmark name
5811 # if we defined a bookmark, we have to remember the original bookmark name
5813 brev = rev
5812 brev = rev
5814 rev = scmutil.revsingle(repo, rev, rev).rev()
5813 rev = scmutil.revsingle(repo, rev, rev).rev()
5815
5814
5816 if check and clean:
5815 if check and clean:
5817 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5816 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5818
5817
5819 if date:
5818 if date:
5820 if rev is not None:
5819 if rev is not None:
5821 raise util.Abort(_("you can't specify a revision and a date"))
5820 raise util.Abort(_("you can't specify a revision and a date"))
5822 rev = cmdutil.finddate(ui, repo, date)
5821 rev = cmdutil.finddate(ui, repo, date)
5823
5822
5824 if check:
5823 if check:
5825 c = repo[None]
5824 c = repo[None]
5826 if c.dirty(merge=False, branch=False, missing=True):
5825 if c.dirty(merge=False, branch=False, missing=True):
5827 raise util.Abort(_("uncommitted local changes"))
5826 raise util.Abort(_("uncommitted local changes"))
5828 if rev is None:
5827 if rev is None:
5829 rev = repo[repo[None].branch()].rev()
5828 rev = repo[repo[None].branch()].rev()
5830 mergemod._checkunknown(repo, repo[None], repo[rev])
5829 mergemod._checkunknown(repo, repo[None], repo[rev])
5831
5830
5832 if clean:
5831 if clean:
5833 ret = hg.clean(repo, rev)
5832 ret = hg.clean(repo, rev)
5834 else:
5833 else:
5835 ret = hg.update(repo, rev)
5834 ret = hg.update(repo, rev)
5836
5835
5837 if not ret and movemarkfrom:
5836 if not ret and movemarkfrom:
5838 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5837 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5839 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5838 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5840 elif brev in repo._bookmarks:
5839 elif brev in repo._bookmarks:
5841 bookmarks.setcurrent(repo, brev)
5840 bookmarks.setcurrent(repo, brev)
5842 elif brev:
5841 elif brev:
5843 bookmarks.unsetcurrent(repo)
5842 bookmarks.unsetcurrent(repo)
5844
5843
5845 return ret
5844 return ret
5846
5845
5847 @command('verify', [])
5846 @command('verify', [])
5848 def verify(ui, repo):
5847 def verify(ui, repo):
5849 """verify the integrity of the repository
5848 """verify the integrity of the repository
5850
5849
5851 Verify the integrity of the current repository.
5850 Verify the integrity of the current repository.
5852
5851
5853 This will perform an extensive check of the repository's
5852 This will perform an extensive check of the repository's
5854 integrity, validating the hashes and checksums of each entry in
5853 integrity, validating the hashes and checksums of each entry in
5855 the changelog, manifest, and tracked files, as well as the
5854 the changelog, manifest, and tracked files, as well as the
5856 integrity of their crosslinks and indices.
5855 integrity of their crosslinks and indices.
5857
5856
5858 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5857 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5859 for more information about recovery from corruption of the
5858 for more information about recovery from corruption of the
5860 repository.
5859 repository.
5861
5860
5862 Returns 0 on success, 1 if errors are encountered.
5861 Returns 0 on success, 1 if errors are encountered.
5863 """
5862 """
5864 return hg.verify(repo)
5863 return hg.verify(repo)
5865
5864
5866 @command('version', [])
5865 @command('version', [])
5867 def version_(ui):
5866 def version_(ui):
5868 """output version and copyright information"""
5867 """output version and copyright information"""
5869 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5868 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5870 % util.version())
5869 % util.version())
5871 ui.status(_(
5870 ui.status(_(
5872 "(see http://mercurial.selenic.com for more information)\n"
5871 "(see http://mercurial.selenic.com for more information)\n"
5873 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5872 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5874 "This is free software; see the source for copying conditions. "
5873 "This is free software; see the source for copying conditions. "
5875 "There is NO\nwarranty; "
5874 "There is NO\nwarranty; "
5876 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5875 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5877 ))
5876 ))
5878
5877
5879 norepo = ("clone init version help debugcommands debugcomplete"
5878 norepo = ("clone init version help debugcommands debugcomplete"
5880 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5879 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5881 " debugknown debuggetbundle debugbundle")
5880 " debugknown debuggetbundle debugbundle")
5882 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5881 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5883 " debugdata debugindex debugindexdot debugrevlog")
5882 " debugdata debugindex debugindexdot debugrevlog")
5884 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5883 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5885 " remove resolve status debugwalk")
5884 " remove resolve status debugwalk")
General Comments 0
You need to be logged in to leave comments. Login now