##// END OF EJS Templates
pull: avoid race condition with 'hg pull --rev name --update' (issue4706)...
Pierre-Yves David -
r25425:9263f86b stable
parent child Browse files
Show More
@@ -1,6463 +1,6469 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, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
108 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
151 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
152 ]
152 ]
153
153
154 mergetoolopts = [
154 mergetoolopts = [
155 ('t', 'tool', '', _('specify merge tool')),
155 ('t', 'tool', '', _('specify merge tool')),
156 ]
156 ]
157
157
158 similarityopts = [
158 similarityopts = [
159 ('s', 'similarity', '',
159 ('s', 'similarity', '',
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
161 ]
161 ]
162
162
163 subrepoopts = [
163 subrepoopts = [
164 ('S', 'subrepos', None,
164 ('S', 'subrepos', None,
165 _('recurse into subrepositories'))
165 _('recurse into subrepositories'))
166 ]
166 ]
167
167
168 # Commands start here, listed alphabetically
168 # Commands start here, listed alphabetically
169
169
170 @command('^add',
170 @command('^add',
171 walkopts + subrepoopts + dryrunopts,
171 walkopts + subrepoopts + dryrunopts,
172 _('[OPTION]... [FILE]...'),
172 _('[OPTION]... [FILE]...'),
173 inferrepo=True)
173 inferrepo=True)
174 def add(ui, repo, *pats, **opts):
174 def add(ui, repo, *pats, **opts):
175 """add the specified files on the next commit
175 """add the specified files on the next commit
176
176
177 Schedule files to be version controlled and added to the
177 Schedule files to be version controlled and added to the
178 repository.
178 repository.
179
179
180 The files will be added to the repository at the next commit. To
180 The files will be added to the repository at the next commit. To
181 undo an add before that, see :hg:`forget`.
181 undo an add before that, see :hg:`forget`.
182
182
183 If no names are given, add all files to the repository.
183 If no names are given, add all files to the repository.
184
184
185 .. container:: verbose
185 .. container:: verbose
186
186
187 An example showing how new (unknown) files are added
187 An example showing how new (unknown) files are added
188 automatically by :hg:`add`::
188 automatically by :hg:`add`::
189
189
190 $ ls
190 $ ls
191 foo.c
191 foo.c
192 $ hg status
192 $ hg status
193 ? foo.c
193 ? foo.c
194 $ hg add
194 $ hg add
195 adding foo.c
195 adding foo.c
196 $ hg status
196 $ hg status
197 A foo.c
197 A foo.c
198
198
199 Returns 0 if all files are successfully added.
199 Returns 0 if all files are successfully added.
200 """
200 """
201
201
202 m = scmutil.match(repo[None], pats, opts)
202 m = scmutil.match(repo[None], pats, opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
204 return rejected and 1 or 0
204 return rejected and 1 or 0
205
205
206 @command('addremove',
206 @command('addremove',
207 similarityopts + subrepoopts + walkopts + dryrunopts,
207 similarityopts + subrepoopts + walkopts + dryrunopts,
208 _('[OPTION]... [FILE]...'),
208 _('[OPTION]... [FILE]...'),
209 inferrepo=True)
209 inferrepo=True)
210 def addremove(ui, repo, *pats, **opts):
210 def addremove(ui, repo, *pats, **opts):
211 """add all new files, delete all missing files
211 """add all new files, delete all missing files
212
212
213 Add all new files and remove all missing files from the
213 Add all new files and remove all missing files from the
214 repository.
214 repository.
215
215
216 New files are ignored if they match any of the patterns in
216 New files are ignored if they match any of the patterns in
217 ``.hgignore``. As with add, these changes take effect at the next
217 ``.hgignore``. As with add, these changes take effect at the next
218 commit.
218 commit.
219
219
220 Use the -s/--similarity option to detect renamed files. This
220 Use the -s/--similarity option to detect renamed files. This
221 option takes a percentage between 0 (disabled) and 100 (files must
221 option takes a percentage between 0 (disabled) and 100 (files must
222 be identical) as its parameter. With a parameter greater than 0,
222 be identical) as its parameter. With a parameter greater than 0,
223 this compares every removed file with every added file and records
223 this compares every removed file with every added file and records
224 those similar enough as renames. Detecting renamed files this way
224 those similar enough as renames. Detecting renamed files this way
225 can be expensive. After using this option, :hg:`status -C` can be
225 can be expensive. After using this option, :hg:`status -C` can be
226 used to check which files were identified as moved or renamed. If
226 used to check which files were identified as moved or renamed. If
227 not specified, -s/--similarity defaults to 100 and only renames of
227 not specified, -s/--similarity defaults to 100 and only renames of
228 identical files are detected.
228 identical files are detected.
229
229
230 Returns 0 if all files are successfully added.
230 Returns 0 if all files are successfully added.
231 """
231 """
232 try:
232 try:
233 sim = float(opts.get('similarity') or 100)
233 sim = float(opts.get('similarity') or 100)
234 except ValueError:
234 except ValueError:
235 raise util.Abort(_('similarity must be a number'))
235 raise util.Abort(_('similarity must be a number'))
236 if sim < 0 or sim > 100:
236 if sim < 0 or sim > 100:
237 raise util.Abort(_('similarity must be between 0 and 100'))
237 raise util.Abort(_('similarity must be between 0 and 100'))
238 matcher = scmutil.match(repo[None], pats, opts)
238 matcher = scmutil.match(repo[None], pats, opts)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
240
240
241 @command('^annotate|blame',
241 @command('^annotate|blame',
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
243 ('', 'follow', None,
243 ('', 'follow', None,
244 _('follow copies/renames and list the filename (DEPRECATED)')),
244 _('follow copies/renames and list the filename (DEPRECATED)')),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('', 'no-follow', None, _("don't follow copies and renames")),
246 ('a', 'text', None, _('treat all files as text')),
246 ('a', 'text', None, _('treat all files as text')),
247 ('u', 'user', None, _('list the author (long with -v)')),
247 ('u', 'user', None, _('list the author (long with -v)')),
248 ('f', 'file', None, _('list the filename')),
248 ('f', 'file', None, _('list the filename')),
249 ('d', 'date', None, _('list the date (short with -q)')),
249 ('d', 'date', None, _('list the date (short with -q)')),
250 ('n', 'number', None, _('list the revision number (default)')),
250 ('n', 'number', None, _('list the revision number (default)')),
251 ('c', 'changeset', None, _('list the changeset')),
251 ('c', 'changeset', None, _('list the changeset')),
252 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ('l', 'line-number', None, _('show line number at the first appearance'))
253 ] + diffwsopts + walkopts + formatteropts,
253 ] + diffwsopts + walkopts + formatteropts,
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
255 inferrepo=True)
255 inferrepo=True)
256 def annotate(ui, repo, *pats, **opts):
256 def annotate(ui, repo, *pats, **opts):
257 """show changeset information by line for each file
257 """show changeset information by line for each file
258
258
259 List changes in files, showing the revision id responsible for
259 List changes in files, showing the revision id responsible for
260 each line
260 each line
261
261
262 This command is useful for discovering when a change was made and
262 This command is useful for discovering when a change was made and
263 by whom.
263 by whom.
264
264
265 Without the -a/--text option, annotate will avoid processing files
265 Without the -a/--text option, annotate will avoid processing files
266 it detects as binary. With -a, annotate will annotate the file
266 it detects as binary. With -a, annotate will annotate the file
267 anyway, although the results will probably be neither useful
267 anyway, although the results will probably be neither useful
268 nor desirable.
268 nor desirable.
269
269
270 Returns 0 on success.
270 Returns 0 on success.
271 """
271 """
272 if not pats:
272 if not pats:
273 raise util.Abort(_('at least one filename or pattern is required'))
273 raise util.Abort(_('at least one filename or pattern is required'))
274
274
275 if opts.get('follow'):
275 if opts.get('follow'):
276 # --follow is deprecated and now just an alias for -f/--file
276 # --follow is deprecated and now just an alias for -f/--file
277 # to mimic the behavior of Mercurial before version 1.5
277 # to mimic the behavior of Mercurial before version 1.5
278 opts['file'] = True
278 opts['file'] = True
279
279
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
280 ctx = scmutil.revsingle(repo, opts.get('rev'))
281
281
282 fm = ui.formatter('annotate', opts)
282 fm = ui.formatter('annotate', opts)
283 if ui.quiet:
283 if ui.quiet:
284 datefunc = util.shortdate
284 datefunc = util.shortdate
285 else:
285 else:
286 datefunc = util.datestr
286 datefunc = util.datestr
287 if ctx.rev() is None:
287 if ctx.rev() is None:
288 def hexfn(node):
288 def hexfn(node):
289 if node is None:
289 if node is None:
290 return None
290 return None
291 else:
291 else:
292 return fm.hexfunc(node)
292 return fm.hexfunc(node)
293 if opts.get('changeset'):
293 if opts.get('changeset'):
294 # omit "+" suffix which is appended to node hex
294 # omit "+" suffix which is appended to node hex
295 def formatrev(rev):
295 def formatrev(rev):
296 if rev is None:
296 if rev is None:
297 return '%d' % ctx.p1().rev()
297 return '%d' % ctx.p1().rev()
298 else:
298 else:
299 return '%d' % rev
299 return '%d' % rev
300 else:
300 else:
301 def formatrev(rev):
301 def formatrev(rev):
302 if rev is None:
302 if rev is None:
303 return '%d+' % ctx.p1().rev()
303 return '%d+' % ctx.p1().rev()
304 else:
304 else:
305 return '%d ' % rev
305 return '%d ' % rev
306 def formathex(hex):
306 def formathex(hex):
307 if hex is None:
307 if hex is None:
308 return '%s+' % fm.hexfunc(ctx.p1().node())
308 return '%s+' % fm.hexfunc(ctx.p1().node())
309 else:
309 else:
310 return '%s ' % hex
310 return '%s ' % hex
311 else:
311 else:
312 hexfn = fm.hexfunc
312 hexfn = fm.hexfunc
313 formatrev = formathex = str
313 formatrev = formathex = str
314
314
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
315 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
316 ('number', ' ', lambda x: x[0].rev(), formatrev),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
317 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
318 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
319 ('file', ' ', lambda x: x[0].path(), str),
319 ('file', ' ', lambda x: x[0].path(), str),
320 ('line_number', ':', lambda x: x[1], str),
320 ('line_number', ':', lambda x: x[1], str),
321 ]
321 ]
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
322 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
323
323
324 if (not opts.get('user') and not opts.get('changeset')
324 if (not opts.get('user') and not opts.get('changeset')
325 and not opts.get('date') and not opts.get('file')):
325 and not opts.get('date') and not opts.get('file')):
326 opts['number'] = True
326 opts['number'] = True
327
327
328 linenumber = opts.get('line_number') is not None
328 linenumber = opts.get('line_number') is not None
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
329 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
330 raise util.Abort(_('at least one of -n/-c is required for -l'))
331
331
332 if fm:
332 if fm:
333 def makefunc(get, fmt):
333 def makefunc(get, fmt):
334 return get
334 return get
335 else:
335 else:
336 def makefunc(get, fmt):
336 def makefunc(get, fmt):
337 return lambda x: fmt(get(x))
337 return lambda x: fmt(get(x))
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
338 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
339 if opts.get(op)]
339 if opts.get(op)]
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
340 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
341 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
342 if opts.get(op))
342 if opts.get(op))
343
343
344 def bad(x, y):
344 def bad(x, y):
345 raise util.Abort("%s: %s" % (x, y))
345 raise util.Abort("%s: %s" % (x, y))
346
346
347 m = scmutil.match(ctx, pats, opts)
347 m = scmutil.match(ctx, pats, opts)
348 m.bad = bad
348 m.bad = bad
349 follow = not opts.get('no_follow')
349 follow = not opts.get('no_follow')
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
350 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
351 whitespace=True)
351 whitespace=True)
352 for abs in ctx.walk(m):
352 for abs in ctx.walk(m):
353 fctx = ctx[abs]
353 fctx = ctx[abs]
354 if not opts.get('text') and util.binary(fctx.data()):
354 if not opts.get('text') and util.binary(fctx.data()):
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
355 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
356 continue
356 continue
357
357
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
358 lines = fctx.annotate(follow=follow, linenumber=linenumber,
359 diffopts=diffopts)
359 diffopts=diffopts)
360 formats = []
360 formats = []
361 pieces = []
361 pieces = []
362
362
363 for f, sep in funcmap:
363 for f, sep in funcmap:
364 l = [f(n) for n, dummy in lines]
364 l = [f(n) for n, dummy in lines]
365 if l:
365 if l:
366 if fm:
366 if fm:
367 formats.append(['%s' for x in l])
367 formats.append(['%s' for x in l])
368 else:
368 else:
369 sizes = [encoding.colwidth(x) for x in l]
369 sizes = [encoding.colwidth(x) for x in l]
370 ml = max(sizes)
370 ml = max(sizes)
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
371 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
372 pieces.append(l)
372 pieces.append(l)
373
373
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
374 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
375 fm.startitem()
375 fm.startitem()
376 fm.write(fields, "".join(f), *p)
376 fm.write(fields, "".join(f), *p)
377 fm.write('line', ": %s", l[1])
377 fm.write('line', ": %s", l[1])
378
378
379 if lines and not lines[-1][1].endswith('\n'):
379 if lines and not lines[-1][1].endswith('\n'):
380 fm.plain('\n')
380 fm.plain('\n')
381
381
382 fm.end()
382 fm.end()
383
383
384 @command('archive',
384 @command('archive',
385 [('', 'no-decode', None, _('do not pass files through decoders')),
385 [('', 'no-decode', None, _('do not pass files through decoders')),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
386 ('p', 'prefix', '', _('directory prefix for files in archive'),
387 _('PREFIX')),
387 _('PREFIX')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
388 ('r', 'rev', '', _('revision to distribute'), _('REV')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
389 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
390 ] + subrepoopts + walkopts,
390 ] + subrepoopts + walkopts,
391 _('[OPTION]... DEST'))
391 _('[OPTION]... DEST'))
392 def archive(ui, repo, dest, **opts):
392 def archive(ui, repo, dest, **opts):
393 '''create an unversioned archive of a repository revision
393 '''create an unversioned archive of a repository revision
394
394
395 By default, the revision used is the parent of the working
395 By default, the revision used is the parent of the working
396 directory; use -r/--rev to specify a different revision.
396 directory; use -r/--rev to specify a different revision.
397
397
398 The archive type is automatically detected based on file
398 The archive type is automatically detected based on file
399 extension (or override using -t/--type).
399 extension (or override using -t/--type).
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 Examples:
403 Examples:
404
404
405 - create a zip file containing the 1.0 release::
405 - create a zip file containing the 1.0 release::
406
406
407 hg archive -r 1.0 project-1.0.zip
407 hg archive -r 1.0 project-1.0.zip
408
408
409 - create a tarball excluding .hg files::
409 - create a tarball excluding .hg files::
410
410
411 hg archive project.tar.gz -X ".hg*"
411 hg archive project.tar.gz -X ".hg*"
412
412
413 Valid types are:
413 Valid types are:
414
414
415 :``files``: a directory full of files (default)
415 :``files``: a directory full of files (default)
416 :``tar``: tar archive, uncompressed
416 :``tar``: tar archive, uncompressed
417 :``tbz2``: tar archive, compressed using bzip2
417 :``tbz2``: tar archive, compressed using bzip2
418 :``tgz``: tar archive, compressed using gzip
418 :``tgz``: tar archive, compressed using gzip
419 :``uzip``: zip archive, uncompressed
419 :``uzip``: zip archive, uncompressed
420 :``zip``: zip archive, compressed using deflate
420 :``zip``: zip archive, compressed using deflate
421
421
422 The exact name of the destination archive or directory is given
422 The exact name of the destination archive or directory is given
423 using a format string; see :hg:`help export` for details.
423 using a format string; see :hg:`help export` for details.
424
424
425 Each member added to an archive file has a directory prefix
425 Each member added to an archive file has a directory prefix
426 prepended. Use -p/--prefix to specify a format string for the
426 prepended. Use -p/--prefix to specify a format string for the
427 prefix. The default is the basename of the archive, with suffixes
427 prefix. The default is the basename of the archive, with suffixes
428 removed.
428 removed.
429
429
430 Returns 0 on success.
430 Returns 0 on success.
431 '''
431 '''
432
432
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
433 ctx = scmutil.revsingle(repo, opts.get('rev'))
434 if not ctx:
434 if not ctx:
435 raise util.Abort(_('no working directory: please specify a revision'))
435 raise util.Abort(_('no working directory: please specify a revision'))
436 node = ctx.node()
436 node = ctx.node()
437 dest = cmdutil.makefilename(repo, dest, node)
437 dest = cmdutil.makefilename(repo, dest, node)
438 if os.path.realpath(dest) == repo.root:
438 if os.path.realpath(dest) == repo.root:
439 raise util.Abort(_('repository root cannot be destination'))
439 raise util.Abort(_('repository root cannot be destination'))
440
440
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
441 kind = opts.get('type') or archival.guesskind(dest) or 'files'
442 prefix = opts.get('prefix')
442 prefix = opts.get('prefix')
443
443
444 if dest == '-':
444 if dest == '-':
445 if kind == 'files':
445 if kind == 'files':
446 raise util.Abort(_('cannot archive plain files to stdout'))
446 raise util.Abort(_('cannot archive plain files to stdout'))
447 dest = cmdutil.makefileobj(repo, dest)
447 dest = cmdutil.makefileobj(repo, dest)
448 if not prefix:
448 if not prefix:
449 prefix = os.path.basename(repo.root) + '-%h'
449 prefix = os.path.basename(repo.root) + '-%h'
450
450
451 prefix = cmdutil.makefilename(repo, prefix, node)
451 prefix = cmdutil.makefilename(repo, prefix, node)
452 matchfn = scmutil.match(ctx, [], opts)
452 matchfn = scmutil.match(ctx, [], opts)
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
453 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
454 matchfn, prefix, subrepos=opts.get('subrepos'))
454 matchfn, prefix, subrepos=opts.get('subrepos'))
455
455
456 @command('backout',
456 @command('backout',
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
457 [('', 'merge', None, _('merge with old dirstate parent after backout')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
458 ('', 'commit', None, _('commit if no conflicts were encountered')),
459 ('', 'parent', '',
459 ('', 'parent', '',
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
460 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
461 ('r', 'rev', '', _('revision to backout'), _('REV')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
462 ('e', 'edit', False, _('invoke editor on commit messages')),
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
463 ] + mergetoolopts + walkopts + commitopts + commitopts2,
464 _('[OPTION]... [-r] REV'))
464 _('[OPTION]... [-r] REV'))
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
465 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
466 '''reverse effect of earlier changeset
466 '''reverse effect of earlier changeset
467
467
468 Prepare a new changeset with the effect of REV undone in the
468 Prepare a new changeset with the effect of REV undone in the
469 current working directory.
469 current working directory.
470
470
471 If REV is the parent of the working directory, then this new changeset
471 If REV is the parent of the working directory, then this new changeset
472 is committed automatically. Otherwise, hg needs to merge the
472 is committed automatically. Otherwise, hg needs to merge the
473 changes and the merged result is left uncommitted.
473 changes and the merged result is left uncommitted.
474
474
475 .. note::
475 .. note::
476
476
477 backout cannot be used to fix either an unwanted or
477 backout cannot be used to fix either an unwanted or
478 incorrect merge.
478 incorrect merge.
479
479
480 .. container:: verbose
480 .. container:: verbose
481
481
482 By default, the pending changeset will have one parent,
482 By default, the pending changeset will have one parent,
483 maintaining a linear history. With --merge, the pending
483 maintaining a linear history. With --merge, the pending
484 changeset will instead have two parents: the old parent of the
484 changeset will instead have two parents: the old parent of the
485 working directory and a new child of REV that simply undoes REV.
485 working directory and a new child of REV that simply undoes REV.
486
486
487 Before version 1.7, the behavior without --merge was equivalent
487 Before version 1.7, the behavior without --merge was equivalent
488 to specifying --merge followed by :hg:`update --clean .` to
488 to specifying --merge followed by :hg:`update --clean .` to
489 cancel the merge and leave the child of REV as a head to be
489 cancel the merge and leave the child of REV as a head to be
490 merged separately.
490 merged separately.
491
491
492 See :hg:`help dates` for a list of formats valid for -d/--date.
492 See :hg:`help dates` for a list of formats valid for -d/--date.
493
493
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
494 Returns 0 on success, 1 if nothing to backout or there are unresolved
495 files.
495 files.
496 '''
496 '''
497 if rev and node:
497 if rev and node:
498 raise util.Abort(_("please specify just one revision"))
498 raise util.Abort(_("please specify just one revision"))
499
499
500 if not rev:
500 if not rev:
501 rev = node
501 rev = node
502
502
503 if not rev:
503 if not rev:
504 raise util.Abort(_("please specify a revision to backout"))
504 raise util.Abort(_("please specify a revision to backout"))
505
505
506 date = opts.get('date')
506 date = opts.get('date')
507 if date:
507 if date:
508 opts['date'] = util.parsedate(date)
508 opts['date'] = util.parsedate(date)
509
509
510 cmdutil.checkunfinished(repo)
510 cmdutil.checkunfinished(repo)
511 cmdutil.bailifchanged(repo)
511 cmdutil.bailifchanged(repo)
512 node = scmutil.revsingle(repo, rev).node()
512 node = scmutil.revsingle(repo, rev).node()
513
513
514 op1, op2 = repo.dirstate.parents()
514 op1, op2 = repo.dirstate.parents()
515 if not repo.changelog.isancestor(node, op1):
515 if not repo.changelog.isancestor(node, op1):
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
516 raise util.Abort(_('cannot backout change that is not an ancestor'))
517
517
518 p1, p2 = repo.changelog.parents(node)
518 p1, p2 = repo.changelog.parents(node)
519 if p1 == nullid:
519 if p1 == nullid:
520 raise util.Abort(_('cannot backout a change with no parents'))
520 raise util.Abort(_('cannot backout a change with no parents'))
521 if p2 != nullid:
521 if p2 != nullid:
522 if not opts.get('parent'):
522 if not opts.get('parent'):
523 raise util.Abort(_('cannot backout a merge changeset'))
523 raise util.Abort(_('cannot backout a merge changeset'))
524 p = repo.lookup(opts['parent'])
524 p = repo.lookup(opts['parent'])
525 if p not in (p1, p2):
525 if p not in (p1, p2):
526 raise util.Abort(_('%s is not a parent of %s') %
526 raise util.Abort(_('%s is not a parent of %s') %
527 (short(p), short(node)))
527 (short(p), short(node)))
528 parent = p
528 parent = p
529 else:
529 else:
530 if opts.get('parent'):
530 if opts.get('parent'):
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
531 raise util.Abort(_('cannot use --parent on non-merge changeset'))
532 parent = p1
532 parent = p1
533
533
534 # the backout should appear on the same branch
534 # the backout should appear on the same branch
535 wlock = repo.wlock()
535 wlock = repo.wlock()
536 try:
536 try:
537 branch = repo.dirstate.branch()
537 branch = repo.dirstate.branch()
538 bheads = repo.branchheads(branch)
538 bheads = repo.branchheads(branch)
539 rctx = scmutil.revsingle(repo, hex(parent))
539 rctx = scmutil.revsingle(repo, hex(parent))
540 if not opts.get('merge') and op1 != node:
540 if not opts.get('merge') and op1 != node:
541 try:
541 try:
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
542 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
543 'backout')
543 'backout')
544 repo.dirstate.beginparentchange()
544 repo.dirstate.beginparentchange()
545 stats = mergemod.update(repo, parent, True, True, False,
545 stats = mergemod.update(repo, parent, True, True, False,
546 node, False)
546 node, False)
547 repo.setparents(op1, op2)
547 repo.setparents(op1, op2)
548 repo.dirstate.endparentchange()
548 repo.dirstate.endparentchange()
549 hg._showstats(repo, stats)
549 hg._showstats(repo, stats)
550 if stats[3]:
550 if stats[3]:
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
551 repo.ui.status(_("use 'hg resolve' to retry unresolved "
552 "file merges\n"))
552 "file merges\n"))
553 return 1
553 return 1
554 elif not commit:
554 elif not commit:
555 msg = _("changeset %s backed out, "
555 msg = _("changeset %s backed out, "
556 "don't forget to commit.\n")
556 "don't forget to commit.\n")
557 ui.status(msg % short(node))
557 ui.status(msg % short(node))
558 return 0
558 return 0
559 finally:
559 finally:
560 ui.setconfig('ui', 'forcemerge', '', '')
560 ui.setconfig('ui', 'forcemerge', '', '')
561 else:
561 else:
562 hg.clean(repo, node, show_stats=False)
562 hg.clean(repo, node, show_stats=False)
563 repo.dirstate.setbranch(branch)
563 repo.dirstate.setbranch(branch)
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
564 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
565
565
566
566
567 def commitfunc(ui, repo, message, match, opts):
567 def commitfunc(ui, repo, message, match, opts):
568 editform = 'backout'
568 editform = 'backout'
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
569 e = cmdutil.getcommiteditor(editform=editform, **opts)
570 if not message:
570 if not message:
571 # we don't translate commit messages
571 # we don't translate commit messages
572 message = "Backed out changeset %s" % short(node)
572 message = "Backed out changeset %s" % short(node)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
573 e = cmdutil.getcommiteditor(edit=True, editform=editform)
574 return repo.commit(message, opts.get('user'), opts.get('date'),
574 return repo.commit(message, opts.get('user'), opts.get('date'),
575 match, editor=e)
575 match, editor=e)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
576 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
577 if not newnode:
577 if not newnode:
578 ui.status(_("nothing changed\n"))
578 ui.status(_("nothing changed\n"))
579 return 1
579 return 1
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
580 cmdutil.commitstatus(repo, newnode, branch, bheads)
581
581
582 def nice(node):
582 def nice(node):
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
583 return '%d:%s' % (repo.changelog.rev(node), short(node))
584 ui.status(_('changeset %s backs out changeset %s\n') %
584 ui.status(_('changeset %s backs out changeset %s\n') %
585 (nice(repo.changelog.tip()), nice(node)))
585 (nice(repo.changelog.tip()), nice(node)))
586 if opts.get('merge') and op1 != node:
586 if opts.get('merge') and op1 != node:
587 hg.clean(repo, op1, show_stats=False)
587 hg.clean(repo, op1, show_stats=False)
588 ui.status(_('merging with changeset %s\n')
588 ui.status(_('merging with changeset %s\n')
589 % nice(repo.changelog.tip()))
589 % nice(repo.changelog.tip()))
590 try:
590 try:
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
592 'backout')
592 'backout')
593 return hg.merge(repo, hex(repo.changelog.tip()))
593 return hg.merge(repo, hex(repo.changelog.tip()))
594 finally:
594 finally:
595 ui.setconfig('ui', 'forcemerge', '', '')
595 ui.setconfig('ui', 'forcemerge', '', '')
596 finally:
596 finally:
597 wlock.release()
597 wlock.release()
598 return 0
598 return 0
599
599
600 @command('bisect',
600 @command('bisect',
601 [('r', 'reset', False, _('reset bisect state')),
601 [('r', 'reset', False, _('reset bisect state')),
602 ('g', 'good', False, _('mark changeset good')),
602 ('g', 'good', False, _('mark changeset good')),
603 ('b', 'bad', False, _('mark changeset bad')),
603 ('b', 'bad', False, _('mark changeset bad')),
604 ('s', 'skip', False, _('skip testing changeset')),
604 ('s', 'skip', False, _('skip testing changeset')),
605 ('e', 'extend', False, _('extend the bisect range')),
605 ('e', 'extend', False, _('extend the bisect range')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
606 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
607 ('U', 'noupdate', False, _('do not update to target'))],
607 ('U', 'noupdate', False, _('do not update to target'))],
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
608 _("[-gbsr] [-U] [-c CMD] [REV]"))
609 def bisect(ui, repo, rev=None, extra=None, command=None,
609 def bisect(ui, repo, rev=None, extra=None, command=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
610 reset=None, good=None, bad=None, skip=None, extend=None,
611 noupdate=None):
611 noupdate=None):
612 """subdivision search of changesets
612 """subdivision search of changesets
613
613
614 This command helps to find changesets which introduce problems. To
614 This command helps to find changesets which introduce problems. To
615 use, mark the earliest changeset you know exhibits the problem as
615 use, mark the earliest changeset you know exhibits the problem as
616 bad, then mark the latest changeset which is free from the problem
616 bad, then mark the latest changeset which is free from the problem
617 as good. Bisect will update your working directory to a revision
617 as good. Bisect will update your working directory to a revision
618 for testing (unless the -U/--noupdate option is specified). Once
618 for testing (unless the -U/--noupdate option is specified). Once
619 you have performed tests, mark the working directory as good or
619 you have performed tests, mark the working directory as good or
620 bad, and bisect will either update to another candidate changeset
620 bad, and bisect will either update to another candidate changeset
621 or announce that it has found the bad revision.
621 or announce that it has found the bad revision.
622
622
623 As a shortcut, you can also use the revision argument to mark a
623 As a shortcut, you can also use the revision argument to mark a
624 revision as good or bad without checking it out first.
624 revision as good or bad without checking it out first.
625
625
626 If you supply a command, it will be used for automatic bisection.
626 If you supply a command, it will be used for automatic bisection.
627 The environment variable HG_NODE will contain the ID of the
627 The environment variable HG_NODE will contain the ID of the
628 changeset being tested. The exit status of the command will be
628 changeset being tested. The exit status of the command will be
629 used to mark revisions as good or bad: status 0 means good, 125
629 used to mark revisions as good or bad: status 0 means good, 125
630 means to skip the revision, 127 (command not found) will abort the
630 means to skip the revision, 127 (command not found) will abort the
631 bisection, and any other non-zero exit status means the revision
631 bisection, and any other non-zero exit status means the revision
632 is bad.
632 is bad.
633
633
634 .. container:: verbose
634 .. container:: verbose
635
635
636 Some examples:
636 Some examples:
637
637
638 - start a bisection with known bad revision 34, and good revision 12::
638 - start a bisection with known bad revision 34, and good revision 12::
639
639
640 hg bisect --bad 34
640 hg bisect --bad 34
641 hg bisect --good 12
641 hg bisect --good 12
642
642
643 - advance the current bisection by marking current revision as good or
643 - advance the current bisection by marking current revision as good or
644 bad::
644 bad::
645
645
646 hg bisect --good
646 hg bisect --good
647 hg bisect --bad
647 hg bisect --bad
648
648
649 - mark the current revision, or a known revision, to be skipped (e.g. if
649 - mark the current revision, or a known revision, to be skipped (e.g. if
650 that revision is not usable because of another issue)::
650 that revision is not usable because of another issue)::
651
651
652 hg bisect --skip
652 hg bisect --skip
653 hg bisect --skip 23
653 hg bisect --skip 23
654
654
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
655 - skip all revisions that do not touch directories ``foo`` or ``bar``::
656
656
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
657 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
658
658
659 - forget the current bisection::
659 - forget the current bisection::
660
660
661 hg bisect --reset
661 hg bisect --reset
662
662
663 - use 'make && make tests' to automatically find the first broken
663 - use 'make && make tests' to automatically find the first broken
664 revision::
664 revision::
665
665
666 hg bisect --reset
666 hg bisect --reset
667 hg bisect --bad 34
667 hg bisect --bad 34
668 hg bisect --good 12
668 hg bisect --good 12
669 hg bisect --command "make && make tests"
669 hg bisect --command "make && make tests"
670
670
671 - see all changesets whose states are already known in the current
671 - see all changesets whose states are already known in the current
672 bisection::
672 bisection::
673
673
674 hg log -r "bisect(pruned)"
674 hg log -r "bisect(pruned)"
675
675
676 - see the changeset currently being bisected (especially useful
676 - see the changeset currently being bisected (especially useful
677 if running with -U/--noupdate)::
677 if running with -U/--noupdate)::
678
678
679 hg log -r "bisect(current)"
679 hg log -r "bisect(current)"
680
680
681 - see all changesets that took part in the current bisection::
681 - see all changesets that took part in the current bisection::
682
682
683 hg log -r "bisect(range)"
683 hg log -r "bisect(range)"
684
684
685 - you can even get a nice graph::
685 - you can even get a nice graph::
686
686
687 hg log --graph -r "bisect(range)"
687 hg log --graph -r "bisect(range)"
688
688
689 See :hg:`help revsets` for more about the `bisect()` keyword.
689 See :hg:`help revsets` for more about the `bisect()` keyword.
690
690
691 Returns 0 on success.
691 Returns 0 on success.
692 """
692 """
693 def extendbisectrange(nodes, good):
693 def extendbisectrange(nodes, good):
694 # bisect is incomplete when it ends on a merge node and
694 # bisect is incomplete when it ends on a merge node and
695 # one of the parent was not checked.
695 # one of the parent was not checked.
696 parents = repo[nodes[0]].parents()
696 parents = repo[nodes[0]].parents()
697 if len(parents) > 1:
697 if len(parents) > 1:
698 if good:
698 if good:
699 side = state['bad']
699 side = state['bad']
700 else:
700 else:
701 side = state['good']
701 side = state['good']
702 num = len(set(i.node() for i in parents) & set(side))
702 num = len(set(i.node() for i in parents) & set(side))
703 if num == 1:
703 if num == 1:
704 return parents[0].ancestor(parents[1])
704 return parents[0].ancestor(parents[1])
705 return None
705 return None
706
706
707 def print_result(nodes, good):
707 def print_result(nodes, good):
708 displayer = cmdutil.show_changeset(ui, repo, {})
708 displayer = cmdutil.show_changeset(ui, repo, {})
709 if len(nodes) == 1:
709 if len(nodes) == 1:
710 # narrowed it down to a single revision
710 # narrowed it down to a single revision
711 if good:
711 if good:
712 ui.write(_("The first good revision is:\n"))
712 ui.write(_("The first good revision is:\n"))
713 else:
713 else:
714 ui.write(_("The first bad revision is:\n"))
714 ui.write(_("The first bad revision is:\n"))
715 displayer.show(repo[nodes[0]])
715 displayer.show(repo[nodes[0]])
716 extendnode = extendbisectrange(nodes, good)
716 extendnode = extendbisectrange(nodes, good)
717 if extendnode is not None:
717 if extendnode is not None:
718 ui.write(_('Not all ancestors of this changeset have been'
718 ui.write(_('Not all ancestors of this changeset have been'
719 ' checked.\nUse bisect --extend to continue the '
719 ' checked.\nUse bisect --extend to continue the '
720 'bisection from\nthe common ancestor, %s.\n')
720 'bisection from\nthe common ancestor, %s.\n')
721 % extendnode)
721 % extendnode)
722 else:
722 else:
723 # multiple possible revisions
723 # multiple possible revisions
724 if good:
724 if good:
725 ui.write(_("Due to skipped revisions, the first "
725 ui.write(_("Due to skipped revisions, the first "
726 "good revision could be any of:\n"))
726 "good revision could be any of:\n"))
727 else:
727 else:
728 ui.write(_("Due to skipped revisions, the first "
728 ui.write(_("Due to skipped revisions, the first "
729 "bad revision could be any of:\n"))
729 "bad revision could be any of:\n"))
730 for n in nodes:
730 for n in nodes:
731 displayer.show(repo[n])
731 displayer.show(repo[n])
732 displayer.close()
732 displayer.close()
733
733
734 def check_state(state, interactive=True):
734 def check_state(state, interactive=True):
735 if not state['good'] or not state['bad']:
735 if not state['good'] or not state['bad']:
736 if (good or bad or skip or reset) and interactive:
736 if (good or bad or skip or reset) and interactive:
737 return
737 return
738 if not state['good']:
738 if not state['good']:
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
739 raise util.Abort(_('cannot bisect (no known good revisions)'))
740 else:
740 else:
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
741 raise util.Abort(_('cannot bisect (no known bad revisions)'))
742 return True
742 return True
743
743
744 # backward compatibility
744 # backward compatibility
745 if rev in "good bad reset init".split():
745 if rev in "good bad reset init".split():
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
746 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
747 cmd, rev, extra = rev, extra, None
747 cmd, rev, extra = rev, extra, None
748 if cmd == "good":
748 if cmd == "good":
749 good = True
749 good = True
750 elif cmd == "bad":
750 elif cmd == "bad":
751 bad = True
751 bad = True
752 else:
752 else:
753 reset = True
753 reset = True
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
754 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
755 raise util.Abort(_('incompatible arguments'))
755 raise util.Abort(_('incompatible arguments'))
756
756
757 cmdutil.checkunfinished(repo)
757 cmdutil.checkunfinished(repo)
758
758
759 if reset:
759 if reset:
760 p = repo.join("bisect.state")
760 p = repo.join("bisect.state")
761 if os.path.exists(p):
761 if os.path.exists(p):
762 os.unlink(p)
762 os.unlink(p)
763 return
763 return
764
764
765 state = hbisect.load_state(repo)
765 state = hbisect.load_state(repo)
766
766
767 if command:
767 if command:
768 changesets = 1
768 changesets = 1
769 if noupdate:
769 if noupdate:
770 try:
770 try:
771 node = state['current'][0]
771 node = state['current'][0]
772 except LookupError:
772 except LookupError:
773 raise util.Abort(_('current bisect revision is unknown - '
773 raise util.Abort(_('current bisect revision is unknown - '
774 'start a new bisect to fix'))
774 'start a new bisect to fix'))
775 else:
775 else:
776 node, p2 = repo.dirstate.parents()
776 node, p2 = repo.dirstate.parents()
777 if p2 != nullid:
777 if p2 != nullid:
778 raise util.Abort(_('current bisect revision is a merge'))
778 raise util.Abort(_('current bisect revision is a merge'))
779 try:
779 try:
780 while changesets:
780 while changesets:
781 # update state
781 # update state
782 state['current'] = [node]
782 state['current'] = [node]
783 hbisect.save_state(repo, state)
783 hbisect.save_state(repo, state)
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
784 status = ui.system(command, environ={'HG_NODE': hex(node)})
785 if status == 125:
785 if status == 125:
786 transition = "skip"
786 transition = "skip"
787 elif status == 0:
787 elif status == 0:
788 transition = "good"
788 transition = "good"
789 # status < 0 means process was killed
789 # status < 0 means process was killed
790 elif status == 127:
790 elif status == 127:
791 raise util.Abort(_("failed to execute %s") % command)
791 raise util.Abort(_("failed to execute %s") % command)
792 elif status < 0:
792 elif status < 0:
793 raise util.Abort(_("%s killed") % command)
793 raise util.Abort(_("%s killed") % command)
794 else:
794 else:
795 transition = "bad"
795 transition = "bad"
796 ctx = scmutil.revsingle(repo, rev, node)
796 ctx = scmutil.revsingle(repo, rev, node)
797 rev = None # clear for future iterations
797 rev = None # clear for future iterations
798 state[transition].append(ctx.node())
798 state[transition].append(ctx.node())
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
799 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
800 check_state(state, interactive=False)
800 check_state(state, interactive=False)
801 # bisect
801 # bisect
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
802 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
803 # update to next check
803 # update to next check
804 node = nodes[0]
804 node = nodes[0]
805 if not noupdate:
805 if not noupdate:
806 cmdutil.bailifchanged(repo)
806 cmdutil.bailifchanged(repo)
807 hg.clean(repo, node, show_stats=False)
807 hg.clean(repo, node, show_stats=False)
808 finally:
808 finally:
809 state['current'] = [node]
809 state['current'] = [node]
810 hbisect.save_state(repo, state)
810 hbisect.save_state(repo, state)
811 print_result(nodes, bgood)
811 print_result(nodes, bgood)
812 return
812 return
813
813
814 # update state
814 # update state
815
815
816 if rev:
816 if rev:
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
817 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
818 else:
818 else:
819 nodes = [repo.lookup('.')]
819 nodes = [repo.lookup('.')]
820
820
821 if good or bad or skip:
821 if good or bad or skip:
822 if good:
822 if good:
823 state['good'] += nodes
823 state['good'] += nodes
824 elif bad:
824 elif bad:
825 state['bad'] += nodes
825 state['bad'] += nodes
826 elif skip:
826 elif skip:
827 state['skip'] += nodes
827 state['skip'] += nodes
828 hbisect.save_state(repo, state)
828 hbisect.save_state(repo, state)
829
829
830 if not check_state(state):
830 if not check_state(state):
831 return
831 return
832
832
833 # actually bisect
833 # actually bisect
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
834 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
835 if extend:
835 if extend:
836 if not changesets:
836 if not changesets:
837 extendnode = extendbisectrange(nodes, good)
837 extendnode = extendbisectrange(nodes, good)
838 if extendnode is not None:
838 if extendnode is not None:
839 ui.write(_("Extending search to changeset %d:%s\n")
839 ui.write(_("Extending search to changeset %d:%s\n")
840 % (extendnode.rev(), extendnode))
840 % (extendnode.rev(), extendnode))
841 state['current'] = [extendnode.node()]
841 state['current'] = [extendnode.node()]
842 hbisect.save_state(repo, state)
842 hbisect.save_state(repo, state)
843 if noupdate:
843 if noupdate:
844 return
844 return
845 cmdutil.bailifchanged(repo)
845 cmdutil.bailifchanged(repo)
846 return hg.clean(repo, extendnode.node())
846 return hg.clean(repo, extendnode.node())
847 raise util.Abort(_("nothing to extend"))
847 raise util.Abort(_("nothing to extend"))
848
848
849 if changesets == 0:
849 if changesets == 0:
850 print_result(nodes, good)
850 print_result(nodes, good)
851 else:
851 else:
852 assert len(nodes) == 1 # only a single node can be tested next
852 assert len(nodes) == 1 # only a single node can be tested next
853 node = nodes[0]
853 node = nodes[0]
854 # compute the approximate number of remaining tests
854 # compute the approximate number of remaining tests
855 tests, size = 0, 2
855 tests, size = 0, 2
856 while size <= changesets:
856 while size <= changesets:
857 tests, size = tests + 1, size * 2
857 tests, size = tests + 1, size * 2
858 rev = repo.changelog.rev(node)
858 rev = repo.changelog.rev(node)
859 ui.write(_("Testing changeset %d:%s "
859 ui.write(_("Testing changeset %d:%s "
860 "(%d changesets remaining, ~%d tests)\n")
860 "(%d changesets remaining, ~%d tests)\n")
861 % (rev, short(node), changesets, tests))
861 % (rev, short(node), changesets, tests))
862 state['current'] = [node]
862 state['current'] = [node]
863 hbisect.save_state(repo, state)
863 hbisect.save_state(repo, state)
864 if not noupdate:
864 if not noupdate:
865 cmdutil.bailifchanged(repo)
865 cmdutil.bailifchanged(repo)
866 return hg.clean(repo, node)
866 return hg.clean(repo, node)
867
867
868 @command('bookmarks|bookmark',
868 @command('bookmarks|bookmark',
869 [('f', 'force', False, _('force')),
869 [('f', 'force', False, _('force')),
870 ('r', 'rev', '', _('revision'), _('REV')),
870 ('r', 'rev', '', _('revision'), _('REV')),
871 ('d', 'delete', False, _('delete a given bookmark')),
871 ('d', 'delete', False, _('delete a given bookmark')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
872 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
873 ('i', 'inactive', False, _('mark a bookmark inactive')),
874 ] + formatteropts,
874 ] + formatteropts,
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
875 _('hg bookmarks [OPTIONS]... [NAME]...'))
876 def bookmark(ui, repo, *names, **opts):
876 def bookmark(ui, repo, *names, **opts):
877 '''create a new bookmark or list existing bookmarks
877 '''create a new bookmark or list existing bookmarks
878
878
879 Bookmarks are labels on changesets to help track lines of development.
879 Bookmarks are labels on changesets to help track lines of development.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
880 Bookmarks are unversioned and can be moved, renamed and deleted.
881 Deleting or moving a bookmark has no effect on the associated changesets.
881 Deleting or moving a bookmark has no effect on the associated changesets.
882
882
883 Creating or updating to a bookmark causes it to be marked as 'active'.
883 Creating or updating to a bookmark causes it to be marked as 'active'.
884 The active bookmark is indicated with a '*'.
884 The active bookmark is indicated with a '*'.
885 When a commit is made, the active bookmark will advance to the new commit.
885 When a commit is made, the active bookmark will advance to the new commit.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
886 A plain :hg:`update` will also advance an active bookmark, if possible.
887 Updating away from a bookmark will cause it to be deactivated.
887 Updating away from a bookmark will cause it to be deactivated.
888
888
889 Bookmarks can be pushed and pulled between repositories (see
889 Bookmarks can be pushed and pulled between repositories (see
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
890 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
891 diverged, a new 'divergent bookmark' of the form 'name@path' will
892 be created. Using :hg:`merge` will resolve the divergence.
892 be created. Using :hg:`merge` will resolve the divergence.
893
893
894 A bookmark named '@' has the special property that :hg:`clone` will
894 A bookmark named '@' has the special property that :hg:`clone` will
895 check it out by default if it exists.
895 check it out by default if it exists.
896
896
897 .. container:: verbose
897 .. container:: verbose
898
898
899 Examples:
899 Examples:
900
900
901 - create an active bookmark for a new line of development::
901 - create an active bookmark for a new line of development::
902
902
903 hg book new-feature
903 hg book new-feature
904
904
905 - create an inactive bookmark as a place marker::
905 - create an inactive bookmark as a place marker::
906
906
907 hg book -i reviewed
907 hg book -i reviewed
908
908
909 - create an inactive bookmark on another changeset::
909 - create an inactive bookmark on another changeset::
910
910
911 hg book -r .^ tested
911 hg book -r .^ tested
912
912
913 - move the '@' bookmark from another branch::
913 - move the '@' bookmark from another branch::
914
914
915 hg book -f @
915 hg book -f @
916 '''
916 '''
917 force = opts.get('force')
917 force = opts.get('force')
918 rev = opts.get('rev')
918 rev = opts.get('rev')
919 delete = opts.get('delete')
919 delete = opts.get('delete')
920 rename = opts.get('rename')
920 rename = opts.get('rename')
921 inactive = opts.get('inactive')
921 inactive = opts.get('inactive')
922
922
923 def checkformat(mark):
923 def checkformat(mark):
924 mark = mark.strip()
924 mark = mark.strip()
925 if not mark:
925 if not mark:
926 raise util.Abort(_("bookmark names cannot consist entirely of "
926 raise util.Abort(_("bookmark names cannot consist entirely of "
927 "whitespace"))
927 "whitespace"))
928 scmutil.checknewlabel(repo, mark, 'bookmark')
928 scmutil.checknewlabel(repo, mark, 'bookmark')
929 return mark
929 return mark
930
930
931 def checkconflict(repo, mark, cur, force=False, target=None):
931 def checkconflict(repo, mark, cur, force=False, target=None):
932 if mark in marks and not force:
932 if mark in marks and not force:
933 if target:
933 if target:
934 if marks[mark] == target and target == cur:
934 if marks[mark] == target and target == cur:
935 # re-activating a bookmark
935 # re-activating a bookmark
936 return
936 return
937 anc = repo.changelog.ancestors([repo[target].rev()])
937 anc = repo.changelog.ancestors([repo[target].rev()])
938 bmctx = repo[marks[mark]]
938 bmctx = repo[marks[mark]]
939 divs = [repo[b].node() for b in marks
939 divs = [repo[b].node() for b in marks
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
940 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
941
941
942 # allow resolving a single divergent bookmark even if moving
942 # allow resolving a single divergent bookmark even if moving
943 # the bookmark across branches when a revision is specified
943 # the bookmark across branches when a revision is specified
944 # that contains a divergent bookmark
944 # that contains a divergent bookmark
945 if bmctx.rev() not in anc and target in divs:
945 if bmctx.rev() not in anc and target in divs:
946 bookmarks.deletedivergent(repo, [target], mark)
946 bookmarks.deletedivergent(repo, [target], mark)
947 return
947 return
948
948
949 deletefrom = [b for b in divs
949 deletefrom = [b for b in divs
950 if repo[b].rev() in anc or b == target]
950 if repo[b].rev() in anc or b == target]
951 bookmarks.deletedivergent(repo, deletefrom, mark)
951 bookmarks.deletedivergent(repo, deletefrom, mark)
952 if bookmarks.validdest(repo, bmctx, repo[target]):
952 if bookmarks.validdest(repo, bmctx, repo[target]):
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
953 ui.status(_("moving bookmark '%s' forward from %s\n") %
954 (mark, short(bmctx.node())))
954 (mark, short(bmctx.node())))
955 return
955 return
956 raise util.Abort(_("bookmark '%s' already exists "
956 raise util.Abort(_("bookmark '%s' already exists "
957 "(use -f to force)") % mark)
957 "(use -f to force)") % mark)
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
958 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
959 and not force):
959 and not force):
960 raise util.Abort(
960 raise util.Abort(
961 _("a bookmark cannot have the name of an existing branch"))
961 _("a bookmark cannot have the name of an existing branch"))
962
962
963 if delete and rename:
963 if delete and rename:
964 raise util.Abort(_("--delete and --rename are incompatible"))
964 raise util.Abort(_("--delete and --rename are incompatible"))
965 if delete and rev:
965 if delete and rev:
966 raise util.Abort(_("--rev is incompatible with --delete"))
966 raise util.Abort(_("--rev is incompatible with --delete"))
967 if rename and rev:
967 if rename and rev:
968 raise util.Abort(_("--rev is incompatible with --rename"))
968 raise util.Abort(_("--rev is incompatible with --rename"))
969 if not names and (delete or rev):
969 if not names and (delete or rev):
970 raise util.Abort(_("bookmark name required"))
970 raise util.Abort(_("bookmark name required"))
971
971
972 if delete or rename or names or inactive:
972 if delete or rename or names or inactive:
973 wlock = repo.wlock()
973 wlock = repo.wlock()
974 try:
974 try:
975 cur = repo.changectx('.').node()
975 cur = repo.changectx('.').node()
976 marks = repo._bookmarks
976 marks = repo._bookmarks
977 if delete:
977 if delete:
978 for mark in names:
978 for mark in names:
979 if mark not in marks:
979 if mark not in marks:
980 raise util.Abort(_("bookmark '%s' does not exist") %
980 raise util.Abort(_("bookmark '%s' does not exist") %
981 mark)
981 mark)
982 if mark == repo._bookmarkcurrent:
982 if mark == repo._bookmarkcurrent:
983 bookmarks.unsetcurrent(repo)
983 bookmarks.unsetcurrent(repo)
984 del marks[mark]
984 del marks[mark]
985 marks.write()
985 marks.write()
986
986
987 elif rename:
987 elif rename:
988 if not names:
988 if not names:
989 raise util.Abort(_("new bookmark name required"))
989 raise util.Abort(_("new bookmark name required"))
990 elif len(names) > 1:
990 elif len(names) > 1:
991 raise util.Abort(_("only one new bookmark name allowed"))
991 raise util.Abort(_("only one new bookmark name allowed"))
992 mark = checkformat(names[0])
992 mark = checkformat(names[0])
993 if rename not in marks:
993 if rename not in marks:
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
994 raise util.Abort(_("bookmark '%s' does not exist") % rename)
995 checkconflict(repo, mark, cur, force)
995 checkconflict(repo, mark, cur, force)
996 marks[mark] = marks[rename]
996 marks[mark] = marks[rename]
997 if repo._bookmarkcurrent == rename and not inactive:
997 if repo._bookmarkcurrent == rename and not inactive:
998 bookmarks.setcurrent(repo, mark)
998 bookmarks.setcurrent(repo, mark)
999 del marks[rename]
999 del marks[rename]
1000 marks.write()
1000 marks.write()
1001
1001
1002 elif names:
1002 elif names:
1003 newact = None
1003 newact = None
1004 for mark in names:
1004 for mark in names:
1005 mark = checkformat(mark)
1005 mark = checkformat(mark)
1006 if newact is None:
1006 if newact is None:
1007 newact = mark
1007 newact = mark
1008 if inactive and mark == repo._bookmarkcurrent:
1008 if inactive and mark == repo._bookmarkcurrent:
1009 bookmarks.unsetcurrent(repo)
1009 bookmarks.unsetcurrent(repo)
1010 return
1010 return
1011 tgt = cur
1011 tgt = cur
1012 if rev:
1012 if rev:
1013 tgt = scmutil.revsingle(repo, rev).node()
1013 tgt = scmutil.revsingle(repo, rev).node()
1014 checkconflict(repo, mark, cur, force, tgt)
1014 checkconflict(repo, mark, cur, force, tgt)
1015 marks[mark] = tgt
1015 marks[mark] = tgt
1016 if not inactive and cur == marks[newact] and not rev:
1016 if not inactive and cur == marks[newact] and not rev:
1017 bookmarks.setcurrent(repo, newact)
1017 bookmarks.setcurrent(repo, newact)
1018 elif cur != tgt and newact == repo._bookmarkcurrent:
1018 elif cur != tgt and newact == repo._bookmarkcurrent:
1019 bookmarks.unsetcurrent(repo)
1019 bookmarks.unsetcurrent(repo)
1020 marks.write()
1020 marks.write()
1021
1021
1022 elif inactive:
1022 elif inactive:
1023 if len(marks) == 0:
1023 if len(marks) == 0:
1024 ui.status(_("no bookmarks set\n"))
1024 ui.status(_("no bookmarks set\n"))
1025 elif not repo._bookmarkcurrent:
1025 elif not repo._bookmarkcurrent:
1026 ui.status(_("no active bookmark\n"))
1026 ui.status(_("no active bookmark\n"))
1027 else:
1027 else:
1028 bookmarks.unsetcurrent(repo)
1028 bookmarks.unsetcurrent(repo)
1029 finally:
1029 finally:
1030 wlock.release()
1030 wlock.release()
1031 else: # show bookmarks
1031 else: # show bookmarks
1032 fm = ui.formatter('bookmarks', opts)
1032 fm = ui.formatter('bookmarks', opts)
1033 hexfn = fm.hexfunc
1033 hexfn = fm.hexfunc
1034 marks = repo._bookmarks
1034 marks = repo._bookmarks
1035 if len(marks) == 0 and not fm:
1035 if len(marks) == 0 and not fm:
1036 ui.status(_("no bookmarks set\n"))
1036 ui.status(_("no bookmarks set\n"))
1037 for bmark, n in sorted(marks.iteritems()):
1037 for bmark, n in sorted(marks.iteritems()):
1038 current = repo._bookmarkcurrent
1038 current = repo._bookmarkcurrent
1039 if bmark == current:
1039 if bmark == current:
1040 prefix, label = '*', 'bookmarks.current'
1040 prefix, label = '*', 'bookmarks.current'
1041 else:
1041 else:
1042 prefix, label = ' ', ''
1042 prefix, label = ' ', ''
1043
1043
1044 fm.startitem()
1044 fm.startitem()
1045 if not ui.quiet:
1045 if not ui.quiet:
1046 fm.plain(' %s ' % prefix, label=label)
1046 fm.plain(' %s ' % prefix, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1047 fm.write('bookmark', '%s', bmark, label=label)
1048 pad = " " * (25 - encoding.colwidth(bmark))
1048 pad = " " * (25 - encoding.colwidth(bmark))
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1049 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1050 repo.changelog.rev(n), hexfn(n), label=label)
1050 repo.changelog.rev(n), hexfn(n), label=label)
1051 fm.data(active=(bmark == current))
1051 fm.data(active=(bmark == current))
1052 fm.plain('\n')
1052 fm.plain('\n')
1053 fm.end()
1053 fm.end()
1054
1054
1055 @command('branch',
1055 @command('branch',
1056 [('f', 'force', None,
1056 [('f', 'force', None,
1057 _('set branch name even if it shadows an existing branch')),
1057 _('set branch name even if it shadows an existing branch')),
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1058 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1059 _('[-fC] [NAME]'))
1059 _('[-fC] [NAME]'))
1060 def branch(ui, repo, label=None, **opts):
1060 def branch(ui, repo, label=None, **opts):
1061 """set or show the current branch name
1061 """set or show the current branch name
1062
1062
1063 .. note::
1063 .. note::
1064
1064
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1065 Branch names are permanent and global. Use :hg:`bookmark` to create a
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1066 light-weight bookmark instead. See :hg:`help glossary` for more
1067 information about named branches and bookmarks.
1067 information about named branches and bookmarks.
1068
1068
1069 With no argument, show the current branch name. With one argument,
1069 With no argument, show the current branch name. With one argument,
1070 set the working directory branch name (the branch will not exist
1070 set the working directory branch name (the branch will not exist
1071 in the repository until the next commit). Standard practice
1071 in the repository until the next commit). Standard practice
1072 recommends that primary development take place on the 'default'
1072 recommends that primary development take place on the 'default'
1073 branch.
1073 branch.
1074
1074
1075 Unless -f/--force is specified, branch will not let you set a
1075 Unless -f/--force is specified, branch will not let you set a
1076 branch name that already exists.
1076 branch name that already exists.
1077
1077
1078 Use -C/--clean to reset the working directory branch to that of
1078 Use -C/--clean to reset the working directory branch to that of
1079 the parent of the working directory, negating a previous branch
1079 the parent of the working directory, negating a previous branch
1080 change.
1080 change.
1081
1081
1082 Use the command :hg:`update` to switch to an existing branch. Use
1082 Use the command :hg:`update` to switch to an existing branch. Use
1083 :hg:`commit --close-branch` to mark this branch as closed.
1083 :hg:`commit --close-branch` to mark this branch as closed.
1084
1084
1085 Returns 0 on success.
1085 Returns 0 on success.
1086 """
1086 """
1087 if label:
1087 if label:
1088 label = label.strip()
1088 label = label.strip()
1089
1089
1090 if not opts.get('clean') and not label:
1090 if not opts.get('clean') and not label:
1091 ui.write("%s\n" % repo.dirstate.branch())
1091 ui.write("%s\n" % repo.dirstate.branch())
1092 return
1092 return
1093
1093
1094 wlock = repo.wlock()
1094 wlock = repo.wlock()
1095 try:
1095 try:
1096 if opts.get('clean'):
1096 if opts.get('clean'):
1097 label = repo[None].p1().branch()
1097 label = repo[None].p1().branch()
1098 repo.dirstate.setbranch(label)
1098 repo.dirstate.setbranch(label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1099 ui.status(_('reset working directory to branch %s\n') % label)
1100 elif label:
1100 elif label:
1101 if not opts.get('force') and label in repo.branchmap():
1101 if not opts.get('force') and label in repo.branchmap():
1102 if label not in [p.branch() for p in repo.parents()]:
1102 if label not in [p.branch() for p in repo.parents()]:
1103 raise util.Abort(_('a branch of the same name already'
1103 raise util.Abort(_('a branch of the same name already'
1104 ' exists'),
1104 ' exists'),
1105 # i18n: "it" refers to an existing branch
1105 # i18n: "it" refers to an existing branch
1106 hint=_("use 'hg update' to switch to it"))
1106 hint=_("use 'hg update' to switch to it"))
1107 scmutil.checknewlabel(repo, label, 'branch')
1107 scmutil.checknewlabel(repo, label, 'branch')
1108 repo.dirstate.setbranch(label)
1108 repo.dirstate.setbranch(label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1109 ui.status(_('marked working directory as branch %s\n') % label)
1110 ui.status(_('(branches are permanent and global, '
1110 ui.status(_('(branches are permanent and global, '
1111 'did you want a bookmark?)\n'))
1111 'did you want a bookmark?)\n'))
1112 finally:
1112 finally:
1113 wlock.release()
1113 wlock.release()
1114
1114
1115 @command('branches',
1115 @command('branches',
1116 [('a', 'active', False,
1116 [('a', 'active', False,
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1117 _('show only branches that have unmerged heads (DEPRECATED)')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1118 ('c', 'closed', False, _('show normal and closed branches')),
1119 ] + formatteropts,
1119 ] + formatteropts,
1120 _('[-ac]'))
1120 _('[-ac]'))
1121 def branches(ui, repo, active=False, closed=False, **opts):
1121 def branches(ui, repo, active=False, closed=False, **opts):
1122 """list repository named branches
1122 """list repository named branches
1123
1123
1124 List the repository's named branches, indicating which ones are
1124 List the repository's named branches, indicating which ones are
1125 inactive. If -c/--closed is specified, also list branches which have
1125 inactive. If -c/--closed is specified, also list branches which have
1126 been marked closed (see :hg:`commit --close-branch`).
1126 been marked closed (see :hg:`commit --close-branch`).
1127
1127
1128 Use the command :hg:`update` to switch to an existing branch.
1128 Use the command :hg:`update` to switch to an existing branch.
1129
1129
1130 Returns 0.
1130 Returns 0.
1131 """
1131 """
1132
1132
1133 fm = ui.formatter('branches', opts)
1133 fm = ui.formatter('branches', opts)
1134 hexfunc = fm.hexfunc
1134 hexfunc = fm.hexfunc
1135
1135
1136 allheads = set(repo.heads())
1136 allheads = set(repo.heads())
1137 branches = []
1137 branches = []
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1138 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1139 isactive = not isclosed and bool(set(heads) & allheads)
1139 isactive = not isclosed and bool(set(heads) & allheads)
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1140 branches.append((tag, repo[tip], isactive, not isclosed))
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1141 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1142 reverse=True)
1142 reverse=True)
1143
1143
1144 for tag, ctx, isactive, isopen in branches:
1144 for tag, ctx, isactive, isopen in branches:
1145 if active and not isactive:
1145 if active and not isactive:
1146 continue
1146 continue
1147 if isactive:
1147 if isactive:
1148 label = 'branches.active'
1148 label = 'branches.active'
1149 notice = ''
1149 notice = ''
1150 elif not isopen:
1150 elif not isopen:
1151 if not closed:
1151 if not closed:
1152 continue
1152 continue
1153 label = 'branches.closed'
1153 label = 'branches.closed'
1154 notice = _(' (closed)')
1154 notice = _(' (closed)')
1155 else:
1155 else:
1156 label = 'branches.inactive'
1156 label = 'branches.inactive'
1157 notice = _(' (inactive)')
1157 notice = _(' (inactive)')
1158 current = (tag == repo.dirstate.branch())
1158 current = (tag == repo.dirstate.branch())
1159 if current:
1159 if current:
1160 label = 'branches.current'
1160 label = 'branches.current'
1161
1161
1162 fm.startitem()
1162 fm.startitem()
1163 fm.write('branch', '%s', tag, label=label)
1163 fm.write('branch', '%s', tag, label=label)
1164 rev = ctx.rev()
1164 rev = ctx.rev()
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1165 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1166 fmt = ' ' * padsize + ' %d:%s'
1166 fmt = ' ' * padsize + ' %d:%s'
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1167 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1168 label='log.changeset changeset.%s' % ctx.phasestr())
1169 fm.data(active=isactive, closed=not isopen, current=current)
1169 fm.data(active=isactive, closed=not isopen, current=current)
1170 if not ui.quiet:
1170 if not ui.quiet:
1171 fm.plain(notice)
1171 fm.plain(notice)
1172 fm.plain('\n')
1172 fm.plain('\n')
1173 fm.end()
1173 fm.end()
1174
1174
1175 @command('bundle',
1175 @command('bundle',
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1176 [('f', 'force', None, _('run even when the destination is unrelated')),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1177 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1178 _('REV')),
1178 _('REV')),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1179 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1180 _('BRANCH')),
1180 _('BRANCH')),
1181 ('', 'base', [],
1181 ('', 'base', [],
1182 _('a base changeset assumed to be available at the destination'),
1182 _('a base changeset assumed to be available at the destination'),
1183 _('REV')),
1183 _('REV')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1184 ('a', 'all', None, _('bundle all changesets in the repository')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1185 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1186 ] + remoteopts,
1186 ] + remoteopts,
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1187 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1188 def bundle(ui, repo, fname, dest=None, **opts):
1188 def bundle(ui, repo, fname, dest=None, **opts):
1189 """create a changegroup file
1189 """create a changegroup file
1190
1190
1191 Generate a compressed changegroup file collecting changesets not
1191 Generate a compressed changegroup file collecting changesets not
1192 known to be in another repository.
1192 known to be in another repository.
1193
1193
1194 If you omit the destination repository, then hg assumes the
1194 If you omit the destination repository, then hg assumes the
1195 destination will have all the nodes you specify with --base
1195 destination will have all the nodes you specify with --base
1196 parameters. To create a bundle containing all changesets, use
1196 parameters. To create a bundle containing all changesets, use
1197 -a/--all (or --base null).
1197 -a/--all (or --base null).
1198
1198
1199 You can change compression method with the -t/--type option.
1199 You can change compression method with the -t/--type option.
1200 The available compression methods are: none, bzip2, and
1200 The available compression methods are: none, bzip2, and
1201 gzip (by default, bundles are compressed using bzip2).
1201 gzip (by default, bundles are compressed using bzip2).
1202
1202
1203 The bundle file can then be transferred using conventional means
1203 The bundle file can then be transferred using conventional means
1204 and applied to another repository with the unbundle or pull
1204 and applied to another repository with the unbundle or pull
1205 command. This is useful when direct push and pull are not
1205 command. This is useful when direct push and pull are not
1206 available or when exporting an entire repository is undesirable.
1206 available or when exporting an entire repository is undesirable.
1207
1207
1208 Applying bundles preserves all changeset contents including
1208 Applying bundles preserves all changeset contents including
1209 permissions, copy/rename information, and revision history.
1209 permissions, copy/rename information, and revision history.
1210
1210
1211 Returns 0 on success, 1 if no changes found.
1211 Returns 0 on success, 1 if no changes found.
1212 """
1212 """
1213 revs = None
1213 revs = None
1214 if 'rev' in opts:
1214 if 'rev' in opts:
1215 revs = scmutil.revrange(repo, opts['rev'])
1215 revs = scmutil.revrange(repo, opts['rev'])
1216
1216
1217 bundletype = opts.get('type', 'bzip2').lower()
1217 bundletype = opts.get('type', 'bzip2').lower()
1218 btypes = {'none': 'HG10UN',
1218 btypes = {'none': 'HG10UN',
1219 'bzip2': 'HG10BZ',
1219 'bzip2': 'HG10BZ',
1220 'gzip': 'HG10GZ',
1220 'gzip': 'HG10GZ',
1221 'bundle2': 'HG20'}
1221 'bundle2': 'HG20'}
1222 bundletype = btypes.get(bundletype)
1222 bundletype = btypes.get(bundletype)
1223 if bundletype not in changegroup.bundletypes:
1223 if bundletype not in changegroup.bundletypes:
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1224 raise util.Abort(_('unknown bundle type specified with --type'))
1225
1225
1226 if opts.get('all'):
1226 if opts.get('all'):
1227 base = ['null']
1227 base = ['null']
1228 else:
1228 else:
1229 base = scmutil.revrange(repo, opts.get('base'))
1229 base = scmutil.revrange(repo, opts.get('base'))
1230 # TODO: get desired bundlecaps from command line.
1230 # TODO: get desired bundlecaps from command line.
1231 bundlecaps = None
1231 bundlecaps = None
1232 if base:
1232 if base:
1233 if dest:
1233 if dest:
1234 raise util.Abort(_("--base is incompatible with specifying "
1234 raise util.Abort(_("--base is incompatible with specifying "
1235 "a destination"))
1235 "a destination"))
1236 common = [repo.lookup(rev) for rev in base]
1236 common = [repo.lookup(rev) for rev in base]
1237 heads = revs and map(repo.lookup, revs) or revs
1237 heads = revs and map(repo.lookup, revs) or revs
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1238 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1239 common=common, bundlecaps=bundlecaps)
1239 common=common, bundlecaps=bundlecaps)
1240 outgoing = None
1240 outgoing = None
1241 else:
1241 else:
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1242 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1243 dest, branches = hg.parseurl(dest, opts.get('branch'))
1244 other = hg.peer(repo, opts, dest)
1244 other = hg.peer(repo, opts, dest)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1245 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1246 heads = revs and map(repo.lookup, revs) or revs
1246 heads = revs and map(repo.lookup, revs) or revs
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1247 outgoing = discovery.findcommonoutgoing(repo, other,
1248 onlyheads=heads,
1248 onlyheads=heads,
1249 force=opts.get('force'),
1249 force=opts.get('force'),
1250 portable=True)
1250 portable=True)
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1251 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1252 bundlecaps)
1252 bundlecaps)
1253 if not cg:
1253 if not cg:
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1254 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1255 return 1
1255 return 1
1256
1256
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1257 changegroup.writebundle(ui, cg, fname, bundletype)
1258
1258
1259 @command('cat',
1259 @command('cat',
1260 [('o', 'output', '',
1260 [('o', 'output', '',
1261 _('print output to file with formatted name'), _('FORMAT')),
1261 _('print output to file with formatted name'), _('FORMAT')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1262 ('r', 'rev', '', _('print the given revision'), _('REV')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1263 ('', 'decode', None, _('apply any matching decode filter')),
1264 ] + walkopts,
1264 ] + walkopts,
1265 _('[OPTION]... FILE...'),
1265 _('[OPTION]... FILE...'),
1266 inferrepo=True)
1266 inferrepo=True)
1267 def cat(ui, repo, file1, *pats, **opts):
1267 def cat(ui, repo, file1, *pats, **opts):
1268 """output the current or given revision of files
1268 """output the current or given revision of files
1269
1269
1270 Print the specified files as they were at the given revision. If
1270 Print the specified files as they were at the given revision. If
1271 no revision is given, the parent of the working directory is used.
1271 no revision is given, the parent of the working directory is used.
1272
1272
1273 Output may be to a file, in which case the name of the file is
1273 Output may be to a file, in which case the name of the file is
1274 given using a format string. The formatting rules as follows:
1274 given using a format string. The formatting rules as follows:
1275
1275
1276 :``%%``: literal "%" character
1276 :``%%``: literal "%" character
1277 :``%s``: basename of file being printed
1277 :``%s``: basename of file being printed
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1278 :``%d``: dirname of file being printed, or '.' if in repository root
1279 :``%p``: root-relative path name of file being printed
1279 :``%p``: root-relative path name of file being printed
1280 :``%H``: changeset hash (40 hexadecimal digits)
1280 :``%H``: changeset hash (40 hexadecimal digits)
1281 :``%R``: changeset revision number
1281 :``%R``: changeset revision number
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1282 :``%h``: short-form changeset hash (12 hexadecimal digits)
1283 :``%r``: zero-padded changeset revision number
1283 :``%r``: zero-padded changeset revision number
1284 :``%b``: basename of the exporting repository
1284 :``%b``: basename of the exporting repository
1285
1285
1286 Returns 0 on success.
1286 Returns 0 on success.
1287 """
1287 """
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1288 ctx = scmutil.revsingle(repo, opts.get('rev'))
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1289 m = scmutil.match(ctx, (file1,) + pats, opts)
1290
1290
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1291 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1292
1292
1293 @command('^clone',
1293 @command('^clone',
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1294 [('U', 'noupdate', None, _('the clone will include an empty working '
1295 'directory (only a repository)')),
1295 'directory (only a repository)')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1296 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1297 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1298 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1299 ('', 'pull', None, _('use pull protocol to copy metadata')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1300 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1301 ] + remoteopts,
1301 ] + remoteopts,
1302 _('[OPTION]... SOURCE [DEST]'),
1302 _('[OPTION]... SOURCE [DEST]'),
1303 norepo=True)
1303 norepo=True)
1304 def clone(ui, source, dest=None, **opts):
1304 def clone(ui, source, dest=None, **opts):
1305 """make a copy of an existing repository
1305 """make a copy of an existing repository
1306
1306
1307 Create a copy of an existing repository in a new directory.
1307 Create a copy of an existing repository in a new directory.
1308
1308
1309 If no destination directory name is specified, it defaults to the
1309 If no destination directory name is specified, it defaults to the
1310 basename of the source.
1310 basename of the source.
1311
1311
1312 The location of the source is added to the new repository's
1312 The location of the source is added to the new repository's
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1313 ``.hg/hgrc`` file, as the default to be used for future pulls.
1314
1314
1315 Only local paths and ``ssh://`` URLs are supported as
1315 Only local paths and ``ssh://`` URLs are supported as
1316 destinations. For ``ssh://`` destinations, no working directory or
1316 destinations. For ``ssh://`` destinations, no working directory or
1317 ``.hg/hgrc`` will be created on the remote side.
1317 ``.hg/hgrc`` will be created on the remote side.
1318
1318
1319 To pull only a subset of changesets, specify one or more revisions
1319 To pull only a subset of changesets, specify one or more revisions
1320 identifiers with -r/--rev or branches with -b/--branch. The
1320 identifiers with -r/--rev or branches with -b/--branch. The
1321 resulting clone will contain only the specified changesets and
1321 resulting clone will contain only the specified changesets and
1322 their ancestors. These options (or 'clone src#rev dest') imply
1322 their ancestors. These options (or 'clone src#rev dest') imply
1323 --pull, even for local source repositories. Note that specifying a
1323 --pull, even for local source repositories. Note that specifying a
1324 tag will include the tagged changeset but not the changeset
1324 tag will include the tagged changeset but not the changeset
1325 containing the tag.
1325 containing the tag.
1326
1326
1327 If the source repository has a bookmark called '@' set, that
1327 If the source repository has a bookmark called '@' set, that
1328 revision will be checked out in the new repository by default.
1328 revision will be checked out in the new repository by default.
1329
1329
1330 To check out a particular version, use -u/--update, or
1330 To check out a particular version, use -u/--update, or
1331 -U/--noupdate to create a clone with no working directory.
1331 -U/--noupdate to create a clone with no working directory.
1332
1332
1333 .. container:: verbose
1333 .. container:: verbose
1334
1334
1335 For efficiency, hardlinks are used for cloning whenever the
1335 For efficiency, hardlinks are used for cloning whenever the
1336 source and destination are on the same filesystem (note this
1336 source and destination are on the same filesystem (note this
1337 applies only to the repository data, not to the working
1337 applies only to the repository data, not to the working
1338 directory). Some filesystems, such as AFS, implement hardlinking
1338 directory). Some filesystems, such as AFS, implement hardlinking
1339 incorrectly, but do not report errors. In these cases, use the
1339 incorrectly, but do not report errors. In these cases, use the
1340 --pull option to avoid hardlinking.
1340 --pull option to avoid hardlinking.
1341
1341
1342 In some cases, you can clone repositories and the working
1342 In some cases, you can clone repositories and the working
1343 directory using full hardlinks with ::
1343 directory using full hardlinks with ::
1344
1344
1345 $ cp -al REPO REPOCLONE
1345 $ cp -al REPO REPOCLONE
1346
1346
1347 This is the fastest way to clone, but it is not always safe. The
1347 This is the fastest way to clone, but it is not always safe. The
1348 operation is not atomic (making sure REPO is not modified during
1348 operation is not atomic (making sure REPO is not modified during
1349 the operation is up to you) and you have to make sure your
1349 the operation is up to you) and you have to make sure your
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1350 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1351 so). Also, this is not compatible with certain extensions that
1351 so). Also, this is not compatible with certain extensions that
1352 place their metadata under the .hg directory, such as mq.
1352 place their metadata under the .hg directory, such as mq.
1353
1353
1354 Mercurial will update the working directory to the first applicable
1354 Mercurial will update the working directory to the first applicable
1355 revision from this list:
1355 revision from this list:
1356
1356
1357 a) null if -U or the source repository has no changesets
1357 a) null if -U or the source repository has no changesets
1358 b) if -u . and the source repository is local, the first parent of
1358 b) if -u . and the source repository is local, the first parent of
1359 the source repository's working directory
1359 the source repository's working directory
1360 c) the changeset specified with -u (if a branch name, this means the
1360 c) the changeset specified with -u (if a branch name, this means the
1361 latest head of that branch)
1361 latest head of that branch)
1362 d) the changeset specified with -r
1362 d) the changeset specified with -r
1363 e) the tipmost head specified with -b
1363 e) the tipmost head specified with -b
1364 f) the tipmost head specified with the url#branch source syntax
1364 f) the tipmost head specified with the url#branch source syntax
1365 g) the revision marked with the '@' bookmark, if present
1365 g) the revision marked with the '@' bookmark, if present
1366 h) the tipmost head of the default branch
1366 h) the tipmost head of the default branch
1367 i) tip
1367 i) tip
1368
1368
1369 Examples:
1369 Examples:
1370
1370
1371 - clone a remote repository to a new directory named hg/::
1371 - clone a remote repository to a new directory named hg/::
1372
1372
1373 hg clone http://selenic.com/hg
1373 hg clone http://selenic.com/hg
1374
1374
1375 - create a lightweight local clone::
1375 - create a lightweight local clone::
1376
1376
1377 hg clone project/ project-feature/
1377 hg clone project/ project-feature/
1378
1378
1379 - clone from an absolute path on an ssh server (note double-slash)::
1379 - clone from an absolute path on an ssh server (note double-slash)::
1380
1380
1381 hg clone ssh://user@server//home/projects/alpha/
1381 hg clone ssh://user@server//home/projects/alpha/
1382
1382
1383 - do a high-speed clone over a LAN while checking out a
1383 - do a high-speed clone over a LAN while checking out a
1384 specified version::
1384 specified version::
1385
1385
1386 hg clone --uncompressed http://server/repo -u 1.5
1386 hg clone --uncompressed http://server/repo -u 1.5
1387
1387
1388 - create a repository without changesets after a particular revision::
1388 - create a repository without changesets after a particular revision::
1389
1389
1390 hg clone -r 04e544 experimental/ good/
1390 hg clone -r 04e544 experimental/ good/
1391
1391
1392 - clone (and track) a particular named branch::
1392 - clone (and track) a particular named branch::
1393
1393
1394 hg clone http://selenic.com/hg#stable
1394 hg clone http://selenic.com/hg#stable
1395
1395
1396 See :hg:`help urls` for details on specifying URLs.
1396 See :hg:`help urls` for details on specifying URLs.
1397
1397
1398 Returns 0 on success.
1398 Returns 0 on success.
1399 """
1399 """
1400 if opts.get('noupdate') and opts.get('updaterev'):
1400 if opts.get('noupdate') and opts.get('updaterev'):
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1401 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1402
1402
1403 r = hg.clone(ui, opts, source, dest,
1403 r = hg.clone(ui, opts, source, dest,
1404 pull=opts.get('pull'),
1404 pull=opts.get('pull'),
1405 stream=opts.get('uncompressed'),
1405 stream=opts.get('uncompressed'),
1406 rev=opts.get('rev'),
1406 rev=opts.get('rev'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1407 update=opts.get('updaterev') or not opts.get('noupdate'),
1408 branch=opts.get('branch'))
1408 branch=opts.get('branch'))
1409
1409
1410 return r is None
1410 return r is None
1411
1411
1412 @command('^commit|ci',
1412 @command('^commit|ci',
1413 [('A', 'addremove', None,
1413 [('A', 'addremove', None,
1414 _('mark new/missing files as added/removed before committing')),
1414 _('mark new/missing files as added/removed before committing')),
1415 ('', 'close-branch', None,
1415 ('', 'close-branch', None,
1416 _('mark a branch as closed, hiding it from the branch list')),
1416 _('mark a branch as closed, hiding it from the branch list')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1417 ('', 'amend', None, _('amend the parent of the working directory')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1418 ('s', 'secret', None, _('use the secret phase for committing')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1419 ('e', 'edit', None, _('invoke editor on commit messages')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1420 ('i', 'interactive', None, _('use interactive mode')),
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1421 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1422 _('[OPTION]... [FILE]...'),
1422 _('[OPTION]... [FILE]...'),
1423 inferrepo=True)
1423 inferrepo=True)
1424 def commit(ui, repo, *pats, **opts):
1424 def commit(ui, repo, *pats, **opts):
1425 """commit the specified files or all outstanding changes
1425 """commit the specified files or all outstanding changes
1426
1426
1427 Commit changes to the given files into the repository. Unlike a
1427 Commit changes to the given files into the repository. Unlike a
1428 centralized SCM, this operation is a local operation. See
1428 centralized SCM, this operation is a local operation. See
1429 :hg:`push` for a way to actively distribute your changes.
1429 :hg:`push` for a way to actively distribute your changes.
1430
1430
1431 If a list of files is omitted, all changes reported by :hg:`status`
1431 If a list of files is omitted, all changes reported by :hg:`status`
1432 will be committed.
1432 will be committed.
1433
1433
1434 If you are committing the result of a merge, do not provide any
1434 If you are committing the result of a merge, do not provide any
1435 filenames or -I/-X filters.
1435 filenames or -I/-X filters.
1436
1436
1437 If no commit message is specified, Mercurial starts your
1437 If no commit message is specified, Mercurial starts your
1438 configured editor where you can enter a message. In case your
1438 configured editor where you can enter a message. In case your
1439 commit fails, you will find a backup of your message in
1439 commit fails, you will find a backup of your message in
1440 ``.hg/last-message.txt``.
1440 ``.hg/last-message.txt``.
1441
1441
1442 The --amend flag can be used to amend the parent of the
1442 The --amend flag can be used to amend the parent of the
1443 working directory with a new commit that contains the changes
1443 working directory with a new commit that contains the changes
1444 in the parent in addition to those currently reported by :hg:`status`,
1444 in the parent in addition to those currently reported by :hg:`status`,
1445 if there are any. The old commit is stored in a backup bundle in
1445 if there are any. The old commit is stored in a backup bundle in
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1446 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1447 on how to restore it).
1447 on how to restore it).
1448
1448
1449 Message, user and date are taken from the amended commit unless
1449 Message, user and date are taken from the amended commit unless
1450 specified. When a message isn't specified on the command line,
1450 specified. When a message isn't specified on the command line,
1451 the editor will open with the message of the amended commit.
1451 the editor will open with the message of the amended commit.
1452
1452
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1453 It is not possible to amend public changesets (see :hg:`help phases`)
1454 or changesets that have children.
1454 or changesets that have children.
1455
1455
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1456 See :hg:`help dates` for a list of formats valid for -d/--date.
1457
1457
1458 Returns 0 on success, 1 if nothing changed.
1458 Returns 0 on success, 1 if nothing changed.
1459 """
1459 """
1460 if opts.get('interactive'):
1460 if opts.get('interactive'):
1461 opts.pop('interactive')
1461 opts.pop('interactive')
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1462 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1463 cmdutil.recordfilter, *pats, **opts)
1463 cmdutil.recordfilter, *pats, **opts)
1464 return
1464 return
1465
1465
1466 if opts.get('subrepos'):
1466 if opts.get('subrepos'):
1467 if opts.get('amend'):
1467 if opts.get('amend'):
1468 raise util.Abort(_('cannot amend with --subrepos'))
1468 raise util.Abort(_('cannot amend with --subrepos'))
1469 # Let --subrepos on the command line override config setting.
1469 # Let --subrepos on the command line override config setting.
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1470 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1471
1471
1472 cmdutil.checkunfinished(repo, commit=True)
1472 cmdutil.checkunfinished(repo, commit=True)
1473
1473
1474 branch = repo[None].branch()
1474 branch = repo[None].branch()
1475 bheads = repo.branchheads(branch)
1475 bheads = repo.branchheads(branch)
1476
1476
1477 extra = {}
1477 extra = {}
1478 if opts.get('close_branch'):
1478 if opts.get('close_branch'):
1479 extra['close'] = 1
1479 extra['close'] = 1
1480
1480
1481 if not bheads:
1481 if not bheads:
1482 raise util.Abort(_('can only close branch heads'))
1482 raise util.Abort(_('can only close branch heads'))
1483 elif opts.get('amend'):
1483 elif opts.get('amend'):
1484 if repo.parents()[0].p1().branch() != branch and \
1484 if repo.parents()[0].p1().branch() != branch and \
1485 repo.parents()[0].p2().branch() != branch:
1485 repo.parents()[0].p2().branch() != branch:
1486 raise util.Abort(_('can only close branch heads'))
1486 raise util.Abort(_('can only close branch heads'))
1487
1487
1488 if opts.get('amend'):
1488 if opts.get('amend'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1489 if ui.configbool('ui', 'commitsubrepos'):
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1490 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1491
1491
1492 old = repo['.']
1492 old = repo['.']
1493 if not old.mutable():
1493 if not old.mutable():
1494 raise util.Abort(_('cannot amend public changesets'))
1494 raise util.Abort(_('cannot amend public changesets'))
1495 if len(repo[None].parents()) > 1:
1495 if len(repo[None].parents()) > 1:
1496 raise util.Abort(_('cannot amend while merging'))
1496 raise util.Abort(_('cannot amend while merging'))
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1497 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1498 if not allowunstable and old.children():
1498 if not allowunstable and old.children():
1499 raise util.Abort(_('cannot amend changeset with children'))
1499 raise util.Abort(_('cannot amend changeset with children'))
1500
1500
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1501 # commitfunc is used only for temporary amend commit by cmdutil.amend
1502 def commitfunc(ui, repo, message, match, opts):
1502 def commitfunc(ui, repo, message, match, opts):
1503 return repo.commit(message,
1503 return repo.commit(message,
1504 opts.get('user') or old.user(),
1504 opts.get('user') or old.user(),
1505 opts.get('date') or old.date(),
1505 opts.get('date') or old.date(),
1506 match,
1506 match,
1507 extra=extra)
1507 extra=extra)
1508
1508
1509 current = repo._bookmarkcurrent
1509 current = repo._bookmarkcurrent
1510 marks = old.bookmarks()
1510 marks = old.bookmarks()
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1511 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1512 if node == old.node():
1512 if node == old.node():
1513 ui.status(_("nothing changed\n"))
1513 ui.status(_("nothing changed\n"))
1514 return 1
1514 return 1
1515 elif marks:
1515 elif marks:
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1516 ui.debug('moving bookmarks %r from %s to %s\n' %
1517 (marks, old.hex(), hex(node)))
1517 (marks, old.hex(), hex(node)))
1518 newmarks = repo._bookmarks
1518 newmarks = repo._bookmarks
1519 for bm in marks:
1519 for bm in marks:
1520 newmarks[bm] = node
1520 newmarks[bm] = node
1521 if bm == current:
1521 if bm == current:
1522 bookmarks.setcurrent(repo, bm)
1522 bookmarks.setcurrent(repo, bm)
1523 newmarks.write()
1523 newmarks.write()
1524 else:
1524 else:
1525 def commitfunc(ui, repo, message, match, opts):
1525 def commitfunc(ui, repo, message, match, opts):
1526 backup = ui.backupconfig('phases', 'new-commit')
1526 backup = ui.backupconfig('phases', 'new-commit')
1527 baseui = repo.baseui
1527 baseui = repo.baseui
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1528 basebackup = baseui.backupconfig('phases', 'new-commit')
1529 try:
1529 try:
1530 if opts.get('secret'):
1530 if opts.get('secret'):
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1531 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1532 # Propagate to subrepos
1532 # Propagate to subrepos
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1533 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1534
1534
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1535 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1536 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1537 return repo.commit(message, opts.get('user'), opts.get('date'),
1538 match,
1538 match,
1539 editor=editor,
1539 editor=editor,
1540 extra=extra)
1540 extra=extra)
1541 finally:
1541 finally:
1542 ui.restoreconfig(backup)
1542 ui.restoreconfig(backup)
1543 repo.baseui.restoreconfig(basebackup)
1543 repo.baseui.restoreconfig(basebackup)
1544
1544
1545
1545
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1546 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1547
1547
1548 if not node:
1548 if not node:
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1549 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1550 if stat[3]:
1550 if stat[3]:
1551 ui.status(_("nothing changed (%d missing files, see "
1551 ui.status(_("nothing changed (%d missing files, see "
1552 "'hg status')\n") % len(stat[3]))
1552 "'hg status')\n") % len(stat[3]))
1553 else:
1553 else:
1554 ui.status(_("nothing changed\n"))
1554 ui.status(_("nothing changed\n"))
1555 return 1
1555 return 1
1556
1556
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1557 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1558
1558
1559 @command('config|showconfig|debugconfig',
1559 @command('config|showconfig|debugconfig',
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1560 [('u', 'untrusted', None, _('show untrusted configuration options')),
1561 ('e', 'edit', None, _('edit user config')),
1561 ('e', 'edit', None, _('edit user config')),
1562 ('l', 'local', None, _('edit repository config')),
1562 ('l', 'local', None, _('edit repository config')),
1563 ('g', 'global', None, _('edit global config'))],
1563 ('g', 'global', None, _('edit global config'))],
1564 _('[-u] [NAME]...'),
1564 _('[-u] [NAME]...'),
1565 optionalrepo=True)
1565 optionalrepo=True)
1566 def config(ui, repo, *values, **opts):
1566 def config(ui, repo, *values, **opts):
1567 """show combined config settings from all hgrc files
1567 """show combined config settings from all hgrc files
1568
1568
1569 With no arguments, print names and values of all config items.
1569 With no arguments, print names and values of all config items.
1570
1570
1571 With one argument of the form section.name, print just the value
1571 With one argument of the form section.name, print just the value
1572 of that config item.
1572 of that config item.
1573
1573
1574 With multiple arguments, print names and values of all config
1574 With multiple arguments, print names and values of all config
1575 items with matching section names.
1575 items with matching section names.
1576
1576
1577 With --edit, start an editor on the user-level config file. With
1577 With --edit, start an editor on the user-level config file. With
1578 --global, edit the system-wide config file. With --local, edit the
1578 --global, edit the system-wide config file. With --local, edit the
1579 repository-level config file.
1579 repository-level config file.
1580
1580
1581 With --debug, the source (filename and line number) is printed
1581 With --debug, the source (filename and line number) is printed
1582 for each config item.
1582 for each config item.
1583
1583
1584 See :hg:`help config` for more information about config files.
1584 See :hg:`help config` for more information about config files.
1585
1585
1586 Returns 0 on success, 1 if NAME does not exist.
1586 Returns 0 on success, 1 if NAME does not exist.
1587
1587
1588 """
1588 """
1589
1589
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1590 if opts.get('edit') or opts.get('local') or opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1591 if opts.get('local') and opts.get('global'):
1592 raise util.Abort(_("can't use --local and --global together"))
1592 raise util.Abort(_("can't use --local and --global together"))
1593
1593
1594 if opts.get('local'):
1594 if opts.get('local'):
1595 if not repo:
1595 if not repo:
1596 raise util.Abort(_("can't use --local outside a repository"))
1596 raise util.Abort(_("can't use --local outside a repository"))
1597 paths = [repo.join('hgrc')]
1597 paths = [repo.join('hgrc')]
1598 elif opts.get('global'):
1598 elif opts.get('global'):
1599 paths = scmutil.systemrcpath()
1599 paths = scmutil.systemrcpath()
1600 else:
1600 else:
1601 paths = scmutil.userrcpath()
1601 paths = scmutil.userrcpath()
1602
1602
1603 for f in paths:
1603 for f in paths:
1604 if os.path.exists(f):
1604 if os.path.exists(f):
1605 break
1605 break
1606 else:
1606 else:
1607 if opts.get('global'):
1607 if opts.get('global'):
1608 samplehgrc = uimod.samplehgrcs['global']
1608 samplehgrc = uimod.samplehgrcs['global']
1609 elif opts.get('local'):
1609 elif opts.get('local'):
1610 samplehgrc = uimod.samplehgrcs['local']
1610 samplehgrc = uimod.samplehgrcs['local']
1611 else:
1611 else:
1612 samplehgrc = uimod.samplehgrcs['user']
1612 samplehgrc = uimod.samplehgrcs['user']
1613
1613
1614 f = paths[0]
1614 f = paths[0]
1615 fp = open(f, "w")
1615 fp = open(f, "w")
1616 fp.write(samplehgrc)
1616 fp.write(samplehgrc)
1617 fp.close()
1617 fp.close()
1618
1618
1619 editor = ui.geteditor()
1619 editor = ui.geteditor()
1620 ui.system("%s \"%s\"" % (editor, f),
1620 ui.system("%s \"%s\"" % (editor, f),
1621 onerr=util.Abort, errprefix=_("edit failed"))
1621 onerr=util.Abort, errprefix=_("edit failed"))
1622 return
1622 return
1623
1623
1624 for f in scmutil.rcpath():
1624 for f in scmutil.rcpath():
1625 ui.debug('read config from: %s\n' % f)
1625 ui.debug('read config from: %s\n' % f)
1626 untrusted = bool(opts.get('untrusted'))
1626 untrusted = bool(opts.get('untrusted'))
1627 if values:
1627 if values:
1628 sections = [v for v in values if '.' not in v]
1628 sections = [v for v in values if '.' not in v]
1629 items = [v for v in values if '.' in v]
1629 items = [v for v in values if '.' in v]
1630 if len(items) > 1 or items and sections:
1630 if len(items) > 1 or items and sections:
1631 raise util.Abort(_('only one config item permitted'))
1631 raise util.Abort(_('only one config item permitted'))
1632 matched = False
1632 matched = False
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1633 for section, name, value in ui.walkconfig(untrusted=untrusted):
1634 value = str(value).replace('\n', '\\n')
1634 value = str(value).replace('\n', '\\n')
1635 sectname = section + '.' + name
1635 sectname = section + '.' + name
1636 if values:
1636 if values:
1637 for v in values:
1637 for v in values:
1638 if v == section:
1638 if v == section:
1639 ui.debug('%s: ' %
1639 ui.debug('%s: ' %
1640 ui.configsource(section, name, untrusted))
1640 ui.configsource(section, name, untrusted))
1641 ui.write('%s=%s\n' % (sectname, value))
1641 ui.write('%s=%s\n' % (sectname, value))
1642 matched = True
1642 matched = True
1643 elif v == sectname:
1643 elif v == sectname:
1644 ui.debug('%s: ' %
1644 ui.debug('%s: ' %
1645 ui.configsource(section, name, untrusted))
1645 ui.configsource(section, name, untrusted))
1646 ui.write(value, '\n')
1646 ui.write(value, '\n')
1647 matched = True
1647 matched = True
1648 else:
1648 else:
1649 ui.debug('%s: ' %
1649 ui.debug('%s: ' %
1650 ui.configsource(section, name, untrusted))
1650 ui.configsource(section, name, untrusted))
1651 ui.write('%s=%s\n' % (sectname, value))
1651 ui.write('%s=%s\n' % (sectname, value))
1652 matched = True
1652 matched = True
1653 if matched:
1653 if matched:
1654 return 0
1654 return 0
1655 return 1
1655 return 1
1656
1656
1657 @command('copy|cp',
1657 @command('copy|cp',
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1658 [('A', 'after', None, _('record a copy that has already occurred')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1659 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1660 ] + walkopts + dryrunopts,
1660 ] + walkopts + dryrunopts,
1661 _('[OPTION]... [SOURCE]... DEST'))
1661 _('[OPTION]... [SOURCE]... DEST'))
1662 def copy(ui, repo, *pats, **opts):
1662 def copy(ui, repo, *pats, **opts):
1663 """mark files as copied for the next commit
1663 """mark files as copied for the next commit
1664
1664
1665 Mark dest as having copies of source files. If dest is a
1665 Mark dest as having copies of source files. If dest is a
1666 directory, copies are put in that directory. If dest is a file,
1666 directory, copies are put in that directory. If dest is a file,
1667 the source must be a single file.
1667 the source must be a single file.
1668
1668
1669 By default, this command copies the contents of files as they
1669 By default, this command copies the contents of files as they
1670 exist in the working directory. If invoked with -A/--after, the
1670 exist in the working directory. If invoked with -A/--after, the
1671 operation is recorded, but no copying is performed.
1671 operation is recorded, but no copying is performed.
1672
1672
1673 This command takes effect with the next commit. To undo a copy
1673 This command takes effect with the next commit. To undo a copy
1674 before that, see :hg:`revert`.
1674 before that, see :hg:`revert`.
1675
1675
1676 Returns 0 on success, 1 if errors are encountered.
1676 Returns 0 on success, 1 if errors are encountered.
1677 """
1677 """
1678 wlock = repo.wlock(False)
1678 wlock = repo.wlock(False)
1679 try:
1679 try:
1680 return cmdutil.copy(ui, repo, pats, opts)
1680 return cmdutil.copy(ui, repo, pats, opts)
1681 finally:
1681 finally:
1682 wlock.release()
1682 wlock.release()
1683
1683
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1684 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1685 def debugancestor(ui, repo, *args):
1685 def debugancestor(ui, repo, *args):
1686 """find the ancestor revision of two revisions in a given index"""
1686 """find the ancestor revision of two revisions in a given index"""
1687 if len(args) == 3:
1687 if len(args) == 3:
1688 index, rev1, rev2 = args
1688 index, rev1, rev2 = args
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1689 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1690 lookup = r.lookup
1690 lookup = r.lookup
1691 elif len(args) == 2:
1691 elif len(args) == 2:
1692 if not repo:
1692 if not repo:
1693 raise util.Abort(_("there is no Mercurial repository here "
1693 raise util.Abort(_("there is no Mercurial repository here "
1694 "(.hg not found)"))
1694 "(.hg not found)"))
1695 rev1, rev2 = args
1695 rev1, rev2 = args
1696 r = repo.changelog
1696 r = repo.changelog
1697 lookup = repo.lookup
1697 lookup = repo.lookup
1698 else:
1698 else:
1699 raise util.Abort(_('either two or three arguments required'))
1699 raise util.Abort(_('either two or three arguments required'))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1700 a = r.ancestor(lookup(rev1), lookup(rev2))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1701 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1702
1702
1703 @command('debugbuilddag',
1703 @command('debugbuilddag',
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1704 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1705 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1706 ('n', 'new-file', None, _('add new file at each rev'))],
1707 _('[OPTION]... [TEXT]'))
1707 _('[OPTION]... [TEXT]'))
1708 def debugbuilddag(ui, repo, text=None,
1708 def debugbuilddag(ui, repo, text=None,
1709 mergeable_file=False,
1709 mergeable_file=False,
1710 overwritten_file=False,
1710 overwritten_file=False,
1711 new_file=False):
1711 new_file=False):
1712 """builds a repo with a given DAG from scratch in the current empty repo
1712 """builds a repo with a given DAG from scratch in the current empty repo
1713
1713
1714 The description of the DAG is read from stdin if not given on the
1714 The description of the DAG is read from stdin if not given on the
1715 command line.
1715 command line.
1716
1716
1717 Elements:
1717 Elements:
1718
1718
1719 - "+n" is a linear run of n nodes based on the current default parent
1719 - "+n" is a linear run of n nodes based on the current default parent
1720 - "." is a single node based on the current default parent
1720 - "." is a single node based on the current default parent
1721 - "$" resets the default parent to null (implied at the start);
1721 - "$" resets the default parent to null (implied at the start);
1722 otherwise the default parent is always the last node created
1722 otherwise the default parent is always the last node created
1723 - "<p" sets the default parent to the backref p
1723 - "<p" sets the default parent to the backref p
1724 - "*p" is a fork at parent p, which is a backref
1724 - "*p" is a fork at parent p, which is a backref
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1725 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1726 - "/p2" is a merge of the preceding node and p2
1726 - "/p2" is a merge of the preceding node and p2
1727 - ":tag" defines a local tag for the preceding node
1727 - ":tag" defines a local tag for the preceding node
1728 - "@branch" sets the named branch for subsequent nodes
1728 - "@branch" sets the named branch for subsequent nodes
1729 - "#...\\n" is a comment up to the end of the line
1729 - "#...\\n" is a comment up to the end of the line
1730
1730
1731 Whitespace between the above elements is ignored.
1731 Whitespace between the above elements is ignored.
1732
1732
1733 A backref is either
1733 A backref is either
1734
1734
1735 - a number n, which references the node curr-n, where curr is the current
1735 - a number n, which references the node curr-n, where curr is the current
1736 node, or
1736 node, or
1737 - the name of a local tag you placed earlier using ":tag", or
1737 - the name of a local tag you placed earlier using ":tag", or
1738 - empty to denote the default parent.
1738 - empty to denote the default parent.
1739
1739
1740 All string valued-elements are either strictly alphanumeric, or must
1740 All string valued-elements are either strictly alphanumeric, or must
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1741 be enclosed in double quotes ("..."), with "\\" as escape character.
1742 """
1742 """
1743
1743
1744 if text is None:
1744 if text is None:
1745 ui.status(_("reading DAG from stdin\n"))
1745 ui.status(_("reading DAG from stdin\n"))
1746 text = ui.fin.read()
1746 text = ui.fin.read()
1747
1747
1748 cl = repo.changelog
1748 cl = repo.changelog
1749 if len(cl) > 0:
1749 if len(cl) > 0:
1750 raise util.Abort(_('repository is not empty'))
1750 raise util.Abort(_('repository is not empty'))
1751
1751
1752 # determine number of revs in DAG
1752 # determine number of revs in DAG
1753 total = 0
1753 total = 0
1754 for type, data in dagparser.parsedag(text):
1754 for type, data in dagparser.parsedag(text):
1755 if type == 'n':
1755 if type == 'n':
1756 total += 1
1756 total += 1
1757
1757
1758 if mergeable_file:
1758 if mergeable_file:
1759 linesperrev = 2
1759 linesperrev = 2
1760 # make a file with k lines per rev
1760 # make a file with k lines per rev
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1761 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1762 initialmergedlines.append("")
1762 initialmergedlines.append("")
1763
1763
1764 tags = []
1764 tags = []
1765
1765
1766 lock = tr = None
1766 lock = tr = None
1767 try:
1767 try:
1768 lock = repo.lock()
1768 lock = repo.lock()
1769 tr = repo.transaction("builddag")
1769 tr = repo.transaction("builddag")
1770
1770
1771 at = -1
1771 at = -1
1772 atbranch = 'default'
1772 atbranch = 'default'
1773 nodeids = []
1773 nodeids = []
1774 id = 0
1774 id = 0
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1775 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1776 for type, data in dagparser.parsedag(text):
1776 for type, data in dagparser.parsedag(text):
1777 if type == 'n':
1777 if type == 'n':
1778 ui.note(('node %s\n' % str(data)))
1778 ui.note(('node %s\n' % str(data)))
1779 id, ps = data
1779 id, ps = data
1780
1780
1781 files = []
1781 files = []
1782 fctxs = {}
1782 fctxs = {}
1783
1783
1784 p2 = None
1784 p2 = None
1785 if mergeable_file:
1785 if mergeable_file:
1786 fn = "mf"
1786 fn = "mf"
1787 p1 = repo[ps[0]]
1787 p1 = repo[ps[0]]
1788 if len(ps) > 1:
1788 if len(ps) > 1:
1789 p2 = repo[ps[1]]
1789 p2 = repo[ps[1]]
1790 pa = p1.ancestor(p2)
1790 pa = p1.ancestor(p2)
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1791 base, local, other = [x[fn].data() for x in (pa, p1,
1792 p2)]
1792 p2)]
1793 m3 = simplemerge.Merge3Text(base, local, other)
1793 m3 = simplemerge.Merge3Text(base, local, other)
1794 ml = [l.strip() for l in m3.merge_lines()]
1794 ml = [l.strip() for l in m3.merge_lines()]
1795 ml.append("")
1795 ml.append("")
1796 elif at > 0:
1796 elif at > 0:
1797 ml = p1[fn].data().split("\n")
1797 ml = p1[fn].data().split("\n")
1798 else:
1798 else:
1799 ml = initialmergedlines
1799 ml = initialmergedlines
1800 ml[id * linesperrev] += " r%i" % id
1800 ml[id * linesperrev] += " r%i" % id
1801 mergedtext = "\n".join(ml)
1801 mergedtext = "\n".join(ml)
1802 files.append(fn)
1802 files.append(fn)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1803 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1804
1804
1805 if overwritten_file:
1805 if overwritten_file:
1806 fn = "of"
1806 fn = "of"
1807 files.append(fn)
1807 files.append(fn)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1808 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1809
1809
1810 if new_file:
1810 if new_file:
1811 fn = "nf%i" % id
1811 fn = "nf%i" % id
1812 files.append(fn)
1812 files.append(fn)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1813 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1814 if len(ps) > 1:
1814 if len(ps) > 1:
1815 if not p2:
1815 if not p2:
1816 p2 = repo[ps[1]]
1816 p2 = repo[ps[1]]
1817 for fn in p2:
1817 for fn in p2:
1818 if fn.startswith("nf"):
1818 if fn.startswith("nf"):
1819 files.append(fn)
1819 files.append(fn)
1820 fctxs[fn] = p2[fn]
1820 fctxs[fn] = p2[fn]
1821
1821
1822 def fctxfn(repo, cx, path):
1822 def fctxfn(repo, cx, path):
1823 return fctxs.get(path)
1823 return fctxs.get(path)
1824
1824
1825 if len(ps) == 0 or ps[0] < 0:
1825 if len(ps) == 0 or ps[0] < 0:
1826 pars = [None, None]
1826 pars = [None, None]
1827 elif len(ps) == 1:
1827 elif len(ps) == 1:
1828 pars = [nodeids[ps[0]], None]
1828 pars = [nodeids[ps[0]], None]
1829 else:
1829 else:
1830 pars = [nodeids[p] for p in ps]
1830 pars = [nodeids[p] for p in ps]
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1831 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1832 date=(id, 0),
1832 date=(id, 0),
1833 user="debugbuilddag",
1833 user="debugbuilddag",
1834 extra={'branch': atbranch})
1834 extra={'branch': atbranch})
1835 nodeid = repo.commitctx(cx)
1835 nodeid = repo.commitctx(cx)
1836 nodeids.append(nodeid)
1836 nodeids.append(nodeid)
1837 at = id
1837 at = id
1838 elif type == 'l':
1838 elif type == 'l':
1839 id, name = data
1839 id, name = data
1840 ui.note(('tag %s\n' % name))
1840 ui.note(('tag %s\n' % name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1841 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1842 elif type == 'a':
1842 elif type == 'a':
1843 ui.note(('branch %s\n' % data))
1843 ui.note(('branch %s\n' % data))
1844 atbranch = data
1844 atbranch = data
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1845 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1846 tr.close()
1846 tr.close()
1847
1847
1848 if tags:
1848 if tags:
1849 repo.vfs.write("localtags", "".join(tags))
1849 repo.vfs.write("localtags", "".join(tags))
1850 finally:
1850 finally:
1851 ui.progress(_('building'), None)
1851 ui.progress(_('building'), None)
1852 release(tr, lock)
1852 release(tr, lock)
1853
1853
1854 @command('debugbundle',
1854 @command('debugbundle',
1855 [('a', 'all', None, _('show all details'))],
1855 [('a', 'all', None, _('show all details'))],
1856 _('FILE'),
1856 _('FILE'),
1857 norepo=True)
1857 norepo=True)
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1858 def debugbundle(ui, bundlepath, all=None, **opts):
1859 """lists the contents of a bundle"""
1859 """lists the contents of a bundle"""
1860 f = hg.openpath(ui, bundlepath)
1860 f = hg.openpath(ui, bundlepath)
1861 try:
1861 try:
1862 gen = exchange.readbundle(ui, f, bundlepath)
1862 gen = exchange.readbundle(ui, f, bundlepath)
1863 if isinstance(gen, bundle2.unbundle20):
1863 if isinstance(gen, bundle2.unbundle20):
1864 return _debugbundle2(ui, gen, all=all, **opts)
1864 return _debugbundle2(ui, gen, all=all, **opts)
1865 if all:
1865 if all:
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1866 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1867
1867
1868 def showchunks(named):
1868 def showchunks(named):
1869 ui.write("\n%s\n" % named)
1869 ui.write("\n%s\n" % named)
1870 chain = None
1870 chain = None
1871 while True:
1871 while True:
1872 chunkdata = gen.deltachunk(chain)
1872 chunkdata = gen.deltachunk(chain)
1873 if not chunkdata:
1873 if not chunkdata:
1874 break
1874 break
1875 node = chunkdata['node']
1875 node = chunkdata['node']
1876 p1 = chunkdata['p1']
1876 p1 = chunkdata['p1']
1877 p2 = chunkdata['p2']
1877 p2 = chunkdata['p2']
1878 cs = chunkdata['cs']
1878 cs = chunkdata['cs']
1879 deltabase = chunkdata['deltabase']
1879 deltabase = chunkdata['deltabase']
1880 delta = chunkdata['delta']
1880 delta = chunkdata['delta']
1881 ui.write("%s %s %s %s %s %s\n" %
1881 ui.write("%s %s %s %s %s %s\n" %
1882 (hex(node), hex(p1), hex(p2),
1882 (hex(node), hex(p1), hex(p2),
1883 hex(cs), hex(deltabase), len(delta)))
1883 hex(cs), hex(deltabase), len(delta)))
1884 chain = node
1884 chain = node
1885
1885
1886 chunkdata = gen.changelogheader()
1886 chunkdata = gen.changelogheader()
1887 showchunks("changelog")
1887 showchunks("changelog")
1888 chunkdata = gen.manifestheader()
1888 chunkdata = gen.manifestheader()
1889 showchunks("manifest")
1889 showchunks("manifest")
1890 while True:
1890 while True:
1891 chunkdata = gen.filelogheader()
1891 chunkdata = gen.filelogheader()
1892 if not chunkdata:
1892 if not chunkdata:
1893 break
1893 break
1894 fname = chunkdata['filename']
1894 fname = chunkdata['filename']
1895 showchunks(fname)
1895 showchunks(fname)
1896 else:
1896 else:
1897 if isinstance(gen, bundle2.unbundle20):
1897 if isinstance(gen, bundle2.unbundle20):
1898 raise util.Abort(_('use debugbundle2 for this file'))
1898 raise util.Abort(_('use debugbundle2 for this file'))
1899 chunkdata = gen.changelogheader()
1899 chunkdata = gen.changelogheader()
1900 chain = None
1900 chain = None
1901 while True:
1901 while True:
1902 chunkdata = gen.deltachunk(chain)
1902 chunkdata = gen.deltachunk(chain)
1903 if not chunkdata:
1903 if not chunkdata:
1904 break
1904 break
1905 node = chunkdata['node']
1905 node = chunkdata['node']
1906 ui.write("%s\n" % hex(node))
1906 ui.write("%s\n" % hex(node))
1907 chain = node
1907 chain = node
1908 finally:
1908 finally:
1909 f.close()
1909 f.close()
1910
1910
1911 def _debugbundle2(ui, gen, **opts):
1911 def _debugbundle2(ui, gen, **opts):
1912 """lists the contents of a bundle2"""
1912 """lists the contents of a bundle2"""
1913 if not isinstance(gen, bundle2.unbundle20):
1913 if not isinstance(gen, bundle2.unbundle20):
1914 raise util.Abort(_('not a bundle2 file'))
1914 raise util.Abort(_('not a bundle2 file'))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1915 ui.write(('Stream params: %s\n' % repr(gen.params)))
1916 for part in gen.iterparts():
1916 for part in gen.iterparts():
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1917 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1918 if part.type == 'changegroup':
1918 if part.type == 'changegroup':
1919 version = part.params.get('version', '01')
1919 version = part.params.get('version', '01')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1920 cg = changegroup.packermap[version][1](part, 'UN')
1921 chunkdata = cg.changelogheader()
1921 chunkdata = cg.changelogheader()
1922 chain = None
1922 chain = None
1923 while True:
1923 while True:
1924 chunkdata = cg.deltachunk(chain)
1924 chunkdata = cg.deltachunk(chain)
1925 if not chunkdata:
1925 if not chunkdata:
1926 break
1926 break
1927 node = chunkdata['node']
1927 node = chunkdata['node']
1928 ui.write(" %s\n" % hex(node))
1928 ui.write(" %s\n" % hex(node))
1929 chain = node
1929 chain = node
1930
1930
1931 @command('debugcheckstate', [], '')
1931 @command('debugcheckstate', [], '')
1932 def debugcheckstate(ui, repo):
1932 def debugcheckstate(ui, repo):
1933 """validate the correctness of the current dirstate"""
1933 """validate the correctness of the current dirstate"""
1934 parent1, parent2 = repo.dirstate.parents()
1934 parent1, parent2 = repo.dirstate.parents()
1935 m1 = repo[parent1].manifest()
1935 m1 = repo[parent1].manifest()
1936 m2 = repo[parent2].manifest()
1936 m2 = repo[parent2].manifest()
1937 errors = 0
1937 errors = 0
1938 for f in repo.dirstate:
1938 for f in repo.dirstate:
1939 state = repo.dirstate[f]
1939 state = repo.dirstate[f]
1940 if state in "nr" and f not in m1:
1940 if state in "nr" and f not in m1:
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1941 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1942 errors += 1
1942 errors += 1
1943 if state in "a" and f in m1:
1943 if state in "a" and f in m1:
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1944 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1945 errors += 1
1945 errors += 1
1946 if state in "m" and f not in m1 and f not in m2:
1946 if state in "m" and f not in m1 and f not in m2:
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1947 ui.warn(_("%s in state %s, but not in either manifest\n") %
1948 (f, state))
1948 (f, state))
1949 errors += 1
1949 errors += 1
1950 for f in m1:
1950 for f in m1:
1951 state = repo.dirstate[f]
1951 state = repo.dirstate[f]
1952 if state not in "nrm":
1952 if state not in "nrm":
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1953 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1954 errors += 1
1954 errors += 1
1955 if errors:
1955 if errors:
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1956 error = _(".hg/dirstate inconsistent with current parent's manifest")
1957 raise util.Abort(error)
1957 raise util.Abort(error)
1958
1958
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1959 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1960 def debugcommands(ui, cmd='', *args):
1960 def debugcommands(ui, cmd='', *args):
1961 """list all available commands and options"""
1961 """list all available commands and options"""
1962 for cmd, vals in sorted(table.iteritems()):
1962 for cmd, vals in sorted(table.iteritems()):
1963 cmd = cmd.split('|')[0].strip('^')
1963 cmd = cmd.split('|')[0].strip('^')
1964 opts = ', '.join([i[1] for i in vals[1]])
1964 opts = ', '.join([i[1] for i in vals[1]])
1965 ui.write('%s: %s\n' % (cmd, opts))
1965 ui.write('%s: %s\n' % (cmd, opts))
1966
1966
1967 @command('debugcomplete',
1967 @command('debugcomplete',
1968 [('o', 'options', None, _('show the command options'))],
1968 [('o', 'options', None, _('show the command options'))],
1969 _('[-o] CMD'),
1969 _('[-o] CMD'),
1970 norepo=True)
1970 norepo=True)
1971 def debugcomplete(ui, cmd='', **opts):
1971 def debugcomplete(ui, cmd='', **opts):
1972 """returns the completion list associated with the given command"""
1972 """returns the completion list associated with the given command"""
1973
1973
1974 if opts.get('options'):
1974 if opts.get('options'):
1975 options = []
1975 options = []
1976 otables = [globalopts]
1976 otables = [globalopts]
1977 if cmd:
1977 if cmd:
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1978 aliases, entry = cmdutil.findcmd(cmd, table, False)
1979 otables.append(entry[1])
1979 otables.append(entry[1])
1980 for t in otables:
1980 for t in otables:
1981 for o in t:
1981 for o in t:
1982 if "(DEPRECATED)" in o[3]:
1982 if "(DEPRECATED)" in o[3]:
1983 continue
1983 continue
1984 if o[0]:
1984 if o[0]:
1985 options.append('-%s' % o[0])
1985 options.append('-%s' % o[0])
1986 options.append('--%s' % o[1])
1986 options.append('--%s' % o[1])
1987 ui.write("%s\n" % "\n".join(options))
1987 ui.write("%s\n" % "\n".join(options))
1988 return
1988 return
1989
1989
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1990 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1991 if ui.verbose:
1991 if ui.verbose:
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1992 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1993 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1994
1994
1995 @command('debugdag',
1995 @command('debugdag',
1996 [('t', 'tags', None, _('use tags as labels')),
1996 [('t', 'tags', None, _('use tags as labels')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1997 ('b', 'branches', None, _('annotate with branch names')),
1998 ('', 'dots', None, _('use dots for runs')),
1998 ('', 'dots', None, _('use dots for runs')),
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
1999 ('s', 'spaces', None, _('separate elements by spaces'))],
2000 _('[OPTION]... [FILE [REV]...]'),
2000 _('[OPTION]... [FILE [REV]...]'),
2001 optionalrepo=True)
2001 optionalrepo=True)
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2002 def debugdag(ui, repo, file_=None, *revs, **opts):
2003 """format the changelog or an index DAG as a concise textual description
2003 """format the changelog or an index DAG as a concise textual description
2004
2004
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2005 If you pass a revlog index, the revlog's DAG is emitted. If you list
2006 revision numbers, they get labeled in the output as rN.
2006 revision numbers, they get labeled in the output as rN.
2007
2007
2008 Otherwise, the changelog DAG of the current repo is emitted.
2008 Otherwise, the changelog DAG of the current repo is emitted.
2009 """
2009 """
2010 spaces = opts.get('spaces')
2010 spaces = opts.get('spaces')
2011 dots = opts.get('dots')
2011 dots = opts.get('dots')
2012 if file_:
2012 if file_:
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2013 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2014 revs = set((int(r) for r in revs))
2014 revs = set((int(r) for r in revs))
2015 def events():
2015 def events():
2016 for r in rlog:
2016 for r in rlog:
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2017 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2018 if p != -1))
2018 if p != -1))
2019 if r in revs:
2019 if r in revs:
2020 yield 'l', (r, "r%i" % r)
2020 yield 'l', (r, "r%i" % r)
2021 elif repo:
2021 elif repo:
2022 cl = repo.changelog
2022 cl = repo.changelog
2023 tags = opts.get('tags')
2023 tags = opts.get('tags')
2024 branches = opts.get('branches')
2024 branches = opts.get('branches')
2025 if tags:
2025 if tags:
2026 labels = {}
2026 labels = {}
2027 for l, n in repo.tags().items():
2027 for l, n in repo.tags().items():
2028 labels.setdefault(cl.rev(n), []).append(l)
2028 labels.setdefault(cl.rev(n), []).append(l)
2029 def events():
2029 def events():
2030 b = "default"
2030 b = "default"
2031 for r in cl:
2031 for r in cl:
2032 if branches:
2032 if branches:
2033 newb = cl.read(cl.node(r))[5]['branch']
2033 newb = cl.read(cl.node(r))[5]['branch']
2034 if newb != b:
2034 if newb != b:
2035 yield 'a', newb
2035 yield 'a', newb
2036 b = newb
2036 b = newb
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2037 yield 'n', (r, list(p for p in cl.parentrevs(r)
2038 if p != -1))
2038 if p != -1))
2039 if tags:
2039 if tags:
2040 ls = labels.get(r)
2040 ls = labels.get(r)
2041 if ls:
2041 if ls:
2042 for l in ls:
2042 for l in ls:
2043 yield 'l', (r, l)
2043 yield 'l', (r, l)
2044 else:
2044 else:
2045 raise util.Abort(_('need repo for changelog dag'))
2045 raise util.Abort(_('need repo for changelog dag'))
2046
2046
2047 for line in dagparser.dagtextlines(events(),
2047 for line in dagparser.dagtextlines(events(),
2048 addspaces=spaces,
2048 addspaces=spaces,
2049 wraplabels=True,
2049 wraplabels=True,
2050 wrapannotations=True,
2050 wrapannotations=True,
2051 wrapnonlinear=dots,
2051 wrapnonlinear=dots,
2052 usedots=dots,
2052 usedots=dots,
2053 maxlinewidth=70):
2053 maxlinewidth=70):
2054 ui.write(line)
2054 ui.write(line)
2055 ui.write("\n")
2055 ui.write("\n")
2056
2056
2057 @command('debugdata',
2057 @command('debugdata',
2058 [('c', 'changelog', False, _('open changelog')),
2058 [('c', 'changelog', False, _('open changelog')),
2059 ('m', 'manifest', False, _('open manifest'))],
2059 ('m', 'manifest', False, _('open manifest'))],
2060 _('-c|-m|FILE REV'))
2060 _('-c|-m|FILE REV'))
2061 def debugdata(ui, repo, file_, rev=None, **opts):
2061 def debugdata(ui, repo, file_, rev=None, **opts):
2062 """dump the contents of a data file revision"""
2062 """dump the contents of a data file revision"""
2063 if opts.get('changelog') or opts.get('manifest'):
2063 if opts.get('changelog') or opts.get('manifest'):
2064 file_, rev = None, file_
2064 file_, rev = None, file_
2065 elif rev is None:
2065 elif rev is None:
2066 raise error.CommandError('debugdata', _('invalid arguments'))
2066 raise error.CommandError('debugdata', _('invalid arguments'))
2067 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2067 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2068 try:
2068 try:
2069 ui.write(r.revision(r.lookup(rev)))
2069 ui.write(r.revision(r.lookup(rev)))
2070 except KeyError:
2070 except KeyError:
2071 raise util.Abort(_('invalid revision identifier %s') % rev)
2071 raise util.Abort(_('invalid revision identifier %s') % rev)
2072
2072
2073 @command('debugdate',
2073 @command('debugdate',
2074 [('e', 'extended', None, _('try extended date formats'))],
2074 [('e', 'extended', None, _('try extended date formats'))],
2075 _('[-e] DATE [RANGE]'),
2075 _('[-e] DATE [RANGE]'),
2076 norepo=True, optionalrepo=True)
2076 norepo=True, optionalrepo=True)
2077 def debugdate(ui, date, range=None, **opts):
2077 def debugdate(ui, date, range=None, **opts):
2078 """parse and display a date"""
2078 """parse and display a date"""
2079 if opts["extended"]:
2079 if opts["extended"]:
2080 d = util.parsedate(date, util.extendeddateformats)
2080 d = util.parsedate(date, util.extendeddateformats)
2081 else:
2081 else:
2082 d = util.parsedate(date)
2082 d = util.parsedate(date)
2083 ui.write(("internal: %s %s\n") % d)
2083 ui.write(("internal: %s %s\n") % d)
2084 ui.write(("standard: %s\n") % util.datestr(d))
2084 ui.write(("standard: %s\n") % util.datestr(d))
2085 if range:
2085 if range:
2086 m = util.matchdate(range)
2086 m = util.matchdate(range)
2087 ui.write(("match: %s\n") % m(d[0]))
2087 ui.write(("match: %s\n") % m(d[0]))
2088
2088
2089 @command('debugdiscovery',
2089 @command('debugdiscovery',
2090 [('', 'old', None, _('use old-style discovery')),
2090 [('', 'old', None, _('use old-style discovery')),
2091 ('', 'nonheads', None,
2091 ('', 'nonheads', None,
2092 _('use old-style discovery with non-heads included')),
2092 _('use old-style discovery with non-heads included')),
2093 ] + remoteopts,
2093 ] + remoteopts,
2094 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2094 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2095 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2095 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2096 """runs the changeset discovery protocol in isolation"""
2096 """runs the changeset discovery protocol in isolation"""
2097 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2097 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2098 opts.get('branch'))
2098 opts.get('branch'))
2099 remote = hg.peer(repo, opts, remoteurl)
2099 remote = hg.peer(repo, opts, remoteurl)
2100 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2100 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2101
2101
2102 # make sure tests are repeatable
2102 # make sure tests are repeatable
2103 random.seed(12323)
2103 random.seed(12323)
2104
2104
2105 def doit(localheads, remoteheads, remote=remote):
2105 def doit(localheads, remoteheads, remote=remote):
2106 if opts.get('old'):
2106 if opts.get('old'):
2107 if localheads:
2107 if localheads:
2108 raise util.Abort('cannot use localheads with old style '
2108 raise util.Abort('cannot use localheads with old style '
2109 'discovery')
2109 'discovery')
2110 if not util.safehasattr(remote, 'branches'):
2110 if not util.safehasattr(remote, 'branches'):
2111 # enable in-client legacy support
2111 # enable in-client legacy support
2112 remote = localrepo.locallegacypeer(remote.local())
2112 remote = localrepo.locallegacypeer(remote.local())
2113 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2113 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2114 force=True)
2114 force=True)
2115 common = set(common)
2115 common = set(common)
2116 if not opts.get('nonheads'):
2116 if not opts.get('nonheads'):
2117 ui.write(("unpruned common: %s\n") %
2117 ui.write(("unpruned common: %s\n") %
2118 " ".join(sorted(short(n) for n in common)))
2118 " ".join(sorted(short(n) for n in common)))
2119 dag = dagutil.revlogdag(repo.changelog)
2119 dag = dagutil.revlogdag(repo.changelog)
2120 all = dag.ancestorset(dag.internalizeall(common))
2120 all = dag.ancestorset(dag.internalizeall(common))
2121 common = dag.externalizeall(dag.headsetofconnecteds(all))
2121 common = dag.externalizeall(dag.headsetofconnecteds(all))
2122 else:
2122 else:
2123 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2123 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2124 common = set(common)
2124 common = set(common)
2125 rheads = set(hds)
2125 rheads = set(hds)
2126 lheads = set(repo.heads())
2126 lheads = set(repo.heads())
2127 ui.write(("common heads: %s\n") %
2127 ui.write(("common heads: %s\n") %
2128 " ".join(sorted(short(n) for n in common)))
2128 " ".join(sorted(short(n) for n in common)))
2129 if lheads <= common:
2129 if lheads <= common:
2130 ui.write(("local is subset\n"))
2130 ui.write(("local is subset\n"))
2131 elif rheads <= common:
2131 elif rheads <= common:
2132 ui.write(("remote is subset\n"))
2132 ui.write(("remote is subset\n"))
2133
2133
2134 serverlogs = opts.get('serverlog')
2134 serverlogs = opts.get('serverlog')
2135 if serverlogs:
2135 if serverlogs:
2136 for filename in serverlogs:
2136 for filename in serverlogs:
2137 logfile = open(filename, 'r')
2137 logfile = open(filename, 'r')
2138 try:
2138 try:
2139 line = logfile.readline()
2139 line = logfile.readline()
2140 while line:
2140 while line:
2141 parts = line.strip().split(';')
2141 parts = line.strip().split(';')
2142 op = parts[1]
2142 op = parts[1]
2143 if op == 'cg':
2143 if op == 'cg':
2144 pass
2144 pass
2145 elif op == 'cgss':
2145 elif op == 'cgss':
2146 doit(parts[2].split(' '), parts[3].split(' '))
2146 doit(parts[2].split(' '), parts[3].split(' '))
2147 elif op == 'unb':
2147 elif op == 'unb':
2148 doit(parts[3].split(' '), parts[2].split(' '))
2148 doit(parts[3].split(' '), parts[2].split(' '))
2149 line = logfile.readline()
2149 line = logfile.readline()
2150 finally:
2150 finally:
2151 logfile.close()
2151 logfile.close()
2152
2152
2153 else:
2153 else:
2154 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2154 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2155 opts.get('remote_head'))
2155 opts.get('remote_head'))
2156 localrevs = opts.get('local_head')
2156 localrevs = opts.get('local_head')
2157 doit(localrevs, remoterevs)
2157 doit(localrevs, remoterevs)
2158
2158
2159 @command('debugfileset',
2159 @command('debugfileset',
2160 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2160 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2161 _('[-r REV] FILESPEC'))
2161 _('[-r REV] FILESPEC'))
2162 def debugfileset(ui, repo, expr, **opts):
2162 def debugfileset(ui, repo, expr, **opts):
2163 '''parse and apply a fileset specification'''
2163 '''parse and apply a fileset specification'''
2164 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2164 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2165 if ui.verbose:
2165 if ui.verbose:
2166 tree = fileset.parse(expr)[0]
2166 tree = fileset.parse(expr)[0]
2167 ui.note(tree, "\n")
2167 ui.note(tree, "\n")
2168
2168
2169 for f in ctx.getfileset(expr):
2169 for f in ctx.getfileset(expr):
2170 ui.write("%s\n" % f)
2170 ui.write("%s\n" % f)
2171
2171
2172 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2172 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2173 def debugfsinfo(ui, path="."):
2173 def debugfsinfo(ui, path="."):
2174 """show information detected about current filesystem"""
2174 """show information detected about current filesystem"""
2175 util.writefile('.debugfsinfo', '')
2175 util.writefile('.debugfsinfo', '')
2176 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2176 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2177 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2177 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2178 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2178 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2179 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2179 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2180 and 'yes' or 'no'))
2180 and 'yes' or 'no'))
2181 os.unlink('.debugfsinfo')
2181 os.unlink('.debugfsinfo')
2182
2182
2183 @command('debuggetbundle',
2183 @command('debuggetbundle',
2184 [('H', 'head', [], _('id of head node'), _('ID')),
2184 [('H', 'head', [], _('id of head node'), _('ID')),
2185 ('C', 'common', [], _('id of common node'), _('ID')),
2185 ('C', 'common', [], _('id of common node'), _('ID')),
2186 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2186 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2187 _('REPO FILE [-H|-C ID]...'),
2187 _('REPO FILE [-H|-C ID]...'),
2188 norepo=True)
2188 norepo=True)
2189 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2189 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2190 """retrieves a bundle from a repo
2190 """retrieves a bundle from a repo
2191
2191
2192 Every ID must be a full-length hex node id string. Saves the bundle to the
2192 Every ID must be a full-length hex node id string. Saves the bundle to the
2193 given file.
2193 given file.
2194 """
2194 """
2195 repo = hg.peer(ui, opts, repopath)
2195 repo = hg.peer(ui, opts, repopath)
2196 if not repo.capable('getbundle'):
2196 if not repo.capable('getbundle'):
2197 raise util.Abort("getbundle() not supported by target repository")
2197 raise util.Abort("getbundle() not supported by target repository")
2198 args = {}
2198 args = {}
2199 if common:
2199 if common:
2200 args['common'] = [bin(s) for s in common]
2200 args['common'] = [bin(s) for s in common]
2201 if head:
2201 if head:
2202 args['heads'] = [bin(s) for s in head]
2202 args['heads'] = [bin(s) for s in head]
2203 # TODO: get desired bundlecaps from command line.
2203 # TODO: get desired bundlecaps from command line.
2204 args['bundlecaps'] = None
2204 args['bundlecaps'] = None
2205 bundle = repo.getbundle('debug', **args)
2205 bundle = repo.getbundle('debug', **args)
2206
2206
2207 bundletype = opts.get('type', 'bzip2').lower()
2207 bundletype = opts.get('type', 'bzip2').lower()
2208 btypes = {'none': 'HG10UN',
2208 btypes = {'none': 'HG10UN',
2209 'bzip2': 'HG10BZ',
2209 'bzip2': 'HG10BZ',
2210 'gzip': 'HG10GZ',
2210 'gzip': 'HG10GZ',
2211 'bundle2': 'HG20'}
2211 'bundle2': 'HG20'}
2212 bundletype = btypes.get(bundletype)
2212 bundletype = btypes.get(bundletype)
2213 if bundletype not in changegroup.bundletypes:
2213 if bundletype not in changegroup.bundletypes:
2214 raise util.Abort(_('unknown bundle type specified with --type'))
2214 raise util.Abort(_('unknown bundle type specified with --type'))
2215 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2215 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2216
2216
2217 @command('debugignore', [], '')
2217 @command('debugignore', [], '')
2218 def debugignore(ui, repo, *values, **opts):
2218 def debugignore(ui, repo, *values, **opts):
2219 """display the combined ignore pattern"""
2219 """display the combined ignore pattern"""
2220 ignore = repo.dirstate._ignore
2220 ignore = repo.dirstate._ignore
2221 includepat = getattr(ignore, 'includepat', None)
2221 includepat = getattr(ignore, 'includepat', None)
2222 if includepat is not None:
2222 if includepat is not None:
2223 ui.write("%s\n" % includepat)
2223 ui.write("%s\n" % includepat)
2224 else:
2224 else:
2225 raise util.Abort(_("no ignore patterns found"))
2225 raise util.Abort(_("no ignore patterns found"))
2226
2226
2227 @command('debugindex',
2227 @command('debugindex',
2228 [('c', 'changelog', False, _('open changelog')),
2228 [('c', 'changelog', False, _('open changelog')),
2229 ('m', 'manifest', False, _('open manifest')),
2229 ('m', 'manifest', False, _('open manifest')),
2230 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2230 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2231 _('[-f FORMAT] -c|-m|FILE'),
2231 _('[-f FORMAT] -c|-m|FILE'),
2232 optionalrepo=True)
2232 optionalrepo=True)
2233 def debugindex(ui, repo, file_=None, **opts):
2233 def debugindex(ui, repo, file_=None, **opts):
2234 """dump the contents of an index file"""
2234 """dump the contents of an index file"""
2235 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2235 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2236 format = opts.get('format', 0)
2236 format = opts.get('format', 0)
2237 if format not in (0, 1):
2237 if format not in (0, 1):
2238 raise util.Abort(_("unknown format %d") % format)
2238 raise util.Abort(_("unknown format %d") % format)
2239
2239
2240 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2240 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2241 if generaldelta:
2241 if generaldelta:
2242 basehdr = ' delta'
2242 basehdr = ' delta'
2243 else:
2243 else:
2244 basehdr = ' base'
2244 basehdr = ' base'
2245
2245
2246 if ui.debugflag:
2246 if ui.debugflag:
2247 shortfn = hex
2247 shortfn = hex
2248 else:
2248 else:
2249 shortfn = short
2249 shortfn = short
2250
2250
2251 # There might not be anything in r, so have a sane default
2251 # There might not be anything in r, so have a sane default
2252 idlen = 12
2252 idlen = 12
2253 for i in r:
2253 for i in r:
2254 idlen = len(shortfn(r.node(i)))
2254 idlen = len(shortfn(r.node(i)))
2255 break
2255 break
2256
2256
2257 if format == 0:
2257 if format == 0:
2258 ui.write(" rev offset length " + basehdr + " linkrev"
2258 ui.write(" rev offset length " + basehdr + " linkrev"
2259 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2259 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2260 elif format == 1:
2260 elif format == 1:
2261 ui.write(" rev flag offset length"
2261 ui.write(" rev flag offset length"
2262 " size " + basehdr + " link p1 p2"
2262 " size " + basehdr + " link p1 p2"
2263 " %s\n" % "nodeid".rjust(idlen))
2263 " %s\n" % "nodeid".rjust(idlen))
2264
2264
2265 for i in r:
2265 for i in r:
2266 node = r.node(i)
2266 node = r.node(i)
2267 if generaldelta:
2267 if generaldelta:
2268 base = r.deltaparent(i)
2268 base = r.deltaparent(i)
2269 else:
2269 else:
2270 base = r.chainbase(i)
2270 base = r.chainbase(i)
2271 if format == 0:
2271 if format == 0:
2272 try:
2272 try:
2273 pp = r.parents(node)
2273 pp = r.parents(node)
2274 except Exception:
2274 except Exception:
2275 pp = [nullid, nullid]
2275 pp = [nullid, nullid]
2276 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2276 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2277 i, r.start(i), r.length(i), base, r.linkrev(i),
2277 i, r.start(i), r.length(i), base, r.linkrev(i),
2278 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2278 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2279 elif format == 1:
2279 elif format == 1:
2280 pr = r.parentrevs(i)
2280 pr = r.parentrevs(i)
2281 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2281 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2282 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2282 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2283 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2283 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2284
2284
2285 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2285 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2286 def debugindexdot(ui, repo, file_):
2286 def debugindexdot(ui, repo, file_):
2287 """dump an index DAG as a graphviz dot file"""
2287 """dump an index DAG as a graphviz dot file"""
2288 r = None
2288 r = None
2289 if repo:
2289 if repo:
2290 filelog = repo.file(file_)
2290 filelog = repo.file(file_)
2291 if len(filelog):
2291 if len(filelog):
2292 r = filelog
2292 r = filelog
2293 if not r:
2293 if not r:
2294 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2294 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2295 ui.write(("digraph G {\n"))
2295 ui.write(("digraph G {\n"))
2296 for i in r:
2296 for i in r:
2297 node = r.node(i)
2297 node = r.node(i)
2298 pp = r.parents(node)
2298 pp = r.parents(node)
2299 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2299 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2300 if pp[1] != nullid:
2300 if pp[1] != nullid:
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2301 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2302 ui.write("}\n")
2302 ui.write("}\n")
2303
2303
2304 @command('debuginstall', [], '', norepo=True)
2304 @command('debuginstall', [], '', norepo=True)
2305 def debuginstall(ui):
2305 def debuginstall(ui):
2306 '''test Mercurial installation
2306 '''test Mercurial installation
2307
2307
2308 Returns 0 on success.
2308 Returns 0 on success.
2309 '''
2309 '''
2310
2310
2311 def writetemp(contents):
2311 def writetemp(contents):
2312 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2312 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2313 f = os.fdopen(fd, "wb")
2313 f = os.fdopen(fd, "wb")
2314 f.write(contents)
2314 f.write(contents)
2315 f.close()
2315 f.close()
2316 return name
2316 return name
2317
2317
2318 problems = 0
2318 problems = 0
2319
2319
2320 # encoding
2320 # encoding
2321 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2321 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2322 try:
2322 try:
2323 encoding.fromlocal("test")
2323 encoding.fromlocal("test")
2324 except util.Abort, inst:
2324 except util.Abort, inst:
2325 ui.write(" %s\n" % inst)
2325 ui.write(" %s\n" % inst)
2326 ui.write(_(" (check that your locale is properly set)\n"))
2326 ui.write(_(" (check that your locale is properly set)\n"))
2327 problems += 1
2327 problems += 1
2328
2328
2329 # Python
2329 # Python
2330 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2330 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2331 ui.status(_("checking Python version (%s)\n")
2331 ui.status(_("checking Python version (%s)\n")
2332 % ("%s.%s.%s" % sys.version_info[:3]))
2332 % ("%s.%s.%s" % sys.version_info[:3]))
2333 ui.status(_("checking Python lib (%s)...\n")
2333 ui.status(_("checking Python lib (%s)...\n")
2334 % os.path.dirname(os.__file__))
2334 % os.path.dirname(os.__file__))
2335
2335
2336 # compiled modules
2336 # compiled modules
2337 ui.status(_("checking installed modules (%s)...\n")
2337 ui.status(_("checking installed modules (%s)...\n")
2338 % os.path.dirname(__file__))
2338 % os.path.dirname(__file__))
2339 try:
2339 try:
2340 import bdiff, mpatch, base85, osutil
2340 import bdiff, mpatch, base85, osutil
2341 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2341 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2342 except Exception, inst:
2342 except Exception, inst:
2343 ui.write(" %s\n" % inst)
2343 ui.write(" %s\n" % inst)
2344 ui.write(_(" One or more extensions could not be found"))
2344 ui.write(_(" One or more extensions could not be found"))
2345 ui.write(_(" (check that you compiled the extensions)\n"))
2345 ui.write(_(" (check that you compiled the extensions)\n"))
2346 problems += 1
2346 problems += 1
2347
2347
2348 # templates
2348 # templates
2349 import templater
2349 import templater
2350 p = templater.templatepaths()
2350 p = templater.templatepaths()
2351 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2351 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2352 if p:
2352 if p:
2353 m = templater.templatepath("map-cmdline.default")
2353 m = templater.templatepath("map-cmdline.default")
2354 if m:
2354 if m:
2355 # template found, check if it is working
2355 # template found, check if it is working
2356 try:
2356 try:
2357 templater.templater(m)
2357 templater.templater(m)
2358 except Exception, inst:
2358 except Exception, inst:
2359 ui.write(" %s\n" % inst)
2359 ui.write(" %s\n" % inst)
2360 p = None
2360 p = None
2361 else:
2361 else:
2362 ui.write(_(" template 'default' not found\n"))
2362 ui.write(_(" template 'default' not found\n"))
2363 p = None
2363 p = None
2364 else:
2364 else:
2365 ui.write(_(" no template directories found\n"))
2365 ui.write(_(" no template directories found\n"))
2366 if not p:
2366 if not p:
2367 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2367 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2368 problems += 1
2368 problems += 1
2369
2369
2370 # editor
2370 # editor
2371 ui.status(_("checking commit editor...\n"))
2371 ui.status(_("checking commit editor...\n"))
2372 editor = ui.geteditor()
2372 editor = ui.geteditor()
2373 editor = util.expandpath(editor)
2373 editor = util.expandpath(editor)
2374 cmdpath = util.findexe(shlex.split(editor)[0])
2374 cmdpath = util.findexe(shlex.split(editor)[0])
2375 if not cmdpath:
2375 if not cmdpath:
2376 if editor == 'vi':
2376 if editor == 'vi':
2377 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2377 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2378 ui.write(_(" (specify a commit editor in your configuration"
2378 ui.write(_(" (specify a commit editor in your configuration"
2379 " file)\n"))
2379 " file)\n"))
2380 else:
2380 else:
2381 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2381 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2382 ui.write(_(" (specify a commit editor in your configuration"
2382 ui.write(_(" (specify a commit editor in your configuration"
2383 " file)\n"))
2383 " file)\n"))
2384 problems += 1
2384 problems += 1
2385
2385
2386 # check username
2386 # check username
2387 ui.status(_("checking username...\n"))
2387 ui.status(_("checking username...\n"))
2388 try:
2388 try:
2389 ui.username()
2389 ui.username()
2390 except util.Abort, e:
2390 except util.Abort, e:
2391 ui.write(" %s\n" % e)
2391 ui.write(" %s\n" % e)
2392 ui.write(_(" (specify a username in your configuration file)\n"))
2392 ui.write(_(" (specify a username in your configuration file)\n"))
2393 problems += 1
2393 problems += 1
2394
2394
2395 if not problems:
2395 if not problems:
2396 ui.status(_("no problems detected\n"))
2396 ui.status(_("no problems detected\n"))
2397 else:
2397 else:
2398 ui.write(_("%s problems detected,"
2398 ui.write(_("%s problems detected,"
2399 " please check your install!\n") % problems)
2399 " please check your install!\n") % problems)
2400
2400
2401 return problems
2401 return problems
2402
2402
2403 @command('debugknown', [], _('REPO ID...'), norepo=True)
2403 @command('debugknown', [], _('REPO ID...'), norepo=True)
2404 def debugknown(ui, repopath, *ids, **opts):
2404 def debugknown(ui, repopath, *ids, **opts):
2405 """test whether node ids are known to a repo
2405 """test whether node ids are known to a repo
2406
2406
2407 Every ID must be a full-length hex node id string. Returns a list of 0s
2407 Every ID must be a full-length hex node id string. Returns a list of 0s
2408 and 1s indicating unknown/known.
2408 and 1s indicating unknown/known.
2409 """
2409 """
2410 repo = hg.peer(ui, opts, repopath)
2410 repo = hg.peer(ui, opts, repopath)
2411 if not repo.capable('known'):
2411 if not repo.capable('known'):
2412 raise util.Abort("known() not supported by target repository")
2412 raise util.Abort("known() not supported by target repository")
2413 flags = repo.known([bin(s) for s in ids])
2413 flags = repo.known([bin(s) for s in ids])
2414 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2414 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2415
2415
2416 @command('debuglabelcomplete', [], _('LABEL...'))
2416 @command('debuglabelcomplete', [], _('LABEL...'))
2417 def debuglabelcomplete(ui, repo, *args):
2417 def debuglabelcomplete(ui, repo, *args):
2418 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2418 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2419 debugnamecomplete(ui, repo, *args)
2419 debugnamecomplete(ui, repo, *args)
2420
2420
2421 @command('debugnamecomplete', [], _('NAME...'))
2421 @command('debugnamecomplete', [], _('NAME...'))
2422 def debugnamecomplete(ui, repo, *args):
2422 def debugnamecomplete(ui, repo, *args):
2423 '''complete "names" - tags, open branch names, bookmark names'''
2423 '''complete "names" - tags, open branch names, bookmark names'''
2424
2424
2425 names = set()
2425 names = set()
2426 # since we previously only listed open branches, we will handle that
2426 # since we previously only listed open branches, we will handle that
2427 # specially (after this for loop)
2427 # specially (after this for loop)
2428 for name, ns in repo.names.iteritems():
2428 for name, ns in repo.names.iteritems():
2429 if name != 'branches':
2429 if name != 'branches':
2430 names.update(ns.listnames(repo))
2430 names.update(ns.listnames(repo))
2431 names.update(tag for (tag, heads, tip, closed)
2431 names.update(tag for (tag, heads, tip, closed)
2432 in repo.branchmap().iterbranches() if not closed)
2432 in repo.branchmap().iterbranches() if not closed)
2433 completions = set()
2433 completions = set()
2434 if not args:
2434 if not args:
2435 args = ['']
2435 args = ['']
2436 for a in args:
2436 for a in args:
2437 completions.update(n for n in names if n.startswith(a))
2437 completions.update(n for n in names if n.startswith(a))
2438 ui.write('\n'.join(sorted(completions)))
2438 ui.write('\n'.join(sorted(completions)))
2439 ui.write('\n')
2439 ui.write('\n')
2440
2440
2441 @command('debuglocks',
2441 @command('debuglocks',
2442 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2442 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2443 ('W', 'force-wlock', None,
2443 ('W', 'force-wlock', None,
2444 _('free the working state lock (DANGEROUS)'))],
2444 _('free the working state lock (DANGEROUS)'))],
2445 _('[OPTION]...'))
2445 _('[OPTION]...'))
2446 def debuglocks(ui, repo, **opts):
2446 def debuglocks(ui, repo, **opts):
2447 """show or modify state of locks
2447 """show or modify state of locks
2448
2448
2449 By default, this command will show which locks are held. This
2449 By default, this command will show which locks are held. This
2450 includes the user and process holding the lock, the amount of time
2450 includes the user and process holding the lock, the amount of time
2451 the lock has been held, and the machine name where the process is
2451 the lock has been held, and the machine name where the process is
2452 running if it's not local.
2452 running if it's not local.
2453
2453
2454 Locks protect the integrity of Mercurial's data, so should be
2454 Locks protect the integrity of Mercurial's data, so should be
2455 treated with care. System crashes or other interruptions may cause
2455 treated with care. System crashes or other interruptions may cause
2456 locks to not be properly released, though Mercurial will usually
2456 locks to not be properly released, though Mercurial will usually
2457 detect and remove such stale locks automatically.
2457 detect and remove such stale locks automatically.
2458
2458
2459 However, detecting stale locks may not always be possible (for
2459 However, detecting stale locks may not always be possible (for
2460 instance, on a shared filesystem). Removing locks may also be
2460 instance, on a shared filesystem). Removing locks may also be
2461 blocked by filesystem permissions.
2461 blocked by filesystem permissions.
2462
2462
2463 Returns 0 if no locks are held.
2463 Returns 0 if no locks are held.
2464
2464
2465 """
2465 """
2466
2466
2467 if opts.get('force_lock'):
2467 if opts.get('force_lock'):
2468 repo.svfs.unlink('lock')
2468 repo.svfs.unlink('lock')
2469 if opts.get('force_wlock'):
2469 if opts.get('force_wlock'):
2470 repo.vfs.unlink('wlock')
2470 repo.vfs.unlink('wlock')
2471 if opts.get('force_lock') or opts.get('force_lock'):
2471 if opts.get('force_lock') or opts.get('force_lock'):
2472 return 0
2472 return 0
2473
2473
2474 now = time.time()
2474 now = time.time()
2475 held = 0
2475 held = 0
2476
2476
2477 def report(vfs, name, method):
2477 def report(vfs, name, method):
2478 # this causes stale locks to get reaped for more accurate reporting
2478 # this causes stale locks to get reaped for more accurate reporting
2479 try:
2479 try:
2480 l = method(False)
2480 l = method(False)
2481 except error.LockHeld:
2481 except error.LockHeld:
2482 l = None
2482 l = None
2483
2483
2484 if l:
2484 if l:
2485 l.release()
2485 l.release()
2486 else:
2486 else:
2487 try:
2487 try:
2488 stat = vfs.lstat(name)
2488 stat = vfs.lstat(name)
2489 age = now - stat.st_mtime
2489 age = now - stat.st_mtime
2490 user = util.username(stat.st_uid)
2490 user = util.username(stat.st_uid)
2491 locker = vfs.readlock(name)
2491 locker = vfs.readlock(name)
2492 if ":" in locker:
2492 if ":" in locker:
2493 host, pid = locker.split(':')
2493 host, pid = locker.split(':')
2494 if host == socket.gethostname():
2494 if host == socket.gethostname():
2495 locker = 'user %s, process %s' % (user, pid)
2495 locker = 'user %s, process %s' % (user, pid)
2496 else:
2496 else:
2497 locker = 'user %s, process %s, host %s' \
2497 locker = 'user %s, process %s, host %s' \
2498 % (user, pid, host)
2498 % (user, pid, host)
2499 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2499 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2500 return 1
2500 return 1
2501 except OSError, e:
2501 except OSError, e:
2502 if e.errno != errno.ENOENT:
2502 if e.errno != errno.ENOENT:
2503 raise
2503 raise
2504
2504
2505 ui.write("%-6s free\n" % (name + ":"))
2505 ui.write("%-6s free\n" % (name + ":"))
2506 return 0
2506 return 0
2507
2507
2508 held += report(repo.svfs, "lock", repo.lock)
2508 held += report(repo.svfs, "lock", repo.lock)
2509 held += report(repo.vfs, "wlock", repo.wlock)
2509 held += report(repo.vfs, "wlock", repo.wlock)
2510
2510
2511 return held
2511 return held
2512
2512
2513 @command('debugobsolete',
2513 @command('debugobsolete',
2514 [('', 'flags', 0, _('markers flag')),
2514 [('', 'flags', 0, _('markers flag')),
2515 ('', 'record-parents', False,
2515 ('', 'record-parents', False,
2516 _('record parent information for the precursor')),
2516 _('record parent information for the precursor')),
2517 ('r', 'rev', [], _('display markers relevant to REV')),
2517 ('r', 'rev', [], _('display markers relevant to REV')),
2518 ] + commitopts2,
2518 ] + commitopts2,
2519 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2519 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2520 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2520 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2521 """create arbitrary obsolete marker
2521 """create arbitrary obsolete marker
2522
2522
2523 With no arguments, displays the list of obsolescence markers."""
2523 With no arguments, displays the list of obsolescence markers."""
2524
2524
2525 def parsenodeid(s):
2525 def parsenodeid(s):
2526 try:
2526 try:
2527 # We do not use revsingle/revrange functions here to accept
2527 # We do not use revsingle/revrange functions here to accept
2528 # arbitrary node identifiers, possibly not present in the
2528 # arbitrary node identifiers, possibly not present in the
2529 # local repository.
2529 # local repository.
2530 n = bin(s)
2530 n = bin(s)
2531 if len(n) != len(nullid):
2531 if len(n) != len(nullid):
2532 raise TypeError()
2532 raise TypeError()
2533 return n
2533 return n
2534 except TypeError:
2534 except TypeError:
2535 raise util.Abort('changeset references must be full hexadecimal '
2535 raise util.Abort('changeset references must be full hexadecimal '
2536 'node identifiers')
2536 'node identifiers')
2537
2537
2538 if precursor is not None:
2538 if precursor is not None:
2539 if opts['rev']:
2539 if opts['rev']:
2540 raise util.Abort('cannot select revision when creating marker')
2540 raise util.Abort('cannot select revision when creating marker')
2541 metadata = {}
2541 metadata = {}
2542 metadata['user'] = opts['user'] or ui.username()
2542 metadata['user'] = opts['user'] or ui.username()
2543 succs = tuple(parsenodeid(succ) for succ in successors)
2543 succs = tuple(parsenodeid(succ) for succ in successors)
2544 l = repo.lock()
2544 l = repo.lock()
2545 try:
2545 try:
2546 tr = repo.transaction('debugobsolete')
2546 tr = repo.transaction('debugobsolete')
2547 try:
2547 try:
2548 try:
2548 try:
2549 date = opts.get('date')
2549 date = opts.get('date')
2550 if date:
2550 if date:
2551 date = util.parsedate(date)
2551 date = util.parsedate(date)
2552 else:
2552 else:
2553 date = None
2553 date = None
2554 prec = parsenodeid(precursor)
2554 prec = parsenodeid(precursor)
2555 parents = None
2555 parents = None
2556 if opts['record_parents']:
2556 if opts['record_parents']:
2557 if prec not in repo.unfiltered():
2557 if prec not in repo.unfiltered():
2558 raise util.Abort('cannot used --record-parents on '
2558 raise util.Abort('cannot used --record-parents on '
2559 'unknown changesets')
2559 'unknown changesets')
2560 parents = repo.unfiltered()[prec].parents()
2560 parents = repo.unfiltered()[prec].parents()
2561 parents = tuple(p.node() for p in parents)
2561 parents = tuple(p.node() for p in parents)
2562 repo.obsstore.create(tr, prec, succs, opts['flags'],
2562 repo.obsstore.create(tr, prec, succs, opts['flags'],
2563 parents=parents, date=date,
2563 parents=parents, date=date,
2564 metadata=metadata)
2564 metadata=metadata)
2565 tr.close()
2565 tr.close()
2566 except ValueError, exc:
2566 except ValueError, exc:
2567 raise util.Abort(_('bad obsmarker input: %s') % exc)
2567 raise util.Abort(_('bad obsmarker input: %s') % exc)
2568 finally:
2568 finally:
2569 tr.release()
2569 tr.release()
2570 finally:
2570 finally:
2571 l.release()
2571 l.release()
2572 else:
2572 else:
2573 if opts['rev']:
2573 if opts['rev']:
2574 revs = scmutil.revrange(repo, opts['rev'])
2574 revs = scmutil.revrange(repo, opts['rev'])
2575 nodes = [repo[r].node() for r in revs]
2575 nodes = [repo[r].node() for r in revs]
2576 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2576 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2577 markers.sort(key=lambda x: x._data)
2577 markers.sort(key=lambda x: x._data)
2578 else:
2578 else:
2579 markers = obsolete.getmarkers(repo)
2579 markers = obsolete.getmarkers(repo)
2580
2580
2581 for m in markers:
2581 for m in markers:
2582 cmdutil.showmarker(ui, m)
2582 cmdutil.showmarker(ui, m)
2583
2583
2584 @command('debugpathcomplete',
2584 @command('debugpathcomplete',
2585 [('f', 'full', None, _('complete an entire path')),
2585 [('f', 'full', None, _('complete an entire path')),
2586 ('n', 'normal', None, _('show only normal files')),
2586 ('n', 'normal', None, _('show only normal files')),
2587 ('a', 'added', None, _('show only added files')),
2587 ('a', 'added', None, _('show only added files')),
2588 ('r', 'removed', None, _('show only removed files'))],
2588 ('r', 'removed', None, _('show only removed files'))],
2589 _('FILESPEC...'))
2589 _('FILESPEC...'))
2590 def debugpathcomplete(ui, repo, *specs, **opts):
2590 def debugpathcomplete(ui, repo, *specs, **opts):
2591 '''complete part or all of a tracked path
2591 '''complete part or all of a tracked path
2592
2592
2593 This command supports shells that offer path name completion. It
2593 This command supports shells that offer path name completion. It
2594 currently completes only files already known to the dirstate.
2594 currently completes only files already known to the dirstate.
2595
2595
2596 Completion extends only to the next path segment unless
2596 Completion extends only to the next path segment unless
2597 --full is specified, in which case entire paths are used.'''
2597 --full is specified, in which case entire paths are used.'''
2598
2598
2599 def complete(path, acceptable):
2599 def complete(path, acceptable):
2600 dirstate = repo.dirstate
2600 dirstate = repo.dirstate
2601 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2601 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2602 rootdir = repo.root + os.sep
2602 rootdir = repo.root + os.sep
2603 if spec != repo.root and not spec.startswith(rootdir):
2603 if spec != repo.root and not spec.startswith(rootdir):
2604 return [], []
2604 return [], []
2605 if os.path.isdir(spec):
2605 if os.path.isdir(spec):
2606 spec += '/'
2606 spec += '/'
2607 spec = spec[len(rootdir):]
2607 spec = spec[len(rootdir):]
2608 fixpaths = os.sep != '/'
2608 fixpaths = os.sep != '/'
2609 if fixpaths:
2609 if fixpaths:
2610 spec = spec.replace(os.sep, '/')
2610 spec = spec.replace(os.sep, '/')
2611 speclen = len(spec)
2611 speclen = len(spec)
2612 fullpaths = opts['full']
2612 fullpaths = opts['full']
2613 files, dirs = set(), set()
2613 files, dirs = set(), set()
2614 adddir, addfile = dirs.add, files.add
2614 adddir, addfile = dirs.add, files.add
2615 for f, st in dirstate.iteritems():
2615 for f, st in dirstate.iteritems():
2616 if f.startswith(spec) and st[0] in acceptable:
2616 if f.startswith(spec) and st[0] in acceptable:
2617 if fixpaths:
2617 if fixpaths:
2618 f = f.replace('/', os.sep)
2618 f = f.replace('/', os.sep)
2619 if fullpaths:
2619 if fullpaths:
2620 addfile(f)
2620 addfile(f)
2621 continue
2621 continue
2622 s = f.find(os.sep, speclen)
2622 s = f.find(os.sep, speclen)
2623 if s >= 0:
2623 if s >= 0:
2624 adddir(f[:s])
2624 adddir(f[:s])
2625 else:
2625 else:
2626 addfile(f)
2626 addfile(f)
2627 return files, dirs
2627 return files, dirs
2628
2628
2629 acceptable = ''
2629 acceptable = ''
2630 if opts['normal']:
2630 if opts['normal']:
2631 acceptable += 'nm'
2631 acceptable += 'nm'
2632 if opts['added']:
2632 if opts['added']:
2633 acceptable += 'a'
2633 acceptable += 'a'
2634 if opts['removed']:
2634 if opts['removed']:
2635 acceptable += 'r'
2635 acceptable += 'r'
2636 cwd = repo.getcwd()
2636 cwd = repo.getcwd()
2637 if not specs:
2637 if not specs:
2638 specs = ['.']
2638 specs = ['.']
2639
2639
2640 files, dirs = set(), set()
2640 files, dirs = set(), set()
2641 for spec in specs:
2641 for spec in specs:
2642 f, d = complete(spec, acceptable or 'nmar')
2642 f, d = complete(spec, acceptable or 'nmar')
2643 files.update(f)
2643 files.update(f)
2644 dirs.update(d)
2644 dirs.update(d)
2645 files.update(dirs)
2645 files.update(dirs)
2646 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2646 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2647 ui.write('\n')
2647 ui.write('\n')
2648
2648
2649 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2649 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2650 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2650 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2651 '''access the pushkey key/value protocol
2651 '''access the pushkey key/value protocol
2652
2652
2653 With two args, list the keys in the given namespace.
2653 With two args, list the keys in the given namespace.
2654
2654
2655 With five args, set a key to new if it currently is set to old.
2655 With five args, set a key to new if it currently is set to old.
2656 Reports success or failure.
2656 Reports success or failure.
2657 '''
2657 '''
2658
2658
2659 target = hg.peer(ui, {}, repopath)
2659 target = hg.peer(ui, {}, repopath)
2660 if keyinfo:
2660 if keyinfo:
2661 key, old, new = keyinfo
2661 key, old, new = keyinfo
2662 r = target.pushkey(namespace, key, old, new)
2662 r = target.pushkey(namespace, key, old, new)
2663 ui.status(str(r) + '\n')
2663 ui.status(str(r) + '\n')
2664 return not r
2664 return not r
2665 else:
2665 else:
2666 for k, v in sorted(target.listkeys(namespace).iteritems()):
2666 for k, v in sorted(target.listkeys(namespace).iteritems()):
2667 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2667 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2668 v.encode('string-escape')))
2668 v.encode('string-escape')))
2669
2669
2670 @command('debugpvec', [], _('A B'))
2670 @command('debugpvec', [], _('A B'))
2671 def debugpvec(ui, repo, a, b=None):
2671 def debugpvec(ui, repo, a, b=None):
2672 ca = scmutil.revsingle(repo, a)
2672 ca = scmutil.revsingle(repo, a)
2673 cb = scmutil.revsingle(repo, b)
2673 cb = scmutil.revsingle(repo, b)
2674 pa = pvec.ctxpvec(ca)
2674 pa = pvec.ctxpvec(ca)
2675 pb = pvec.ctxpvec(cb)
2675 pb = pvec.ctxpvec(cb)
2676 if pa == pb:
2676 if pa == pb:
2677 rel = "="
2677 rel = "="
2678 elif pa > pb:
2678 elif pa > pb:
2679 rel = ">"
2679 rel = ">"
2680 elif pa < pb:
2680 elif pa < pb:
2681 rel = "<"
2681 rel = "<"
2682 elif pa | pb:
2682 elif pa | pb:
2683 rel = "|"
2683 rel = "|"
2684 ui.write(_("a: %s\n") % pa)
2684 ui.write(_("a: %s\n") % pa)
2685 ui.write(_("b: %s\n") % pb)
2685 ui.write(_("b: %s\n") % pb)
2686 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2686 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2687 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2687 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2688 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2688 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2689 pa.distance(pb), rel))
2689 pa.distance(pb), rel))
2690
2690
2691 @command('debugrebuilddirstate|debugrebuildstate',
2691 @command('debugrebuilddirstate|debugrebuildstate',
2692 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2692 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2693 _('[-r REV]'))
2693 _('[-r REV]'))
2694 def debugrebuilddirstate(ui, repo, rev):
2694 def debugrebuilddirstate(ui, repo, rev):
2695 """rebuild the dirstate as it would look like for the given revision
2695 """rebuild the dirstate as it would look like for the given revision
2696
2696
2697 If no revision is specified the first current parent will be used.
2697 If no revision is specified the first current parent will be used.
2698
2698
2699 The dirstate will be set to the files of the given revision.
2699 The dirstate will be set to the files of the given revision.
2700 The actual working directory content or existing dirstate
2700 The actual working directory content or existing dirstate
2701 information such as adds or removes is not considered.
2701 information such as adds or removes is not considered.
2702
2702
2703 One use of this command is to make the next :hg:`status` invocation
2703 One use of this command is to make the next :hg:`status` invocation
2704 check the actual file content.
2704 check the actual file content.
2705 """
2705 """
2706 ctx = scmutil.revsingle(repo, rev)
2706 ctx = scmutil.revsingle(repo, rev)
2707 wlock = repo.wlock()
2707 wlock = repo.wlock()
2708 try:
2708 try:
2709 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2709 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2710 finally:
2710 finally:
2711 wlock.release()
2711 wlock.release()
2712
2712
2713 @command('debugrename',
2713 @command('debugrename',
2714 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2714 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2715 _('[-r REV] FILE'))
2715 _('[-r REV] FILE'))
2716 def debugrename(ui, repo, file1, *pats, **opts):
2716 def debugrename(ui, repo, file1, *pats, **opts):
2717 """dump rename information"""
2717 """dump rename information"""
2718
2718
2719 ctx = scmutil.revsingle(repo, opts.get('rev'))
2719 ctx = scmutil.revsingle(repo, opts.get('rev'))
2720 m = scmutil.match(ctx, (file1,) + pats, opts)
2720 m = scmutil.match(ctx, (file1,) + pats, opts)
2721 for abs in ctx.walk(m):
2721 for abs in ctx.walk(m):
2722 fctx = ctx[abs]
2722 fctx = ctx[abs]
2723 o = fctx.filelog().renamed(fctx.filenode())
2723 o = fctx.filelog().renamed(fctx.filenode())
2724 rel = m.rel(abs)
2724 rel = m.rel(abs)
2725 if o:
2725 if o:
2726 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2726 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2727 else:
2727 else:
2728 ui.write(_("%s not renamed\n") % rel)
2728 ui.write(_("%s not renamed\n") % rel)
2729
2729
2730 @command('debugrevlog',
2730 @command('debugrevlog',
2731 [('c', 'changelog', False, _('open changelog')),
2731 [('c', 'changelog', False, _('open changelog')),
2732 ('m', 'manifest', False, _('open manifest')),
2732 ('m', 'manifest', False, _('open manifest')),
2733 ('d', 'dump', False, _('dump index data'))],
2733 ('d', 'dump', False, _('dump index data'))],
2734 _('-c|-m|FILE'),
2734 _('-c|-m|FILE'),
2735 optionalrepo=True)
2735 optionalrepo=True)
2736 def debugrevlog(ui, repo, file_=None, **opts):
2736 def debugrevlog(ui, repo, file_=None, **opts):
2737 """show data and statistics about a revlog"""
2737 """show data and statistics about a revlog"""
2738 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2738 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2739
2739
2740 if opts.get("dump"):
2740 if opts.get("dump"):
2741 numrevs = len(r)
2741 numrevs = len(r)
2742 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2742 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2743 " rawsize totalsize compression heads chainlen\n")
2743 " rawsize totalsize compression heads chainlen\n")
2744 ts = 0
2744 ts = 0
2745 heads = set()
2745 heads = set()
2746
2746
2747 for rev in xrange(numrevs):
2747 for rev in xrange(numrevs):
2748 dbase = r.deltaparent(rev)
2748 dbase = r.deltaparent(rev)
2749 if dbase == -1:
2749 if dbase == -1:
2750 dbase = rev
2750 dbase = rev
2751 cbase = r.chainbase(rev)
2751 cbase = r.chainbase(rev)
2752 clen = r.chainlen(rev)
2752 clen = r.chainlen(rev)
2753 p1, p2 = r.parentrevs(rev)
2753 p1, p2 = r.parentrevs(rev)
2754 rs = r.rawsize(rev)
2754 rs = r.rawsize(rev)
2755 ts = ts + rs
2755 ts = ts + rs
2756 heads -= set(r.parentrevs(rev))
2756 heads -= set(r.parentrevs(rev))
2757 heads.add(rev)
2757 heads.add(rev)
2758 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2758 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2759 "%11d %5d %8d\n" %
2759 "%11d %5d %8d\n" %
2760 (rev, p1, p2, r.start(rev), r.end(rev),
2760 (rev, p1, p2, r.start(rev), r.end(rev),
2761 r.start(dbase), r.start(cbase),
2761 r.start(dbase), r.start(cbase),
2762 r.start(p1), r.start(p2),
2762 r.start(p1), r.start(p2),
2763 rs, ts, ts / r.end(rev), len(heads), clen))
2763 rs, ts, ts / r.end(rev), len(heads), clen))
2764 return 0
2764 return 0
2765
2765
2766 v = r.version
2766 v = r.version
2767 format = v & 0xFFFF
2767 format = v & 0xFFFF
2768 flags = []
2768 flags = []
2769 gdelta = False
2769 gdelta = False
2770 if v & revlog.REVLOGNGINLINEDATA:
2770 if v & revlog.REVLOGNGINLINEDATA:
2771 flags.append('inline')
2771 flags.append('inline')
2772 if v & revlog.REVLOGGENERALDELTA:
2772 if v & revlog.REVLOGGENERALDELTA:
2773 gdelta = True
2773 gdelta = True
2774 flags.append('generaldelta')
2774 flags.append('generaldelta')
2775 if not flags:
2775 if not flags:
2776 flags = ['(none)']
2776 flags = ['(none)']
2777
2777
2778 nummerges = 0
2778 nummerges = 0
2779 numfull = 0
2779 numfull = 0
2780 numprev = 0
2780 numprev = 0
2781 nump1 = 0
2781 nump1 = 0
2782 nump2 = 0
2782 nump2 = 0
2783 numother = 0
2783 numother = 0
2784 nump1prev = 0
2784 nump1prev = 0
2785 nump2prev = 0
2785 nump2prev = 0
2786 chainlengths = []
2786 chainlengths = []
2787
2787
2788 datasize = [None, 0, 0L]
2788 datasize = [None, 0, 0L]
2789 fullsize = [None, 0, 0L]
2789 fullsize = [None, 0, 0L]
2790 deltasize = [None, 0, 0L]
2790 deltasize = [None, 0, 0L]
2791
2791
2792 def addsize(size, l):
2792 def addsize(size, l):
2793 if l[0] is None or size < l[0]:
2793 if l[0] is None or size < l[0]:
2794 l[0] = size
2794 l[0] = size
2795 if size > l[1]:
2795 if size > l[1]:
2796 l[1] = size
2796 l[1] = size
2797 l[2] += size
2797 l[2] += size
2798
2798
2799 numrevs = len(r)
2799 numrevs = len(r)
2800 for rev in xrange(numrevs):
2800 for rev in xrange(numrevs):
2801 p1, p2 = r.parentrevs(rev)
2801 p1, p2 = r.parentrevs(rev)
2802 delta = r.deltaparent(rev)
2802 delta = r.deltaparent(rev)
2803 if format > 0:
2803 if format > 0:
2804 addsize(r.rawsize(rev), datasize)
2804 addsize(r.rawsize(rev), datasize)
2805 if p2 != nullrev:
2805 if p2 != nullrev:
2806 nummerges += 1
2806 nummerges += 1
2807 size = r.length(rev)
2807 size = r.length(rev)
2808 if delta == nullrev:
2808 if delta == nullrev:
2809 chainlengths.append(0)
2809 chainlengths.append(0)
2810 numfull += 1
2810 numfull += 1
2811 addsize(size, fullsize)
2811 addsize(size, fullsize)
2812 else:
2812 else:
2813 chainlengths.append(chainlengths[delta] + 1)
2813 chainlengths.append(chainlengths[delta] + 1)
2814 addsize(size, deltasize)
2814 addsize(size, deltasize)
2815 if delta == rev - 1:
2815 if delta == rev - 1:
2816 numprev += 1
2816 numprev += 1
2817 if delta == p1:
2817 if delta == p1:
2818 nump1prev += 1
2818 nump1prev += 1
2819 elif delta == p2:
2819 elif delta == p2:
2820 nump2prev += 1
2820 nump2prev += 1
2821 elif delta == p1:
2821 elif delta == p1:
2822 nump1 += 1
2822 nump1 += 1
2823 elif delta == p2:
2823 elif delta == p2:
2824 nump2 += 1
2824 nump2 += 1
2825 elif delta != nullrev:
2825 elif delta != nullrev:
2826 numother += 1
2826 numother += 1
2827
2827
2828 # Adjust size min value for empty cases
2828 # Adjust size min value for empty cases
2829 for size in (datasize, fullsize, deltasize):
2829 for size in (datasize, fullsize, deltasize):
2830 if size[0] is None:
2830 if size[0] is None:
2831 size[0] = 0
2831 size[0] = 0
2832
2832
2833 numdeltas = numrevs - numfull
2833 numdeltas = numrevs - numfull
2834 numoprev = numprev - nump1prev - nump2prev
2834 numoprev = numprev - nump1prev - nump2prev
2835 totalrawsize = datasize[2]
2835 totalrawsize = datasize[2]
2836 datasize[2] /= numrevs
2836 datasize[2] /= numrevs
2837 fulltotal = fullsize[2]
2837 fulltotal = fullsize[2]
2838 fullsize[2] /= numfull
2838 fullsize[2] /= numfull
2839 deltatotal = deltasize[2]
2839 deltatotal = deltasize[2]
2840 if numrevs - numfull > 0:
2840 if numrevs - numfull > 0:
2841 deltasize[2] /= numrevs - numfull
2841 deltasize[2] /= numrevs - numfull
2842 totalsize = fulltotal + deltatotal
2842 totalsize = fulltotal + deltatotal
2843 avgchainlen = sum(chainlengths) / numrevs
2843 avgchainlen = sum(chainlengths) / numrevs
2844 maxchainlen = max(chainlengths)
2844 maxchainlen = max(chainlengths)
2845 compratio = totalrawsize / totalsize
2845 compratio = totalrawsize / totalsize
2846
2846
2847 basedfmtstr = '%%%dd\n'
2847 basedfmtstr = '%%%dd\n'
2848 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2848 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2849
2849
2850 def dfmtstr(max):
2850 def dfmtstr(max):
2851 return basedfmtstr % len(str(max))
2851 return basedfmtstr % len(str(max))
2852 def pcfmtstr(max, padding=0):
2852 def pcfmtstr(max, padding=0):
2853 return basepcfmtstr % (len(str(max)), ' ' * padding)
2853 return basepcfmtstr % (len(str(max)), ' ' * padding)
2854
2854
2855 def pcfmt(value, total):
2855 def pcfmt(value, total):
2856 return (value, 100 * float(value) / total)
2856 return (value, 100 * float(value) / total)
2857
2857
2858 ui.write(('format : %d\n') % format)
2858 ui.write(('format : %d\n') % format)
2859 ui.write(('flags : %s\n') % ', '.join(flags))
2859 ui.write(('flags : %s\n') % ', '.join(flags))
2860
2860
2861 ui.write('\n')
2861 ui.write('\n')
2862 fmt = pcfmtstr(totalsize)
2862 fmt = pcfmtstr(totalsize)
2863 fmt2 = dfmtstr(totalsize)
2863 fmt2 = dfmtstr(totalsize)
2864 ui.write(('revisions : ') + fmt2 % numrevs)
2864 ui.write(('revisions : ') + fmt2 % numrevs)
2865 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2865 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2866 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2866 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2867 ui.write(('revisions : ') + fmt2 % numrevs)
2867 ui.write(('revisions : ') + fmt2 % numrevs)
2868 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2868 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2869 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2869 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2870 ui.write(('revision size : ') + fmt2 % totalsize)
2870 ui.write(('revision size : ') + fmt2 % totalsize)
2871 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2871 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2872 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2872 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2873
2873
2874 ui.write('\n')
2874 ui.write('\n')
2875 fmt = dfmtstr(max(avgchainlen, compratio))
2875 fmt = dfmtstr(max(avgchainlen, compratio))
2876 ui.write(('avg chain length : ') + fmt % avgchainlen)
2876 ui.write(('avg chain length : ') + fmt % avgchainlen)
2877 ui.write(('max chain length : ') + fmt % maxchainlen)
2877 ui.write(('max chain length : ') + fmt % maxchainlen)
2878 ui.write(('compression ratio : ') + fmt % compratio)
2878 ui.write(('compression ratio : ') + fmt % compratio)
2879
2879
2880 if format > 0:
2880 if format > 0:
2881 ui.write('\n')
2881 ui.write('\n')
2882 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2882 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2883 % tuple(datasize))
2883 % tuple(datasize))
2884 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2884 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2885 % tuple(fullsize))
2885 % tuple(fullsize))
2886 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2886 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2887 % tuple(deltasize))
2887 % tuple(deltasize))
2888
2888
2889 if numdeltas > 0:
2889 if numdeltas > 0:
2890 ui.write('\n')
2890 ui.write('\n')
2891 fmt = pcfmtstr(numdeltas)
2891 fmt = pcfmtstr(numdeltas)
2892 fmt2 = pcfmtstr(numdeltas, 4)
2892 fmt2 = pcfmtstr(numdeltas, 4)
2893 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2893 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2894 if numprev > 0:
2894 if numprev > 0:
2895 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2895 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2896 numprev))
2896 numprev))
2897 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2897 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2898 numprev))
2898 numprev))
2899 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2899 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2900 numprev))
2900 numprev))
2901 if gdelta:
2901 if gdelta:
2902 ui.write(('deltas against p1 : ')
2902 ui.write(('deltas against p1 : ')
2903 + fmt % pcfmt(nump1, numdeltas))
2903 + fmt % pcfmt(nump1, numdeltas))
2904 ui.write(('deltas against p2 : ')
2904 ui.write(('deltas against p2 : ')
2905 + fmt % pcfmt(nump2, numdeltas))
2905 + fmt % pcfmt(nump2, numdeltas))
2906 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2906 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2907 numdeltas))
2907 numdeltas))
2908
2908
2909 @command('debugrevspec',
2909 @command('debugrevspec',
2910 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2910 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2911 ('REVSPEC'))
2911 ('REVSPEC'))
2912 def debugrevspec(ui, repo, expr, **opts):
2912 def debugrevspec(ui, repo, expr, **opts):
2913 """parse and apply a revision specification
2913 """parse and apply a revision specification
2914
2914
2915 Use --verbose to print the parsed tree before and after aliases
2915 Use --verbose to print the parsed tree before and after aliases
2916 expansion.
2916 expansion.
2917 """
2917 """
2918 if ui.verbose:
2918 if ui.verbose:
2919 tree = revset.parse(expr)[0]
2919 tree = revset.parse(expr)[0]
2920 ui.note(revset.prettyformat(tree), "\n")
2920 ui.note(revset.prettyformat(tree), "\n")
2921 newtree = revset.findaliases(ui, tree)
2921 newtree = revset.findaliases(ui, tree)
2922 if newtree != tree:
2922 if newtree != tree:
2923 ui.note(revset.prettyformat(newtree), "\n")
2923 ui.note(revset.prettyformat(newtree), "\n")
2924 tree = newtree
2924 tree = newtree
2925 newtree = revset.foldconcat(tree)
2925 newtree = revset.foldconcat(tree)
2926 if newtree != tree:
2926 if newtree != tree:
2927 ui.note(revset.prettyformat(newtree), "\n")
2927 ui.note(revset.prettyformat(newtree), "\n")
2928 if opts["optimize"]:
2928 if opts["optimize"]:
2929 weight, optimizedtree = revset.optimize(newtree, True)
2929 weight, optimizedtree = revset.optimize(newtree, True)
2930 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2930 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2931 func = revset.match(ui, expr)
2931 func = revset.match(ui, expr)
2932 revs = func(repo)
2932 revs = func(repo)
2933 if ui.verbose:
2933 if ui.verbose:
2934 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2934 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2935 for c in revs:
2935 for c in revs:
2936 ui.write("%s\n" % c)
2936 ui.write("%s\n" % c)
2937
2937
2938 @command('debugsetparents', [], _('REV1 [REV2]'))
2938 @command('debugsetparents', [], _('REV1 [REV2]'))
2939 def debugsetparents(ui, repo, rev1, rev2=None):
2939 def debugsetparents(ui, repo, rev1, rev2=None):
2940 """manually set the parents of the current working directory
2940 """manually set the parents of the current working directory
2941
2941
2942 This is useful for writing repository conversion tools, but should
2942 This is useful for writing repository conversion tools, but should
2943 be used with care. For example, neither the working directory nor the
2943 be used with care. For example, neither the working directory nor the
2944 dirstate is updated, so file status may be incorrect after running this
2944 dirstate is updated, so file status may be incorrect after running this
2945 command.
2945 command.
2946
2946
2947 Returns 0 on success.
2947 Returns 0 on success.
2948 """
2948 """
2949
2949
2950 r1 = scmutil.revsingle(repo, rev1).node()
2950 r1 = scmutil.revsingle(repo, rev1).node()
2951 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2951 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2952
2952
2953 wlock = repo.wlock()
2953 wlock = repo.wlock()
2954 try:
2954 try:
2955 repo.dirstate.beginparentchange()
2955 repo.dirstate.beginparentchange()
2956 repo.setparents(r1, r2)
2956 repo.setparents(r1, r2)
2957 repo.dirstate.endparentchange()
2957 repo.dirstate.endparentchange()
2958 finally:
2958 finally:
2959 wlock.release()
2959 wlock.release()
2960
2960
2961 @command('debugdirstate|debugstate',
2961 @command('debugdirstate|debugstate',
2962 [('', 'nodates', None, _('do not display the saved mtime')),
2962 [('', 'nodates', None, _('do not display the saved mtime')),
2963 ('', 'datesort', None, _('sort by saved mtime'))],
2963 ('', 'datesort', None, _('sort by saved mtime'))],
2964 _('[OPTION]...'))
2964 _('[OPTION]...'))
2965 def debugstate(ui, repo, nodates=None, datesort=None):
2965 def debugstate(ui, repo, nodates=None, datesort=None):
2966 """show the contents of the current dirstate"""
2966 """show the contents of the current dirstate"""
2967 timestr = ""
2967 timestr = ""
2968 if datesort:
2968 if datesort:
2969 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2969 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2970 else:
2970 else:
2971 keyfunc = None # sort by filename
2971 keyfunc = None # sort by filename
2972 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2972 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2973 if ent[3] == -1:
2973 if ent[3] == -1:
2974 timestr = 'unset '
2974 timestr = 'unset '
2975 elif nodates:
2975 elif nodates:
2976 timestr = 'set '
2976 timestr = 'set '
2977 else:
2977 else:
2978 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2978 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2979 time.localtime(ent[3]))
2979 time.localtime(ent[3]))
2980 if ent[1] & 020000:
2980 if ent[1] & 020000:
2981 mode = 'lnk'
2981 mode = 'lnk'
2982 else:
2982 else:
2983 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2983 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2984 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2984 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2985 for f in repo.dirstate.copies():
2985 for f in repo.dirstate.copies():
2986 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2986 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2987
2987
2988 @command('debugsub',
2988 @command('debugsub',
2989 [('r', 'rev', '',
2989 [('r', 'rev', '',
2990 _('revision to check'), _('REV'))],
2990 _('revision to check'), _('REV'))],
2991 _('[-r REV] [REV]'))
2991 _('[-r REV] [REV]'))
2992 def debugsub(ui, repo, rev=None):
2992 def debugsub(ui, repo, rev=None):
2993 ctx = scmutil.revsingle(repo, rev, None)
2993 ctx = scmutil.revsingle(repo, rev, None)
2994 for k, v in sorted(ctx.substate.items()):
2994 for k, v in sorted(ctx.substate.items()):
2995 ui.write(('path %s\n') % k)
2995 ui.write(('path %s\n') % k)
2996 ui.write((' source %s\n') % v[0])
2996 ui.write((' source %s\n') % v[0])
2997 ui.write((' revision %s\n') % v[1])
2997 ui.write((' revision %s\n') % v[1])
2998
2998
2999 @command('debugsuccessorssets',
2999 @command('debugsuccessorssets',
3000 [],
3000 [],
3001 _('[REV]'))
3001 _('[REV]'))
3002 def debugsuccessorssets(ui, repo, *revs):
3002 def debugsuccessorssets(ui, repo, *revs):
3003 """show set of successors for revision
3003 """show set of successors for revision
3004
3004
3005 A successors set of changeset A is a consistent group of revisions that
3005 A successors set of changeset A is a consistent group of revisions that
3006 succeed A. It contains non-obsolete changesets only.
3006 succeed A. It contains non-obsolete changesets only.
3007
3007
3008 In most cases a changeset A has a single successors set containing a single
3008 In most cases a changeset A has a single successors set containing a single
3009 successor (changeset A replaced by A').
3009 successor (changeset A replaced by A').
3010
3010
3011 A changeset that is made obsolete with no successors are called "pruned".
3011 A changeset that is made obsolete with no successors are called "pruned".
3012 Such changesets have no successors sets at all.
3012 Such changesets have no successors sets at all.
3013
3013
3014 A changeset that has been "split" will have a successors set containing
3014 A changeset that has been "split" will have a successors set containing
3015 more than one successor.
3015 more than one successor.
3016
3016
3017 A changeset that has been rewritten in multiple different ways is called
3017 A changeset that has been rewritten in multiple different ways is called
3018 "divergent". Such changesets have multiple successor sets (each of which
3018 "divergent". Such changesets have multiple successor sets (each of which
3019 may also be split, i.e. have multiple successors).
3019 may also be split, i.e. have multiple successors).
3020
3020
3021 Results are displayed as follows::
3021 Results are displayed as follows::
3022
3022
3023 <rev1>
3023 <rev1>
3024 <successors-1A>
3024 <successors-1A>
3025 <rev2>
3025 <rev2>
3026 <successors-2A>
3026 <successors-2A>
3027 <successors-2B1> <successors-2B2> <successors-2B3>
3027 <successors-2B1> <successors-2B2> <successors-2B3>
3028
3028
3029 Here rev2 has two possible (i.e. divergent) successors sets. The first
3029 Here rev2 has two possible (i.e. divergent) successors sets. The first
3030 holds one element, whereas the second holds three (i.e. the changeset has
3030 holds one element, whereas the second holds three (i.e. the changeset has
3031 been split).
3031 been split).
3032 """
3032 """
3033 # passed to successorssets caching computation from one call to another
3033 # passed to successorssets caching computation from one call to another
3034 cache = {}
3034 cache = {}
3035 ctx2str = str
3035 ctx2str = str
3036 node2str = short
3036 node2str = short
3037 if ui.debug():
3037 if ui.debug():
3038 def ctx2str(ctx):
3038 def ctx2str(ctx):
3039 return ctx.hex()
3039 return ctx.hex()
3040 node2str = hex
3040 node2str = hex
3041 for rev in scmutil.revrange(repo, revs):
3041 for rev in scmutil.revrange(repo, revs):
3042 ctx = repo[rev]
3042 ctx = repo[rev]
3043 ui.write('%s\n'% ctx2str(ctx))
3043 ui.write('%s\n'% ctx2str(ctx))
3044 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3044 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3045 if succsset:
3045 if succsset:
3046 ui.write(' ')
3046 ui.write(' ')
3047 ui.write(node2str(succsset[0]))
3047 ui.write(node2str(succsset[0]))
3048 for node in succsset[1:]:
3048 for node in succsset[1:]:
3049 ui.write(' ')
3049 ui.write(' ')
3050 ui.write(node2str(node))
3050 ui.write(node2str(node))
3051 ui.write('\n')
3051 ui.write('\n')
3052
3052
3053 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3053 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3054 def debugwalk(ui, repo, *pats, **opts):
3054 def debugwalk(ui, repo, *pats, **opts):
3055 """show how files match on given patterns"""
3055 """show how files match on given patterns"""
3056 m = scmutil.match(repo[None], pats, opts)
3056 m = scmutil.match(repo[None], pats, opts)
3057 items = list(repo.walk(m))
3057 items = list(repo.walk(m))
3058 if not items:
3058 if not items:
3059 return
3059 return
3060 f = lambda fn: fn
3060 f = lambda fn: fn
3061 if ui.configbool('ui', 'slash') and os.sep != '/':
3061 if ui.configbool('ui', 'slash') and os.sep != '/':
3062 f = lambda fn: util.normpath(fn)
3062 f = lambda fn: util.normpath(fn)
3063 fmt = 'f %%-%ds %%-%ds %%s' % (
3063 fmt = 'f %%-%ds %%-%ds %%s' % (
3064 max([len(abs) for abs in items]),
3064 max([len(abs) for abs in items]),
3065 max([len(m.rel(abs)) for abs in items]))
3065 max([len(m.rel(abs)) for abs in items]))
3066 for abs in items:
3066 for abs in items:
3067 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3067 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3068 ui.write("%s\n" % line.rstrip())
3068 ui.write("%s\n" % line.rstrip())
3069
3069
3070 @command('debugwireargs',
3070 @command('debugwireargs',
3071 [('', 'three', '', 'three'),
3071 [('', 'three', '', 'three'),
3072 ('', 'four', '', 'four'),
3072 ('', 'four', '', 'four'),
3073 ('', 'five', '', 'five'),
3073 ('', 'five', '', 'five'),
3074 ] + remoteopts,
3074 ] + remoteopts,
3075 _('REPO [OPTIONS]... [ONE [TWO]]'),
3075 _('REPO [OPTIONS]... [ONE [TWO]]'),
3076 norepo=True)
3076 norepo=True)
3077 def debugwireargs(ui, repopath, *vals, **opts):
3077 def debugwireargs(ui, repopath, *vals, **opts):
3078 repo = hg.peer(ui, opts, repopath)
3078 repo = hg.peer(ui, opts, repopath)
3079 for opt in remoteopts:
3079 for opt in remoteopts:
3080 del opts[opt[1]]
3080 del opts[opt[1]]
3081 args = {}
3081 args = {}
3082 for k, v in opts.iteritems():
3082 for k, v in opts.iteritems():
3083 if v:
3083 if v:
3084 args[k] = v
3084 args[k] = v
3085 # run twice to check that we don't mess up the stream for the next command
3085 # run twice to check that we don't mess up the stream for the next command
3086 res1 = repo.debugwireargs(*vals, **args)
3086 res1 = repo.debugwireargs(*vals, **args)
3087 res2 = repo.debugwireargs(*vals, **args)
3087 res2 = repo.debugwireargs(*vals, **args)
3088 ui.write("%s\n" % res1)
3088 ui.write("%s\n" % res1)
3089 if res1 != res2:
3089 if res1 != res2:
3090 ui.warn("%s\n" % res2)
3090 ui.warn("%s\n" % res2)
3091
3091
3092 @command('^diff',
3092 @command('^diff',
3093 [('r', 'rev', [], _('revision'), _('REV')),
3093 [('r', 'rev', [], _('revision'), _('REV')),
3094 ('c', 'change', '', _('change made by revision'), _('REV'))
3094 ('c', 'change', '', _('change made by revision'), _('REV'))
3095 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3095 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3096 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3096 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3097 inferrepo=True)
3097 inferrepo=True)
3098 def diff(ui, repo, *pats, **opts):
3098 def diff(ui, repo, *pats, **opts):
3099 """diff repository (or selected files)
3099 """diff repository (or selected files)
3100
3100
3101 Show differences between revisions for the specified files.
3101 Show differences between revisions for the specified files.
3102
3102
3103 Differences between files are shown using the unified diff format.
3103 Differences between files are shown using the unified diff format.
3104
3104
3105 .. note::
3105 .. note::
3106
3106
3107 diff may generate unexpected results for merges, as it will
3107 diff may generate unexpected results for merges, as it will
3108 default to comparing against the working directory's first
3108 default to comparing against the working directory's first
3109 parent changeset if no revisions are specified.
3109 parent changeset if no revisions are specified.
3110
3110
3111 When two revision arguments are given, then changes are shown
3111 When two revision arguments are given, then changes are shown
3112 between those revisions. If only one revision is specified then
3112 between those revisions. If only one revision is specified then
3113 that revision is compared to the working directory, and, when no
3113 that revision is compared to the working directory, and, when no
3114 revisions are specified, the working directory files are compared
3114 revisions are specified, the working directory files are compared
3115 to its parent.
3115 to its parent.
3116
3116
3117 Alternatively you can specify -c/--change with a revision to see
3117 Alternatively you can specify -c/--change with a revision to see
3118 the changes in that changeset relative to its first parent.
3118 the changes in that changeset relative to its first parent.
3119
3119
3120 Without the -a/--text option, diff will avoid generating diffs of
3120 Without the -a/--text option, diff will avoid generating diffs of
3121 files it detects as binary. With -a, diff will generate a diff
3121 files it detects as binary. With -a, diff will generate a diff
3122 anyway, probably with undesirable results.
3122 anyway, probably with undesirable results.
3123
3123
3124 Use the -g/--git option to generate diffs in the git extended diff
3124 Use the -g/--git option to generate diffs in the git extended diff
3125 format. For more information, read :hg:`help diffs`.
3125 format. For more information, read :hg:`help diffs`.
3126
3126
3127 .. container:: verbose
3127 .. container:: verbose
3128
3128
3129 Examples:
3129 Examples:
3130
3130
3131 - compare a file in the current working directory to its parent::
3131 - compare a file in the current working directory to its parent::
3132
3132
3133 hg diff foo.c
3133 hg diff foo.c
3134
3134
3135 - compare two historical versions of a directory, with rename info::
3135 - compare two historical versions of a directory, with rename info::
3136
3136
3137 hg diff --git -r 1.0:1.2 lib/
3137 hg diff --git -r 1.0:1.2 lib/
3138
3138
3139 - get change stats relative to the last change on some date::
3139 - get change stats relative to the last change on some date::
3140
3140
3141 hg diff --stat -r "date('may 2')"
3141 hg diff --stat -r "date('may 2')"
3142
3142
3143 - diff all newly-added files that contain a keyword::
3143 - diff all newly-added files that contain a keyword::
3144
3144
3145 hg diff "set:added() and grep(GNU)"
3145 hg diff "set:added() and grep(GNU)"
3146
3146
3147 - compare a revision and its parents::
3147 - compare a revision and its parents::
3148
3148
3149 hg diff -c 9353 # compare against first parent
3149 hg diff -c 9353 # compare against first parent
3150 hg diff -r 9353^:9353 # same using revset syntax
3150 hg diff -r 9353^:9353 # same using revset syntax
3151 hg diff -r 9353^2:9353 # compare against the second parent
3151 hg diff -r 9353^2:9353 # compare against the second parent
3152
3152
3153 Returns 0 on success.
3153 Returns 0 on success.
3154 """
3154 """
3155
3155
3156 revs = opts.get('rev')
3156 revs = opts.get('rev')
3157 change = opts.get('change')
3157 change = opts.get('change')
3158 stat = opts.get('stat')
3158 stat = opts.get('stat')
3159 reverse = opts.get('reverse')
3159 reverse = opts.get('reverse')
3160
3160
3161 if revs and change:
3161 if revs and change:
3162 msg = _('cannot specify --rev and --change at the same time')
3162 msg = _('cannot specify --rev and --change at the same time')
3163 raise util.Abort(msg)
3163 raise util.Abort(msg)
3164 elif change:
3164 elif change:
3165 node2 = scmutil.revsingle(repo, change, None).node()
3165 node2 = scmutil.revsingle(repo, change, None).node()
3166 node1 = repo[node2].p1().node()
3166 node1 = repo[node2].p1().node()
3167 else:
3167 else:
3168 node1, node2 = scmutil.revpair(repo, revs)
3168 node1, node2 = scmutil.revpair(repo, revs)
3169
3169
3170 if reverse:
3170 if reverse:
3171 node1, node2 = node2, node1
3171 node1, node2 = node2, node1
3172
3172
3173 diffopts = patch.diffallopts(ui, opts)
3173 diffopts = patch.diffallopts(ui, opts)
3174 m = scmutil.match(repo[node2], pats, opts)
3174 m = scmutil.match(repo[node2], pats, opts)
3175 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3175 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3176 listsubrepos=opts.get('subrepos'),
3176 listsubrepos=opts.get('subrepos'),
3177 root=opts.get('root'))
3177 root=opts.get('root'))
3178
3178
3179 @command('^export',
3179 @command('^export',
3180 [('o', 'output', '',
3180 [('o', 'output', '',
3181 _('print output to file with formatted name'), _('FORMAT')),
3181 _('print output to file with formatted name'), _('FORMAT')),
3182 ('', 'switch-parent', None, _('diff against the second parent')),
3182 ('', 'switch-parent', None, _('diff against the second parent')),
3183 ('r', 'rev', [], _('revisions to export'), _('REV')),
3183 ('r', 'rev', [], _('revisions to export'), _('REV')),
3184 ] + diffopts,
3184 ] + diffopts,
3185 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3185 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3186 def export(ui, repo, *changesets, **opts):
3186 def export(ui, repo, *changesets, **opts):
3187 """dump the header and diffs for one or more changesets
3187 """dump the header and diffs for one or more changesets
3188
3188
3189 Print the changeset header and diffs for one or more revisions.
3189 Print the changeset header and diffs for one or more revisions.
3190 If no revision is given, the parent of the working directory is used.
3190 If no revision is given, the parent of the working directory is used.
3191
3191
3192 The information shown in the changeset header is: author, date,
3192 The information shown in the changeset header is: author, date,
3193 branch name (if non-default), changeset hash, parent(s) and commit
3193 branch name (if non-default), changeset hash, parent(s) and commit
3194 comment.
3194 comment.
3195
3195
3196 .. note::
3196 .. note::
3197
3197
3198 export may generate unexpected diff output for merge
3198 export may generate unexpected diff output for merge
3199 changesets, as it will compare the merge changeset against its
3199 changesets, as it will compare the merge changeset against its
3200 first parent only.
3200 first parent only.
3201
3201
3202 Output may be to a file, in which case the name of the file is
3202 Output may be to a file, in which case the name of the file is
3203 given using a format string. The formatting rules are as follows:
3203 given using a format string. The formatting rules are as follows:
3204
3204
3205 :``%%``: literal "%" character
3205 :``%%``: literal "%" character
3206 :``%H``: changeset hash (40 hexadecimal digits)
3206 :``%H``: changeset hash (40 hexadecimal digits)
3207 :``%N``: number of patches being generated
3207 :``%N``: number of patches being generated
3208 :``%R``: changeset revision number
3208 :``%R``: changeset revision number
3209 :``%b``: basename of the exporting repository
3209 :``%b``: basename of the exporting repository
3210 :``%h``: short-form changeset hash (12 hexadecimal digits)
3210 :``%h``: short-form changeset hash (12 hexadecimal digits)
3211 :``%m``: first line of the commit message (only alphanumeric characters)
3211 :``%m``: first line of the commit message (only alphanumeric characters)
3212 :``%n``: zero-padded sequence number, starting at 1
3212 :``%n``: zero-padded sequence number, starting at 1
3213 :``%r``: zero-padded changeset revision number
3213 :``%r``: zero-padded changeset revision number
3214
3214
3215 Without the -a/--text option, export will avoid generating diffs
3215 Without the -a/--text option, export will avoid generating diffs
3216 of files it detects as binary. With -a, export will generate a
3216 of files it detects as binary. With -a, export will generate a
3217 diff anyway, probably with undesirable results.
3217 diff anyway, probably with undesirable results.
3218
3218
3219 Use the -g/--git option to generate diffs in the git extended diff
3219 Use the -g/--git option to generate diffs in the git extended diff
3220 format. See :hg:`help diffs` for more information.
3220 format. See :hg:`help diffs` for more information.
3221
3221
3222 With the --switch-parent option, the diff will be against the
3222 With the --switch-parent option, the diff will be against the
3223 second parent. It can be useful to review a merge.
3223 second parent. It can be useful to review a merge.
3224
3224
3225 .. container:: verbose
3225 .. container:: verbose
3226
3226
3227 Examples:
3227 Examples:
3228
3228
3229 - use export and import to transplant a bugfix to the current
3229 - use export and import to transplant a bugfix to the current
3230 branch::
3230 branch::
3231
3231
3232 hg export -r 9353 | hg import -
3232 hg export -r 9353 | hg import -
3233
3233
3234 - export all the changesets between two revisions to a file with
3234 - export all the changesets between two revisions to a file with
3235 rename information::
3235 rename information::
3236
3236
3237 hg export --git -r 123:150 > changes.txt
3237 hg export --git -r 123:150 > changes.txt
3238
3238
3239 - split outgoing changes into a series of patches with
3239 - split outgoing changes into a series of patches with
3240 descriptive names::
3240 descriptive names::
3241
3241
3242 hg export -r "outgoing()" -o "%n-%m.patch"
3242 hg export -r "outgoing()" -o "%n-%m.patch"
3243
3243
3244 Returns 0 on success.
3244 Returns 0 on success.
3245 """
3245 """
3246 changesets += tuple(opts.get('rev', []))
3246 changesets += tuple(opts.get('rev', []))
3247 if not changesets:
3247 if not changesets:
3248 changesets = ['.']
3248 changesets = ['.']
3249 revs = scmutil.revrange(repo, changesets)
3249 revs = scmutil.revrange(repo, changesets)
3250 if not revs:
3250 if not revs:
3251 raise util.Abort(_("export requires at least one changeset"))
3251 raise util.Abort(_("export requires at least one changeset"))
3252 if len(revs) > 1:
3252 if len(revs) > 1:
3253 ui.note(_('exporting patches:\n'))
3253 ui.note(_('exporting patches:\n'))
3254 else:
3254 else:
3255 ui.note(_('exporting patch:\n'))
3255 ui.note(_('exporting patch:\n'))
3256 cmdutil.export(repo, revs, template=opts.get('output'),
3256 cmdutil.export(repo, revs, template=opts.get('output'),
3257 switch_parent=opts.get('switch_parent'),
3257 switch_parent=opts.get('switch_parent'),
3258 opts=patch.diffallopts(ui, opts))
3258 opts=patch.diffallopts(ui, opts))
3259
3259
3260 @command('files',
3260 @command('files',
3261 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3261 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3263 ] + walkopts + formatteropts + subrepoopts,
3263 ] + walkopts + formatteropts + subrepoopts,
3264 _('[OPTION]... [PATTERN]...'))
3264 _('[OPTION]... [PATTERN]...'))
3265 def files(ui, repo, *pats, **opts):
3265 def files(ui, repo, *pats, **opts):
3266 """list tracked files
3266 """list tracked files
3267
3267
3268 Print files under Mercurial control in the working directory or
3268 Print files under Mercurial control in the working directory or
3269 specified revision whose names match the given patterns (excluding
3269 specified revision whose names match the given patterns (excluding
3270 removed files).
3270 removed files).
3271
3271
3272 If no patterns are given to match, this command prints the names
3272 If no patterns are given to match, this command prints the names
3273 of all files under Mercurial control in the working directory.
3273 of all files under Mercurial control in the working directory.
3274
3274
3275 .. container:: verbose
3275 .. container:: verbose
3276
3276
3277 Examples:
3277 Examples:
3278
3278
3279 - list all files under the current directory::
3279 - list all files under the current directory::
3280
3280
3281 hg files .
3281 hg files .
3282
3282
3283 - shows sizes and flags for current revision::
3283 - shows sizes and flags for current revision::
3284
3284
3285 hg files -vr .
3285 hg files -vr .
3286
3286
3287 - list all files named README::
3287 - list all files named README::
3288
3288
3289 hg files -I "**/README"
3289 hg files -I "**/README"
3290
3290
3291 - list all binary files::
3291 - list all binary files::
3292
3292
3293 hg files "set:binary()"
3293 hg files "set:binary()"
3294
3294
3295 - find files containing a regular expression::
3295 - find files containing a regular expression::
3296
3296
3297 hg files "set:grep('bob')"
3297 hg files "set:grep('bob')"
3298
3298
3299 - search tracked file contents with xargs and grep::
3299 - search tracked file contents with xargs and grep::
3300
3300
3301 hg files -0 | xargs -0 grep foo
3301 hg files -0 | xargs -0 grep foo
3302
3302
3303 See :hg:`help patterns` and :hg:`help filesets` for more information
3303 See :hg:`help patterns` and :hg:`help filesets` for more information
3304 on specifying file patterns.
3304 on specifying file patterns.
3305
3305
3306 Returns 0 if a match is found, 1 otherwise.
3306 Returns 0 if a match is found, 1 otherwise.
3307
3307
3308 """
3308 """
3309 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3309 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3310
3310
3311 end = '\n'
3311 end = '\n'
3312 if opts.get('print0'):
3312 if opts.get('print0'):
3313 end = '\0'
3313 end = '\0'
3314 fm = ui.formatter('files', opts)
3314 fm = ui.formatter('files', opts)
3315 fmt = '%s' + end
3315 fmt = '%s' + end
3316
3316
3317 m = scmutil.match(ctx, pats, opts)
3317 m = scmutil.match(ctx, pats, opts)
3318 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3318 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3319
3319
3320 fm.end()
3320 fm.end()
3321
3321
3322 return ret
3322 return ret
3323
3323
3324 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3324 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3325 def forget(ui, repo, *pats, **opts):
3325 def forget(ui, repo, *pats, **opts):
3326 """forget the specified files on the next commit
3326 """forget the specified files on the next commit
3327
3327
3328 Mark the specified files so they will no longer be tracked
3328 Mark the specified files so they will no longer be tracked
3329 after the next commit.
3329 after the next commit.
3330
3330
3331 This only removes files from the current branch, not from the
3331 This only removes files from the current branch, not from the
3332 entire project history, and it does not delete them from the
3332 entire project history, and it does not delete them from the
3333 working directory.
3333 working directory.
3334
3334
3335 To undo a forget before the next commit, see :hg:`add`.
3335 To undo a forget before the next commit, see :hg:`add`.
3336
3336
3337 .. container:: verbose
3337 .. container:: verbose
3338
3338
3339 Examples:
3339 Examples:
3340
3340
3341 - forget newly-added binary files::
3341 - forget newly-added binary files::
3342
3342
3343 hg forget "set:added() and binary()"
3343 hg forget "set:added() and binary()"
3344
3344
3345 - forget files that would be excluded by .hgignore::
3345 - forget files that would be excluded by .hgignore::
3346
3346
3347 hg forget "set:hgignore()"
3347 hg forget "set:hgignore()"
3348
3348
3349 Returns 0 on success.
3349 Returns 0 on success.
3350 """
3350 """
3351
3351
3352 if not pats:
3352 if not pats:
3353 raise util.Abort(_('no files specified'))
3353 raise util.Abort(_('no files specified'))
3354
3354
3355 m = scmutil.match(repo[None], pats, opts)
3355 m = scmutil.match(repo[None], pats, opts)
3356 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3356 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3357 return rejected and 1 or 0
3357 return rejected and 1 or 0
3358
3358
3359 @command(
3359 @command(
3360 'graft',
3360 'graft',
3361 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3361 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3362 ('c', 'continue', False, _('resume interrupted graft')),
3362 ('c', 'continue', False, _('resume interrupted graft')),
3363 ('e', 'edit', False, _('invoke editor on commit messages')),
3363 ('e', 'edit', False, _('invoke editor on commit messages')),
3364 ('', 'log', None, _('append graft info to log message')),
3364 ('', 'log', None, _('append graft info to log message')),
3365 ('f', 'force', False, _('force graft')),
3365 ('f', 'force', False, _('force graft')),
3366 ('D', 'currentdate', False,
3366 ('D', 'currentdate', False,
3367 _('record the current date as commit date')),
3367 _('record the current date as commit date')),
3368 ('U', 'currentuser', False,
3368 ('U', 'currentuser', False,
3369 _('record the current user as committer'), _('DATE'))]
3369 _('record the current user as committer'), _('DATE'))]
3370 + commitopts2 + mergetoolopts + dryrunopts,
3370 + commitopts2 + mergetoolopts + dryrunopts,
3371 _('[OPTION]... [-r] REV...'))
3371 _('[OPTION]... [-r] REV...'))
3372 def graft(ui, repo, *revs, **opts):
3372 def graft(ui, repo, *revs, **opts):
3373 '''copy changes from other branches onto the current branch
3373 '''copy changes from other branches onto the current branch
3374
3374
3375 This command uses Mercurial's merge logic to copy individual
3375 This command uses Mercurial's merge logic to copy individual
3376 changes from other branches without merging branches in the
3376 changes from other branches without merging branches in the
3377 history graph. This is sometimes known as 'backporting' or
3377 history graph. This is sometimes known as 'backporting' or
3378 'cherry-picking'. By default, graft will copy user, date, and
3378 'cherry-picking'. By default, graft will copy user, date, and
3379 description from the source changesets.
3379 description from the source changesets.
3380
3380
3381 Changesets that are ancestors of the current revision, that have
3381 Changesets that are ancestors of the current revision, that have
3382 already been grafted, or that are merges will be skipped.
3382 already been grafted, or that are merges will be skipped.
3383
3383
3384 If --log is specified, log messages will have a comment appended
3384 If --log is specified, log messages will have a comment appended
3385 of the form::
3385 of the form::
3386
3386
3387 (grafted from CHANGESETHASH)
3387 (grafted from CHANGESETHASH)
3388
3388
3389 If --force is specified, revisions will be grafted even if they
3389 If --force is specified, revisions will be grafted even if they
3390 are already ancestors of or have been grafted to the destination.
3390 are already ancestors of or have been grafted to the destination.
3391 This is useful when the revisions have since been backed out.
3391 This is useful when the revisions have since been backed out.
3392
3392
3393 If a graft merge results in conflicts, the graft process is
3393 If a graft merge results in conflicts, the graft process is
3394 interrupted so that the current merge can be manually resolved.
3394 interrupted so that the current merge can be manually resolved.
3395 Once all conflicts are addressed, the graft process can be
3395 Once all conflicts are addressed, the graft process can be
3396 continued with the -c/--continue option.
3396 continued with the -c/--continue option.
3397
3397
3398 .. note::
3398 .. note::
3399
3399
3400 The -c/--continue option does not reapply earlier options, except
3400 The -c/--continue option does not reapply earlier options, except
3401 for --force.
3401 for --force.
3402
3402
3403 .. container:: verbose
3403 .. container:: verbose
3404
3404
3405 Examples:
3405 Examples:
3406
3406
3407 - copy a single change to the stable branch and edit its description::
3407 - copy a single change to the stable branch and edit its description::
3408
3408
3409 hg update stable
3409 hg update stable
3410 hg graft --edit 9393
3410 hg graft --edit 9393
3411
3411
3412 - graft a range of changesets with one exception, updating dates::
3412 - graft a range of changesets with one exception, updating dates::
3413
3413
3414 hg graft -D "2085::2093 and not 2091"
3414 hg graft -D "2085::2093 and not 2091"
3415
3415
3416 - continue a graft after resolving conflicts::
3416 - continue a graft after resolving conflicts::
3417
3417
3418 hg graft -c
3418 hg graft -c
3419
3419
3420 - show the source of a grafted changeset::
3420 - show the source of a grafted changeset::
3421
3421
3422 hg log --debug -r .
3422 hg log --debug -r .
3423
3423
3424 See :hg:`help revisions` and :hg:`help revsets` for more about
3424 See :hg:`help revisions` and :hg:`help revsets` for more about
3425 specifying revisions.
3425 specifying revisions.
3426
3426
3427 Returns 0 on successful completion.
3427 Returns 0 on successful completion.
3428 '''
3428 '''
3429
3429
3430 revs = list(revs)
3430 revs = list(revs)
3431 revs.extend(opts['rev'])
3431 revs.extend(opts['rev'])
3432
3432
3433 if not opts.get('user') and opts.get('currentuser'):
3433 if not opts.get('user') and opts.get('currentuser'):
3434 opts['user'] = ui.username()
3434 opts['user'] = ui.username()
3435 if not opts.get('date') and opts.get('currentdate'):
3435 if not opts.get('date') and opts.get('currentdate'):
3436 opts['date'] = "%d %d" % util.makedate()
3436 opts['date'] = "%d %d" % util.makedate()
3437
3437
3438 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3438 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3439
3439
3440 cont = False
3440 cont = False
3441 if opts['continue']:
3441 if opts['continue']:
3442 cont = True
3442 cont = True
3443 if revs:
3443 if revs:
3444 raise util.Abort(_("can't specify --continue and revisions"))
3444 raise util.Abort(_("can't specify --continue and revisions"))
3445 # read in unfinished revisions
3445 # read in unfinished revisions
3446 try:
3446 try:
3447 nodes = repo.vfs.read('graftstate').splitlines()
3447 nodes = repo.vfs.read('graftstate').splitlines()
3448 revs = [repo[node].rev() for node in nodes]
3448 revs = [repo[node].rev() for node in nodes]
3449 except IOError, inst:
3449 except IOError, inst:
3450 if inst.errno != errno.ENOENT:
3450 if inst.errno != errno.ENOENT:
3451 raise
3451 raise
3452 raise util.Abort(_("no graft state found, can't continue"))
3452 raise util.Abort(_("no graft state found, can't continue"))
3453 else:
3453 else:
3454 cmdutil.checkunfinished(repo)
3454 cmdutil.checkunfinished(repo)
3455 cmdutil.bailifchanged(repo)
3455 cmdutil.bailifchanged(repo)
3456 if not revs:
3456 if not revs:
3457 raise util.Abort(_('no revisions specified'))
3457 raise util.Abort(_('no revisions specified'))
3458 revs = scmutil.revrange(repo, revs)
3458 revs = scmutil.revrange(repo, revs)
3459
3459
3460 skipped = set()
3460 skipped = set()
3461 # check for merges
3461 # check for merges
3462 for rev in repo.revs('%ld and merge()', revs):
3462 for rev in repo.revs('%ld and merge()', revs):
3463 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3463 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3464 skipped.add(rev)
3464 skipped.add(rev)
3465 revs = [r for r in revs if r not in skipped]
3465 revs = [r for r in revs if r not in skipped]
3466 if not revs:
3466 if not revs:
3467 return -1
3467 return -1
3468
3468
3469 # Don't check in the --continue case, in effect retaining --force across
3469 # Don't check in the --continue case, in effect retaining --force across
3470 # --continues. That's because without --force, any revisions we decided to
3470 # --continues. That's because without --force, any revisions we decided to
3471 # skip would have been filtered out here, so they wouldn't have made their
3471 # skip would have been filtered out here, so they wouldn't have made their
3472 # way to the graftstate. With --force, any revisions we would have otherwise
3472 # way to the graftstate. With --force, any revisions we would have otherwise
3473 # skipped would not have been filtered out, and if they hadn't been applied
3473 # skipped would not have been filtered out, and if they hadn't been applied
3474 # already, they'd have been in the graftstate.
3474 # already, they'd have been in the graftstate.
3475 if not (cont or opts.get('force')):
3475 if not (cont or opts.get('force')):
3476 # check for ancestors of dest branch
3476 # check for ancestors of dest branch
3477 crev = repo['.'].rev()
3477 crev = repo['.'].rev()
3478 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3478 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3479 # Cannot use x.remove(y) on smart set, this has to be a list.
3479 # Cannot use x.remove(y) on smart set, this has to be a list.
3480 # XXX make this lazy in the future
3480 # XXX make this lazy in the future
3481 revs = list(revs)
3481 revs = list(revs)
3482 # don't mutate while iterating, create a copy
3482 # don't mutate while iterating, create a copy
3483 for rev in list(revs):
3483 for rev in list(revs):
3484 if rev in ancestors:
3484 if rev in ancestors:
3485 ui.warn(_('skipping ancestor revision %d:%s\n') %
3485 ui.warn(_('skipping ancestor revision %d:%s\n') %
3486 (rev, repo[rev]))
3486 (rev, repo[rev]))
3487 # XXX remove on list is slow
3487 # XXX remove on list is slow
3488 revs.remove(rev)
3488 revs.remove(rev)
3489 if not revs:
3489 if not revs:
3490 return -1
3490 return -1
3491
3491
3492 # analyze revs for earlier grafts
3492 # analyze revs for earlier grafts
3493 ids = {}
3493 ids = {}
3494 for ctx in repo.set("%ld", revs):
3494 for ctx in repo.set("%ld", revs):
3495 ids[ctx.hex()] = ctx.rev()
3495 ids[ctx.hex()] = ctx.rev()
3496 n = ctx.extra().get('source')
3496 n = ctx.extra().get('source')
3497 if n:
3497 if n:
3498 ids[n] = ctx.rev()
3498 ids[n] = ctx.rev()
3499
3499
3500 # check ancestors for earlier grafts
3500 # check ancestors for earlier grafts
3501 ui.debug('scanning for duplicate grafts\n')
3501 ui.debug('scanning for duplicate grafts\n')
3502
3502
3503 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3503 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3504 ctx = repo[rev]
3504 ctx = repo[rev]
3505 n = ctx.extra().get('source')
3505 n = ctx.extra().get('source')
3506 if n in ids:
3506 if n in ids:
3507 try:
3507 try:
3508 r = repo[n].rev()
3508 r = repo[n].rev()
3509 except error.RepoLookupError:
3509 except error.RepoLookupError:
3510 r = None
3510 r = None
3511 if r in revs:
3511 if r in revs:
3512 ui.warn(_('skipping revision %d:%s '
3512 ui.warn(_('skipping revision %d:%s '
3513 '(already grafted to %d:%s)\n')
3513 '(already grafted to %d:%s)\n')
3514 % (r, repo[r], rev, ctx))
3514 % (r, repo[r], rev, ctx))
3515 revs.remove(r)
3515 revs.remove(r)
3516 elif ids[n] in revs:
3516 elif ids[n] in revs:
3517 if r is None:
3517 if r is None:
3518 ui.warn(_('skipping already grafted revision %d:%s '
3518 ui.warn(_('skipping already grafted revision %d:%s '
3519 '(%d:%s also has unknown origin %s)\n')
3519 '(%d:%s also has unknown origin %s)\n')
3520 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3520 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3521 else:
3521 else:
3522 ui.warn(_('skipping already grafted revision %d:%s '
3522 ui.warn(_('skipping already grafted revision %d:%s '
3523 '(%d:%s also has origin %d:%s)\n')
3523 '(%d:%s also has origin %d:%s)\n')
3524 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3524 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3525 revs.remove(ids[n])
3525 revs.remove(ids[n])
3526 elif ctx.hex() in ids:
3526 elif ctx.hex() in ids:
3527 r = ids[ctx.hex()]
3527 r = ids[ctx.hex()]
3528 ui.warn(_('skipping already grafted revision %d:%s '
3528 ui.warn(_('skipping already grafted revision %d:%s '
3529 '(was grafted from %d:%s)\n') %
3529 '(was grafted from %d:%s)\n') %
3530 (r, repo[r], rev, ctx))
3530 (r, repo[r], rev, ctx))
3531 revs.remove(r)
3531 revs.remove(r)
3532 if not revs:
3532 if not revs:
3533 return -1
3533 return -1
3534
3534
3535 wlock = repo.wlock()
3535 wlock = repo.wlock()
3536 try:
3536 try:
3537 for pos, ctx in enumerate(repo.set("%ld", revs)):
3537 for pos, ctx in enumerate(repo.set("%ld", revs)):
3538 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3538 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3539 ctx.description().split('\n', 1)[0])
3539 ctx.description().split('\n', 1)[0])
3540 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3540 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3541 if names:
3541 if names:
3542 desc += ' (%s)' % ' '.join(names)
3542 desc += ' (%s)' % ' '.join(names)
3543 ui.status(_('grafting %s\n') % desc)
3543 ui.status(_('grafting %s\n') % desc)
3544 if opts.get('dry_run'):
3544 if opts.get('dry_run'):
3545 continue
3545 continue
3546
3546
3547 source = ctx.extra().get('source')
3547 source = ctx.extra().get('source')
3548 extra = {}
3548 extra = {}
3549 if source:
3549 if source:
3550 extra['source'] = source
3550 extra['source'] = source
3551 extra['intermediate-source'] = ctx.hex()
3551 extra['intermediate-source'] = ctx.hex()
3552 else:
3552 else:
3553 extra['source'] = ctx.hex()
3553 extra['source'] = ctx.hex()
3554 user = ctx.user()
3554 user = ctx.user()
3555 if opts.get('user'):
3555 if opts.get('user'):
3556 user = opts['user']
3556 user = opts['user']
3557 date = ctx.date()
3557 date = ctx.date()
3558 if opts.get('date'):
3558 if opts.get('date'):
3559 date = opts['date']
3559 date = opts['date']
3560 message = ctx.description()
3560 message = ctx.description()
3561 if opts.get('log'):
3561 if opts.get('log'):
3562 message += '\n(grafted from %s)' % ctx.hex()
3562 message += '\n(grafted from %s)' % ctx.hex()
3563
3563
3564 # we don't merge the first commit when continuing
3564 # we don't merge the first commit when continuing
3565 if not cont:
3565 if not cont:
3566 # perform the graft merge with p1(rev) as 'ancestor'
3566 # perform the graft merge with p1(rev) as 'ancestor'
3567 try:
3567 try:
3568 # ui.forcemerge is an internal variable, do not document
3568 # ui.forcemerge is an internal variable, do not document
3569 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3569 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3570 'graft')
3570 'graft')
3571 stats = mergemod.graft(repo, ctx, ctx.p1(),
3571 stats = mergemod.graft(repo, ctx, ctx.p1(),
3572 ['local', 'graft'])
3572 ['local', 'graft'])
3573 finally:
3573 finally:
3574 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3574 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3575 # report any conflicts
3575 # report any conflicts
3576 if stats and stats[3] > 0:
3576 if stats and stats[3] > 0:
3577 # write out state for --continue
3577 # write out state for --continue
3578 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3578 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3579 repo.vfs.write('graftstate', ''.join(nodelines))
3579 repo.vfs.write('graftstate', ''.join(nodelines))
3580 raise util.Abort(
3580 raise util.Abort(
3581 _("unresolved conflicts, can't continue"),
3581 _("unresolved conflicts, can't continue"),
3582 hint=_('use hg resolve and hg graft --continue'))
3582 hint=_('use hg resolve and hg graft --continue'))
3583 else:
3583 else:
3584 cont = False
3584 cont = False
3585
3585
3586 # commit
3586 # commit
3587 node = repo.commit(text=message, user=user,
3587 node = repo.commit(text=message, user=user,
3588 date=date, extra=extra, editor=editor)
3588 date=date, extra=extra, editor=editor)
3589 if node is None:
3589 if node is None:
3590 ui.warn(
3590 ui.warn(
3591 _('note: graft of %d:%s created no changes to commit\n') %
3591 _('note: graft of %d:%s created no changes to commit\n') %
3592 (ctx.rev(), ctx))
3592 (ctx.rev(), ctx))
3593 finally:
3593 finally:
3594 wlock.release()
3594 wlock.release()
3595
3595
3596 # remove state when we complete successfully
3596 # remove state when we complete successfully
3597 if not opts.get('dry_run'):
3597 if not opts.get('dry_run'):
3598 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3598 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3599
3599
3600 return 0
3600 return 0
3601
3601
3602 @command('grep',
3602 @command('grep',
3603 [('0', 'print0', None, _('end fields with NUL')),
3603 [('0', 'print0', None, _('end fields with NUL')),
3604 ('', 'all', None, _('print all revisions that match')),
3604 ('', 'all', None, _('print all revisions that match')),
3605 ('a', 'text', None, _('treat all files as text')),
3605 ('a', 'text', None, _('treat all files as text')),
3606 ('f', 'follow', None,
3606 ('f', 'follow', None,
3607 _('follow changeset history,'
3607 _('follow changeset history,'
3608 ' or file history across copies and renames')),
3608 ' or file history across copies and renames')),
3609 ('i', 'ignore-case', None, _('ignore case when matching')),
3609 ('i', 'ignore-case', None, _('ignore case when matching')),
3610 ('l', 'files-with-matches', None,
3610 ('l', 'files-with-matches', None,
3611 _('print only filenames and revisions that match')),
3611 _('print only filenames and revisions that match')),
3612 ('n', 'line-number', None, _('print matching line numbers')),
3612 ('n', 'line-number', None, _('print matching line numbers')),
3613 ('r', 'rev', [],
3613 ('r', 'rev', [],
3614 _('only search files changed within revision range'), _('REV')),
3614 _('only search files changed within revision range'), _('REV')),
3615 ('u', 'user', None, _('list the author (long with -v)')),
3615 ('u', 'user', None, _('list the author (long with -v)')),
3616 ('d', 'date', None, _('list the date (short with -q)')),
3616 ('d', 'date', None, _('list the date (short with -q)')),
3617 ] + walkopts,
3617 ] + walkopts,
3618 _('[OPTION]... PATTERN [FILE]...'),
3618 _('[OPTION]... PATTERN [FILE]...'),
3619 inferrepo=True)
3619 inferrepo=True)
3620 def grep(ui, repo, pattern, *pats, **opts):
3620 def grep(ui, repo, pattern, *pats, **opts):
3621 """search for a pattern in specified files and revisions
3621 """search for a pattern in specified files and revisions
3622
3622
3623 Search revisions of files for a regular expression.
3623 Search revisions of files for a regular expression.
3624
3624
3625 This command behaves differently than Unix grep. It only accepts
3625 This command behaves differently than Unix grep. It only accepts
3626 Python/Perl regexps. It searches repository history, not the
3626 Python/Perl regexps. It searches repository history, not the
3627 working directory. It always prints the revision number in which a
3627 working directory. It always prints the revision number in which a
3628 match appears.
3628 match appears.
3629
3629
3630 By default, grep only prints output for the first revision of a
3630 By default, grep only prints output for the first revision of a
3631 file in which it finds a match. To get it to print every revision
3631 file in which it finds a match. To get it to print every revision
3632 that contains a change in match status ("-" for a match that
3632 that contains a change in match status ("-" for a match that
3633 becomes a non-match, or "+" for a non-match that becomes a match),
3633 becomes a non-match, or "+" for a non-match that becomes a match),
3634 use the --all flag.
3634 use the --all flag.
3635
3635
3636 Returns 0 if a match is found, 1 otherwise.
3636 Returns 0 if a match is found, 1 otherwise.
3637 """
3637 """
3638 reflags = re.M
3638 reflags = re.M
3639 if opts.get('ignore_case'):
3639 if opts.get('ignore_case'):
3640 reflags |= re.I
3640 reflags |= re.I
3641 try:
3641 try:
3642 regexp = util.re.compile(pattern, reflags)
3642 regexp = util.re.compile(pattern, reflags)
3643 except re.error, inst:
3643 except re.error, inst:
3644 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3644 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3645 return 1
3645 return 1
3646 sep, eol = ':', '\n'
3646 sep, eol = ':', '\n'
3647 if opts.get('print0'):
3647 if opts.get('print0'):
3648 sep = eol = '\0'
3648 sep = eol = '\0'
3649
3649
3650 getfile = util.lrucachefunc(repo.file)
3650 getfile = util.lrucachefunc(repo.file)
3651
3651
3652 def matchlines(body):
3652 def matchlines(body):
3653 begin = 0
3653 begin = 0
3654 linenum = 0
3654 linenum = 0
3655 while begin < len(body):
3655 while begin < len(body):
3656 match = regexp.search(body, begin)
3656 match = regexp.search(body, begin)
3657 if not match:
3657 if not match:
3658 break
3658 break
3659 mstart, mend = match.span()
3659 mstart, mend = match.span()
3660 linenum += body.count('\n', begin, mstart) + 1
3660 linenum += body.count('\n', begin, mstart) + 1
3661 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3661 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3662 begin = body.find('\n', mend) + 1 or len(body) + 1
3662 begin = body.find('\n', mend) + 1 or len(body) + 1
3663 lend = begin - 1
3663 lend = begin - 1
3664 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3664 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3665
3665
3666 class linestate(object):
3666 class linestate(object):
3667 def __init__(self, line, linenum, colstart, colend):
3667 def __init__(self, line, linenum, colstart, colend):
3668 self.line = line
3668 self.line = line
3669 self.linenum = linenum
3669 self.linenum = linenum
3670 self.colstart = colstart
3670 self.colstart = colstart
3671 self.colend = colend
3671 self.colend = colend
3672
3672
3673 def __hash__(self):
3673 def __hash__(self):
3674 return hash((self.linenum, self.line))
3674 return hash((self.linenum, self.line))
3675
3675
3676 def __eq__(self, other):
3676 def __eq__(self, other):
3677 return self.line == other.line
3677 return self.line == other.line
3678
3678
3679 def __iter__(self):
3679 def __iter__(self):
3680 yield (self.line[:self.colstart], '')
3680 yield (self.line[:self.colstart], '')
3681 yield (self.line[self.colstart:self.colend], 'grep.match')
3681 yield (self.line[self.colstart:self.colend], 'grep.match')
3682 rest = self.line[self.colend:]
3682 rest = self.line[self.colend:]
3683 while rest != '':
3683 while rest != '':
3684 match = regexp.search(rest)
3684 match = regexp.search(rest)
3685 if not match:
3685 if not match:
3686 yield (rest, '')
3686 yield (rest, '')
3687 break
3687 break
3688 mstart, mend = match.span()
3688 mstart, mend = match.span()
3689 yield (rest[:mstart], '')
3689 yield (rest[:mstart], '')
3690 yield (rest[mstart:mend], 'grep.match')
3690 yield (rest[mstart:mend], 'grep.match')
3691 rest = rest[mend:]
3691 rest = rest[mend:]
3692
3692
3693 matches = {}
3693 matches = {}
3694 copies = {}
3694 copies = {}
3695 def grepbody(fn, rev, body):
3695 def grepbody(fn, rev, body):
3696 matches[rev].setdefault(fn, [])
3696 matches[rev].setdefault(fn, [])
3697 m = matches[rev][fn]
3697 m = matches[rev][fn]
3698 for lnum, cstart, cend, line in matchlines(body):
3698 for lnum, cstart, cend, line in matchlines(body):
3699 s = linestate(line, lnum, cstart, cend)
3699 s = linestate(line, lnum, cstart, cend)
3700 m.append(s)
3700 m.append(s)
3701
3701
3702 def difflinestates(a, b):
3702 def difflinestates(a, b):
3703 sm = difflib.SequenceMatcher(None, a, b)
3703 sm = difflib.SequenceMatcher(None, a, b)
3704 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3704 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3705 if tag == 'insert':
3705 if tag == 'insert':
3706 for i in xrange(blo, bhi):
3706 for i in xrange(blo, bhi):
3707 yield ('+', b[i])
3707 yield ('+', b[i])
3708 elif tag == 'delete':
3708 elif tag == 'delete':
3709 for i in xrange(alo, ahi):
3709 for i in xrange(alo, ahi):
3710 yield ('-', a[i])
3710 yield ('-', a[i])
3711 elif tag == 'replace':
3711 elif tag == 'replace':
3712 for i in xrange(alo, ahi):
3712 for i in xrange(alo, ahi):
3713 yield ('-', a[i])
3713 yield ('-', a[i])
3714 for i in xrange(blo, bhi):
3714 for i in xrange(blo, bhi):
3715 yield ('+', b[i])
3715 yield ('+', b[i])
3716
3716
3717 def display(fn, ctx, pstates, states):
3717 def display(fn, ctx, pstates, states):
3718 rev = ctx.rev()
3718 rev = ctx.rev()
3719 if ui.quiet:
3719 if ui.quiet:
3720 datefunc = util.shortdate
3720 datefunc = util.shortdate
3721 else:
3721 else:
3722 datefunc = util.datestr
3722 datefunc = util.datestr
3723 found = False
3723 found = False
3724 @util.cachefunc
3724 @util.cachefunc
3725 def binary():
3725 def binary():
3726 flog = getfile(fn)
3726 flog = getfile(fn)
3727 return util.binary(flog.read(ctx.filenode(fn)))
3727 return util.binary(flog.read(ctx.filenode(fn)))
3728
3728
3729 if opts.get('all'):
3729 if opts.get('all'):
3730 iter = difflinestates(pstates, states)
3730 iter = difflinestates(pstates, states)
3731 else:
3731 else:
3732 iter = [('', l) for l in states]
3732 iter = [('', l) for l in states]
3733 for change, l in iter:
3733 for change, l in iter:
3734 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3734 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3735
3735
3736 if opts.get('line_number'):
3736 if opts.get('line_number'):
3737 cols.append((str(l.linenum), 'grep.linenumber'))
3737 cols.append((str(l.linenum), 'grep.linenumber'))
3738 if opts.get('all'):
3738 if opts.get('all'):
3739 cols.append((change, 'grep.change'))
3739 cols.append((change, 'grep.change'))
3740 if opts.get('user'):
3740 if opts.get('user'):
3741 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3741 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3742 if opts.get('date'):
3742 if opts.get('date'):
3743 cols.append((datefunc(ctx.date()), 'grep.date'))
3743 cols.append((datefunc(ctx.date()), 'grep.date'))
3744 for col, label in cols[:-1]:
3744 for col, label in cols[:-1]:
3745 ui.write(col, label=label)
3745 ui.write(col, label=label)
3746 ui.write(sep, label='grep.sep')
3746 ui.write(sep, label='grep.sep')
3747 ui.write(cols[-1][0], label=cols[-1][1])
3747 ui.write(cols[-1][0], label=cols[-1][1])
3748 if not opts.get('files_with_matches'):
3748 if not opts.get('files_with_matches'):
3749 ui.write(sep, label='grep.sep')
3749 ui.write(sep, label='grep.sep')
3750 if not opts.get('text') and binary():
3750 if not opts.get('text') and binary():
3751 ui.write(" Binary file matches")
3751 ui.write(" Binary file matches")
3752 else:
3752 else:
3753 for s, label in l:
3753 for s, label in l:
3754 ui.write(s, label=label)
3754 ui.write(s, label=label)
3755 ui.write(eol)
3755 ui.write(eol)
3756 found = True
3756 found = True
3757 if opts.get('files_with_matches'):
3757 if opts.get('files_with_matches'):
3758 break
3758 break
3759 return found
3759 return found
3760
3760
3761 skip = {}
3761 skip = {}
3762 revfiles = {}
3762 revfiles = {}
3763 matchfn = scmutil.match(repo[None], pats, opts)
3763 matchfn = scmutil.match(repo[None], pats, opts)
3764 found = False
3764 found = False
3765 follow = opts.get('follow')
3765 follow = opts.get('follow')
3766
3766
3767 def prep(ctx, fns):
3767 def prep(ctx, fns):
3768 rev = ctx.rev()
3768 rev = ctx.rev()
3769 pctx = ctx.p1()
3769 pctx = ctx.p1()
3770 parent = pctx.rev()
3770 parent = pctx.rev()
3771 matches.setdefault(rev, {})
3771 matches.setdefault(rev, {})
3772 matches.setdefault(parent, {})
3772 matches.setdefault(parent, {})
3773 files = revfiles.setdefault(rev, [])
3773 files = revfiles.setdefault(rev, [])
3774 for fn in fns:
3774 for fn in fns:
3775 flog = getfile(fn)
3775 flog = getfile(fn)
3776 try:
3776 try:
3777 fnode = ctx.filenode(fn)
3777 fnode = ctx.filenode(fn)
3778 except error.LookupError:
3778 except error.LookupError:
3779 continue
3779 continue
3780
3780
3781 copied = flog.renamed(fnode)
3781 copied = flog.renamed(fnode)
3782 copy = follow and copied and copied[0]
3782 copy = follow and copied and copied[0]
3783 if copy:
3783 if copy:
3784 copies.setdefault(rev, {})[fn] = copy
3784 copies.setdefault(rev, {})[fn] = copy
3785 if fn in skip:
3785 if fn in skip:
3786 if copy:
3786 if copy:
3787 skip[copy] = True
3787 skip[copy] = True
3788 continue
3788 continue
3789 files.append(fn)
3789 files.append(fn)
3790
3790
3791 if fn not in matches[rev]:
3791 if fn not in matches[rev]:
3792 grepbody(fn, rev, flog.read(fnode))
3792 grepbody(fn, rev, flog.read(fnode))
3793
3793
3794 pfn = copy or fn
3794 pfn = copy or fn
3795 if pfn not in matches[parent]:
3795 if pfn not in matches[parent]:
3796 try:
3796 try:
3797 fnode = pctx.filenode(pfn)
3797 fnode = pctx.filenode(pfn)
3798 grepbody(pfn, parent, flog.read(fnode))
3798 grepbody(pfn, parent, flog.read(fnode))
3799 except error.LookupError:
3799 except error.LookupError:
3800 pass
3800 pass
3801
3801
3802 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3802 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3803 rev = ctx.rev()
3803 rev = ctx.rev()
3804 parent = ctx.p1().rev()
3804 parent = ctx.p1().rev()
3805 for fn in sorted(revfiles.get(rev, [])):
3805 for fn in sorted(revfiles.get(rev, [])):
3806 states = matches[rev][fn]
3806 states = matches[rev][fn]
3807 copy = copies.get(rev, {}).get(fn)
3807 copy = copies.get(rev, {}).get(fn)
3808 if fn in skip:
3808 if fn in skip:
3809 if copy:
3809 if copy:
3810 skip[copy] = True
3810 skip[copy] = True
3811 continue
3811 continue
3812 pstates = matches.get(parent, {}).get(copy or fn, [])
3812 pstates = matches.get(parent, {}).get(copy or fn, [])
3813 if pstates or states:
3813 if pstates or states:
3814 r = display(fn, ctx, pstates, states)
3814 r = display(fn, ctx, pstates, states)
3815 found = found or r
3815 found = found or r
3816 if r and not opts.get('all'):
3816 if r and not opts.get('all'):
3817 skip[fn] = True
3817 skip[fn] = True
3818 if copy:
3818 if copy:
3819 skip[copy] = True
3819 skip[copy] = True
3820 del matches[rev]
3820 del matches[rev]
3821 del revfiles[rev]
3821 del revfiles[rev]
3822
3822
3823 return not found
3823 return not found
3824
3824
3825 @command('heads',
3825 @command('heads',
3826 [('r', 'rev', '',
3826 [('r', 'rev', '',
3827 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3827 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3828 ('t', 'topo', False, _('show topological heads only')),
3828 ('t', 'topo', False, _('show topological heads only')),
3829 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3829 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3830 ('c', 'closed', False, _('show normal and closed branch heads')),
3830 ('c', 'closed', False, _('show normal and closed branch heads')),
3831 ] + templateopts,
3831 ] + templateopts,
3832 _('[-ct] [-r STARTREV] [REV]...'))
3832 _('[-ct] [-r STARTREV] [REV]...'))
3833 def heads(ui, repo, *branchrevs, **opts):
3833 def heads(ui, repo, *branchrevs, **opts):
3834 """show branch heads
3834 """show branch heads
3835
3835
3836 With no arguments, show all open branch heads in the repository.
3836 With no arguments, show all open branch heads in the repository.
3837 Branch heads are changesets that have no descendants on the
3837 Branch heads are changesets that have no descendants on the
3838 same branch. They are where development generally takes place and
3838 same branch. They are where development generally takes place and
3839 are the usual targets for update and merge operations.
3839 are the usual targets for update and merge operations.
3840
3840
3841 If one or more REVs are given, only open branch heads on the
3841 If one or more REVs are given, only open branch heads on the
3842 branches associated with the specified changesets are shown. This
3842 branches associated with the specified changesets are shown. This
3843 means that you can use :hg:`heads .` to see the heads on the
3843 means that you can use :hg:`heads .` to see the heads on the
3844 currently checked-out branch.
3844 currently checked-out branch.
3845
3845
3846 If -c/--closed is specified, also show branch heads marked closed
3846 If -c/--closed is specified, also show branch heads marked closed
3847 (see :hg:`commit --close-branch`).
3847 (see :hg:`commit --close-branch`).
3848
3848
3849 If STARTREV is specified, only those heads that are descendants of
3849 If STARTREV is specified, only those heads that are descendants of
3850 STARTREV will be displayed.
3850 STARTREV will be displayed.
3851
3851
3852 If -t/--topo is specified, named branch mechanics will be ignored and only
3852 If -t/--topo is specified, named branch mechanics will be ignored and only
3853 topological heads (changesets with no children) will be shown.
3853 topological heads (changesets with no children) will be shown.
3854
3854
3855 Returns 0 if matching heads are found, 1 if not.
3855 Returns 0 if matching heads are found, 1 if not.
3856 """
3856 """
3857
3857
3858 start = None
3858 start = None
3859 if 'rev' in opts:
3859 if 'rev' in opts:
3860 start = scmutil.revsingle(repo, opts['rev'], None).node()
3860 start = scmutil.revsingle(repo, opts['rev'], None).node()
3861
3861
3862 if opts.get('topo'):
3862 if opts.get('topo'):
3863 heads = [repo[h] for h in repo.heads(start)]
3863 heads = [repo[h] for h in repo.heads(start)]
3864 else:
3864 else:
3865 heads = []
3865 heads = []
3866 for branch in repo.branchmap():
3866 for branch in repo.branchmap():
3867 heads += repo.branchheads(branch, start, opts.get('closed'))
3867 heads += repo.branchheads(branch, start, opts.get('closed'))
3868 heads = [repo[h] for h in heads]
3868 heads = [repo[h] for h in heads]
3869
3869
3870 if branchrevs:
3870 if branchrevs:
3871 branches = set(repo[br].branch() for br in branchrevs)
3871 branches = set(repo[br].branch() for br in branchrevs)
3872 heads = [h for h in heads if h.branch() in branches]
3872 heads = [h for h in heads if h.branch() in branches]
3873
3873
3874 if opts.get('active') and branchrevs:
3874 if opts.get('active') and branchrevs:
3875 dagheads = repo.heads(start)
3875 dagheads = repo.heads(start)
3876 heads = [h for h in heads if h.node() in dagheads]
3876 heads = [h for h in heads if h.node() in dagheads]
3877
3877
3878 if branchrevs:
3878 if branchrevs:
3879 haveheads = set(h.branch() for h in heads)
3879 haveheads = set(h.branch() for h in heads)
3880 if branches - haveheads:
3880 if branches - haveheads:
3881 headless = ', '.join(b for b in branches - haveheads)
3881 headless = ', '.join(b for b in branches - haveheads)
3882 msg = _('no open branch heads found on branches %s')
3882 msg = _('no open branch heads found on branches %s')
3883 if opts.get('rev'):
3883 if opts.get('rev'):
3884 msg += _(' (started at %s)') % opts['rev']
3884 msg += _(' (started at %s)') % opts['rev']
3885 ui.warn((msg + '\n') % headless)
3885 ui.warn((msg + '\n') % headless)
3886
3886
3887 if not heads:
3887 if not heads:
3888 return 1
3888 return 1
3889
3889
3890 heads = sorted(heads, key=lambda x: -x.rev())
3890 heads = sorted(heads, key=lambda x: -x.rev())
3891 displayer = cmdutil.show_changeset(ui, repo, opts)
3891 displayer = cmdutil.show_changeset(ui, repo, opts)
3892 for ctx in heads:
3892 for ctx in heads:
3893 displayer.show(ctx)
3893 displayer.show(ctx)
3894 displayer.close()
3894 displayer.close()
3895
3895
3896 @command('help',
3896 @command('help',
3897 [('e', 'extension', None, _('show only help for extensions')),
3897 [('e', 'extension', None, _('show only help for extensions')),
3898 ('c', 'command', None, _('show only help for commands')),
3898 ('c', 'command', None, _('show only help for commands')),
3899 ('k', 'keyword', '', _('show topics matching keyword')),
3899 ('k', 'keyword', '', _('show topics matching keyword')),
3900 ],
3900 ],
3901 _('[-ec] [TOPIC]'),
3901 _('[-ec] [TOPIC]'),
3902 norepo=True)
3902 norepo=True)
3903 def help_(ui, name=None, **opts):
3903 def help_(ui, name=None, **opts):
3904 """show help for a given topic or a help overview
3904 """show help for a given topic or a help overview
3905
3905
3906 With no arguments, print a list of commands with short help messages.
3906 With no arguments, print a list of commands with short help messages.
3907
3907
3908 Given a topic, extension, or command name, print help for that
3908 Given a topic, extension, or command name, print help for that
3909 topic.
3909 topic.
3910
3910
3911 Returns 0 if successful.
3911 Returns 0 if successful.
3912 """
3912 """
3913
3913
3914 textwidth = min(ui.termwidth(), 80) - 2
3914 textwidth = min(ui.termwidth(), 80) - 2
3915
3915
3916 keep = []
3916 keep = []
3917 if ui.verbose:
3917 if ui.verbose:
3918 keep.append('verbose')
3918 keep.append('verbose')
3919 if sys.platform.startswith('win'):
3919 if sys.platform.startswith('win'):
3920 keep.append('windows')
3920 keep.append('windows')
3921 elif sys.platform == 'OpenVMS':
3921 elif sys.platform == 'OpenVMS':
3922 keep.append('vms')
3922 keep.append('vms')
3923 elif sys.platform == 'plan9':
3923 elif sys.platform == 'plan9':
3924 keep.append('plan9')
3924 keep.append('plan9')
3925 else:
3925 else:
3926 keep.append('unix')
3926 keep.append('unix')
3927 keep.append(sys.platform.lower())
3927 keep.append(sys.platform.lower())
3928
3928
3929 section = None
3929 section = None
3930 if name and '.' in name:
3930 if name and '.' in name:
3931 name, section = name.split('.', 1)
3931 name, section = name.split('.', 1)
3932
3932
3933 text = help.help_(ui, name, **opts)
3933 text = help.help_(ui, name, **opts)
3934
3934
3935 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3935 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3936 section=section)
3936 section=section)
3937 if section and not formatted:
3937 if section and not formatted:
3938 raise util.Abort(_("help section not found"))
3938 raise util.Abort(_("help section not found"))
3939
3939
3940 if 'verbose' in pruned:
3940 if 'verbose' in pruned:
3941 keep.append('omitted')
3941 keep.append('omitted')
3942 else:
3942 else:
3943 keep.append('notomitted')
3943 keep.append('notomitted')
3944 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3944 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3945 section=section)
3945 section=section)
3946 ui.write(formatted)
3946 ui.write(formatted)
3947
3947
3948
3948
3949 @command('identify|id',
3949 @command('identify|id',
3950 [('r', 'rev', '',
3950 [('r', 'rev', '',
3951 _('identify the specified revision'), _('REV')),
3951 _('identify the specified revision'), _('REV')),
3952 ('n', 'num', None, _('show local revision number')),
3952 ('n', 'num', None, _('show local revision number')),
3953 ('i', 'id', None, _('show global revision id')),
3953 ('i', 'id', None, _('show global revision id')),
3954 ('b', 'branch', None, _('show branch')),
3954 ('b', 'branch', None, _('show branch')),
3955 ('t', 'tags', None, _('show tags')),
3955 ('t', 'tags', None, _('show tags')),
3956 ('B', 'bookmarks', None, _('show bookmarks')),
3956 ('B', 'bookmarks', None, _('show bookmarks')),
3957 ] + remoteopts,
3957 ] + remoteopts,
3958 _('[-nibtB] [-r REV] [SOURCE]'),
3958 _('[-nibtB] [-r REV] [SOURCE]'),
3959 optionalrepo=True)
3959 optionalrepo=True)
3960 def identify(ui, repo, source=None, rev=None,
3960 def identify(ui, repo, source=None, rev=None,
3961 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3961 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3962 """identify the working directory or specified revision
3962 """identify the working directory or specified revision
3963
3963
3964 Print a summary identifying the repository state at REV using one or
3964 Print a summary identifying the repository state at REV using one or
3965 two parent hash identifiers, followed by a "+" if the working
3965 two parent hash identifiers, followed by a "+" if the working
3966 directory has uncommitted changes, the branch name (if not default),
3966 directory has uncommitted changes, the branch name (if not default),
3967 a list of tags, and a list of bookmarks.
3967 a list of tags, and a list of bookmarks.
3968
3968
3969 When REV is not given, print a summary of the current state of the
3969 When REV is not given, print a summary of the current state of the
3970 repository.
3970 repository.
3971
3971
3972 Specifying a path to a repository root or Mercurial bundle will
3972 Specifying a path to a repository root or Mercurial bundle will
3973 cause lookup to operate on that repository/bundle.
3973 cause lookup to operate on that repository/bundle.
3974
3974
3975 .. container:: verbose
3975 .. container:: verbose
3976
3976
3977 Examples:
3977 Examples:
3978
3978
3979 - generate a build identifier for the working directory::
3979 - generate a build identifier for the working directory::
3980
3980
3981 hg id --id > build-id.dat
3981 hg id --id > build-id.dat
3982
3982
3983 - find the revision corresponding to a tag::
3983 - find the revision corresponding to a tag::
3984
3984
3985 hg id -n -r 1.3
3985 hg id -n -r 1.3
3986
3986
3987 - check the most recent revision of a remote repository::
3987 - check the most recent revision of a remote repository::
3988
3988
3989 hg id -r tip http://selenic.com/hg/
3989 hg id -r tip http://selenic.com/hg/
3990
3990
3991 Returns 0 if successful.
3991 Returns 0 if successful.
3992 """
3992 """
3993
3993
3994 if not repo and not source:
3994 if not repo and not source:
3995 raise util.Abort(_("there is no Mercurial repository here "
3995 raise util.Abort(_("there is no Mercurial repository here "
3996 "(.hg not found)"))
3996 "(.hg not found)"))
3997
3997
3998 if ui.debugflag:
3998 if ui.debugflag:
3999 hexfunc = hex
3999 hexfunc = hex
4000 else:
4000 else:
4001 hexfunc = short
4001 hexfunc = short
4002 default = not (num or id or branch or tags or bookmarks)
4002 default = not (num or id or branch or tags or bookmarks)
4003 output = []
4003 output = []
4004 revs = []
4004 revs = []
4005
4005
4006 if source:
4006 if source:
4007 source, branches = hg.parseurl(ui.expandpath(source))
4007 source, branches = hg.parseurl(ui.expandpath(source))
4008 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4008 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4009 repo = peer.local()
4009 repo = peer.local()
4010 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4010 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4011
4011
4012 if not repo:
4012 if not repo:
4013 if num or branch or tags:
4013 if num or branch or tags:
4014 raise util.Abort(
4014 raise util.Abort(
4015 _("can't query remote revision number, branch, or tags"))
4015 _("can't query remote revision number, branch, or tags"))
4016 if not rev and revs:
4016 if not rev and revs:
4017 rev = revs[0]
4017 rev = revs[0]
4018 if not rev:
4018 if not rev:
4019 rev = "tip"
4019 rev = "tip"
4020
4020
4021 remoterev = peer.lookup(rev)
4021 remoterev = peer.lookup(rev)
4022 if default or id:
4022 if default or id:
4023 output = [hexfunc(remoterev)]
4023 output = [hexfunc(remoterev)]
4024
4024
4025 def getbms():
4025 def getbms():
4026 bms = []
4026 bms = []
4027
4027
4028 if 'bookmarks' in peer.listkeys('namespaces'):
4028 if 'bookmarks' in peer.listkeys('namespaces'):
4029 hexremoterev = hex(remoterev)
4029 hexremoterev = hex(remoterev)
4030 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4030 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4031 if bmr == hexremoterev]
4031 if bmr == hexremoterev]
4032
4032
4033 return sorted(bms)
4033 return sorted(bms)
4034
4034
4035 if bookmarks:
4035 if bookmarks:
4036 output.extend(getbms())
4036 output.extend(getbms())
4037 elif default and not ui.quiet:
4037 elif default and not ui.quiet:
4038 # multiple bookmarks for a single parent separated by '/'
4038 # multiple bookmarks for a single parent separated by '/'
4039 bm = '/'.join(getbms())
4039 bm = '/'.join(getbms())
4040 if bm:
4040 if bm:
4041 output.append(bm)
4041 output.append(bm)
4042 else:
4042 else:
4043 if not rev:
4043 if not rev:
4044 ctx = repo[None]
4044 ctx = repo[None]
4045 parents = ctx.parents()
4045 parents = ctx.parents()
4046 changed = ""
4046 changed = ""
4047 if default or id or num:
4047 if default or id or num:
4048 if (util.any(repo.status())
4048 if (util.any(repo.status())
4049 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4049 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4050 changed = '+'
4050 changed = '+'
4051 if default or id:
4051 if default or id:
4052 output = ["%s%s" %
4052 output = ["%s%s" %
4053 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4053 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4054 if num:
4054 if num:
4055 output.append("%s%s" %
4055 output.append("%s%s" %
4056 ('+'.join([str(p.rev()) for p in parents]), changed))
4056 ('+'.join([str(p.rev()) for p in parents]), changed))
4057 else:
4057 else:
4058 ctx = scmutil.revsingle(repo, rev)
4058 ctx = scmutil.revsingle(repo, rev)
4059 if default or id:
4059 if default or id:
4060 output = [hexfunc(ctx.node())]
4060 output = [hexfunc(ctx.node())]
4061 if num:
4061 if num:
4062 output.append(str(ctx.rev()))
4062 output.append(str(ctx.rev()))
4063
4063
4064 if default and not ui.quiet:
4064 if default and not ui.quiet:
4065 b = ctx.branch()
4065 b = ctx.branch()
4066 if b != 'default':
4066 if b != 'default':
4067 output.append("(%s)" % b)
4067 output.append("(%s)" % b)
4068
4068
4069 # multiple tags for a single parent separated by '/'
4069 # multiple tags for a single parent separated by '/'
4070 t = '/'.join(ctx.tags())
4070 t = '/'.join(ctx.tags())
4071 if t:
4071 if t:
4072 output.append(t)
4072 output.append(t)
4073
4073
4074 # multiple bookmarks for a single parent separated by '/'
4074 # multiple bookmarks for a single parent separated by '/'
4075 bm = '/'.join(ctx.bookmarks())
4075 bm = '/'.join(ctx.bookmarks())
4076 if bm:
4076 if bm:
4077 output.append(bm)
4077 output.append(bm)
4078 else:
4078 else:
4079 if branch:
4079 if branch:
4080 output.append(ctx.branch())
4080 output.append(ctx.branch())
4081
4081
4082 if tags:
4082 if tags:
4083 output.extend(ctx.tags())
4083 output.extend(ctx.tags())
4084
4084
4085 if bookmarks:
4085 if bookmarks:
4086 output.extend(ctx.bookmarks())
4086 output.extend(ctx.bookmarks())
4087
4087
4088 ui.write("%s\n" % ' '.join(output))
4088 ui.write("%s\n" % ' '.join(output))
4089
4089
4090 @command('import|patch',
4090 @command('import|patch',
4091 [('p', 'strip', 1,
4091 [('p', 'strip', 1,
4092 _('directory strip option for patch. This has the same '
4092 _('directory strip option for patch. This has the same '
4093 'meaning as the corresponding patch option'), _('NUM')),
4093 'meaning as the corresponding patch option'), _('NUM')),
4094 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4094 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4095 ('e', 'edit', False, _('invoke editor on commit messages')),
4095 ('e', 'edit', False, _('invoke editor on commit messages')),
4096 ('f', 'force', None,
4096 ('f', 'force', None,
4097 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4097 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4098 ('', 'no-commit', None,
4098 ('', 'no-commit', None,
4099 _("don't commit, just update the working directory")),
4099 _("don't commit, just update the working directory")),
4100 ('', 'bypass', None,
4100 ('', 'bypass', None,
4101 _("apply patch without touching the working directory")),
4101 _("apply patch without touching the working directory")),
4102 ('', 'partial', None,
4102 ('', 'partial', None,
4103 _('commit even if some hunks fail')),
4103 _('commit even if some hunks fail')),
4104 ('', 'exact', None,
4104 ('', 'exact', None,
4105 _('apply patch to the nodes from which it was generated')),
4105 _('apply patch to the nodes from which it was generated')),
4106 ('', 'prefix', '',
4106 ('', 'prefix', '',
4107 _('apply patch to subdirectory'), _('DIR')),
4107 _('apply patch to subdirectory'), _('DIR')),
4108 ('', 'import-branch', None,
4108 ('', 'import-branch', None,
4109 _('use any branch information in patch (implied by --exact)'))] +
4109 _('use any branch information in patch (implied by --exact)'))] +
4110 commitopts + commitopts2 + similarityopts,
4110 commitopts + commitopts2 + similarityopts,
4111 _('[OPTION]... PATCH...'))
4111 _('[OPTION]... PATCH...'))
4112 def import_(ui, repo, patch1=None, *patches, **opts):
4112 def import_(ui, repo, patch1=None, *patches, **opts):
4113 """import an ordered set of patches
4113 """import an ordered set of patches
4114
4114
4115 Import a list of patches and commit them individually (unless
4115 Import a list of patches and commit them individually (unless
4116 --no-commit is specified).
4116 --no-commit is specified).
4117
4117
4118 Because import first applies changes to the working directory,
4118 Because import first applies changes to the working directory,
4119 import will abort if there are outstanding changes.
4119 import will abort if there are outstanding changes.
4120
4120
4121 You can import a patch straight from a mail message. Even patches
4121 You can import a patch straight from a mail message. Even patches
4122 as attachments work (to use the body part, it must have type
4122 as attachments work (to use the body part, it must have type
4123 text/plain or text/x-patch). From and Subject headers of email
4123 text/plain or text/x-patch). From and Subject headers of email
4124 message are used as default committer and commit message. All
4124 message are used as default committer and commit message. All
4125 text/plain body parts before first diff are added to commit
4125 text/plain body parts before first diff are added to commit
4126 message.
4126 message.
4127
4127
4128 If the imported patch was generated by :hg:`export`, user and
4128 If the imported patch was generated by :hg:`export`, user and
4129 description from patch override values from message headers and
4129 description from patch override values from message headers and
4130 body. Values given on command line with -m/--message and -u/--user
4130 body. Values given on command line with -m/--message and -u/--user
4131 override these.
4131 override these.
4132
4132
4133 If --exact is specified, import will set the working directory to
4133 If --exact is specified, import will set the working directory to
4134 the parent of each patch before applying it, and will abort if the
4134 the parent of each patch before applying it, and will abort if the
4135 resulting changeset has a different ID than the one recorded in
4135 resulting changeset has a different ID than the one recorded in
4136 the patch. This may happen due to character set problems or other
4136 the patch. This may happen due to character set problems or other
4137 deficiencies in the text patch format.
4137 deficiencies in the text patch format.
4138
4138
4139 Use --bypass to apply and commit patches directly to the
4139 Use --bypass to apply and commit patches directly to the
4140 repository, not touching the working directory. Without --exact,
4140 repository, not touching the working directory. Without --exact,
4141 patches will be applied on top of the working directory parent
4141 patches will be applied on top of the working directory parent
4142 revision.
4142 revision.
4143
4143
4144 With -s/--similarity, hg will attempt to discover renames and
4144 With -s/--similarity, hg will attempt to discover renames and
4145 copies in the patch in the same way as :hg:`addremove`.
4145 copies in the patch in the same way as :hg:`addremove`.
4146
4146
4147 Use --partial to ensure a changeset will be created from the patch
4147 Use --partial to ensure a changeset will be created from the patch
4148 even if some hunks fail to apply. Hunks that fail to apply will be
4148 even if some hunks fail to apply. Hunks that fail to apply will be
4149 written to a <target-file>.rej file. Conflicts can then be resolved
4149 written to a <target-file>.rej file. Conflicts can then be resolved
4150 by hand before :hg:`commit --amend` is run to update the created
4150 by hand before :hg:`commit --amend` is run to update the created
4151 changeset. This flag exists to let people import patches that
4151 changeset. This flag exists to let people import patches that
4152 partially apply without losing the associated metadata (author,
4152 partially apply without losing the associated metadata (author,
4153 date, description, ...). Note that when none of the hunk applies
4153 date, description, ...). Note that when none of the hunk applies
4154 cleanly, :hg:`import --partial` will create an empty changeset,
4154 cleanly, :hg:`import --partial` will create an empty changeset,
4155 importing only the patch metadata.
4155 importing only the patch metadata.
4156
4156
4157 To read a patch from standard input, use "-" as the patch name. If
4157 To read a patch from standard input, use "-" as the patch name. If
4158 a URL is specified, the patch will be downloaded from it.
4158 a URL is specified, the patch will be downloaded from it.
4159 See :hg:`help dates` for a list of formats valid for -d/--date.
4159 See :hg:`help dates` for a list of formats valid for -d/--date.
4160
4160
4161 .. container:: verbose
4161 .. container:: verbose
4162
4162
4163 Examples:
4163 Examples:
4164
4164
4165 - import a traditional patch from a website and detect renames::
4165 - import a traditional patch from a website and detect renames::
4166
4166
4167 hg import -s 80 http://example.com/bugfix.patch
4167 hg import -s 80 http://example.com/bugfix.patch
4168
4168
4169 - import a changeset from an hgweb server::
4169 - import a changeset from an hgweb server::
4170
4170
4171 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4171 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4172
4172
4173 - import all the patches in an Unix-style mbox::
4173 - import all the patches in an Unix-style mbox::
4174
4174
4175 hg import incoming-patches.mbox
4175 hg import incoming-patches.mbox
4176
4176
4177 - attempt to exactly restore an exported changeset (not always
4177 - attempt to exactly restore an exported changeset (not always
4178 possible)::
4178 possible)::
4179
4179
4180 hg import --exact proposed-fix.patch
4180 hg import --exact proposed-fix.patch
4181
4181
4182 Returns 0 on success, 1 on partial success (see --partial).
4182 Returns 0 on success, 1 on partial success (see --partial).
4183 """
4183 """
4184
4184
4185 if not patch1:
4185 if not patch1:
4186 raise util.Abort(_('need at least one patch to import'))
4186 raise util.Abort(_('need at least one patch to import'))
4187
4187
4188 patches = (patch1,) + patches
4188 patches = (patch1,) + patches
4189
4189
4190 date = opts.get('date')
4190 date = opts.get('date')
4191 if date:
4191 if date:
4192 opts['date'] = util.parsedate(date)
4192 opts['date'] = util.parsedate(date)
4193
4193
4194 update = not opts.get('bypass')
4194 update = not opts.get('bypass')
4195 if not update and opts.get('no_commit'):
4195 if not update and opts.get('no_commit'):
4196 raise util.Abort(_('cannot use --no-commit with --bypass'))
4196 raise util.Abort(_('cannot use --no-commit with --bypass'))
4197 try:
4197 try:
4198 sim = float(opts.get('similarity') or 0)
4198 sim = float(opts.get('similarity') or 0)
4199 except ValueError:
4199 except ValueError:
4200 raise util.Abort(_('similarity must be a number'))
4200 raise util.Abort(_('similarity must be a number'))
4201 if sim < 0 or sim > 100:
4201 if sim < 0 or sim > 100:
4202 raise util.Abort(_('similarity must be between 0 and 100'))
4202 raise util.Abort(_('similarity must be between 0 and 100'))
4203 if sim and not update:
4203 if sim and not update:
4204 raise util.Abort(_('cannot use --similarity with --bypass'))
4204 raise util.Abort(_('cannot use --similarity with --bypass'))
4205 if opts.get('exact') and opts.get('edit'):
4205 if opts.get('exact') and opts.get('edit'):
4206 raise util.Abort(_('cannot use --exact with --edit'))
4206 raise util.Abort(_('cannot use --exact with --edit'))
4207 if opts.get('exact') and opts.get('prefix'):
4207 if opts.get('exact') and opts.get('prefix'):
4208 raise util.Abort(_('cannot use --exact with --prefix'))
4208 raise util.Abort(_('cannot use --exact with --prefix'))
4209
4209
4210 if update:
4210 if update:
4211 cmdutil.checkunfinished(repo)
4211 cmdutil.checkunfinished(repo)
4212 if (opts.get('exact') or not opts.get('force')) and update:
4212 if (opts.get('exact') or not opts.get('force')) and update:
4213 cmdutil.bailifchanged(repo)
4213 cmdutil.bailifchanged(repo)
4214
4214
4215 base = opts["base"]
4215 base = opts["base"]
4216 wlock = lock = tr = None
4216 wlock = lock = tr = None
4217 msgs = []
4217 msgs = []
4218 ret = 0
4218 ret = 0
4219
4219
4220
4220
4221 try:
4221 try:
4222 try:
4222 try:
4223 wlock = repo.wlock()
4223 wlock = repo.wlock()
4224 repo.dirstate.beginparentchange()
4224 repo.dirstate.beginparentchange()
4225 if not opts.get('no_commit'):
4225 if not opts.get('no_commit'):
4226 lock = repo.lock()
4226 lock = repo.lock()
4227 tr = repo.transaction('import')
4227 tr = repo.transaction('import')
4228 parents = repo.parents()
4228 parents = repo.parents()
4229 for patchurl in patches:
4229 for patchurl in patches:
4230 if patchurl == '-':
4230 if patchurl == '-':
4231 ui.status(_('applying patch from stdin\n'))
4231 ui.status(_('applying patch from stdin\n'))
4232 patchfile = ui.fin
4232 patchfile = ui.fin
4233 patchurl = 'stdin' # for error message
4233 patchurl = 'stdin' # for error message
4234 else:
4234 else:
4235 patchurl = os.path.join(base, patchurl)
4235 patchurl = os.path.join(base, patchurl)
4236 ui.status(_('applying %s\n') % patchurl)
4236 ui.status(_('applying %s\n') % patchurl)
4237 patchfile = hg.openpath(ui, patchurl)
4237 patchfile = hg.openpath(ui, patchurl)
4238
4238
4239 haspatch = False
4239 haspatch = False
4240 for hunk in patch.split(patchfile):
4240 for hunk in patch.split(patchfile):
4241 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4241 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4242 parents, opts,
4242 parents, opts,
4243 msgs, hg.clean)
4243 msgs, hg.clean)
4244 if msg:
4244 if msg:
4245 haspatch = True
4245 haspatch = True
4246 ui.note(msg + '\n')
4246 ui.note(msg + '\n')
4247 if update or opts.get('exact'):
4247 if update or opts.get('exact'):
4248 parents = repo.parents()
4248 parents = repo.parents()
4249 else:
4249 else:
4250 parents = [repo[node]]
4250 parents = [repo[node]]
4251 if rej:
4251 if rej:
4252 ui.write_err(_("patch applied partially\n"))
4252 ui.write_err(_("patch applied partially\n"))
4253 ui.write_err(_("(fix the .rej files and run "
4253 ui.write_err(_("(fix the .rej files and run "
4254 "`hg commit --amend`)\n"))
4254 "`hg commit --amend`)\n"))
4255 ret = 1
4255 ret = 1
4256 break
4256 break
4257
4257
4258 if not haspatch:
4258 if not haspatch:
4259 raise util.Abort(_('%s: no diffs found') % patchurl)
4259 raise util.Abort(_('%s: no diffs found') % patchurl)
4260
4260
4261 if tr:
4261 if tr:
4262 tr.close()
4262 tr.close()
4263 if msgs:
4263 if msgs:
4264 repo.savecommitmessage('\n* * *\n'.join(msgs))
4264 repo.savecommitmessage('\n* * *\n'.join(msgs))
4265 repo.dirstate.endparentchange()
4265 repo.dirstate.endparentchange()
4266 return ret
4266 return ret
4267 except: # re-raises
4267 except: # re-raises
4268 # wlock.release() indirectly calls dirstate.write(): since
4268 # wlock.release() indirectly calls dirstate.write(): since
4269 # we're crashing, we do not want to change the working dir
4269 # we're crashing, we do not want to change the working dir
4270 # parent after all, so make sure it writes nothing
4270 # parent after all, so make sure it writes nothing
4271 repo.dirstate.invalidate()
4271 repo.dirstate.invalidate()
4272 raise
4272 raise
4273 finally:
4273 finally:
4274 if tr:
4274 if tr:
4275 tr.release()
4275 tr.release()
4276 release(lock, wlock)
4276 release(lock, wlock)
4277
4277
4278 @command('incoming|in',
4278 @command('incoming|in',
4279 [('f', 'force', None,
4279 [('f', 'force', None,
4280 _('run even if remote repository is unrelated')),
4280 _('run even if remote repository is unrelated')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4281 ('n', 'newest-first', None, _('show newest record first')),
4282 ('', 'bundle', '',
4282 ('', 'bundle', '',
4283 _('file to store the bundles into'), _('FILE')),
4283 _('file to store the bundles into'), _('FILE')),
4284 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4284 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4285 ('B', 'bookmarks', False, _("compare bookmarks")),
4285 ('B', 'bookmarks', False, _("compare bookmarks")),
4286 ('b', 'branch', [],
4286 ('b', 'branch', [],
4287 _('a specific branch you would like to pull'), _('BRANCH')),
4287 _('a specific branch you would like to pull'), _('BRANCH')),
4288 ] + logopts + remoteopts + subrepoopts,
4288 ] + logopts + remoteopts + subrepoopts,
4289 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4289 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4290 def incoming(ui, repo, source="default", **opts):
4290 def incoming(ui, repo, source="default", **opts):
4291 """show new changesets found in source
4291 """show new changesets found in source
4292
4292
4293 Show new changesets found in the specified path/URL or the default
4293 Show new changesets found in the specified path/URL or the default
4294 pull location. These are the changesets that would have been pulled
4294 pull location. These are the changesets that would have been pulled
4295 if a pull at the time you issued this command.
4295 if a pull at the time you issued this command.
4296
4296
4297 See pull for valid source format details.
4297 See pull for valid source format details.
4298
4298
4299 .. container:: verbose
4299 .. container:: verbose
4300
4300
4301 With -B/--bookmarks, the result of bookmark comparison between
4301 With -B/--bookmarks, the result of bookmark comparison between
4302 local and remote repositories is displayed. With -v/--verbose,
4302 local and remote repositories is displayed. With -v/--verbose,
4303 status is also displayed for each bookmark like below::
4303 status is also displayed for each bookmark like below::
4304
4304
4305 BM1 01234567890a added
4305 BM1 01234567890a added
4306 BM2 1234567890ab advanced
4306 BM2 1234567890ab advanced
4307 BM3 234567890abc diverged
4307 BM3 234567890abc diverged
4308 BM4 34567890abcd changed
4308 BM4 34567890abcd changed
4309
4309
4310 The action taken locally when pulling depends on the
4310 The action taken locally when pulling depends on the
4311 status of each bookmark:
4311 status of each bookmark:
4312
4312
4313 :``added``: pull will create it
4313 :``added``: pull will create it
4314 :``advanced``: pull will update it
4314 :``advanced``: pull will update it
4315 :``diverged``: pull will create a divergent bookmark
4315 :``diverged``: pull will create a divergent bookmark
4316 :``changed``: result depends on remote changesets
4316 :``changed``: result depends on remote changesets
4317
4317
4318 From the point of view of pulling behavior, bookmark
4318 From the point of view of pulling behavior, bookmark
4319 existing only in the remote repository are treated as ``added``,
4319 existing only in the remote repository are treated as ``added``,
4320 even if it is in fact locally deleted.
4320 even if it is in fact locally deleted.
4321
4321
4322 .. container:: verbose
4322 .. container:: verbose
4323
4323
4324 For remote repository, using --bundle avoids downloading the
4324 For remote repository, using --bundle avoids downloading the
4325 changesets twice if the incoming is followed by a pull.
4325 changesets twice if the incoming is followed by a pull.
4326
4326
4327 Examples:
4327 Examples:
4328
4328
4329 - show incoming changes with patches and full description::
4329 - show incoming changes with patches and full description::
4330
4330
4331 hg incoming -vp
4331 hg incoming -vp
4332
4332
4333 - show incoming changes excluding merges, store a bundle::
4333 - show incoming changes excluding merges, store a bundle::
4334
4334
4335 hg in -vpM --bundle incoming.hg
4335 hg in -vpM --bundle incoming.hg
4336 hg pull incoming.hg
4336 hg pull incoming.hg
4337
4337
4338 - briefly list changes inside a bundle::
4338 - briefly list changes inside a bundle::
4339
4339
4340 hg in changes.hg -T "{desc|firstline}\\n"
4340 hg in changes.hg -T "{desc|firstline}\\n"
4341
4341
4342 Returns 0 if there are incoming changes, 1 otherwise.
4342 Returns 0 if there are incoming changes, 1 otherwise.
4343 """
4343 """
4344 if opts.get('graph'):
4344 if opts.get('graph'):
4345 cmdutil.checkunsupportedgraphflags([], opts)
4345 cmdutil.checkunsupportedgraphflags([], opts)
4346 def display(other, chlist, displayer):
4346 def display(other, chlist, displayer):
4347 revdag = cmdutil.graphrevs(other, chlist, opts)
4347 revdag = cmdutil.graphrevs(other, chlist, opts)
4348 showparents = [ctx.node() for ctx in repo[None].parents()]
4348 showparents = [ctx.node() for ctx in repo[None].parents()]
4349 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4349 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4350 graphmod.asciiedges)
4350 graphmod.asciiedges)
4351
4351
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4352 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4353 return 0
4353 return 0
4354
4354
4355 if opts.get('bundle') and opts.get('subrepos'):
4355 if opts.get('bundle') and opts.get('subrepos'):
4356 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4356 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4357
4357
4358 if opts.get('bookmarks'):
4358 if opts.get('bookmarks'):
4359 source, branches = hg.parseurl(ui.expandpath(source),
4359 source, branches = hg.parseurl(ui.expandpath(source),
4360 opts.get('branch'))
4360 opts.get('branch'))
4361 other = hg.peer(repo, opts, source)
4361 other = hg.peer(repo, opts, source)
4362 if 'bookmarks' not in other.listkeys('namespaces'):
4362 if 'bookmarks' not in other.listkeys('namespaces'):
4363 ui.warn(_("remote doesn't support bookmarks\n"))
4363 ui.warn(_("remote doesn't support bookmarks\n"))
4364 return 0
4364 return 0
4365 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4365 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4366 return bookmarks.incoming(ui, repo, other)
4366 return bookmarks.incoming(ui, repo, other)
4367
4367
4368 repo._subtoppath = ui.expandpath(source)
4368 repo._subtoppath = ui.expandpath(source)
4369 try:
4369 try:
4370 return hg.incoming(ui, repo, source, opts)
4370 return hg.incoming(ui, repo, source, opts)
4371 finally:
4371 finally:
4372 del repo._subtoppath
4372 del repo._subtoppath
4373
4373
4374
4374
4375 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4375 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4376 norepo=True)
4376 norepo=True)
4377 def init(ui, dest=".", **opts):
4377 def init(ui, dest=".", **opts):
4378 """create a new repository in the given directory
4378 """create a new repository in the given directory
4379
4379
4380 Initialize a new repository in the given directory. If the given
4380 Initialize a new repository in the given directory. If the given
4381 directory does not exist, it will be created.
4381 directory does not exist, it will be created.
4382
4382
4383 If no directory is given, the current directory is used.
4383 If no directory is given, the current directory is used.
4384
4384
4385 It is possible to specify an ``ssh://`` URL as the destination.
4385 It is possible to specify an ``ssh://`` URL as the destination.
4386 See :hg:`help urls` for more information.
4386 See :hg:`help urls` for more information.
4387
4387
4388 Returns 0 on success.
4388 Returns 0 on success.
4389 """
4389 """
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4390 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4391
4391
4392 @command('locate',
4392 @command('locate',
4393 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4393 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4394 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4394 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4395 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4395 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4396 ] + walkopts,
4396 ] + walkopts,
4397 _('[OPTION]... [PATTERN]...'))
4397 _('[OPTION]... [PATTERN]...'))
4398 def locate(ui, repo, *pats, **opts):
4398 def locate(ui, repo, *pats, **opts):
4399 """locate files matching specific patterns (DEPRECATED)
4399 """locate files matching specific patterns (DEPRECATED)
4400
4400
4401 Print files under Mercurial control in the working directory whose
4401 Print files under Mercurial control in the working directory whose
4402 names match the given patterns.
4402 names match the given patterns.
4403
4403
4404 By default, this command searches all directories in the working
4404 By default, this command searches all directories in the working
4405 directory. To search just the current directory and its
4405 directory. To search just the current directory and its
4406 subdirectories, use "--include .".
4406 subdirectories, use "--include .".
4407
4407
4408 If no patterns are given to match, this command prints the names
4408 If no patterns are given to match, this command prints the names
4409 of all files under Mercurial control in the working directory.
4409 of all files under Mercurial control in the working directory.
4410
4410
4411 If you want to feed the output of this command into the "xargs"
4411 If you want to feed the output of this command into the "xargs"
4412 command, use the -0 option to both this command and "xargs". This
4412 command, use the -0 option to both this command and "xargs". This
4413 will avoid the problem of "xargs" treating single filenames that
4413 will avoid the problem of "xargs" treating single filenames that
4414 contain whitespace as multiple filenames.
4414 contain whitespace as multiple filenames.
4415
4415
4416 See :hg:`help files` for a more versatile command.
4416 See :hg:`help files` for a more versatile command.
4417
4417
4418 Returns 0 if a match is found, 1 otherwise.
4418 Returns 0 if a match is found, 1 otherwise.
4419 """
4419 """
4420 if opts.get('print0'):
4420 if opts.get('print0'):
4421 end = '\0'
4421 end = '\0'
4422 else:
4422 else:
4423 end = '\n'
4423 end = '\n'
4424 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4424 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4425
4425
4426 ret = 1
4426 ret = 1
4427 ctx = repo[rev]
4427 ctx = repo[rev]
4428 m = scmutil.match(ctx, pats, opts, default='relglob')
4428 m = scmutil.match(ctx, pats, opts, default='relglob')
4429 m.bad = lambda x, y: False
4429 m.bad = lambda x, y: False
4430
4430
4431 for abs in ctx.matches(m):
4431 for abs in ctx.matches(m):
4432 if opts.get('fullpath'):
4432 if opts.get('fullpath'):
4433 ui.write(repo.wjoin(abs), end)
4433 ui.write(repo.wjoin(abs), end)
4434 else:
4434 else:
4435 ui.write(((pats and m.rel(abs)) or abs), end)
4435 ui.write(((pats and m.rel(abs)) or abs), end)
4436 ret = 0
4436 ret = 0
4437
4437
4438 return ret
4438 return ret
4439
4439
4440 @command('^log|history',
4440 @command('^log|history',
4441 [('f', 'follow', None,
4441 [('f', 'follow', None,
4442 _('follow changeset history, or file history across copies and renames')),
4442 _('follow changeset history, or file history across copies and renames')),
4443 ('', 'follow-first', None,
4443 ('', 'follow-first', None,
4444 _('only follow the first parent of merge changesets (DEPRECATED)')),
4444 _('only follow the first parent of merge changesets (DEPRECATED)')),
4445 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4445 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4446 ('C', 'copies', None, _('show copied files')),
4446 ('C', 'copies', None, _('show copied files')),
4447 ('k', 'keyword', [],
4447 ('k', 'keyword', [],
4448 _('do case-insensitive search for a given text'), _('TEXT')),
4448 _('do case-insensitive search for a given text'), _('TEXT')),
4449 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4449 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4450 ('', 'removed', None, _('include revisions where files were removed')),
4450 ('', 'removed', None, _('include revisions where files were removed')),
4451 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4451 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4452 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4452 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4453 ('', 'only-branch', [],
4453 ('', 'only-branch', [],
4454 _('show only changesets within the given named branch (DEPRECATED)'),
4454 _('show only changesets within the given named branch (DEPRECATED)'),
4455 _('BRANCH')),
4455 _('BRANCH')),
4456 ('b', 'branch', [],
4456 ('b', 'branch', [],
4457 _('show changesets within the given named branch'), _('BRANCH')),
4457 _('show changesets within the given named branch'), _('BRANCH')),
4458 ('P', 'prune', [],
4458 ('P', 'prune', [],
4459 _('do not display revision or any of its ancestors'), _('REV')),
4459 _('do not display revision or any of its ancestors'), _('REV')),
4460 ] + logopts + walkopts,
4460 ] + logopts + walkopts,
4461 _('[OPTION]... [FILE]'),
4461 _('[OPTION]... [FILE]'),
4462 inferrepo=True)
4462 inferrepo=True)
4463 def log(ui, repo, *pats, **opts):
4463 def log(ui, repo, *pats, **opts):
4464 """show revision history of entire repository or files
4464 """show revision history of entire repository or files
4465
4465
4466 Print the revision history of the specified files or the entire
4466 Print the revision history of the specified files or the entire
4467 project.
4467 project.
4468
4468
4469 If no revision range is specified, the default is ``tip:0`` unless
4469 If no revision range is specified, the default is ``tip:0`` unless
4470 --follow is set, in which case the working directory parent is
4470 --follow is set, in which case the working directory parent is
4471 used as the starting revision.
4471 used as the starting revision.
4472
4472
4473 File history is shown without following rename or copy history of
4473 File history is shown without following rename or copy history of
4474 files. Use -f/--follow with a filename to follow history across
4474 files. Use -f/--follow with a filename to follow history across
4475 renames and copies. --follow without a filename will only show
4475 renames and copies. --follow without a filename will only show
4476 ancestors or descendants of the starting revision.
4476 ancestors or descendants of the starting revision.
4477
4477
4478 By default this command prints revision number and changeset id,
4478 By default this command prints revision number and changeset id,
4479 tags, non-trivial parents, user, date and time, and a summary for
4479 tags, non-trivial parents, user, date and time, and a summary for
4480 each commit. When the -v/--verbose switch is used, the list of
4480 each commit. When the -v/--verbose switch is used, the list of
4481 changed files and full commit message are shown.
4481 changed files and full commit message are shown.
4482
4482
4483 With --graph the revisions are shown as an ASCII art DAG with the most
4483 With --graph the revisions are shown as an ASCII art DAG with the most
4484 recent changeset at the top.
4484 recent changeset at the top.
4485 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4485 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4486 and '+' represents a fork where the changeset from the lines below is a
4486 and '+' represents a fork where the changeset from the lines below is a
4487 parent of the 'o' merge on the same line.
4487 parent of the 'o' merge on the same line.
4488
4488
4489 .. note::
4489 .. note::
4490
4490
4491 log -p/--patch may generate unexpected diff output for merge
4491 log -p/--patch may generate unexpected diff output for merge
4492 changesets, as it will only compare the merge changeset against
4492 changesets, as it will only compare the merge changeset against
4493 its first parent. Also, only files different from BOTH parents
4493 its first parent. Also, only files different from BOTH parents
4494 will appear in files:.
4494 will appear in files:.
4495
4495
4496 .. note::
4496 .. note::
4497
4497
4498 for performance reasons, log FILE may omit duplicate changes
4498 for performance reasons, log FILE may omit duplicate changes
4499 made on branches and will not show removals or mode changes. To
4499 made on branches and will not show removals or mode changes. To
4500 see all such changes, use the --removed switch.
4500 see all such changes, use the --removed switch.
4501
4501
4502 .. container:: verbose
4502 .. container:: verbose
4503
4503
4504 Some examples:
4504 Some examples:
4505
4505
4506 - changesets with full descriptions and file lists::
4506 - changesets with full descriptions and file lists::
4507
4507
4508 hg log -v
4508 hg log -v
4509
4509
4510 - changesets ancestral to the working directory::
4510 - changesets ancestral to the working directory::
4511
4511
4512 hg log -f
4512 hg log -f
4513
4513
4514 - last 10 commits on the current branch::
4514 - last 10 commits on the current branch::
4515
4515
4516 hg log -l 10 -b .
4516 hg log -l 10 -b .
4517
4517
4518 - changesets showing all modifications of a file, including removals::
4518 - changesets showing all modifications of a file, including removals::
4519
4519
4520 hg log --removed file.c
4520 hg log --removed file.c
4521
4521
4522 - all changesets that touch a directory, with diffs, excluding merges::
4522 - all changesets that touch a directory, with diffs, excluding merges::
4523
4523
4524 hg log -Mp lib/
4524 hg log -Mp lib/
4525
4525
4526 - all revision numbers that match a keyword::
4526 - all revision numbers that match a keyword::
4527
4527
4528 hg log -k bug --template "{rev}\\n"
4528 hg log -k bug --template "{rev}\\n"
4529
4529
4530 - list available log templates::
4530 - list available log templates::
4531
4531
4532 hg log -T list
4532 hg log -T list
4533
4533
4534 - check if a given changeset is included in a tagged release::
4534 - check if a given changeset is included in a tagged release::
4535
4535
4536 hg log -r "a21ccf and ancestor(1.9)"
4536 hg log -r "a21ccf and ancestor(1.9)"
4537
4537
4538 - find all changesets by some user in a date range::
4538 - find all changesets by some user in a date range::
4539
4539
4540 hg log -k alice -d "may 2008 to jul 2008"
4540 hg log -k alice -d "may 2008 to jul 2008"
4541
4541
4542 - summary of all changesets after the last tag::
4542 - summary of all changesets after the last tag::
4543
4543
4544 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4544 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4545
4545
4546 See :hg:`help dates` for a list of formats valid for -d/--date.
4546 See :hg:`help dates` for a list of formats valid for -d/--date.
4547
4547
4548 See :hg:`help revisions` and :hg:`help revsets` for more about
4548 See :hg:`help revisions` and :hg:`help revsets` for more about
4549 specifying revisions.
4549 specifying revisions.
4550
4550
4551 See :hg:`help templates` for more about pre-packaged styles and
4551 See :hg:`help templates` for more about pre-packaged styles and
4552 specifying custom templates.
4552 specifying custom templates.
4553
4553
4554 Returns 0 on success.
4554 Returns 0 on success.
4555
4555
4556 """
4556 """
4557 if opts.get('follow') and opts.get('rev'):
4557 if opts.get('follow') and opts.get('rev'):
4558 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4558 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4559 del opts['follow']
4559 del opts['follow']
4560
4560
4561 if opts.get('graph'):
4561 if opts.get('graph'):
4562 return cmdutil.graphlog(ui, repo, *pats, **opts)
4562 return cmdutil.graphlog(ui, repo, *pats, **opts)
4563
4563
4564 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4564 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4565 limit = cmdutil.loglimit(opts)
4565 limit = cmdutil.loglimit(opts)
4566 count = 0
4566 count = 0
4567
4567
4568 getrenamed = None
4568 getrenamed = None
4569 if opts.get('copies'):
4569 if opts.get('copies'):
4570 endrev = None
4570 endrev = None
4571 if opts.get('rev'):
4571 if opts.get('rev'):
4572 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4572 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4573 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4573 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4574
4574
4575 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4575 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4576 for rev in revs:
4576 for rev in revs:
4577 if count == limit:
4577 if count == limit:
4578 break
4578 break
4579 ctx = repo[rev]
4579 ctx = repo[rev]
4580 copies = None
4580 copies = None
4581 if getrenamed is not None and rev:
4581 if getrenamed is not None and rev:
4582 copies = []
4582 copies = []
4583 for fn in ctx.files():
4583 for fn in ctx.files():
4584 rename = getrenamed(fn, rev)
4584 rename = getrenamed(fn, rev)
4585 if rename:
4585 if rename:
4586 copies.append((fn, rename[0]))
4586 copies.append((fn, rename[0]))
4587 if filematcher:
4587 if filematcher:
4588 revmatchfn = filematcher(ctx.rev())
4588 revmatchfn = filematcher(ctx.rev())
4589 else:
4589 else:
4590 revmatchfn = None
4590 revmatchfn = None
4591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4591 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4592 if displayer.flush(rev):
4592 if displayer.flush(rev):
4593 count += 1
4593 count += 1
4594
4594
4595 displayer.close()
4595 displayer.close()
4596
4596
4597 @command('manifest',
4597 @command('manifest',
4598 [('r', 'rev', '', _('revision to display'), _('REV')),
4598 [('r', 'rev', '', _('revision to display'), _('REV')),
4599 ('', 'all', False, _("list files from all revisions"))]
4599 ('', 'all', False, _("list files from all revisions"))]
4600 + formatteropts,
4600 + formatteropts,
4601 _('[-r REV]'))
4601 _('[-r REV]'))
4602 def manifest(ui, repo, node=None, rev=None, **opts):
4602 def manifest(ui, repo, node=None, rev=None, **opts):
4603 """output the current or given revision of the project manifest
4603 """output the current or given revision of the project manifest
4604
4604
4605 Print a list of version controlled files for the given revision.
4605 Print a list of version controlled files for the given revision.
4606 If no revision is given, the first parent of the working directory
4606 If no revision is given, the first parent of the working directory
4607 is used, or the null revision if no revision is checked out.
4607 is used, or the null revision if no revision is checked out.
4608
4608
4609 With -v, print file permissions, symlink and executable bits.
4609 With -v, print file permissions, symlink and executable bits.
4610 With --debug, print file revision hashes.
4610 With --debug, print file revision hashes.
4611
4611
4612 If option --all is specified, the list of all files from all revisions
4612 If option --all is specified, the list of all files from all revisions
4613 is printed. This includes deleted and renamed files.
4613 is printed. This includes deleted and renamed files.
4614
4614
4615 Returns 0 on success.
4615 Returns 0 on success.
4616 """
4616 """
4617
4617
4618 fm = ui.formatter('manifest', opts)
4618 fm = ui.formatter('manifest', opts)
4619
4619
4620 if opts.get('all'):
4620 if opts.get('all'):
4621 if rev or node:
4621 if rev or node:
4622 raise util.Abort(_("can't specify a revision with --all"))
4622 raise util.Abort(_("can't specify a revision with --all"))
4623
4623
4624 res = []
4624 res = []
4625 prefix = "data/"
4625 prefix = "data/"
4626 suffix = ".i"
4626 suffix = ".i"
4627 plen = len(prefix)
4627 plen = len(prefix)
4628 slen = len(suffix)
4628 slen = len(suffix)
4629 lock = repo.lock()
4629 lock = repo.lock()
4630 try:
4630 try:
4631 for fn, b, size in repo.store.datafiles():
4631 for fn, b, size in repo.store.datafiles():
4632 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4632 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4633 res.append(fn[plen:-slen])
4633 res.append(fn[plen:-slen])
4634 finally:
4634 finally:
4635 lock.release()
4635 lock.release()
4636 for f in res:
4636 for f in res:
4637 fm.startitem()
4637 fm.startitem()
4638 fm.write("path", '%s\n', f)
4638 fm.write("path", '%s\n', f)
4639 fm.end()
4639 fm.end()
4640 return
4640 return
4641
4641
4642 if rev and node:
4642 if rev and node:
4643 raise util.Abort(_("please specify just one revision"))
4643 raise util.Abort(_("please specify just one revision"))
4644
4644
4645 if not node:
4645 if not node:
4646 node = rev
4646 node = rev
4647
4647
4648 char = {'l': '@', 'x': '*', '': ''}
4648 char = {'l': '@', 'x': '*', '': ''}
4649 mode = {'l': '644', 'x': '755', '': '644'}
4649 mode = {'l': '644', 'x': '755', '': '644'}
4650 ctx = scmutil.revsingle(repo, node)
4650 ctx = scmutil.revsingle(repo, node)
4651 mf = ctx.manifest()
4651 mf = ctx.manifest()
4652 for f in ctx:
4652 for f in ctx:
4653 fm.startitem()
4653 fm.startitem()
4654 fl = ctx[f].flags()
4654 fl = ctx[f].flags()
4655 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4655 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4656 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4656 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4657 fm.write('path', '%s\n', f)
4657 fm.write('path', '%s\n', f)
4658 fm.end()
4658 fm.end()
4659
4659
4660 @command('^merge',
4660 @command('^merge',
4661 [('f', 'force', None,
4661 [('f', 'force', None,
4662 _('force a merge including outstanding changes (DEPRECATED)')),
4662 _('force a merge including outstanding changes (DEPRECATED)')),
4663 ('r', 'rev', '', _('revision to merge'), _('REV')),
4663 ('r', 'rev', '', _('revision to merge'), _('REV')),
4664 ('P', 'preview', None,
4664 ('P', 'preview', None,
4665 _('review revisions to merge (no merge is performed)'))
4665 _('review revisions to merge (no merge is performed)'))
4666 ] + mergetoolopts,
4666 ] + mergetoolopts,
4667 _('[-P] [-f] [[-r] REV]'))
4667 _('[-P] [-f] [[-r] REV]'))
4668 def merge(ui, repo, node=None, **opts):
4668 def merge(ui, repo, node=None, **opts):
4669 """merge another revision into working directory
4669 """merge another revision into working directory
4670
4670
4671 The current working directory is updated with all changes made in
4671 The current working directory is updated with all changes made in
4672 the requested revision since the last common predecessor revision.
4672 the requested revision since the last common predecessor revision.
4673
4673
4674 Files that changed between either parent are marked as changed for
4674 Files that changed between either parent are marked as changed for
4675 the next commit and a commit must be performed before any further
4675 the next commit and a commit must be performed before any further
4676 updates to the repository are allowed. The next commit will have
4676 updates to the repository are allowed. The next commit will have
4677 two parents.
4677 two parents.
4678
4678
4679 ``--tool`` can be used to specify the merge tool used for file
4679 ``--tool`` can be used to specify the merge tool used for file
4680 merges. It overrides the HGMERGE environment variable and your
4680 merges. It overrides the HGMERGE environment variable and your
4681 configuration files. See :hg:`help merge-tools` for options.
4681 configuration files. See :hg:`help merge-tools` for options.
4682
4682
4683 If no revision is specified, the working directory's parent is a
4683 If no revision is specified, the working directory's parent is a
4684 head revision, and the current branch contains exactly one other
4684 head revision, and the current branch contains exactly one other
4685 head, the other head is merged with by default. Otherwise, an
4685 head, the other head is merged with by default. Otherwise, an
4686 explicit revision with which to merge with must be provided.
4686 explicit revision with which to merge with must be provided.
4687
4687
4688 :hg:`resolve` must be used to resolve unresolved files.
4688 :hg:`resolve` must be used to resolve unresolved files.
4689
4689
4690 To undo an uncommitted merge, use :hg:`update --clean .` which
4690 To undo an uncommitted merge, use :hg:`update --clean .` which
4691 will check out a clean copy of the original merge parent, losing
4691 will check out a clean copy of the original merge parent, losing
4692 all changes.
4692 all changes.
4693
4693
4694 Returns 0 on success, 1 if there are unresolved files.
4694 Returns 0 on success, 1 if there are unresolved files.
4695 """
4695 """
4696
4696
4697 if opts.get('rev') and node:
4697 if opts.get('rev') and node:
4698 raise util.Abort(_("please specify just one revision"))
4698 raise util.Abort(_("please specify just one revision"))
4699 if not node:
4699 if not node:
4700 node = opts.get('rev')
4700 node = opts.get('rev')
4701
4701
4702 if node:
4702 if node:
4703 node = scmutil.revsingle(repo, node).node()
4703 node = scmutil.revsingle(repo, node).node()
4704
4704
4705 if not node and repo._bookmarkcurrent:
4705 if not node and repo._bookmarkcurrent:
4706 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4706 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4707 curhead = repo[repo._bookmarkcurrent].node()
4707 curhead = repo[repo._bookmarkcurrent].node()
4708 if len(bmheads) == 2:
4708 if len(bmheads) == 2:
4709 if curhead == bmheads[0]:
4709 if curhead == bmheads[0]:
4710 node = bmheads[1]
4710 node = bmheads[1]
4711 else:
4711 else:
4712 node = bmheads[0]
4712 node = bmheads[0]
4713 elif len(bmheads) > 2:
4713 elif len(bmheads) > 2:
4714 raise util.Abort(_("multiple matching bookmarks to merge - "
4714 raise util.Abort(_("multiple matching bookmarks to merge - "
4715 "please merge with an explicit rev or bookmark"),
4715 "please merge with an explicit rev or bookmark"),
4716 hint=_("run 'hg heads' to see all heads"))
4716 hint=_("run 'hg heads' to see all heads"))
4717 elif len(bmheads) <= 1:
4717 elif len(bmheads) <= 1:
4718 raise util.Abort(_("no matching bookmark to merge - "
4718 raise util.Abort(_("no matching bookmark to merge - "
4719 "please merge with an explicit rev or bookmark"),
4719 "please merge with an explicit rev or bookmark"),
4720 hint=_("run 'hg heads' to see all heads"))
4720 hint=_("run 'hg heads' to see all heads"))
4721
4721
4722 if not node and not repo._bookmarkcurrent:
4722 if not node and not repo._bookmarkcurrent:
4723 branch = repo[None].branch()
4723 branch = repo[None].branch()
4724 bheads = repo.branchheads(branch)
4724 bheads = repo.branchheads(branch)
4725 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4725 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4726
4726
4727 if len(nbhs) > 2:
4727 if len(nbhs) > 2:
4728 raise util.Abort(_("branch '%s' has %d heads - "
4728 raise util.Abort(_("branch '%s' has %d heads - "
4729 "please merge with an explicit rev")
4729 "please merge with an explicit rev")
4730 % (branch, len(bheads)),
4730 % (branch, len(bheads)),
4731 hint=_("run 'hg heads .' to see heads"))
4731 hint=_("run 'hg heads .' to see heads"))
4732
4732
4733 parent = repo.dirstate.p1()
4733 parent = repo.dirstate.p1()
4734 if len(nbhs) <= 1:
4734 if len(nbhs) <= 1:
4735 if len(bheads) > 1:
4735 if len(bheads) > 1:
4736 raise util.Abort(_("heads are bookmarked - "
4736 raise util.Abort(_("heads are bookmarked - "
4737 "please merge with an explicit rev"),
4737 "please merge with an explicit rev"),
4738 hint=_("run 'hg heads' to see all heads"))
4738 hint=_("run 'hg heads' to see all heads"))
4739 if len(repo.heads()) > 1:
4739 if len(repo.heads()) > 1:
4740 raise util.Abort(_("branch '%s' has one head - "
4740 raise util.Abort(_("branch '%s' has one head - "
4741 "please merge with an explicit rev")
4741 "please merge with an explicit rev")
4742 % branch,
4742 % branch,
4743 hint=_("run 'hg heads' to see all heads"))
4743 hint=_("run 'hg heads' to see all heads"))
4744 msg, hint = _('nothing to merge'), None
4744 msg, hint = _('nothing to merge'), None
4745 if parent != repo.lookup(branch):
4745 if parent != repo.lookup(branch):
4746 hint = _("use 'hg update' instead")
4746 hint = _("use 'hg update' instead")
4747 raise util.Abort(msg, hint=hint)
4747 raise util.Abort(msg, hint=hint)
4748
4748
4749 if parent not in bheads:
4749 if parent not in bheads:
4750 raise util.Abort(_('working directory not at a head revision'),
4750 raise util.Abort(_('working directory not at a head revision'),
4751 hint=_("use 'hg update' or merge with an "
4751 hint=_("use 'hg update' or merge with an "
4752 "explicit revision"))
4752 "explicit revision"))
4753 if parent == nbhs[0]:
4753 if parent == nbhs[0]:
4754 node = nbhs[-1]
4754 node = nbhs[-1]
4755 else:
4755 else:
4756 node = nbhs[0]
4756 node = nbhs[0]
4757
4757
4758 if opts.get('preview'):
4758 if opts.get('preview'):
4759 # find nodes that are ancestors of p2 but not of p1
4759 # find nodes that are ancestors of p2 but not of p1
4760 p1 = repo.lookup('.')
4760 p1 = repo.lookup('.')
4761 p2 = repo.lookup(node)
4761 p2 = repo.lookup(node)
4762 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4762 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4763
4763
4764 displayer = cmdutil.show_changeset(ui, repo, opts)
4764 displayer = cmdutil.show_changeset(ui, repo, opts)
4765 for node in nodes:
4765 for node in nodes:
4766 displayer.show(repo[node])
4766 displayer.show(repo[node])
4767 displayer.close()
4767 displayer.close()
4768 return 0
4768 return 0
4769
4769
4770 try:
4770 try:
4771 # ui.forcemerge is an internal variable, do not document
4771 # ui.forcemerge is an internal variable, do not document
4772 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4772 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4773 return hg.merge(repo, node, force=opts.get('force'))
4773 return hg.merge(repo, node, force=opts.get('force'))
4774 finally:
4774 finally:
4775 ui.setconfig('ui', 'forcemerge', '', 'merge')
4775 ui.setconfig('ui', 'forcemerge', '', 'merge')
4776
4776
4777 @command('outgoing|out',
4777 @command('outgoing|out',
4778 [('f', 'force', None, _('run even when the destination is unrelated')),
4778 [('f', 'force', None, _('run even when the destination is unrelated')),
4779 ('r', 'rev', [],
4779 ('r', 'rev', [],
4780 _('a changeset intended to be included in the destination'), _('REV')),
4780 _('a changeset intended to be included in the destination'), _('REV')),
4781 ('n', 'newest-first', None, _('show newest record first')),
4781 ('n', 'newest-first', None, _('show newest record first')),
4782 ('B', 'bookmarks', False, _('compare bookmarks')),
4782 ('B', 'bookmarks', False, _('compare bookmarks')),
4783 ('b', 'branch', [], _('a specific branch you would like to push'),
4783 ('b', 'branch', [], _('a specific branch you would like to push'),
4784 _('BRANCH')),
4784 _('BRANCH')),
4785 ] + logopts + remoteopts + subrepoopts,
4785 ] + logopts + remoteopts + subrepoopts,
4786 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4786 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4787 def outgoing(ui, repo, dest=None, **opts):
4787 def outgoing(ui, repo, dest=None, **opts):
4788 """show changesets not found in the destination
4788 """show changesets not found in the destination
4789
4789
4790 Show changesets not found in the specified destination repository
4790 Show changesets not found in the specified destination repository
4791 or the default push location. These are the changesets that would
4791 or the default push location. These are the changesets that would
4792 be pushed if a push was requested.
4792 be pushed if a push was requested.
4793
4793
4794 See pull for details of valid destination formats.
4794 See pull for details of valid destination formats.
4795
4795
4796 .. container:: verbose
4796 .. container:: verbose
4797
4797
4798 With -B/--bookmarks, the result of bookmark comparison between
4798 With -B/--bookmarks, the result of bookmark comparison between
4799 local and remote repositories is displayed. With -v/--verbose,
4799 local and remote repositories is displayed. With -v/--verbose,
4800 status is also displayed for each bookmark like below::
4800 status is also displayed for each bookmark like below::
4801
4801
4802 BM1 01234567890a added
4802 BM1 01234567890a added
4803 BM2 deleted
4803 BM2 deleted
4804 BM3 234567890abc advanced
4804 BM3 234567890abc advanced
4805 BM4 34567890abcd diverged
4805 BM4 34567890abcd diverged
4806 BM5 4567890abcde changed
4806 BM5 4567890abcde changed
4807
4807
4808 The action taken when pushing depends on the
4808 The action taken when pushing depends on the
4809 status of each bookmark:
4809 status of each bookmark:
4810
4810
4811 :``added``: push with ``-B`` will create it
4811 :``added``: push with ``-B`` will create it
4812 :``deleted``: push with ``-B`` will delete it
4812 :``deleted``: push with ``-B`` will delete it
4813 :``advanced``: push will update it
4813 :``advanced``: push will update it
4814 :``diverged``: push with ``-B`` will update it
4814 :``diverged``: push with ``-B`` will update it
4815 :``changed``: push with ``-B`` will update it
4815 :``changed``: push with ``-B`` will update it
4816
4816
4817 From the point of view of pushing behavior, bookmarks
4817 From the point of view of pushing behavior, bookmarks
4818 existing only in the remote repository are treated as
4818 existing only in the remote repository are treated as
4819 ``deleted``, even if it is in fact added remotely.
4819 ``deleted``, even if it is in fact added remotely.
4820
4820
4821 Returns 0 if there are outgoing changes, 1 otherwise.
4821 Returns 0 if there are outgoing changes, 1 otherwise.
4822 """
4822 """
4823 if opts.get('graph'):
4823 if opts.get('graph'):
4824 cmdutil.checkunsupportedgraphflags([], opts)
4824 cmdutil.checkunsupportedgraphflags([], opts)
4825 o, other = hg._outgoing(ui, repo, dest, opts)
4825 o, other = hg._outgoing(ui, repo, dest, opts)
4826 if not o:
4826 if not o:
4827 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4827 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4828 return
4828 return
4829
4829
4830 revdag = cmdutil.graphrevs(repo, o, opts)
4830 revdag = cmdutil.graphrevs(repo, o, opts)
4831 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4831 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4832 showparents = [ctx.node() for ctx in repo[None].parents()]
4832 showparents = [ctx.node() for ctx in repo[None].parents()]
4833 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4833 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4834 graphmod.asciiedges)
4834 graphmod.asciiedges)
4835 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4835 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4836 return 0
4836 return 0
4837
4837
4838 if opts.get('bookmarks'):
4838 if opts.get('bookmarks'):
4839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4839 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4840 dest, branches = hg.parseurl(dest, opts.get('branch'))
4840 dest, branches = hg.parseurl(dest, opts.get('branch'))
4841 other = hg.peer(repo, opts, dest)
4841 other = hg.peer(repo, opts, dest)
4842 if 'bookmarks' not in other.listkeys('namespaces'):
4842 if 'bookmarks' not in other.listkeys('namespaces'):
4843 ui.warn(_("remote doesn't support bookmarks\n"))
4843 ui.warn(_("remote doesn't support bookmarks\n"))
4844 return 0
4844 return 0
4845 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4845 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4846 return bookmarks.outgoing(ui, repo, other)
4846 return bookmarks.outgoing(ui, repo, other)
4847
4847
4848 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4848 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4849 try:
4849 try:
4850 return hg.outgoing(ui, repo, dest, opts)
4850 return hg.outgoing(ui, repo, dest, opts)
4851 finally:
4851 finally:
4852 del repo._subtoppath
4852 del repo._subtoppath
4853
4853
4854 @command('parents',
4854 @command('parents',
4855 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4855 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4856 ] + templateopts,
4856 ] + templateopts,
4857 _('[-r REV] [FILE]'),
4857 _('[-r REV] [FILE]'),
4858 inferrepo=True)
4858 inferrepo=True)
4859 def parents(ui, repo, file_=None, **opts):
4859 def parents(ui, repo, file_=None, **opts):
4860 """show the parents of the working directory or revision (DEPRECATED)
4860 """show the parents of the working directory or revision (DEPRECATED)
4861
4861
4862 Print the working directory's parent revisions. If a revision is
4862 Print the working directory's parent revisions. If a revision is
4863 given via -r/--rev, the parent of that revision will be printed.
4863 given via -r/--rev, the parent of that revision will be printed.
4864 If a file argument is given, the revision in which the file was
4864 If a file argument is given, the revision in which the file was
4865 last changed (before the working directory revision or the
4865 last changed (before the working directory revision or the
4866 argument to --rev if given) is printed.
4866 argument to --rev if given) is printed.
4867
4867
4868 See :hg:`summary` and :hg:`help revsets` for related information.
4868 See :hg:`summary` and :hg:`help revsets` for related information.
4869
4869
4870 Returns 0 on success.
4870 Returns 0 on success.
4871 """
4871 """
4872
4872
4873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4873 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4874
4874
4875 if file_:
4875 if file_:
4876 m = scmutil.match(ctx, (file_,), opts)
4876 m = scmutil.match(ctx, (file_,), opts)
4877 if m.anypats() or len(m.files()) != 1:
4877 if m.anypats() or len(m.files()) != 1:
4878 raise util.Abort(_('can only specify an explicit filename'))
4878 raise util.Abort(_('can only specify an explicit filename'))
4879 file_ = m.files()[0]
4879 file_ = m.files()[0]
4880 filenodes = []
4880 filenodes = []
4881 for cp in ctx.parents():
4881 for cp in ctx.parents():
4882 if not cp:
4882 if not cp:
4883 continue
4883 continue
4884 try:
4884 try:
4885 filenodes.append(cp.filenode(file_))
4885 filenodes.append(cp.filenode(file_))
4886 except error.LookupError:
4886 except error.LookupError:
4887 pass
4887 pass
4888 if not filenodes:
4888 if not filenodes:
4889 raise util.Abort(_("'%s' not found in manifest!") % file_)
4889 raise util.Abort(_("'%s' not found in manifest!") % file_)
4890 p = []
4890 p = []
4891 for fn in filenodes:
4891 for fn in filenodes:
4892 fctx = repo.filectx(file_, fileid=fn)
4892 fctx = repo.filectx(file_, fileid=fn)
4893 p.append(fctx.node())
4893 p.append(fctx.node())
4894 else:
4894 else:
4895 p = [cp.node() for cp in ctx.parents()]
4895 p = [cp.node() for cp in ctx.parents()]
4896
4896
4897 displayer = cmdutil.show_changeset(ui, repo, opts)
4897 displayer = cmdutil.show_changeset(ui, repo, opts)
4898 for n in p:
4898 for n in p:
4899 if n != nullid:
4899 if n != nullid:
4900 displayer.show(repo[n])
4900 displayer.show(repo[n])
4901 displayer.close()
4901 displayer.close()
4902
4902
4903 @command('paths', [], _('[NAME]'), optionalrepo=True)
4903 @command('paths', [], _('[NAME]'), optionalrepo=True)
4904 def paths(ui, repo, search=None):
4904 def paths(ui, repo, search=None):
4905 """show aliases for remote repositories
4905 """show aliases for remote repositories
4906
4906
4907 Show definition of symbolic path name NAME. If no name is given,
4907 Show definition of symbolic path name NAME. If no name is given,
4908 show definition of all available names.
4908 show definition of all available names.
4909
4909
4910 Option -q/--quiet suppresses all output when searching for NAME
4910 Option -q/--quiet suppresses all output when searching for NAME
4911 and shows only the path names when listing all definitions.
4911 and shows only the path names when listing all definitions.
4912
4912
4913 Path names are defined in the [paths] section of your
4913 Path names are defined in the [paths] section of your
4914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4914 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4915 repository, ``.hg/hgrc`` is used, too.
4915 repository, ``.hg/hgrc`` is used, too.
4916
4916
4917 The path names ``default`` and ``default-push`` have a special
4917 The path names ``default`` and ``default-push`` have a special
4918 meaning. When performing a push or pull operation, they are used
4918 meaning. When performing a push or pull operation, they are used
4919 as fallbacks if no location is specified on the command-line.
4919 as fallbacks if no location is specified on the command-line.
4920 When ``default-push`` is set, it will be used for push and
4920 When ``default-push`` is set, it will be used for push and
4921 ``default`` will be used for pull; otherwise ``default`` is used
4921 ``default`` will be used for pull; otherwise ``default`` is used
4922 as the fallback for both. When cloning a repository, the clone
4922 as the fallback for both. When cloning a repository, the clone
4923 source is written as ``default`` in ``.hg/hgrc``. Note that
4923 source is written as ``default`` in ``.hg/hgrc``. Note that
4924 ``default`` and ``default-push`` apply to all inbound (e.g.
4924 ``default`` and ``default-push`` apply to all inbound (e.g.
4925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4925 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4926 :hg:`bundle`) operations.
4926 :hg:`bundle`) operations.
4927
4927
4928 See :hg:`help urls` for more information.
4928 See :hg:`help urls` for more information.
4929
4929
4930 Returns 0 on success.
4930 Returns 0 on success.
4931 """
4931 """
4932 if search:
4932 if search:
4933 for name, path in sorted(ui.paths.iteritems()):
4933 for name, path in sorted(ui.paths.iteritems()):
4934 if name == search:
4934 if name == search:
4935 ui.status("%s\n" % util.hidepassword(path.loc))
4935 ui.status("%s\n" % util.hidepassword(path.loc))
4936 return
4936 return
4937 if not ui.quiet:
4937 if not ui.quiet:
4938 ui.warn(_("not found!\n"))
4938 ui.warn(_("not found!\n"))
4939 return 1
4939 return 1
4940 else:
4940 else:
4941 for name, path in sorted(ui.paths.iteritems()):
4941 for name, path in sorted(ui.paths.iteritems()):
4942 if ui.quiet:
4942 if ui.quiet:
4943 ui.write("%s\n" % name)
4943 ui.write("%s\n" % name)
4944 else:
4944 else:
4945 ui.write("%s = %s\n" % (name,
4945 ui.write("%s = %s\n" % (name,
4946 util.hidepassword(path.loc)))
4946 util.hidepassword(path.loc)))
4947
4947
4948 @command('phase',
4948 @command('phase',
4949 [('p', 'public', False, _('set changeset phase to public')),
4949 [('p', 'public', False, _('set changeset phase to public')),
4950 ('d', 'draft', False, _('set changeset phase to draft')),
4950 ('d', 'draft', False, _('set changeset phase to draft')),
4951 ('s', 'secret', False, _('set changeset phase to secret')),
4951 ('s', 'secret', False, _('set changeset phase to secret')),
4952 ('f', 'force', False, _('allow to move boundary backward')),
4952 ('f', 'force', False, _('allow to move boundary backward')),
4953 ('r', 'rev', [], _('target revision'), _('REV')),
4953 ('r', 'rev', [], _('target revision'), _('REV')),
4954 ],
4954 ],
4955 _('[-p|-d|-s] [-f] [-r] REV...'))
4955 _('[-p|-d|-s] [-f] [-r] REV...'))
4956 def phase(ui, repo, *revs, **opts):
4956 def phase(ui, repo, *revs, **opts):
4957 """set or show the current phase name
4957 """set or show the current phase name
4958
4958
4959 With no argument, show the phase name of specified revisions.
4959 With no argument, show the phase name of specified revisions.
4960
4960
4961 With one of -p/--public, -d/--draft or -s/--secret, change the
4961 With one of -p/--public, -d/--draft or -s/--secret, change the
4962 phase value of the specified revisions.
4962 phase value of the specified revisions.
4963
4963
4964 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4964 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4965 lower phase to an higher phase. Phases are ordered as follows::
4965 lower phase to an higher phase. Phases are ordered as follows::
4966
4966
4967 public < draft < secret
4967 public < draft < secret
4968
4968
4969 Returns 0 on success, 1 if no phases were changed or some could not
4969 Returns 0 on success, 1 if no phases were changed or some could not
4970 be changed.
4970 be changed.
4971 """
4971 """
4972 # search for a unique phase argument
4972 # search for a unique phase argument
4973 targetphase = None
4973 targetphase = None
4974 for idx, name in enumerate(phases.phasenames):
4974 for idx, name in enumerate(phases.phasenames):
4975 if opts[name]:
4975 if opts[name]:
4976 if targetphase is not None:
4976 if targetphase is not None:
4977 raise util.Abort(_('only one phase can be specified'))
4977 raise util.Abort(_('only one phase can be specified'))
4978 targetphase = idx
4978 targetphase = idx
4979
4979
4980 # look for specified revision
4980 # look for specified revision
4981 revs = list(revs)
4981 revs = list(revs)
4982 revs.extend(opts['rev'])
4982 revs.extend(opts['rev'])
4983 if not revs:
4983 if not revs:
4984 raise util.Abort(_('no revisions specified'))
4984 raise util.Abort(_('no revisions specified'))
4985
4985
4986 revs = scmutil.revrange(repo, revs)
4986 revs = scmutil.revrange(repo, revs)
4987
4987
4988 lock = None
4988 lock = None
4989 ret = 0
4989 ret = 0
4990 if targetphase is None:
4990 if targetphase is None:
4991 # display
4991 # display
4992 for r in revs:
4992 for r in revs:
4993 ctx = repo[r]
4993 ctx = repo[r]
4994 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4994 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4995 else:
4995 else:
4996 tr = None
4996 tr = None
4997 lock = repo.lock()
4997 lock = repo.lock()
4998 try:
4998 try:
4999 tr = repo.transaction("phase")
4999 tr = repo.transaction("phase")
5000 # set phase
5000 # set phase
5001 if not revs:
5001 if not revs:
5002 raise util.Abort(_('empty revision set'))
5002 raise util.Abort(_('empty revision set'))
5003 nodes = [repo[r].node() for r in revs]
5003 nodes = [repo[r].node() for r in revs]
5004 # moving revision from public to draft may hide them
5004 # moving revision from public to draft may hide them
5005 # We have to check result on an unfiltered repository
5005 # We have to check result on an unfiltered repository
5006 unfi = repo.unfiltered()
5006 unfi = repo.unfiltered()
5007 getphase = unfi._phasecache.phase
5007 getphase = unfi._phasecache.phase
5008 olddata = [getphase(unfi, r) for r in unfi]
5008 olddata = [getphase(unfi, r) for r in unfi]
5009 phases.advanceboundary(repo, tr, targetphase, nodes)
5009 phases.advanceboundary(repo, tr, targetphase, nodes)
5010 if opts['force']:
5010 if opts['force']:
5011 phases.retractboundary(repo, tr, targetphase, nodes)
5011 phases.retractboundary(repo, tr, targetphase, nodes)
5012 tr.close()
5012 tr.close()
5013 finally:
5013 finally:
5014 if tr is not None:
5014 if tr is not None:
5015 tr.release()
5015 tr.release()
5016 lock.release()
5016 lock.release()
5017 getphase = unfi._phasecache.phase
5017 getphase = unfi._phasecache.phase
5018 newdata = [getphase(unfi, r) for r in unfi]
5018 newdata = [getphase(unfi, r) for r in unfi]
5019 changes = sum(newdata[r] != olddata[r] for r in unfi)
5019 changes = sum(newdata[r] != olddata[r] for r in unfi)
5020 cl = unfi.changelog
5020 cl = unfi.changelog
5021 rejected = [n for n in nodes
5021 rejected = [n for n in nodes
5022 if newdata[cl.rev(n)] < targetphase]
5022 if newdata[cl.rev(n)] < targetphase]
5023 if rejected:
5023 if rejected:
5024 ui.warn(_('cannot move %i changesets to a higher '
5024 ui.warn(_('cannot move %i changesets to a higher '
5025 'phase, use --force\n') % len(rejected))
5025 'phase, use --force\n') % len(rejected))
5026 ret = 1
5026 ret = 1
5027 if changes:
5027 if changes:
5028 msg = _('phase changed for %i changesets\n') % changes
5028 msg = _('phase changed for %i changesets\n') % changes
5029 if ret:
5029 if ret:
5030 ui.status(msg)
5030 ui.status(msg)
5031 else:
5031 else:
5032 ui.note(msg)
5032 ui.note(msg)
5033 else:
5033 else:
5034 ui.warn(_('no phases changed\n'))
5034 ui.warn(_('no phases changed\n'))
5035 ret = 1
5035 ret = 1
5036 return ret
5036 return ret
5037
5037
5038 def postincoming(ui, repo, modheads, optupdate, checkout):
5038 def postincoming(ui, repo, modheads, optupdate, checkout):
5039 if modheads == 0:
5039 if modheads == 0:
5040 return
5040 return
5041 if optupdate:
5041 if optupdate:
5042 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5042 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5043 try:
5043 try:
5044 ret = hg.update(repo, checkout)
5044 ret = hg.update(repo, checkout)
5045 except util.Abort, inst:
5045 except util.Abort, inst:
5046 ui.warn(_("not updating: %s\n") % str(inst))
5046 ui.warn(_("not updating: %s\n") % str(inst))
5047 if inst.hint:
5047 if inst.hint:
5048 ui.warn(_("(%s)\n") % inst.hint)
5048 ui.warn(_("(%s)\n") % inst.hint)
5049 return 0
5049 return 0
5050 if not ret and not checkout:
5050 if not ret and not checkout:
5051 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5051 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5052 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5052 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5053 return ret
5053 return ret
5054 if modheads > 1:
5054 if modheads > 1:
5055 currentbranchheads = len(repo.branchheads())
5055 currentbranchheads = len(repo.branchheads())
5056 if currentbranchheads == modheads:
5056 if currentbranchheads == modheads:
5057 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5057 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5058 elif currentbranchheads > 1:
5058 elif currentbranchheads > 1:
5059 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5059 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5060 "merge)\n"))
5060 "merge)\n"))
5061 else:
5061 else:
5062 ui.status(_("(run 'hg heads' to see heads)\n"))
5062 ui.status(_("(run 'hg heads' to see heads)\n"))
5063 else:
5063 else:
5064 ui.status(_("(run 'hg update' to get a working copy)\n"))
5064 ui.status(_("(run 'hg update' to get a working copy)\n"))
5065
5065
5066 @command('^pull',
5066 @command('^pull',
5067 [('u', 'update', None,
5067 [('u', 'update', None,
5068 _('update to new branch head if changesets were pulled')),
5068 _('update to new branch head if changesets were pulled')),
5069 ('f', 'force', None, _('run even when remote repository is unrelated')),
5069 ('f', 'force', None, _('run even when remote repository is unrelated')),
5070 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5070 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5071 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5071 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5072 ('b', 'branch', [], _('a specific branch you would like to pull'),
5072 ('b', 'branch', [], _('a specific branch you would like to pull'),
5073 _('BRANCH')),
5073 _('BRANCH')),
5074 ] + remoteopts,
5074 ] + remoteopts,
5075 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5075 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5076 def pull(ui, repo, source="default", **opts):
5076 def pull(ui, repo, source="default", **opts):
5077 """pull changes from the specified source
5077 """pull changes from the specified source
5078
5078
5079 Pull changes from a remote repository to a local one.
5079 Pull changes from a remote repository to a local one.
5080
5080
5081 This finds all changes from the repository at the specified path
5081 This finds all changes from the repository at the specified path
5082 or URL and adds them to a local repository (the current one unless
5082 or URL and adds them to a local repository (the current one unless
5083 -R is specified). By default, this does not update the copy of the
5083 -R is specified). By default, this does not update the copy of the
5084 project in the working directory.
5084 project in the working directory.
5085
5085
5086 Use :hg:`incoming` if you want to see what would have been added
5086 Use :hg:`incoming` if you want to see what would have been added
5087 by a pull at the time you issued this command. If you then decide
5087 by a pull at the time you issued this command. If you then decide
5088 to add those changes to the repository, you should use :hg:`pull
5088 to add those changes to the repository, you should use :hg:`pull
5089 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5089 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5090
5090
5091 If SOURCE is omitted, the 'default' path will be used.
5091 If SOURCE is omitted, the 'default' path will be used.
5092 See :hg:`help urls` for more information.
5092 See :hg:`help urls` for more information.
5093
5093
5094 Returns 0 on success, 1 if an update had unresolved files.
5094 Returns 0 on success, 1 if an update had unresolved files.
5095 """
5095 """
5096 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5096 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5097 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5097 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5098 other = hg.peer(repo, opts, source)
5098 other = hg.peer(repo, opts, source)
5099 try:
5099 try:
5100 revs, checkout = hg.addbranchrevs(repo, other, branches,
5100 revs, checkout = hg.addbranchrevs(repo, other, branches,
5101 opts.get('rev'))
5101 opts.get('rev'))
5102
5102
5103 remotebookmarks = other.listkeys('bookmarks')
5103 remotebookmarks = other.listkeys('bookmarks')
5104
5104
5105 if opts.get('bookmark'):
5105 if opts.get('bookmark'):
5106 if not revs:
5106 if not revs:
5107 revs = []
5107 revs = []
5108 for b in opts['bookmark']:
5108 for b in opts['bookmark']:
5109 if b not in remotebookmarks:
5109 if b not in remotebookmarks:
5110 raise util.Abort(_('remote bookmark %s not found!') % b)
5110 raise util.Abort(_('remote bookmark %s not found!') % b)
5111 revs.append(remotebookmarks[b])
5111 revs.append(remotebookmarks[b])
5112
5112
5113 if revs:
5113 if revs:
5114 try:
5114 try:
5115 revs = [other.lookup(rev) for rev in revs]
5115 oldrevs = revs
5116 revs = [] # actually, nodes
5117 for r in oldrevs:
5118 node = other.lookup(r)
5119 revs.append(node)
5120 if r == checkout:
5121 checkout = node
5116 except error.CapabilityError:
5122 except error.CapabilityError:
5117 err = _("other repository doesn't support revision lookup, "
5123 err = _("other repository doesn't support revision lookup, "
5118 "so a rev cannot be specified.")
5124 "so a rev cannot be specified.")
5119 raise util.Abort(err)
5125 raise util.Abort(err)
5120
5126
5121 modheads = exchange.pull(repo, other, heads=revs,
5127 modheads = exchange.pull(repo, other, heads=revs,
5122 force=opts.get('force'),
5128 force=opts.get('force'),
5123 bookmarks=opts.get('bookmark', ())).cgresult
5129 bookmarks=opts.get('bookmark', ())).cgresult
5124 if checkout:
5130 if checkout:
5125 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5131 checkout = str(repo.changelog.rev(checkout))
5126 repo._subtoppath = source
5132 repo._subtoppath = source
5127 try:
5133 try:
5128 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5134 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5129
5135
5130 finally:
5136 finally:
5131 del repo._subtoppath
5137 del repo._subtoppath
5132
5138
5133 finally:
5139 finally:
5134 other.close()
5140 other.close()
5135 return ret
5141 return ret
5136
5142
5137 @command('^push',
5143 @command('^push',
5138 [('f', 'force', None, _('force push')),
5144 [('f', 'force', None, _('force push')),
5139 ('r', 'rev', [],
5145 ('r', 'rev', [],
5140 _('a changeset intended to be included in the destination'),
5146 _('a changeset intended to be included in the destination'),
5141 _('REV')),
5147 _('REV')),
5142 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5148 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5143 ('b', 'branch', [],
5149 ('b', 'branch', [],
5144 _('a specific branch you would like to push'), _('BRANCH')),
5150 _('a specific branch you would like to push'), _('BRANCH')),
5145 ('', 'new-branch', False, _('allow pushing a new branch')),
5151 ('', 'new-branch', False, _('allow pushing a new branch')),
5146 ] + remoteopts,
5152 ] + remoteopts,
5147 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5153 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5148 def push(ui, repo, dest=None, **opts):
5154 def push(ui, repo, dest=None, **opts):
5149 """push changes to the specified destination
5155 """push changes to the specified destination
5150
5156
5151 Push changesets from the local repository to the specified
5157 Push changesets from the local repository to the specified
5152 destination.
5158 destination.
5153
5159
5154 This operation is symmetrical to pull: it is identical to a pull
5160 This operation is symmetrical to pull: it is identical to a pull
5155 in the destination repository from the current one.
5161 in the destination repository from the current one.
5156
5162
5157 By default, push will not allow creation of new heads at the
5163 By default, push will not allow creation of new heads at the
5158 destination, since multiple heads would make it unclear which head
5164 destination, since multiple heads would make it unclear which head
5159 to use. In this situation, it is recommended to pull and merge
5165 to use. In this situation, it is recommended to pull and merge
5160 before pushing.
5166 before pushing.
5161
5167
5162 Use --new-branch if you want to allow push to create a new named
5168 Use --new-branch if you want to allow push to create a new named
5163 branch that is not present at the destination. This allows you to
5169 branch that is not present at the destination. This allows you to
5164 only create a new branch without forcing other changes.
5170 only create a new branch without forcing other changes.
5165
5171
5166 .. note::
5172 .. note::
5167
5173
5168 Extra care should be taken with the -f/--force option,
5174 Extra care should be taken with the -f/--force option,
5169 which will push all new heads on all branches, an action which will
5175 which will push all new heads on all branches, an action which will
5170 almost always cause confusion for collaborators.
5176 almost always cause confusion for collaborators.
5171
5177
5172 If -r/--rev is used, the specified revision and all its ancestors
5178 If -r/--rev is used, the specified revision and all its ancestors
5173 will be pushed to the remote repository.
5179 will be pushed to the remote repository.
5174
5180
5175 If -B/--bookmark is used, the specified bookmarked revision, its
5181 If -B/--bookmark is used, the specified bookmarked revision, its
5176 ancestors, and the bookmark will be pushed to the remote
5182 ancestors, and the bookmark will be pushed to the remote
5177 repository.
5183 repository.
5178
5184
5179 Please see :hg:`help urls` for important details about ``ssh://``
5185 Please see :hg:`help urls` for important details about ``ssh://``
5180 URLs. If DESTINATION is omitted, a default path will be used.
5186 URLs. If DESTINATION is omitted, a default path will be used.
5181
5187
5182 Returns 0 if push was successful, 1 if nothing to push.
5188 Returns 0 if push was successful, 1 if nothing to push.
5183 """
5189 """
5184
5190
5185 if opts.get('bookmark'):
5191 if opts.get('bookmark'):
5186 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5192 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5187 for b in opts['bookmark']:
5193 for b in opts['bookmark']:
5188 # translate -B options to -r so changesets get pushed
5194 # translate -B options to -r so changesets get pushed
5189 if b in repo._bookmarks:
5195 if b in repo._bookmarks:
5190 opts.setdefault('rev', []).append(b)
5196 opts.setdefault('rev', []).append(b)
5191 else:
5197 else:
5192 # if we try to push a deleted bookmark, translate it to null
5198 # if we try to push a deleted bookmark, translate it to null
5193 # this lets simultaneous -r, -b options continue working
5199 # this lets simultaneous -r, -b options continue working
5194 opts.setdefault('rev', []).append("null")
5200 opts.setdefault('rev', []).append("null")
5195
5201
5196 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5202 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5197 dest, branches = hg.parseurl(dest, opts.get('branch'))
5203 dest, branches = hg.parseurl(dest, opts.get('branch'))
5198 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5204 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5199 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5205 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5200 try:
5206 try:
5201 other = hg.peer(repo, opts, dest)
5207 other = hg.peer(repo, opts, dest)
5202 except error.RepoError:
5208 except error.RepoError:
5203 if dest == "default-push":
5209 if dest == "default-push":
5204 raise util.Abort(_("default repository not configured!"),
5210 raise util.Abort(_("default repository not configured!"),
5205 hint=_('see the "path" section in "hg help config"'))
5211 hint=_('see the "path" section in "hg help config"'))
5206 else:
5212 else:
5207 raise
5213 raise
5208
5214
5209 if revs:
5215 if revs:
5210 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5216 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5211 if not revs:
5217 if not revs:
5212 raise util.Abort(_("specified revisions evaluate to an empty set"),
5218 raise util.Abort(_("specified revisions evaluate to an empty set"),
5213 hint=_("use different revision arguments"))
5219 hint=_("use different revision arguments"))
5214
5220
5215 repo._subtoppath = dest
5221 repo._subtoppath = dest
5216 try:
5222 try:
5217 # push subrepos depth-first for coherent ordering
5223 # push subrepos depth-first for coherent ordering
5218 c = repo['']
5224 c = repo['']
5219 subs = c.substate # only repos that are committed
5225 subs = c.substate # only repos that are committed
5220 for s in sorted(subs):
5226 for s in sorted(subs):
5221 result = c.sub(s).push(opts)
5227 result = c.sub(s).push(opts)
5222 if result == 0:
5228 if result == 0:
5223 return not result
5229 return not result
5224 finally:
5230 finally:
5225 del repo._subtoppath
5231 del repo._subtoppath
5226 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5232 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5227 newbranch=opts.get('new_branch'),
5233 newbranch=opts.get('new_branch'),
5228 bookmarks=opts.get('bookmark', ()))
5234 bookmarks=opts.get('bookmark', ()))
5229
5235
5230 result = not pushop.cgresult
5236 result = not pushop.cgresult
5231
5237
5232 if pushop.bkresult is not None:
5238 if pushop.bkresult is not None:
5233 if pushop.bkresult == 2:
5239 if pushop.bkresult == 2:
5234 result = 2
5240 result = 2
5235 elif not result and pushop.bkresult:
5241 elif not result and pushop.bkresult:
5236 result = 2
5242 result = 2
5237
5243
5238 return result
5244 return result
5239
5245
5240 @command('recover', [])
5246 @command('recover', [])
5241 def recover(ui, repo):
5247 def recover(ui, repo):
5242 """roll back an interrupted transaction
5248 """roll back an interrupted transaction
5243
5249
5244 Recover from an interrupted commit or pull.
5250 Recover from an interrupted commit or pull.
5245
5251
5246 This command tries to fix the repository status after an
5252 This command tries to fix the repository status after an
5247 interrupted operation. It should only be necessary when Mercurial
5253 interrupted operation. It should only be necessary when Mercurial
5248 suggests it.
5254 suggests it.
5249
5255
5250 Returns 0 if successful, 1 if nothing to recover or verify fails.
5256 Returns 0 if successful, 1 if nothing to recover or verify fails.
5251 """
5257 """
5252 if repo.recover():
5258 if repo.recover():
5253 return hg.verify(repo)
5259 return hg.verify(repo)
5254 return 1
5260 return 1
5255
5261
5256 @command('^remove|rm',
5262 @command('^remove|rm',
5257 [('A', 'after', None, _('record delete for missing files')),
5263 [('A', 'after', None, _('record delete for missing files')),
5258 ('f', 'force', None,
5264 ('f', 'force', None,
5259 _('remove (and delete) file even if added or modified')),
5265 _('remove (and delete) file even if added or modified')),
5260 ] + subrepoopts + walkopts,
5266 ] + subrepoopts + walkopts,
5261 _('[OPTION]... FILE...'),
5267 _('[OPTION]... FILE...'),
5262 inferrepo=True)
5268 inferrepo=True)
5263 def remove(ui, repo, *pats, **opts):
5269 def remove(ui, repo, *pats, **opts):
5264 """remove the specified files on the next commit
5270 """remove the specified files on the next commit
5265
5271
5266 Schedule the indicated files for removal from the current branch.
5272 Schedule the indicated files for removal from the current branch.
5267
5273
5268 This command schedules the files to be removed at the next commit.
5274 This command schedules the files to be removed at the next commit.
5269 To undo a remove before that, see :hg:`revert`. To undo added
5275 To undo a remove before that, see :hg:`revert`. To undo added
5270 files, see :hg:`forget`.
5276 files, see :hg:`forget`.
5271
5277
5272 .. container:: verbose
5278 .. container:: verbose
5273
5279
5274 -A/--after can be used to remove only files that have already
5280 -A/--after can be used to remove only files that have already
5275 been deleted, -f/--force can be used to force deletion, and -Af
5281 been deleted, -f/--force can be used to force deletion, and -Af
5276 can be used to remove files from the next revision without
5282 can be used to remove files from the next revision without
5277 deleting them from the working directory.
5283 deleting them from the working directory.
5278
5284
5279 The following table details the behavior of remove for different
5285 The following table details the behavior of remove for different
5280 file states (columns) and option combinations (rows). The file
5286 file states (columns) and option combinations (rows). The file
5281 states are Added [A], Clean [C], Modified [M] and Missing [!]
5287 states are Added [A], Clean [C], Modified [M] and Missing [!]
5282 (as reported by :hg:`status`). The actions are Warn, Remove
5288 (as reported by :hg:`status`). The actions are Warn, Remove
5283 (from branch) and Delete (from disk):
5289 (from branch) and Delete (from disk):
5284
5290
5285 ========= == == == ==
5291 ========= == == == ==
5286 opt/state A C M !
5292 opt/state A C M !
5287 ========= == == == ==
5293 ========= == == == ==
5288 none W RD W R
5294 none W RD W R
5289 -f R RD RD R
5295 -f R RD RD R
5290 -A W W W R
5296 -A W W W R
5291 -Af R R R R
5297 -Af R R R R
5292 ========= == == == ==
5298 ========= == == == ==
5293
5299
5294 Note that remove never deletes files in Added [A] state from the
5300 Note that remove never deletes files in Added [A] state from the
5295 working directory, not even if option --force is specified.
5301 working directory, not even if option --force is specified.
5296
5302
5297 Returns 0 on success, 1 if any warnings encountered.
5303 Returns 0 on success, 1 if any warnings encountered.
5298 """
5304 """
5299
5305
5300 after, force = opts.get('after'), opts.get('force')
5306 after, force = opts.get('after'), opts.get('force')
5301 if not pats and not after:
5307 if not pats and not after:
5302 raise util.Abort(_('no files specified'))
5308 raise util.Abort(_('no files specified'))
5303
5309
5304 m = scmutil.match(repo[None], pats, opts)
5310 m = scmutil.match(repo[None], pats, opts)
5305 subrepos = opts.get('subrepos')
5311 subrepos = opts.get('subrepos')
5306 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5312 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5307
5313
5308 @command('rename|move|mv',
5314 @command('rename|move|mv',
5309 [('A', 'after', None, _('record a rename that has already occurred')),
5315 [('A', 'after', None, _('record a rename that has already occurred')),
5310 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5316 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5311 ] + walkopts + dryrunopts,
5317 ] + walkopts + dryrunopts,
5312 _('[OPTION]... SOURCE... DEST'))
5318 _('[OPTION]... SOURCE... DEST'))
5313 def rename(ui, repo, *pats, **opts):
5319 def rename(ui, repo, *pats, **opts):
5314 """rename files; equivalent of copy + remove
5320 """rename files; equivalent of copy + remove
5315
5321
5316 Mark dest as copies of sources; mark sources for deletion. If dest
5322 Mark dest as copies of sources; mark sources for deletion. If dest
5317 is a directory, copies are put in that directory. If dest is a
5323 is a directory, copies are put in that directory. If dest is a
5318 file, there can only be one source.
5324 file, there can only be one source.
5319
5325
5320 By default, this command copies the contents of files as they
5326 By default, this command copies the contents of files as they
5321 exist in the working directory. If invoked with -A/--after, the
5327 exist in the working directory. If invoked with -A/--after, the
5322 operation is recorded, but no copying is performed.
5328 operation is recorded, but no copying is performed.
5323
5329
5324 This command takes effect at the next commit. To undo a rename
5330 This command takes effect at the next commit. To undo a rename
5325 before that, see :hg:`revert`.
5331 before that, see :hg:`revert`.
5326
5332
5327 Returns 0 on success, 1 if errors are encountered.
5333 Returns 0 on success, 1 if errors are encountered.
5328 """
5334 """
5329 wlock = repo.wlock(False)
5335 wlock = repo.wlock(False)
5330 try:
5336 try:
5331 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5337 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5332 finally:
5338 finally:
5333 wlock.release()
5339 wlock.release()
5334
5340
5335 @command('resolve',
5341 @command('resolve',
5336 [('a', 'all', None, _('select all unresolved files')),
5342 [('a', 'all', None, _('select all unresolved files')),
5337 ('l', 'list', None, _('list state of files needing merge')),
5343 ('l', 'list', None, _('list state of files needing merge')),
5338 ('m', 'mark', None, _('mark files as resolved')),
5344 ('m', 'mark', None, _('mark files as resolved')),
5339 ('u', 'unmark', None, _('mark files as unresolved')),
5345 ('u', 'unmark', None, _('mark files as unresolved')),
5340 ('n', 'no-status', None, _('hide status prefix'))]
5346 ('n', 'no-status', None, _('hide status prefix'))]
5341 + mergetoolopts + walkopts + formatteropts,
5347 + mergetoolopts + walkopts + formatteropts,
5342 _('[OPTION]... [FILE]...'),
5348 _('[OPTION]... [FILE]...'),
5343 inferrepo=True)
5349 inferrepo=True)
5344 def resolve(ui, repo, *pats, **opts):
5350 def resolve(ui, repo, *pats, **opts):
5345 """redo merges or set/view the merge status of files
5351 """redo merges or set/view the merge status of files
5346
5352
5347 Merges with unresolved conflicts are often the result of
5353 Merges with unresolved conflicts are often the result of
5348 non-interactive merging using the ``internal:merge`` configuration
5354 non-interactive merging using the ``internal:merge`` configuration
5349 setting, or a command-line merge tool like ``diff3``. The resolve
5355 setting, or a command-line merge tool like ``diff3``. The resolve
5350 command is used to manage the files involved in a merge, after
5356 command is used to manage the files involved in a merge, after
5351 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5357 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5352 working directory must have two parents). See :hg:`help
5358 working directory must have two parents). See :hg:`help
5353 merge-tools` for information on configuring merge tools.
5359 merge-tools` for information on configuring merge tools.
5354
5360
5355 The resolve command can be used in the following ways:
5361 The resolve command can be used in the following ways:
5356
5362
5357 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5363 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5358 files, discarding any previous merge attempts. Re-merging is not
5364 files, discarding any previous merge attempts. Re-merging is not
5359 performed for files already marked as resolved. Use ``--all/-a``
5365 performed for files already marked as resolved. Use ``--all/-a``
5360 to select all unresolved files. ``--tool`` can be used to specify
5366 to select all unresolved files. ``--tool`` can be used to specify
5361 the merge tool used for the given files. It overrides the HGMERGE
5367 the merge tool used for the given files. It overrides the HGMERGE
5362 environment variable and your configuration files. Previous file
5368 environment variable and your configuration files. Previous file
5363 contents are saved with a ``.orig`` suffix.
5369 contents are saved with a ``.orig`` suffix.
5364
5370
5365 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5371 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5366 (e.g. after having manually fixed-up the files). The default is
5372 (e.g. after having manually fixed-up the files). The default is
5367 to mark all unresolved files.
5373 to mark all unresolved files.
5368
5374
5369 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5375 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5370 default is to mark all resolved files.
5376 default is to mark all resolved files.
5371
5377
5372 - :hg:`resolve -l`: list files which had or still have conflicts.
5378 - :hg:`resolve -l`: list files which had or still have conflicts.
5373 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5379 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5374
5380
5375 Note that Mercurial will not let you commit files with unresolved
5381 Note that Mercurial will not let you commit files with unresolved
5376 merge conflicts. You must use :hg:`resolve -m ...` before you can
5382 merge conflicts. You must use :hg:`resolve -m ...` before you can
5377 commit after a conflicting merge.
5383 commit after a conflicting merge.
5378
5384
5379 Returns 0 on success, 1 if any files fail a resolve attempt.
5385 Returns 0 on success, 1 if any files fail a resolve attempt.
5380 """
5386 """
5381
5387
5382 all, mark, unmark, show, nostatus = \
5388 all, mark, unmark, show, nostatus = \
5383 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5389 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5384
5390
5385 if (show and (mark or unmark)) or (mark and unmark):
5391 if (show and (mark or unmark)) or (mark and unmark):
5386 raise util.Abort(_("too many options specified"))
5392 raise util.Abort(_("too many options specified"))
5387 if pats and all:
5393 if pats and all:
5388 raise util.Abort(_("can't specify --all and patterns"))
5394 raise util.Abort(_("can't specify --all and patterns"))
5389 if not (all or pats or show or mark or unmark):
5395 if not (all or pats or show or mark or unmark):
5390 raise util.Abort(_('no files or directories specified'),
5396 raise util.Abort(_('no files or directories specified'),
5391 hint=('use --all to remerge all files'))
5397 hint=('use --all to remerge all files'))
5392
5398
5393 if show:
5399 if show:
5394 fm = ui.formatter('resolve', opts)
5400 fm = ui.formatter('resolve', opts)
5395 ms = mergemod.mergestate(repo)
5401 ms = mergemod.mergestate(repo)
5396 m = scmutil.match(repo[None], pats, opts)
5402 m = scmutil.match(repo[None], pats, opts)
5397 for f in ms:
5403 for f in ms:
5398 if not m(f):
5404 if not m(f):
5399 continue
5405 continue
5400 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5406 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5401 fm.startitem()
5407 fm.startitem()
5402 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5408 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5403 fm.write('path', '%s\n', f, label=l)
5409 fm.write('path', '%s\n', f, label=l)
5404 fm.end()
5410 fm.end()
5405 return 0
5411 return 0
5406
5412
5407 wlock = repo.wlock()
5413 wlock = repo.wlock()
5408 try:
5414 try:
5409 ms = mergemod.mergestate(repo)
5415 ms = mergemod.mergestate(repo)
5410
5416
5411 if not (ms.active() or repo.dirstate.p2() != nullid):
5417 if not (ms.active() or repo.dirstate.p2() != nullid):
5412 raise util.Abort(
5418 raise util.Abort(
5413 _('resolve command not applicable when not merging'))
5419 _('resolve command not applicable when not merging'))
5414
5420
5415 m = scmutil.match(repo[None], pats, opts)
5421 m = scmutil.match(repo[None], pats, opts)
5416 ret = 0
5422 ret = 0
5417 didwork = False
5423 didwork = False
5418
5424
5419 for f in ms:
5425 for f in ms:
5420 if not m(f):
5426 if not m(f):
5421 continue
5427 continue
5422
5428
5423 didwork = True
5429 didwork = True
5424
5430
5425 if mark:
5431 if mark:
5426 ms.mark(f, "r")
5432 ms.mark(f, "r")
5427 elif unmark:
5433 elif unmark:
5428 ms.mark(f, "u")
5434 ms.mark(f, "u")
5429 else:
5435 else:
5430 wctx = repo[None]
5436 wctx = repo[None]
5431
5437
5432 # backup pre-resolve (merge uses .orig for its own purposes)
5438 # backup pre-resolve (merge uses .orig for its own purposes)
5433 a = repo.wjoin(f)
5439 a = repo.wjoin(f)
5434 util.copyfile(a, a + ".resolve")
5440 util.copyfile(a, a + ".resolve")
5435
5441
5436 try:
5442 try:
5437 # resolve file
5443 # resolve file
5438 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5444 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5439 'resolve')
5445 'resolve')
5440 if ms.resolve(f, wctx):
5446 if ms.resolve(f, wctx):
5441 ret = 1
5447 ret = 1
5442 finally:
5448 finally:
5443 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5449 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5444 ms.commit()
5450 ms.commit()
5445
5451
5446 # replace filemerge's .orig file with our resolve file
5452 # replace filemerge's .orig file with our resolve file
5447 util.rename(a + ".resolve", a + ".orig")
5453 util.rename(a + ".resolve", a + ".orig")
5448
5454
5449 ms.commit()
5455 ms.commit()
5450
5456
5451 if not didwork and pats:
5457 if not didwork and pats:
5452 ui.warn(_("arguments do not match paths that need resolving\n"))
5458 ui.warn(_("arguments do not match paths that need resolving\n"))
5453
5459
5454 finally:
5460 finally:
5455 wlock.release()
5461 wlock.release()
5456
5462
5457 # Nudge users into finishing an unfinished operation
5463 # Nudge users into finishing an unfinished operation
5458 if not list(ms.unresolved()):
5464 if not list(ms.unresolved()):
5459 ui.status(_('(no more unresolved files)\n'))
5465 ui.status(_('(no more unresolved files)\n'))
5460
5466
5461 return ret
5467 return ret
5462
5468
5463 @command('revert',
5469 @command('revert',
5464 [('a', 'all', None, _('revert all changes when no arguments given')),
5470 [('a', 'all', None, _('revert all changes when no arguments given')),
5465 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5471 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5466 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5472 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5467 ('C', 'no-backup', None, _('do not save backup copies of files')),
5473 ('C', 'no-backup', None, _('do not save backup copies of files')),
5468 ('i', 'interactive', None,
5474 ('i', 'interactive', None,
5469 _('interactively select the changes (EXPERIMENTAL)')),
5475 _('interactively select the changes (EXPERIMENTAL)')),
5470 ] + walkopts + dryrunopts,
5476 ] + walkopts + dryrunopts,
5471 _('[OPTION]... [-r REV] [NAME]...'))
5477 _('[OPTION]... [-r REV] [NAME]...'))
5472 def revert(ui, repo, *pats, **opts):
5478 def revert(ui, repo, *pats, **opts):
5473 """restore files to their checkout state
5479 """restore files to their checkout state
5474
5480
5475 .. note::
5481 .. note::
5476
5482
5477 To check out earlier revisions, you should use :hg:`update REV`.
5483 To check out earlier revisions, you should use :hg:`update REV`.
5478 To cancel an uncommitted merge (and lose your changes),
5484 To cancel an uncommitted merge (and lose your changes),
5479 use :hg:`update --clean .`.
5485 use :hg:`update --clean .`.
5480
5486
5481 With no revision specified, revert the specified files or directories
5487 With no revision specified, revert the specified files or directories
5482 to the contents they had in the parent of the working directory.
5488 to the contents they had in the parent of the working directory.
5483 This restores the contents of files to an unmodified
5489 This restores the contents of files to an unmodified
5484 state and unschedules adds, removes, copies, and renames. If the
5490 state and unschedules adds, removes, copies, and renames. If the
5485 working directory has two parents, you must explicitly specify a
5491 working directory has two parents, you must explicitly specify a
5486 revision.
5492 revision.
5487
5493
5488 Using the -r/--rev or -d/--date options, revert the given files or
5494 Using the -r/--rev or -d/--date options, revert the given files or
5489 directories to their states as of a specific revision. Because
5495 directories to their states as of a specific revision. Because
5490 revert does not change the working directory parents, this will
5496 revert does not change the working directory parents, this will
5491 cause these files to appear modified. This can be helpful to "back
5497 cause these files to appear modified. This can be helpful to "back
5492 out" some or all of an earlier change. See :hg:`backout` for a
5498 out" some or all of an earlier change. See :hg:`backout` for a
5493 related method.
5499 related method.
5494
5500
5495 Modified files are saved with a .orig suffix before reverting.
5501 Modified files are saved with a .orig suffix before reverting.
5496 To disable these backups, use --no-backup.
5502 To disable these backups, use --no-backup.
5497
5503
5498 See :hg:`help dates` for a list of formats valid for -d/--date.
5504 See :hg:`help dates` for a list of formats valid for -d/--date.
5499
5505
5500 Returns 0 on success.
5506 Returns 0 on success.
5501 """
5507 """
5502
5508
5503 if opts.get("date"):
5509 if opts.get("date"):
5504 if opts.get("rev"):
5510 if opts.get("rev"):
5505 raise util.Abort(_("you can't specify a revision and a date"))
5511 raise util.Abort(_("you can't specify a revision and a date"))
5506 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5512 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5507
5513
5508 parent, p2 = repo.dirstate.parents()
5514 parent, p2 = repo.dirstate.parents()
5509 if not opts.get('rev') and p2 != nullid:
5515 if not opts.get('rev') and p2 != nullid:
5510 # revert after merge is a trap for new users (issue2915)
5516 # revert after merge is a trap for new users (issue2915)
5511 raise util.Abort(_('uncommitted merge with no revision specified'),
5517 raise util.Abort(_('uncommitted merge with no revision specified'),
5512 hint=_('use "hg update" or see "hg help revert"'))
5518 hint=_('use "hg update" or see "hg help revert"'))
5513
5519
5514 ctx = scmutil.revsingle(repo, opts.get('rev'))
5520 ctx = scmutil.revsingle(repo, opts.get('rev'))
5515
5521
5516 if (not (pats or opts.get('include') or opts.get('exclude') or
5522 if (not (pats or opts.get('include') or opts.get('exclude') or
5517 opts.get('all') or opts.get('interactive'))):
5523 opts.get('all') or opts.get('interactive'))):
5518 msg = _("no files or directories specified")
5524 msg = _("no files or directories specified")
5519 if p2 != nullid:
5525 if p2 != nullid:
5520 hint = _("uncommitted merge, use --all to discard all changes,"
5526 hint = _("uncommitted merge, use --all to discard all changes,"
5521 " or 'hg update -C .' to abort the merge")
5527 " or 'hg update -C .' to abort the merge")
5522 raise util.Abort(msg, hint=hint)
5528 raise util.Abort(msg, hint=hint)
5523 dirty = util.any(repo.status())
5529 dirty = util.any(repo.status())
5524 node = ctx.node()
5530 node = ctx.node()
5525 if node != parent:
5531 if node != parent:
5526 if dirty:
5532 if dirty:
5527 hint = _("uncommitted changes, use --all to discard all"
5533 hint = _("uncommitted changes, use --all to discard all"
5528 " changes, or 'hg update %s' to update") % ctx.rev()
5534 " changes, or 'hg update %s' to update") % ctx.rev()
5529 else:
5535 else:
5530 hint = _("use --all to revert all files,"
5536 hint = _("use --all to revert all files,"
5531 " or 'hg update %s' to update") % ctx.rev()
5537 " or 'hg update %s' to update") % ctx.rev()
5532 elif dirty:
5538 elif dirty:
5533 hint = _("uncommitted changes, use --all to discard all changes")
5539 hint = _("uncommitted changes, use --all to discard all changes")
5534 else:
5540 else:
5535 hint = _("use --all to revert all files")
5541 hint = _("use --all to revert all files")
5536 raise util.Abort(msg, hint=hint)
5542 raise util.Abort(msg, hint=hint)
5537
5543
5538 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5544 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5539
5545
5540 @command('rollback', dryrunopts +
5546 @command('rollback', dryrunopts +
5541 [('f', 'force', False, _('ignore safety measures'))])
5547 [('f', 'force', False, _('ignore safety measures'))])
5542 def rollback(ui, repo, **opts):
5548 def rollback(ui, repo, **opts):
5543 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5549 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5544
5550
5545 Please use :hg:`commit --amend` instead of rollback to correct
5551 Please use :hg:`commit --amend` instead of rollback to correct
5546 mistakes in the last commit.
5552 mistakes in the last commit.
5547
5553
5548 This command should be used with care. There is only one level of
5554 This command should be used with care. There is only one level of
5549 rollback, and there is no way to undo a rollback. It will also
5555 rollback, and there is no way to undo a rollback. It will also
5550 restore the dirstate at the time of the last transaction, losing
5556 restore the dirstate at the time of the last transaction, losing
5551 any dirstate changes since that time. This command does not alter
5557 any dirstate changes since that time. This command does not alter
5552 the working directory.
5558 the working directory.
5553
5559
5554 Transactions are used to encapsulate the effects of all commands
5560 Transactions are used to encapsulate the effects of all commands
5555 that create new changesets or propagate existing changesets into a
5561 that create new changesets or propagate existing changesets into a
5556 repository.
5562 repository.
5557
5563
5558 .. container:: verbose
5564 .. container:: verbose
5559
5565
5560 For example, the following commands are transactional, and their
5566 For example, the following commands are transactional, and their
5561 effects can be rolled back:
5567 effects can be rolled back:
5562
5568
5563 - commit
5569 - commit
5564 - import
5570 - import
5565 - pull
5571 - pull
5566 - push (with this repository as the destination)
5572 - push (with this repository as the destination)
5567 - unbundle
5573 - unbundle
5568
5574
5569 To avoid permanent data loss, rollback will refuse to rollback a
5575 To avoid permanent data loss, rollback will refuse to rollback a
5570 commit transaction if it isn't checked out. Use --force to
5576 commit transaction if it isn't checked out. Use --force to
5571 override this protection.
5577 override this protection.
5572
5578
5573 This command is not intended for use on public repositories. Once
5579 This command is not intended for use on public repositories. Once
5574 changes are visible for pull by other users, rolling a transaction
5580 changes are visible for pull by other users, rolling a transaction
5575 back locally is ineffective (someone else may already have pulled
5581 back locally is ineffective (someone else may already have pulled
5576 the changes). Furthermore, a race is possible with readers of the
5582 the changes). Furthermore, a race is possible with readers of the
5577 repository; for example an in-progress pull from the repository
5583 repository; for example an in-progress pull from the repository
5578 may fail if a rollback is performed.
5584 may fail if a rollback is performed.
5579
5585
5580 Returns 0 on success, 1 if no rollback data is available.
5586 Returns 0 on success, 1 if no rollback data is available.
5581 """
5587 """
5582 return repo.rollback(dryrun=opts.get('dry_run'),
5588 return repo.rollback(dryrun=opts.get('dry_run'),
5583 force=opts.get('force'))
5589 force=opts.get('force'))
5584
5590
5585 @command('root', [])
5591 @command('root', [])
5586 def root(ui, repo):
5592 def root(ui, repo):
5587 """print the root (top) of the current working directory
5593 """print the root (top) of the current working directory
5588
5594
5589 Print the root directory of the current repository.
5595 Print the root directory of the current repository.
5590
5596
5591 Returns 0 on success.
5597 Returns 0 on success.
5592 """
5598 """
5593 ui.write(repo.root + "\n")
5599 ui.write(repo.root + "\n")
5594
5600
5595 @command('^serve',
5601 @command('^serve',
5596 [('A', 'accesslog', '', _('name of access log file to write to'),
5602 [('A', 'accesslog', '', _('name of access log file to write to'),
5597 _('FILE')),
5603 _('FILE')),
5598 ('d', 'daemon', None, _('run server in background')),
5604 ('d', 'daemon', None, _('run server in background')),
5599 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5605 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5600 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5606 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5601 # use string type, then we can check if something was passed
5607 # use string type, then we can check if something was passed
5602 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5608 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5603 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5609 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5604 _('ADDR')),
5610 _('ADDR')),
5605 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5611 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5606 _('PREFIX')),
5612 _('PREFIX')),
5607 ('n', 'name', '',
5613 ('n', 'name', '',
5608 _('name to show in web pages (default: working directory)'), _('NAME')),
5614 _('name to show in web pages (default: working directory)'), _('NAME')),
5609 ('', 'web-conf', '',
5615 ('', 'web-conf', '',
5610 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5616 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5611 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5617 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5612 _('FILE')),
5618 _('FILE')),
5613 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5619 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5614 ('', 'stdio', None, _('for remote clients')),
5620 ('', 'stdio', None, _('for remote clients')),
5615 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5621 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5616 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5622 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5617 ('', 'style', '', _('template style to use'), _('STYLE')),
5623 ('', 'style', '', _('template style to use'), _('STYLE')),
5618 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5624 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5619 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5625 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5620 _('[OPTION]...'),
5626 _('[OPTION]...'),
5621 optionalrepo=True)
5627 optionalrepo=True)
5622 def serve(ui, repo, **opts):
5628 def serve(ui, repo, **opts):
5623 """start stand-alone webserver
5629 """start stand-alone webserver
5624
5630
5625 Start a local HTTP repository browser and pull server. You can use
5631 Start a local HTTP repository browser and pull server. You can use
5626 this for ad-hoc sharing and browsing of repositories. It is
5632 this for ad-hoc sharing and browsing of repositories. It is
5627 recommended to use a real web server to serve a repository for
5633 recommended to use a real web server to serve a repository for
5628 longer periods of time.
5634 longer periods of time.
5629
5635
5630 Please note that the server does not implement access control.
5636 Please note that the server does not implement access control.
5631 This means that, by default, anybody can read from the server and
5637 This means that, by default, anybody can read from the server and
5632 nobody can write to it by default. Set the ``web.allow_push``
5638 nobody can write to it by default. Set the ``web.allow_push``
5633 option to ``*`` to allow everybody to push to the server. You
5639 option to ``*`` to allow everybody to push to the server. You
5634 should use a real web server if you need to authenticate users.
5640 should use a real web server if you need to authenticate users.
5635
5641
5636 By default, the server logs accesses to stdout and errors to
5642 By default, the server logs accesses to stdout and errors to
5637 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5643 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5638 files.
5644 files.
5639
5645
5640 To have the server choose a free port number to listen on, specify
5646 To have the server choose a free port number to listen on, specify
5641 a port number of 0; in this case, the server will print the port
5647 a port number of 0; in this case, the server will print the port
5642 number it uses.
5648 number it uses.
5643
5649
5644 Returns 0 on success.
5650 Returns 0 on success.
5645 """
5651 """
5646
5652
5647 if opts["stdio"] and opts["cmdserver"]:
5653 if opts["stdio"] and opts["cmdserver"]:
5648 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5654 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5649
5655
5650 if opts["stdio"]:
5656 if opts["stdio"]:
5651 if repo is None:
5657 if repo is None:
5652 raise error.RepoError(_("there is no Mercurial repository here"
5658 raise error.RepoError(_("there is no Mercurial repository here"
5653 " (.hg not found)"))
5659 " (.hg not found)"))
5654 s = sshserver.sshserver(ui, repo)
5660 s = sshserver.sshserver(ui, repo)
5655 s.serve_forever()
5661 s.serve_forever()
5656
5662
5657 if opts["cmdserver"]:
5663 if opts["cmdserver"]:
5658 service = commandserver.createservice(ui, repo, opts)
5664 service = commandserver.createservice(ui, repo, opts)
5659 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5665 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5660
5666
5661 # this way we can check if something was given in the command-line
5667 # this way we can check if something was given in the command-line
5662 if opts.get('port'):
5668 if opts.get('port'):
5663 opts['port'] = util.getport(opts.get('port'))
5669 opts['port'] = util.getport(opts.get('port'))
5664
5670
5665 if repo:
5671 if repo:
5666 baseui = repo.baseui
5672 baseui = repo.baseui
5667 else:
5673 else:
5668 baseui = ui
5674 baseui = ui
5669 optlist = ("name templates style address port prefix ipv6"
5675 optlist = ("name templates style address port prefix ipv6"
5670 " accesslog errorlog certificate encoding")
5676 " accesslog errorlog certificate encoding")
5671 for o in optlist.split():
5677 for o in optlist.split():
5672 val = opts.get(o, '')
5678 val = opts.get(o, '')
5673 if val in (None, ''): # should check against default options instead
5679 if val in (None, ''): # should check against default options instead
5674 continue
5680 continue
5675 baseui.setconfig("web", o, val, 'serve')
5681 baseui.setconfig("web", o, val, 'serve')
5676 if repo and repo.ui != baseui:
5682 if repo and repo.ui != baseui:
5677 repo.ui.setconfig("web", o, val, 'serve')
5683 repo.ui.setconfig("web", o, val, 'serve')
5678
5684
5679 o = opts.get('web_conf') or opts.get('webdir_conf')
5685 o = opts.get('web_conf') or opts.get('webdir_conf')
5680 if not o:
5686 if not o:
5681 if not repo:
5687 if not repo:
5682 raise error.RepoError(_("there is no Mercurial repository"
5688 raise error.RepoError(_("there is no Mercurial repository"
5683 " here (.hg not found)"))
5689 " here (.hg not found)"))
5684 o = repo
5690 o = repo
5685
5691
5686 app = hgweb.hgweb(o, baseui=baseui)
5692 app = hgweb.hgweb(o, baseui=baseui)
5687 service = httpservice(ui, app, opts)
5693 service = httpservice(ui, app, opts)
5688 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5694 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5689
5695
5690 class httpservice(object):
5696 class httpservice(object):
5691 def __init__(self, ui, app, opts):
5697 def __init__(self, ui, app, opts):
5692 self.ui = ui
5698 self.ui = ui
5693 self.app = app
5699 self.app = app
5694 self.opts = opts
5700 self.opts = opts
5695
5701
5696 def init(self):
5702 def init(self):
5697 util.setsignalhandler()
5703 util.setsignalhandler()
5698 self.httpd = hgweb_server.create_server(self.ui, self.app)
5704 self.httpd = hgweb_server.create_server(self.ui, self.app)
5699
5705
5700 if self.opts['port'] and not self.ui.verbose:
5706 if self.opts['port'] and not self.ui.verbose:
5701 return
5707 return
5702
5708
5703 if self.httpd.prefix:
5709 if self.httpd.prefix:
5704 prefix = self.httpd.prefix.strip('/') + '/'
5710 prefix = self.httpd.prefix.strip('/') + '/'
5705 else:
5711 else:
5706 prefix = ''
5712 prefix = ''
5707
5713
5708 port = ':%d' % self.httpd.port
5714 port = ':%d' % self.httpd.port
5709 if port == ':80':
5715 if port == ':80':
5710 port = ''
5716 port = ''
5711
5717
5712 bindaddr = self.httpd.addr
5718 bindaddr = self.httpd.addr
5713 if bindaddr == '0.0.0.0':
5719 if bindaddr == '0.0.0.0':
5714 bindaddr = '*'
5720 bindaddr = '*'
5715 elif ':' in bindaddr: # IPv6
5721 elif ':' in bindaddr: # IPv6
5716 bindaddr = '[%s]' % bindaddr
5722 bindaddr = '[%s]' % bindaddr
5717
5723
5718 fqaddr = self.httpd.fqaddr
5724 fqaddr = self.httpd.fqaddr
5719 if ':' in fqaddr:
5725 if ':' in fqaddr:
5720 fqaddr = '[%s]' % fqaddr
5726 fqaddr = '[%s]' % fqaddr
5721 if self.opts['port']:
5727 if self.opts['port']:
5722 write = self.ui.status
5728 write = self.ui.status
5723 else:
5729 else:
5724 write = self.ui.write
5730 write = self.ui.write
5725 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5731 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5726 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5732 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5727 self.ui.flush() # avoid buffering of status message
5733 self.ui.flush() # avoid buffering of status message
5728
5734
5729 def run(self):
5735 def run(self):
5730 self.httpd.serve_forever()
5736 self.httpd.serve_forever()
5731
5737
5732
5738
5733 @command('^status|st',
5739 @command('^status|st',
5734 [('A', 'all', None, _('show status of all files')),
5740 [('A', 'all', None, _('show status of all files')),
5735 ('m', 'modified', None, _('show only modified files')),
5741 ('m', 'modified', None, _('show only modified files')),
5736 ('a', 'added', None, _('show only added files')),
5742 ('a', 'added', None, _('show only added files')),
5737 ('r', 'removed', None, _('show only removed files')),
5743 ('r', 'removed', None, _('show only removed files')),
5738 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5744 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5739 ('c', 'clean', None, _('show only files without changes')),
5745 ('c', 'clean', None, _('show only files without changes')),
5740 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5746 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5741 ('i', 'ignored', None, _('show only ignored files')),
5747 ('i', 'ignored', None, _('show only ignored files')),
5742 ('n', 'no-status', None, _('hide status prefix')),
5748 ('n', 'no-status', None, _('hide status prefix')),
5743 ('C', 'copies', None, _('show source of copied files')),
5749 ('C', 'copies', None, _('show source of copied files')),
5744 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5750 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5745 ('', 'rev', [], _('show difference from revision'), _('REV')),
5751 ('', 'rev', [], _('show difference from revision'), _('REV')),
5746 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5752 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5747 ] + walkopts + subrepoopts + formatteropts,
5753 ] + walkopts + subrepoopts + formatteropts,
5748 _('[OPTION]... [FILE]...'),
5754 _('[OPTION]... [FILE]...'),
5749 inferrepo=True)
5755 inferrepo=True)
5750 def status(ui, repo, *pats, **opts):
5756 def status(ui, repo, *pats, **opts):
5751 """show changed files in the working directory
5757 """show changed files in the working directory
5752
5758
5753 Show status of files in the repository. If names are given, only
5759 Show status of files in the repository. If names are given, only
5754 files that match are shown. Files that are clean or ignored or
5760 files that match are shown. Files that are clean or ignored or
5755 the source of a copy/move operation, are not listed unless
5761 the source of a copy/move operation, are not listed unless
5756 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5762 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5757 Unless options described with "show only ..." are given, the
5763 Unless options described with "show only ..." are given, the
5758 options -mardu are used.
5764 options -mardu are used.
5759
5765
5760 Option -q/--quiet hides untracked (unknown and ignored) files
5766 Option -q/--quiet hides untracked (unknown and ignored) files
5761 unless explicitly requested with -u/--unknown or -i/--ignored.
5767 unless explicitly requested with -u/--unknown or -i/--ignored.
5762
5768
5763 .. note::
5769 .. note::
5764
5770
5765 status may appear to disagree with diff if permissions have
5771 status may appear to disagree with diff if permissions have
5766 changed or a merge has occurred. The standard diff format does
5772 changed or a merge has occurred. The standard diff format does
5767 not report permission changes and diff only reports changes
5773 not report permission changes and diff only reports changes
5768 relative to one merge parent.
5774 relative to one merge parent.
5769
5775
5770 If one revision is given, it is used as the base revision.
5776 If one revision is given, it is used as the base revision.
5771 If two revisions are given, the differences between them are
5777 If two revisions are given, the differences between them are
5772 shown. The --change option can also be used as a shortcut to list
5778 shown. The --change option can also be used as a shortcut to list
5773 the changed files of a revision from its first parent.
5779 the changed files of a revision from its first parent.
5774
5780
5775 The codes used to show the status of files are::
5781 The codes used to show the status of files are::
5776
5782
5777 M = modified
5783 M = modified
5778 A = added
5784 A = added
5779 R = removed
5785 R = removed
5780 C = clean
5786 C = clean
5781 ! = missing (deleted by non-hg command, but still tracked)
5787 ! = missing (deleted by non-hg command, but still tracked)
5782 ? = not tracked
5788 ? = not tracked
5783 I = ignored
5789 I = ignored
5784 = origin of the previous file (with --copies)
5790 = origin of the previous file (with --copies)
5785
5791
5786 .. container:: verbose
5792 .. container:: verbose
5787
5793
5788 Examples:
5794 Examples:
5789
5795
5790 - show changes in the working directory relative to a
5796 - show changes in the working directory relative to a
5791 changeset::
5797 changeset::
5792
5798
5793 hg status --rev 9353
5799 hg status --rev 9353
5794
5800
5795 - show changes in the working directory relative to the
5801 - show changes in the working directory relative to the
5796 current directory (see :hg:`help patterns` for more information)::
5802 current directory (see :hg:`help patterns` for more information)::
5797
5803
5798 hg status re:
5804 hg status re:
5799
5805
5800 - show all changes including copies in an existing changeset::
5806 - show all changes including copies in an existing changeset::
5801
5807
5802 hg status --copies --change 9353
5808 hg status --copies --change 9353
5803
5809
5804 - get a NUL separated list of added files, suitable for xargs::
5810 - get a NUL separated list of added files, suitable for xargs::
5805
5811
5806 hg status -an0
5812 hg status -an0
5807
5813
5808 Returns 0 on success.
5814 Returns 0 on success.
5809 """
5815 """
5810
5816
5811 revs = opts.get('rev')
5817 revs = opts.get('rev')
5812 change = opts.get('change')
5818 change = opts.get('change')
5813
5819
5814 if revs and change:
5820 if revs and change:
5815 msg = _('cannot specify --rev and --change at the same time')
5821 msg = _('cannot specify --rev and --change at the same time')
5816 raise util.Abort(msg)
5822 raise util.Abort(msg)
5817 elif change:
5823 elif change:
5818 node2 = scmutil.revsingle(repo, change, None).node()
5824 node2 = scmutil.revsingle(repo, change, None).node()
5819 node1 = repo[node2].p1().node()
5825 node1 = repo[node2].p1().node()
5820 else:
5826 else:
5821 node1, node2 = scmutil.revpair(repo, revs)
5827 node1, node2 = scmutil.revpair(repo, revs)
5822
5828
5823 if pats:
5829 if pats:
5824 cwd = repo.getcwd()
5830 cwd = repo.getcwd()
5825 else:
5831 else:
5826 cwd = ''
5832 cwd = ''
5827
5833
5828 if opts.get('print0'):
5834 if opts.get('print0'):
5829 end = '\0'
5835 end = '\0'
5830 else:
5836 else:
5831 end = '\n'
5837 end = '\n'
5832 copy = {}
5838 copy = {}
5833 states = 'modified added removed deleted unknown ignored clean'.split()
5839 states = 'modified added removed deleted unknown ignored clean'.split()
5834 show = [k for k in states if opts.get(k)]
5840 show = [k for k in states if opts.get(k)]
5835 if opts.get('all'):
5841 if opts.get('all'):
5836 show += ui.quiet and (states[:4] + ['clean']) or states
5842 show += ui.quiet and (states[:4] + ['clean']) or states
5837 if not show:
5843 if not show:
5838 if ui.quiet:
5844 if ui.quiet:
5839 show = states[:4]
5845 show = states[:4]
5840 else:
5846 else:
5841 show = states[:5]
5847 show = states[:5]
5842
5848
5843 m = scmutil.match(repo[node2], pats, opts)
5849 m = scmutil.match(repo[node2], pats, opts)
5844 stat = repo.status(node1, node2, m,
5850 stat = repo.status(node1, node2, m,
5845 'ignored' in show, 'clean' in show, 'unknown' in show,
5851 'ignored' in show, 'clean' in show, 'unknown' in show,
5846 opts.get('subrepos'))
5852 opts.get('subrepos'))
5847 changestates = zip(states, 'MAR!?IC', stat)
5853 changestates = zip(states, 'MAR!?IC', stat)
5848
5854
5849 if (opts.get('all') or opts.get('copies')
5855 if (opts.get('all') or opts.get('copies')
5850 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5856 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5851 copy = copies.pathcopies(repo[node1], repo[node2], m)
5857 copy = copies.pathcopies(repo[node1], repo[node2], m)
5852
5858
5853 fm = ui.formatter('status', opts)
5859 fm = ui.formatter('status', opts)
5854 fmt = '%s' + end
5860 fmt = '%s' + end
5855 showchar = not opts.get('no_status')
5861 showchar = not opts.get('no_status')
5856
5862
5857 for state, char, files in changestates:
5863 for state, char, files in changestates:
5858 if state in show:
5864 if state in show:
5859 label = 'status.' + state
5865 label = 'status.' + state
5860 for f in files:
5866 for f in files:
5861 fm.startitem()
5867 fm.startitem()
5862 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5868 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5863 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5869 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5864 if f in copy:
5870 if f in copy:
5865 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5871 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5866 label='status.copied')
5872 label='status.copied')
5867 fm.end()
5873 fm.end()
5868
5874
5869 @command('^summary|sum',
5875 @command('^summary|sum',
5870 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5876 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5871 def summary(ui, repo, **opts):
5877 def summary(ui, repo, **opts):
5872 """summarize working directory state
5878 """summarize working directory state
5873
5879
5874 This generates a brief summary of the working directory state,
5880 This generates a brief summary of the working directory state,
5875 including parents, branch, commit status, and available updates.
5881 including parents, branch, commit status, and available updates.
5876
5882
5877 With the --remote option, this will check the default paths for
5883 With the --remote option, this will check the default paths for
5878 incoming and outgoing changes. This can be time-consuming.
5884 incoming and outgoing changes. This can be time-consuming.
5879
5885
5880 Returns 0 on success.
5886 Returns 0 on success.
5881 """
5887 """
5882
5888
5883 ctx = repo[None]
5889 ctx = repo[None]
5884 parents = ctx.parents()
5890 parents = ctx.parents()
5885 pnode = parents[0].node()
5891 pnode = parents[0].node()
5886 marks = []
5892 marks = []
5887
5893
5888 for p in parents:
5894 for p in parents:
5889 # label with log.changeset (instead of log.parent) since this
5895 # label with log.changeset (instead of log.parent) since this
5890 # shows a working directory parent *changeset*:
5896 # shows a working directory parent *changeset*:
5891 # i18n: column positioning for "hg summary"
5897 # i18n: column positioning for "hg summary"
5892 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5898 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5893 label='log.changeset changeset.%s' % p.phasestr())
5899 label='log.changeset changeset.%s' % p.phasestr())
5894 ui.write(' '.join(p.tags()), label='log.tag')
5900 ui.write(' '.join(p.tags()), label='log.tag')
5895 if p.bookmarks():
5901 if p.bookmarks():
5896 marks.extend(p.bookmarks())
5902 marks.extend(p.bookmarks())
5897 if p.rev() == -1:
5903 if p.rev() == -1:
5898 if not len(repo):
5904 if not len(repo):
5899 ui.write(_(' (empty repository)'))
5905 ui.write(_(' (empty repository)'))
5900 else:
5906 else:
5901 ui.write(_(' (no revision checked out)'))
5907 ui.write(_(' (no revision checked out)'))
5902 ui.write('\n')
5908 ui.write('\n')
5903 if p.description():
5909 if p.description():
5904 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5910 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5905 label='log.summary')
5911 label='log.summary')
5906
5912
5907 branch = ctx.branch()
5913 branch = ctx.branch()
5908 bheads = repo.branchheads(branch)
5914 bheads = repo.branchheads(branch)
5909 # i18n: column positioning for "hg summary"
5915 # i18n: column positioning for "hg summary"
5910 m = _('branch: %s\n') % branch
5916 m = _('branch: %s\n') % branch
5911 if branch != 'default':
5917 if branch != 'default':
5912 ui.write(m, label='log.branch')
5918 ui.write(m, label='log.branch')
5913 else:
5919 else:
5914 ui.status(m, label='log.branch')
5920 ui.status(m, label='log.branch')
5915
5921
5916 if marks:
5922 if marks:
5917 current = repo._bookmarkcurrent
5923 current = repo._bookmarkcurrent
5918 # i18n: column positioning for "hg summary"
5924 # i18n: column positioning for "hg summary"
5919 ui.write(_('bookmarks:'), label='log.bookmark')
5925 ui.write(_('bookmarks:'), label='log.bookmark')
5920 if current is not None:
5926 if current is not None:
5921 if current in marks:
5927 if current in marks:
5922 ui.write(' *' + current, label='bookmarks.current')
5928 ui.write(' *' + current, label='bookmarks.current')
5923 marks.remove(current)
5929 marks.remove(current)
5924 else:
5930 else:
5925 ui.write(' [%s]' % current, label='bookmarks.current')
5931 ui.write(' [%s]' % current, label='bookmarks.current')
5926 for m in marks:
5932 for m in marks:
5927 ui.write(' ' + m, label='log.bookmark')
5933 ui.write(' ' + m, label='log.bookmark')
5928 ui.write('\n', label='log.bookmark')
5934 ui.write('\n', label='log.bookmark')
5929
5935
5930 status = repo.status(unknown=True)
5936 status = repo.status(unknown=True)
5931
5937
5932 c = repo.dirstate.copies()
5938 c = repo.dirstate.copies()
5933 copied, renamed = [], []
5939 copied, renamed = [], []
5934 for d, s in c.iteritems():
5940 for d, s in c.iteritems():
5935 if s in status.removed:
5941 if s in status.removed:
5936 status.removed.remove(s)
5942 status.removed.remove(s)
5937 renamed.append(d)
5943 renamed.append(d)
5938 else:
5944 else:
5939 copied.append(d)
5945 copied.append(d)
5940 if d in status.added:
5946 if d in status.added:
5941 status.added.remove(d)
5947 status.added.remove(d)
5942
5948
5943 ms = mergemod.mergestate(repo)
5949 ms = mergemod.mergestate(repo)
5944 unresolved = [f for f in ms if ms[f] == 'u']
5950 unresolved = [f for f in ms if ms[f] == 'u']
5945
5951
5946 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5952 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5947
5953
5948 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5954 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5949 (ui.label(_('%d added'), 'status.added'), status.added),
5955 (ui.label(_('%d added'), 'status.added'), status.added),
5950 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5956 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5951 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5957 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5952 (ui.label(_('%d copied'), 'status.copied'), copied),
5958 (ui.label(_('%d copied'), 'status.copied'), copied),
5953 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5959 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5954 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5960 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5955 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5961 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5956 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5962 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5957 t = []
5963 t = []
5958 for l, s in labels:
5964 for l, s in labels:
5959 if s:
5965 if s:
5960 t.append(l % len(s))
5966 t.append(l % len(s))
5961
5967
5962 t = ', '.join(t)
5968 t = ', '.join(t)
5963 cleanworkdir = False
5969 cleanworkdir = False
5964
5970
5965 if repo.vfs.exists('updatestate'):
5971 if repo.vfs.exists('updatestate'):
5966 t += _(' (interrupted update)')
5972 t += _(' (interrupted update)')
5967 elif len(parents) > 1:
5973 elif len(parents) > 1:
5968 t += _(' (merge)')
5974 t += _(' (merge)')
5969 elif branch != parents[0].branch():
5975 elif branch != parents[0].branch():
5970 t += _(' (new branch)')
5976 t += _(' (new branch)')
5971 elif (parents[0].closesbranch() and
5977 elif (parents[0].closesbranch() and
5972 pnode in repo.branchheads(branch, closed=True)):
5978 pnode in repo.branchheads(branch, closed=True)):
5973 t += _(' (head closed)')
5979 t += _(' (head closed)')
5974 elif not (status.modified or status.added or status.removed or renamed or
5980 elif not (status.modified or status.added or status.removed or renamed or
5975 copied or subs):
5981 copied or subs):
5976 t += _(' (clean)')
5982 t += _(' (clean)')
5977 cleanworkdir = True
5983 cleanworkdir = True
5978 elif pnode not in bheads:
5984 elif pnode not in bheads:
5979 t += _(' (new branch head)')
5985 t += _(' (new branch head)')
5980
5986
5981 if cleanworkdir:
5987 if cleanworkdir:
5982 # i18n: column positioning for "hg summary"
5988 # i18n: column positioning for "hg summary"
5983 ui.status(_('commit: %s\n') % t.strip())
5989 ui.status(_('commit: %s\n') % t.strip())
5984 else:
5990 else:
5985 # i18n: column positioning for "hg summary"
5991 # i18n: column positioning for "hg summary"
5986 ui.write(_('commit: %s\n') % t.strip())
5992 ui.write(_('commit: %s\n') % t.strip())
5987
5993
5988 # all ancestors of branch heads - all ancestors of parent = new csets
5994 # all ancestors of branch heads - all ancestors of parent = new csets
5989 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5995 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5990 bheads))
5996 bheads))
5991
5997
5992 if new == 0:
5998 if new == 0:
5993 # i18n: column positioning for "hg summary"
5999 # i18n: column positioning for "hg summary"
5994 ui.status(_('update: (current)\n'))
6000 ui.status(_('update: (current)\n'))
5995 elif pnode not in bheads:
6001 elif pnode not in bheads:
5996 # i18n: column positioning for "hg summary"
6002 # i18n: column positioning for "hg summary"
5997 ui.write(_('update: %d new changesets (update)\n') % new)
6003 ui.write(_('update: %d new changesets (update)\n') % new)
5998 else:
6004 else:
5999 # i18n: column positioning for "hg summary"
6005 # i18n: column positioning for "hg summary"
6000 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6006 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6001 (new, len(bheads)))
6007 (new, len(bheads)))
6002
6008
6003 cmdutil.summaryhooks(ui, repo)
6009 cmdutil.summaryhooks(ui, repo)
6004
6010
6005 if opts.get('remote'):
6011 if opts.get('remote'):
6006 needsincoming, needsoutgoing = True, True
6012 needsincoming, needsoutgoing = True, True
6007 else:
6013 else:
6008 needsincoming, needsoutgoing = False, False
6014 needsincoming, needsoutgoing = False, False
6009 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6015 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6010 if i:
6016 if i:
6011 needsincoming = True
6017 needsincoming = True
6012 if o:
6018 if o:
6013 needsoutgoing = True
6019 needsoutgoing = True
6014 if not needsincoming and not needsoutgoing:
6020 if not needsincoming and not needsoutgoing:
6015 return
6021 return
6016
6022
6017 def getincoming():
6023 def getincoming():
6018 source, branches = hg.parseurl(ui.expandpath('default'))
6024 source, branches = hg.parseurl(ui.expandpath('default'))
6019 sbranch = branches[0]
6025 sbranch = branches[0]
6020 try:
6026 try:
6021 other = hg.peer(repo, {}, source)
6027 other = hg.peer(repo, {}, source)
6022 except error.RepoError:
6028 except error.RepoError:
6023 if opts.get('remote'):
6029 if opts.get('remote'):
6024 raise
6030 raise
6025 return source, sbranch, None, None, None
6031 return source, sbranch, None, None, None
6026 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6032 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6027 if revs:
6033 if revs:
6028 revs = [other.lookup(rev) for rev in revs]
6034 revs = [other.lookup(rev) for rev in revs]
6029 ui.debug('comparing with %s\n' % util.hidepassword(source))
6035 ui.debug('comparing with %s\n' % util.hidepassword(source))
6030 repo.ui.pushbuffer()
6036 repo.ui.pushbuffer()
6031 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6037 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6032 repo.ui.popbuffer()
6038 repo.ui.popbuffer()
6033 return source, sbranch, other, commoninc, commoninc[1]
6039 return source, sbranch, other, commoninc, commoninc[1]
6034
6040
6035 if needsincoming:
6041 if needsincoming:
6036 source, sbranch, sother, commoninc, incoming = getincoming()
6042 source, sbranch, sother, commoninc, incoming = getincoming()
6037 else:
6043 else:
6038 source = sbranch = sother = commoninc = incoming = None
6044 source = sbranch = sother = commoninc = incoming = None
6039
6045
6040 def getoutgoing():
6046 def getoutgoing():
6041 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6047 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6042 dbranch = branches[0]
6048 dbranch = branches[0]
6043 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6049 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6044 if source != dest:
6050 if source != dest:
6045 try:
6051 try:
6046 dother = hg.peer(repo, {}, dest)
6052 dother = hg.peer(repo, {}, dest)
6047 except error.RepoError:
6053 except error.RepoError:
6048 if opts.get('remote'):
6054 if opts.get('remote'):
6049 raise
6055 raise
6050 return dest, dbranch, None, None
6056 return dest, dbranch, None, None
6051 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6057 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6052 elif sother is None:
6058 elif sother is None:
6053 # there is no explicit destination peer, but source one is invalid
6059 # there is no explicit destination peer, but source one is invalid
6054 return dest, dbranch, None, None
6060 return dest, dbranch, None, None
6055 else:
6061 else:
6056 dother = sother
6062 dother = sother
6057 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6063 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6058 common = None
6064 common = None
6059 else:
6065 else:
6060 common = commoninc
6066 common = commoninc
6061 if revs:
6067 if revs:
6062 revs = [repo.lookup(rev) for rev in revs]
6068 revs = [repo.lookup(rev) for rev in revs]
6063 repo.ui.pushbuffer()
6069 repo.ui.pushbuffer()
6064 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6070 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6065 commoninc=common)
6071 commoninc=common)
6066 repo.ui.popbuffer()
6072 repo.ui.popbuffer()
6067 return dest, dbranch, dother, outgoing
6073 return dest, dbranch, dother, outgoing
6068
6074
6069 if needsoutgoing:
6075 if needsoutgoing:
6070 dest, dbranch, dother, outgoing = getoutgoing()
6076 dest, dbranch, dother, outgoing = getoutgoing()
6071 else:
6077 else:
6072 dest = dbranch = dother = outgoing = None
6078 dest = dbranch = dother = outgoing = None
6073
6079
6074 if opts.get('remote'):
6080 if opts.get('remote'):
6075 t = []
6081 t = []
6076 if incoming:
6082 if incoming:
6077 t.append(_('1 or more incoming'))
6083 t.append(_('1 or more incoming'))
6078 o = outgoing.missing
6084 o = outgoing.missing
6079 if o:
6085 if o:
6080 t.append(_('%d outgoing') % len(o))
6086 t.append(_('%d outgoing') % len(o))
6081 other = dother or sother
6087 other = dother or sother
6082 if 'bookmarks' in other.listkeys('namespaces'):
6088 if 'bookmarks' in other.listkeys('namespaces'):
6083 counts = bookmarks.summary(repo, other)
6089 counts = bookmarks.summary(repo, other)
6084 if counts[0] > 0:
6090 if counts[0] > 0:
6085 t.append(_('%d incoming bookmarks') % counts[0])
6091 t.append(_('%d incoming bookmarks') % counts[0])
6086 if counts[1] > 0:
6092 if counts[1] > 0:
6087 t.append(_('%d outgoing bookmarks') % counts[1])
6093 t.append(_('%d outgoing bookmarks') % counts[1])
6088
6094
6089 if t:
6095 if t:
6090 # i18n: column positioning for "hg summary"
6096 # i18n: column positioning for "hg summary"
6091 ui.write(_('remote: %s\n') % (', '.join(t)))
6097 ui.write(_('remote: %s\n') % (', '.join(t)))
6092 else:
6098 else:
6093 # i18n: column positioning for "hg summary"
6099 # i18n: column positioning for "hg summary"
6094 ui.status(_('remote: (synced)\n'))
6100 ui.status(_('remote: (synced)\n'))
6095
6101
6096 cmdutil.summaryremotehooks(ui, repo, opts,
6102 cmdutil.summaryremotehooks(ui, repo, opts,
6097 ((source, sbranch, sother, commoninc),
6103 ((source, sbranch, sother, commoninc),
6098 (dest, dbranch, dother, outgoing)))
6104 (dest, dbranch, dother, outgoing)))
6099
6105
6100 @command('tag',
6106 @command('tag',
6101 [('f', 'force', None, _('force tag')),
6107 [('f', 'force', None, _('force tag')),
6102 ('l', 'local', None, _('make the tag local')),
6108 ('l', 'local', None, _('make the tag local')),
6103 ('r', 'rev', '', _('revision to tag'), _('REV')),
6109 ('r', 'rev', '', _('revision to tag'), _('REV')),
6104 ('', 'remove', None, _('remove a tag')),
6110 ('', 'remove', None, _('remove a tag')),
6105 # -l/--local is already there, commitopts cannot be used
6111 # -l/--local is already there, commitopts cannot be used
6106 ('e', 'edit', None, _('invoke editor on commit messages')),
6112 ('e', 'edit', None, _('invoke editor on commit messages')),
6107 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6113 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6108 ] + commitopts2,
6114 ] + commitopts2,
6109 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6115 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6110 def tag(ui, repo, name1, *names, **opts):
6116 def tag(ui, repo, name1, *names, **opts):
6111 """add one or more tags for the current or given revision
6117 """add one or more tags for the current or given revision
6112
6118
6113 Name a particular revision using <name>.
6119 Name a particular revision using <name>.
6114
6120
6115 Tags are used to name particular revisions of the repository and are
6121 Tags are used to name particular revisions of the repository and are
6116 very useful to compare different revisions, to go back to significant
6122 very useful to compare different revisions, to go back to significant
6117 earlier versions or to mark branch points as releases, etc. Changing
6123 earlier versions or to mark branch points as releases, etc. Changing
6118 an existing tag is normally disallowed; use -f/--force to override.
6124 an existing tag is normally disallowed; use -f/--force to override.
6119
6125
6120 If no revision is given, the parent of the working directory is
6126 If no revision is given, the parent of the working directory is
6121 used.
6127 used.
6122
6128
6123 To facilitate version control, distribution, and merging of tags,
6129 To facilitate version control, distribution, and merging of tags,
6124 they are stored as a file named ".hgtags" which is managed similarly
6130 they are stored as a file named ".hgtags" which is managed similarly
6125 to other project files and can be hand-edited if necessary. This
6131 to other project files and can be hand-edited if necessary. This
6126 also means that tagging creates a new commit. The file
6132 also means that tagging creates a new commit. The file
6127 ".hg/localtags" is used for local tags (not shared among
6133 ".hg/localtags" is used for local tags (not shared among
6128 repositories).
6134 repositories).
6129
6135
6130 Tag commits are usually made at the head of a branch. If the parent
6136 Tag commits are usually made at the head of a branch. If the parent
6131 of the working directory is not a branch head, :hg:`tag` aborts; use
6137 of the working directory is not a branch head, :hg:`tag` aborts; use
6132 -f/--force to force the tag commit to be based on a non-head
6138 -f/--force to force the tag commit to be based on a non-head
6133 changeset.
6139 changeset.
6134
6140
6135 See :hg:`help dates` for a list of formats valid for -d/--date.
6141 See :hg:`help dates` for a list of formats valid for -d/--date.
6136
6142
6137 Since tag names have priority over branch names during revision
6143 Since tag names have priority over branch names during revision
6138 lookup, using an existing branch name as a tag name is discouraged.
6144 lookup, using an existing branch name as a tag name is discouraged.
6139
6145
6140 Returns 0 on success.
6146 Returns 0 on success.
6141 """
6147 """
6142 wlock = lock = None
6148 wlock = lock = None
6143 try:
6149 try:
6144 wlock = repo.wlock()
6150 wlock = repo.wlock()
6145 lock = repo.lock()
6151 lock = repo.lock()
6146 rev_ = "."
6152 rev_ = "."
6147 names = [t.strip() for t in (name1,) + names]
6153 names = [t.strip() for t in (name1,) + names]
6148 if len(names) != len(set(names)):
6154 if len(names) != len(set(names)):
6149 raise util.Abort(_('tag names must be unique'))
6155 raise util.Abort(_('tag names must be unique'))
6150 for n in names:
6156 for n in names:
6151 scmutil.checknewlabel(repo, n, 'tag')
6157 scmutil.checknewlabel(repo, n, 'tag')
6152 if not n:
6158 if not n:
6153 raise util.Abort(_('tag names cannot consist entirely of '
6159 raise util.Abort(_('tag names cannot consist entirely of '
6154 'whitespace'))
6160 'whitespace'))
6155 if opts.get('rev') and opts.get('remove'):
6161 if opts.get('rev') and opts.get('remove'):
6156 raise util.Abort(_("--rev and --remove are incompatible"))
6162 raise util.Abort(_("--rev and --remove are incompatible"))
6157 if opts.get('rev'):
6163 if opts.get('rev'):
6158 rev_ = opts['rev']
6164 rev_ = opts['rev']
6159 message = opts.get('message')
6165 message = opts.get('message')
6160 if opts.get('remove'):
6166 if opts.get('remove'):
6161 if opts.get('local'):
6167 if opts.get('local'):
6162 expectedtype = 'local'
6168 expectedtype = 'local'
6163 else:
6169 else:
6164 expectedtype = 'global'
6170 expectedtype = 'global'
6165
6171
6166 for n in names:
6172 for n in names:
6167 if not repo.tagtype(n):
6173 if not repo.tagtype(n):
6168 raise util.Abort(_("tag '%s' does not exist") % n)
6174 raise util.Abort(_("tag '%s' does not exist") % n)
6169 if repo.tagtype(n) != expectedtype:
6175 if repo.tagtype(n) != expectedtype:
6170 if expectedtype == 'global':
6176 if expectedtype == 'global':
6171 raise util.Abort(_("tag '%s' is not a global tag") % n)
6177 raise util.Abort(_("tag '%s' is not a global tag") % n)
6172 else:
6178 else:
6173 raise util.Abort(_("tag '%s' is not a local tag") % n)
6179 raise util.Abort(_("tag '%s' is not a local tag") % n)
6174 rev_ = nullid
6180 rev_ = nullid
6175 if not message:
6181 if not message:
6176 # we don't translate commit messages
6182 # we don't translate commit messages
6177 message = 'Removed tag %s' % ', '.join(names)
6183 message = 'Removed tag %s' % ', '.join(names)
6178 elif not opts.get('force'):
6184 elif not opts.get('force'):
6179 for n in names:
6185 for n in names:
6180 if n in repo.tags():
6186 if n in repo.tags():
6181 raise util.Abort(_("tag '%s' already exists "
6187 raise util.Abort(_("tag '%s' already exists "
6182 "(use -f to force)") % n)
6188 "(use -f to force)") % n)
6183 if not opts.get('local'):
6189 if not opts.get('local'):
6184 p1, p2 = repo.dirstate.parents()
6190 p1, p2 = repo.dirstate.parents()
6185 if p2 != nullid:
6191 if p2 != nullid:
6186 raise util.Abort(_('uncommitted merge'))
6192 raise util.Abort(_('uncommitted merge'))
6187 bheads = repo.branchheads()
6193 bheads = repo.branchheads()
6188 if not opts.get('force') and bheads and p1 not in bheads:
6194 if not opts.get('force') and bheads and p1 not in bheads:
6189 raise util.Abort(_('not at a branch head (use -f to force)'))
6195 raise util.Abort(_('not at a branch head (use -f to force)'))
6190 r = scmutil.revsingle(repo, rev_).node()
6196 r = scmutil.revsingle(repo, rev_).node()
6191
6197
6192 if not message:
6198 if not message:
6193 # we don't translate commit messages
6199 # we don't translate commit messages
6194 message = ('Added tag %s for changeset %s' %
6200 message = ('Added tag %s for changeset %s' %
6195 (', '.join(names), short(r)))
6201 (', '.join(names), short(r)))
6196
6202
6197 date = opts.get('date')
6203 date = opts.get('date')
6198 if date:
6204 if date:
6199 date = util.parsedate(date)
6205 date = util.parsedate(date)
6200
6206
6201 if opts.get('remove'):
6207 if opts.get('remove'):
6202 editform = 'tag.remove'
6208 editform = 'tag.remove'
6203 else:
6209 else:
6204 editform = 'tag.add'
6210 editform = 'tag.add'
6205 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6211 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6206
6212
6207 # don't allow tagging the null rev
6213 # don't allow tagging the null rev
6208 if (not opts.get('remove') and
6214 if (not opts.get('remove') and
6209 scmutil.revsingle(repo, rev_).rev() == nullrev):
6215 scmutil.revsingle(repo, rev_).rev() == nullrev):
6210 raise util.Abort(_("cannot tag null revision"))
6216 raise util.Abort(_("cannot tag null revision"))
6211
6217
6212 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6218 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6213 editor=editor)
6219 editor=editor)
6214 finally:
6220 finally:
6215 release(lock, wlock)
6221 release(lock, wlock)
6216
6222
6217 @command('tags', formatteropts, '')
6223 @command('tags', formatteropts, '')
6218 def tags(ui, repo, **opts):
6224 def tags(ui, repo, **opts):
6219 """list repository tags
6225 """list repository tags
6220
6226
6221 This lists both regular and local tags. When the -v/--verbose
6227 This lists both regular and local tags. When the -v/--verbose
6222 switch is used, a third column "local" is printed for local tags.
6228 switch is used, a third column "local" is printed for local tags.
6223
6229
6224 Returns 0 on success.
6230 Returns 0 on success.
6225 """
6231 """
6226
6232
6227 fm = ui.formatter('tags', opts)
6233 fm = ui.formatter('tags', opts)
6228 hexfunc = fm.hexfunc
6234 hexfunc = fm.hexfunc
6229 tagtype = ""
6235 tagtype = ""
6230
6236
6231 for t, n in reversed(repo.tagslist()):
6237 for t, n in reversed(repo.tagslist()):
6232 hn = hexfunc(n)
6238 hn = hexfunc(n)
6233 label = 'tags.normal'
6239 label = 'tags.normal'
6234 tagtype = ''
6240 tagtype = ''
6235 if repo.tagtype(t) == 'local':
6241 if repo.tagtype(t) == 'local':
6236 label = 'tags.local'
6242 label = 'tags.local'
6237 tagtype = 'local'
6243 tagtype = 'local'
6238
6244
6239 fm.startitem()
6245 fm.startitem()
6240 fm.write('tag', '%s', t, label=label)
6246 fm.write('tag', '%s', t, label=label)
6241 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6247 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6242 fm.condwrite(not ui.quiet, 'rev node', fmt,
6248 fm.condwrite(not ui.quiet, 'rev node', fmt,
6243 repo.changelog.rev(n), hn, label=label)
6249 repo.changelog.rev(n), hn, label=label)
6244 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6250 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6245 tagtype, label=label)
6251 tagtype, label=label)
6246 fm.plain('\n')
6252 fm.plain('\n')
6247 fm.end()
6253 fm.end()
6248
6254
6249 @command('tip',
6255 @command('tip',
6250 [('p', 'patch', None, _('show patch')),
6256 [('p', 'patch', None, _('show patch')),
6251 ('g', 'git', None, _('use git extended diff format')),
6257 ('g', 'git', None, _('use git extended diff format')),
6252 ] + templateopts,
6258 ] + templateopts,
6253 _('[-p] [-g]'))
6259 _('[-p] [-g]'))
6254 def tip(ui, repo, **opts):
6260 def tip(ui, repo, **opts):
6255 """show the tip revision (DEPRECATED)
6261 """show the tip revision (DEPRECATED)
6256
6262
6257 The tip revision (usually just called the tip) is the changeset
6263 The tip revision (usually just called the tip) is the changeset
6258 most recently added to the repository (and therefore the most
6264 most recently added to the repository (and therefore the most
6259 recently changed head).
6265 recently changed head).
6260
6266
6261 If you have just made a commit, that commit will be the tip. If
6267 If you have just made a commit, that commit will be the tip. If
6262 you have just pulled changes from another repository, the tip of
6268 you have just pulled changes from another repository, the tip of
6263 that repository becomes the current tip. The "tip" tag is special
6269 that repository becomes the current tip. The "tip" tag is special
6264 and cannot be renamed or assigned to a different changeset.
6270 and cannot be renamed or assigned to a different changeset.
6265
6271
6266 This command is deprecated, please use :hg:`heads` instead.
6272 This command is deprecated, please use :hg:`heads` instead.
6267
6273
6268 Returns 0 on success.
6274 Returns 0 on success.
6269 """
6275 """
6270 displayer = cmdutil.show_changeset(ui, repo, opts)
6276 displayer = cmdutil.show_changeset(ui, repo, opts)
6271 displayer.show(repo['tip'])
6277 displayer.show(repo['tip'])
6272 displayer.close()
6278 displayer.close()
6273
6279
6274 @command('unbundle',
6280 @command('unbundle',
6275 [('u', 'update', None,
6281 [('u', 'update', None,
6276 _('update to new branch head if changesets were unbundled'))],
6282 _('update to new branch head if changesets were unbundled'))],
6277 _('[-u] FILE...'))
6283 _('[-u] FILE...'))
6278 def unbundle(ui, repo, fname1, *fnames, **opts):
6284 def unbundle(ui, repo, fname1, *fnames, **opts):
6279 """apply one or more changegroup files
6285 """apply one or more changegroup files
6280
6286
6281 Apply one or more compressed changegroup files generated by the
6287 Apply one or more compressed changegroup files generated by the
6282 bundle command.
6288 bundle command.
6283
6289
6284 Returns 0 on success, 1 if an update has unresolved files.
6290 Returns 0 on success, 1 if an update has unresolved files.
6285 """
6291 """
6286 fnames = (fname1,) + fnames
6292 fnames = (fname1,) + fnames
6287
6293
6288 lock = repo.lock()
6294 lock = repo.lock()
6289 try:
6295 try:
6290 for fname in fnames:
6296 for fname in fnames:
6291 f = hg.openpath(ui, fname)
6297 f = hg.openpath(ui, fname)
6292 gen = exchange.readbundle(ui, f, fname)
6298 gen = exchange.readbundle(ui, f, fname)
6293 if isinstance(gen, bundle2.unbundle20):
6299 if isinstance(gen, bundle2.unbundle20):
6294 tr = repo.transaction('unbundle')
6300 tr = repo.transaction('unbundle')
6295 try:
6301 try:
6296 op = bundle2.processbundle(repo, gen, lambda: tr)
6302 op = bundle2.processbundle(repo, gen, lambda: tr)
6297 tr.close()
6303 tr.close()
6298 finally:
6304 finally:
6299 if tr:
6305 if tr:
6300 tr.release()
6306 tr.release()
6301 changes = [r.get('result', 0)
6307 changes = [r.get('result', 0)
6302 for r in op.records['changegroup']]
6308 for r in op.records['changegroup']]
6303 modheads = changegroup.combineresults(changes)
6309 modheads = changegroup.combineresults(changes)
6304 else:
6310 else:
6305 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6311 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6306 'bundle:' + fname)
6312 'bundle:' + fname)
6307 finally:
6313 finally:
6308 lock.release()
6314 lock.release()
6309
6315
6310 return postincoming(ui, repo, modheads, opts.get('update'), None)
6316 return postincoming(ui, repo, modheads, opts.get('update'), None)
6311
6317
6312 @command('^update|up|checkout|co',
6318 @command('^update|up|checkout|co',
6313 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6319 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6314 ('c', 'check', None,
6320 ('c', 'check', None,
6315 _('update across branches if no uncommitted changes')),
6321 _('update across branches if no uncommitted changes')),
6316 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6322 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6317 ('r', 'rev', '', _('revision'), _('REV'))
6323 ('r', 'rev', '', _('revision'), _('REV'))
6318 ] + mergetoolopts,
6324 ] + mergetoolopts,
6319 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6325 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6320 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6326 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6321 tool=None):
6327 tool=None):
6322 """update working directory (or switch revisions)
6328 """update working directory (or switch revisions)
6323
6329
6324 Update the repository's working directory to the specified
6330 Update the repository's working directory to the specified
6325 changeset. If no changeset is specified, update to the tip of the
6331 changeset. If no changeset is specified, update to the tip of the
6326 current named branch and move the current bookmark (see :hg:`help
6332 current named branch and move the current bookmark (see :hg:`help
6327 bookmarks`).
6333 bookmarks`).
6328
6334
6329 Update sets the working directory's parent revision to the specified
6335 Update sets the working directory's parent revision to the specified
6330 changeset (see :hg:`help parents`).
6336 changeset (see :hg:`help parents`).
6331
6337
6332 If the changeset is not a descendant or ancestor of the working
6338 If the changeset is not a descendant or ancestor of the working
6333 directory's parent, the update is aborted. With the -c/--check
6339 directory's parent, the update is aborted. With the -c/--check
6334 option, the working directory is checked for uncommitted changes; if
6340 option, the working directory is checked for uncommitted changes; if
6335 none are found, the working directory is updated to the specified
6341 none are found, the working directory is updated to the specified
6336 changeset.
6342 changeset.
6337
6343
6338 .. container:: verbose
6344 .. container:: verbose
6339
6345
6340 The following rules apply when the working directory contains
6346 The following rules apply when the working directory contains
6341 uncommitted changes:
6347 uncommitted changes:
6342
6348
6343 1. If neither -c/--check nor -C/--clean is specified, and if
6349 1. If neither -c/--check nor -C/--clean is specified, and if
6344 the requested changeset is an ancestor or descendant of
6350 the requested changeset is an ancestor or descendant of
6345 the working directory's parent, the uncommitted changes
6351 the working directory's parent, the uncommitted changes
6346 are merged into the requested changeset and the merged
6352 are merged into the requested changeset and the merged
6347 result is left uncommitted. If the requested changeset is
6353 result is left uncommitted. If the requested changeset is
6348 not an ancestor or descendant (that is, it is on another
6354 not an ancestor or descendant (that is, it is on another
6349 branch), the update is aborted and the uncommitted changes
6355 branch), the update is aborted and the uncommitted changes
6350 are preserved.
6356 are preserved.
6351
6357
6352 2. With the -c/--check option, the update is aborted and the
6358 2. With the -c/--check option, the update is aborted and the
6353 uncommitted changes are preserved.
6359 uncommitted changes are preserved.
6354
6360
6355 3. With the -C/--clean option, uncommitted changes are discarded and
6361 3. With the -C/--clean option, uncommitted changes are discarded and
6356 the working directory is updated to the requested changeset.
6362 the working directory is updated to the requested changeset.
6357
6363
6358 To cancel an uncommitted merge (and lose your changes), use
6364 To cancel an uncommitted merge (and lose your changes), use
6359 :hg:`update --clean .`.
6365 :hg:`update --clean .`.
6360
6366
6361 Use null as the changeset to remove the working directory (like
6367 Use null as the changeset to remove the working directory (like
6362 :hg:`clone -U`).
6368 :hg:`clone -U`).
6363
6369
6364 If you want to revert just one file to an older revision, use
6370 If you want to revert just one file to an older revision, use
6365 :hg:`revert [-r REV] NAME`.
6371 :hg:`revert [-r REV] NAME`.
6366
6372
6367 See :hg:`help dates` for a list of formats valid for -d/--date.
6373 See :hg:`help dates` for a list of formats valid for -d/--date.
6368
6374
6369 Returns 0 on success, 1 if there are unresolved files.
6375 Returns 0 on success, 1 if there are unresolved files.
6370 """
6376 """
6371 if rev and node:
6377 if rev and node:
6372 raise util.Abort(_("please specify just one revision"))
6378 raise util.Abort(_("please specify just one revision"))
6373
6379
6374 if rev is None or rev == '':
6380 if rev is None or rev == '':
6375 rev = node
6381 rev = node
6376
6382
6377 cmdutil.clearunfinished(repo)
6383 cmdutil.clearunfinished(repo)
6378
6384
6379 # with no argument, we also move the current bookmark, if any
6385 # with no argument, we also move the current bookmark, if any
6380 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6386 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6381
6387
6382 # if we defined a bookmark, we have to remember the original bookmark name
6388 # if we defined a bookmark, we have to remember the original bookmark name
6383 brev = rev
6389 brev = rev
6384 rev = scmutil.revsingle(repo, rev, rev).rev()
6390 rev = scmutil.revsingle(repo, rev, rev).rev()
6385
6391
6386 if check and clean:
6392 if check and clean:
6387 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6393 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6388
6394
6389 if date:
6395 if date:
6390 if rev is not None:
6396 if rev is not None:
6391 raise util.Abort(_("you can't specify a revision and a date"))
6397 raise util.Abort(_("you can't specify a revision and a date"))
6392 rev = cmdutil.finddate(ui, repo, date)
6398 rev = cmdutil.finddate(ui, repo, date)
6393
6399
6394 if check:
6400 if check:
6395 cmdutil.bailifchanged(repo, merge=False)
6401 cmdutil.bailifchanged(repo, merge=False)
6396 if rev is None:
6402 if rev is None:
6397 rev = repo[repo[None].branch()].rev()
6403 rev = repo[repo[None].branch()].rev()
6398
6404
6399 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6405 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6400
6406
6401 if clean:
6407 if clean:
6402 ret = hg.clean(repo, rev)
6408 ret = hg.clean(repo, rev)
6403 else:
6409 else:
6404 ret = hg.update(repo, rev)
6410 ret = hg.update(repo, rev)
6405
6411
6406 if not ret and movemarkfrom:
6412 if not ret and movemarkfrom:
6407 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6413 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6408 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6414 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6409 elif brev in repo._bookmarks:
6415 elif brev in repo._bookmarks:
6410 bookmarks.setcurrent(repo, brev)
6416 bookmarks.setcurrent(repo, brev)
6411 ui.status(_("(activating bookmark %s)\n") % brev)
6417 ui.status(_("(activating bookmark %s)\n") % brev)
6412 elif brev:
6418 elif brev:
6413 if repo._bookmarkcurrent:
6419 if repo._bookmarkcurrent:
6414 ui.status(_("(leaving bookmark %s)\n") %
6420 ui.status(_("(leaving bookmark %s)\n") %
6415 repo._bookmarkcurrent)
6421 repo._bookmarkcurrent)
6416 bookmarks.unsetcurrent(repo)
6422 bookmarks.unsetcurrent(repo)
6417
6423
6418 return ret
6424 return ret
6419
6425
6420 @command('verify', [])
6426 @command('verify', [])
6421 def verify(ui, repo):
6427 def verify(ui, repo):
6422 """verify the integrity of the repository
6428 """verify the integrity of the repository
6423
6429
6424 Verify the integrity of the current repository.
6430 Verify the integrity of the current repository.
6425
6431
6426 This will perform an extensive check of the repository's
6432 This will perform an extensive check of the repository's
6427 integrity, validating the hashes and checksums of each entry in
6433 integrity, validating the hashes and checksums of each entry in
6428 the changelog, manifest, and tracked files, as well as the
6434 the changelog, manifest, and tracked files, as well as the
6429 integrity of their crosslinks and indices.
6435 integrity of their crosslinks and indices.
6430
6436
6431 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6437 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6432 for more information about recovery from corruption of the
6438 for more information about recovery from corruption of the
6433 repository.
6439 repository.
6434
6440
6435 Returns 0 on success, 1 if errors are encountered.
6441 Returns 0 on success, 1 if errors are encountered.
6436 """
6442 """
6437 return hg.verify(repo)
6443 return hg.verify(repo)
6438
6444
6439 @command('version', [], norepo=True)
6445 @command('version', [], norepo=True)
6440 def version_(ui):
6446 def version_(ui):
6441 """output version and copyright information"""
6447 """output version and copyright information"""
6442 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6448 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6443 % util.version())
6449 % util.version())
6444 ui.status(_(
6450 ui.status(_(
6445 "(see http://mercurial.selenic.com for more information)\n"
6451 "(see http://mercurial.selenic.com for more information)\n"
6446 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6452 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6447 "This is free software; see the source for copying conditions. "
6453 "This is free software; see the source for copying conditions. "
6448 "There is NO\nwarranty; "
6454 "There is NO\nwarranty; "
6449 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6455 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6450 ))
6456 ))
6451
6457
6452 ui.note(_("\nEnabled extensions:\n\n"))
6458 ui.note(_("\nEnabled extensions:\n\n"))
6453 if ui.verbose:
6459 if ui.verbose:
6454 # format names and versions into columns
6460 # format names and versions into columns
6455 names = []
6461 names = []
6456 vers = []
6462 vers = []
6457 for name, module in extensions.extensions():
6463 for name, module in extensions.extensions():
6458 names.append(name)
6464 names.append(name)
6459 vers.append(extensions.moduleversion(module))
6465 vers.append(extensions.moduleversion(module))
6460 if names:
6466 if names:
6461 maxnamelen = max(len(n) for n in names)
6467 maxnamelen = max(len(n) for n in names)
6462 for i, name in enumerate(names):
6468 for i, name in enumerate(names):
6463 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6469 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,104 +1,144 b''
1 $ hg init repo
1 $ hg init repo
2 $ cd repo
2 $ cd repo
3 $ echo foo > foo
3 $ echo foo > foo
4 $ hg ci -qAm 'add foo'
4 $ hg ci -qAm 'add foo'
5 $ echo >> foo
5 $ echo >> foo
6 $ hg ci -m 'change foo'
6 $ hg ci -m 'change foo'
7 $ hg up -qC 0
7 $ hg up -qC 0
8 $ echo bar > bar
8 $ echo bar > bar
9 $ hg ci -qAm 'add bar'
9 $ hg ci -qAm 'add bar'
10
10
11 $ hg log
11 $ hg log
12 changeset: 2:effea6de0384
12 changeset: 2:effea6de0384
13 tag: tip
13 tag: tip
14 parent: 0:bbd179dfa0a7
14 parent: 0:bbd179dfa0a7
15 user: test
15 user: test
16 date: Thu Jan 01 00:00:00 1970 +0000
16 date: Thu Jan 01 00:00:00 1970 +0000
17 summary: add bar
17 summary: add bar
18
18
19 changeset: 1:ed1b79f46b9a
19 changeset: 1:ed1b79f46b9a
20 user: test
20 user: test
21 date: Thu Jan 01 00:00:00 1970 +0000
21 date: Thu Jan 01 00:00:00 1970 +0000
22 summary: change foo
22 summary: change foo
23
23
24 changeset: 0:bbd179dfa0a7
24 changeset: 0:bbd179dfa0a7
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
27 summary: add foo
27 summary: add foo
28
28
29 $ cd ..
29 $ cd ..
30
30
31 don't show "(+1 heads)" message when pulling closed head
31 don't show "(+1 heads)" message when pulling closed head
32
32
33 $ hg clone -q repo repo2
33 $ hg clone -q repo repo2
34 $ hg clone -q repo2 repo3
34 $ hg clone -q repo2 repo3
35 $ cd repo2
35 $ cd repo2
36 $ hg up -q 0
36 $ hg up -q 0
37 $ echo hello >> foo
37 $ echo hello >> foo
38 $ hg ci -mx1
38 $ hg ci -mx1
39 created new head
39 created new head
40 $ hg ci -mx2 --close-branch
40 $ hg ci -mx2 --close-branch
41 $ cd ../repo3
41 $ cd ../repo3
42 $ hg heads -q --closed
42 $ hg heads -q --closed
43 2:effea6de0384
43 2:effea6de0384
44 1:ed1b79f46b9a
44 1:ed1b79f46b9a
45 $ hg pull
45 $ hg pull
46 pulling from $TESTTMP/repo2 (glob)
46 pulling from $TESTTMP/repo2 (glob)
47 searching for changes
47 searching for changes
48 adding changesets
48 adding changesets
49 adding manifests
49 adding manifests
50 adding file changes
50 adding file changes
51 added 2 changesets with 1 changes to 1 files
51 added 2 changesets with 1 changes to 1 files
52 (run 'hg update' to get a working copy)
52 (run 'hg update' to get a working copy)
53 $ hg heads -q --closed
53 $ hg heads -q --closed
54 4:00cfe9073916
54 4:00cfe9073916
55 2:effea6de0384
55 2:effea6de0384
56 1:ed1b79f46b9a
56 1:ed1b79f46b9a
57
57
58 $ cd ..
58 $ cd ..
59
59
60 $ hg init copy
60 $ hg init copy
61 $ cd copy
61 $ cd copy
62
62
63 Pull a missing revision:
63 Pull a missing revision:
64
64
65 $ hg pull -qr missing ../repo
65 $ hg pull -qr missing ../repo
66 abort: unknown revision 'missing'!
66 abort: unknown revision 'missing'!
67 [255]
67 [255]
68
68
69 Pull multiple revisions with update:
69 Pull multiple revisions with update:
70
70
71 $ hg pull -qu -r 0 -r 1 ../repo
71 $ hg pull -qu -r 0 -r 1 ../repo
72 $ hg -q parents
72 $ hg -q parents
73 0:bbd179dfa0a7
73 0:bbd179dfa0a7
74 $ hg rollback
74 $ hg rollback
75 repository tip rolled back to revision -1 (undo pull)
75 repository tip rolled back to revision -1 (undo pull)
76 working directory now based on revision -1
76 working directory now based on revision -1
77
77
78 $ hg pull -qr 0 ../repo
78 $ hg pull -qr 0 ../repo
79 $ hg log
79 $ hg log
80 changeset: 0:bbd179dfa0a7
80 changeset: 0:bbd179dfa0a7
81 tag: tip
81 tag: tip
82 user: test
82 user: test
83 date: Thu Jan 01 00:00:00 1970 +0000
83 date: Thu Jan 01 00:00:00 1970 +0000
84 summary: add foo
84 summary: add foo
85
85
86 $ hg pull -qr 1 ../repo
86 $ hg pull -qr 1 ../repo
87 $ hg log
87 $ hg log
88 changeset: 1:ed1b79f46b9a
88 changeset: 1:ed1b79f46b9a
89 tag: tip
89 tag: tip
90 user: test
90 user: test
91 date: Thu Jan 01 00:00:00 1970 +0000
91 date: Thu Jan 01 00:00:00 1970 +0000
92 summary: change foo
92 summary: change foo
93
93
94 changeset: 0:bbd179dfa0a7
94 changeset: 0:bbd179dfa0a7
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:00 1970 +0000
96 date: Thu Jan 01 00:00:00 1970 +0000
97 summary: add foo
97 summary: add foo
98
98
99
99
100 This used to abort: received changelog group is empty:
100 This used to abort: received changelog group is empty:
101
101
102 $ hg pull -qr 1 ../repo
102 $ hg pull -qr 1 ../repo
103
103
104 Test race condition with -r and -U (issue4707)
105
106 We pull '-U -r <name>' and the name change right after/during the changegroup emission.
107 We use http because http is better is our racy-est option.
108
109
110 $ echo babar > ../repo/jungle
111 $ cat <<EOF > ../repo/.hg/hgrc
112 > [hooks]
113 > outgoing.makecommit = hg ci -Am 'racy commit'; echo committed in pull-race
114 > EOF
115 $ hg -R ../repo serve -p $HGPORT2 -d --pid-file=../repo.pid
116 $ cat ../repo.pid >> $DAEMON_PIDS
117 $ hg pull --rev default --update http://localhost:$HGPORT2/
118 pulling from http://localhost:$HGPORT2/
119 searching for changes
120 adding changesets
121 adding manifests
122 adding file changes
123 added 1 changesets with 1 changes to 1 files (+1 heads)
124 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 $ hg log -G
126 @ changeset: 2:effea6de0384
127 | tag: tip
128 | parent: 0:bbd179dfa0a7
129 | user: test
130 | date: Thu Jan 01 00:00:00 1970 +0000
131 | summary: add bar
132 |
133 | o changeset: 1:ed1b79f46b9a
134 |/ user: test
135 | date: Thu Jan 01 00:00:00 1970 +0000
136 | summary: change foo
137 |
138 o changeset: 0:bbd179dfa0a7
139 user: test
140 date: Thu Jan 01 00:00:00 1970 +0000
141 summary: add foo
142
143
104 $ cd ..
144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now