##// END OF EJS Templates
destupdate: move the check related to the "clean" logic in the function...
Pierre-Yves David -
r26628:45b86dba default
parent child Browse files
Show More
@@ -1,6672 +1,6674 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
16 import sshserver, hgweb
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, operator
22 import random, operator
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
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 # label constants
43 # label constants
44 # until 3.5, bookmarks.current was the advertised name, not
44 # until 3.5, bookmarks.current was the advertised name, not
45 # bookmarks.active, so we must use both to avoid breaking old
45 # bookmarks.active, so we must use both to avoid breaking old
46 # custom styles
46 # custom styles
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
48
48
49 # common command options
49 # common command options
50
50
51 globalopts = [
51 globalopts = [
52 ('R', 'repository', '',
52 ('R', 'repository', '',
53 _('repository root directory or name of overlay bundle file'),
53 _('repository root directory or name of overlay bundle file'),
54 _('REPO')),
54 _('REPO')),
55 ('', 'cwd', '',
55 ('', 'cwd', '',
56 _('change working directory'), _('DIR')),
56 _('change working directory'), _('DIR')),
57 ('y', 'noninteractive', None,
57 ('y', 'noninteractive', None,
58 _('do not prompt, automatically pick the first choice for all prompts')),
58 _('do not prompt, automatically pick the first choice for all prompts')),
59 ('q', 'quiet', None, _('suppress output')),
59 ('q', 'quiet', None, _('suppress output')),
60 ('v', 'verbose', None, _('enable additional output')),
60 ('v', 'verbose', None, _('enable additional output')),
61 ('', 'config', [],
61 ('', 'config', [],
62 _('set/override config option (use \'section.name=value\')'),
62 _('set/override config option (use \'section.name=value\')'),
63 _('CONFIG')),
63 _('CONFIG')),
64 ('', 'debug', None, _('enable debugging output')),
64 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debugger', None, _('start debugger')),
65 ('', 'debugger', None, _('start debugger')),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 _('ENCODE')),
67 _('ENCODE')),
68 ('', 'encodingmode', encoding.encodingmode,
68 ('', 'encodingmode', encoding.encodingmode,
69 _('set the charset encoding mode'), _('MODE')),
69 _('set the charset encoding mode'), _('MODE')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'time', None, _('time how long the command takes')),
71 ('', 'time', None, _('time how long the command takes')),
72 ('', 'profile', None, _('print command execution profile')),
72 ('', 'profile', None, _('print command execution profile')),
73 ('', 'version', None, _('output version information and exit')),
73 ('', 'version', None, _('output version information and exit')),
74 ('h', 'help', None, _('display help and exit')),
74 ('h', 'help', None, _('display help and exit')),
75 ('', 'hidden', False, _('consider hidden changesets')),
75 ('', 'hidden', False, _('consider hidden changesets')),
76 ]
76 ]
77
77
78 dryrunopts = [('n', 'dry-run', None,
78 dryrunopts = [('n', 'dry-run', None,
79 _('do not perform actions, just print output'))]
79 _('do not perform actions, just print output'))]
80
80
81 remoteopts = [
81 remoteopts = [
82 ('e', 'ssh', '',
82 ('e', 'ssh', '',
83 _('specify ssh command to use'), _('CMD')),
83 _('specify ssh command to use'), _('CMD')),
84 ('', 'remotecmd', '',
84 ('', 'remotecmd', '',
85 _('specify hg command to run on the remote side'), _('CMD')),
85 _('specify hg command to run on the remote side'), _('CMD')),
86 ('', 'insecure', None,
86 ('', 'insecure', None,
87 _('do not verify server certificate (ignoring web.cacerts config)')),
87 _('do not verify server certificate (ignoring web.cacerts config)')),
88 ]
88 ]
89
89
90 walkopts = [
90 walkopts = [
91 ('I', 'include', [],
91 ('I', 'include', [],
92 _('include names matching the given patterns'), _('PATTERN')),
92 _('include names matching the given patterns'), _('PATTERN')),
93 ('X', 'exclude', [],
93 ('X', 'exclude', [],
94 _('exclude names matching the given patterns'), _('PATTERN')),
94 _('exclude names matching the given patterns'), _('PATTERN')),
95 ]
95 ]
96
96
97 commitopts = [
97 commitopts = [
98 ('m', 'message', '',
98 ('m', 'message', '',
99 _('use text as commit message'), _('TEXT')),
99 _('use text as commit message'), _('TEXT')),
100 ('l', 'logfile', '',
100 ('l', 'logfile', '',
101 _('read commit message from file'), _('FILE')),
101 _('read commit message from file'), _('FILE')),
102 ]
102 ]
103
103
104 commitopts2 = [
104 commitopts2 = [
105 ('d', 'date', '',
105 ('d', 'date', '',
106 _('record the specified date as commit date'), _('DATE')),
106 _('record the specified date as commit date'), _('DATE')),
107 ('u', 'user', '',
107 ('u', 'user', '',
108 _('record the specified user as committer'), _('USER')),
108 _('record the specified user as committer'), _('USER')),
109 ]
109 ]
110
110
111 # hidden for now
111 # hidden for now
112 formatteropts = [
112 formatteropts = [
113 ('T', 'template', '',
113 ('T', 'template', '',
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 ]
115 ]
116
116
117 templateopts = [
117 templateopts = [
118 ('', 'style', '',
118 ('', 'style', '',
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 ('T', 'template', '',
120 ('T', 'template', '',
121 _('display with template'), _('TEMPLATE')),
121 _('display with template'), _('TEMPLATE')),
122 ]
122 ]
123
123
124 logopts = [
124 logopts = [
125 ('p', 'patch', None, _('show patch')),
125 ('p', 'patch', None, _('show patch')),
126 ('g', 'git', None, _('use git extended diff format')),
126 ('g', 'git', None, _('use git extended diff format')),
127 ('l', 'limit', '',
127 ('l', 'limit', '',
128 _('limit number of changes displayed'), _('NUM')),
128 _('limit number of changes displayed'), _('NUM')),
129 ('M', 'no-merges', None, _('do not show merges')),
129 ('M', 'no-merges', None, _('do not show merges')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('G', 'graph', None, _("show the revision DAG")),
131 ('G', 'graph', None, _("show the revision DAG")),
132 ] + templateopts
132 ] + templateopts
133
133
134 diffopts = [
134 diffopts = [
135 ('a', 'text', None, _('treat all files as text')),
135 ('a', 'text', None, _('treat all files as text')),
136 ('g', 'git', None, _('use git extended diff format')),
136 ('g', 'git', None, _('use git extended diff format')),
137 ('', 'nodates', None, _('omit dates from diff headers'))
137 ('', 'nodates', None, _('omit dates from diff headers'))
138 ]
138 ]
139
139
140 diffwsopts = [
140 diffwsopts = [
141 ('w', 'ignore-all-space', None,
141 ('w', 'ignore-all-space', None,
142 _('ignore white space when comparing lines')),
142 _('ignore white space when comparing lines')),
143 ('b', 'ignore-space-change', None,
143 ('b', 'ignore-space-change', None,
144 _('ignore changes in the amount of white space')),
144 _('ignore changes in the amount of white space')),
145 ('B', 'ignore-blank-lines', None,
145 ('B', 'ignore-blank-lines', None,
146 _('ignore changes whose lines are all blank')),
146 _('ignore changes whose lines are all blank')),
147 ]
147 ]
148
148
149 diffopts2 = [
149 diffopts2 = [
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('p', 'show-function', None, _('show which function each change is in')),
151 ('p', 'show-function', None, _('show which function each change is in')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ] + diffwsopts + [
153 ] + diffwsopts + [
154 ('U', 'unified', '',
154 ('U', 'unified', '',
155 _('number of lines of context to show'), _('NUM')),
155 _('number of lines of context to show'), _('NUM')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ]
158 ]
159
159
160 mergetoolopts = [
160 mergetoolopts = [
161 ('t', 'tool', '', _('specify merge tool')),
161 ('t', 'tool', '', _('specify merge tool')),
162 ]
162 ]
163
163
164 similarityopts = [
164 similarityopts = [
165 ('s', 'similarity', '',
165 ('s', 'similarity', '',
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 ]
167 ]
168
168
169 subrepoopts = [
169 subrepoopts = [
170 ('S', 'subrepos', None,
170 ('S', 'subrepos', None,
171 _('recurse into subrepositories'))
171 _('recurse into subrepositories'))
172 ]
172 ]
173
173
174 # Commands start here, listed alphabetically
174 # Commands start here, listed alphabetically
175
175
176 @command('^add',
176 @command('^add',
177 walkopts + subrepoopts + dryrunopts,
177 walkopts + subrepoopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def add(ui, repo, *pats, **opts):
180 def add(ui, repo, *pats, **opts):
181 """add the specified files on the next commit
181 """add the specified files on the next commit
182
182
183 Schedule files to be version controlled and added to the
183 Schedule files to be version controlled and added to the
184 repository.
184 repository.
185
185
186 The files will be added to the repository at the next commit. To
186 The files will be added to the repository at the next commit. To
187 undo an add before that, see :hg:`forget`.
187 undo an add before that, see :hg:`forget`.
188
188
189 If no names are given, add all files to the repository.
189 If no names are given, add all files to the repository.
190
190
191 .. container:: verbose
191 .. container:: verbose
192
192
193 An example showing how new (unknown) files are added
193 An example showing how new (unknown) files are added
194 automatically by :hg:`add`::
194 automatically by :hg:`add`::
195
195
196 $ ls
196 $ ls
197 foo.c
197 foo.c
198 $ hg status
198 $ hg status
199 ? foo.c
199 ? foo.c
200 $ hg add
200 $ hg add
201 adding foo.c
201 adding foo.c
202 $ hg status
202 $ hg status
203 A foo.c
203 A foo.c
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207
207
208 m = scmutil.match(repo[None], pats, opts)
208 m = scmutil.match(repo[None], pats, opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
210 return rejected and 1 or 0
210 return rejected and 1 or 0
211
211
212 @command('addremove',
212 @command('addremove',
213 similarityopts + subrepoopts + walkopts + dryrunopts,
213 similarityopts + subrepoopts + walkopts + dryrunopts,
214 _('[OPTION]... [FILE]...'),
214 _('[OPTION]... [FILE]...'),
215 inferrepo=True)
215 inferrepo=True)
216 def addremove(ui, repo, *pats, **opts):
216 def addremove(ui, repo, *pats, **opts):
217 """add all new files, delete all missing files
217 """add all new files, delete all missing files
218
218
219 Add all new files and remove all missing files from the
219 Add all new files and remove all missing files from the
220 repository.
220 repository.
221
221
222 New files are ignored if they match any of the patterns in
222 New files are ignored if they match any of the patterns in
223 ``.hgignore``. As with add, these changes take effect at the next
223 ``.hgignore``. As with add, these changes take effect at the next
224 commit.
224 commit.
225
225
226 Use the -s/--similarity option to detect renamed files. This
226 Use the -s/--similarity option to detect renamed files. This
227 option takes a percentage between 0 (disabled) and 100 (files must
227 option takes a percentage between 0 (disabled) and 100 (files must
228 be identical) as its parameter. With a parameter greater than 0,
228 be identical) as its parameter. With a parameter greater than 0,
229 this compares every removed file with every added file and records
229 this compares every removed file with every added file and records
230 those similar enough as renames. Detecting renamed files this way
230 those similar enough as renames. Detecting renamed files this way
231 can be expensive. After using this option, :hg:`status -C` can be
231 can be expensive. After using this option, :hg:`status -C` can be
232 used to check which files were identified as moved or renamed. If
232 used to check which files were identified as moved or renamed. If
233 not specified, -s/--similarity defaults to 100 and only renames of
233 not specified, -s/--similarity defaults to 100 and only renames of
234 identical files are detected.
234 identical files are detected.
235
235
236 Returns 0 if all files are successfully added.
236 Returns 0 if all files are successfully added.
237 """
237 """
238 try:
238 try:
239 sim = float(opts.get('similarity') or 100)
239 sim = float(opts.get('similarity') or 100)
240 except ValueError:
240 except ValueError:
241 raise error.Abort(_('similarity must be a number'))
241 raise error.Abort(_('similarity must be a number'))
242 if sim < 0 or sim > 100:
242 if sim < 0 or sim > 100:
243 raise error.Abort(_('similarity must be between 0 and 100'))
243 raise error.Abort(_('similarity must be between 0 and 100'))
244 matcher = scmutil.match(repo[None], pats, opts)
244 matcher = scmutil.match(repo[None], pats, opts)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
246
246
247 @command('^annotate|blame',
247 @command('^annotate|blame',
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
249 ('', 'follow', None,
249 ('', 'follow', None,
250 _('follow copies/renames and list the filename (DEPRECATED)')),
250 _('follow copies/renames and list the filename (DEPRECATED)')),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
252 ('a', 'text', None, _('treat all files as text')),
252 ('a', 'text', None, _('treat all files as text')),
253 ('u', 'user', None, _('list the author (long with -v)')),
253 ('u', 'user', None, _('list the author (long with -v)')),
254 ('f', 'file', None, _('list the filename')),
254 ('f', 'file', None, _('list the filename')),
255 ('d', 'date', None, _('list the date (short with -q)')),
255 ('d', 'date', None, _('list the date (short with -q)')),
256 ('n', 'number', None, _('list the revision number (default)')),
256 ('n', 'number', None, _('list the revision number (default)')),
257 ('c', 'changeset', None, _('list the changeset')),
257 ('c', 'changeset', None, _('list the changeset')),
258 ('l', 'line-number', None, _('show line number at the first appearance'))
258 ('l', 'line-number', None, _('show line number at the first appearance'))
259 ] + diffwsopts + walkopts + formatteropts,
259 ] + diffwsopts + walkopts + formatteropts,
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
261 inferrepo=True)
261 inferrepo=True)
262 def annotate(ui, repo, *pats, **opts):
262 def annotate(ui, repo, *pats, **opts):
263 """show changeset information by line for each file
263 """show changeset information by line for each file
264
264
265 List changes in files, showing the revision id responsible for
265 List changes in files, showing the revision id responsible for
266 each line
266 each line
267
267
268 This command is useful for discovering when a change was made and
268 This command is useful for discovering when a change was made and
269 by whom.
269 by whom.
270
270
271 Without the -a/--text option, annotate will avoid processing files
271 Without the -a/--text option, annotate will avoid processing files
272 it detects as binary. With -a, annotate will annotate the file
272 it detects as binary. With -a, annotate will annotate the file
273 anyway, although the results will probably be neither useful
273 anyway, although the results will probably be neither useful
274 nor desirable.
274 nor desirable.
275
275
276 Returns 0 on success.
276 Returns 0 on success.
277 """
277 """
278 if not pats:
278 if not pats:
279 raise error.Abort(_('at least one filename or pattern is required'))
279 raise error.Abort(_('at least one filename or pattern is required'))
280
280
281 if opts.get('follow'):
281 if opts.get('follow'):
282 # --follow is deprecated and now just an alias for -f/--file
282 # --follow is deprecated and now just an alias for -f/--file
283 # to mimic the behavior of Mercurial before version 1.5
283 # to mimic the behavior of Mercurial before version 1.5
284 opts['file'] = True
284 opts['file'] = True
285
285
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
287
287
288 fm = ui.formatter('annotate', opts)
288 fm = ui.formatter('annotate', opts)
289 if ui.quiet:
289 if ui.quiet:
290 datefunc = util.shortdate
290 datefunc = util.shortdate
291 else:
291 else:
292 datefunc = util.datestr
292 datefunc = util.datestr
293 if ctx.rev() is None:
293 if ctx.rev() is None:
294 def hexfn(node):
294 def hexfn(node):
295 if node is None:
295 if node is None:
296 return None
296 return None
297 else:
297 else:
298 return fm.hexfunc(node)
298 return fm.hexfunc(node)
299 if opts.get('changeset'):
299 if opts.get('changeset'):
300 # omit "+" suffix which is appended to node hex
300 # omit "+" suffix which is appended to node hex
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 else:
306 else:
307 def formatrev(rev):
307 def formatrev(rev):
308 if rev is None:
308 if rev is None:
309 return '%d+' % ctx.p1().rev()
309 return '%d+' % ctx.p1().rev()
310 else:
310 else:
311 return '%d ' % rev
311 return '%d ' % rev
312 def formathex(hex):
312 def formathex(hex):
313 if hex is None:
313 if hex is None:
314 return '%s+' % fm.hexfunc(ctx.p1().node())
314 return '%s+' % fm.hexfunc(ctx.p1().node())
315 else:
315 else:
316 return '%s ' % hex
316 return '%s ' % hex
317 else:
317 else:
318 hexfn = fm.hexfunc
318 hexfn = fm.hexfunc
319 formatrev = formathex = str
319 formatrev = formathex = str
320
320
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
325 ('file', ' ', lambda x: x[0].path(), str),
325 ('file', ' ', lambda x: x[0].path(), str),
326 ('line_number', ':', lambda x: x[1], str),
326 ('line_number', ':', lambda x: x[1], str),
327 ]
327 ]
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
329
329
330 if (not opts.get('user') and not opts.get('changeset')
330 if (not opts.get('user') and not opts.get('changeset')
331 and not opts.get('date') and not opts.get('file')):
331 and not opts.get('date') and not opts.get('file')):
332 opts['number'] = True
332 opts['number'] = True
333
333
334 linenumber = opts.get('line_number') is not None
334 linenumber = opts.get('line_number') is not None
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
336 raise error.Abort(_('at least one of -n/-c is required for -l'))
336 raise error.Abort(_('at least one of -n/-c is required for -l'))
337
337
338 if fm:
338 if fm:
339 def makefunc(get, fmt):
339 def makefunc(get, fmt):
340 return get
340 return get
341 else:
341 else:
342 def makefunc(get, fmt):
342 def makefunc(get, fmt):
343 return lambda x: fmt(get(x))
343 return lambda x: fmt(get(x))
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
345 if opts.get(op)]
345 if opts.get(op)]
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
348 if opts.get(op))
348 if opts.get(op))
349
349
350 def bad(x, y):
350 def bad(x, y):
351 raise error.Abort("%s: %s" % (x, y))
351 raise error.Abort("%s: %s" % (x, y))
352
352
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
354
354
355 follow = not opts.get('no_follow')
355 follow = not opts.get('no_follow')
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
357 whitespace=True)
357 whitespace=True)
358 for abs in ctx.walk(m):
358 for abs in ctx.walk(m):
359 fctx = ctx[abs]
359 fctx = ctx[abs]
360 if not opts.get('text') and util.binary(fctx.data()):
360 if not opts.get('text') and util.binary(fctx.data()):
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
362 continue
362 continue
363
363
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
365 diffopts=diffopts)
365 diffopts=diffopts)
366 formats = []
366 formats = []
367 pieces = []
367 pieces = []
368
368
369 for f, sep in funcmap:
369 for f, sep in funcmap:
370 l = [f(n) for n, dummy in lines]
370 l = [f(n) for n, dummy in lines]
371 if l:
371 if l:
372 if fm:
372 if fm:
373 formats.append(['%s' for x in l])
373 formats.append(['%s' for x in l])
374 else:
374 else:
375 sizes = [encoding.colwidth(x) for x in l]
375 sizes = [encoding.colwidth(x) for x in l]
376 ml = max(sizes)
376 ml = max(sizes)
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
378 pieces.append(l)
378 pieces.append(l)
379
379
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
381 fm.startitem()
381 fm.startitem()
382 fm.write(fields, "".join(f), *p)
382 fm.write(fields, "".join(f), *p)
383 fm.write('line', ": %s", l[1])
383 fm.write('line', ": %s", l[1])
384
384
385 if lines and not lines[-1][1].endswith('\n'):
385 if lines and not lines[-1][1].endswith('\n'):
386 fm.plain('\n')
386 fm.plain('\n')
387
387
388 fm.end()
388 fm.end()
389
389
390 @command('archive',
390 @command('archive',
391 [('', 'no-decode', None, _('do not pass files through decoders')),
391 [('', 'no-decode', None, _('do not pass files through decoders')),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
393 _('PREFIX')),
393 _('PREFIX')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
396 ] + subrepoopts + walkopts,
396 ] + subrepoopts + walkopts,
397 _('[OPTION]... DEST'))
397 _('[OPTION]... DEST'))
398 def archive(ui, repo, dest, **opts):
398 def archive(ui, repo, dest, **opts):
399 '''create an unversioned archive of a repository revision
399 '''create an unversioned archive of a repository revision
400
400
401 By default, the revision used is the parent of the working
401 By default, the revision used is the parent of the working
402 directory; use -r/--rev to specify a different revision.
402 directory; use -r/--rev to specify a different revision.
403
403
404 The archive type is automatically detected based on file
404 The archive type is automatically detected based on file
405 extension (or override using -t/--type).
405 extension (or override using -t/--type).
406
406
407 .. container:: verbose
407 .. container:: verbose
408
408
409 Examples:
409 Examples:
410
410
411 - create a zip file containing the 1.0 release::
411 - create a zip file containing the 1.0 release::
412
412
413 hg archive -r 1.0 project-1.0.zip
413 hg archive -r 1.0 project-1.0.zip
414
414
415 - create a tarball excluding .hg files::
415 - create a tarball excluding .hg files::
416
416
417 hg archive project.tar.gz -X ".hg*"
417 hg archive project.tar.gz -X ".hg*"
418
418
419 Valid types are:
419 Valid types are:
420
420
421 :``files``: a directory full of files (default)
421 :``files``: a directory full of files (default)
422 :``tar``: tar archive, uncompressed
422 :``tar``: tar archive, uncompressed
423 :``tbz2``: tar archive, compressed using bzip2
423 :``tbz2``: tar archive, compressed using bzip2
424 :``tgz``: tar archive, compressed using gzip
424 :``tgz``: tar archive, compressed using gzip
425 :``uzip``: zip archive, uncompressed
425 :``uzip``: zip archive, uncompressed
426 :``zip``: zip archive, compressed using deflate
426 :``zip``: zip archive, compressed using deflate
427
427
428 The exact name of the destination archive or directory is given
428 The exact name of the destination archive or directory is given
429 using a format string; see :hg:`help export` for details.
429 using a format string; see :hg:`help export` for details.
430
430
431 Each member added to an archive file has a directory prefix
431 Each member added to an archive file has a directory prefix
432 prepended. Use -p/--prefix to specify a format string for the
432 prepended. Use -p/--prefix to specify a format string for the
433 prefix. The default is the basename of the archive, with suffixes
433 prefix. The default is the basename of the archive, with suffixes
434 removed.
434 removed.
435
435
436 Returns 0 on success.
436 Returns 0 on success.
437 '''
437 '''
438
438
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
440 if not ctx:
440 if not ctx:
441 raise error.Abort(_('no working directory: please specify a revision'))
441 raise error.Abort(_('no working directory: please specify a revision'))
442 node = ctx.node()
442 node = ctx.node()
443 dest = cmdutil.makefilename(repo, dest, node)
443 dest = cmdutil.makefilename(repo, dest, node)
444 if os.path.realpath(dest) == repo.root:
444 if os.path.realpath(dest) == repo.root:
445 raise error.Abort(_('repository root cannot be destination'))
445 raise error.Abort(_('repository root cannot be destination'))
446
446
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
448 prefix = opts.get('prefix')
448 prefix = opts.get('prefix')
449
449
450 if dest == '-':
450 if dest == '-':
451 if kind == 'files':
451 if kind == 'files':
452 raise error.Abort(_('cannot archive plain files to stdout'))
452 raise error.Abort(_('cannot archive plain files to stdout'))
453 dest = cmdutil.makefileobj(repo, dest)
453 dest = cmdutil.makefileobj(repo, dest)
454 if not prefix:
454 if not prefix:
455 prefix = os.path.basename(repo.root) + '-%h'
455 prefix = os.path.basename(repo.root) + '-%h'
456
456
457 prefix = cmdutil.makefilename(repo, prefix, node)
457 prefix = cmdutil.makefilename(repo, prefix, node)
458 matchfn = scmutil.match(ctx, [], opts)
458 matchfn = scmutil.match(ctx, [], opts)
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
460 matchfn, prefix, subrepos=opts.get('subrepos'))
460 matchfn, prefix, subrepos=opts.get('subrepos'))
461
461
462 @command('backout',
462 @command('backout',
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
465 ('', 'parent', '',
465 ('', 'parent', '',
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
470 _('[OPTION]... [-r] REV'))
470 _('[OPTION]... [-r] REV'))
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
472 '''reverse effect of earlier changeset
472 '''reverse effect of earlier changeset
473
473
474 Prepare a new changeset with the effect of REV undone in the
474 Prepare a new changeset with the effect of REV undone in the
475 current working directory.
475 current working directory.
476
476
477 If REV is the parent of the working directory, then this new changeset
477 If REV is the parent of the working directory, then this new changeset
478 is committed automatically. Otherwise, hg needs to merge the
478 is committed automatically. Otherwise, hg needs to merge the
479 changes and the merged result is left uncommitted.
479 changes and the merged result is left uncommitted.
480
480
481 .. note::
481 .. note::
482
482
483 backout cannot be used to fix either an unwanted or
483 backout cannot be used to fix either an unwanted or
484 incorrect merge.
484 incorrect merge.
485
485
486 .. container:: verbose
486 .. container:: verbose
487
487
488 By default, the pending changeset will have one parent,
488 By default, the pending changeset will have one parent,
489 maintaining a linear history. With --merge, the pending
489 maintaining a linear history. With --merge, the pending
490 changeset will instead have two parents: the old parent of the
490 changeset will instead have two parents: the old parent of the
491 working directory and a new child of REV that simply undoes REV.
491 working directory and a new child of REV that simply undoes REV.
492
492
493 Before version 1.7, the behavior without --merge was equivalent
493 Before version 1.7, the behavior without --merge was equivalent
494 to specifying --merge followed by :hg:`update --clean .` to
494 to specifying --merge followed by :hg:`update --clean .` to
495 cancel the merge and leave the child of REV as a head to be
495 cancel the merge and leave the child of REV as a head to be
496 merged separately.
496 merged separately.
497
497
498 See :hg:`help dates` for a list of formats valid for -d/--date.
498 See :hg:`help dates` for a list of formats valid for -d/--date.
499
499
500 See :hg:`help revert` for a way to restore files to the state
500 See :hg:`help revert` for a way to restore files to the state
501 of another revision.
501 of another revision.
502
502
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
504 files.
504 files.
505 '''
505 '''
506 if rev and node:
506 if rev and node:
507 raise error.Abort(_("please specify just one revision"))
507 raise error.Abort(_("please specify just one revision"))
508
508
509 if not rev:
509 if not rev:
510 rev = node
510 rev = node
511
511
512 if not rev:
512 if not rev:
513 raise error.Abort(_("please specify a revision to backout"))
513 raise error.Abort(_("please specify a revision to backout"))
514
514
515 date = opts.get('date')
515 date = opts.get('date')
516 if date:
516 if date:
517 opts['date'] = util.parsedate(date)
517 opts['date'] = util.parsedate(date)
518
518
519 cmdutil.checkunfinished(repo)
519 cmdutil.checkunfinished(repo)
520 cmdutil.bailifchanged(repo)
520 cmdutil.bailifchanged(repo)
521 node = scmutil.revsingle(repo, rev).node()
521 node = scmutil.revsingle(repo, rev).node()
522
522
523 op1, op2 = repo.dirstate.parents()
523 op1, op2 = repo.dirstate.parents()
524 if not repo.changelog.isancestor(node, op1):
524 if not repo.changelog.isancestor(node, op1):
525 raise error.Abort(_('cannot backout change that is not an ancestor'))
525 raise error.Abort(_('cannot backout change that is not an ancestor'))
526
526
527 p1, p2 = repo.changelog.parents(node)
527 p1, p2 = repo.changelog.parents(node)
528 if p1 == nullid:
528 if p1 == nullid:
529 raise error.Abort(_('cannot backout a change with no parents'))
529 raise error.Abort(_('cannot backout a change with no parents'))
530 if p2 != nullid:
530 if p2 != nullid:
531 if not opts.get('parent'):
531 if not opts.get('parent'):
532 raise error.Abort(_('cannot backout a merge changeset'))
532 raise error.Abort(_('cannot backout a merge changeset'))
533 p = repo.lookup(opts['parent'])
533 p = repo.lookup(opts['parent'])
534 if p not in (p1, p2):
534 if p not in (p1, p2):
535 raise error.Abort(_('%s is not a parent of %s') %
535 raise error.Abort(_('%s is not a parent of %s') %
536 (short(p), short(node)))
536 (short(p), short(node)))
537 parent = p
537 parent = p
538 else:
538 else:
539 if opts.get('parent'):
539 if opts.get('parent'):
540 raise error.Abort(_('cannot use --parent on non-merge changeset'))
540 raise error.Abort(_('cannot use --parent on non-merge changeset'))
541 parent = p1
541 parent = p1
542
542
543 # the backout should appear on the same branch
543 # the backout should appear on the same branch
544 wlock = repo.wlock()
544 wlock = repo.wlock()
545 try:
545 try:
546 branch = repo.dirstate.branch()
546 branch = repo.dirstate.branch()
547 bheads = repo.branchheads(branch)
547 bheads = repo.branchheads(branch)
548 rctx = scmutil.revsingle(repo, hex(parent))
548 rctx = scmutil.revsingle(repo, hex(parent))
549 if not opts.get('merge') and op1 != node:
549 if not opts.get('merge') and op1 != node:
550 dsguard = cmdutil.dirstateguard(repo, 'backout')
550 dsguard = cmdutil.dirstateguard(repo, 'backout')
551 try:
551 try:
552 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
552 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
553 'backout')
553 'backout')
554 stats = mergemod.update(repo, parent, True, True, False,
554 stats = mergemod.update(repo, parent, True, True, False,
555 node, False)
555 node, False)
556 repo.setparents(op1, op2)
556 repo.setparents(op1, op2)
557 dsguard.close()
557 dsguard.close()
558 hg._showstats(repo, stats)
558 hg._showstats(repo, stats)
559 if stats[3]:
559 if stats[3]:
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
561 "file merges\n"))
561 "file merges\n"))
562 return 1
562 return 1
563 elif not commit:
563 elif not commit:
564 msg = _("changeset %s backed out, "
564 msg = _("changeset %s backed out, "
565 "don't forget to commit.\n")
565 "don't forget to commit.\n")
566 ui.status(msg % short(node))
566 ui.status(msg % short(node))
567 return 0
567 return 0
568 finally:
568 finally:
569 ui.setconfig('ui', 'forcemerge', '', '')
569 ui.setconfig('ui', 'forcemerge', '', '')
570 lockmod.release(dsguard)
570 lockmod.release(dsguard)
571 else:
571 else:
572 hg.clean(repo, node, show_stats=False)
572 hg.clean(repo, node, show_stats=False)
573 repo.dirstate.setbranch(branch)
573 repo.dirstate.setbranch(branch)
574 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
574 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
575
575
576
576
577 def commitfunc(ui, repo, message, match, opts):
577 def commitfunc(ui, repo, message, match, opts):
578 editform = 'backout'
578 editform = 'backout'
579 e = cmdutil.getcommiteditor(editform=editform, **opts)
579 e = cmdutil.getcommiteditor(editform=editform, **opts)
580 if not message:
580 if not message:
581 # we don't translate commit messages
581 # we don't translate commit messages
582 message = "Backed out changeset %s" % short(node)
582 message = "Backed out changeset %s" % short(node)
583 e = cmdutil.getcommiteditor(edit=True, editform=editform)
583 e = cmdutil.getcommiteditor(edit=True, editform=editform)
584 return repo.commit(message, opts.get('user'), opts.get('date'),
584 return repo.commit(message, opts.get('user'), opts.get('date'),
585 match, editor=e)
585 match, editor=e)
586 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
586 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
587 if not newnode:
587 if not newnode:
588 ui.status(_("nothing changed\n"))
588 ui.status(_("nothing changed\n"))
589 return 1
589 return 1
590 cmdutil.commitstatus(repo, newnode, branch, bheads)
590 cmdutil.commitstatus(repo, newnode, branch, bheads)
591
591
592 def nice(node):
592 def nice(node):
593 return '%d:%s' % (repo.changelog.rev(node), short(node))
593 return '%d:%s' % (repo.changelog.rev(node), short(node))
594 ui.status(_('changeset %s backs out changeset %s\n') %
594 ui.status(_('changeset %s backs out changeset %s\n') %
595 (nice(repo.changelog.tip()), nice(node)))
595 (nice(repo.changelog.tip()), nice(node)))
596 if opts.get('merge') and op1 != node:
596 if opts.get('merge') and op1 != node:
597 hg.clean(repo, op1, show_stats=False)
597 hg.clean(repo, op1, show_stats=False)
598 ui.status(_('merging with changeset %s\n')
598 ui.status(_('merging with changeset %s\n')
599 % nice(repo.changelog.tip()))
599 % nice(repo.changelog.tip()))
600 try:
600 try:
601 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
601 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
602 'backout')
602 'backout')
603 return hg.merge(repo, hex(repo.changelog.tip()))
603 return hg.merge(repo, hex(repo.changelog.tip()))
604 finally:
604 finally:
605 ui.setconfig('ui', 'forcemerge', '', '')
605 ui.setconfig('ui', 'forcemerge', '', '')
606 finally:
606 finally:
607 wlock.release()
607 wlock.release()
608 return 0
608 return 0
609
609
610 @command('bisect',
610 @command('bisect',
611 [('r', 'reset', False, _('reset bisect state')),
611 [('r', 'reset', False, _('reset bisect state')),
612 ('g', 'good', False, _('mark changeset good')),
612 ('g', 'good', False, _('mark changeset good')),
613 ('b', 'bad', False, _('mark changeset bad')),
613 ('b', 'bad', False, _('mark changeset bad')),
614 ('s', 'skip', False, _('skip testing changeset')),
614 ('s', 'skip', False, _('skip testing changeset')),
615 ('e', 'extend', False, _('extend the bisect range')),
615 ('e', 'extend', False, _('extend the bisect range')),
616 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
616 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
617 ('U', 'noupdate', False, _('do not update to target'))],
617 ('U', 'noupdate', False, _('do not update to target'))],
618 _("[-gbsr] [-U] [-c CMD] [REV]"))
618 _("[-gbsr] [-U] [-c CMD] [REV]"))
619 def bisect(ui, repo, rev=None, extra=None, command=None,
619 def bisect(ui, repo, rev=None, extra=None, command=None,
620 reset=None, good=None, bad=None, skip=None, extend=None,
620 reset=None, good=None, bad=None, skip=None, extend=None,
621 noupdate=None):
621 noupdate=None):
622 """subdivision search of changesets
622 """subdivision search of changesets
623
623
624 This command helps to find changesets which introduce problems. To
624 This command helps to find changesets which introduce problems. To
625 use, mark the earliest changeset you know exhibits the problem as
625 use, mark the earliest changeset you know exhibits the problem as
626 bad, then mark the latest changeset which is free from the problem
626 bad, then mark the latest changeset which is free from the problem
627 as good. Bisect will update your working directory to a revision
627 as good. Bisect will update your working directory to a revision
628 for testing (unless the -U/--noupdate option is specified). Once
628 for testing (unless the -U/--noupdate option is specified). Once
629 you have performed tests, mark the working directory as good or
629 you have performed tests, mark the working directory as good or
630 bad, and bisect will either update to another candidate changeset
630 bad, and bisect will either update to another candidate changeset
631 or announce that it has found the bad revision.
631 or announce that it has found the bad revision.
632
632
633 As a shortcut, you can also use the revision argument to mark a
633 As a shortcut, you can also use the revision argument to mark a
634 revision as good or bad without checking it out first.
634 revision as good or bad without checking it out first.
635
635
636 If you supply a command, it will be used for automatic bisection.
636 If you supply a command, it will be used for automatic bisection.
637 The environment variable HG_NODE will contain the ID of the
637 The environment variable HG_NODE will contain the ID of the
638 changeset being tested. The exit status of the command will be
638 changeset being tested. The exit status of the command will be
639 used to mark revisions as good or bad: status 0 means good, 125
639 used to mark revisions as good or bad: status 0 means good, 125
640 means to skip the revision, 127 (command not found) will abort the
640 means to skip the revision, 127 (command not found) will abort the
641 bisection, and any other non-zero exit status means the revision
641 bisection, and any other non-zero exit status means the revision
642 is bad.
642 is bad.
643
643
644 .. container:: verbose
644 .. container:: verbose
645
645
646 Some examples:
646 Some examples:
647
647
648 - start a bisection with known bad revision 34, and good revision 12::
648 - start a bisection with known bad revision 34, and good revision 12::
649
649
650 hg bisect --bad 34
650 hg bisect --bad 34
651 hg bisect --good 12
651 hg bisect --good 12
652
652
653 - advance the current bisection by marking current revision as good or
653 - advance the current bisection by marking current revision as good or
654 bad::
654 bad::
655
655
656 hg bisect --good
656 hg bisect --good
657 hg bisect --bad
657 hg bisect --bad
658
658
659 - mark the current revision, or a known revision, to be skipped (e.g. if
659 - mark the current revision, or a known revision, to be skipped (e.g. if
660 that revision is not usable because of another issue)::
660 that revision is not usable because of another issue)::
661
661
662 hg bisect --skip
662 hg bisect --skip
663 hg bisect --skip 23
663 hg bisect --skip 23
664
664
665 - skip all revisions that do not touch directories ``foo`` or ``bar``::
665 - skip all revisions that do not touch directories ``foo`` or ``bar``::
666
666
667 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
667 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
668
668
669 - forget the current bisection::
669 - forget the current bisection::
670
670
671 hg bisect --reset
671 hg bisect --reset
672
672
673 - use 'make && make tests' to automatically find the first broken
673 - use 'make && make tests' to automatically find the first broken
674 revision::
674 revision::
675
675
676 hg bisect --reset
676 hg bisect --reset
677 hg bisect --bad 34
677 hg bisect --bad 34
678 hg bisect --good 12
678 hg bisect --good 12
679 hg bisect --command "make && make tests"
679 hg bisect --command "make && make tests"
680
680
681 - see all changesets whose states are already known in the current
681 - see all changesets whose states are already known in the current
682 bisection::
682 bisection::
683
683
684 hg log -r "bisect(pruned)"
684 hg log -r "bisect(pruned)"
685
685
686 - see the changeset currently being bisected (especially useful
686 - see the changeset currently being bisected (especially useful
687 if running with -U/--noupdate)::
687 if running with -U/--noupdate)::
688
688
689 hg log -r "bisect(current)"
689 hg log -r "bisect(current)"
690
690
691 - see all changesets that took part in the current bisection::
691 - see all changesets that took part in the current bisection::
692
692
693 hg log -r "bisect(range)"
693 hg log -r "bisect(range)"
694
694
695 - you can even get a nice graph::
695 - you can even get a nice graph::
696
696
697 hg log --graph -r "bisect(range)"
697 hg log --graph -r "bisect(range)"
698
698
699 See :hg:`help revsets` for more about the `bisect()` keyword.
699 See :hg:`help revsets` for more about the `bisect()` keyword.
700
700
701 Returns 0 on success.
701 Returns 0 on success.
702 """
702 """
703 def extendbisectrange(nodes, good):
703 def extendbisectrange(nodes, good):
704 # bisect is incomplete when it ends on a merge node and
704 # bisect is incomplete when it ends on a merge node and
705 # one of the parent was not checked.
705 # one of the parent was not checked.
706 parents = repo[nodes[0]].parents()
706 parents = repo[nodes[0]].parents()
707 if len(parents) > 1:
707 if len(parents) > 1:
708 if good:
708 if good:
709 side = state['bad']
709 side = state['bad']
710 else:
710 else:
711 side = state['good']
711 side = state['good']
712 num = len(set(i.node() for i in parents) & set(side))
712 num = len(set(i.node() for i in parents) & set(side))
713 if num == 1:
713 if num == 1:
714 return parents[0].ancestor(parents[1])
714 return parents[0].ancestor(parents[1])
715 return None
715 return None
716
716
717 def print_result(nodes, good):
717 def print_result(nodes, good):
718 displayer = cmdutil.show_changeset(ui, repo, {})
718 displayer = cmdutil.show_changeset(ui, repo, {})
719 if len(nodes) == 1:
719 if len(nodes) == 1:
720 # narrowed it down to a single revision
720 # narrowed it down to a single revision
721 if good:
721 if good:
722 ui.write(_("The first good revision is:\n"))
722 ui.write(_("The first good revision is:\n"))
723 else:
723 else:
724 ui.write(_("The first bad revision is:\n"))
724 ui.write(_("The first bad revision is:\n"))
725 displayer.show(repo[nodes[0]])
725 displayer.show(repo[nodes[0]])
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_('Not all ancestors of this changeset have been'
728 ui.write(_('Not all ancestors of this changeset have been'
729 ' checked.\nUse bisect --extend to continue the '
729 ' checked.\nUse bisect --extend to continue the '
730 'bisection from\nthe common ancestor, %s.\n')
730 'bisection from\nthe common ancestor, %s.\n')
731 % extendnode)
731 % extendnode)
732 else:
732 else:
733 # multiple possible revisions
733 # multiple possible revisions
734 if good:
734 if good:
735 ui.write(_("Due to skipped revisions, the first "
735 ui.write(_("Due to skipped revisions, the first "
736 "good revision could be any of:\n"))
736 "good revision could be any of:\n"))
737 else:
737 else:
738 ui.write(_("Due to skipped revisions, the first "
738 ui.write(_("Due to skipped revisions, the first "
739 "bad revision could be any of:\n"))
739 "bad revision could be any of:\n"))
740 for n in nodes:
740 for n in nodes:
741 displayer.show(repo[n])
741 displayer.show(repo[n])
742 displayer.close()
742 displayer.close()
743
743
744 def check_state(state, interactive=True):
744 def check_state(state, interactive=True):
745 if not state['good'] or not state['bad']:
745 if not state['good'] or not state['bad']:
746 if (good or bad or skip or reset) and interactive:
746 if (good or bad or skip or reset) and interactive:
747 return
747 return
748 if not state['good']:
748 if not state['good']:
749 raise error.Abort(_('cannot bisect (no known good revisions)'))
749 raise error.Abort(_('cannot bisect (no known good revisions)'))
750 else:
750 else:
751 raise error.Abort(_('cannot bisect (no known bad revisions)'))
751 raise error.Abort(_('cannot bisect (no known bad revisions)'))
752 return True
752 return True
753
753
754 # backward compatibility
754 # backward compatibility
755 if rev in "good bad reset init".split():
755 if rev in "good bad reset init".split():
756 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
756 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
757 cmd, rev, extra = rev, extra, None
757 cmd, rev, extra = rev, extra, None
758 if cmd == "good":
758 if cmd == "good":
759 good = True
759 good = True
760 elif cmd == "bad":
760 elif cmd == "bad":
761 bad = True
761 bad = True
762 else:
762 else:
763 reset = True
763 reset = True
764 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
764 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
765 raise error.Abort(_('incompatible arguments'))
765 raise error.Abort(_('incompatible arguments'))
766
766
767 cmdutil.checkunfinished(repo)
767 cmdutil.checkunfinished(repo)
768
768
769 if reset:
769 if reset:
770 p = repo.join("bisect.state")
770 p = repo.join("bisect.state")
771 if os.path.exists(p):
771 if os.path.exists(p):
772 os.unlink(p)
772 os.unlink(p)
773 return
773 return
774
774
775 state = hbisect.load_state(repo)
775 state = hbisect.load_state(repo)
776
776
777 if command:
777 if command:
778 changesets = 1
778 changesets = 1
779 if noupdate:
779 if noupdate:
780 try:
780 try:
781 node = state['current'][0]
781 node = state['current'][0]
782 except LookupError:
782 except LookupError:
783 raise error.Abort(_('current bisect revision is unknown - '
783 raise error.Abort(_('current bisect revision is unknown - '
784 'start a new bisect to fix'))
784 'start a new bisect to fix'))
785 else:
785 else:
786 node, p2 = repo.dirstate.parents()
786 node, p2 = repo.dirstate.parents()
787 if p2 != nullid:
787 if p2 != nullid:
788 raise error.Abort(_('current bisect revision is a merge'))
788 raise error.Abort(_('current bisect revision is a merge'))
789 try:
789 try:
790 while changesets:
790 while changesets:
791 # update state
791 # update state
792 state['current'] = [node]
792 state['current'] = [node]
793 hbisect.save_state(repo, state)
793 hbisect.save_state(repo, state)
794 status = ui.system(command, environ={'HG_NODE': hex(node)})
794 status = ui.system(command, environ={'HG_NODE': hex(node)})
795 if status == 125:
795 if status == 125:
796 transition = "skip"
796 transition = "skip"
797 elif status == 0:
797 elif status == 0:
798 transition = "good"
798 transition = "good"
799 # status < 0 means process was killed
799 # status < 0 means process was killed
800 elif status == 127:
800 elif status == 127:
801 raise error.Abort(_("failed to execute %s") % command)
801 raise error.Abort(_("failed to execute %s") % command)
802 elif status < 0:
802 elif status < 0:
803 raise error.Abort(_("%s killed") % command)
803 raise error.Abort(_("%s killed") % command)
804 else:
804 else:
805 transition = "bad"
805 transition = "bad"
806 ctx = scmutil.revsingle(repo, rev, node)
806 ctx = scmutil.revsingle(repo, rev, node)
807 rev = None # clear for future iterations
807 rev = None # clear for future iterations
808 state[transition].append(ctx.node())
808 state[transition].append(ctx.node())
809 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
809 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
810 check_state(state, interactive=False)
810 check_state(state, interactive=False)
811 # bisect
811 # bisect
812 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
812 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
813 # update to next check
813 # update to next check
814 node = nodes[0]
814 node = nodes[0]
815 if not noupdate:
815 if not noupdate:
816 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
817 hg.clean(repo, node, show_stats=False)
817 hg.clean(repo, node, show_stats=False)
818 finally:
818 finally:
819 state['current'] = [node]
819 state['current'] = [node]
820 hbisect.save_state(repo, state)
820 hbisect.save_state(repo, state)
821 print_result(nodes, bgood)
821 print_result(nodes, bgood)
822 return
822 return
823
823
824 # update state
824 # update state
825
825
826 if rev:
826 if rev:
827 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
827 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
828 else:
828 else:
829 nodes = [repo.lookup('.')]
829 nodes = [repo.lookup('.')]
830
830
831 if good or bad or skip:
831 if good or bad or skip:
832 if good:
832 if good:
833 state['good'] += nodes
833 state['good'] += nodes
834 elif bad:
834 elif bad:
835 state['bad'] += nodes
835 state['bad'] += nodes
836 elif skip:
836 elif skip:
837 state['skip'] += nodes
837 state['skip'] += nodes
838 hbisect.save_state(repo, state)
838 hbisect.save_state(repo, state)
839
839
840 if not check_state(state):
840 if not check_state(state):
841 return
841 return
842
842
843 # actually bisect
843 # actually bisect
844 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
844 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
845 if extend:
845 if extend:
846 if not changesets:
846 if not changesets:
847 extendnode = extendbisectrange(nodes, good)
847 extendnode = extendbisectrange(nodes, good)
848 if extendnode is not None:
848 if extendnode is not None:
849 ui.write(_("Extending search to changeset %d:%s\n")
849 ui.write(_("Extending search to changeset %d:%s\n")
850 % (extendnode.rev(), extendnode))
850 % (extendnode.rev(), extendnode))
851 state['current'] = [extendnode.node()]
851 state['current'] = [extendnode.node()]
852 hbisect.save_state(repo, state)
852 hbisect.save_state(repo, state)
853 if noupdate:
853 if noupdate:
854 return
854 return
855 cmdutil.bailifchanged(repo)
855 cmdutil.bailifchanged(repo)
856 return hg.clean(repo, extendnode.node())
856 return hg.clean(repo, extendnode.node())
857 raise error.Abort(_("nothing to extend"))
857 raise error.Abort(_("nothing to extend"))
858
858
859 if changesets == 0:
859 if changesets == 0:
860 print_result(nodes, good)
860 print_result(nodes, good)
861 else:
861 else:
862 assert len(nodes) == 1 # only a single node can be tested next
862 assert len(nodes) == 1 # only a single node can be tested next
863 node = nodes[0]
863 node = nodes[0]
864 # compute the approximate number of remaining tests
864 # compute the approximate number of remaining tests
865 tests, size = 0, 2
865 tests, size = 0, 2
866 while size <= changesets:
866 while size <= changesets:
867 tests, size = tests + 1, size * 2
867 tests, size = tests + 1, size * 2
868 rev = repo.changelog.rev(node)
868 rev = repo.changelog.rev(node)
869 ui.write(_("Testing changeset %d:%s "
869 ui.write(_("Testing changeset %d:%s "
870 "(%d changesets remaining, ~%d tests)\n")
870 "(%d changesets remaining, ~%d tests)\n")
871 % (rev, short(node), changesets, tests))
871 % (rev, short(node), changesets, tests))
872 state['current'] = [node]
872 state['current'] = [node]
873 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
874 if not noupdate:
874 if not noupdate:
875 cmdutil.bailifchanged(repo)
875 cmdutil.bailifchanged(repo)
876 return hg.clean(repo, node)
876 return hg.clean(repo, node)
877
877
878 @command('bookmarks|bookmark',
878 @command('bookmarks|bookmark',
879 [('f', 'force', False, _('force')),
879 [('f', 'force', False, _('force')),
880 ('r', 'rev', '', _('revision'), _('REV')),
880 ('r', 'rev', '', _('revision'), _('REV')),
881 ('d', 'delete', False, _('delete a given bookmark')),
881 ('d', 'delete', False, _('delete a given bookmark')),
882 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
882 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
883 ('i', 'inactive', False, _('mark a bookmark inactive')),
883 ('i', 'inactive', False, _('mark a bookmark inactive')),
884 ] + formatteropts,
884 ] + formatteropts,
885 _('hg bookmarks [OPTIONS]... [NAME]...'))
885 _('hg bookmarks [OPTIONS]... [NAME]...'))
886 def bookmark(ui, repo, *names, **opts):
886 def bookmark(ui, repo, *names, **opts):
887 '''create a new bookmark or list existing bookmarks
887 '''create a new bookmark or list existing bookmarks
888
888
889 Bookmarks are labels on changesets to help track lines of development.
889 Bookmarks are labels on changesets to help track lines of development.
890 Bookmarks are unversioned and can be moved, renamed and deleted.
890 Bookmarks are unversioned and can be moved, renamed and deleted.
891 Deleting or moving a bookmark has no effect on the associated changesets.
891 Deleting or moving a bookmark has no effect on the associated changesets.
892
892
893 Creating or updating to a bookmark causes it to be marked as 'active'.
893 Creating or updating to a bookmark causes it to be marked as 'active'.
894 The active bookmark is indicated with a '*'.
894 The active bookmark is indicated with a '*'.
895 When a commit is made, the active bookmark will advance to the new commit.
895 When a commit is made, the active bookmark will advance to the new commit.
896 A plain :hg:`update` will also advance an active bookmark, if possible.
896 A plain :hg:`update` will also advance an active bookmark, if possible.
897 Updating away from a bookmark will cause it to be deactivated.
897 Updating away from a bookmark will cause it to be deactivated.
898
898
899 Bookmarks can be pushed and pulled between repositories (see
899 Bookmarks can be pushed and pulled between repositories (see
900 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
900 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
901 diverged, a new 'divergent bookmark' of the form 'name@path' will
901 diverged, a new 'divergent bookmark' of the form 'name@path' will
902 be created. Using :hg:`merge` will resolve the divergence.
902 be created. Using :hg:`merge` will resolve the divergence.
903
903
904 A bookmark named '@' has the special property that :hg:`clone` will
904 A bookmark named '@' has the special property that :hg:`clone` will
905 check it out by default if it exists.
905 check it out by default if it exists.
906
906
907 .. container:: verbose
907 .. container:: verbose
908
908
909 Examples:
909 Examples:
910
910
911 - create an active bookmark for a new line of development::
911 - create an active bookmark for a new line of development::
912
912
913 hg book new-feature
913 hg book new-feature
914
914
915 - create an inactive bookmark as a place marker::
915 - create an inactive bookmark as a place marker::
916
916
917 hg book -i reviewed
917 hg book -i reviewed
918
918
919 - create an inactive bookmark on another changeset::
919 - create an inactive bookmark on another changeset::
920
920
921 hg book -r .^ tested
921 hg book -r .^ tested
922
922
923 - rename bookmark turkey to dinner::
923 - rename bookmark turkey to dinner::
924
924
925 hg book -m turkey dinner
925 hg book -m turkey dinner
926
926
927 - move the '@' bookmark from another branch::
927 - move the '@' bookmark from another branch::
928
928
929 hg book -f @
929 hg book -f @
930 '''
930 '''
931 force = opts.get('force')
931 force = opts.get('force')
932 rev = opts.get('rev')
932 rev = opts.get('rev')
933 delete = opts.get('delete')
933 delete = opts.get('delete')
934 rename = opts.get('rename')
934 rename = opts.get('rename')
935 inactive = opts.get('inactive')
935 inactive = opts.get('inactive')
936
936
937 def checkformat(mark):
937 def checkformat(mark):
938 mark = mark.strip()
938 mark = mark.strip()
939 if not mark:
939 if not mark:
940 raise error.Abort(_("bookmark names cannot consist entirely of "
940 raise error.Abort(_("bookmark names cannot consist entirely of "
941 "whitespace"))
941 "whitespace"))
942 scmutil.checknewlabel(repo, mark, 'bookmark')
942 scmutil.checknewlabel(repo, mark, 'bookmark')
943 return mark
943 return mark
944
944
945 def checkconflict(repo, mark, cur, force=False, target=None):
945 def checkconflict(repo, mark, cur, force=False, target=None):
946 if mark in marks and not force:
946 if mark in marks and not force:
947 if target:
947 if target:
948 if marks[mark] == target and target == cur:
948 if marks[mark] == target and target == cur:
949 # re-activating a bookmark
949 # re-activating a bookmark
950 return
950 return
951 anc = repo.changelog.ancestors([repo[target].rev()])
951 anc = repo.changelog.ancestors([repo[target].rev()])
952 bmctx = repo[marks[mark]]
952 bmctx = repo[marks[mark]]
953 divs = [repo[b].node() for b in marks
953 divs = [repo[b].node() for b in marks
954 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
954 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
955
955
956 # allow resolving a single divergent bookmark even if moving
956 # allow resolving a single divergent bookmark even if moving
957 # the bookmark across branches when a revision is specified
957 # the bookmark across branches when a revision is specified
958 # that contains a divergent bookmark
958 # that contains a divergent bookmark
959 if bmctx.rev() not in anc and target in divs:
959 if bmctx.rev() not in anc and target in divs:
960 bookmarks.deletedivergent(repo, [target], mark)
960 bookmarks.deletedivergent(repo, [target], mark)
961 return
961 return
962
962
963 deletefrom = [b for b in divs
963 deletefrom = [b for b in divs
964 if repo[b].rev() in anc or b == target]
964 if repo[b].rev() in anc or b == target]
965 bookmarks.deletedivergent(repo, deletefrom, mark)
965 bookmarks.deletedivergent(repo, deletefrom, mark)
966 if bookmarks.validdest(repo, bmctx, repo[target]):
966 if bookmarks.validdest(repo, bmctx, repo[target]):
967 ui.status(_("moving bookmark '%s' forward from %s\n") %
967 ui.status(_("moving bookmark '%s' forward from %s\n") %
968 (mark, short(bmctx.node())))
968 (mark, short(bmctx.node())))
969 return
969 return
970 raise error.Abort(_("bookmark '%s' already exists "
970 raise error.Abort(_("bookmark '%s' already exists "
971 "(use -f to force)") % mark)
971 "(use -f to force)") % mark)
972 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
972 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
973 and not force):
973 and not force):
974 raise error.Abort(
974 raise error.Abort(
975 _("a bookmark cannot have the name of an existing branch"))
975 _("a bookmark cannot have the name of an existing branch"))
976
976
977 if delete and rename:
977 if delete and rename:
978 raise error.Abort(_("--delete and --rename are incompatible"))
978 raise error.Abort(_("--delete and --rename are incompatible"))
979 if delete and rev:
979 if delete and rev:
980 raise error.Abort(_("--rev is incompatible with --delete"))
980 raise error.Abort(_("--rev is incompatible with --delete"))
981 if rename and rev:
981 if rename and rev:
982 raise error.Abort(_("--rev is incompatible with --rename"))
982 raise error.Abort(_("--rev is incompatible with --rename"))
983 if not names and (delete or rev):
983 if not names and (delete or rev):
984 raise error.Abort(_("bookmark name required"))
984 raise error.Abort(_("bookmark name required"))
985
985
986 if delete or rename or names or inactive:
986 if delete or rename or names or inactive:
987 wlock = lock = tr = None
987 wlock = lock = tr = None
988 try:
988 try:
989 wlock = repo.wlock()
989 wlock = repo.wlock()
990 lock = repo.lock()
990 lock = repo.lock()
991 cur = repo.changectx('.').node()
991 cur = repo.changectx('.').node()
992 marks = repo._bookmarks
992 marks = repo._bookmarks
993 if delete:
993 if delete:
994 tr = repo.transaction('bookmark')
994 tr = repo.transaction('bookmark')
995 for mark in names:
995 for mark in names:
996 if mark not in marks:
996 if mark not in marks:
997 raise error.Abort(_("bookmark '%s' does not exist") %
997 raise error.Abort(_("bookmark '%s' does not exist") %
998 mark)
998 mark)
999 if mark == repo._activebookmark:
999 if mark == repo._activebookmark:
1000 bookmarks.deactivate(repo)
1000 bookmarks.deactivate(repo)
1001 del marks[mark]
1001 del marks[mark]
1002
1002
1003 elif rename:
1003 elif rename:
1004 tr = repo.transaction('bookmark')
1004 tr = repo.transaction('bookmark')
1005 if not names:
1005 if not names:
1006 raise error.Abort(_("new bookmark name required"))
1006 raise error.Abort(_("new bookmark name required"))
1007 elif len(names) > 1:
1007 elif len(names) > 1:
1008 raise error.Abort(_("only one new bookmark name allowed"))
1008 raise error.Abort(_("only one new bookmark name allowed"))
1009 mark = checkformat(names[0])
1009 mark = checkformat(names[0])
1010 if rename not in marks:
1010 if rename not in marks:
1011 raise error.Abort(_("bookmark '%s' does not exist")
1011 raise error.Abort(_("bookmark '%s' does not exist")
1012 % rename)
1012 % rename)
1013 checkconflict(repo, mark, cur, force)
1013 checkconflict(repo, mark, cur, force)
1014 marks[mark] = marks[rename]
1014 marks[mark] = marks[rename]
1015 if repo._activebookmark == rename and not inactive:
1015 if repo._activebookmark == rename and not inactive:
1016 bookmarks.activate(repo, mark)
1016 bookmarks.activate(repo, mark)
1017 del marks[rename]
1017 del marks[rename]
1018 elif names:
1018 elif names:
1019 tr = repo.transaction('bookmark')
1019 tr = repo.transaction('bookmark')
1020 newact = None
1020 newact = None
1021 for mark in names:
1021 for mark in names:
1022 mark = checkformat(mark)
1022 mark = checkformat(mark)
1023 if newact is None:
1023 if newact is None:
1024 newact = mark
1024 newact = mark
1025 if inactive and mark == repo._activebookmark:
1025 if inactive and mark == repo._activebookmark:
1026 bookmarks.deactivate(repo)
1026 bookmarks.deactivate(repo)
1027 return
1027 return
1028 tgt = cur
1028 tgt = cur
1029 if rev:
1029 if rev:
1030 tgt = scmutil.revsingle(repo, rev).node()
1030 tgt = scmutil.revsingle(repo, rev).node()
1031 checkconflict(repo, mark, cur, force, tgt)
1031 checkconflict(repo, mark, cur, force, tgt)
1032 marks[mark] = tgt
1032 marks[mark] = tgt
1033 if not inactive and cur == marks[newact] and not rev:
1033 if not inactive and cur == marks[newact] and not rev:
1034 bookmarks.activate(repo, newact)
1034 bookmarks.activate(repo, newact)
1035 elif cur != tgt and newact == repo._activebookmark:
1035 elif cur != tgt and newact == repo._activebookmark:
1036 bookmarks.deactivate(repo)
1036 bookmarks.deactivate(repo)
1037 elif inactive:
1037 elif inactive:
1038 if len(marks) == 0:
1038 if len(marks) == 0:
1039 ui.status(_("no bookmarks set\n"))
1039 ui.status(_("no bookmarks set\n"))
1040 elif not repo._activebookmark:
1040 elif not repo._activebookmark:
1041 ui.status(_("no active bookmark\n"))
1041 ui.status(_("no active bookmark\n"))
1042 else:
1042 else:
1043 bookmarks.deactivate(repo)
1043 bookmarks.deactivate(repo)
1044 if tr is not None:
1044 if tr is not None:
1045 marks.recordchange(tr)
1045 marks.recordchange(tr)
1046 tr.close()
1046 tr.close()
1047 finally:
1047 finally:
1048 lockmod.release(tr, lock, wlock)
1048 lockmod.release(tr, lock, wlock)
1049 else: # show bookmarks
1049 else: # show bookmarks
1050 fm = ui.formatter('bookmarks', opts)
1050 fm = ui.formatter('bookmarks', opts)
1051 hexfn = fm.hexfunc
1051 hexfn = fm.hexfunc
1052 marks = repo._bookmarks
1052 marks = repo._bookmarks
1053 if len(marks) == 0 and not fm:
1053 if len(marks) == 0 and not fm:
1054 ui.status(_("no bookmarks set\n"))
1054 ui.status(_("no bookmarks set\n"))
1055 for bmark, n in sorted(marks.iteritems()):
1055 for bmark, n in sorted(marks.iteritems()):
1056 active = repo._activebookmark
1056 active = repo._activebookmark
1057 if bmark == active:
1057 if bmark == active:
1058 prefix, label = '*', activebookmarklabel
1058 prefix, label = '*', activebookmarklabel
1059 else:
1059 else:
1060 prefix, label = ' ', ''
1060 prefix, label = ' ', ''
1061
1061
1062 fm.startitem()
1062 fm.startitem()
1063 if not ui.quiet:
1063 if not ui.quiet:
1064 fm.plain(' %s ' % prefix, label=label)
1064 fm.plain(' %s ' % prefix, label=label)
1065 fm.write('bookmark', '%s', bmark, label=label)
1065 fm.write('bookmark', '%s', bmark, label=label)
1066 pad = " " * (25 - encoding.colwidth(bmark))
1066 pad = " " * (25 - encoding.colwidth(bmark))
1067 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1067 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1068 repo.changelog.rev(n), hexfn(n), label=label)
1068 repo.changelog.rev(n), hexfn(n), label=label)
1069 fm.data(active=(bmark == active))
1069 fm.data(active=(bmark == active))
1070 fm.plain('\n')
1070 fm.plain('\n')
1071 fm.end()
1071 fm.end()
1072
1072
1073 @command('branch',
1073 @command('branch',
1074 [('f', 'force', None,
1074 [('f', 'force', None,
1075 _('set branch name even if it shadows an existing branch')),
1075 _('set branch name even if it shadows an existing branch')),
1076 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1076 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1077 _('[-fC] [NAME]'))
1077 _('[-fC] [NAME]'))
1078 def branch(ui, repo, label=None, **opts):
1078 def branch(ui, repo, label=None, **opts):
1079 """set or show the current branch name
1079 """set or show the current branch name
1080
1080
1081 .. note::
1081 .. note::
1082
1082
1083 Branch names are permanent and global. Use :hg:`bookmark` to create a
1083 Branch names are permanent and global. Use :hg:`bookmark` to create a
1084 light-weight bookmark instead. See :hg:`help glossary` for more
1084 light-weight bookmark instead. See :hg:`help glossary` for more
1085 information about named branches and bookmarks.
1085 information about named branches and bookmarks.
1086
1086
1087 With no argument, show the current branch name. With one argument,
1087 With no argument, show the current branch name. With one argument,
1088 set the working directory branch name (the branch will not exist
1088 set the working directory branch name (the branch will not exist
1089 in the repository until the next commit). Standard practice
1089 in the repository until the next commit). Standard practice
1090 recommends that primary development take place on the 'default'
1090 recommends that primary development take place on the 'default'
1091 branch.
1091 branch.
1092
1092
1093 Unless -f/--force is specified, branch will not let you set a
1093 Unless -f/--force is specified, branch will not let you set a
1094 branch name that already exists.
1094 branch name that already exists.
1095
1095
1096 Use -C/--clean to reset the working directory branch to that of
1096 Use -C/--clean to reset the working directory branch to that of
1097 the parent of the working directory, negating a previous branch
1097 the parent of the working directory, negating a previous branch
1098 change.
1098 change.
1099
1099
1100 Use the command :hg:`update` to switch to an existing branch. Use
1100 Use the command :hg:`update` to switch to an existing branch. Use
1101 :hg:`commit --close-branch` to mark this branch head as closed.
1101 :hg:`commit --close-branch` to mark this branch head as closed.
1102 When all heads of the branch are closed, the branch will be
1102 When all heads of the branch are closed, the branch will be
1103 considered closed.
1103 considered closed.
1104
1104
1105 Returns 0 on success.
1105 Returns 0 on success.
1106 """
1106 """
1107 if label:
1107 if label:
1108 label = label.strip()
1108 label = label.strip()
1109
1109
1110 if not opts.get('clean') and not label:
1110 if not opts.get('clean') and not label:
1111 ui.write("%s\n" % repo.dirstate.branch())
1111 ui.write("%s\n" % repo.dirstate.branch())
1112 return
1112 return
1113
1113
1114 wlock = repo.wlock()
1114 wlock = repo.wlock()
1115 try:
1115 try:
1116 if opts.get('clean'):
1116 if opts.get('clean'):
1117 label = repo[None].p1().branch()
1117 label = repo[None].p1().branch()
1118 repo.dirstate.setbranch(label)
1118 repo.dirstate.setbranch(label)
1119 ui.status(_('reset working directory to branch %s\n') % label)
1119 ui.status(_('reset working directory to branch %s\n') % label)
1120 elif label:
1120 elif label:
1121 if not opts.get('force') and label in repo.branchmap():
1121 if not opts.get('force') and label in repo.branchmap():
1122 if label not in [p.branch() for p in repo.parents()]:
1122 if label not in [p.branch() for p in repo.parents()]:
1123 raise error.Abort(_('a branch of the same name already'
1123 raise error.Abort(_('a branch of the same name already'
1124 ' exists'),
1124 ' exists'),
1125 # i18n: "it" refers to an existing branch
1125 # i18n: "it" refers to an existing branch
1126 hint=_("use 'hg update' to switch to it"))
1126 hint=_("use 'hg update' to switch to it"))
1127 scmutil.checknewlabel(repo, label, 'branch')
1127 scmutil.checknewlabel(repo, label, 'branch')
1128 repo.dirstate.setbranch(label)
1128 repo.dirstate.setbranch(label)
1129 ui.status(_('marked working directory as branch %s\n') % label)
1129 ui.status(_('marked working directory as branch %s\n') % label)
1130
1130
1131 # find any open named branches aside from default
1131 # find any open named branches aside from default
1132 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1132 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1133 if n != "default" and not c]
1133 if n != "default" and not c]
1134 if not others:
1134 if not others:
1135 ui.status(_('(branches are permanent and global, '
1135 ui.status(_('(branches are permanent and global, '
1136 'did you want a bookmark?)\n'))
1136 'did you want a bookmark?)\n'))
1137 finally:
1137 finally:
1138 wlock.release()
1138 wlock.release()
1139
1139
1140 @command('branches',
1140 @command('branches',
1141 [('a', 'active', False,
1141 [('a', 'active', False,
1142 _('show only branches that have unmerged heads (DEPRECATED)')),
1142 _('show only branches that have unmerged heads (DEPRECATED)')),
1143 ('c', 'closed', False, _('show normal and closed branches')),
1143 ('c', 'closed', False, _('show normal and closed branches')),
1144 ] + formatteropts,
1144 ] + formatteropts,
1145 _('[-ac]'))
1145 _('[-ac]'))
1146 def branches(ui, repo, active=False, closed=False, **opts):
1146 def branches(ui, repo, active=False, closed=False, **opts):
1147 """list repository named branches
1147 """list repository named branches
1148
1148
1149 List the repository's named branches, indicating which ones are
1149 List the repository's named branches, indicating which ones are
1150 inactive. If -c/--closed is specified, also list branches which have
1150 inactive. If -c/--closed is specified, also list branches which have
1151 been marked closed (see :hg:`commit --close-branch`).
1151 been marked closed (see :hg:`commit --close-branch`).
1152
1152
1153 Use the command :hg:`update` to switch to an existing branch.
1153 Use the command :hg:`update` to switch to an existing branch.
1154
1154
1155 Returns 0.
1155 Returns 0.
1156 """
1156 """
1157
1157
1158 fm = ui.formatter('branches', opts)
1158 fm = ui.formatter('branches', opts)
1159 hexfunc = fm.hexfunc
1159 hexfunc = fm.hexfunc
1160
1160
1161 allheads = set(repo.heads())
1161 allheads = set(repo.heads())
1162 branches = []
1162 branches = []
1163 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1163 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1164 isactive = not isclosed and bool(set(heads) & allheads)
1164 isactive = not isclosed and bool(set(heads) & allheads)
1165 branches.append((tag, repo[tip], isactive, not isclosed))
1165 branches.append((tag, repo[tip], isactive, not isclosed))
1166 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1166 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1167 reverse=True)
1167 reverse=True)
1168
1168
1169 for tag, ctx, isactive, isopen in branches:
1169 for tag, ctx, isactive, isopen in branches:
1170 if active and not isactive:
1170 if active and not isactive:
1171 continue
1171 continue
1172 if isactive:
1172 if isactive:
1173 label = 'branches.active'
1173 label = 'branches.active'
1174 notice = ''
1174 notice = ''
1175 elif not isopen:
1175 elif not isopen:
1176 if not closed:
1176 if not closed:
1177 continue
1177 continue
1178 label = 'branches.closed'
1178 label = 'branches.closed'
1179 notice = _(' (closed)')
1179 notice = _(' (closed)')
1180 else:
1180 else:
1181 label = 'branches.inactive'
1181 label = 'branches.inactive'
1182 notice = _(' (inactive)')
1182 notice = _(' (inactive)')
1183 current = (tag == repo.dirstate.branch())
1183 current = (tag == repo.dirstate.branch())
1184 if current:
1184 if current:
1185 label = 'branches.current'
1185 label = 'branches.current'
1186
1186
1187 fm.startitem()
1187 fm.startitem()
1188 fm.write('branch', '%s', tag, label=label)
1188 fm.write('branch', '%s', tag, label=label)
1189 rev = ctx.rev()
1189 rev = ctx.rev()
1190 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1190 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1191 fmt = ' ' * padsize + ' %d:%s'
1191 fmt = ' ' * padsize + ' %d:%s'
1192 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1192 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1193 label='log.changeset changeset.%s' % ctx.phasestr())
1193 label='log.changeset changeset.%s' % ctx.phasestr())
1194 fm.data(active=isactive, closed=not isopen, current=current)
1194 fm.data(active=isactive, closed=not isopen, current=current)
1195 if not ui.quiet:
1195 if not ui.quiet:
1196 fm.plain(notice)
1196 fm.plain(notice)
1197 fm.plain('\n')
1197 fm.plain('\n')
1198 fm.end()
1198 fm.end()
1199
1199
1200 @command('bundle',
1200 @command('bundle',
1201 [('f', 'force', None, _('run even when the destination is unrelated')),
1201 [('f', 'force', None, _('run even when the destination is unrelated')),
1202 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1202 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1203 _('REV')),
1203 _('REV')),
1204 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1204 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1205 _('BRANCH')),
1205 _('BRANCH')),
1206 ('', 'base', [],
1206 ('', 'base', [],
1207 _('a base changeset assumed to be available at the destination'),
1207 _('a base changeset assumed to be available at the destination'),
1208 _('REV')),
1208 _('REV')),
1209 ('a', 'all', None, _('bundle all changesets in the repository')),
1209 ('a', 'all', None, _('bundle all changesets in the repository')),
1210 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1210 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1211 ] + remoteopts,
1211 ] + remoteopts,
1212 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1212 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1213 def bundle(ui, repo, fname, dest=None, **opts):
1213 def bundle(ui, repo, fname, dest=None, **opts):
1214 """create a changegroup file
1214 """create a changegroup file
1215
1215
1216 Generate a compressed changegroup file collecting changesets not
1216 Generate a compressed changegroup file collecting changesets not
1217 known to be in another repository.
1217 known to be in another repository.
1218
1218
1219 If you omit the destination repository, then hg assumes the
1219 If you omit the destination repository, then hg assumes the
1220 destination will have all the nodes you specify with --base
1220 destination will have all the nodes you specify with --base
1221 parameters. To create a bundle containing all changesets, use
1221 parameters. To create a bundle containing all changesets, use
1222 -a/--all (or --base null).
1222 -a/--all (or --base null).
1223
1223
1224 You can change bundle format with the -t/--type option. You can
1224 You can change bundle format with the -t/--type option. You can
1225 specify a compression, a bundle version or both using a dash
1225 specify a compression, a bundle version or both using a dash
1226 (comp-version). The available compression methods are: none, bzip2,
1226 (comp-version). The available compression methods are: none, bzip2,
1227 and gzip (by default, bundles are compressed using bzip2). The
1227 and gzip (by default, bundles are compressed using bzip2). The
1228 available format are: v1, v2 (default to most suitable).
1228 available format are: v1, v2 (default to most suitable).
1229
1229
1230 The bundle file can then be transferred using conventional means
1230 The bundle file can then be transferred using conventional means
1231 and applied to another repository with the unbundle or pull
1231 and applied to another repository with the unbundle or pull
1232 command. This is useful when direct push and pull are not
1232 command. This is useful when direct push and pull are not
1233 available or when exporting an entire repository is undesirable.
1233 available or when exporting an entire repository is undesirable.
1234
1234
1235 Applying bundles preserves all changeset contents including
1235 Applying bundles preserves all changeset contents including
1236 permissions, copy/rename information, and revision history.
1236 permissions, copy/rename information, and revision history.
1237
1237
1238 Returns 0 on success, 1 if no changes found.
1238 Returns 0 on success, 1 if no changes found.
1239 """
1239 """
1240 revs = None
1240 revs = None
1241 if 'rev' in opts:
1241 if 'rev' in opts:
1242 revs = scmutil.revrange(repo, opts['rev'])
1242 revs = scmutil.revrange(repo, opts['rev'])
1243
1243
1244 bundletype = opts.get('type', 'bzip2').lower()
1244 bundletype = opts.get('type', 'bzip2').lower()
1245 cgversion, bcompression = cmdutil.parsebundletype(repo, bundletype)
1245 cgversion, bcompression = cmdutil.parsebundletype(repo, bundletype)
1246
1246
1247 if opts.get('all'):
1247 if opts.get('all'):
1248 base = ['null']
1248 base = ['null']
1249 else:
1249 else:
1250 base = scmutil.revrange(repo, opts.get('base'))
1250 base = scmutil.revrange(repo, opts.get('base'))
1251 # TODO: get desired bundlecaps from command line.
1251 # TODO: get desired bundlecaps from command line.
1252 bundlecaps = None
1252 bundlecaps = None
1253 if base:
1253 if base:
1254 if dest:
1254 if dest:
1255 raise error.Abort(_("--base is incompatible with specifying "
1255 raise error.Abort(_("--base is incompatible with specifying "
1256 "a destination"))
1256 "a destination"))
1257 common = [repo.lookup(rev) for rev in base]
1257 common = [repo.lookup(rev) for rev in base]
1258 heads = revs and map(repo.lookup, revs) or revs
1258 heads = revs and map(repo.lookup, revs) or revs
1259 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1259 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1260 common=common, bundlecaps=bundlecaps,
1260 common=common, bundlecaps=bundlecaps,
1261 version=cgversion)
1261 version=cgversion)
1262 outgoing = None
1262 outgoing = None
1263 else:
1263 else:
1264 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1264 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1265 dest, branches = hg.parseurl(dest, opts.get('branch'))
1265 dest, branches = hg.parseurl(dest, opts.get('branch'))
1266 other = hg.peer(repo, opts, dest)
1266 other = hg.peer(repo, opts, dest)
1267 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1267 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1268 heads = revs and map(repo.lookup, revs) or revs
1268 heads = revs and map(repo.lookup, revs) or revs
1269 outgoing = discovery.findcommonoutgoing(repo, other,
1269 outgoing = discovery.findcommonoutgoing(repo, other,
1270 onlyheads=heads,
1270 onlyheads=heads,
1271 force=opts.get('force'),
1271 force=opts.get('force'),
1272 portable=True)
1272 portable=True)
1273 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1273 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1274 bundlecaps, version=cgversion)
1274 bundlecaps, version=cgversion)
1275 if not cg:
1275 if not cg:
1276 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1276 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1277 return 1
1277 return 1
1278
1278
1279 if cgversion == '01': #bundle1
1279 if cgversion == '01': #bundle1
1280 if bcompression is None:
1280 if bcompression is None:
1281 bcompression = 'UN'
1281 bcompression = 'UN'
1282 bversion = 'HG10' + bcompression
1282 bversion = 'HG10' + bcompression
1283 bcompression = None
1283 bcompression = None
1284 else:
1284 else:
1285 assert cgversion == '02'
1285 assert cgversion == '02'
1286 bversion = 'HG20'
1286 bversion = 'HG20'
1287
1287
1288
1288
1289 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1289 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1290
1290
1291 @command('cat',
1291 @command('cat',
1292 [('o', 'output', '',
1292 [('o', 'output', '',
1293 _('print output to file with formatted name'), _('FORMAT')),
1293 _('print output to file with formatted name'), _('FORMAT')),
1294 ('r', 'rev', '', _('print the given revision'), _('REV')),
1294 ('r', 'rev', '', _('print the given revision'), _('REV')),
1295 ('', 'decode', None, _('apply any matching decode filter')),
1295 ('', 'decode', None, _('apply any matching decode filter')),
1296 ] + walkopts,
1296 ] + walkopts,
1297 _('[OPTION]... FILE...'),
1297 _('[OPTION]... FILE...'),
1298 inferrepo=True)
1298 inferrepo=True)
1299 def cat(ui, repo, file1, *pats, **opts):
1299 def cat(ui, repo, file1, *pats, **opts):
1300 """output the current or given revision of files
1300 """output the current or given revision of files
1301
1301
1302 Print the specified files as they were at the given revision. If
1302 Print the specified files as they were at the given revision. If
1303 no revision is given, the parent of the working directory is used.
1303 no revision is given, the parent of the working directory is used.
1304
1304
1305 Output may be to a file, in which case the name of the file is
1305 Output may be to a file, in which case the name of the file is
1306 given using a format string. The formatting rules as follows:
1306 given using a format string. The formatting rules as follows:
1307
1307
1308 :``%%``: literal "%" character
1308 :``%%``: literal "%" character
1309 :``%s``: basename of file being printed
1309 :``%s``: basename of file being printed
1310 :``%d``: dirname of file being printed, or '.' if in repository root
1310 :``%d``: dirname of file being printed, or '.' if in repository root
1311 :``%p``: root-relative path name of file being printed
1311 :``%p``: root-relative path name of file being printed
1312 :``%H``: changeset hash (40 hexadecimal digits)
1312 :``%H``: changeset hash (40 hexadecimal digits)
1313 :``%R``: changeset revision number
1313 :``%R``: changeset revision number
1314 :``%h``: short-form changeset hash (12 hexadecimal digits)
1314 :``%h``: short-form changeset hash (12 hexadecimal digits)
1315 :``%r``: zero-padded changeset revision number
1315 :``%r``: zero-padded changeset revision number
1316 :``%b``: basename of the exporting repository
1316 :``%b``: basename of the exporting repository
1317
1317
1318 Returns 0 on success.
1318 Returns 0 on success.
1319 """
1319 """
1320 ctx = scmutil.revsingle(repo, opts.get('rev'))
1320 ctx = scmutil.revsingle(repo, opts.get('rev'))
1321 m = scmutil.match(ctx, (file1,) + pats, opts)
1321 m = scmutil.match(ctx, (file1,) + pats, opts)
1322
1322
1323 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1323 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1324
1324
1325 @command('^clone',
1325 @command('^clone',
1326 [('U', 'noupdate', None, _('the clone will include an empty working '
1326 [('U', 'noupdate', None, _('the clone will include an empty working '
1327 'directory (only a repository)')),
1327 'directory (only a repository)')),
1328 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1328 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1329 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1329 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1330 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1330 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1331 ('', 'pull', None, _('use pull protocol to copy metadata')),
1331 ('', 'pull', None, _('use pull protocol to copy metadata')),
1332 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1332 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1333 ] + remoteopts,
1333 ] + remoteopts,
1334 _('[OPTION]... SOURCE [DEST]'),
1334 _('[OPTION]... SOURCE [DEST]'),
1335 norepo=True)
1335 norepo=True)
1336 def clone(ui, source, dest=None, **opts):
1336 def clone(ui, source, dest=None, **opts):
1337 """make a copy of an existing repository
1337 """make a copy of an existing repository
1338
1338
1339 Create a copy of an existing repository in a new directory.
1339 Create a copy of an existing repository in a new directory.
1340
1340
1341 If no destination directory name is specified, it defaults to the
1341 If no destination directory name is specified, it defaults to the
1342 basename of the source.
1342 basename of the source.
1343
1343
1344 The location of the source is added to the new repository's
1344 The location of the source is added to the new repository's
1345 ``.hg/hgrc`` file, as the default to be used for future pulls.
1345 ``.hg/hgrc`` file, as the default to be used for future pulls.
1346
1346
1347 Only local paths and ``ssh://`` URLs are supported as
1347 Only local paths and ``ssh://`` URLs are supported as
1348 destinations. For ``ssh://`` destinations, no working directory or
1348 destinations. For ``ssh://`` destinations, no working directory or
1349 ``.hg/hgrc`` will be created on the remote side.
1349 ``.hg/hgrc`` will be created on the remote side.
1350
1350
1351 To pull only a subset of changesets, specify one or more revisions
1351 To pull only a subset of changesets, specify one or more revisions
1352 identifiers with -r/--rev or branches with -b/--branch. The
1352 identifiers with -r/--rev or branches with -b/--branch. The
1353 resulting clone will contain only the specified changesets and
1353 resulting clone will contain only the specified changesets and
1354 their ancestors. These options (or 'clone src#rev dest') imply
1354 their ancestors. These options (or 'clone src#rev dest') imply
1355 --pull, even for local source repositories. Note that specifying a
1355 --pull, even for local source repositories. Note that specifying a
1356 tag will include the tagged changeset but not the changeset
1356 tag will include the tagged changeset but not the changeset
1357 containing the tag.
1357 containing the tag.
1358
1358
1359 If the source repository has a bookmark called '@' set, that
1359 If the source repository has a bookmark called '@' set, that
1360 revision will be checked out in the new repository by default.
1360 revision will be checked out in the new repository by default.
1361
1361
1362 To check out a particular version, use -u/--update, or
1362 To check out a particular version, use -u/--update, or
1363 -U/--noupdate to create a clone with no working directory.
1363 -U/--noupdate to create a clone with no working directory.
1364
1364
1365 .. container:: verbose
1365 .. container:: verbose
1366
1366
1367 For efficiency, hardlinks are used for cloning whenever the
1367 For efficiency, hardlinks are used for cloning whenever the
1368 source and destination are on the same filesystem (note this
1368 source and destination are on the same filesystem (note this
1369 applies only to the repository data, not to the working
1369 applies only to the repository data, not to the working
1370 directory). Some filesystems, such as AFS, implement hardlinking
1370 directory). Some filesystems, such as AFS, implement hardlinking
1371 incorrectly, but do not report errors. In these cases, use the
1371 incorrectly, but do not report errors. In these cases, use the
1372 --pull option to avoid hardlinking.
1372 --pull option to avoid hardlinking.
1373
1373
1374 In some cases, you can clone repositories and the working
1374 In some cases, you can clone repositories and the working
1375 directory using full hardlinks with ::
1375 directory using full hardlinks with ::
1376
1376
1377 $ cp -al REPO REPOCLONE
1377 $ cp -al REPO REPOCLONE
1378
1378
1379 This is the fastest way to clone, but it is not always safe. The
1379 This is the fastest way to clone, but it is not always safe. The
1380 operation is not atomic (making sure REPO is not modified during
1380 operation is not atomic (making sure REPO is not modified during
1381 the operation is up to you) and you have to make sure your
1381 the operation is up to you) and you have to make sure your
1382 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1382 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1383 so). Also, this is not compatible with certain extensions that
1383 so). Also, this is not compatible with certain extensions that
1384 place their metadata under the .hg directory, such as mq.
1384 place their metadata under the .hg directory, such as mq.
1385
1385
1386 Mercurial will update the working directory to the first applicable
1386 Mercurial will update the working directory to the first applicable
1387 revision from this list:
1387 revision from this list:
1388
1388
1389 a) null if -U or the source repository has no changesets
1389 a) null if -U or the source repository has no changesets
1390 b) if -u . and the source repository is local, the first parent of
1390 b) if -u . and the source repository is local, the first parent of
1391 the source repository's working directory
1391 the source repository's working directory
1392 c) the changeset specified with -u (if a branch name, this means the
1392 c) the changeset specified with -u (if a branch name, this means the
1393 latest head of that branch)
1393 latest head of that branch)
1394 d) the changeset specified with -r
1394 d) the changeset specified with -r
1395 e) the tipmost head specified with -b
1395 e) the tipmost head specified with -b
1396 f) the tipmost head specified with the url#branch source syntax
1396 f) the tipmost head specified with the url#branch source syntax
1397 g) the revision marked with the '@' bookmark, if present
1397 g) the revision marked with the '@' bookmark, if present
1398 h) the tipmost head of the default branch
1398 h) the tipmost head of the default branch
1399 i) tip
1399 i) tip
1400
1400
1401 Examples:
1401 Examples:
1402
1402
1403 - clone a remote repository to a new directory named hg/::
1403 - clone a remote repository to a new directory named hg/::
1404
1404
1405 hg clone http://selenic.com/hg
1405 hg clone http://selenic.com/hg
1406
1406
1407 - create a lightweight local clone::
1407 - create a lightweight local clone::
1408
1408
1409 hg clone project/ project-feature/
1409 hg clone project/ project-feature/
1410
1410
1411 - clone from an absolute path on an ssh server (note double-slash)::
1411 - clone from an absolute path on an ssh server (note double-slash)::
1412
1412
1413 hg clone ssh://user@server//home/projects/alpha/
1413 hg clone ssh://user@server//home/projects/alpha/
1414
1414
1415 - do a high-speed clone over a LAN while checking out a
1415 - do a high-speed clone over a LAN while checking out a
1416 specified version::
1416 specified version::
1417
1417
1418 hg clone --uncompressed http://server/repo -u 1.5
1418 hg clone --uncompressed http://server/repo -u 1.5
1419
1419
1420 - create a repository without changesets after a particular revision::
1420 - create a repository without changesets after a particular revision::
1421
1421
1422 hg clone -r 04e544 experimental/ good/
1422 hg clone -r 04e544 experimental/ good/
1423
1423
1424 - clone (and track) a particular named branch::
1424 - clone (and track) a particular named branch::
1425
1425
1426 hg clone http://selenic.com/hg#stable
1426 hg clone http://selenic.com/hg#stable
1427
1427
1428 See :hg:`help urls` for details on specifying URLs.
1428 See :hg:`help urls` for details on specifying URLs.
1429
1429
1430 Returns 0 on success.
1430 Returns 0 on success.
1431 """
1431 """
1432 if opts.get('noupdate') and opts.get('updaterev'):
1432 if opts.get('noupdate') and opts.get('updaterev'):
1433 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1433 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1434
1434
1435 r = hg.clone(ui, opts, source, dest,
1435 r = hg.clone(ui, opts, source, dest,
1436 pull=opts.get('pull'),
1436 pull=opts.get('pull'),
1437 stream=opts.get('uncompressed'),
1437 stream=opts.get('uncompressed'),
1438 rev=opts.get('rev'),
1438 rev=opts.get('rev'),
1439 update=opts.get('updaterev') or not opts.get('noupdate'),
1439 update=opts.get('updaterev') or not opts.get('noupdate'),
1440 branch=opts.get('branch'),
1440 branch=opts.get('branch'),
1441 shareopts=opts.get('shareopts'))
1441 shareopts=opts.get('shareopts'))
1442
1442
1443 return r is None
1443 return r is None
1444
1444
1445 @command('^commit|ci',
1445 @command('^commit|ci',
1446 [('A', 'addremove', None,
1446 [('A', 'addremove', None,
1447 _('mark new/missing files as added/removed before committing')),
1447 _('mark new/missing files as added/removed before committing')),
1448 ('', 'close-branch', None,
1448 ('', 'close-branch', None,
1449 _('mark a branch head as closed')),
1449 _('mark a branch head as closed')),
1450 ('', 'amend', None, _('amend the parent of the working directory')),
1450 ('', 'amend', None, _('amend the parent of the working directory')),
1451 ('s', 'secret', None, _('use the secret phase for committing')),
1451 ('s', 'secret', None, _('use the secret phase for committing')),
1452 ('e', 'edit', None, _('invoke editor on commit messages')),
1452 ('e', 'edit', None, _('invoke editor on commit messages')),
1453 ('i', 'interactive', None, _('use interactive mode')),
1453 ('i', 'interactive', None, _('use interactive mode')),
1454 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1454 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1455 _('[OPTION]... [FILE]...'),
1455 _('[OPTION]... [FILE]...'),
1456 inferrepo=True)
1456 inferrepo=True)
1457 def commit(ui, repo, *pats, **opts):
1457 def commit(ui, repo, *pats, **opts):
1458 """commit the specified files or all outstanding changes
1458 """commit the specified files or all outstanding changes
1459
1459
1460 Commit changes to the given files into the repository. Unlike a
1460 Commit changes to the given files into the repository. Unlike a
1461 centralized SCM, this operation is a local operation. See
1461 centralized SCM, this operation is a local operation. See
1462 :hg:`push` for a way to actively distribute your changes.
1462 :hg:`push` for a way to actively distribute your changes.
1463
1463
1464 If a list of files is omitted, all changes reported by :hg:`status`
1464 If a list of files is omitted, all changes reported by :hg:`status`
1465 will be committed.
1465 will be committed.
1466
1466
1467 If you are committing the result of a merge, do not provide any
1467 If you are committing the result of a merge, do not provide any
1468 filenames or -I/-X filters.
1468 filenames or -I/-X filters.
1469
1469
1470 If no commit message is specified, Mercurial starts your
1470 If no commit message is specified, Mercurial starts your
1471 configured editor where you can enter a message. In case your
1471 configured editor where you can enter a message. In case your
1472 commit fails, you will find a backup of your message in
1472 commit fails, you will find a backup of your message in
1473 ``.hg/last-message.txt``.
1473 ``.hg/last-message.txt``.
1474
1474
1475 The --close-branch flag can be used to mark the current branch
1475 The --close-branch flag can be used to mark the current branch
1476 head closed. When all heads of a branch are closed, the branch
1476 head closed. When all heads of a branch are closed, the branch
1477 will be considered closed and no longer listed.
1477 will be considered closed and no longer listed.
1478
1478
1479 The --amend flag can be used to amend the parent of the
1479 The --amend flag can be used to amend the parent of the
1480 working directory with a new commit that contains the changes
1480 working directory with a new commit that contains the changes
1481 in the parent in addition to those currently reported by :hg:`status`,
1481 in the parent in addition to those currently reported by :hg:`status`,
1482 if there are any. The old commit is stored in a backup bundle in
1482 if there are any. The old commit is stored in a backup bundle in
1483 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1483 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1484 on how to restore it).
1484 on how to restore it).
1485
1485
1486 Message, user and date are taken from the amended commit unless
1486 Message, user and date are taken from the amended commit unless
1487 specified. When a message isn't specified on the command line,
1487 specified. When a message isn't specified on the command line,
1488 the editor will open with the message of the amended commit.
1488 the editor will open with the message of the amended commit.
1489
1489
1490 It is not possible to amend public changesets (see :hg:`help phases`)
1490 It is not possible to amend public changesets (see :hg:`help phases`)
1491 or changesets that have children.
1491 or changesets that have children.
1492
1492
1493 See :hg:`help dates` for a list of formats valid for -d/--date.
1493 See :hg:`help dates` for a list of formats valid for -d/--date.
1494
1494
1495 Returns 0 on success, 1 if nothing changed.
1495 Returns 0 on success, 1 if nothing changed.
1496 """
1496 """
1497 if opts.get('interactive'):
1497 if opts.get('interactive'):
1498 opts.pop('interactive')
1498 opts.pop('interactive')
1499 cmdutil.dorecord(ui, repo, commit, None, False,
1499 cmdutil.dorecord(ui, repo, commit, None, False,
1500 cmdutil.recordfilter, *pats, **opts)
1500 cmdutil.recordfilter, *pats, **opts)
1501 return
1501 return
1502
1502
1503 if opts.get('subrepos'):
1503 if opts.get('subrepos'):
1504 if opts.get('amend'):
1504 if opts.get('amend'):
1505 raise error.Abort(_('cannot amend with --subrepos'))
1505 raise error.Abort(_('cannot amend with --subrepos'))
1506 # Let --subrepos on the command line override config setting.
1506 # Let --subrepos on the command line override config setting.
1507 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1507 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1508
1508
1509 cmdutil.checkunfinished(repo, commit=True)
1509 cmdutil.checkunfinished(repo, commit=True)
1510
1510
1511 branch = repo[None].branch()
1511 branch = repo[None].branch()
1512 bheads = repo.branchheads(branch)
1512 bheads = repo.branchheads(branch)
1513
1513
1514 extra = {}
1514 extra = {}
1515 if opts.get('close_branch'):
1515 if opts.get('close_branch'):
1516 extra['close'] = 1
1516 extra['close'] = 1
1517
1517
1518 if not bheads:
1518 if not bheads:
1519 raise error.Abort(_('can only close branch heads'))
1519 raise error.Abort(_('can only close branch heads'))
1520 elif opts.get('amend'):
1520 elif opts.get('amend'):
1521 if repo.parents()[0].p1().branch() != branch and \
1521 if repo.parents()[0].p1().branch() != branch and \
1522 repo.parents()[0].p2().branch() != branch:
1522 repo.parents()[0].p2().branch() != branch:
1523 raise error.Abort(_('can only close branch heads'))
1523 raise error.Abort(_('can only close branch heads'))
1524
1524
1525 if opts.get('amend'):
1525 if opts.get('amend'):
1526 if ui.configbool('ui', 'commitsubrepos'):
1526 if ui.configbool('ui', 'commitsubrepos'):
1527 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1527 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1528
1528
1529 old = repo['.']
1529 old = repo['.']
1530 if not old.mutable():
1530 if not old.mutable():
1531 raise error.Abort(_('cannot amend public changesets'))
1531 raise error.Abort(_('cannot amend public changesets'))
1532 if len(repo[None].parents()) > 1:
1532 if len(repo[None].parents()) > 1:
1533 raise error.Abort(_('cannot amend while merging'))
1533 raise error.Abort(_('cannot amend while merging'))
1534 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1534 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1535 if not allowunstable and old.children():
1535 if not allowunstable and old.children():
1536 raise error.Abort(_('cannot amend changeset with children'))
1536 raise error.Abort(_('cannot amend changeset with children'))
1537
1537
1538 # commitfunc is used only for temporary amend commit by cmdutil.amend
1538 # commitfunc is used only for temporary amend commit by cmdutil.amend
1539 def commitfunc(ui, repo, message, match, opts):
1539 def commitfunc(ui, repo, message, match, opts):
1540 return repo.commit(message,
1540 return repo.commit(message,
1541 opts.get('user') or old.user(),
1541 opts.get('user') or old.user(),
1542 opts.get('date') or old.date(),
1542 opts.get('date') or old.date(),
1543 match,
1543 match,
1544 extra=extra)
1544 extra=extra)
1545
1545
1546 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1546 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1547 if node == old.node():
1547 if node == old.node():
1548 ui.status(_("nothing changed\n"))
1548 ui.status(_("nothing changed\n"))
1549 return 1
1549 return 1
1550 else:
1550 else:
1551 def commitfunc(ui, repo, message, match, opts):
1551 def commitfunc(ui, repo, message, match, opts):
1552 backup = ui.backupconfig('phases', 'new-commit')
1552 backup = ui.backupconfig('phases', 'new-commit')
1553 baseui = repo.baseui
1553 baseui = repo.baseui
1554 basebackup = baseui.backupconfig('phases', 'new-commit')
1554 basebackup = baseui.backupconfig('phases', 'new-commit')
1555 try:
1555 try:
1556 if opts.get('secret'):
1556 if opts.get('secret'):
1557 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1557 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1558 # Propagate to subrepos
1558 # Propagate to subrepos
1559 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1559 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1560
1560
1561 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1561 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1562 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1562 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1563 return repo.commit(message, opts.get('user'), opts.get('date'),
1563 return repo.commit(message, opts.get('user'), opts.get('date'),
1564 match,
1564 match,
1565 editor=editor,
1565 editor=editor,
1566 extra=extra)
1566 extra=extra)
1567 finally:
1567 finally:
1568 ui.restoreconfig(backup)
1568 ui.restoreconfig(backup)
1569 repo.baseui.restoreconfig(basebackup)
1569 repo.baseui.restoreconfig(basebackup)
1570
1570
1571
1571
1572 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1572 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1573
1573
1574 if not node:
1574 if not node:
1575 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1575 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1576 if stat[3]:
1576 if stat[3]:
1577 ui.status(_("nothing changed (%d missing files, see "
1577 ui.status(_("nothing changed (%d missing files, see "
1578 "'hg status')\n") % len(stat[3]))
1578 "'hg status')\n") % len(stat[3]))
1579 else:
1579 else:
1580 ui.status(_("nothing changed\n"))
1580 ui.status(_("nothing changed\n"))
1581 return 1
1581 return 1
1582
1582
1583 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1583 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1584
1584
1585 @command('config|showconfig|debugconfig',
1585 @command('config|showconfig|debugconfig',
1586 [('u', 'untrusted', None, _('show untrusted configuration options')),
1586 [('u', 'untrusted', None, _('show untrusted configuration options')),
1587 ('e', 'edit', None, _('edit user config')),
1587 ('e', 'edit', None, _('edit user config')),
1588 ('l', 'local', None, _('edit repository config')),
1588 ('l', 'local', None, _('edit repository config')),
1589 ('g', 'global', None, _('edit global config'))],
1589 ('g', 'global', None, _('edit global config'))],
1590 _('[-u] [NAME]...'),
1590 _('[-u] [NAME]...'),
1591 optionalrepo=True)
1591 optionalrepo=True)
1592 def config(ui, repo, *values, **opts):
1592 def config(ui, repo, *values, **opts):
1593 """show combined config settings from all hgrc files
1593 """show combined config settings from all hgrc files
1594
1594
1595 With no arguments, print names and values of all config items.
1595 With no arguments, print names and values of all config items.
1596
1596
1597 With one argument of the form section.name, print just the value
1597 With one argument of the form section.name, print just the value
1598 of that config item.
1598 of that config item.
1599
1599
1600 With multiple arguments, print names and values of all config
1600 With multiple arguments, print names and values of all config
1601 items with matching section names.
1601 items with matching section names.
1602
1602
1603 With --edit, start an editor on the user-level config file. With
1603 With --edit, start an editor on the user-level config file. With
1604 --global, edit the system-wide config file. With --local, edit the
1604 --global, edit the system-wide config file. With --local, edit the
1605 repository-level config file.
1605 repository-level config file.
1606
1606
1607 With --debug, the source (filename and line number) is printed
1607 With --debug, the source (filename and line number) is printed
1608 for each config item.
1608 for each config item.
1609
1609
1610 See :hg:`help config` for more information about config files.
1610 See :hg:`help config` for more information about config files.
1611
1611
1612 Returns 0 on success, 1 if NAME does not exist.
1612 Returns 0 on success, 1 if NAME does not exist.
1613
1613
1614 """
1614 """
1615
1615
1616 if opts.get('edit') or opts.get('local') or opts.get('global'):
1616 if opts.get('edit') or opts.get('local') or opts.get('global'):
1617 if opts.get('local') and opts.get('global'):
1617 if opts.get('local') and opts.get('global'):
1618 raise error.Abort(_("can't use --local and --global together"))
1618 raise error.Abort(_("can't use --local and --global together"))
1619
1619
1620 if opts.get('local'):
1620 if opts.get('local'):
1621 if not repo:
1621 if not repo:
1622 raise error.Abort(_("can't use --local outside a repository"))
1622 raise error.Abort(_("can't use --local outside a repository"))
1623 paths = [repo.join('hgrc')]
1623 paths = [repo.join('hgrc')]
1624 elif opts.get('global'):
1624 elif opts.get('global'):
1625 paths = scmutil.systemrcpath()
1625 paths = scmutil.systemrcpath()
1626 else:
1626 else:
1627 paths = scmutil.userrcpath()
1627 paths = scmutil.userrcpath()
1628
1628
1629 for f in paths:
1629 for f in paths:
1630 if os.path.exists(f):
1630 if os.path.exists(f):
1631 break
1631 break
1632 else:
1632 else:
1633 if opts.get('global'):
1633 if opts.get('global'):
1634 samplehgrc = uimod.samplehgrcs['global']
1634 samplehgrc = uimod.samplehgrcs['global']
1635 elif opts.get('local'):
1635 elif opts.get('local'):
1636 samplehgrc = uimod.samplehgrcs['local']
1636 samplehgrc = uimod.samplehgrcs['local']
1637 else:
1637 else:
1638 samplehgrc = uimod.samplehgrcs['user']
1638 samplehgrc = uimod.samplehgrcs['user']
1639
1639
1640 f = paths[0]
1640 f = paths[0]
1641 fp = open(f, "w")
1641 fp = open(f, "w")
1642 fp.write(samplehgrc)
1642 fp.write(samplehgrc)
1643 fp.close()
1643 fp.close()
1644
1644
1645 editor = ui.geteditor()
1645 editor = ui.geteditor()
1646 ui.system("%s \"%s\"" % (editor, f),
1646 ui.system("%s \"%s\"" % (editor, f),
1647 onerr=error.Abort, errprefix=_("edit failed"))
1647 onerr=error.Abort, errprefix=_("edit failed"))
1648 return
1648 return
1649
1649
1650 for f in scmutil.rcpath():
1650 for f in scmutil.rcpath():
1651 ui.debug('read config from: %s\n' % f)
1651 ui.debug('read config from: %s\n' % f)
1652 untrusted = bool(opts.get('untrusted'))
1652 untrusted = bool(opts.get('untrusted'))
1653 if values:
1653 if values:
1654 sections = [v for v in values if '.' not in v]
1654 sections = [v for v in values if '.' not in v]
1655 items = [v for v in values if '.' in v]
1655 items = [v for v in values if '.' in v]
1656 if len(items) > 1 or items and sections:
1656 if len(items) > 1 or items and sections:
1657 raise error.Abort(_('only one config item permitted'))
1657 raise error.Abort(_('only one config item permitted'))
1658 matched = False
1658 matched = False
1659 for section, name, value in ui.walkconfig(untrusted=untrusted):
1659 for section, name, value in ui.walkconfig(untrusted=untrusted):
1660 value = str(value).replace('\n', '\\n')
1660 value = str(value).replace('\n', '\\n')
1661 sectname = section + '.' + name
1661 sectname = section + '.' + name
1662 if values:
1662 if values:
1663 for v in values:
1663 for v in values:
1664 if v == section:
1664 if v == section:
1665 ui.debug('%s: ' %
1665 ui.debug('%s: ' %
1666 ui.configsource(section, name, untrusted))
1666 ui.configsource(section, name, untrusted))
1667 ui.write('%s=%s\n' % (sectname, value))
1667 ui.write('%s=%s\n' % (sectname, value))
1668 matched = True
1668 matched = True
1669 elif v == sectname:
1669 elif v == sectname:
1670 ui.debug('%s: ' %
1670 ui.debug('%s: ' %
1671 ui.configsource(section, name, untrusted))
1671 ui.configsource(section, name, untrusted))
1672 ui.write(value, '\n')
1672 ui.write(value, '\n')
1673 matched = True
1673 matched = True
1674 else:
1674 else:
1675 ui.debug('%s: ' %
1675 ui.debug('%s: ' %
1676 ui.configsource(section, name, untrusted))
1676 ui.configsource(section, name, untrusted))
1677 ui.write('%s=%s\n' % (sectname, value))
1677 ui.write('%s=%s\n' % (sectname, value))
1678 matched = True
1678 matched = True
1679 if matched:
1679 if matched:
1680 return 0
1680 return 0
1681 return 1
1681 return 1
1682
1682
1683 @command('copy|cp',
1683 @command('copy|cp',
1684 [('A', 'after', None, _('record a copy that has already occurred')),
1684 [('A', 'after', None, _('record a copy that has already occurred')),
1685 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1685 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1686 ] + walkopts + dryrunopts,
1686 ] + walkopts + dryrunopts,
1687 _('[OPTION]... [SOURCE]... DEST'))
1687 _('[OPTION]... [SOURCE]... DEST'))
1688 def copy(ui, repo, *pats, **opts):
1688 def copy(ui, repo, *pats, **opts):
1689 """mark files as copied for the next commit
1689 """mark files as copied for the next commit
1690
1690
1691 Mark dest as having copies of source files. If dest is a
1691 Mark dest as having copies of source files. If dest is a
1692 directory, copies are put in that directory. If dest is a file,
1692 directory, copies are put in that directory. If dest is a file,
1693 the source must be a single file.
1693 the source must be a single file.
1694
1694
1695 By default, this command copies the contents of files as they
1695 By default, this command copies the contents of files as they
1696 exist in the working directory. If invoked with -A/--after, the
1696 exist in the working directory. If invoked with -A/--after, the
1697 operation is recorded, but no copying is performed.
1697 operation is recorded, but no copying is performed.
1698
1698
1699 This command takes effect with the next commit. To undo a copy
1699 This command takes effect with the next commit. To undo a copy
1700 before that, see :hg:`revert`.
1700 before that, see :hg:`revert`.
1701
1701
1702 Returns 0 on success, 1 if errors are encountered.
1702 Returns 0 on success, 1 if errors are encountered.
1703 """
1703 """
1704 wlock = repo.wlock(False)
1704 wlock = repo.wlock(False)
1705 try:
1705 try:
1706 return cmdutil.copy(ui, repo, pats, opts)
1706 return cmdutil.copy(ui, repo, pats, opts)
1707 finally:
1707 finally:
1708 wlock.release()
1708 wlock.release()
1709
1709
1710 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1710 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1711 def debugancestor(ui, repo, *args):
1711 def debugancestor(ui, repo, *args):
1712 """find the ancestor revision of two revisions in a given index"""
1712 """find the ancestor revision of two revisions in a given index"""
1713 if len(args) == 3:
1713 if len(args) == 3:
1714 index, rev1, rev2 = args
1714 index, rev1, rev2 = args
1715 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1715 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1716 lookup = r.lookup
1716 lookup = r.lookup
1717 elif len(args) == 2:
1717 elif len(args) == 2:
1718 if not repo:
1718 if not repo:
1719 raise error.Abort(_("there is no Mercurial repository here "
1719 raise error.Abort(_("there is no Mercurial repository here "
1720 "(.hg not found)"))
1720 "(.hg not found)"))
1721 rev1, rev2 = args
1721 rev1, rev2 = args
1722 r = repo.changelog
1722 r = repo.changelog
1723 lookup = repo.lookup
1723 lookup = repo.lookup
1724 else:
1724 else:
1725 raise error.Abort(_('either two or three arguments required'))
1725 raise error.Abort(_('either two or three arguments required'))
1726 a = r.ancestor(lookup(rev1), lookup(rev2))
1726 a = r.ancestor(lookup(rev1), lookup(rev2))
1727 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1727 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1728
1728
1729 @command('debugbuilddag',
1729 @command('debugbuilddag',
1730 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1730 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1731 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1731 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1732 ('n', 'new-file', None, _('add new file at each rev'))],
1732 ('n', 'new-file', None, _('add new file at each rev'))],
1733 _('[OPTION]... [TEXT]'))
1733 _('[OPTION]... [TEXT]'))
1734 def debugbuilddag(ui, repo, text=None,
1734 def debugbuilddag(ui, repo, text=None,
1735 mergeable_file=False,
1735 mergeable_file=False,
1736 overwritten_file=False,
1736 overwritten_file=False,
1737 new_file=False):
1737 new_file=False):
1738 """builds a repo with a given DAG from scratch in the current empty repo
1738 """builds a repo with a given DAG from scratch in the current empty repo
1739
1739
1740 The description of the DAG is read from stdin if not given on the
1740 The description of the DAG is read from stdin if not given on the
1741 command line.
1741 command line.
1742
1742
1743 Elements:
1743 Elements:
1744
1744
1745 - "+n" is a linear run of n nodes based on the current default parent
1745 - "+n" is a linear run of n nodes based on the current default parent
1746 - "." is a single node based on the current default parent
1746 - "." is a single node based on the current default parent
1747 - "$" resets the default parent to null (implied at the start);
1747 - "$" resets the default parent to null (implied at the start);
1748 otherwise the default parent is always the last node created
1748 otherwise the default parent is always the last node created
1749 - "<p" sets the default parent to the backref p
1749 - "<p" sets the default parent to the backref p
1750 - "*p" is a fork at parent p, which is a backref
1750 - "*p" is a fork at parent p, which is a backref
1751 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1751 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1752 - "/p2" is a merge of the preceding node and p2
1752 - "/p2" is a merge of the preceding node and p2
1753 - ":tag" defines a local tag for the preceding node
1753 - ":tag" defines a local tag for the preceding node
1754 - "@branch" sets the named branch for subsequent nodes
1754 - "@branch" sets the named branch for subsequent nodes
1755 - "#...\\n" is a comment up to the end of the line
1755 - "#...\\n" is a comment up to the end of the line
1756
1756
1757 Whitespace between the above elements is ignored.
1757 Whitespace between the above elements is ignored.
1758
1758
1759 A backref is either
1759 A backref is either
1760
1760
1761 - a number n, which references the node curr-n, where curr is the current
1761 - a number n, which references the node curr-n, where curr is the current
1762 node, or
1762 node, or
1763 - the name of a local tag you placed earlier using ":tag", or
1763 - the name of a local tag you placed earlier using ":tag", or
1764 - empty to denote the default parent.
1764 - empty to denote the default parent.
1765
1765
1766 All string valued-elements are either strictly alphanumeric, or must
1766 All string valued-elements are either strictly alphanumeric, or must
1767 be enclosed in double quotes ("..."), with "\\" as escape character.
1767 be enclosed in double quotes ("..."), with "\\" as escape character.
1768 """
1768 """
1769
1769
1770 if text is None:
1770 if text is None:
1771 ui.status(_("reading DAG from stdin\n"))
1771 ui.status(_("reading DAG from stdin\n"))
1772 text = ui.fin.read()
1772 text = ui.fin.read()
1773
1773
1774 cl = repo.changelog
1774 cl = repo.changelog
1775 if len(cl) > 0:
1775 if len(cl) > 0:
1776 raise error.Abort(_('repository is not empty'))
1776 raise error.Abort(_('repository is not empty'))
1777
1777
1778 # determine number of revs in DAG
1778 # determine number of revs in DAG
1779 total = 0
1779 total = 0
1780 for type, data in dagparser.parsedag(text):
1780 for type, data in dagparser.parsedag(text):
1781 if type == 'n':
1781 if type == 'n':
1782 total += 1
1782 total += 1
1783
1783
1784 if mergeable_file:
1784 if mergeable_file:
1785 linesperrev = 2
1785 linesperrev = 2
1786 # make a file with k lines per rev
1786 # make a file with k lines per rev
1787 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1787 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1788 initialmergedlines.append("")
1788 initialmergedlines.append("")
1789
1789
1790 tags = []
1790 tags = []
1791
1791
1792 lock = tr = None
1792 lock = tr = None
1793 try:
1793 try:
1794 lock = repo.lock()
1794 lock = repo.lock()
1795 tr = repo.transaction("builddag")
1795 tr = repo.transaction("builddag")
1796
1796
1797 at = -1
1797 at = -1
1798 atbranch = 'default'
1798 atbranch = 'default'
1799 nodeids = []
1799 nodeids = []
1800 id = 0
1800 id = 0
1801 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1801 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1802 for type, data in dagparser.parsedag(text):
1802 for type, data in dagparser.parsedag(text):
1803 if type == 'n':
1803 if type == 'n':
1804 ui.note(('node %s\n' % str(data)))
1804 ui.note(('node %s\n' % str(data)))
1805 id, ps = data
1805 id, ps = data
1806
1806
1807 files = []
1807 files = []
1808 fctxs = {}
1808 fctxs = {}
1809
1809
1810 p2 = None
1810 p2 = None
1811 if mergeable_file:
1811 if mergeable_file:
1812 fn = "mf"
1812 fn = "mf"
1813 p1 = repo[ps[0]]
1813 p1 = repo[ps[0]]
1814 if len(ps) > 1:
1814 if len(ps) > 1:
1815 p2 = repo[ps[1]]
1815 p2 = repo[ps[1]]
1816 pa = p1.ancestor(p2)
1816 pa = p1.ancestor(p2)
1817 base, local, other = [x[fn].data() for x in (pa, p1,
1817 base, local, other = [x[fn].data() for x in (pa, p1,
1818 p2)]
1818 p2)]
1819 m3 = simplemerge.Merge3Text(base, local, other)
1819 m3 = simplemerge.Merge3Text(base, local, other)
1820 ml = [l.strip() for l in m3.merge_lines()]
1820 ml = [l.strip() for l in m3.merge_lines()]
1821 ml.append("")
1821 ml.append("")
1822 elif at > 0:
1822 elif at > 0:
1823 ml = p1[fn].data().split("\n")
1823 ml = p1[fn].data().split("\n")
1824 else:
1824 else:
1825 ml = initialmergedlines
1825 ml = initialmergedlines
1826 ml[id * linesperrev] += " r%i" % id
1826 ml[id * linesperrev] += " r%i" % id
1827 mergedtext = "\n".join(ml)
1827 mergedtext = "\n".join(ml)
1828 files.append(fn)
1828 files.append(fn)
1829 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1829 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1830
1830
1831 if overwritten_file:
1831 if overwritten_file:
1832 fn = "of"
1832 fn = "of"
1833 files.append(fn)
1833 files.append(fn)
1834 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1834 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1835
1835
1836 if new_file:
1836 if new_file:
1837 fn = "nf%i" % id
1837 fn = "nf%i" % id
1838 files.append(fn)
1838 files.append(fn)
1839 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1839 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1840 if len(ps) > 1:
1840 if len(ps) > 1:
1841 if not p2:
1841 if not p2:
1842 p2 = repo[ps[1]]
1842 p2 = repo[ps[1]]
1843 for fn in p2:
1843 for fn in p2:
1844 if fn.startswith("nf"):
1844 if fn.startswith("nf"):
1845 files.append(fn)
1845 files.append(fn)
1846 fctxs[fn] = p2[fn]
1846 fctxs[fn] = p2[fn]
1847
1847
1848 def fctxfn(repo, cx, path):
1848 def fctxfn(repo, cx, path):
1849 return fctxs.get(path)
1849 return fctxs.get(path)
1850
1850
1851 if len(ps) == 0 or ps[0] < 0:
1851 if len(ps) == 0 or ps[0] < 0:
1852 pars = [None, None]
1852 pars = [None, None]
1853 elif len(ps) == 1:
1853 elif len(ps) == 1:
1854 pars = [nodeids[ps[0]], None]
1854 pars = [nodeids[ps[0]], None]
1855 else:
1855 else:
1856 pars = [nodeids[p] for p in ps]
1856 pars = [nodeids[p] for p in ps]
1857 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1857 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1858 date=(id, 0),
1858 date=(id, 0),
1859 user="debugbuilddag",
1859 user="debugbuilddag",
1860 extra={'branch': atbranch})
1860 extra={'branch': atbranch})
1861 nodeid = repo.commitctx(cx)
1861 nodeid = repo.commitctx(cx)
1862 nodeids.append(nodeid)
1862 nodeids.append(nodeid)
1863 at = id
1863 at = id
1864 elif type == 'l':
1864 elif type == 'l':
1865 id, name = data
1865 id, name = data
1866 ui.note(('tag %s\n' % name))
1866 ui.note(('tag %s\n' % name))
1867 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1867 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1868 elif type == 'a':
1868 elif type == 'a':
1869 ui.note(('branch %s\n' % data))
1869 ui.note(('branch %s\n' % data))
1870 atbranch = data
1870 atbranch = data
1871 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1871 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1872 tr.close()
1872 tr.close()
1873
1873
1874 if tags:
1874 if tags:
1875 repo.vfs.write("localtags", "".join(tags))
1875 repo.vfs.write("localtags", "".join(tags))
1876 finally:
1876 finally:
1877 ui.progress(_('building'), None)
1877 ui.progress(_('building'), None)
1878 release(tr, lock)
1878 release(tr, lock)
1879
1879
1880 @command('debugbundle',
1880 @command('debugbundle',
1881 [('a', 'all', None, _('show all details'))],
1881 [('a', 'all', None, _('show all details'))],
1882 _('FILE'),
1882 _('FILE'),
1883 norepo=True)
1883 norepo=True)
1884 def debugbundle(ui, bundlepath, all=None, **opts):
1884 def debugbundle(ui, bundlepath, all=None, **opts):
1885 """lists the contents of a bundle"""
1885 """lists the contents of a bundle"""
1886 f = hg.openpath(ui, bundlepath)
1886 f = hg.openpath(ui, bundlepath)
1887 try:
1887 try:
1888 gen = exchange.readbundle(ui, f, bundlepath)
1888 gen = exchange.readbundle(ui, f, bundlepath)
1889 if isinstance(gen, bundle2.unbundle20):
1889 if isinstance(gen, bundle2.unbundle20):
1890 return _debugbundle2(ui, gen, all=all, **opts)
1890 return _debugbundle2(ui, gen, all=all, **opts)
1891 if all:
1891 if all:
1892 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1892 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1893
1893
1894 def showchunks(named):
1894 def showchunks(named):
1895 ui.write("\n%s\n" % named)
1895 ui.write("\n%s\n" % named)
1896 chain = None
1896 chain = None
1897 while True:
1897 while True:
1898 chunkdata = gen.deltachunk(chain)
1898 chunkdata = gen.deltachunk(chain)
1899 if not chunkdata:
1899 if not chunkdata:
1900 break
1900 break
1901 node = chunkdata['node']
1901 node = chunkdata['node']
1902 p1 = chunkdata['p1']
1902 p1 = chunkdata['p1']
1903 p2 = chunkdata['p2']
1903 p2 = chunkdata['p2']
1904 cs = chunkdata['cs']
1904 cs = chunkdata['cs']
1905 deltabase = chunkdata['deltabase']
1905 deltabase = chunkdata['deltabase']
1906 delta = chunkdata['delta']
1906 delta = chunkdata['delta']
1907 ui.write("%s %s %s %s %s %s\n" %
1907 ui.write("%s %s %s %s %s %s\n" %
1908 (hex(node), hex(p1), hex(p2),
1908 (hex(node), hex(p1), hex(p2),
1909 hex(cs), hex(deltabase), len(delta)))
1909 hex(cs), hex(deltabase), len(delta)))
1910 chain = node
1910 chain = node
1911
1911
1912 chunkdata = gen.changelogheader()
1912 chunkdata = gen.changelogheader()
1913 showchunks("changelog")
1913 showchunks("changelog")
1914 chunkdata = gen.manifestheader()
1914 chunkdata = gen.manifestheader()
1915 showchunks("manifest")
1915 showchunks("manifest")
1916 while True:
1916 while True:
1917 chunkdata = gen.filelogheader()
1917 chunkdata = gen.filelogheader()
1918 if not chunkdata:
1918 if not chunkdata:
1919 break
1919 break
1920 fname = chunkdata['filename']
1920 fname = chunkdata['filename']
1921 showchunks(fname)
1921 showchunks(fname)
1922 else:
1922 else:
1923 if isinstance(gen, bundle2.unbundle20):
1923 if isinstance(gen, bundle2.unbundle20):
1924 raise error.Abort(_('use debugbundle2 for this file'))
1924 raise error.Abort(_('use debugbundle2 for this file'))
1925 chunkdata = gen.changelogheader()
1925 chunkdata = gen.changelogheader()
1926 chain = None
1926 chain = None
1927 while True:
1927 while True:
1928 chunkdata = gen.deltachunk(chain)
1928 chunkdata = gen.deltachunk(chain)
1929 if not chunkdata:
1929 if not chunkdata:
1930 break
1930 break
1931 node = chunkdata['node']
1931 node = chunkdata['node']
1932 ui.write("%s\n" % hex(node))
1932 ui.write("%s\n" % hex(node))
1933 chain = node
1933 chain = node
1934 finally:
1934 finally:
1935 f.close()
1935 f.close()
1936
1936
1937 def _debugbundle2(ui, gen, **opts):
1937 def _debugbundle2(ui, gen, **opts):
1938 """lists the contents of a bundle2"""
1938 """lists the contents of a bundle2"""
1939 if not isinstance(gen, bundle2.unbundle20):
1939 if not isinstance(gen, bundle2.unbundle20):
1940 raise error.Abort(_('not a bundle2 file'))
1940 raise error.Abort(_('not a bundle2 file'))
1941 ui.write(('Stream params: %s\n' % repr(gen.params)))
1941 ui.write(('Stream params: %s\n' % repr(gen.params)))
1942 for part in gen.iterparts():
1942 for part in gen.iterparts():
1943 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1943 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1944 if part.type == 'changegroup':
1944 if part.type == 'changegroup':
1945 version = part.params.get('version', '01')
1945 version = part.params.get('version', '01')
1946 cg = changegroup.packermap[version][1](part, 'UN')
1946 cg = changegroup.packermap[version][1](part, 'UN')
1947 chunkdata = cg.changelogheader()
1947 chunkdata = cg.changelogheader()
1948 chain = None
1948 chain = None
1949 while True:
1949 while True:
1950 chunkdata = cg.deltachunk(chain)
1950 chunkdata = cg.deltachunk(chain)
1951 if not chunkdata:
1951 if not chunkdata:
1952 break
1952 break
1953 node = chunkdata['node']
1953 node = chunkdata['node']
1954 ui.write(" %s\n" % hex(node))
1954 ui.write(" %s\n" % hex(node))
1955 chain = node
1955 chain = node
1956
1956
1957 @command('debugcheckstate', [], '')
1957 @command('debugcheckstate', [], '')
1958 def debugcheckstate(ui, repo):
1958 def debugcheckstate(ui, repo):
1959 """validate the correctness of the current dirstate"""
1959 """validate the correctness of the current dirstate"""
1960 parent1, parent2 = repo.dirstate.parents()
1960 parent1, parent2 = repo.dirstate.parents()
1961 m1 = repo[parent1].manifest()
1961 m1 = repo[parent1].manifest()
1962 m2 = repo[parent2].manifest()
1962 m2 = repo[parent2].manifest()
1963 errors = 0
1963 errors = 0
1964 for f in repo.dirstate:
1964 for f in repo.dirstate:
1965 state = repo.dirstate[f]
1965 state = repo.dirstate[f]
1966 if state in "nr" and f not in m1:
1966 if state in "nr" and f not in m1:
1967 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1967 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1968 errors += 1
1968 errors += 1
1969 if state in "a" and f in m1:
1969 if state in "a" and f in m1:
1970 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1970 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1971 errors += 1
1971 errors += 1
1972 if state in "m" and f not in m1 and f not in m2:
1972 if state in "m" and f not in m1 and f not in m2:
1973 ui.warn(_("%s in state %s, but not in either manifest\n") %
1973 ui.warn(_("%s in state %s, but not in either manifest\n") %
1974 (f, state))
1974 (f, state))
1975 errors += 1
1975 errors += 1
1976 for f in m1:
1976 for f in m1:
1977 state = repo.dirstate[f]
1977 state = repo.dirstate[f]
1978 if state not in "nrm":
1978 if state not in "nrm":
1979 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1979 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1980 errors += 1
1980 errors += 1
1981 if errors:
1981 if errors:
1982 error = _(".hg/dirstate inconsistent with current parent's manifest")
1982 error = _(".hg/dirstate inconsistent with current parent's manifest")
1983 raise error.Abort(error)
1983 raise error.Abort(error)
1984
1984
1985 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1985 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1986 def debugcommands(ui, cmd='', *args):
1986 def debugcommands(ui, cmd='', *args):
1987 """list all available commands and options"""
1987 """list all available commands and options"""
1988 for cmd, vals in sorted(table.iteritems()):
1988 for cmd, vals in sorted(table.iteritems()):
1989 cmd = cmd.split('|')[0].strip('^')
1989 cmd = cmd.split('|')[0].strip('^')
1990 opts = ', '.join([i[1] for i in vals[1]])
1990 opts = ', '.join([i[1] for i in vals[1]])
1991 ui.write('%s: %s\n' % (cmd, opts))
1991 ui.write('%s: %s\n' % (cmd, opts))
1992
1992
1993 @command('debugcomplete',
1993 @command('debugcomplete',
1994 [('o', 'options', None, _('show the command options'))],
1994 [('o', 'options', None, _('show the command options'))],
1995 _('[-o] CMD'),
1995 _('[-o] CMD'),
1996 norepo=True)
1996 norepo=True)
1997 def debugcomplete(ui, cmd='', **opts):
1997 def debugcomplete(ui, cmd='', **opts):
1998 """returns the completion list associated with the given command"""
1998 """returns the completion list associated with the given command"""
1999
1999
2000 if opts.get('options'):
2000 if opts.get('options'):
2001 options = []
2001 options = []
2002 otables = [globalopts]
2002 otables = [globalopts]
2003 if cmd:
2003 if cmd:
2004 aliases, entry = cmdutil.findcmd(cmd, table, False)
2004 aliases, entry = cmdutil.findcmd(cmd, table, False)
2005 otables.append(entry[1])
2005 otables.append(entry[1])
2006 for t in otables:
2006 for t in otables:
2007 for o in t:
2007 for o in t:
2008 if "(DEPRECATED)" in o[3]:
2008 if "(DEPRECATED)" in o[3]:
2009 continue
2009 continue
2010 if o[0]:
2010 if o[0]:
2011 options.append('-%s' % o[0])
2011 options.append('-%s' % o[0])
2012 options.append('--%s' % o[1])
2012 options.append('--%s' % o[1])
2013 ui.write("%s\n" % "\n".join(options))
2013 ui.write("%s\n" % "\n".join(options))
2014 return
2014 return
2015
2015
2016 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2016 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2017 if ui.verbose:
2017 if ui.verbose:
2018 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2018 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2019 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2019 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2020
2020
2021 @command('debugdag',
2021 @command('debugdag',
2022 [('t', 'tags', None, _('use tags as labels')),
2022 [('t', 'tags', None, _('use tags as labels')),
2023 ('b', 'branches', None, _('annotate with branch names')),
2023 ('b', 'branches', None, _('annotate with branch names')),
2024 ('', 'dots', None, _('use dots for runs')),
2024 ('', 'dots', None, _('use dots for runs')),
2025 ('s', 'spaces', None, _('separate elements by spaces'))],
2025 ('s', 'spaces', None, _('separate elements by spaces'))],
2026 _('[OPTION]... [FILE [REV]...]'),
2026 _('[OPTION]... [FILE [REV]...]'),
2027 optionalrepo=True)
2027 optionalrepo=True)
2028 def debugdag(ui, repo, file_=None, *revs, **opts):
2028 def debugdag(ui, repo, file_=None, *revs, **opts):
2029 """format the changelog or an index DAG as a concise textual description
2029 """format the changelog or an index DAG as a concise textual description
2030
2030
2031 If you pass a revlog index, the revlog's DAG is emitted. If you list
2031 If you pass a revlog index, the revlog's DAG is emitted. If you list
2032 revision numbers, they get labeled in the output as rN.
2032 revision numbers, they get labeled in the output as rN.
2033
2033
2034 Otherwise, the changelog DAG of the current repo is emitted.
2034 Otherwise, the changelog DAG of the current repo is emitted.
2035 """
2035 """
2036 spaces = opts.get('spaces')
2036 spaces = opts.get('spaces')
2037 dots = opts.get('dots')
2037 dots = opts.get('dots')
2038 if file_:
2038 if file_:
2039 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2039 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2040 revs = set((int(r) for r in revs))
2040 revs = set((int(r) for r in revs))
2041 def events():
2041 def events():
2042 for r in rlog:
2042 for r in rlog:
2043 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2043 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2044 if p != -1))
2044 if p != -1))
2045 if r in revs:
2045 if r in revs:
2046 yield 'l', (r, "r%i" % r)
2046 yield 'l', (r, "r%i" % r)
2047 elif repo:
2047 elif repo:
2048 cl = repo.changelog
2048 cl = repo.changelog
2049 tags = opts.get('tags')
2049 tags = opts.get('tags')
2050 branches = opts.get('branches')
2050 branches = opts.get('branches')
2051 if tags:
2051 if tags:
2052 labels = {}
2052 labels = {}
2053 for l, n in repo.tags().items():
2053 for l, n in repo.tags().items():
2054 labels.setdefault(cl.rev(n), []).append(l)
2054 labels.setdefault(cl.rev(n), []).append(l)
2055 def events():
2055 def events():
2056 b = "default"
2056 b = "default"
2057 for r in cl:
2057 for r in cl:
2058 if branches:
2058 if branches:
2059 newb = cl.read(cl.node(r))[5]['branch']
2059 newb = cl.read(cl.node(r))[5]['branch']
2060 if newb != b:
2060 if newb != b:
2061 yield 'a', newb
2061 yield 'a', newb
2062 b = newb
2062 b = newb
2063 yield 'n', (r, list(p for p in cl.parentrevs(r)
2063 yield 'n', (r, list(p for p in cl.parentrevs(r)
2064 if p != -1))
2064 if p != -1))
2065 if tags:
2065 if tags:
2066 ls = labels.get(r)
2066 ls = labels.get(r)
2067 if ls:
2067 if ls:
2068 for l in ls:
2068 for l in ls:
2069 yield 'l', (r, l)
2069 yield 'l', (r, l)
2070 else:
2070 else:
2071 raise error.Abort(_('need repo for changelog dag'))
2071 raise error.Abort(_('need repo for changelog dag'))
2072
2072
2073 for line in dagparser.dagtextlines(events(),
2073 for line in dagparser.dagtextlines(events(),
2074 addspaces=spaces,
2074 addspaces=spaces,
2075 wraplabels=True,
2075 wraplabels=True,
2076 wrapannotations=True,
2076 wrapannotations=True,
2077 wrapnonlinear=dots,
2077 wrapnonlinear=dots,
2078 usedots=dots,
2078 usedots=dots,
2079 maxlinewidth=70):
2079 maxlinewidth=70):
2080 ui.write(line)
2080 ui.write(line)
2081 ui.write("\n")
2081 ui.write("\n")
2082
2082
2083 @command('debugdata',
2083 @command('debugdata',
2084 [('c', 'changelog', False, _('open changelog')),
2084 [('c', 'changelog', False, _('open changelog')),
2085 ('m', 'manifest', False, _('open manifest')),
2085 ('m', 'manifest', False, _('open manifest')),
2086 ('', 'dir', False, _('open directory manifest'))],
2086 ('', 'dir', False, _('open directory manifest'))],
2087 _('-c|-m|FILE REV'))
2087 _('-c|-m|FILE REV'))
2088 def debugdata(ui, repo, file_, rev=None, **opts):
2088 def debugdata(ui, repo, file_, rev=None, **opts):
2089 """dump the contents of a data file revision"""
2089 """dump the contents of a data file revision"""
2090 if opts.get('changelog') or opts.get('manifest'):
2090 if opts.get('changelog') or opts.get('manifest'):
2091 file_, rev = None, file_
2091 file_, rev = None, file_
2092 elif rev is None:
2092 elif rev is None:
2093 raise error.CommandError('debugdata', _('invalid arguments'))
2093 raise error.CommandError('debugdata', _('invalid arguments'))
2094 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2094 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2095 try:
2095 try:
2096 ui.write(r.revision(r.lookup(rev)))
2096 ui.write(r.revision(r.lookup(rev)))
2097 except KeyError:
2097 except KeyError:
2098 raise error.Abort(_('invalid revision identifier %s') % rev)
2098 raise error.Abort(_('invalid revision identifier %s') % rev)
2099
2099
2100 @command('debugdate',
2100 @command('debugdate',
2101 [('e', 'extended', None, _('try extended date formats'))],
2101 [('e', 'extended', None, _('try extended date formats'))],
2102 _('[-e] DATE [RANGE]'),
2102 _('[-e] DATE [RANGE]'),
2103 norepo=True, optionalrepo=True)
2103 norepo=True, optionalrepo=True)
2104 def debugdate(ui, date, range=None, **opts):
2104 def debugdate(ui, date, range=None, **opts):
2105 """parse and display a date"""
2105 """parse and display a date"""
2106 if opts["extended"]:
2106 if opts["extended"]:
2107 d = util.parsedate(date, util.extendeddateformats)
2107 d = util.parsedate(date, util.extendeddateformats)
2108 else:
2108 else:
2109 d = util.parsedate(date)
2109 d = util.parsedate(date)
2110 ui.write(("internal: %s %s\n") % d)
2110 ui.write(("internal: %s %s\n") % d)
2111 ui.write(("standard: %s\n") % util.datestr(d))
2111 ui.write(("standard: %s\n") % util.datestr(d))
2112 if range:
2112 if range:
2113 m = util.matchdate(range)
2113 m = util.matchdate(range)
2114 ui.write(("match: %s\n") % m(d[0]))
2114 ui.write(("match: %s\n") % m(d[0]))
2115
2115
2116 @command('debugdiscovery',
2116 @command('debugdiscovery',
2117 [('', 'old', None, _('use old-style discovery')),
2117 [('', 'old', None, _('use old-style discovery')),
2118 ('', 'nonheads', None,
2118 ('', 'nonheads', None,
2119 _('use old-style discovery with non-heads included')),
2119 _('use old-style discovery with non-heads included')),
2120 ] + remoteopts,
2120 ] + remoteopts,
2121 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2121 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2122 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2122 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2123 """runs the changeset discovery protocol in isolation"""
2123 """runs the changeset discovery protocol in isolation"""
2124 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2124 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2125 opts.get('branch'))
2125 opts.get('branch'))
2126 remote = hg.peer(repo, opts, remoteurl)
2126 remote = hg.peer(repo, opts, remoteurl)
2127 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2127 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2128
2128
2129 # make sure tests are repeatable
2129 # make sure tests are repeatable
2130 random.seed(12323)
2130 random.seed(12323)
2131
2131
2132 def doit(localheads, remoteheads, remote=remote):
2132 def doit(localheads, remoteheads, remote=remote):
2133 if opts.get('old'):
2133 if opts.get('old'):
2134 if localheads:
2134 if localheads:
2135 raise error.Abort('cannot use localheads with old style '
2135 raise error.Abort('cannot use localheads with old style '
2136 'discovery')
2136 'discovery')
2137 if not util.safehasattr(remote, 'branches'):
2137 if not util.safehasattr(remote, 'branches'):
2138 # enable in-client legacy support
2138 # enable in-client legacy support
2139 remote = localrepo.locallegacypeer(remote.local())
2139 remote = localrepo.locallegacypeer(remote.local())
2140 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2140 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2141 force=True)
2141 force=True)
2142 common = set(common)
2142 common = set(common)
2143 if not opts.get('nonheads'):
2143 if not opts.get('nonheads'):
2144 ui.write(("unpruned common: %s\n") %
2144 ui.write(("unpruned common: %s\n") %
2145 " ".join(sorted(short(n) for n in common)))
2145 " ".join(sorted(short(n) for n in common)))
2146 dag = dagutil.revlogdag(repo.changelog)
2146 dag = dagutil.revlogdag(repo.changelog)
2147 all = dag.ancestorset(dag.internalizeall(common))
2147 all = dag.ancestorset(dag.internalizeall(common))
2148 common = dag.externalizeall(dag.headsetofconnecteds(all))
2148 common = dag.externalizeall(dag.headsetofconnecteds(all))
2149 else:
2149 else:
2150 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2150 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2151 common = set(common)
2151 common = set(common)
2152 rheads = set(hds)
2152 rheads = set(hds)
2153 lheads = set(repo.heads())
2153 lheads = set(repo.heads())
2154 ui.write(("common heads: %s\n") %
2154 ui.write(("common heads: %s\n") %
2155 " ".join(sorted(short(n) for n in common)))
2155 " ".join(sorted(short(n) for n in common)))
2156 if lheads <= common:
2156 if lheads <= common:
2157 ui.write(("local is subset\n"))
2157 ui.write(("local is subset\n"))
2158 elif rheads <= common:
2158 elif rheads <= common:
2159 ui.write(("remote is subset\n"))
2159 ui.write(("remote is subset\n"))
2160
2160
2161 serverlogs = opts.get('serverlog')
2161 serverlogs = opts.get('serverlog')
2162 if serverlogs:
2162 if serverlogs:
2163 for filename in serverlogs:
2163 for filename in serverlogs:
2164 logfile = open(filename, 'r')
2164 logfile = open(filename, 'r')
2165 try:
2165 try:
2166 line = logfile.readline()
2166 line = logfile.readline()
2167 while line:
2167 while line:
2168 parts = line.strip().split(';')
2168 parts = line.strip().split(';')
2169 op = parts[1]
2169 op = parts[1]
2170 if op == 'cg':
2170 if op == 'cg':
2171 pass
2171 pass
2172 elif op == 'cgss':
2172 elif op == 'cgss':
2173 doit(parts[2].split(' '), parts[3].split(' '))
2173 doit(parts[2].split(' '), parts[3].split(' '))
2174 elif op == 'unb':
2174 elif op == 'unb':
2175 doit(parts[3].split(' '), parts[2].split(' '))
2175 doit(parts[3].split(' '), parts[2].split(' '))
2176 line = logfile.readline()
2176 line = logfile.readline()
2177 finally:
2177 finally:
2178 logfile.close()
2178 logfile.close()
2179
2179
2180 else:
2180 else:
2181 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2181 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2182 opts.get('remote_head'))
2182 opts.get('remote_head'))
2183 localrevs = opts.get('local_head')
2183 localrevs = opts.get('local_head')
2184 doit(localrevs, remoterevs)
2184 doit(localrevs, remoterevs)
2185
2185
2186 @command('debugextensions', formatteropts, [], norepo=True)
2186 @command('debugextensions', formatteropts, [], norepo=True)
2187 def debugextensions(ui, **opts):
2187 def debugextensions(ui, **opts):
2188 '''show information about active extensions'''
2188 '''show information about active extensions'''
2189 exts = extensions.extensions(ui)
2189 exts = extensions.extensions(ui)
2190 fm = ui.formatter('debugextensions', opts)
2190 fm = ui.formatter('debugextensions', opts)
2191 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2191 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2192 extsource = extmod.__file__
2192 extsource = extmod.__file__
2193 exttestedwith = getattr(extmod, 'testedwith', None)
2193 exttestedwith = getattr(extmod, 'testedwith', None)
2194 if exttestedwith is not None:
2194 if exttestedwith is not None:
2195 exttestedwith = exttestedwith.split()
2195 exttestedwith = exttestedwith.split()
2196 extbuglink = getattr(extmod, 'buglink', None)
2196 extbuglink = getattr(extmod, 'buglink', None)
2197
2197
2198 fm.startitem()
2198 fm.startitem()
2199
2199
2200 if ui.quiet or ui.verbose:
2200 if ui.quiet or ui.verbose:
2201 fm.write('name', '%s\n', extname)
2201 fm.write('name', '%s\n', extname)
2202 else:
2202 else:
2203 fm.write('name', '%s', extname)
2203 fm.write('name', '%s', extname)
2204 if not exttestedwith:
2204 if not exttestedwith:
2205 fm.plain(_(' (untested!)\n'))
2205 fm.plain(_(' (untested!)\n'))
2206 else:
2206 else:
2207 if exttestedwith == ['internal'] or \
2207 if exttestedwith == ['internal'] or \
2208 util.version() in exttestedwith:
2208 util.version() in exttestedwith:
2209 fm.plain('\n')
2209 fm.plain('\n')
2210 else:
2210 else:
2211 lasttestedversion = exttestedwith[-1]
2211 lasttestedversion = exttestedwith[-1]
2212 fm.plain(' (%s!)\n' % lasttestedversion)
2212 fm.plain(' (%s!)\n' % lasttestedversion)
2213
2213
2214 fm.condwrite(ui.verbose and extsource, 'source',
2214 fm.condwrite(ui.verbose and extsource, 'source',
2215 _(' location: %s\n'), extsource or "")
2215 _(' location: %s\n'), extsource or "")
2216
2216
2217 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2217 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2218 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2218 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2219
2219
2220 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2220 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2221 _(' bug reporting: %s\n'), extbuglink or "")
2221 _(' bug reporting: %s\n'), extbuglink or "")
2222
2222
2223 fm.end()
2223 fm.end()
2224
2224
2225 @command('debugfileset',
2225 @command('debugfileset',
2226 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2226 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2227 _('[-r REV] FILESPEC'))
2227 _('[-r REV] FILESPEC'))
2228 def debugfileset(ui, repo, expr, **opts):
2228 def debugfileset(ui, repo, expr, **opts):
2229 '''parse and apply a fileset specification'''
2229 '''parse and apply a fileset specification'''
2230 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2230 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2231 if ui.verbose:
2231 if ui.verbose:
2232 tree = fileset.parse(expr)
2232 tree = fileset.parse(expr)
2233 ui.note(fileset.prettyformat(tree), "\n")
2233 ui.note(fileset.prettyformat(tree), "\n")
2234
2234
2235 for f in ctx.getfileset(expr):
2235 for f in ctx.getfileset(expr):
2236 ui.write("%s\n" % f)
2236 ui.write("%s\n" % f)
2237
2237
2238 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2238 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2239 def debugfsinfo(ui, path="."):
2239 def debugfsinfo(ui, path="."):
2240 """show information detected about current filesystem"""
2240 """show information detected about current filesystem"""
2241 util.writefile('.debugfsinfo', '')
2241 util.writefile('.debugfsinfo', '')
2242 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2242 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2243 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2243 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2244 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2244 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2245 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2245 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2246 and 'yes' or 'no'))
2246 and 'yes' or 'no'))
2247 os.unlink('.debugfsinfo')
2247 os.unlink('.debugfsinfo')
2248
2248
2249 @command('debuggetbundle',
2249 @command('debuggetbundle',
2250 [('H', 'head', [], _('id of head node'), _('ID')),
2250 [('H', 'head', [], _('id of head node'), _('ID')),
2251 ('C', 'common', [], _('id of common node'), _('ID')),
2251 ('C', 'common', [], _('id of common node'), _('ID')),
2252 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2252 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2253 _('REPO FILE [-H|-C ID]...'),
2253 _('REPO FILE [-H|-C ID]...'),
2254 norepo=True)
2254 norepo=True)
2255 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2255 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2256 """retrieves a bundle from a repo
2256 """retrieves a bundle from a repo
2257
2257
2258 Every ID must be a full-length hex node id string. Saves the bundle to the
2258 Every ID must be a full-length hex node id string. Saves the bundle to the
2259 given file.
2259 given file.
2260 """
2260 """
2261 repo = hg.peer(ui, opts, repopath)
2261 repo = hg.peer(ui, opts, repopath)
2262 if not repo.capable('getbundle'):
2262 if not repo.capable('getbundle'):
2263 raise error.Abort("getbundle() not supported by target repository")
2263 raise error.Abort("getbundle() not supported by target repository")
2264 args = {}
2264 args = {}
2265 if common:
2265 if common:
2266 args['common'] = [bin(s) for s in common]
2266 args['common'] = [bin(s) for s in common]
2267 if head:
2267 if head:
2268 args['heads'] = [bin(s) for s in head]
2268 args['heads'] = [bin(s) for s in head]
2269 # TODO: get desired bundlecaps from command line.
2269 # TODO: get desired bundlecaps from command line.
2270 args['bundlecaps'] = None
2270 args['bundlecaps'] = None
2271 bundle = repo.getbundle('debug', **args)
2271 bundle = repo.getbundle('debug', **args)
2272
2272
2273 bundletype = opts.get('type', 'bzip2').lower()
2273 bundletype = opts.get('type', 'bzip2').lower()
2274 btypes = {'none': 'HG10UN',
2274 btypes = {'none': 'HG10UN',
2275 'bzip2': 'HG10BZ',
2275 'bzip2': 'HG10BZ',
2276 'gzip': 'HG10GZ',
2276 'gzip': 'HG10GZ',
2277 'bundle2': 'HG20'}
2277 'bundle2': 'HG20'}
2278 bundletype = btypes.get(bundletype)
2278 bundletype = btypes.get(bundletype)
2279 if bundletype not in changegroup.bundletypes:
2279 if bundletype not in changegroup.bundletypes:
2280 raise error.Abort(_('unknown bundle type specified with --type'))
2280 raise error.Abort(_('unknown bundle type specified with --type'))
2281 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2281 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2282
2282
2283 @command('debugignore', [], '')
2283 @command('debugignore', [], '')
2284 def debugignore(ui, repo, *values, **opts):
2284 def debugignore(ui, repo, *values, **opts):
2285 """display the combined ignore pattern"""
2285 """display the combined ignore pattern"""
2286 ignore = repo.dirstate._ignore
2286 ignore = repo.dirstate._ignore
2287 includepat = getattr(ignore, 'includepat', None)
2287 includepat = getattr(ignore, 'includepat', None)
2288 if includepat is not None:
2288 if includepat is not None:
2289 ui.write("%s\n" % includepat)
2289 ui.write("%s\n" % includepat)
2290 else:
2290 else:
2291 raise error.Abort(_("no ignore patterns found"))
2291 raise error.Abort(_("no ignore patterns found"))
2292
2292
2293 @command('debugindex',
2293 @command('debugindex',
2294 [('c', 'changelog', False, _('open changelog')),
2294 [('c', 'changelog', False, _('open changelog')),
2295 ('m', 'manifest', False, _('open manifest')),
2295 ('m', 'manifest', False, _('open manifest')),
2296 ('', 'dir', False, _('open directory manifest')),
2296 ('', 'dir', False, _('open directory manifest')),
2297 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2297 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2298 _('[-f FORMAT] -c|-m|FILE'),
2298 _('[-f FORMAT] -c|-m|FILE'),
2299 optionalrepo=True)
2299 optionalrepo=True)
2300 def debugindex(ui, repo, file_=None, **opts):
2300 def debugindex(ui, repo, file_=None, **opts):
2301 """dump the contents of an index file"""
2301 """dump the contents of an index file"""
2302 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2302 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2303 format = opts.get('format', 0)
2303 format = opts.get('format', 0)
2304 if format not in (0, 1):
2304 if format not in (0, 1):
2305 raise error.Abort(_("unknown format %d") % format)
2305 raise error.Abort(_("unknown format %d") % format)
2306
2306
2307 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2307 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2308 if generaldelta:
2308 if generaldelta:
2309 basehdr = ' delta'
2309 basehdr = ' delta'
2310 else:
2310 else:
2311 basehdr = ' base'
2311 basehdr = ' base'
2312
2312
2313 if ui.debugflag:
2313 if ui.debugflag:
2314 shortfn = hex
2314 shortfn = hex
2315 else:
2315 else:
2316 shortfn = short
2316 shortfn = short
2317
2317
2318 # There might not be anything in r, so have a sane default
2318 # There might not be anything in r, so have a sane default
2319 idlen = 12
2319 idlen = 12
2320 for i in r:
2320 for i in r:
2321 idlen = len(shortfn(r.node(i)))
2321 idlen = len(shortfn(r.node(i)))
2322 break
2322 break
2323
2323
2324 if format == 0:
2324 if format == 0:
2325 ui.write(" rev offset length " + basehdr + " linkrev"
2325 ui.write(" rev offset length " + basehdr + " linkrev"
2326 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2326 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2327 elif format == 1:
2327 elif format == 1:
2328 ui.write(" rev flag offset length"
2328 ui.write(" rev flag offset length"
2329 " size " + basehdr + " link p1 p2"
2329 " size " + basehdr + " link p1 p2"
2330 " %s\n" % "nodeid".rjust(idlen))
2330 " %s\n" % "nodeid".rjust(idlen))
2331
2331
2332 for i in r:
2332 for i in r:
2333 node = r.node(i)
2333 node = r.node(i)
2334 if generaldelta:
2334 if generaldelta:
2335 base = r.deltaparent(i)
2335 base = r.deltaparent(i)
2336 else:
2336 else:
2337 base = r.chainbase(i)
2337 base = r.chainbase(i)
2338 if format == 0:
2338 if format == 0:
2339 try:
2339 try:
2340 pp = r.parents(node)
2340 pp = r.parents(node)
2341 except Exception:
2341 except Exception:
2342 pp = [nullid, nullid]
2342 pp = [nullid, nullid]
2343 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2343 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2344 i, r.start(i), r.length(i), base, r.linkrev(i),
2344 i, r.start(i), r.length(i), base, r.linkrev(i),
2345 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2345 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2346 elif format == 1:
2346 elif format == 1:
2347 pr = r.parentrevs(i)
2347 pr = r.parentrevs(i)
2348 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2348 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2349 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2349 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2350 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2350 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2351
2351
2352 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2352 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2353 def debugindexdot(ui, repo, file_):
2353 def debugindexdot(ui, repo, file_):
2354 """dump an index DAG as a graphviz dot file"""
2354 """dump an index DAG as a graphviz dot file"""
2355 r = None
2355 r = None
2356 if repo:
2356 if repo:
2357 filelog = repo.file(file_)
2357 filelog = repo.file(file_)
2358 if len(filelog):
2358 if len(filelog):
2359 r = filelog
2359 r = filelog
2360 if not r:
2360 if not r:
2361 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2361 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2362 ui.write(("digraph G {\n"))
2362 ui.write(("digraph G {\n"))
2363 for i in r:
2363 for i in r:
2364 node = r.node(i)
2364 node = r.node(i)
2365 pp = r.parents(node)
2365 pp = r.parents(node)
2366 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2366 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2367 if pp[1] != nullid:
2367 if pp[1] != nullid:
2368 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2368 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2369 ui.write("}\n")
2369 ui.write("}\n")
2370
2370
2371 @command('debuginstall', [], '', norepo=True)
2371 @command('debuginstall', [], '', norepo=True)
2372 def debuginstall(ui):
2372 def debuginstall(ui):
2373 '''test Mercurial installation
2373 '''test Mercurial installation
2374
2374
2375 Returns 0 on success.
2375 Returns 0 on success.
2376 '''
2376 '''
2377
2377
2378 def writetemp(contents):
2378 def writetemp(contents):
2379 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2379 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2380 f = os.fdopen(fd, "wb")
2380 f = os.fdopen(fd, "wb")
2381 f.write(contents)
2381 f.write(contents)
2382 f.close()
2382 f.close()
2383 return name
2383 return name
2384
2384
2385 problems = 0
2385 problems = 0
2386
2386
2387 # encoding
2387 # encoding
2388 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2388 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2389 try:
2389 try:
2390 encoding.fromlocal("test")
2390 encoding.fromlocal("test")
2391 except error.Abort as inst:
2391 except error.Abort as inst:
2392 ui.write(" %s\n" % inst)
2392 ui.write(" %s\n" % inst)
2393 ui.write(_(" (check that your locale is properly set)\n"))
2393 ui.write(_(" (check that your locale is properly set)\n"))
2394 problems += 1
2394 problems += 1
2395
2395
2396 # Python
2396 # Python
2397 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2397 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2398 ui.status(_("checking Python version (%s)\n")
2398 ui.status(_("checking Python version (%s)\n")
2399 % ("%s.%s.%s" % sys.version_info[:3]))
2399 % ("%s.%s.%s" % sys.version_info[:3]))
2400 ui.status(_("checking Python lib (%s)...\n")
2400 ui.status(_("checking Python lib (%s)...\n")
2401 % os.path.dirname(os.__file__))
2401 % os.path.dirname(os.__file__))
2402
2402
2403 # compiled modules
2403 # compiled modules
2404 ui.status(_("checking installed modules (%s)...\n")
2404 ui.status(_("checking installed modules (%s)...\n")
2405 % os.path.dirname(__file__))
2405 % os.path.dirname(__file__))
2406 try:
2406 try:
2407 import bdiff, mpatch, base85, osutil
2407 import bdiff, mpatch, base85, osutil
2408 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2408 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2409 except Exception as inst:
2409 except Exception as inst:
2410 ui.write(" %s\n" % inst)
2410 ui.write(" %s\n" % inst)
2411 ui.write(_(" One or more extensions could not be found"))
2411 ui.write(_(" One or more extensions could not be found"))
2412 ui.write(_(" (check that you compiled the extensions)\n"))
2412 ui.write(_(" (check that you compiled the extensions)\n"))
2413 problems += 1
2413 problems += 1
2414
2414
2415 # templates
2415 # templates
2416 import templater
2416 import templater
2417 p = templater.templatepaths()
2417 p = templater.templatepaths()
2418 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2418 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2419 if p:
2419 if p:
2420 m = templater.templatepath("map-cmdline.default")
2420 m = templater.templatepath("map-cmdline.default")
2421 if m:
2421 if m:
2422 # template found, check if it is working
2422 # template found, check if it is working
2423 try:
2423 try:
2424 templater.templater(m)
2424 templater.templater(m)
2425 except Exception as inst:
2425 except Exception as inst:
2426 ui.write(" %s\n" % inst)
2426 ui.write(" %s\n" % inst)
2427 p = None
2427 p = None
2428 else:
2428 else:
2429 ui.write(_(" template 'default' not found\n"))
2429 ui.write(_(" template 'default' not found\n"))
2430 p = None
2430 p = None
2431 else:
2431 else:
2432 ui.write(_(" no template directories found\n"))
2432 ui.write(_(" no template directories found\n"))
2433 if not p:
2433 if not p:
2434 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2434 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2435 problems += 1
2435 problems += 1
2436
2436
2437 # editor
2437 # editor
2438 ui.status(_("checking commit editor...\n"))
2438 ui.status(_("checking commit editor...\n"))
2439 editor = ui.geteditor()
2439 editor = ui.geteditor()
2440 editor = util.expandpath(editor)
2440 editor = util.expandpath(editor)
2441 cmdpath = util.findexe(shlex.split(editor)[0])
2441 cmdpath = util.findexe(shlex.split(editor)[0])
2442 if not cmdpath:
2442 if not cmdpath:
2443 if editor == 'vi':
2443 if editor == 'vi':
2444 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2444 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2445 ui.write(_(" (specify a commit editor in your configuration"
2445 ui.write(_(" (specify a commit editor in your configuration"
2446 " file)\n"))
2446 " file)\n"))
2447 else:
2447 else:
2448 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2448 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2449 ui.write(_(" (specify a commit editor in your configuration"
2449 ui.write(_(" (specify a commit editor in your configuration"
2450 " file)\n"))
2450 " file)\n"))
2451 problems += 1
2451 problems += 1
2452
2452
2453 # check username
2453 # check username
2454 ui.status(_("checking username...\n"))
2454 ui.status(_("checking username...\n"))
2455 try:
2455 try:
2456 ui.username()
2456 ui.username()
2457 except error.Abort as e:
2457 except error.Abort as e:
2458 ui.write(" %s\n" % e)
2458 ui.write(" %s\n" % e)
2459 ui.write(_(" (specify a username in your configuration file)\n"))
2459 ui.write(_(" (specify a username in your configuration file)\n"))
2460 problems += 1
2460 problems += 1
2461
2461
2462 if not problems:
2462 if not problems:
2463 ui.status(_("no problems detected\n"))
2463 ui.status(_("no problems detected\n"))
2464 else:
2464 else:
2465 ui.write(_("%s problems detected,"
2465 ui.write(_("%s problems detected,"
2466 " please check your install!\n") % problems)
2466 " please check your install!\n") % problems)
2467
2467
2468 return problems
2468 return problems
2469
2469
2470 @command('debugknown', [], _('REPO ID...'), norepo=True)
2470 @command('debugknown', [], _('REPO ID...'), norepo=True)
2471 def debugknown(ui, repopath, *ids, **opts):
2471 def debugknown(ui, repopath, *ids, **opts):
2472 """test whether node ids are known to a repo
2472 """test whether node ids are known to a repo
2473
2473
2474 Every ID must be a full-length hex node id string. Returns a list of 0s
2474 Every ID must be a full-length hex node id string. Returns a list of 0s
2475 and 1s indicating unknown/known.
2475 and 1s indicating unknown/known.
2476 """
2476 """
2477 repo = hg.peer(ui, opts, repopath)
2477 repo = hg.peer(ui, opts, repopath)
2478 if not repo.capable('known'):
2478 if not repo.capable('known'):
2479 raise error.Abort("known() not supported by target repository")
2479 raise error.Abort("known() not supported by target repository")
2480 flags = repo.known([bin(s) for s in ids])
2480 flags = repo.known([bin(s) for s in ids])
2481 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2481 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2482
2482
2483 @command('debuglabelcomplete', [], _('LABEL...'))
2483 @command('debuglabelcomplete', [], _('LABEL...'))
2484 def debuglabelcomplete(ui, repo, *args):
2484 def debuglabelcomplete(ui, repo, *args):
2485 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2485 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2486 debugnamecomplete(ui, repo, *args)
2486 debugnamecomplete(ui, repo, *args)
2487
2487
2488 @command('debugmergestate', [], '')
2488 @command('debugmergestate', [], '')
2489 def debugmergestate(ui, repo, *args):
2489 def debugmergestate(ui, repo, *args):
2490 """print merge state
2490 """print merge state
2491
2491
2492 Use --verbose to print out information about whether v1 or v2 merge state
2492 Use --verbose to print out information about whether v1 or v2 merge state
2493 was chosen."""
2493 was chosen."""
2494 def printrecords(version):
2494 def printrecords(version):
2495 ui.write(('* version %s records\n') % version)
2495 ui.write(('* version %s records\n') % version)
2496 if version == 1:
2496 if version == 1:
2497 records = v1records
2497 records = v1records
2498 else:
2498 else:
2499 records = v2records
2499 records = v2records
2500
2500
2501 for rtype, record in records:
2501 for rtype, record in records:
2502 # pretty print some record types
2502 # pretty print some record types
2503 if rtype == 'L':
2503 if rtype == 'L':
2504 ui.write(('local: %s\n') % record)
2504 ui.write(('local: %s\n') % record)
2505 elif rtype == 'O':
2505 elif rtype == 'O':
2506 ui.write(('other: %s\n') % record)
2506 ui.write(('other: %s\n') % record)
2507 elif rtype == 'F':
2507 elif rtype == 'F':
2508 r = record.split('\0')
2508 r = record.split('\0')
2509 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2509 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2510 if version == 1:
2510 if version == 1:
2511 onode = 'not stored in v1 format'
2511 onode = 'not stored in v1 format'
2512 flags = r[7]
2512 flags = r[7]
2513 else:
2513 else:
2514 onode, flags = r[7:9]
2514 onode, flags = r[7:9]
2515 ui.write(('file: %s (state "%s", hash %s)\n')
2515 ui.write(('file: %s (state "%s", hash %s)\n')
2516 % (f, state, hash))
2516 % (f, state, hash))
2517 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2517 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2518 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2518 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2519 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2519 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2520 else:
2520 else:
2521 ui.write(('unrecognized entry: %s\t%s\n')
2521 ui.write(('unrecognized entry: %s\t%s\n')
2522 % (rtype, record.replace('\0', '\t')))
2522 % (rtype, record.replace('\0', '\t')))
2523
2523
2524 ms = mergemod.mergestate(repo)
2524 ms = mergemod.mergestate(repo)
2525
2525
2526 # sort so that reasonable information is on top
2526 # sort so that reasonable information is on top
2527 v1records = ms._readrecordsv1()
2527 v1records = ms._readrecordsv1()
2528 v2records = ms._readrecordsv2()
2528 v2records = ms._readrecordsv2()
2529 order = 'LO'
2529 order = 'LO'
2530 def key(r):
2530 def key(r):
2531 idx = order.find(r[0])
2531 idx = order.find(r[0])
2532 if idx == -1:
2532 if idx == -1:
2533 return (1, r[1])
2533 return (1, r[1])
2534 else:
2534 else:
2535 return (0, idx)
2535 return (0, idx)
2536 v1records.sort(key=key)
2536 v1records.sort(key=key)
2537 v2records.sort(key=key)
2537 v2records.sort(key=key)
2538
2538
2539 if not v1records and not v2records:
2539 if not v1records and not v2records:
2540 ui.write(('no merge state found\n'))
2540 ui.write(('no merge state found\n'))
2541 elif not v2records:
2541 elif not v2records:
2542 ui.note(('no version 2 merge state\n'))
2542 ui.note(('no version 2 merge state\n'))
2543 printrecords(1)
2543 printrecords(1)
2544 elif ms._v1v2match(v1records, v2records):
2544 elif ms._v1v2match(v1records, v2records):
2545 ui.note(('v1 and v2 states match: using v2\n'))
2545 ui.note(('v1 and v2 states match: using v2\n'))
2546 printrecords(2)
2546 printrecords(2)
2547 else:
2547 else:
2548 ui.note(('v1 and v2 states mismatch: using v1\n'))
2548 ui.note(('v1 and v2 states mismatch: using v1\n'))
2549 printrecords(1)
2549 printrecords(1)
2550 if ui.verbose:
2550 if ui.verbose:
2551 printrecords(2)
2551 printrecords(2)
2552
2552
2553 @command('debugnamecomplete', [], _('NAME...'))
2553 @command('debugnamecomplete', [], _('NAME...'))
2554 def debugnamecomplete(ui, repo, *args):
2554 def debugnamecomplete(ui, repo, *args):
2555 '''complete "names" - tags, open branch names, bookmark names'''
2555 '''complete "names" - tags, open branch names, bookmark names'''
2556
2556
2557 names = set()
2557 names = set()
2558 # since we previously only listed open branches, we will handle that
2558 # since we previously only listed open branches, we will handle that
2559 # specially (after this for loop)
2559 # specially (after this for loop)
2560 for name, ns in repo.names.iteritems():
2560 for name, ns in repo.names.iteritems():
2561 if name != 'branches':
2561 if name != 'branches':
2562 names.update(ns.listnames(repo))
2562 names.update(ns.listnames(repo))
2563 names.update(tag for (tag, heads, tip, closed)
2563 names.update(tag for (tag, heads, tip, closed)
2564 in repo.branchmap().iterbranches() if not closed)
2564 in repo.branchmap().iterbranches() if not closed)
2565 completions = set()
2565 completions = set()
2566 if not args:
2566 if not args:
2567 args = ['']
2567 args = ['']
2568 for a in args:
2568 for a in args:
2569 completions.update(n for n in names if n.startswith(a))
2569 completions.update(n for n in names if n.startswith(a))
2570 ui.write('\n'.join(sorted(completions)))
2570 ui.write('\n'.join(sorted(completions)))
2571 ui.write('\n')
2571 ui.write('\n')
2572
2572
2573 @command('debuglocks',
2573 @command('debuglocks',
2574 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2574 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2575 ('W', 'force-wlock', None,
2575 ('W', 'force-wlock', None,
2576 _('free the working state lock (DANGEROUS)'))],
2576 _('free the working state lock (DANGEROUS)'))],
2577 _('[OPTION]...'))
2577 _('[OPTION]...'))
2578 def debuglocks(ui, repo, **opts):
2578 def debuglocks(ui, repo, **opts):
2579 """show or modify state of locks
2579 """show or modify state of locks
2580
2580
2581 By default, this command will show which locks are held. This
2581 By default, this command will show which locks are held. This
2582 includes the user and process holding the lock, the amount of time
2582 includes the user and process holding the lock, the amount of time
2583 the lock has been held, and the machine name where the process is
2583 the lock has been held, and the machine name where the process is
2584 running if it's not local.
2584 running if it's not local.
2585
2585
2586 Locks protect the integrity of Mercurial's data, so should be
2586 Locks protect the integrity of Mercurial's data, so should be
2587 treated with care. System crashes or other interruptions may cause
2587 treated with care. System crashes or other interruptions may cause
2588 locks to not be properly released, though Mercurial will usually
2588 locks to not be properly released, though Mercurial will usually
2589 detect and remove such stale locks automatically.
2589 detect and remove such stale locks automatically.
2590
2590
2591 However, detecting stale locks may not always be possible (for
2591 However, detecting stale locks may not always be possible (for
2592 instance, on a shared filesystem). Removing locks may also be
2592 instance, on a shared filesystem). Removing locks may also be
2593 blocked by filesystem permissions.
2593 blocked by filesystem permissions.
2594
2594
2595 Returns 0 if no locks are held.
2595 Returns 0 if no locks are held.
2596
2596
2597 """
2597 """
2598
2598
2599 if opts.get('force_lock'):
2599 if opts.get('force_lock'):
2600 repo.svfs.unlink('lock')
2600 repo.svfs.unlink('lock')
2601 if opts.get('force_wlock'):
2601 if opts.get('force_wlock'):
2602 repo.vfs.unlink('wlock')
2602 repo.vfs.unlink('wlock')
2603 if opts.get('force_lock') or opts.get('force_lock'):
2603 if opts.get('force_lock') or opts.get('force_lock'):
2604 return 0
2604 return 0
2605
2605
2606 now = time.time()
2606 now = time.time()
2607 held = 0
2607 held = 0
2608
2608
2609 def report(vfs, name, method):
2609 def report(vfs, name, method):
2610 # this causes stale locks to get reaped for more accurate reporting
2610 # this causes stale locks to get reaped for more accurate reporting
2611 try:
2611 try:
2612 l = method(False)
2612 l = method(False)
2613 except error.LockHeld:
2613 except error.LockHeld:
2614 l = None
2614 l = None
2615
2615
2616 if l:
2616 if l:
2617 l.release()
2617 l.release()
2618 else:
2618 else:
2619 try:
2619 try:
2620 stat = vfs.lstat(name)
2620 stat = vfs.lstat(name)
2621 age = now - stat.st_mtime
2621 age = now - stat.st_mtime
2622 user = util.username(stat.st_uid)
2622 user = util.username(stat.st_uid)
2623 locker = vfs.readlock(name)
2623 locker = vfs.readlock(name)
2624 if ":" in locker:
2624 if ":" in locker:
2625 host, pid = locker.split(':')
2625 host, pid = locker.split(':')
2626 if host == socket.gethostname():
2626 if host == socket.gethostname():
2627 locker = 'user %s, process %s' % (user, pid)
2627 locker = 'user %s, process %s' % (user, pid)
2628 else:
2628 else:
2629 locker = 'user %s, process %s, host %s' \
2629 locker = 'user %s, process %s, host %s' \
2630 % (user, pid, host)
2630 % (user, pid, host)
2631 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2631 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2632 return 1
2632 return 1
2633 except OSError as e:
2633 except OSError as e:
2634 if e.errno != errno.ENOENT:
2634 if e.errno != errno.ENOENT:
2635 raise
2635 raise
2636
2636
2637 ui.write("%-6s free\n" % (name + ":"))
2637 ui.write("%-6s free\n" % (name + ":"))
2638 return 0
2638 return 0
2639
2639
2640 held += report(repo.svfs, "lock", repo.lock)
2640 held += report(repo.svfs, "lock", repo.lock)
2641 held += report(repo.vfs, "wlock", repo.wlock)
2641 held += report(repo.vfs, "wlock", repo.wlock)
2642
2642
2643 return held
2643 return held
2644
2644
2645 @command('debugobsolete',
2645 @command('debugobsolete',
2646 [('', 'flags', 0, _('markers flag')),
2646 [('', 'flags', 0, _('markers flag')),
2647 ('', 'record-parents', False,
2647 ('', 'record-parents', False,
2648 _('record parent information for the precursor')),
2648 _('record parent information for the precursor')),
2649 ('r', 'rev', [], _('display markers relevant to REV')),
2649 ('r', 'rev', [], _('display markers relevant to REV')),
2650 ] + commitopts2,
2650 ] + commitopts2,
2651 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2651 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2652 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2652 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2653 """create arbitrary obsolete marker
2653 """create arbitrary obsolete marker
2654
2654
2655 With no arguments, displays the list of obsolescence markers."""
2655 With no arguments, displays the list of obsolescence markers."""
2656
2656
2657 def parsenodeid(s):
2657 def parsenodeid(s):
2658 try:
2658 try:
2659 # We do not use revsingle/revrange functions here to accept
2659 # We do not use revsingle/revrange functions here to accept
2660 # arbitrary node identifiers, possibly not present in the
2660 # arbitrary node identifiers, possibly not present in the
2661 # local repository.
2661 # local repository.
2662 n = bin(s)
2662 n = bin(s)
2663 if len(n) != len(nullid):
2663 if len(n) != len(nullid):
2664 raise TypeError()
2664 raise TypeError()
2665 return n
2665 return n
2666 except TypeError:
2666 except TypeError:
2667 raise error.Abort('changeset references must be full hexadecimal '
2667 raise error.Abort('changeset references must be full hexadecimal '
2668 'node identifiers')
2668 'node identifiers')
2669
2669
2670 if precursor is not None:
2670 if precursor is not None:
2671 if opts['rev']:
2671 if opts['rev']:
2672 raise error.Abort('cannot select revision when creating marker')
2672 raise error.Abort('cannot select revision when creating marker')
2673 metadata = {}
2673 metadata = {}
2674 metadata['user'] = opts['user'] or ui.username()
2674 metadata['user'] = opts['user'] or ui.username()
2675 succs = tuple(parsenodeid(succ) for succ in successors)
2675 succs = tuple(parsenodeid(succ) for succ in successors)
2676 l = repo.lock()
2676 l = repo.lock()
2677 try:
2677 try:
2678 tr = repo.transaction('debugobsolete')
2678 tr = repo.transaction('debugobsolete')
2679 try:
2679 try:
2680 date = opts.get('date')
2680 date = opts.get('date')
2681 if date:
2681 if date:
2682 date = util.parsedate(date)
2682 date = util.parsedate(date)
2683 else:
2683 else:
2684 date = None
2684 date = None
2685 prec = parsenodeid(precursor)
2685 prec = parsenodeid(precursor)
2686 parents = None
2686 parents = None
2687 if opts['record_parents']:
2687 if opts['record_parents']:
2688 if prec not in repo.unfiltered():
2688 if prec not in repo.unfiltered():
2689 raise error.Abort('cannot used --record-parents on '
2689 raise error.Abort('cannot used --record-parents on '
2690 'unknown changesets')
2690 'unknown changesets')
2691 parents = repo.unfiltered()[prec].parents()
2691 parents = repo.unfiltered()[prec].parents()
2692 parents = tuple(p.node() for p in parents)
2692 parents = tuple(p.node() for p in parents)
2693 repo.obsstore.create(tr, prec, succs, opts['flags'],
2693 repo.obsstore.create(tr, prec, succs, opts['flags'],
2694 parents=parents, date=date,
2694 parents=parents, date=date,
2695 metadata=metadata)
2695 metadata=metadata)
2696 tr.close()
2696 tr.close()
2697 except ValueError as exc:
2697 except ValueError as exc:
2698 raise error.Abort(_('bad obsmarker input: %s') % exc)
2698 raise error.Abort(_('bad obsmarker input: %s') % exc)
2699 finally:
2699 finally:
2700 tr.release()
2700 tr.release()
2701 finally:
2701 finally:
2702 l.release()
2702 l.release()
2703 else:
2703 else:
2704 if opts['rev']:
2704 if opts['rev']:
2705 revs = scmutil.revrange(repo, opts['rev'])
2705 revs = scmutil.revrange(repo, opts['rev'])
2706 nodes = [repo[r].node() for r in revs]
2706 nodes = [repo[r].node() for r in revs]
2707 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2707 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2708 markers.sort(key=lambda x: x._data)
2708 markers.sort(key=lambda x: x._data)
2709 else:
2709 else:
2710 markers = obsolete.getmarkers(repo)
2710 markers = obsolete.getmarkers(repo)
2711
2711
2712 for m in markers:
2712 for m in markers:
2713 cmdutil.showmarker(ui, m)
2713 cmdutil.showmarker(ui, m)
2714
2714
2715 @command('debugpathcomplete',
2715 @command('debugpathcomplete',
2716 [('f', 'full', None, _('complete an entire path')),
2716 [('f', 'full', None, _('complete an entire path')),
2717 ('n', 'normal', None, _('show only normal files')),
2717 ('n', 'normal', None, _('show only normal files')),
2718 ('a', 'added', None, _('show only added files')),
2718 ('a', 'added', None, _('show only added files')),
2719 ('r', 'removed', None, _('show only removed files'))],
2719 ('r', 'removed', None, _('show only removed files'))],
2720 _('FILESPEC...'))
2720 _('FILESPEC...'))
2721 def debugpathcomplete(ui, repo, *specs, **opts):
2721 def debugpathcomplete(ui, repo, *specs, **opts):
2722 '''complete part or all of a tracked path
2722 '''complete part or all of a tracked path
2723
2723
2724 This command supports shells that offer path name completion. It
2724 This command supports shells that offer path name completion. It
2725 currently completes only files already known to the dirstate.
2725 currently completes only files already known to the dirstate.
2726
2726
2727 Completion extends only to the next path segment unless
2727 Completion extends only to the next path segment unless
2728 --full is specified, in which case entire paths are used.'''
2728 --full is specified, in which case entire paths are used.'''
2729
2729
2730 def complete(path, acceptable):
2730 def complete(path, acceptable):
2731 dirstate = repo.dirstate
2731 dirstate = repo.dirstate
2732 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2732 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2733 rootdir = repo.root + os.sep
2733 rootdir = repo.root + os.sep
2734 if spec != repo.root and not spec.startswith(rootdir):
2734 if spec != repo.root and not spec.startswith(rootdir):
2735 return [], []
2735 return [], []
2736 if os.path.isdir(spec):
2736 if os.path.isdir(spec):
2737 spec += '/'
2737 spec += '/'
2738 spec = spec[len(rootdir):]
2738 spec = spec[len(rootdir):]
2739 fixpaths = os.sep != '/'
2739 fixpaths = os.sep != '/'
2740 if fixpaths:
2740 if fixpaths:
2741 spec = spec.replace(os.sep, '/')
2741 spec = spec.replace(os.sep, '/')
2742 speclen = len(spec)
2742 speclen = len(spec)
2743 fullpaths = opts['full']
2743 fullpaths = opts['full']
2744 files, dirs = set(), set()
2744 files, dirs = set(), set()
2745 adddir, addfile = dirs.add, files.add
2745 adddir, addfile = dirs.add, files.add
2746 for f, st in dirstate.iteritems():
2746 for f, st in dirstate.iteritems():
2747 if f.startswith(spec) and st[0] in acceptable:
2747 if f.startswith(spec) and st[0] in acceptable:
2748 if fixpaths:
2748 if fixpaths:
2749 f = f.replace('/', os.sep)
2749 f = f.replace('/', os.sep)
2750 if fullpaths:
2750 if fullpaths:
2751 addfile(f)
2751 addfile(f)
2752 continue
2752 continue
2753 s = f.find(os.sep, speclen)
2753 s = f.find(os.sep, speclen)
2754 if s >= 0:
2754 if s >= 0:
2755 adddir(f[:s])
2755 adddir(f[:s])
2756 else:
2756 else:
2757 addfile(f)
2757 addfile(f)
2758 return files, dirs
2758 return files, dirs
2759
2759
2760 acceptable = ''
2760 acceptable = ''
2761 if opts['normal']:
2761 if opts['normal']:
2762 acceptable += 'nm'
2762 acceptable += 'nm'
2763 if opts['added']:
2763 if opts['added']:
2764 acceptable += 'a'
2764 acceptable += 'a'
2765 if opts['removed']:
2765 if opts['removed']:
2766 acceptable += 'r'
2766 acceptable += 'r'
2767 cwd = repo.getcwd()
2767 cwd = repo.getcwd()
2768 if not specs:
2768 if not specs:
2769 specs = ['.']
2769 specs = ['.']
2770
2770
2771 files, dirs = set(), set()
2771 files, dirs = set(), set()
2772 for spec in specs:
2772 for spec in specs:
2773 f, d = complete(spec, acceptable or 'nmar')
2773 f, d = complete(spec, acceptable or 'nmar')
2774 files.update(f)
2774 files.update(f)
2775 dirs.update(d)
2775 dirs.update(d)
2776 files.update(dirs)
2776 files.update(dirs)
2777 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2777 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2778 ui.write('\n')
2778 ui.write('\n')
2779
2779
2780 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2780 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2781 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2781 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2782 '''access the pushkey key/value protocol
2782 '''access the pushkey key/value protocol
2783
2783
2784 With two args, list the keys in the given namespace.
2784 With two args, list the keys in the given namespace.
2785
2785
2786 With five args, set a key to new if it currently is set to old.
2786 With five args, set a key to new if it currently is set to old.
2787 Reports success or failure.
2787 Reports success or failure.
2788 '''
2788 '''
2789
2789
2790 target = hg.peer(ui, {}, repopath)
2790 target = hg.peer(ui, {}, repopath)
2791 if keyinfo:
2791 if keyinfo:
2792 key, old, new = keyinfo
2792 key, old, new = keyinfo
2793 r = target.pushkey(namespace, key, old, new)
2793 r = target.pushkey(namespace, key, old, new)
2794 ui.status(str(r) + '\n')
2794 ui.status(str(r) + '\n')
2795 return not r
2795 return not r
2796 else:
2796 else:
2797 for k, v in sorted(target.listkeys(namespace).iteritems()):
2797 for k, v in sorted(target.listkeys(namespace).iteritems()):
2798 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2798 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2799 v.encode('string-escape')))
2799 v.encode('string-escape')))
2800
2800
2801 @command('debugpvec', [], _('A B'))
2801 @command('debugpvec', [], _('A B'))
2802 def debugpvec(ui, repo, a, b=None):
2802 def debugpvec(ui, repo, a, b=None):
2803 ca = scmutil.revsingle(repo, a)
2803 ca = scmutil.revsingle(repo, a)
2804 cb = scmutil.revsingle(repo, b)
2804 cb = scmutil.revsingle(repo, b)
2805 pa = pvec.ctxpvec(ca)
2805 pa = pvec.ctxpvec(ca)
2806 pb = pvec.ctxpvec(cb)
2806 pb = pvec.ctxpvec(cb)
2807 if pa == pb:
2807 if pa == pb:
2808 rel = "="
2808 rel = "="
2809 elif pa > pb:
2809 elif pa > pb:
2810 rel = ">"
2810 rel = ">"
2811 elif pa < pb:
2811 elif pa < pb:
2812 rel = "<"
2812 rel = "<"
2813 elif pa | pb:
2813 elif pa | pb:
2814 rel = "|"
2814 rel = "|"
2815 ui.write(_("a: %s\n") % pa)
2815 ui.write(_("a: %s\n") % pa)
2816 ui.write(_("b: %s\n") % pb)
2816 ui.write(_("b: %s\n") % pb)
2817 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2817 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2818 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2818 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2819 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2819 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2820 pa.distance(pb), rel))
2820 pa.distance(pb), rel))
2821
2821
2822 @command('debugrebuilddirstate|debugrebuildstate',
2822 @command('debugrebuilddirstate|debugrebuildstate',
2823 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2823 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2824 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2824 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2825 'the working copy parent')),
2825 'the working copy parent')),
2826 ],
2826 ],
2827 _('[-r REV]'))
2827 _('[-r REV]'))
2828 def debugrebuilddirstate(ui, repo, rev, **opts):
2828 def debugrebuilddirstate(ui, repo, rev, **opts):
2829 """rebuild the dirstate as it would look like for the given revision
2829 """rebuild the dirstate as it would look like for the given revision
2830
2830
2831 If no revision is specified the first current parent will be used.
2831 If no revision is specified the first current parent will be used.
2832
2832
2833 The dirstate will be set to the files of the given revision.
2833 The dirstate will be set to the files of the given revision.
2834 The actual working directory content or existing dirstate
2834 The actual working directory content or existing dirstate
2835 information such as adds or removes is not considered.
2835 information such as adds or removes is not considered.
2836
2836
2837 ``minimal`` will only rebuild the dirstate status for files that claim to be
2837 ``minimal`` will only rebuild the dirstate status for files that claim to be
2838 tracked but are not in the parent manifest, or that exist in the parent
2838 tracked but are not in the parent manifest, or that exist in the parent
2839 manifest but are not in the dirstate. It will not change adds, removes, or
2839 manifest but are not in the dirstate. It will not change adds, removes, or
2840 modified files that are in the working copy parent.
2840 modified files that are in the working copy parent.
2841
2841
2842 One use of this command is to make the next :hg:`status` invocation
2842 One use of this command is to make the next :hg:`status` invocation
2843 check the actual file content.
2843 check the actual file content.
2844 """
2844 """
2845 ctx = scmutil.revsingle(repo, rev)
2845 ctx = scmutil.revsingle(repo, rev)
2846 wlock = repo.wlock()
2846 wlock = repo.wlock()
2847 try:
2847 try:
2848 dirstate = repo.dirstate
2848 dirstate = repo.dirstate
2849
2849
2850 # See command doc for what minimal does.
2850 # See command doc for what minimal does.
2851 if opts.get('minimal'):
2851 if opts.get('minimal'):
2852 dirstatefiles = set(dirstate)
2852 dirstatefiles = set(dirstate)
2853 ctxfiles = set(ctx.manifest().keys())
2853 ctxfiles = set(ctx.manifest().keys())
2854 for file in (dirstatefiles | ctxfiles):
2854 for file in (dirstatefiles | ctxfiles):
2855 indirstate = file in dirstatefiles
2855 indirstate = file in dirstatefiles
2856 inctx = file in ctxfiles
2856 inctx = file in ctxfiles
2857
2857
2858 if indirstate and not inctx and dirstate[file] != 'a':
2858 if indirstate and not inctx and dirstate[file] != 'a':
2859 dirstate.drop(file)
2859 dirstate.drop(file)
2860 elif inctx and not indirstate:
2860 elif inctx and not indirstate:
2861 dirstate.normallookup(file)
2861 dirstate.normallookup(file)
2862 else:
2862 else:
2863 dirstate.rebuild(ctx.node(), ctx.manifest())
2863 dirstate.rebuild(ctx.node(), ctx.manifest())
2864 finally:
2864 finally:
2865 wlock.release()
2865 wlock.release()
2866
2866
2867 @command('debugrebuildfncache', [], '')
2867 @command('debugrebuildfncache', [], '')
2868 def debugrebuildfncache(ui, repo):
2868 def debugrebuildfncache(ui, repo):
2869 """rebuild the fncache file"""
2869 """rebuild the fncache file"""
2870 repair.rebuildfncache(ui, repo)
2870 repair.rebuildfncache(ui, repo)
2871
2871
2872 @command('debugrename',
2872 @command('debugrename',
2873 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2873 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2874 _('[-r REV] FILE'))
2874 _('[-r REV] FILE'))
2875 def debugrename(ui, repo, file1, *pats, **opts):
2875 def debugrename(ui, repo, file1, *pats, **opts):
2876 """dump rename information"""
2876 """dump rename information"""
2877
2877
2878 ctx = scmutil.revsingle(repo, opts.get('rev'))
2878 ctx = scmutil.revsingle(repo, opts.get('rev'))
2879 m = scmutil.match(ctx, (file1,) + pats, opts)
2879 m = scmutil.match(ctx, (file1,) + pats, opts)
2880 for abs in ctx.walk(m):
2880 for abs in ctx.walk(m):
2881 fctx = ctx[abs]
2881 fctx = ctx[abs]
2882 o = fctx.filelog().renamed(fctx.filenode())
2882 o = fctx.filelog().renamed(fctx.filenode())
2883 rel = m.rel(abs)
2883 rel = m.rel(abs)
2884 if o:
2884 if o:
2885 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2885 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2886 else:
2886 else:
2887 ui.write(_("%s not renamed\n") % rel)
2887 ui.write(_("%s not renamed\n") % rel)
2888
2888
2889 @command('debugrevlog',
2889 @command('debugrevlog',
2890 [('c', 'changelog', False, _('open changelog')),
2890 [('c', 'changelog', False, _('open changelog')),
2891 ('m', 'manifest', False, _('open manifest')),
2891 ('m', 'manifest', False, _('open manifest')),
2892 ('', 'dir', False, _('open directory manifest')),
2892 ('', 'dir', False, _('open directory manifest')),
2893 ('d', 'dump', False, _('dump index data'))],
2893 ('d', 'dump', False, _('dump index data'))],
2894 _('-c|-m|FILE'),
2894 _('-c|-m|FILE'),
2895 optionalrepo=True)
2895 optionalrepo=True)
2896 def debugrevlog(ui, repo, file_=None, **opts):
2896 def debugrevlog(ui, repo, file_=None, **opts):
2897 """show data and statistics about a revlog"""
2897 """show data and statistics about a revlog"""
2898 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2898 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2899
2899
2900 if opts.get("dump"):
2900 if opts.get("dump"):
2901 numrevs = len(r)
2901 numrevs = len(r)
2902 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2902 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2903 " rawsize totalsize compression heads chainlen\n")
2903 " rawsize totalsize compression heads chainlen\n")
2904 ts = 0
2904 ts = 0
2905 heads = set()
2905 heads = set()
2906
2906
2907 for rev in xrange(numrevs):
2907 for rev in xrange(numrevs):
2908 dbase = r.deltaparent(rev)
2908 dbase = r.deltaparent(rev)
2909 if dbase == -1:
2909 if dbase == -1:
2910 dbase = rev
2910 dbase = rev
2911 cbase = r.chainbase(rev)
2911 cbase = r.chainbase(rev)
2912 clen = r.chainlen(rev)
2912 clen = r.chainlen(rev)
2913 p1, p2 = r.parentrevs(rev)
2913 p1, p2 = r.parentrevs(rev)
2914 rs = r.rawsize(rev)
2914 rs = r.rawsize(rev)
2915 ts = ts + rs
2915 ts = ts + rs
2916 heads -= set(r.parentrevs(rev))
2916 heads -= set(r.parentrevs(rev))
2917 heads.add(rev)
2917 heads.add(rev)
2918 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2918 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2919 "%11d %5d %8d\n" %
2919 "%11d %5d %8d\n" %
2920 (rev, p1, p2, r.start(rev), r.end(rev),
2920 (rev, p1, p2, r.start(rev), r.end(rev),
2921 r.start(dbase), r.start(cbase),
2921 r.start(dbase), r.start(cbase),
2922 r.start(p1), r.start(p2),
2922 r.start(p1), r.start(p2),
2923 rs, ts, ts / r.end(rev), len(heads), clen))
2923 rs, ts, ts / r.end(rev), len(heads), clen))
2924 return 0
2924 return 0
2925
2925
2926 v = r.version
2926 v = r.version
2927 format = v & 0xFFFF
2927 format = v & 0xFFFF
2928 flags = []
2928 flags = []
2929 gdelta = False
2929 gdelta = False
2930 if v & revlog.REVLOGNGINLINEDATA:
2930 if v & revlog.REVLOGNGINLINEDATA:
2931 flags.append('inline')
2931 flags.append('inline')
2932 if v & revlog.REVLOGGENERALDELTA:
2932 if v & revlog.REVLOGGENERALDELTA:
2933 gdelta = True
2933 gdelta = True
2934 flags.append('generaldelta')
2934 flags.append('generaldelta')
2935 if not flags:
2935 if not flags:
2936 flags = ['(none)']
2936 flags = ['(none)']
2937
2937
2938 nummerges = 0
2938 nummerges = 0
2939 numfull = 0
2939 numfull = 0
2940 numprev = 0
2940 numprev = 0
2941 nump1 = 0
2941 nump1 = 0
2942 nump2 = 0
2942 nump2 = 0
2943 numother = 0
2943 numother = 0
2944 nump1prev = 0
2944 nump1prev = 0
2945 nump2prev = 0
2945 nump2prev = 0
2946 chainlengths = []
2946 chainlengths = []
2947
2947
2948 datasize = [None, 0, 0L]
2948 datasize = [None, 0, 0L]
2949 fullsize = [None, 0, 0L]
2949 fullsize = [None, 0, 0L]
2950 deltasize = [None, 0, 0L]
2950 deltasize = [None, 0, 0L]
2951
2951
2952 def addsize(size, l):
2952 def addsize(size, l):
2953 if l[0] is None or size < l[0]:
2953 if l[0] is None or size < l[0]:
2954 l[0] = size
2954 l[0] = size
2955 if size > l[1]:
2955 if size > l[1]:
2956 l[1] = size
2956 l[1] = size
2957 l[2] += size
2957 l[2] += size
2958
2958
2959 numrevs = len(r)
2959 numrevs = len(r)
2960 for rev in xrange(numrevs):
2960 for rev in xrange(numrevs):
2961 p1, p2 = r.parentrevs(rev)
2961 p1, p2 = r.parentrevs(rev)
2962 delta = r.deltaparent(rev)
2962 delta = r.deltaparent(rev)
2963 if format > 0:
2963 if format > 0:
2964 addsize(r.rawsize(rev), datasize)
2964 addsize(r.rawsize(rev), datasize)
2965 if p2 != nullrev:
2965 if p2 != nullrev:
2966 nummerges += 1
2966 nummerges += 1
2967 size = r.length(rev)
2967 size = r.length(rev)
2968 if delta == nullrev:
2968 if delta == nullrev:
2969 chainlengths.append(0)
2969 chainlengths.append(0)
2970 numfull += 1
2970 numfull += 1
2971 addsize(size, fullsize)
2971 addsize(size, fullsize)
2972 else:
2972 else:
2973 chainlengths.append(chainlengths[delta] + 1)
2973 chainlengths.append(chainlengths[delta] + 1)
2974 addsize(size, deltasize)
2974 addsize(size, deltasize)
2975 if delta == rev - 1:
2975 if delta == rev - 1:
2976 numprev += 1
2976 numprev += 1
2977 if delta == p1:
2977 if delta == p1:
2978 nump1prev += 1
2978 nump1prev += 1
2979 elif delta == p2:
2979 elif delta == p2:
2980 nump2prev += 1
2980 nump2prev += 1
2981 elif delta == p1:
2981 elif delta == p1:
2982 nump1 += 1
2982 nump1 += 1
2983 elif delta == p2:
2983 elif delta == p2:
2984 nump2 += 1
2984 nump2 += 1
2985 elif delta != nullrev:
2985 elif delta != nullrev:
2986 numother += 1
2986 numother += 1
2987
2987
2988 # Adjust size min value for empty cases
2988 # Adjust size min value for empty cases
2989 for size in (datasize, fullsize, deltasize):
2989 for size in (datasize, fullsize, deltasize):
2990 if size[0] is None:
2990 if size[0] is None:
2991 size[0] = 0
2991 size[0] = 0
2992
2992
2993 numdeltas = numrevs - numfull
2993 numdeltas = numrevs - numfull
2994 numoprev = numprev - nump1prev - nump2prev
2994 numoprev = numprev - nump1prev - nump2prev
2995 totalrawsize = datasize[2]
2995 totalrawsize = datasize[2]
2996 datasize[2] /= numrevs
2996 datasize[2] /= numrevs
2997 fulltotal = fullsize[2]
2997 fulltotal = fullsize[2]
2998 fullsize[2] /= numfull
2998 fullsize[2] /= numfull
2999 deltatotal = deltasize[2]
2999 deltatotal = deltasize[2]
3000 if numrevs - numfull > 0:
3000 if numrevs - numfull > 0:
3001 deltasize[2] /= numrevs - numfull
3001 deltasize[2] /= numrevs - numfull
3002 totalsize = fulltotal + deltatotal
3002 totalsize = fulltotal + deltatotal
3003 avgchainlen = sum(chainlengths) / numrevs
3003 avgchainlen = sum(chainlengths) / numrevs
3004 maxchainlen = max(chainlengths)
3004 maxchainlen = max(chainlengths)
3005 compratio = totalrawsize / totalsize
3005 compratio = totalrawsize / totalsize
3006
3006
3007 basedfmtstr = '%%%dd\n'
3007 basedfmtstr = '%%%dd\n'
3008 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3008 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3009
3009
3010 def dfmtstr(max):
3010 def dfmtstr(max):
3011 return basedfmtstr % len(str(max))
3011 return basedfmtstr % len(str(max))
3012 def pcfmtstr(max, padding=0):
3012 def pcfmtstr(max, padding=0):
3013 return basepcfmtstr % (len(str(max)), ' ' * padding)
3013 return basepcfmtstr % (len(str(max)), ' ' * padding)
3014
3014
3015 def pcfmt(value, total):
3015 def pcfmt(value, total):
3016 return (value, 100 * float(value) / total)
3016 return (value, 100 * float(value) / total)
3017
3017
3018 ui.write(('format : %d\n') % format)
3018 ui.write(('format : %d\n') % format)
3019 ui.write(('flags : %s\n') % ', '.join(flags))
3019 ui.write(('flags : %s\n') % ', '.join(flags))
3020
3020
3021 ui.write('\n')
3021 ui.write('\n')
3022 fmt = pcfmtstr(totalsize)
3022 fmt = pcfmtstr(totalsize)
3023 fmt2 = dfmtstr(totalsize)
3023 fmt2 = dfmtstr(totalsize)
3024 ui.write(('revisions : ') + fmt2 % numrevs)
3024 ui.write(('revisions : ') + fmt2 % numrevs)
3025 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3025 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3026 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3026 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3027 ui.write(('revisions : ') + fmt2 % numrevs)
3027 ui.write(('revisions : ') + fmt2 % numrevs)
3028 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3028 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3029 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3029 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3030 ui.write(('revision size : ') + fmt2 % totalsize)
3030 ui.write(('revision size : ') + fmt2 % totalsize)
3031 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3031 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3032 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3032 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3033
3033
3034 ui.write('\n')
3034 ui.write('\n')
3035 fmt = dfmtstr(max(avgchainlen, compratio))
3035 fmt = dfmtstr(max(avgchainlen, compratio))
3036 ui.write(('avg chain length : ') + fmt % avgchainlen)
3036 ui.write(('avg chain length : ') + fmt % avgchainlen)
3037 ui.write(('max chain length : ') + fmt % maxchainlen)
3037 ui.write(('max chain length : ') + fmt % maxchainlen)
3038 ui.write(('compression ratio : ') + fmt % compratio)
3038 ui.write(('compression ratio : ') + fmt % compratio)
3039
3039
3040 if format > 0:
3040 if format > 0:
3041 ui.write('\n')
3041 ui.write('\n')
3042 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3042 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3043 % tuple(datasize))
3043 % tuple(datasize))
3044 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3044 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3045 % tuple(fullsize))
3045 % tuple(fullsize))
3046 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3046 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3047 % tuple(deltasize))
3047 % tuple(deltasize))
3048
3048
3049 if numdeltas > 0:
3049 if numdeltas > 0:
3050 ui.write('\n')
3050 ui.write('\n')
3051 fmt = pcfmtstr(numdeltas)
3051 fmt = pcfmtstr(numdeltas)
3052 fmt2 = pcfmtstr(numdeltas, 4)
3052 fmt2 = pcfmtstr(numdeltas, 4)
3053 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3053 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3054 if numprev > 0:
3054 if numprev > 0:
3055 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3055 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3056 numprev))
3056 numprev))
3057 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3057 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3058 numprev))
3058 numprev))
3059 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3059 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3060 numprev))
3060 numprev))
3061 if gdelta:
3061 if gdelta:
3062 ui.write(('deltas against p1 : ')
3062 ui.write(('deltas against p1 : ')
3063 + fmt % pcfmt(nump1, numdeltas))
3063 + fmt % pcfmt(nump1, numdeltas))
3064 ui.write(('deltas against p2 : ')
3064 ui.write(('deltas against p2 : ')
3065 + fmt % pcfmt(nump2, numdeltas))
3065 + fmt % pcfmt(nump2, numdeltas))
3066 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3066 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3067 numdeltas))
3067 numdeltas))
3068
3068
3069 @command('debugrevspec',
3069 @command('debugrevspec',
3070 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3070 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3071 ('REVSPEC'))
3071 ('REVSPEC'))
3072 def debugrevspec(ui, repo, expr, **opts):
3072 def debugrevspec(ui, repo, expr, **opts):
3073 """parse and apply a revision specification
3073 """parse and apply a revision specification
3074
3074
3075 Use --verbose to print the parsed tree before and after aliases
3075 Use --verbose to print the parsed tree before and after aliases
3076 expansion.
3076 expansion.
3077 """
3077 """
3078 if ui.verbose:
3078 if ui.verbose:
3079 tree = revset.parse(expr, lookup=repo.__contains__)
3079 tree = revset.parse(expr, lookup=repo.__contains__)
3080 ui.note(revset.prettyformat(tree), "\n")
3080 ui.note(revset.prettyformat(tree), "\n")
3081 newtree = revset.findaliases(ui, tree)
3081 newtree = revset.findaliases(ui, tree)
3082 if newtree != tree:
3082 if newtree != tree:
3083 ui.note(revset.prettyformat(newtree), "\n")
3083 ui.note(revset.prettyformat(newtree), "\n")
3084 tree = newtree
3084 tree = newtree
3085 newtree = revset.foldconcat(tree)
3085 newtree = revset.foldconcat(tree)
3086 if newtree != tree:
3086 if newtree != tree:
3087 ui.note(revset.prettyformat(newtree), "\n")
3087 ui.note(revset.prettyformat(newtree), "\n")
3088 if opts["optimize"]:
3088 if opts["optimize"]:
3089 weight, optimizedtree = revset.optimize(newtree, True)
3089 weight, optimizedtree = revset.optimize(newtree, True)
3090 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3090 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3091 func = revset.match(ui, expr, repo)
3091 func = revset.match(ui, expr, repo)
3092 revs = func(repo)
3092 revs = func(repo)
3093 if ui.verbose:
3093 if ui.verbose:
3094 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3094 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3095 for c in revs:
3095 for c in revs:
3096 ui.write("%s\n" % c)
3096 ui.write("%s\n" % c)
3097
3097
3098 @command('debugsetparents', [], _('REV1 [REV2]'))
3098 @command('debugsetparents', [], _('REV1 [REV2]'))
3099 def debugsetparents(ui, repo, rev1, rev2=None):
3099 def debugsetparents(ui, repo, rev1, rev2=None):
3100 """manually set the parents of the current working directory
3100 """manually set the parents of the current working directory
3101
3101
3102 This is useful for writing repository conversion tools, but should
3102 This is useful for writing repository conversion tools, but should
3103 be used with care. For example, neither the working directory nor the
3103 be used with care. For example, neither the working directory nor the
3104 dirstate is updated, so file status may be incorrect after running this
3104 dirstate is updated, so file status may be incorrect after running this
3105 command.
3105 command.
3106
3106
3107 Returns 0 on success.
3107 Returns 0 on success.
3108 """
3108 """
3109
3109
3110 r1 = scmutil.revsingle(repo, rev1).node()
3110 r1 = scmutil.revsingle(repo, rev1).node()
3111 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3111 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3112
3112
3113 wlock = repo.wlock()
3113 wlock = repo.wlock()
3114 try:
3114 try:
3115 repo.dirstate.beginparentchange()
3115 repo.dirstate.beginparentchange()
3116 repo.setparents(r1, r2)
3116 repo.setparents(r1, r2)
3117 repo.dirstate.endparentchange()
3117 repo.dirstate.endparentchange()
3118 finally:
3118 finally:
3119 wlock.release()
3119 wlock.release()
3120
3120
3121 @command('debugdirstate|debugstate',
3121 @command('debugdirstate|debugstate',
3122 [('', 'nodates', None, _('do not display the saved mtime')),
3122 [('', 'nodates', None, _('do not display the saved mtime')),
3123 ('', 'datesort', None, _('sort by saved mtime'))],
3123 ('', 'datesort', None, _('sort by saved mtime'))],
3124 _('[OPTION]...'))
3124 _('[OPTION]...'))
3125 def debugstate(ui, repo, nodates=None, datesort=None):
3125 def debugstate(ui, repo, nodates=None, datesort=None):
3126 """show the contents of the current dirstate"""
3126 """show the contents of the current dirstate"""
3127 timestr = ""
3127 timestr = ""
3128 if datesort:
3128 if datesort:
3129 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3129 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3130 else:
3130 else:
3131 keyfunc = None # sort by filename
3131 keyfunc = None # sort by filename
3132 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3132 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3133 if ent[3] == -1:
3133 if ent[3] == -1:
3134 timestr = 'unset '
3134 timestr = 'unset '
3135 elif nodates:
3135 elif nodates:
3136 timestr = 'set '
3136 timestr = 'set '
3137 else:
3137 else:
3138 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3138 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3139 time.localtime(ent[3]))
3139 time.localtime(ent[3]))
3140 if ent[1] & 0o20000:
3140 if ent[1] & 0o20000:
3141 mode = 'lnk'
3141 mode = 'lnk'
3142 else:
3142 else:
3143 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3143 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3144 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3144 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3145 for f in repo.dirstate.copies():
3145 for f in repo.dirstate.copies():
3146 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3146 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3147
3147
3148 @command('debugsub',
3148 @command('debugsub',
3149 [('r', 'rev', '',
3149 [('r', 'rev', '',
3150 _('revision to check'), _('REV'))],
3150 _('revision to check'), _('REV'))],
3151 _('[-r REV] [REV]'))
3151 _('[-r REV] [REV]'))
3152 def debugsub(ui, repo, rev=None):
3152 def debugsub(ui, repo, rev=None):
3153 ctx = scmutil.revsingle(repo, rev, None)
3153 ctx = scmutil.revsingle(repo, rev, None)
3154 for k, v in sorted(ctx.substate.items()):
3154 for k, v in sorted(ctx.substate.items()):
3155 ui.write(('path %s\n') % k)
3155 ui.write(('path %s\n') % k)
3156 ui.write((' source %s\n') % v[0])
3156 ui.write((' source %s\n') % v[0])
3157 ui.write((' revision %s\n') % v[1])
3157 ui.write((' revision %s\n') % v[1])
3158
3158
3159 @command('debugsuccessorssets',
3159 @command('debugsuccessorssets',
3160 [],
3160 [],
3161 _('[REV]'))
3161 _('[REV]'))
3162 def debugsuccessorssets(ui, repo, *revs):
3162 def debugsuccessorssets(ui, repo, *revs):
3163 """show set of successors for revision
3163 """show set of successors for revision
3164
3164
3165 A successors set of changeset A is a consistent group of revisions that
3165 A successors set of changeset A is a consistent group of revisions that
3166 succeed A. It contains non-obsolete changesets only.
3166 succeed A. It contains non-obsolete changesets only.
3167
3167
3168 In most cases a changeset A has a single successors set containing a single
3168 In most cases a changeset A has a single successors set containing a single
3169 successor (changeset A replaced by A').
3169 successor (changeset A replaced by A').
3170
3170
3171 A changeset that is made obsolete with no successors are called "pruned".
3171 A changeset that is made obsolete with no successors are called "pruned".
3172 Such changesets have no successors sets at all.
3172 Such changesets have no successors sets at all.
3173
3173
3174 A changeset that has been "split" will have a successors set containing
3174 A changeset that has been "split" will have a successors set containing
3175 more than one successor.
3175 more than one successor.
3176
3176
3177 A changeset that has been rewritten in multiple different ways is called
3177 A changeset that has been rewritten in multiple different ways is called
3178 "divergent". Such changesets have multiple successor sets (each of which
3178 "divergent". Such changesets have multiple successor sets (each of which
3179 may also be split, i.e. have multiple successors).
3179 may also be split, i.e. have multiple successors).
3180
3180
3181 Results are displayed as follows::
3181 Results are displayed as follows::
3182
3182
3183 <rev1>
3183 <rev1>
3184 <successors-1A>
3184 <successors-1A>
3185 <rev2>
3185 <rev2>
3186 <successors-2A>
3186 <successors-2A>
3187 <successors-2B1> <successors-2B2> <successors-2B3>
3187 <successors-2B1> <successors-2B2> <successors-2B3>
3188
3188
3189 Here rev2 has two possible (i.e. divergent) successors sets. The first
3189 Here rev2 has two possible (i.e. divergent) successors sets. The first
3190 holds one element, whereas the second holds three (i.e. the changeset has
3190 holds one element, whereas the second holds three (i.e. the changeset has
3191 been split).
3191 been split).
3192 """
3192 """
3193 # passed to successorssets caching computation from one call to another
3193 # passed to successorssets caching computation from one call to another
3194 cache = {}
3194 cache = {}
3195 ctx2str = str
3195 ctx2str = str
3196 node2str = short
3196 node2str = short
3197 if ui.debug():
3197 if ui.debug():
3198 def ctx2str(ctx):
3198 def ctx2str(ctx):
3199 return ctx.hex()
3199 return ctx.hex()
3200 node2str = hex
3200 node2str = hex
3201 for rev in scmutil.revrange(repo, revs):
3201 for rev in scmutil.revrange(repo, revs):
3202 ctx = repo[rev]
3202 ctx = repo[rev]
3203 ui.write('%s\n'% ctx2str(ctx))
3203 ui.write('%s\n'% ctx2str(ctx))
3204 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3204 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3205 if succsset:
3205 if succsset:
3206 ui.write(' ')
3206 ui.write(' ')
3207 ui.write(node2str(succsset[0]))
3207 ui.write(node2str(succsset[0]))
3208 for node in succsset[1:]:
3208 for node in succsset[1:]:
3209 ui.write(' ')
3209 ui.write(' ')
3210 ui.write(node2str(node))
3210 ui.write(node2str(node))
3211 ui.write('\n')
3211 ui.write('\n')
3212
3212
3213 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3213 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3214 def debugwalk(ui, repo, *pats, **opts):
3214 def debugwalk(ui, repo, *pats, **opts):
3215 """show how files match on given patterns"""
3215 """show how files match on given patterns"""
3216 m = scmutil.match(repo[None], pats, opts)
3216 m = scmutil.match(repo[None], pats, opts)
3217 items = list(repo.walk(m))
3217 items = list(repo.walk(m))
3218 if not items:
3218 if not items:
3219 return
3219 return
3220 f = lambda fn: fn
3220 f = lambda fn: fn
3221 if ui.configbool('ui', 'slash') and os.sep != '/':
3221 if ui.configbool('ui', 'slash') and os.sep != '/':
3222 f = lambda fn: util.normpath(fn)
3222 f = lambda fn: util.normpath(fn)
3223 fmt = 'f %%-%ds %%-%ds %%s' % (
3223 fmt = 'f %%-%ds %%-%ds %%s' % (
3224 max([len(abs) for abs in items]),
3224 max([len(abs) for abs in items]),
3225 max([len(m.rel(abs)) for abs in items]))
3225 max([len(m.rel(abs)) for abs in items]))
3226 for abs in items:
3226 for abs in items:
3227 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3227 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3228 ui.write("%s\n" % line.rstrip())
3228 ui.write("%s\n" % line.rstrip())
3229
3229
3230 @command('debugwireargs',
3230 @command('debugwireargs',
3231 [('', 'three', '', 'three'),
3231 [('', 'three', '', 'three'),
3232 ('', 'four', '', 'four'),
3232 ('', 'four', '', 'four'),
3233 ('', 'five', '', 'five'),
3233 ('', 'five', '', 'five'),
3234 ] + remoteopts,
3234 ] + remoteopts,
3235 _('REPO [OPTIONS]... [ONE [TWO]]'),
3235 _('REPO [OPTIONS]... [ONE [TWO]]'),
3236 norepo=True)
3236 norepo=True)
3237 def debugwireargs(ui, repopath, *vals, **opts):
3237 def debugwireargs(ui, repopath, *vals, **opts):
3238 repo = hg.peer(ui, opts, repopath)
3238 repo = hg.peer(ui, opts, repopath)
3239 for opt in remoteopts:
3239 for opt in remoteopts:
3240 del opts[opt[1]]
3240 del opts[opt[1]]
3241 args = {}
3241 args = {}
3242 for k, v in opts.iteritems():
3242 for k, v in opts.iteritems():
3243 if v:
3243 if v:
3244 args[k] = v
3244 args[k] = v
3245 # run twice to check that we don't mess up the stream for the next command
3245 # run twice to check that we don't mess up the stream for the next command
3246 res1 = repo.debugwireargs(*vals, **args)
3246 res1 = repo.debugwireargs(*vals, **args)
3247 res2 = repo.debugwireargs(*vals, **args)
3247 res2 = repo.debugwireargs(*vals, **args)
3248 ui.write("%s\n" % res1)
3248 ui.write("%s\n" % res1)
3249 if res1 != res2:
3249 if res1 != res2:
3250 ui.warn("%s\n" % res2)
3250 ui.warn("%s\n" % res2)
3251
3251
3252 @command('^diff',
3252 @command('^diff',
3253 [('r', 'rev', [], _('revision'), _('REV')),
3253 [('r', 'rev', [], _('revision'), _('REV')),
3254 ('c', 'change', '', _('change made by revision'), _('REV'))
3254 ('c', 'change', '', _('change made by revision'), _('REV'))
3255 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3255 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3256 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3256 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3257 inferrepo=True)
3257 inferrepo=True)
3258 def diff(ui, repo, *pats, **opts):
3258 def diff(ui, repo, *pats, **opts):
3259 """diff repository (or selected files)
3259 """diff repository (or selected files)
3260
3260
3261 Show differences between revisions for the specified files.
3261 Show differences between revisions for the specified files.
3262
3262
3263 Differences between files are shown using the unified diff format.
3263 Differences between files are shown using the unified diff format.
3264
3264
3265 .. note::
3265 .. note::
3266
3266
3267 diff may generate unexpected results for merges, as it will
3267 diff may generate unexpected results for merges, as it will
3268 default to comparing against the working directory's first
3268 default to comparing against the working directory's first
3269 parent changeset if no revisions are specified.
3269 parent changeset if no revisions are specified.
3270
3270
3271 When two revision arguments are given, then changes are shown
3271 When two revision arguments are given, then changes are shown
3272 between those revisions. If only one revision is specified then
3272 between those revisions. If only one revision is specified then
3273 that revision is compared to the working directory, and, when no
3273 that revision is compared to the working directory, and, when no
3274 revisions are specified, the working directory files are compared
3274 revisions are specified, the working directory files are compared
3275 to its parent.
3275 to its parent.
3276
3276
3277 Alternatively you can specify -c/--change with a revision to see
3277 Alternatively you can specify -c/--change with a revision to see
3278 the changes in that changeset relative to its first parent.
3278 the changes in that changeset relative to its first parent.
3279
3279
3280 Without the -a/--text option, diff will avoid generating diffs of
3280 Without the -a/--text option, diff will avoid generating diffs of
3281 files it detects as binary. With -a, diff will generate a diff
3281 files it detects as binary. With -a, diff will generate a diff
3282 anyway, probably with undesirable results.
3282 anyway, probably with undesirable results.
3283
3283
3284 Use the -g/--git option to generate diffs in the git extended diff
3284 Use the -g/--git option to generate diffs in the git extended diff
3285 format. For more information, read :hg:`help diffs`.
3285 format. For more information, read :hg:`help diffs`.
3286
3286
3287 .. container:: verbose
3287 .. container:: verbose
3288
3288
3289 Examples:
3289 Examples:
3290
3290
3291 - compare a file in the current working directory to its parent::
3291 - compare a file in the current working directory to its parent::
3292
3292
3293 hg diff foo.c
3293 hg diff foo.c
3294
3294
3295 - compare two historical versions of a directory, with rename info::
3295 - compare two historical versions of a directory, with rename info::
3296
3296
3297 hg diff --git -r 1.0:1.2 lib/
3297 hg diff --git -r 1.0:1.2 lib/
3298
3298
3299 - get change stats relative to the last change on some date::
3299 - get change stats relative to the last change on some date::
3300
3300
3301 hg diff --stat -r "date('may 2')"
3301 hg diff --stat -r "date('may 2')"
3302
3302
3303 - diff all newly-added files that contain a keyword::
3303 - diff all newly-added files that contain a keyword::
3304
3304
3305 hg diff "set:added() and grep(GNU)"
3305 hg diff "set:added() and grep(GNU)"
3306
3306
3307 - compare a revision and its parents::
3307 - compare a revision and its parents::
3308
3308
3309 hg diff -c 9353 # compare against first parent
3309 hg diff -c 9353 # compare against first parent
3310 hg diff -r 9353^:9353 # same using revset syntax
3310 hg diff -r 9353^:9353 # same using revset syntax
3311 hg diff -r 9353^2:9353 # compare against the second parent
3311 hg diff -r 9353^2:9353 # compare against the second parent
3312
3312
3313 Returns 0 on success.
3313 Returns 0 on success.
3314 """
3314 """
3315
3315
3316 revs = opts.get('rev')
3316 revs = opts.get('rev')
3317 change = opts.get('change')
3317 change = opts.get('change')
3318 stat = opts.get('stat')
3318 stat = opts.get('stat')
3319 reverse = opts.get('reverse')
3319 reverse = opts.get('reverse')
3320
3320
3321 if revs and change:
3321 if revs and change:
3322 msg = _('cannot specify --rev and --change at the same time')
3322 msg = _('cannot specify --rev and --change at the same time')
3323 raise error.Abort(msg)
3323 raise error.Abort(msg)
3324 elif change:
3324 elif change:
3325 node2 = scmutil.revsingle(repo, change, None).node()
3325 node2 = scmutil.revsingle(repo, change, None).node()
3326 node1 = repo[node2].p1().node()
3326 node1 = repo[node2].p1().node()
3327 else:
3327 else:
3328 node1, node2 = scmutil.revpair(repo, revs)
3328 node1, node2 = scmutil.revpair(repo, revs)
3329
3329
3330 if reverse:
3330 if reverse:
3331 node1, node2 = node2, node1
3331 node1, node2 = node2, node1
3332
3332
3333 diffopts = patch.diffallopts(ui, opts)
3333 diffopts = patch.diffallopts(ui, opts)
3334 m = scmutil.match(repo[node2], pats, opts)
3334 m = scmutil.match(repo[node2], pats, opts)
3335 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3335 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3336 listsubrepos=opts.get('subrepos'),
3336 listsubrepos=opts.get('subrepos'),
3337 root=opts.get('root'))
3337 root=opts.get('root'))
3338
3338
3339 @command('^export',
3339 @command('^export',
3340 [('o', 'output', '',
3340 [('o', 'output', '',
3341 _('print output to file with formatted name'), _('FORMAT')),
3341 _('print output to file with formatted name'), _('FORMAT')),
3342 ('', 'switch-parent', None, _('diff against the second parent')),
3342 ('', 'switch-parent', None, _('diff against the second parent')),
3343 ('r', 'rev', [], _('revisions to export'), _('REV')),
3343 ('r', 'rev', [], _('revisions to export'), _('REV')),
3344 ] + diffopts,
3344 ] + diffopts,
3345 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3345 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3346 def export(ui, repo, *changesets, **opts):
3346 def export(ui, repo, *changesets, **opts):
3347 """dump the header and diffs for one or more changesets
3347 """dump the header and diffs for one or more changesets
3348
3348
3349 Print the changeset header and diffs for one or more revisions.
3349 Print the changeset header and diffs for one or more revisions.
3350 If no revision is given, the parent of the working directory is used.
3350 If no revision is given, the parent of the working directory is used.
3351
3351
3352 The information shown in the changeset header is: author, date,
3352 The information shown in the changeset header is: author, date,
3353 branch name (if non-default), changeset hash, parent(s) and commit
3353 branch name (if non-default), changeset hash, parent(s) and commit
3354 comment.
3354 comment.
3355
3355
3356 .. note::
3356 .. note::
3357
3357
3358 export may generate unexpected diff output for merge
3358 export may generate unexpected diff output for merge
3359 changesets, as it will compare the merge changeset against its
3359 changesets, as it will compare the merge changeset against its
3360 first parent only.
3360 first parent only.
3361
3361
3362 Output may be to a file, in which case the name of the file is
3362 Output may be to a file, in which case the name of the file is
3363 given using a format string. The formatting rules are as follows:
3363 given using a format string. The formatting rules are as follows:
3364
3364
3365 :``%%``: literal "%" character
3365 :``%%``: literal "%" character
3366 :``%H``: changeset hash (40 hexadecimal digits)
3366 :``%H``: changeset hash (40 hexadecimal digits)
3367 :``%N``: number of patches being generated
3367 :``%N``: number of patches being generated
3368 :``%R``: changeset revision number
3368 :``%R``: changeset revision number
3369 :``%b``: basename of the exporting repository
3369 :``%b``: basename of the exporting repository
3370 :``%h``: short-form changeset hash (12 hexadecimal digits)
3370 :``%h``: short-form changeset hash (12 hexadecimal digits)
3371 :``%m``: first line of the commit message (only alphanumeric characters)
3371 :``%m``: first line of the commit message (only alphanumeric characters)
3372 :``%n``: zero-padded sequence number, starting at 1
3372 :``%n``: zero-padded sequence number, starting at 1
3373 :``%r``: zero-padded changeset revision number
3373 :``%r``: zero-padded changeset revision number
3374
3374
3375 Without the -a/--text option, export will avoid generating diffs
3375 Without the -a/--text option, export will avoid generating diffs
3376 of files it detects as binary. With -a, export will generate a
3376 of files it detects as binary. With -a, export will generate a
3377 diff anyway, probably with undesirable results.
3377 diff anyway, probably with undesirable results.
3378
3378
3379 Use the -g/--git option to generate diffs in the git extended diff
3379 Use the -g/--git option to generate diffs in the git extended diff
3380 format. See :hg:`help diffs` for more information.
3380 format. See :hg:`help diffs` for more information.
3381
3381
3382 With the --switch-parent option, the diff will be against the
3382 With the --switch-parent option, the diff will be against the
3383 second parent. It can be useful to review a merge.
3383 second parent. It can be useful to review a merge.
3384
3384
3385 .. container:: verbose
3385 .. container:: verbose
3386
3386
3387 Examples:
3387 Examples:
3388
3388
3389 - use export and import to transplant a bugfix to the current
3389 - use export and import to transplant a bugfix to the current
3390 branch::
3390 branch::
3391
3391
3392 hg export -r 9353 | hg import -
3392 hg export -r 9353 | hg import -
3393
3393
3394 - export all the changesets between two revisions to a file with
3394 - export all the changesets between two revisions to a file with
3395 rename information::
3395 rename information::
3396
3396
3397 hg export --git -r 123:150 > changes.txt
3397 hg export --git -r 123:150 > changes.txt
3398
3398
3399 - split outgoing changes into a series of patches with
3399 - split outgoing changes into a series of patches with
3400 descriptive names::
3400 descriptive names::
3401
3401
3402 hg export -r "outgoing()" -o "%n-%m.patch"
3402 hg export -r "outgoing()" -o "%n-%m.patch"
3403
3403
3404 Returns 0 on success.
3404 Returns 0 on success.
3405 """
3405 """
3406 changesets += tuple(opts.get('rev', []))
3406 changesets += tuple(opts.get('rev', []))
3407 if not changesets:
3407 if not changesets:
3408 changesets = ['.']
3408 changesets = ['.']
3409 revs = scmutil.revrange(repo, changesets)
3409 revs = scmutil.revrange(repo, changesets)
3410 if not revs:
3410 if not revs:
3411 raise error.Abort(_("export requires at least one changeset"))
3411 raise error.Abort(_("export requires at least one changeset"))
3412 if len(revs) > 1:
3412 if len(revs) > 1:
3413 ui.note(_('exporting patches:\n'))
3413 ui.note(_('exporting patches:\n'))
3414 else:
3414 else:
3415 ui.note(_('exporting patch:\n'))
3415 ui.note(_('exporting patch:\n'))
3416 cmdutil.export(repo, revs, template=opts.get('output'),
3416 cmdutil.export(repo, revs, template=opts.get('output'),
3417 switch_parent=opts.get('switch_parent'),
3417 switch_parent=opts.get('switch_parent'),
3418 opts=patch.diffallopts(ui, opts))
3418 opts=patch.diffallopts(ui, opts))
3419
3419
3420 @command('files',
3420 @command('files',
3421 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3421 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3422 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3422 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3423 ] + walkopts + formatteropts + subrepoopts,
3423 ] + walkopts + formatteropts + subrepoopts,
3424 _('[OPTION]... [PATTERN]...'))
3424 _('[OPTION]... [PATTERN]...'))
3425 def files(ui, repo, *pats, **opts):
3425 def files(ui, repo, *pats, **opts):
3426 """list tracked files
3426 """list tracked files
3427
3427
3428 Print files under Mercurial control in the working directory or
3428 Print files under Mercurial control in the working directory or
3429 specified revision whose names match the given patterns (excluding
3429 specified revision whose names match the given patterns (excluding
3430 removed files).
3430 removed files).
3431
3431
3432 If no patterns are given to match, this command prints the names
3432 If no patterns are given to match, this command prints the names
3433 of all files under Mercurial control in the working directory.
3433 of all files under Mercurial control in the working directory.
3434
3434
3435 .. container:: verbose
3435 .. container:: verbose
3436
3436
3437 Examples:
3437 Examples:
3438
3438
3439 - list all files under the current directory::
3439 - list all files under the current directory::
3440
3440
3441 hg files .
3441 hg files .
3442
3442
3443 - shows sizes and flags for current revision::
3443 - shows sizes and flags for current revision::
3444
3444
3445 hg files -vr .
3445 hg files -vr .
3446
3446
3447 - list all files named README::
3447 - list all files named README::
3448
3448
3449 hg files -I "**/README"
3449 hg files -I "**/README"
3450
3450
3451 - list all binary files::
3451 - list all binary files::
3452
3452
3453 hg files "set:binary()"
3453 hg files "set:binary()"
3454
3454
3455 - find files containing a regular expression::
3455 - find files containing a regular expression::
3456
3456
3457 hg files "set:grep('bob')"
3457 hg files "set:grep('bob')"
3458
3458
3459 - search tracked file contents with xargs and grep::
3459 - search tracked file contents with xargs and grep::
3460
3460
3461 hg files -0 | xargs -0 grep foo
3461 hg files -0 | xargs -0 grep foo
3462
3462
3463 See :hg:`help patterns` and :hg:`help filesets` for more information
3463 See :hg:`help patterns` and :hg:`help filesets` for more information
3464 on specifying file patterns.
3464 on specifying file patterns.
3465
3465
3466 Returns 0 if a match is found, 1 otherwise.
3466 Returns 0 if a match is found, 1 otherwise.
3467
3467
3468 """
3468 """
3469 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3469 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3470
3470
3471 end = '\n'
3471 end = '\n'
3472 if opts.get('print0'):
3472 if opts.get('print0'):
3473 end = '\0'
3473 end = '\0'
3474 fm = ui.formatter('files', opts)
3474 fm = ui.formatter('files', opts)
3475 fmt = '%s' + end
3475 fmt = '%s' + end
3476
3476
3477 m = scmutil.match(ctx, pats, opts)
3477 m = scmutil.match(ctx, pats, opts)
3478 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3478 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3479
3479
3480 fm.end()
3480 fm.end()
3481
3481
3482 return ret
3482 return ret
3483
3483
3484 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3484 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3485 def forget(ui, repo, *pats, **opts):
3485 def forget(ui, repo, *pats, **opts):
3486 """forget the specified files on the next commit
3486 """forget the specified files on the next commit
3487
3487
3488 Mark the specified files so they will no longer be tracked
3488 Mark the specified files so they will no longer be tracked
3489 after the next commit.
3489 after the next commit.
3490
3490
3491 This only removes files from the current branch, not from the
3491 This only removes files from the current branch, not from the
3492 entire project history, and it does not delete them from the
3492 entire project history, and it does not delete them from the
3493 working directory.
3493 working directory.
3494
3494
3495 To delete the file from the working directory, see :hg:`remove`.
3495 To delete the file from the working directory, see :hg:`remove`.
3496
3496
3497 To undo a forget before the next commit, see :hg:`add`.
3497 To undo a forget before the next commit, see :hg:`add`.
3498
3498
3499 .. container:: verbose
3499 .. container:: verbose
3500
3500
3501 Examples:
3501 Examples:
3502
3502
3503 - forget newly-added binary files::
3503 - forget newly-added binary files::
3504
3504
3505 hg forget "set:added() and binary()"
3505 hg forget "set:added() and binary()"
3506
3506
3507 - forget files that would be excluded by .hgignore::
3507 - forget files that would be excluded by .hgignore::
3508
3508
3509 hg forget "set:hgignore()"
3509 hg forget "set:hgignore()"
3510
3510
3511 Returns 0 on success.
3511 Returns 0 on success.
3512 """
3512 """
3513
3513
3514 if not pats:
3514 if not pats:
3515 raise error.Abort(_('no files specified'))
3515 raise error.Abort(_('no files specified'))
3516
3516
3517 m = scmutil.match(repo[None], pats, opts)
3517 m = scmutil.match(repo[None], pats, opts)
3518 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3518 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3519 return rejected and 1 or 0
3519 return rejected and 1 or 0
3520
3520
3521 @command(
3521 @command(
3522 'graft',
3522 'graft',
3523 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3523 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3524 ('c', 'continue', False, _('resume interrupted graft')),
3524 ('c', 'continue', False, _('resume interrupted graft')),
3525 ('e', 'edit', False, _('invoke editor on commit messages')),
3525 ('e', 'edit', False, _('invoke editor on commit messages')),
3526 ('', 'log', None, _('append graft info to log message')),
3526 ('', 'log', None, _('append graft info to log message')),
3527 ('f', 'force', False, _('force graft')),
3527 ('f', 'force', False, _('force graft')),
3528 ('D', 'currentdate', False,
3528 ('D', 'currentdate', False,
3529 _('record the current date as commit date')),
3529 _('record the current date as commit date')),
3530 ('U', 'currentuser', False,
3530 ('U', 'currentuser', False,
3531 _('record the current user as committer'), _('DATE'))]
3531 _('record the current user as committer'), _('DATE'))]
3532 + commitopts2 + mergetoolopts + dryrunopts,
3532 + commitopts2 + mergetoolopts + dryrunopts,
3533 _('[OPTION]... [-r] REV...'))
3533 _('[OPTION]... [-r] REV...'))
3534 def graft(ui, repo, *revs, **opts):
3534 def graft(ui, repo, *revs, **opts):
3535 '''copy changes from other branches onto the current branch
3535 '''copy changes from other branches onto the current branch
3536
3536
3537 This command uses Mercurial's merge logic to copy individual
3537 This command uses Mercurial's merge logic to copy individual
3538 changes from other branches without merging branches in the
3538 changes from other branches without merging branches in the
3539 history graph. This is sometimes known as 'backporting' or
3539 history graph. This is sometimes known as 'backporting' or
3540 'cherry-picking'. By default, graft will copy user, date, and
3540 'cherry-picking'. By default, graft will copy user, date, and
3541 description from the source changesets.
3541 description from the source changesets.
3542
3542
3543 Changesets that are ancestors of the current revision, that have
3543 Changesets that are ancestors of the current revision, that have
3544 already been grafted, or that are merges will be skipped.
3544 already been grafted, or that are merges will be skipped.
3545
3545
3546 If --log is specified, log messages will have a comment appended
3546 If --log is specified, log messages will have a comment appended
3547 of the form::
3547 of the form::
3548
3548
3549 (grafted from CHANGESETHASH)
3549 (grafted from CHANGESETHASH)
3550
3550
3551 If --force is specified, revisions will be grafted even if they
3551 If --force is specified, revisions will be grafted even if they
3552 are already ancestors of or have been grafted to the destination.
3552 are already ancestors of or have been grafted to the destination.
3553 This is useful when the revisions have since been backed out.
3553 This is useful when the revisions have since been backed out.
3554
3554
3555 If a graft merge results in conflicts, the graft process is
3555 If a graft merge results in conflicts, the graft process is
3556 interrupted so that the current merge can be manually resolved.
3556 interrupted so that the current merge can be manually resolved.
3557 Once all conflicts are addressed, the graft process can be
3557 Once all conflicts are addressed, the graft process can be
3558 continued with the -c/--continue option.
3558 continued with the -c/--continue option.
3559
3559
3560 .. note::
3560 .. note::
3561
3561
3562 The -c/--continue option does not reapply earlier options, except
3562 The -c/--continue option does not reapply earlier options, except
3563 for --force.
3563 for --force.
3564
3564
3565 .. container:: verbose
3565 .. container:: verbose
3566
3566
3567 Examples:
3567 Examples:
3568
3568
3569 - copy a single change to the stable branch and edit its description::
3569 - copy a single change to the stable branch and edit its description::
3570
3570
3571 hg update stable
3571 hg update stable
3572 hg graft --edit 9393
3572 hg graft --edit 9393
3573
3573
3574 - graft a range of changesets with one exception, updating dates::
3574 - graft a range of changesets with one exception, updating dates::
3575
3575
3576 hg graft -D "2085::2093 and not 2091"
3576 hg graft -D "2085::2093 and not 2091"
3577
3577
3578 - continue a graft after resolving conflicts::
3578 - continue a graft after resolving conflicts::
3579
3579
3580 hg graft -c
3580 hg graft -c
3581
3581
3582 - show the source of a grafted changeset::
3582 - show the source of a grafted changeset::
3583
3583
3584 hg log --debug -r .
3584 hg log --debug -r .
3585
3585
3586 See :hg:`help revisions` and :hg:`help revsets` for more about
3586 See :hg:`help revisions` and :hg:`help revsets` for more about
3587 specifying revisions.
3587 specifying revisions.
3588
3588
3589 Returns 0 on successful completion.
3589 Returns 0 on successful completion.
3590 '''
3590 '''
3591
3591
3592 revs = list(revs)
3592 revs = list(revs)
3593 revs.extend(opts['rev'])
3593 revs.extend(opts['rev'])
3594
3594
3595 if not opts.get('user') and opts.get('currentuser'):
3595 if not opts.get('user') and opts.get('currentuser'):
3596 opts['user'] = ui.username()
3596 opts['user'] = ui.username()
3597 if not opts.get('date') and opts.get('currentdate'):
3597 if not opts.get('date') and opts.get('currentdate'):
3598 opts['date'] = "%d %d" % util.makedate()
3598 opts['date'] = "%d %d" % util.makedate()
3599
3599
3600 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3600 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3601
3601
3602 cont = False
3602 cont = False
3603 if opts['continue']:
3603 if opts['continue']:
3604 cont = True
3604 cont = True
3605 if revs:
3605 if revs:
3606 raise error.Abort(_("can't specify --continue and revisions"))
3606 raise error.Abort(_("can't specify --continue and revisions"))
3607 # read in unfinished revisions
3607 # read in unfinished revisions
3608 try:
3608 try:
3609 nodes = repo.vfs.read('graftstate').splitlines()
3609 nodes = repo.vfs.read('graftstate').splitlines()
3610 revs = [repo[node].rev() for node in nodes]
3610 revs = [repo[node].rev() for node in nodes]
3611 except IOError as inst:
3611 except IOError as inst:
3612 if inst.errno != errno.ENOENT:
3612 if inst.errno != errno.ENOENT:
3613 raise
3613 raise
3614 raise error.Abort(_("no graft state found, can't continue"))
3614 raise error.Abort(_("no graft state found, can't continue"))
3615 else:
3615 else:
3616 cmdutil.checkunfinished(repo)
3616 cmdutil.checkunfinished(repo)
3617 cmdutil.bailifchanged(repo)
3617 cmdutil.bailifchanged(repo)
3618 if not revs:
3618 if not revs:
3619 raise error.Abort(_('no revisions specified'))
3619 raise error.Abort(_('no revisions specified'))
3620 revs = scmutil.revrange(repo, revs)
3620 revs = scmutil.revrange(repo, revs)
3621
3621
3622 skipped = set()
3622 skipped = set()
3623 # check for merges
3623 # check for merges
3624 for rev in repo.revs('%ld and merge()', revs):
3624 for rev in repo.revs('%ld and merge()', revs):
3625 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3625 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3626 skipped.add(rev)
3626 skipped.add(rev)
3627 revs = [r for r in revs if r not in skipped]
3627 revs = [r for r in revs if r not in skipped]
3628 if not revs:
3628 if not revs:
3629 return -1
3629 return -1
3630
3630
3631 # Don't check in the --continue case, in effect retaining --force across
3631 # Don't check in the --continue case, in effect retaining --force across
3632 # --continues. That's because without --force, any revisions we decided to
3632 # --continues. That's because without --force, any revisions we decided to
3633 # skip would have been filtered out here, so they wouldn't have made their
3633 # skip would have been filtered out here, so they wouldn't have made their
3634 # way to the graftstate. With --force, any revisions we would have otherwise
3634 # way to the graftstate. With --force, any revisions we would have otherwise
3635 # skipped would not have been filtered out, and if they hadn't been applied
3635 # skipped would not have been filtered out, and if they hadn't been applied
3636 # already, they'd have been in the graftstate.
3636 # already, they'd have been in the graftstate.
3637 if not (cont or opts.get('force')):
3637 if not (cont or opts.get('force')):
3638 # check for ancestors of dest branch
3638 # check for ancestors of dest branch
3639 crev = repo['.'].rev()
3639 crev = repo['.'].rev()
3640 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3640 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3641 # Cannot use x.remove(y) on smart set, this has to be a list.
3641 # Cannot use x.remove(y) on smart set, this has to be a list.
3642 # XXX make this lazy in the future
3642 # XXX make this lazy in the future
3643 revs = list(revs)
3643 revs = list(revs)
3644 # don't mutate while iterating, create a copy
3644 # don't mutate while iterating, create a copy
3645 for rev in list(revs):
3645 for rev in list(revs):
3646 if rev in ancestors:
3646 if rev in ancestors:
3647 ui.warn(_('skipping ancestor revision %d:%s\n') %
3647 ui.warn(_('skipping ancestor revision %d:%s\n') %
3648 (rev, repo[rev]))
3648 (rev, repo[rev]))
3649 # XXX remove on list is slow
3649 # XXX remove on list is slow
3650 revs.remove(rev)
3650 revs.remove(rev)
3651 if not revs:
3651 if not revs:
3652 return -1
3652 return -1
3653
3653
3654 # analyze revs for earlier grafts
3654 # analyze revs for earlier grafts
3655 ids = {}
3655 ids = {}
3656 for ctx in repo.set("%ld", revs):
3656 for ctx in repo.set("%ld", revs):
3657 ids[ctx.hex()] = ctx.rev()
3657 ids[ctx.hex()] = ctx.rev()
3658 n = ctx.extra().get('source')
3658 n = ctx.extra().get('source')
3659 if n:
3659 if n:
3660 ids[n] = ctx.rev()
3660 ids[n] = ctx.rev()
3661
3661
3662 # check ancestors for earlier grafts
3662 # check ancestors for earlier grafts
3663 ui.debug('scanning for duplicate grafts\n')
3663 ui.debug('scanning for duplicate grafts\n')
3664
3664
3665 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3665 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3666 ctx = repo[rev]
3666 ctx = repo[rev]
3667 n = ctx.extra().get('source')
3667 n = ctx.extra().get('source')
3668 if n in ids:
3668 if n in ids:
3669 try:
3669 try:
3670 r = repo[n].rev()
3670 r = repo[n].rev()
3671 except error.RepoLookupError:
3671 except error.RepoLookupError:
3672 r = None
3672 r = None
3673 if r in revs:
3673 if r in revs:
3674 ui.warn(_('skipping revision %d:%s '
3674 ui.warn(_('skipping revision %d:%s '
3675 '(already grafted to %d:%s)\n')
3675 '(already grafted to %d:%s)\n')
3676 % (r, repo[r], rev, ctx))
3676 % (r, repo[r], rev, ctx))
3677 revs.remove(r)
3677 revs.remove(r)
3678 elif ids[n] in revs:
3678 elif ids[n] in revs:
3679 if r is None:
3679 if r is None:
3680 ui.warn(_('skipping already grafted revision %d:%s '
3680 ui.warn(_('skipping already grafted revision %d:%s '
3681 '(%d:%s also has unknown origin %s)\n')
3681 '(%d:%s also has unknown origin %s)\n')
3682 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3682 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3683 else:
3683 else:
3684 ui.warn(_('skipping already grafted revision %d:%s '
3684 ui.warn(_('skipping already grafted revision %d:%s '
3685 '(%d:%s also has origin %d:%s)\n')
3685 '(%d:%s also has origin %d:%s)\n')
3686 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3686 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3687 revs.remove(ids[n])
3687 revs.remove(ids[n])
3688 elif ctx.hex() in ids:
3688 elif ctx.hex() in ids:
3689 r = ids[ctx.hex()]
3689 r = ids[ctx.hex()]
3690 ui.warn(_('skipping already grafted revision %d:%s '
3690 ui.warn(_('skipping already grafted revision %d:%s '
3691 '(was grafted from %d:%s)\n') %
3691 '(was grafted from %d:%s)\n') %
3692 (r, repo[r], rev, ctx))
3692 (r, repo[r], rev, ctx))
3693 revs.remove(r)
3693 revs.remove(r)
3694 if not revs:
3694 if not revs:
3695 return -1
3695 return -1
3696
3696
3697 wlock = repo.wlock()
3697 wlock = repo.wlock()
3698 try:
3698 try:
3699 for pos, ctx in enumerate(repo.set("%ld", revs)):
3699 for pos, ctx in enumerate(repo.set("%ld", revs)):
3700 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3700 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3701 ctx.description().split('\n', 1)[0])
3701 ctx.description().split('\n', 1)[0])
3702 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3702 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3703 if names:
3703 if names:
3704 desc += ' (%s)' % ' '.join(names)
3704 desc += ' (%s)' % ' '.join(names)
3705 ui.status(_('grafting %s\n') % desc)
3705 ui.status(_('grafting %s\n') % desc)
3706 if opts.get('dry_run'):
3706 if opts.get('dry_run'):
3707 continue
3707 continue
3708
3708
3709 source = ctx.extra().get('source')
3709 source = ctx.extra().get('source')
3710 extra = {}
3710 extra = {}
3711 if source:
3711 if source:
3712 extra['source'] = source
3712 extra['source'] = source
3713 extra['intermediate-source'] = ctx.hex()
3713 extra['intermediate-source'] = ctx.hex()
3714 else:
3714 else:
3715 extra['source'] = ctx.hex()
3715 extra['source'] = ctx.hex()
3716 user = ctx.user()
3716 user = ctx.user()
3717 if opts.get('user'):
3717 if opts.get('user'):
3718 user = opts['user']
3718 user = opts['user']
3719 date = ctx.date()
3719 date = ctx.date()
3720 if opts.get('date'):
3720 if opts.get('date'):
3721 date = opts['date']
3721 date = opts['date']
3722 message = ctx.description()
3722 message = ctx.description()
3723 if opts.get('log'):
3723 if opts.get('log'):
3724 message += '\n(grafted from %s)' % ctx.hex()
3724 message += '\n(grafted from %s)' % ctx.hex()
3725
3725
3726 # we don't merge the first commit when continuing
3726 # we don't merge the first commit when continuing
3727 if not cont:
3727 if not cont:
3728 # perform the graft merge with p1(rev) as 'ancestor'
3728 # perform the graft merge with p1(rev) as 'ancestor'
3729 try:
3729 try:
3730 # ui.forcemerge is an internal variable, do not document
3730 # ui.forcemerge is an internal variable, do not document
3731 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3731 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3732 'graft')
3732 'graft')
3733 stats = mergemod.graft(repo, ctx, ctx.p1(),
3733 stats = mergemod.graft(repo, ctx, ctx.p1(),
3734 ['local', 'graft'])
3734 ['local', 'graft'])
3735 finally:
3735 finally:
3736 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3736 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3737 # report any conflicts
3737 # report any conflicts
3738 if stats and stats[3] > 0:
3738 if stats and stats[3] > 0:
3739 # write out state for --continue
3739 # write out state for --continue
3740 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3740 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3741 repo.vfs.write('graftstate', ''.join(nodelines))
3741 repo.vfs.write('graftstate', ''.join(nodelines))
3742 raise error.Abort(
3742 raise error.Abort(
3743 _("unresolved conflicts, can't continue"),
3743 _("unresolved conflicts, can't continue"),
3744 hint=_('use hg resolve and hg graft --continue'))
3744 hint=_('use hg resolve and hg graft --continue'))
3745 else:
3745 else:
3746 cont = False
3746 cont = False
3747
3747
3748 # commit
3748 # commit
3749 node = repo.commit(text=message, user=user,
3749 node = repo.commit(text=message, user=user,
3750 date=date, extra=extra, editor=editor)
3750 date=date, extra=extra, editor=editor)
3751 if node is None:
3751 if node is None:
3752 ui.warn(
3752 ui.warn(
3753 _('note: graft of %d:%s created no changes to commit\n') %
3753 _('note: graft of %d:%s created no changes to commit\n') %
3754 (ctx.rev(), ctx))
3754 (ctx.rev(), ctx))
3755 finally:
3755 finally:
3756 wlock.release()
3756 wlock.release()
3757
3757
3758 # remove state when we complete successfully
3758 # remove state when we complete successfully
3759 if not opts.get('dry_run'):
3759 if not opts.get('dry_run'):
3760 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3760 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3761
3761
3762 return 0
3762 return 0
3763
3763
3764 @command('grep',
3764 @command('grep',
3765 [('0', 'print0', None, _('end fields with NUL')),
3765 [('0', 'print0', None, _('end fields with NUL')),
3766 ('', 'all', None, _('print all revisions that match')),
3766 ('', 'all', None, _('print all revisions that match')),
3767 ('a', 'text', None, _('treat all files as text')),
3767 ('a', 'text', None, _('treat all files as text')),
3768 ('f', 'follow', None,
3768 ('f', 'follow', None,
3769 _('follow changeset history,'
3769 _('follow changeset history,'
3770 ' or file history across copies and renames')),
3770 ' or file history across copies and renames')),
3771 ('i', 'ignore-case', None, _('ignore case when matching')),
3771 ('i', 'ignore-case', None, _('ignore case when matching')),
3772 ('l', 'files-with-matches', None,
3772 ('l', 'files-with-matches', None,
3773 _('print only filenames and revisions that match')),
3773 _('print only filenames and revisions that match')),
3774 ('n', 'line-number', None, _('print matching line numbers')),
3774 ('n', 'line-number', None, _('print matching line numbers')),
3775 ('r', 'rev', [],
3775 ('r', 'rev', [],
3776 _('only search files changed within revision range'), _('REV')),
3776 _('only search files changed within revision range'), _('REV')),
3777 ('u', 'user', None, _('list the author (long with -v)')),
3777 ('u', 'user', None, _('list the author (long with -v)')),
3778 ('d', 'date', None, _('list the date (short with -q)')),
3778 ('d', 'date', None, _('list the date (short with -q)')),
3779 ] + walkopts,
3779 ] + walkopts,
3780 _('[OPTION]... PATTERN [FILE]...'),
3780 _('[OPTION]... PATTERN [FILE]...'),
3781 inferrepo=True)
3781 inferrepo=True)
3782 def grep(ui, repo, pattern, *pats, **opts):
3782 def grep(ui, repo, pattern, *pats, **opts):
3783 """search for a pattern in specified files and revisions
3783 """search for a pattern in specified files and revisions
3784
3784
3785 Search revisions of files for a regular expression.
3785 Search revisions of files for a regular expression.
3786
3786
3787 This command behaves differently than Unix grep. It only accepts
3787 This command behaves differently than Unix grep. It only accepts
3788 Python/Perl regexps. It searches repository history, not the
3788 Python/Perl regexps. It searches repository history, not the
3789 working directory. It always prints the revision number in which a
3789 working directory. It always prints the revision number in which a
3790 match appears.
3790 match appears.
3791
3791
3792 By default, grep only prints output for the first revision of a
3792 By default, grep only prints output for the first revision of a
3793 file in which it finds a match. To get it to print every revision
3793 file in which it finds a match. To get it to print every revision
3794 that contains a change in match status ("-" for a match that
3794 that contains a change in match status ("-" for a match that
3795 becomes a non-match, or "+" for a non-match that becomes a match),
3795 becomes a non-match, or "+" for a non-match that becomes a match),
3796 use the --all flag.
3796 use the --all flag.
3797
3797
3798 Returns 0 if a match is found, 1 otherwise.
3798 Returns 0 if a match is found, 1 otherwise.
3799 """
3799 """
3800 reflags = re.M
3800 reflags = re.M
3801 if opts.get('ignore_case'):
3801 if opts.get('ignore_case'):
3802 reflags |= re.I
3802 reflags |= re.I
3803 try:
3803 try:
3804 regexp = util.re.compile(pattern, reflags)
3804 regexp = util.re.compile(pattern, reflags)
3805 except re.error as inst:
3805 except re.error as inst:
3806 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3806 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3807 return 1
3807 return 1
3808 sep, eol = ':', '\n'
3808 sep, eol = ':', '\n'
3809 if opts.get('print0'):
3809 if opts.get('print0'):
3810 sep = eol = '\0'
3810 sep = eol = '\0'
3811
3811
3812 getfile = util.lrucachefunc(repo.file)
3812 getfile = util.lrucachefunc(repo.file)
3813
3813
3814 def matchlines(body):
3814 def matchlines(body):
3815 begin = 0
3815 begin = 0
3816 linenum = 0
3816 linenum = 0
3817 while begin < len(body):
3817 while begin < len(body):
3818 match = regexp.search(body, begin)
3818 match = regexp.search(body, begin)
3819 if not match:
3819 if not match:
3820 break
3820 break
3821 mstart, mend = match.span()
3821 mstart, mend = match.span()
3822 linenum += body.count('\n', begin, mstart) + 1
3822 linenum += body.count('\n', begin, mstart) + 1
3823 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3823 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3824 begin = body.find('\n', mend) + 1 or len(body) + 1
3824 begin = body.find('\n', mend) + 1 or len(body) + 1
3825 lend = begin - 1
3825 lend = begin - 1
3826 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3826 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3827
3827
3828 class linestate(object):
3828 class linestate(object):
3829 def __init__(self, line, linenum, colstart, colend):
3829 def __init__(self, line, linenum, colstart, colend):
3830 self.line = line
3830 self.line = line
3831 self.linenum = linenum
3831 self.linenum = linenum
3832 self.colstart = colstart
3832 self.colstart = colstart
3833 self.colend = colend
3833 self.colend = colend
3834
3834
3835 def __hash__(self):
3835 def __hash__(self):
3836 return hash((self.linenum, self.line))
3836 return hash((self.linenum, self.line))
3837
3837
3838 def __eq__(self, other):
3838 def __eq__(self, other):
3839 return self.line == other.line
3839 return self.line == other.line
3840
3840
3841 def __iter__(self):
3841 def __iter__(self):
3842 yield (self.line[:self.colstart], '')
3842 yield (self.line[:self.colstart], '')
3843 yield (self.line[self.colstart:self.colend], 'grep.match')
3843 yield (self.line[self.colstart:self.colend], 'grep.match')
3844 rest = self.line[self.colend:]
3844 rest = self.line[self.colend:]
3845 while rest != '':
3845 while rest != '':
3846 match = regexp.search(rest)
3846 match = regexp.search(rest)
3847 if not match:
3847 if not match:
3848 yield (rest, '')
3848 yield (rest, '')
3849 break
3849 break
3850 mstart, mend = match.span()
3850 mstart, mend = match.span()
3851 yield (rest[:mstart], '')
3851 yield (rest[:mstart], '')
3852 yield (rest[mstart:mend], 'grep.match')
3852 yield (rest[mstart:mend], 'grep.match')
3853 rest = rest[mend:]
3853 rest = rest[mend:]
3854
3854
3855 matches = {}
3855 matches = {}
3856 copies = {}
3856 copies = {}
3857 def grepbody(fn, rev, body):
3857 def grepbody(fn, rev, body):
3858 matches[rev].setdefault(fn, [])
3858 matches[rev].setdefault(fn, [])
3859 m = matches[rev][fn]
3859 m = matches[rev][fn]
3860 for lnum, cstart, cend, line in matchlines(body):
3860 for lnum, cstart, cend, line in matchlines(body):
3861 s = linestate(line, lnum, cstart, cend)
3861 s = linestate(line, lnum, cstart, cend)
3862 m.append(s)
3862 m.append(s)
3863
3863
3864 def difflinestates(a, b):
3864 def difflinestates(a, b):
3865 sm = difflib.SequenceMatcher(None, a, b)
3865 sm = difflib.SequenceMatcher(None, a, b)
3866 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3866 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3867 if tag == 'insert':
3867 if tag == 'insert':
3868 for i in xrange(blo, bhi):
3868 for i in xrange(blo, bhi):
3869 yield ('+', b[i])
3869 yield ('+', b[i])
3870 elif tag == 'delete':
3870 elif tag == 'delete':
3871 for i in xrange(alo, ahi):
3871 for i in xrange(alo, ahi):
3872 yield ('-', a[i])
3872 yield ('-', a[i])
3873 elif tag == 'replace':
3873 elif tag == 'replace':
3874 for i in xrange(alo, ahi):
3874 for i in xrange(alo, ahi):
3875 yield ('-', a[i])
3875 yield ('-', a[i])
3876 for i in xrange(blo, bhi):
3876 for i in xrange(blo, bhi):
3877 yield ('+', b[i])
3877 yield ('+', b[i])
3878
3878
3879 def display(fn, ctx, pstates, states):
3879 def display(fn, ctx, pstates, states):
3880 rev = ctx.rev()
3880 rev = ctx.rev()
3881 if ui.quiet:
3881 if ui.quiet:
3882 datefunc = util.shortdate
3882 datefunc = util.shortdate
3883 else:
3883 else:
3884 datefunc = util.datestr
3884 datefunc = util.datestr
3885 found = False
3885 found = False
3886 @util.cachefunc
3886 @util.cachefunc
3887 def binary():
3887 def binary():
3888 flog = getfile(fn)
3888 flog = getfile(fn)
3889 return util.binary(flog.read(ctx.filenode(fn)))
3889 return util.binary(flog.read(ctx.filenode(fn)))
3890
3890
3891 if opts.get('all'):
3891 if opts.get('all'):
3892 iter = difflinestates(pstates, states)
3892 iter = difflinestates(pstates, states)
3893 else:
3893 else:
3894 iter = [('', l) for l in states]
3894 iter = [('', l) for l in states]
3895 for change, l in iter:
3895 for change, l in iter:
3896 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3896 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3897
3897
3898 if opts.get('line_number'):
3898 if opts.get('line_number'):
3899 cols.append((str(l.linenum), 'grep.linenumber'))
3899 cols.append((str(l.linenum), 'grep.linenumber'))
3900 if opts.get('all'):
3900 if opts.get('all'):
3901 cols.append((change, 'grep.change'))
3901 cols.append((change, 'grep.change'))
3902 if opts.get('user'):
3902 if opts.get('user'):
3903 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3903 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3904 if opts.get('date'):
3904 if opts.get('date'):
3905 cols.append((datefunc(ctx.date()), 'grep.date'))
3905 cols.append((datefunc(ctx.date()), 'grep.date'))
3906 for col, label in cols[:-1]:
3906 for col, label in cols[:-1]:
3907 ui.write(col, label=label)
3907 ui.write(col, label=label)
3908 ui.write(sep, label='grep.sep')
3908 ui.write(sep, label='grep.sep')
3909 ui.write(cols[-1][0], label=cols[-1][1])
3909 ui.write(cols[-1][0], label=cols[-1][1])
3910 if not opts.get('files_with_matches'):
3910 if not opts.get('files_with_matches'):
3911 ui.write(sep, label='grep.sep')
3911 ui.write(sep, label='grep.sep')
3912 if not opts.get('text') and binary():
3912 if not opts.get('text') and binary():
3913 ui.write(" Binary file matches")
3913 ui.write(" Binary file matches")
3914 else:
3914 else:
3915 for s, label in l:
3915 for s, label in l:
3916 ui.write(s, label=label)
3916 ui.write(s, label=label)
3917 ui.write(eol)
3917 ui.write(eol)
3918 found = True
3918 found = True
3919 if opts.get('files_with_matches'):
3919 if opts.get('files_with_matches'):
3920 break
3920 break
3921 return found
3921 return found
3922
3922
3923 skip = {}
3923 skip = {}
3924 revfiles = {}
3924 revfiles = {}
3925 matchfn = scmutil.match(repo[None], pats, opts)
3925 matchfn = scmutil.match(repo[None], pats, opts)
3926 found = False
3926 found = False
3927 follow = opts.get('follow')
3927 follow = opts.get('follow')
3928
3928
3929 def prep(ctx, fns):
3929 def prep(ctx, fns):
3930 rev = ctx.rev()
3930 rev = ctx.rev()
3931 pctx = ctx.p1()
3931 pctx = ctx.p1()
3932 parent = pctx.rev()
3932 parent = pctx.rev()
3933 matches.setdefault(rev, {})
3933 matches.setdefault(rev, {})
3934 matches.setdefault(parent, {})
3934 matches.setdefault(parent, {})
3935 files = revfiles.setdefault(rev, [])
3935 files = revfiles.setdefault(rev, [])
3936 for fn in fns:
3936 for fn in fns:
3937 flog = getfile(fn)
3937 flog = getfile(fn)
3938 try:
3938 try:
3939 fnode = ctx.filenode(fn)
3939 fnode = ctx.filenode(fn)
3940 except error.LookupError:
3940 except error.LookupError:
3941 continue
3941 continue
3942
3942
3943 copied = flog.renamed(fnode)
3943 copied = flog.renamed(fnode)
3944 copy = follow and copied and copied[0]
3944 copy = follow and copied and copied[0]
3945 if copy:
3945 if copy:
3946 copies.setdefault(rev, {})[fn] = copy
3946 copies.setdefault(rev, {})[fn] = copy
3947 if fn in skip:
3947 if fn in skip:
3948 if copy:
3948 if copy:
3949 skip[copy] = True
3949 skip[copy] = True
3950 continue
3950 continue
3951 files.append(fn)
3951 files.append(fn)
3952
3952
3953 if fn not in matches[rev]:
3953 if fn not in matches[rev]:
3954 grepbody(fn, rev, flog.read(fnode))
3954 grepbody(fn, rev, flog.read(fnode))
3955
3955
3956 pfn = copy or fn
3956 pfn = copy or fn
3957 if pfn not in matches[parent]:
3957 if pfn not in matches[parent]:
3958 try:
3958 try:
3959 fnode = pctx.filenode(pfn)
3959 fnode = pctx.filenode(pfn)
3960 grepbody(pfn, parent, flog.read(fnode))
3960 grepbody(pfn, parent, flog.read(fnode))
3961 except error.LookupError:
3961 except error.LookupError:
3962 pass
3962 pass
3963
3963
3964 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3964 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3965 rev = ctx.rev()
3965 rev = ctx.rev()
3966 parent = ctx.p1().rev()
3966 parent = ctx.p1().rev()
3967 for fn in sorted(revfiles.get(rev, [])):
3967 for fn in sorted(revfiles.get(rev, [])):
3968 states = matches[rev][fn]
3968 states = matches[rev][fn]
3969 copy = copies.get(rev, {}).get(fn)
3969 copy = copies.get(rev, {}).get(fn)
3970 if fn in skip:
3970 if fn in skip:
3971 if copy:
3971 if copy:
3972 skip[copy] = True
3972 skip[copy] = True
3973 continue
3973 continue
3974 pstates = matches.get(parent, {}).get(copy or fn, [])
3974 pstates = matches.get(parent, {}).get(copy or fn, [])
3975 if pstates or states:
3975 if pstates or states:
3976 r = display(fn, ctx, pstates, states)
3976 r = display(fn, ctx, pstates, states)
3977 found = found or r
3977 found = found or r
3978 if r and not opts.get('all'):
3978 if r and not opts.get('all'):
3979 skip[fn] = True
3979 skip[fn] = True
3980 if copy:
3980 if copy:
3981 skip[copy] = True
3981 skip[copy] = True
3982 del matches[rev]
3982 del matches[rev]
3983 del revfiles[rev]
3983 del revfiles[rev]
3984
3984
3985 return not found
3985 return not found
3986
3986
3987 @command('heads',
3987 @command('heads',
3988 [('r', 'rev', '',
3988 [('r', 'rev', '',
3989 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3989 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3990 ('t', 'topo', False, _('show topological heads only')),
3990 ('t', 'topo', False, _('show topological heads only')),
3991 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3991 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3992 ('c', 'closed', False, _('show normal and closed branch heads')),
3992 ('c', 'closed', False, _('show normal and closed branch heads')),
3993 ] + templateopts,
3993 ] + templateopts,
3994 _('[-ct] [-r STARTREV] [REV]...'))
3994 _('[-ct] [-r STARTREV] [REV]...'))
3995 def heads(ui, repo, *branchrevs, **opts):
3995 def heads(ui, repo, *branchrevs, **opts):
3996 """show branch heads
3996 """show branch heads
3997
3997
3998 With no arguments, show all open branch heads in the repository.
3998 With no arguments, show all open branch heads in the repository.
3999 Branch heads are changesets that have no descendants on the
3999 Branch heads are changesets that have no descendants on the
4000 same branch. They are where development generally takes place and
4000 same branch. They are where development generally takes place and
4001 are the usual targets for update and merge operations.
4001 are the usual targets for update and merge operations.
4002
4002
4003 If one or more REVs are given, only open branch heads on the
4003 If one or more REVs are given, only open branch heads on the
4004 branches associated with the specified changesets are shown. This
4004 branches associated with the specified changesets are shown. This
4005 means that you can use :hg:`heads .` to see the heads on the
4005 means that you can use :hg:`heads .` to see the heads on the
4006 currently checked-out branch.
4006 currently checked-out branch.
4007
4007
4008 If -c/--closed is specified, also show branch heads marked closed
4008 If -c/--closed is specified, also show branch heads marked closed
4009 (see :hg:`commit --close-branch`).
4009 (see :hg:`commit --close-branch`).
4010
4010
4011 If STARTREV is specified, only those heads that are descendants of
4011 If STARTREV is specified, only those heads that are descendants of
4012 STARTREV will be displayed.
4012 STARTREV will be displayed.
4013
4013
4014 If -t/--topo is specified, named branch mechanics will be ignored and only
4014 If -t/--topo is specified, named branch mechanics will be ignored and only
4015 topological heads (changesets with no children) will be shown.
4015 topological heads (changesets with no children) will be shown.
4016
4016
4017 Returns 0 if matching heads are found, 1 if not.
4017 Returns 0 if matching heads are found, 1 if not.
4018 """
4018 """
4019
4019
4020 start = None
4020 start = None
4021 if 'rev' in opts:
4021 if 'rev' in opts:
4022 start = scmutil.revsingle(repo, opts['rev'], None).node()
4022 start = scmutil.revsingle(repo, opts['rev'], None).node()
4023
4023
4024 if opts.get('topo'):
4024 if opts.get('topo'):
4025 heads = [repo[h] for h in repo.heads(start)]
4025 heads = [repo[h] for h in repo.heads(start)]
4026 else:
4026 else:
4027 heads = []
4027 heads = []
4028 for branch in repo.branchmap():
4028 for branch in repo.branchmap():
4029 heads += repo.branchheads(branch, start, opts.get('closed'))
4029 heads += repo.branchheads(branch, start, opts.get('closed'))
4030 heads = [repo[h] for h in heads]
4030 heads = [repo[h] for h in heads]
4031
4031
4032 if branchrevs:
4032 if branchrevs:
4033 branches = set(repo[br].branch() for br in branchrevs)
4033 branches = set(repo[br].branch() for br in branchrevs)
4034 heads = [h for h in heads if h.branch() in branches]
4034 heads = [h for h in heads if h.branch() in branches]
4035
4035
4036 if opts.get('active') and branchrevs:
4036 if opts.get('active') and branchrevs:
4037 dagheads = repo.heads(start)
4037 dagheads = repo.heads(start)
4038 heads = [h for h in heads if h.node() in dagheads]
4038 heads = [h for h in heads if h.node() in dagheads]
4039
4039
4040 if branchrevs:
4040 if branchrevs:
4041 haveheads = set(h.branch() for h in heads)
4041 haveheads = set(h.branch() for h in heads)
4042 if branches - haveheads:
4042 if branches - haveheads:
4043 headless = ', '.join(b for b in branches - haveheads)
4043 headless = ', '.join(b for b in branches - haveheads)
4044 msg = _('no open branch heads found on branches %s')
4044 msg = _('no open branch heads found on branches %s')
4045 if opts.get('rev'):
4045 if opts.get('rev'):
4046 msg += _(' (started at %s)') % opts['rev']
4046 msg += _(' (started at %s)') % opts['rev']
4047 ui.warn((msg + '\n') % headless)
4047 ui.warn((msg + '\n') % headless)
4048
4048
4049 if not heads:
4049 if not heads:
4050 return 1
4050 return 1
4051
4051
4052 heads = sorted(heads, key=lambda x: -x.rev())
4052 heads = sorted(heads, key=lambda x: -x.rev())
4053 displayer = cmdutil.show_changeset(ui, repo, opts)
4053 displayer = cmdutil.show_changeset(ui, repo, opts)
4054 for ctx in heads:
4054 for ctx in heads:
4055 displayer.show(ctx)
4055 displayer.show(ctx)
4056 displayer.close()
4056 displayer.close()
4057
4057
4058 @command('help',
4058 @command('help',
4059 [('e', 'extension', None, _('show only help for extensions')),
4059 [('e', 'extension', None, _('show only help for extensions')),
4060 ('c', 'command', None, _('show only help for commands')),
4060 ('c', 'command', None, _('show only help for commands')),
4061 ('k', 'keyword', None, _('show topics matching keyword')),
4061 ('k', 'keyword', None, _('show topics matching keyword')),
4062 ],
4062 ],
4063 _('[-eck] [TOPIC]'),
4063 _('[-eck] [TOPIC]'),
4064 norepo=True)
4064 norepo=True)
4065 def help_(ui, name=None, **opts):
4065 def help_(ui, name=None, **opts):
4066 """show help for a given topic or a help overview
4066 """show help for a given topic or a help overview
4067
4067
4068 With no arguments, print a list of commands with short help messages.
4068 With no arguments, print a list of commands with short help messages.
4069
4069
4070 Given a topic, extension, or command name, print help for that
4070 Given a topic, extension, or command name, print help for that
4071 topic.
4071 topic.
4072
4072
4073 Returns 0 if successful.
4073 Returns 0 if successful.
4074 """
4074 """
4075
4075
4076 textwidth = min(ui.termwidth(), 80) - 2
4076 textwidth = min(ui.termwidth(), 80) - 2
4077
4077
4078 keep = []
4078 keep = []
4079 if ui.verbose:
4079 if ui.verbose:
4080 keep.append('verbose')
4080 keep.append('verbose')
4081 if sys.platform.startswith('win'):
4081 if sys.platform.startswith('win'):
4082 keep.append('windows')
4082 keep.append('windows')
4083 elif sys.platform == 'OpenVMS':
4083 elif sys.platform == 'OpenVMS':
4084 keep.append('vms')
4084 keep.append('vms')
4085 elif sys.platform == 'plan9':
4085 elif sys.platform == 'plan9':
4086 keep.append('plan9')
4086 keep.append('plan9')
4087 else:
4087 else:
4088 keep.append('unix')
4088 keep.append('unix')
4089 keep.append(sys.platform.lower())
4089 keep.append(sys.platform.lower())
4090
4090
4091 section = None
4091 section = None
4092 if name and '.' in name:
4092 if name and '.' in name:
4093 name, section = name.split('.', 1)
4093 name, section = name.split('.', 1)
4094 section = section.lower()
4094 section = section.lower()
4095
4095
4096 text = help.help_(ui, name, **opts)
4096 text = help.help_(ui, name, **opts)
4097
4097
4098 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4098 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4099 section=section)
4099 section=section)
4100
4100
4101 # We could have been given a weird ".foo" section without a name
4101 # We could have been given a weird ".foo" section without a name
4102 # to look for, or we could have simply failed to found "foo.bar"
4102 # to look for, or we could have simply failed to found "foo.bar"
4103 # because bar isn't a section of foo
4103 # because bar isn't a section of foo
4104 if section and not (formatted and name):
4104 if section and not (formatted and name):
4105 raise error.Abort(_("help section not found"))
4105 raise error.Abort(_("help section not found"))
4106
4106
4107 if 'verbose' in pruned:
4107 if 'verbose' in pruned:
4108 keep.append('omitted')
4108 keep.append('omitted')
4109 else:
4109 else:
4110 keep.append('notomitted')
4110 keep.append('notomitted')
4111 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4111 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4112 section=section)
4112 section=section)
4113 ui.write(formatted)
4113 ui.write(formatted)
4114
4114
4115
4115
4116 @command('identify|id',
4116 @command('identify|id',
4117 [('r', 'rev', '',
4117 [('r', 'rev', '',
4118 _('identify the specified revision'), _('REV')),
4118 _('identify the specified revision'), _('REV')),
4119 ('n', 'num', None, _('show local revision number')),
4119 ('n', 'num', None, _('show local revision number')),
4120 ('i', 'id', None, _('show global revision id')),
4120 ('i', 'id', None, _('show global revision id')),
4121 ('b', 'branch', None, _('show branch')),
4121 ('b', 'branch', None, _('show branch')),
4122 ('t', 'tags', None, _('show tags')),
4122 ('t', 'tags', None, _('show tags')),
4123 ('B', 'bookmarks', None, _('show bookmarks')),
4123 ('B', 'bookmarks', None, _('show bookmarks')),
4124 ] + remoteopts,
4124 ] + remoteopts,
4125 _('[-nibtB] [-r REV] [SOURCE]'),
4125 _('[-nibtB] [-r REV] [SOURCE]'),
4126 optionalrepo=True)
4126 optionalrepo=True)
4127 def identify(ui, repo, source=None, rev=None,
4127 def identify(ui, repo, source=None, rev=None,
4128 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4128 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4129 """identify the working directory or specified revision
4129 """identify the working directory or specified revision
4130
4130
4131 Print a summary identifying the repository state at REV using one or
4131 Print a summary identifying the repository state at REV using one or
4132 two parent hash identifiers, followed by a "+" if the working
4132 two parent hash identifiers, followed by a "+" if the working
4133 directory has uncommitted changes, the branch name (if not default),
4133 directory has uncommitted changes, the branch name (if not default),
4134 a list of tags, and a list of bookmarks.
4134 a list of tags, and a list of bookmarks.
4135
4135
4136 When REV is not given, print a summary of the current state of the
4136 When REV is not given, print a summary of the current state of the
4137 repository.
4137 repository.
4138
4138
4139 Specifying a path to a repository root or Mercurial bundle will
4139 Specifying a path to a repository root or Mercurial bundle will
4140 cause lookup to operate on that repository/bundle.
4140 cause lookup to operate on that repository/bundle.
4141
4141
4142 .. container:: verbose
4142 .. container:: verbose
4143
4143
4144 Examples:
4144 Examples:
4145
4145
4146 - generate a build identifier for the working directory::
4146 - generate a build identifier for the working directory::
4147
4147
4148 hg id --id > build-id.dat
4148 hg id --id > build-id.dat
4149
4149
4150 - find the revision corresponding to a tag::
4150 - find the revision corresponding to a tag::
4151
4151
4152 hg id -n -r 1.3
4152 hg id -n -r 1.3
4153
4153
4154 - check the most recent revision of a remote repository::
4154 - check the most recent revision of a remote repository::
4155
4155
4156 hg id -r tip http://selenic.com/hg/
4156 hg id -r tip http://selenic.com/hg/
4157
4157
4158 Returns 0 if successful.
4158 Returns 0 if successful.
4159 """
4159 """
4160
4160
4161 if not repo and not source:
4161 if not repo and not source:
4162 raise error.Abort(_("there is no Mercurial repository here "
4162 raise error.Abort(_("there is no Mercurial repository here "
4163 "(.hg not found)"))
4163 "(.hg not found)"))
4164
4164
4165 if ui.debugflag:
4165 if ui.debugflag:
4166 hexfunc = hex
4166 hexfunc = hex
4167 else:
4167 else:
4168 hexfunc = short
4168 hexfunc = short
4169 default = not (num or id or branch or tags or bookmarks)
4169 default = not (num or id or branch or tags or bookmarks)
4170 output = []
4170 output = []
4171 revs = []
4171 revs = []
4172
4172
4173 if source:
4173 if source:
4174 source, branches = hg.parseurl(ui.expandpath(source))
4174 source, branches = hg.parseurl(ui.expandpath(source))
4175 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4175 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4176 repo = peer.local()
4176 repo = peer.local()
4177 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4177 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4178
4178
4179 if not repo:
4179 if not repo:
4180 if num or branch or tags:
4180 if num or branch or tags:
4181 raise error.Abort(
4181 raise error.Abort(
4182 _("can't query remote revision number, branch, or tags"))
4182 _("can't query remote revision number, branch, or tags"))
4183 if not rev and revs:
4183 if not rev and revs:
4184 rev = revs[0]
4184 rev = revs[0]
4185 if not rev:
4185 if not rev:
4186 rev = "tip"
4186 rev = "tip"
4187
4187
4188 remoterev = peer.lookup(rev)
4188 remoterev = peer.lookup(rev)
4189 if default or id:
4189 if default or id:
4190 output = [hexfunc(remoterev)]
4190 output = [hexfunc(remoterev)]
4191
4191
4192 def getbms():
4192 def getbms():
4193 bms = []
4193 bms = []
4194
4194
4195 if 'bookmarks' in peer.listkeys('namespaces'):
4195 if 'bookmarks' in peer.listkeys('namespaces'):
4196 hexremoterev = hex(remoterev)
4196 hexremoterev = hex(remoterev)
4197 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4197 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4198 if bmr == hexremoterev]
4198 if bmr == hexremoterev]
4199
4199
4200 return sorted(bms)
4200 return sorted(bms)
4201
4201
4202 if bookmarks:
4202 if bookmarks:
4203 output.extend(getbms())
4203 output.extend(getbms())
4204 elif default and not ui.quiet:
4204 elif default and not ui.quiet:
4205 # multiple bookmarks for a single parent separated by '/'
4205 # multiple bookmarks for a single parent separated by '/'
4206 bm = '/'.join(getbms())
4206 bm = '/'.join(getbms())
4207 if bm:
4207 if bm:
4208 output.append(bm)
4208 output.append(bm)
4209 else:
4209 else:
4210 ctx = scmutil.revsingle(repo, rev, None)
4210 ctx = scmutil.revsingle(repo, rev, None)
4211
4211
4212 if ctx.rev() is None:
4212 if ctx.rev() is None:
4213 ctx = repo[None]
4213 ctx = repo[None]
4214 parents = ctx.parents()
4214 parents = ctx.parents()
4215 taglist = []
4215 taglist = []
4216 for p in parents:
4216 for p in parents:
4217 taglist.extend(p.tags())
4217 taglist.extend(p.tags())
4218
4218
4219 changed = ""
4219 changed = ""
4220 if default or id or num:
4220 if default or id or num:
4221 if (any(repo.status())
4221 if (any(repo.status())
4222 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4222 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4223 changed = '+'
4223 changed = '+'
4224 if default or id:
4224 if default or id:
4225 output = ["%s%s" %
4225 output = ["%s%s" %
4226 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4226 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4227 if num:
4227 if num:
4228 output.append("%s%s" %
4228 output.append("%s%s" %
4229 ('+'.join([str(p.rev()) for p in parents]), changed))
4229 ('+'.join([str(p.rev()) for p in parents]), changed))
4230 else:
4230 else:
4231 if default or id:
4231 if default or id:
4232 output = [hexfunc(ctx.node())]
4232 output = [hexfunc(ctx.node())]
4233 if num:
4233 if num:
4234 output.append(str(ctx.rev()))
4234 output.append(str(ctx.rev()))
4235 taglist = ctx.tags()
4235 taglist = ctx.tags()
4236
4236
4237 if default and not ui.quiet:
4237 if default and not ui.quiet:
4238 b = ctx.branch()
4238 b = ctx.branch()
4239 if b != 'default':
4239 if b != 'default':
4240 output.append("(%s)" % b)
4240 output.append("(%s)" % b)
4241
4241
4242 # multiple tags for a single parent separated by '/'
4242 # multiple tags for a single parent separated by '/'
4243 t = '/'.join(taglist)
4243 t = '/'.join(taglist)
4244 if t:
4244 if t:
4245 output.append(t)
4245 output.append(t)
4246
4246
4247 # multiple bookmarks for a single parent separated by '/'
4247 # multiple bookmarks for a single parent separated by '/'
4248 bm = '/'.join(ctx.bookmarks())
4248 bm = '/'.join(ctx.bookmarks())
4249 if bm:
4249 if bm:
4250 output.append(bm)
4250 output.append(bm)
4251 else:
4251 else:
4252 if branch:
4252 if branch:
4253 output.append(ctx.branch())
4253 output.append(ctx.branch())
4254
4254
4255 if tags:
4255 if tags:
4256 output.extend(taglist)
4256 output.extend(taglist)
4257
4257
4258 if bookmarks:
4258 if bookmarks:
4259 output.extend(ctx.bookmarks())
4259 output.extend(ctx.bookmarks())
4260
4260
4261 ui.write("%s\n" % ' '.join(output))
4261 ui.write("%s\n" % ' '.join(output))
4262
4262
4263 @command('import|patch',
4263 @command('import|patch',
4264 [('p', 'strip', 1,
4264 [('p', 'strip', 1,
4265 _('directory strip option for patch. This has the same '
4265 _('directory strip option for patch. This has the same '
4266 'meaning as the corresponding patch option'), _('NUM')),
4266 'meaning as the corresponding patch option'), _('NUM')),
4267 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4267 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4268 ('e', 'edit', False, _('invoke editor on commit messages')),
4268 ('e', 'edit', False, _('invoke editor on commit messages')),
4269 ('f', 'force', None,
4269 ('f', 'force', None,
4270 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4270 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4271 ('', 'no-commit', None,
4271 ('', 'no-commit', None,
4272 _("don't commit, just update the working directory")),
4272 _("don't commit, just update the working directory")),
4273 ('', 'bypass', None,
4273 ('', 'bypass', None,
4274 _("apply patch without touching the working directory")),
4274 _("apply patch without touching the working directory")),
4275 ('', 'partial', None,
4275 ('', 'partial', None,
4276 _('commit even if some hunks fail')),
4276 _('commit even if some hunks fail')),
4277 ('', 'exact', None,
4277 ('', 'exact', None,
4278 _('apply patch to the nodes from which it was generated')),
4278 _('apply patch to the nodes from which it was generated')),
4279 ('', 'prefix', '',
4279 ('', 'prefix', '',
4280 _('apply patch to subdirectory'), _('DIR')),
4280 _('apply patch to subdirectory'), _('DIR')),
4281 ('', 'import-branch', None,
4281 ('', 'import-branch', None,
4282 _('use any branch information in patch (implied by --exact)'))] +
4282 _('use any branch information in patch (implied by --exact)'))] +
4283 commitopts + commitopts2 + similarityopts,
4283 commitopts + commitopts2 + similarityopts,
4284 _('[OPTION]... PATCH...'))
4284 _('[OPTION]... PATCH...'))
4285 def import_(ui, repo, patch1=None, *patches, **opts):
4285 def import_(ui, repo, patch1=None, *patches, **opts):
4286 """import an ordered set of patches
4286 """import an ordered set of patches
4287
4287
4288 Import a list of patches and commit them individually (unless
4288 Import a list of patches and commit them individually (unless
4289 --no-commit is specified).
4289 --no-commit is specified).
4290
4290
4291 Because import first applies changes to the working directory,
4291 Because import first applies changes to the working directory,
4292 import will abort if there are outstanding changes.
4292 import will abort if there are outstanding changes.
4293
4293
4294 You can import a patch straight from a mail message. Even patches
4294 You can import a patch straight from a mail message. Even patches
4295 as attachments work (to use the body part, it must have type
4295 as attachments work (to use the body part, it must have type
4296 text/plain or text/x-patch). From and Subject headers of email
4296 text/plain or text/x-patch). From and Subject headers of email
4297 message are used as default committer and commit message. All
4297 message are used as default committer and commit message. All
4298 text/plain body parts before first diff are added to commit
4298 text/plain body parts before first diff are added to commit
4299 message.
4299 message.
4300
4300
4301 If the imported patch was generated by :hg:`export`, user and
4301 If the imported patch was generated by :hg:`export`, user and
4302 description from patch override values from message headers and
4302 description from patch override values from message headers and
4303 body. Values given on command line with -m/--message and -u/--user
4303 body. Values given on command line with -m/--message and -u/--user
4304 override these.
4304 override these.
4305
4305
4306 If --exact is specified, import will set the working directory to
4306 If --exact is specified, import will set the working directory to
4307 the parent of each patch before applying it, and will abort if the
4307 the parent of each patch before applying it, and will abort if the
4308 resulting changeset has a different ID than the one recorded in
4308 resulting changeset has a different ID than the one recorded in
4309 the patch. This may happen due to character set problems or other
4309 the patch. This may happen due to character set problems or other
4310 deficiencies in the text patch format.
4310 deficiencies in the text patch format.
4311
4311
4312 Use --bypass to apply and commit patches directly to the
4312 Use --bypass to apply and commit patches directly to the
4313 repository, not touching the working directory. Without --exact,
4313 repository, not touching the working directory. Without --exact,
4314 patches will be applied on top of the working directory parent
4314 patches will be applied on top of the working directory parent
4315 revision.
4315 revision.
4316
4316
4317 With -s/--similarity, hg will attempt to discover renames and
4317 With -s/--similarity, hg will attempt to discover renames and
4318 copies in the patch in the same way as :hg:`addremove`.
4318 copies in the patch in the same way as :hg:`addremove`.
4319
4319
4320 Use --partial to ensure a changeset will be created from the patch
4320 Use --partial to ensure a changeset will be created from the patch
4321 even if some hunks fail to apply. Hunks that fail to apply will be
4321 even if some hunks fail to apply. Hunks that fail to apply will be
4322 written to a <target-file>.rej file. Conflicts can then be resolved
4322 written to a <target-file>.rej file. Conflicts can then be resolved
4323 by hand before :hg:`commit --amend` is run to update the created
4323 by hand before :hg:`commit --amend` is run to update the created
4324 changeset. This flag exists to let people import patches that
4324 changeset. This flag exists to let people import patches that
4325 partially apply without losing the associated metadata (author,
4325 partially apply without losing the associated metadata (author,
4326 date, description, ...). Note that when none of the hunk applies
4326 date, description, ...). Note that when none of the hunk applies
4327 cleanly, :hg:`import --partial` will create an empty changeset,
4327 cleanly, :hg:`import --partial` will create an empty changeset,
4328 importing only the patch metadata.
4328 importing only the patch metadata.
4329
4329
4330 It is possible to use external patch programs to perform the patch
4330 It is possible to use external patch programs to perform the patch
4331 by setting the ``ui.patch`` configuration option. For the default
4331 by setting the ``ui.patch`` configuration option. For the default
4332 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4332 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4333 See :hg:`help config` for more information about configuration
4333 See :hg:`help config` for more information about configuration
4334 files and how to use these options.
4334 files and how to use these options.
4335
4335
4336 To read a patch from standard input, use "-" as the patch name. If
4336 To read a patch from standard input, use "-" as the patch name. If
4337 a URL is specified, the patch will be downloaded from it.
4337 a URL is specified, the patch will be downloaded from it.
4338 See :hg:`help dates` for a list of formats valid for -d/--date.
4338 See :hg:`help dates` for a list of formats valid for -d/--date.
4339
4339
4340 .. container:: verbose
4340 .. container:: verbose
4341
4341
4342 Examples:
4342 Examples:
4343
4343
4344 - import a traditional patch from a website and detect renames::
4344 - import a traditional patch from a website and detect renames::
4345
4345
4346 hg import -s 80 http://example.com/bugfix.patch
4346 hg import -s 80 http://example.com/bugfix.patch
4347
4347
4348 - import a changeset from an hgweb server::
4348 - import a changeset from an hgweb server::
4349
4349
4350 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4350 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4351
4351
4352 - import all the patches in an Unix-style mbox::
4352 - import all the patches in an Unix-style mbox::
4353
4353
4354 hg import incoming-patches.mbox
4354 hg import incoming-patches.mbox
4355
4355
4356 - attempt to exactly restore an exported changeset (not always
4356 - attempt to exactly restore an exported changeset (not always
4357 possible)::
4357 possible)::
4358
4358
4359 hg import --exact proposed-fix.patch
4359 hg import --exact proposed-fix.patch
4360
4360
4361 - use an external tool to apply a patch which is too fuzzy for
4361 - use an external tool to apply a patch which is too fuzzy for
4362 the default internal tool.
4362 the default internal tool.
4363
4363
4364 hg import --config ui.patch="patch --merge" fuzzy.patch
4364 hg import --config ui.patch="patch --merge" fuzzy.patch
4365
4365
4366 - change the default fuzzing from 2 to a less strict 7
4366 - change the default fuzzing from 2 to a less strict 7
4367
4367
4368 hg import --config ui.fuzz=7 fuzz.patch
4368 hg import --config ui.fuzz=7 fuzz.patch
4369
4369
4370 Returns 0 on success, 1 on partial success (see --partial).
4370 Returns 0 on success, 1 on partial success (see --partial).
4371 """
4371 """
4372
4372
4373 if not patch1:
4373 if not patch1:
4374 raise error.Abort(_('need at least one patch to import'))
4374 raise error.Abort(_('need at least one patch to import'))
4375
4375
4376 patches = (patch1,) + patches
4376 patches = (patch1,) + patches
4377
4377
4378 date = opts.get('date')
4378 date = opts.get('date')
4379 if date:
4379 if date:
4380 opts['date'] = util.parsedate(date)
4380 opts['date'] = util.parsedate(date)
4381
4381
4382 update = not opts.get('bypass')
4382 update = not opts.get('bypass')
4383 if not update and opts.get('no_commit'):
4383 if not update and opts.get('no_commit'):
4384 raise error.Abort(_('cannot use --no-commit with --bypass'))
4384 raise error.Abort(_('cannot use --no-commit with --bypass'))
4385 try:
4385 try:
4386 sim = float(opts.get('similarity') or 0)
4386 sim = float(opts.get('similarity') or 0)
4387 except ValueError:
4387 except ValueError:
4388 raise error.Abort(_('similarity must be a number'))
4388 raise error.Abort(_('similarity must be a number'))
4389 if sim < 0 or sim > 100:
4389 if sim < 0 or sim > 100:
4390 raise error.Abort(_('similarity must be between 0 and 100'))
4390 raise error.Abort(_('similarity must be between 0 and 100'))
4391 if sim and not update:
4391 if sim and not update:
4392 raise error.Abort(_('cannot use --similarity with --bypass'))
4392 raise error.Abort(_('cannot use --similarity with --bypass'))
4393 if opts.get('exact') and opts.get('edit'):
4393 if opts.get('exact') and opts.get('edit'):
4394 raise error.Abort(_('cannot use --exact with --edit'))
4394 raise error.Abort(_('cannot use --exact with --edit'))
4395 if opts.get('exact') and opts.get('prefix'):
4395 if opts.get('exact') and opts.get('prefix'):
4396 raise error.Abort(_('cannot use --exact with --prefix'))
4396 raise error.Abort(_('cannot use --exact with --prefix'))
4397
4397
4398 if update:
4398 if update:
4399 cmdutil.checkunfinished(repo)
4399 cmdutil.checkunfinished(repo)
4400 if (opts.get('exact') or not opts.get('force')) and update:
4400 if (opts.get('exact') or not opts.get('force')) and update:
4401 cmdutil.bailifchanged(repo)
4401 cmdutil.bailifchanged(repo)
4402
4402
4403 base = opts["base"]
4403 base = opts["base"]
4404 wlock = dsguard = lock = tr = None
4404 wlock = dsguard = lock = tr = None
4405 msgs = []
4405 msgs = []
4406 ret = 0
4406 ret = 0
4407
4407
4408
4408
4409 try:
4409 try:
4410 try:
4410 try:
4411 wlock = repo.wlock()
4411 wlock = repo.wlock()
4412 if not opts.get('no_commit'):
4412 if not opts.get('no_commit'):
4413 lock = repo.lock()
4413 lock = repo.lock()
4414 tr = repo.transaction('import')
4414 tr = repo.transaction('import')
4415 else:
4415 else:
4416 dsguard = cmdutil.dirstateguard(repo, 'import')
4416 dsguard = cmdutil.dirstateguard(repo, 'import')
4417 parents = repo.parents()
4417 parents = repo.parents()
4418 for patchurl in patches:
4418 for patchurl in patches:
4419 if patchurl == '-':
4419 if patchurl == '-':
4420 ui.status(_('applying patch from stdin\n'))
4420 ui.status(_('applying patch from stdin\n'))
4421 patchfile = ui.fin
4421 patchfile = ui.fin
4422 patchurl = 'stdin' # for error message
4422 patchurl = 'stdin' # for error message
4423 else:
4423 else:
4424 patchurl = os.path.join(base, patchurl)
4424 patchurl = os.path.join(base, patchurl)
4425 ui.status(_('applying %s\n') % patchurl)
4425 ui.status(_('applying %s\n') % patchurl)
4426 patchfile = hg.openpath(ui, patchurl)
4426 patchfile = hg.openpath(ui, patchurl)
4427
4427
4428 haspatch = False
4428 haspatch = False
4429 for hunk in patch.split(patchfile):
4429 for hunk in patch.split(patchfile):
4430 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4430 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4431 parents, opts,
4431 parents, opts,
4432 msgs, hg.clean)
4432 msgs, hg.clean)
4433 if msg:
4433 if msg:
4434 haspatch = True
4434 haspatch = True
4435 ui.note(msg + '\n')
4435 ui.note(msg + '\n')
4436 if update or opts.get('exact'):
4436 if update or opts.get('exact'):
4437 parents = repo.parents()
4437 parents = repo.parents()
4438 else:
4438 else:
4439 parents = [repo[node]]
4439 parents = [repo[node]]
4440 if rej:
4440 if rej:
4441 ui.write_err(_("patch applied partially\n"))
4441 ui.write_err(_("patch applied partially\n"))
4442 ui.write_err(_("(fix the .rej files and run "
4442 ui.write_err(_("(fix the .rej files and run "
4443 "`hg commit --amend`)\n"))
4443 "`hg commit --amend`)\n"))
4444 ret = 1
4444 ret = 1
4445 break
4445 break
4446
4446
4447 if not haspatch:
4447 if not haspatch:
4448 raise error.Abort(_('%s: no diffs found') % patchurl)
4448 raise error.Abort(_('%s: no diffs found') % patchurl)
4449
4449
4450 if tr:
4450 if tr:
4451 tr.close()
4451 tr.close()
4452 if msgs:
4452 if msgs:
4453 repo.savecommitmessage('\n* * *\n'.join(msgs))
4453 repo.savecommitmessage('\n* * *\n'.join(msgs))
4454 if dsguard:
4454 if dsguard:
4455 dsguard.close()
4455 dsguard.close()
4456 return ret
4456 return ret
4457 finally:
4457 finally:
4458 # TODO: get rid of this meaningless try/finally enclosing.
4458 # TODO: get rid of this meaningless try/finally enclosing.
4459 # this is kept only to reduce changes in a patch.
4459 # this is kept only to reduce changes in a patch.
4460 pass
4460 pass
4461 finally:
4461 finally:
4462 if tr:
4462 if tr:
4463 tr.release()
4463 tr.release()
4464 release(lock, dsguard, wlock)
4464 release(lock, dsguard, wlock)
4465
4465
4466 @command('incoming|in',
4466 @command('incoming|in',
4467 [('f', 'force', None,
4467 [('f', 'force', None,
4468 _('run even if remote repository is unrelated')),
4468 _('run even if remote repository is unrelated')),
4469 ('n', 'newest-first', None, _('show newest record first')),
4469 ('n', 'newest-first', None, _('show newest record first')),
4470 ('', 'bundle', '',
4470 ('', 'bundle', '',
4471 _('file to store the bundles into'), _('FILE')),
4471 _('file to store the bundles into'), _('FILE')),
4472 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4472 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4473 ('B', 'bookmarks', False, _("compare bookmarks")),
4473 ('B', 'bookmarks', False, _("compare bookmarks")),
4474 ('b', 'branch', [],
4474 ('b', 'branch', [],
4475 _('a specific branch you would like to pull'), _('BRANCH')),
4475 _('a specific branch you would like to pull'), _('BRANCH')),
4476 ] + logopts + remoteopts + subrepoopts,
4476 ] + logopts + remoteopts + subrepoopts,
4477 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4477 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4478 def incoming(ui, repo, source="default", **opts):
4478 def incoming(ui, repo, source="default", **opts):
4479 """show new changesets found in source
4479 """show new changesets found in source
4480
4480
4481 Show new changesets found in the specified path/URL or the default
4481 Show new changesets found in the specified path/URL or the default
4482 pull location. These are the changesets that would have been pulled
4482 pull location. These are the changesets that would have been pulled
4483 if a pull at the time you issued this command.
4483 if a pull at the time you issued this command.
4484
4484
4485 See pull for valid source format details.
4485 See pull for valid source format details.
4486
4486
4487 .. container:: verbose
4487 .. container:: verbose
4488
4488
4489 With -B/--bookmarks, the result of bookmark comparison between
4489 With -B/--bookmarks, the result of bookmark comparison between
4490 local and remote repositories is displayed. With -v/--verbose,
4490 local and remote repositories is displayed. With -v/--verbose,
4491 status is also displayed for each bookmark like below::
4491 status is also displayed for each bookmark like below::
4492
4492
4493 BM1 01234567890a added
4493 BM1 01234567890a added
4494 BM2 1234567890ab advanced
4494 BM2 1234567890ab advanced
4495 BM3 234567890abc diverged
4495 BM3 234567890abc diverged
4496 BM4 34567890abcd changed
4496 BM4 34567890abcd changed
4497
4497
4498 The action taken locally when pulling depends on the
4498 The action taken locally when pulling depends on the
4499 status of each bookmark:
4499 status of each bookmark:
4500
4500
4501 :``added``: pull will create it
4501 :``added``: pull will create it
4502 :``advanced``: pull will update it
4502 :``advanced``: pull will update it
4503 :``diverged``: pull will create a divergent bookmark
4503 :``diverged``: pull will create a divergent bookmark
4504 :``changed``: result depends on remote changesets
4504 :``changed``: result depends on remote changesets
4505
4505
4506 From the point of view of pulling behavior, bookmark
4506 From the point of view of pulling behavior, bookmark
4507 existing only in the remote repository are treated as ``added``,
4507 existing only in the remote repository are treated as ``added``,
4508 even if it is in fact locally deleted.
4508 even if it is in fact locally deleted.
4509
4509
4510 .. container:: verbose
4510 .. container:: verbose
4511
4511
4512 For remote repository, using --bundle avoids downloading the
4512 For remote repository, using --bundle avoids downloading the
4513 changesets twice if the incoming is followed by a pull.
4513 changesets twice if the incoming is followed by a pull.
4514
4514
4515 Examples:
4515 Examples:
4516
4516
4517 - show incoming changes with patches and full description::
4517 - show incoming changes with patches and full description::
4518
4518
4519 hg incoming -vp
4519 hg incoming -vp
4520
4520
4521 - show incoming changes excluding merges, store a bundle::
4521 - show incoming changes excluding merges, store a bundle::
4522
4522
4523 hg in -vpM --bundle incoming.hg
4523 hg in -vpM --bundle incoming.hg
4524 hg pull incoming.hg
4524 hg pull incoming.hg
4525
4525
4526 - briefly list changes inside a bundle::
4526 - briefly list changes inside a bundle::
4527
4527
4528 hg in changes.hg -T "{desc|firstline}\\n"
4528 hg in changes.hg -T "{desc|firstline}\\n"
4529
4529
4530 Returns 0 if there are incoming changes, 1 otherwise.
4530 Returns 0 if there are incoming changes, 1 otherwise.
4531 """
4531 """
4532 if opts.get('graph'):
4532 if opts.get('graph'):
4533 cmdutil.checkunsupportedgraphflags([], opts)
4533 cmdutil.checkunsupportedgraphflags([], opts)
4534 def display(other, chlist, displayer):
4534 def display(other, chlist, displayer):
4535 revdag = cmdutil.graphrevs(other, chlist, opts)
4535 revdag = cmdutil.graphrevs(other, chlist, opts)
4536 showparents = [ctx.node() for ctx in repo[None].parents()]
4536 showparents = [ctx.node() for ctx in repo[None].parents()]
4537 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4537 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4538 graphmod.asciiedges)
4538 graphmod.asciiedges)
4539
4539
4540 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4540 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4541 return 0
4541 return 0
4542
4542
4543 if opts.get('bundle') and opts.get('subrepos'):
4543 if opts.get('bundle') and opts.get('subrepos'):
4544 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4544 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4545
4545
4546 if opts.get('bookmarks'):
4546 if opts.get('bookmarks'):
4547 source, branches = hg.parseurl(ui.expandpath(source),
4547 source, branches = hg.parseurl(ui.expandpath(source),
4548 opts.get('branch'))
4548 opts.get('branch'))
4549 other = hg.peer(repo, opts, source)
4549 other = hg.peer(repo, opts, source)
4550 if 'bookmarks' not in other.listkeys('namespaces'):
4550 if 'bookmarks' not in other.listkeys('namespaces'):
4551 ui.warn(_("remote doesn't support bookmarks\n"))
4551 ui.warn(_("remote doesn't support bookmarks\n"))
4552 return 0
4552 return 0
4553 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4553 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4554 return bookmarks.incoming(ui, repo, other)
4554 return bookmarks.incoming(ui, repo, other)
4555
4555
4556 repo._subtoppath = ui.expandpath(source)
4556 repo._subtoppath = ui.expandpath(source)
4557 try:
4557 try:
4558 return hg.incoming(ui, repo, source, opts)
4558 return hg.incoming(ui, repo, source, opts)
4559 finally:
4559 finally:
4560 del repo._subtoppath
4560 del repo._subtoppath
4561
4561
4562
4562
4563 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4563 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4564 norepo=True)
4564 norepo=True)
4565 def init(ui, dest=".", **opts):
4565 def init(ui, dest=".", **opts):
4566 """create a new repository in the given directory
4566 """create a new repository in the given directory
4567
4567
4568 Initialize a new repository in the given directory. If the given
4568 Initialize a new repository in the given directory. If the given
4569 directory does not exist, it will be created.
4569 directory does not exist, it will be created.
4570
4570
4571 If no directory is given, the current directory is used.
4571 If no directory is given, the current directory is used.
4572
4572
4573 It is possible to specify an ``ssh://`` URL as the destination.
4573 It is possible to specify an ``ssh://`` URL as the destination.
4574 See :hg:`help urls` for more information.
4574 See :hg:`help urls` for more information.
4575
4575
4576 Returns 0 on success.
4576 Returns 0 on success.
4577 """
4577 """
4578 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4578 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4579
4579
4580 @command('locate',
4580 @command('locate',
4581 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4581 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4582 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4582 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4583 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4583 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4584 ] + walkopts,
4584 ] + walkopts,
4585 _('[OPTION]... [PATTERN]...'))
4585 _('[OPTION]... [PATTERN]...'))
4586 def locate(ui, repo, *pats, **opts):
4586 def locate(ui, repo, *pats, **opts):
4587 """locate files matching specific patterns (DEPRECATED)
4587 """locate files matching specific patterns (DEPRECATED)
4588
4588
4589 Print files under Mercurial control in the working directory whose
4589 Print files under Mercurial control in the working directory whose
4590 names match the given patterns.
4590 names match the given patterns.
4591
4591
4592 By default, this command searches all directories in the working
4592 By default, this command searches all directories in the working
4593 directory. To search just the current directory and its
4593 directory. To search just the current directory and its
4594 subdirectories, use "--include .".
4594 subdirectories, use "--include .".
4595
4595
4596 If no patterns are given to match, this command prints the names
4596 If no patterns are given to match, this command prints the names
4597 of all files under Mercurial control in the working directory.
4597 of all files under Mercurial control in the working directory.
4598
4598
4599 If you want to feed the output of this command into the "xargs"
4599 If you want to feed the output of this command into the "xargs"
4600 command, use the -0 option to both this command and "xargs". This
4600 command, use the -0 option to both this command and "xargs". This
4601 will avoid the problem of "xargs" treating single filenames that
4601 will avoid the problem of "xargs" treating single filenames that
4602 contain whitespace as multiple filenames.
4602 contain whitespace as multiple filenames.
4603
4603
4604 See :hg:`help files` for a more versatile command.
4604 See :hg:`help files` for a more versatile command.
4605
4605
4606 Returns 0 if a match is found, 1 otherwise.
4606 Returns 0 if a match is found, 1 otherwise.
4607 """
4607 """
4608 if opts.get('print0'):
4608 if opts.get('print0'):
4609 end = '\0'
4609 end = '\0'
4610 else:
4610 else:
4611 end = '\n'
4611 end = '\n'
4612 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4612 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4613
4613
4614 ret = 1
4614 ret = 1
4615 ctx = repo[rev]
4615 ctx = repo[rev]
4616 m = scmutil.match(ctx, pats, opts, default='relglob',
4616 m = scmutil.match(ctx, pats, opts, default='relglob',
4617 badfn=lambda x, y: False)
4617 badfn=lambda x, y: False)
4618
4618
4619 for abs in ctx.matches(m):
4619 for abs in ctx.matches(m):
4620 if opts.get('fullpath'):
4620 if opts.get('fullpath'):
4621 ui.write(repo.wjoin(abs), end)
4621 ui.write(repo.wjoin(abs), end)
4622 else:
4622 else:
4623 ui.write(((pats and m.rel(abs)) or abs), end)
4623 ui.write(((pats and m.rel(abs)) or abs), end)
4624 ret = 0
4624 ret = 0
4625
4625
4626 return ret
4626 return ret
4627
4627
4628 @command('^log|history',
4628 @command('^log|history',
4629 [('f', 'follow', None,
4629 [('f', 'follow', None,
4630 _('follow changeset history, or file history across copies and renames')),
4630 _('follow changeset history, or file history across copies and renames')),
4631 ('', 'follow-first', None,
4631 ('', 'follow-first', None,
4632 _('only follow the first parent of merge changesets (DEPRECATED)')),
4632 _('only follow the first parent of merge changesets (DEPRECATED)')),
4633 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4633 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4634 ('C', 'copies', None, _('show copied files')),
4634 ('C', 'copies', None, _('show copied files')),
4635 ('k', 'keyword', [],
4635 ('k', 'keyword', [],
4636 _('do case-insensitive search for a given text'), _('TEXT')),
4636 _('do case-insensitive search for a given text'), _('TEXT')),
4637 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4637 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4638 ('', 'removed', None, _('include revisions where files were removed')),
4638 ('', 'removed', None, _('include revisions where files were removed')),
4639 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4639 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4640 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4640 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4641 ('', 'only-branch', [],
4641 ('', 'only-branch', [],
4642 _('show only changesets within the given named branch (DEPRECATED)'),
4642 _('show only changesets within the given named branch (DEPRECATED)'),
4643 _('BRANCH')),
4643 _('BRANCH')),
4644 ('b', 'branch', [],
4644 ('b', 'branch', [],
4645 _('show changesets within the given named branch'), _('BRANCH')),
4645 _('show changesets within the given named branch'), _('BRANCH')),
4646 ('P', 'prune', [],
4646 ('P', 'prune', [],
4647 _('do not display revision or any of its ancestors'), _('REV')),
4647 _('do not display revision or any of its ancestors'), _('REV')),
4648 ] + logopts + walkopts,
4648 ] + logopts + walkopts,
4649 _('[OPTION]... [FILE]'),
4649 _('[OPTION]... [FILE]'),
4650 inferrepo=True)
4650 inferrepo=True)
4651 def log(ui, repo, *pats, **opts):
4651 def log(ui, repo, *pats, **opts):
4652 """show revision history of entire repository or files
4652 """show revision history of entire repository or files
4653
4653
4654 Print the revision history of the specified files or the entire
4654 Print the revision history of the specified files or the entire
4655 project.
4655 project.
4656
4656
4657 If no revision range is specified, the default is ``tip:0`` unless
4657 If no revision range is specified, the default is ``tip:0`` unless
4658 --follow is set, in which case the working directory parent is
4658 --follow is set, in which case the working directory parent is
4659 used as the starting revision.
4659 used as the starting revision.
4660
4660
4661 File history is shown without following rename or copy history of
4661 File history is shown without following rename or copy history of
4662 files. Use -f/--follow with a filename to follow history across
4662 files. Use -f/--follow with a filename to follow history across
4663 renames and copies. --follow without a filename will only show
4663 renames and copies. --follow without a filename will only show
4664 ancestors or descendants of the starting revision.
4664 ancestors or descendants of the starting revision.
4665
4665
4666 By default this command prints revision number and changeset id,
4666 By default this command prints revision number and changeset id,
4667 tags, non-trivial parents, user, date and time, and a summary for
4667 tags, non-trivial parents, user, date and time, and a summary for
4668 each commit. When the -v/--verbose switch is used, the list of
4668 each commit. When the -v/--verbose switch is used, the list of
4669 changed files and full commit message are shown.
4669 changed files and full commit message are shown.
4670
4670
4671 With --graph the revisions are shown as an ASCII art DAG with the most
4671 With --graph the revisions are shown as an ASCII art DAG with the most
4672 recent changeset at the top.
4672 recent changeset at the top.
4673 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4673 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4674 and '+' represents a fork where the changeset from the lines below is a
4674 and '+' represents a fork where the changeset from the lines below is a
4675 parent of the 'o' merge on the same line.
4675 parent of the 'o' merge on the same line.
4676
4676
4677 .. note::
4677 .. note::
4678
4678
4679 log -p/--patch may generate unexpected diff output for merge
4679 log -p/--patch may generate unexpected diff output for merge
4680 changesets, as it will only compare the merge changeset against
4680 changesets, as it will only compare the merge changeset against
4681 its first parent. Also, only files different from BOTH parents
4681 its first parent. Also, only files different from BOTH parents
4682 will appear in files:.
4682 will appear in files:.
4683
4683
4684 .. note::
4684 .. note::
4685
4685
4686 for performance reasons, log FILE may omit duplicate changes
4686 for performance reasons, log FILE may omit duplicate changes
4687 made on branches and will not show removals or mode changes. To
4687 made on branches and will not show removals or mode changes. To
4688 see all such changes, use the --removed switch.
4688 see all such changes, use the --removed switch.
4689
4689
4690 .. container:: verbose
4690 .. container:: verbose
4691
4691
4692 Some examples:
4692 Some examples:
4693
4693
4694 - changesets with full descriptions and file lists::
4694 - changesets with full descriptions and file lists::
4695
4695
4696 hg log -v
4696 hg log -v
4697
4697
4698 - changesets ancestral to the working directory::
4698 - changesets ancestral to the working directory::
4699
4699
4700 hg log -f
4700 hg log -f
4701
4701
4702 - last 10 commits on the current branch::
4702 - last 10 commits on the current branch::
4703
4703
4704 hg log -l 10 -b .
4704 hg log -l 10 -b .
4705
4705
4706 - changesets showing all modifications of a file, including removals::
4706 - changesets showing all modifications of a file, including removals::
4707
4707
4708 hg log --removed file.c
4708 hg log --removed file.c
4709
4709
4710 - all changesets that touch a directory, with diffs, excluding merges::
4710 - all changesets that touch a directory, with diffs, excluding merges::
4711
4711
4712 hg log -Mp lib/
4712 hg log -Mp lib/
4713
4713
4714 - all revision numbers that match a keyword::
4714 - all revision numbers that match a keyword::
4715
4715
4716 hg log -k bug --template "{rev}\\n"
4716 hg log -k bug --template "{rev}\\n"
4717
4717
4718 - list available log templates::
4718 - list available log templates::
4719
4719
4720 hg log -T list
4720 hg log -T list
4721
4721
4722 - check if a given changeset is included in a tagged release::
4722 - check if a given changeset is included in a tagged release::
4723
4723
4724 hg log -r "a21ccf and ancestor(1.9)"
4724 hg log -r "a21ccf and ancestor(1.9)"
4725
4725
4726 - find all changesets by some user in a date range::
4726 - find all changesets by some user in a date range::
4727
4727
4728 hg log -k alice -d "may 2008 to jul 2008"
4728 hg log -k alice -d "may 2008 to jul 2008"
4729
4729
4730 - summary of all changesets after the last tag::
4730 - summary of all changesets after the last tag::
4731
4731
4732 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4732 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4733
4733
4734 See :hg:`help dates` for a list of formats valid for -d/--date.
4734 See :hg:`help dates` for a list of formats valid for -d/--date.
4735
4735
4736 See :hg:`help revisions` and :hg:`help revsets` for more about
4736 See :hg:`help revisions` and :hg:`help revsets` for more about
4737 specifying revisions.
4737 specifying revisions.
4738
4738
4739 See :hg:`help templates` for more about pre-packaged styles and
4739 See :hg:`help templates` for more about pre-packaged styles and
4740 specifying custom templates.
4740 specifying custom templates.
4741
4741
4742 Returns 0 on success.
4742 Returns 0 on success.
4743
4743
4744 """
4744 """
4745 if opts.get('follow') and opts.get('rev'):
4745 if opts.get('follow') and opts.get('rev'):
4746 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4746 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4747 del opts['follow']
4747 del opts['follow']
4748
4748
4749 if opts.get('graph'):
4749 if opts.get('graph'):
4750 return cmdutil.graphlog(ui, repo, *pats, **opts)
4750 return cmdutil.graphlog(ui, repo, *pats, **opts)
4751
4751
4752 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4752 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4753 limit = cmdutil.loglimit(opts)
4753 limit = cmdutil.loglimit(opts)
4754 count = 0
4754 count = 0
4755
4755
4756 getrenamed = None
4756 getrenamed = None
4757 if opts.get('copies'):
4757 if opts.get('copies'):
4758 endrev = None
4758 endrev = None
4759 if opts.get('rev'):
4759 if opts.get('rev'):
4760 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4760 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4761 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4761 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4762
4762
4763 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4763 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4764 for rev in revs:
4764 for rev in revs:
4765 if count == limit:
4765 if count == limit:
4766 break
4766 break
4767 ctx = repo[rev]
4767 ctx = repo[rev]
4768 copies = None
4768 copies = None
4769 if getrenamed is not None and rev:
4769 if getrenamed is not None and rev:
4770 copies = []
4770 copies = []
4771 for fn in ctx.files():
4771 for fn in ctx.files():
4772 rename = getrenamed(fn, rev)
4772 rename = getrenamed(fn, rev)
4773 if rename:
4773 if rename:
4774 copies.append((fn, rename[0]))
4774 copies.append((fn, rename[0]))
4775 if filematcher:
4775 if filematcher:
4776 revmatchfn = filematcher(ctx.rev())
4776 revmatchfn = filematcher(ctx.rev())
4777 else:
4777 else:
4778 revmatchfn = None
4778 revmatchfn = None
4779 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4779 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4780 if displayer.flush(ctx):
4780 if displayer.flush(ctx):
4781 count += 1
4781 count += 1
4782
4782
4783 displayer.close()
4783 displayer.close()
4784
4784
4785 @command('manifest',
4785 @command('manifest',
4786 [('r', 'rev', '', _('revision to display'), _('REV')),
4786 [('r', 'rev', '', _('revision to display'), _('REV')),
4787 ('', 'all', False, _("list files from all revisions"))]
4787 ('', 'all', False, _("list files from all revisions"))]
4788 + formatteropts,
4788 + formatteropts,
4789 _('[-r REV]'))
4789 _('[-r REV]'))
4790 def manifest(ui, repo, node=None, rev=None, **opts):
4790 def manifest(ui, repo, node=None, rev=None, **opts):
4791 """output the current or given revision of the project manifest
4791 """output the current or given revision of the project manifest
4792
4792
4793 Print a list of version controlled files for the given revision.
4793 Print a list of version controlled files for the given revision.
4794 If no revision is given, the first parent of the working directory
4794 If no revision is given, the first parent of the working directory
4795 is used, or the null revision if no revision is checked out.
4795 is used, or the null revision if no revision is checked out.
4796
4796
4797 With -v, print file permissions, symlink and executable bits.
4797 With -v, print file permissions, symlink and executable bits.
4798 With --debug, print file revision hashes.
4798 With --debug, print file revision hashes.
4799
4799
4800 If option --all is specified, the list of all files from all revisions
4800 If option --all is specified, the list of all files from all revisions
4801 is printed. This includes deleted and renamed files.
4801 is printed. This includes deleted and renamed files.
4802
4802
4803 Returns 0 on success.
4803 Returns 0 on success.
4804 """
4804 """
4805
4805
4806 fm = ui.formatter('manifest', opts)
4806 fm = ui.formatter('manifest', opts)
4807
4807
4808 if opts.get('all'):
4808 if opts.get('all'):
4809 if rev or node:
4809 if rev or node:
4810 raise error.Abort(_("can't specify a revision with --all"))
4810 raise error.Abort(_("can't specify a revision with --all"))
4811
4811
4812 res = []
4812 res = []
4813 prefix = "data/"
4813 prefix = "data/"
4814 suffix = ".i"
4814 suffix = ".i"
4815 plen = len(prefix)
4815 plen = len(prefix)
4816 slen = len(suffix)
4816 slen = len(suffix)
4817 lock = repo.lock()
4817 lock = repo.lock()
4818 try:
4818 try:
4819 for fn, b, size in repo.store.datafiles():
4819 for fn, b, size in repo.store.datafiles():
4820 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4820 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4821 res.append(fn[plen:-slen])
4821 res.append(fn[plen:-slen])
4822 finally:
4822 finally:
4823 lock.release()
4823 lock.release()
4824 for f in res:
4824 for f in res:
4825 fm.startitem()
4825 fm.startitem()
4826 fm.write("path", '%s\n', f)
4826 fm.write("path", '%s\n', f)
4827 fm.end()
4827 fm.end()
4828 return
4828 return
4829
4829
4830 if rev and node:
4830 if rev and node:
4831 raise error.Abort(_("please specify just one revision"))
4831 raise error.Abort(_("please specify just one revision"))
4832
4832
4833 if not node:
4833 if not node:
4834 node = rev
4834 node = rev
4835
4835
4836 char = {'l': '@', 'x': '*', '': ''}
4836 char = {'l': '@', 'x': '*', '': ''}
4837 mode = {'l': '644', 'x': '755', '': '644'}
4837 mode = {'l': '644', 'x': '755', '': '644'}
4838 ctx = scmutil.revsingle(repo, node)
4838 ctx = scmutil.revsingle(repo, node)
4839 mf = ctx.manifest()
4839 mf = ctx.manifest()
4840 for f in ctx:
4840 for f in ctx:
4841 fm.startitem()
4841 fm.startitem()
4842 fl = ctx[f].flags()
4842 fl = ctx[f].flags()
4843 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4843 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4844 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4844 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4845 fm.write('path', '%s\n', f)
4845 fm.write('path', '%s\n', f)
4846 fm.end()
4846 fm.end()
4847
4847
4848 @command('^merge',
4848 @command('^merge',
4849 [('f', 'force', None,
4849 [('f', 'force', None,
4850 _('force a merge including outstanding changes (DEPRECATED)')),
4850 _('force a merge including outstanding changes (DEPRECATED)')),
4851 ('r', 'rev', '', _('revision to merge'), _('REV')),
4851 ('r', 'rev', '', _('revision to merge'), _('REV')),
4852 ('P', 'preview', None,
4852 ('P', 'preview', None,
4853 _('review revisions to merge (no merge is performed)'))
4853 _('review revisions to merge (no merge is performed)'))
4854 ] + mergetoolopts,
4854 ] + mergetoolopts,
4855 _('[-P] [-f] [[-r] REV]'))
4855 _('[-P] [-f] [[-r] REV]'))
4856 def merge(ui, repo, node=None, **opts):
4856 def merge(ui, repo, node=None, **opts):
4857 """merge another revision into working directory
4857 """merge another revision into working directory
4858
4858
4859 The current working directory is updated with all changes made in
4859 The current working directory is updated with all changes made in
4860 the requested revision since the last common predecessor revision.
4860 the requested revision since the last common predecessor revision.
4861
4861
4862 Files that changed between either parent are marked as changed for
4862 Files that changed between either parent are marked as changed for
4863 the next commit and a commit must be performed before any further
4863 the next commit and a commit must be performed before any further
4864 updates to the repository are allowed. The next commit will have
4864 updates to the repository are allowed. The next commit will have
4865 two parents.
4865 two parents.
4866
4866
4867 ``--tool`` can be used to specify the merge tool used for file
4867 ``--tool`` can be used to specify the merge tool used for file
4868 merges. It overrides the HGMERGE environment variable and your
4868 merges. It overrides the HGMERGE environment variable and your
4869 configuration files. See :hg:`help merge-tools` for options.
4869 configuration files. See :hg:`help merge-tools` for options.
4870
4870
4871 If no revision is specified, the working directory's parent is a
4871 If no revision is specified, the working directory's parent is a
4872 head revision, and the current branch contains exactly one other
4872 head revision, and the current branch contains exactly one other
4873 head, the other head is merged with by default. Otherwise, an
4873 head, the other head is merged with by default. Otherwise, an
4874 explicit revision with which to merge with must be provided.
4874 explicit revision with which to merge with must be provided.
4875
4875
4876 :hg:`resolve` must be used to resolve unresolved files.
4876 :hg:`resolve` must be used to resolve unresolved files.
4877
4877
4878 To undo an uncommitted merge, use :hg:`update --clean .` which
4878 To undo an uncommitted merge, use :hg:`update --clean .` which
4879 will check out a clean copy of the original merge parent, losing
4879 will check out a clean copy of the original merge parent, losing
4880 all changes.
4880 all changes.
4881
4881
4882 Returns 0 on success, 1 if there are unresolved files.
4882 Returns 0 on success, 1 if there are unresolved files.
4883 """
4883 """
4884
4884
4885 if opts.get('rev') and node:
4885 if opts.get('rev') and node:
4886 raise error.Abort(_("please specify just one revision"))
4886 raise error.Abort(_("please specify just one revision"))
4887 if not node:
4887 if not node:
4888 node = opts.get('rev')
4888 node = opts.get('rev')
4889
4889
4890 if node:
4890 if node:
4891 node = scmutil.revsingle(repo, node).node()
4891 node = scmutil.revsingle(repo, node).node()
4892
4892
4893 if not node:
4893 if not node:
4894 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4894 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4895
4895
4896 if opts.get('preview'):
4896 if opts.get('preview'):
4897 # find nodes that are ancestors of p2 but not of p1
4897 # find nodes that are ancestors of p2 but not of p1
4898 p1 = repo.lookup('.')
4898 p1 = repo.lookup('.')
4899 p2 = repo.lookup(node)
4899 p2 = repo.lookup(node)
4900 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4900 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4901
4901
4902 displayer = cmdutil.show_changeset(ui, repo, opts)
4902 displayer = cmdutil.show_changeset(ui, repo, opts)
4903 for node in nodes:
4903 for node in nodes:
4904 displayer.show(repo[node])
4904 displayer.show(repo[node])
4905 displayer.close()
4905 displayer.close()
4906 return 0
4906 return 0
4907
4907
4908 try:
4908 try:
4909 # ui.forcemerge is an internal variable, do not document
4909 # ui.forcemerge is an internal variable, do not document
4910 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4910 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4911 return hg.merge(repo, node, force=opts.get('force'))
4911 return hg.merge(repo, node, force=opts.get('force'))
4912 finally:
4912 finally:
4913 ui.setconfig('ui', 'forcemerge', '', 'merge')
4913 ui.setconfig('ui', 'forcemerge', '', 'merge')
4914
4914
4915 @command('outgoing|out',
4915 @command('outgoing|out',
4916 [('f', 'force', None, _('run even when the destination is unrelated')),
4916 [('f', 'force', None, _('run even when the destination is unrelated')),
4917 ('r', 'rev', [],
4917 ('r', 'rev', [],
4918 _('a changeset intended to be included in the destination'), _('REV')),
4918 _('a changeset intended to be included in the destination'), _('REV')),
4919 ('n', 'newest-first', None, _('show newest record first')),
4919 ('n', 'newest-first', None, _('show newest record first')),
4920 ('B', 'bookmarks', False, _('compare bookmarks')),
4920 ('B', 'bookmarks', False, _('compare bookmarks')),
4921 ('b', 'branch', [], _('a specific branch you would like to push'),
4921 ('b', 'branch', [], _('a specific branch you would like to push'),
4922 _('BRANCH')),
4922 _('BRANCH')),
4923 ] + logopts + remoteopts + subrepoopts,
4923 ] + logopts + remoteopts + subrepoopts,
4924 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4924 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4925 def outgoing(ui, repo, dest=None, **opts):
4925 def outgoing(ui, repo, dest=None, **opts):
4926 """show changesets not found in the destination
4926 """show changesets not found in the destination
4927
4927
4928 Show changesets not found in the specified destination repository
4928 Show changesets not found in the specified destination repository
4929 or the default push location. These are the changesets that would
4929 or the default push location. These are the changesets that would
4930 be pushed if a push was requested.
4930 be pushed if a push was requested.
4931
4931
4932 See pull for details of valid destination formats.
4932 See pull for details of valid destination formats.
4933
4933
4934 .. container:: verbose
4934 .. container:: verbose
4935
4935
4936 With -B/--bookmarks, the result of bookmark comparison between
4936 With -B/--bookmarks, the result of bookmark comparison between
4937 local and remote repositories is displayed. With -v/--verbose,
4937 local and remote repositories is displayed. With -v/--verbose,
4938 status is also displayed for each bookmark like below::
4938 status is also displayed for each bookmark like below::
4939
4939
4940 BM1 01234567890a added
4940 BM1 01234567890a added
4941 BM2 deleted
4941 BM2 deleted
4942 BM3 234567890abc advanced
4942 BM3 234567890abc advanced
4943 BM4 34567890abcd diverged
4943 BM4 34567890abcd diverged
4944 BM5 4567890abcde changed
4944 BM5 4567890abcde changed
4945
4945
4946 The action taken when pushing depends on the
4946 The action taken when pushing depends on the
4947 status of each bookmark:
4947 status of each bookmark:
4948
4948
4949 :``added``: push with ``-B`` will create it
4949 :``added``: push with ``-B`` will create it
4950 :``deleted``: push with ``-B`` will delete it
4950 :``deleted``: push with ``-B`` will delete it
4951 :``advanced``: push will update it
4951 :``advanced``: push will update it
4952 :``diverged``: push with ``-B`` will update it
4952 :``diverged``: push with ``-B`` will update it
4953 :``changed``: push with ``-B`` will update it
4953 :``changed``: push with ``-B`` will update it
4954
4954
4955 From the point of view of pushing behavior, bookmarks
4955 From the point of view of pushing behavior, bookmarks
4956 existing only in the remote repository are treated as
4956 existing only in the remote repository are treated as
4957 ``deleted``, even if it is in fact added remotely.
4957 ``deleted``, even if it is in fact added remotely.
4958
4958
4959 Returns 0 if there are outgoing changes, 1 otherwise.
4959 Returns 0 if there are outgoing changes, 1 otherwise.
4960 """
4960 """
4961 if opts.get('graph'):
4961 if opts.get('graph'):
4962 cmdutil.checkunsupportedgraphflags([], opts)
4962 cmdutil.checkunsupportedgraphflags([], opts)
4963 o, other = hg._outgoing(ui, repo, dest, opts)
4963 o, other = hg._outgoing(ui, repo, dest, opts)
4964 if not o:
4964 if not o:
4965 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4965 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4966 return
4966 return
4967
4967
4968 revdag = cmdutil.graphrevs(repo, o, opts)
4968 revdag = cmdutil.graphrevs(repo, o, opts)
4969 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4969 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4970 showparents = [ctx.node() for ctx in repo[None].parents()]
4970 showparents = [ctx.node() for ctx in repo[None].parents()]
4971 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4971 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4972 graphmod.asciiedges)
4972 graphmod.asciiedges)
4973 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4973 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4974 return 0
4974 return 0
4975
4975
4976 if opts.get('bookmarks'):
4976 if opts.get('bookmarks'):
4977 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4977 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4978 dest, branches = hg.parseurl(dest, opts.get('branch'))
4978 dest, branches = hg.parseurl(dest, opts.get('branch'))
4979 other = hg.peer(repo, opts, dest)
4979 other = hg.peer(repo, opts, dest)
4980 if 'bookmarks' not in other.listkeys('namespaces'):
4980 if 'bookmarks' not in other.listkeys('namespaces'):
4981 ui.warn(_("remote doesn't support bookmarks\n"))
4981 ui.warn(_("remote doesn't support bookmarks\n"))
4982 return 0
4982 return 0
4983 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4983 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4984 return bookmarks.outgoing(ui, repo, other)
4984 return bookmarks.outgoing(ui, repo, other)
4985
4985
4986 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4986 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4987 try:
4987 try:
4988 return hg.outgoing(ui, repo, dest, opts)
4988 return hg.outgoing(ui, repo, dest, opts)
4989 finally:
4989 finally:
4990 del repo._subtoppath
4990 del repo._subtoppath
4991
4991
4992 @command('parents',
4992 @command('parents',
4993 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4993 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4994 ] + templateopts,
4994 ] + templateopts,
4995 _('[-r REV] [FILE]'),
4995 _('[-r REV] [FILE]'),
4996 inferrepo=True)
4996 inferrepo=True)
4997 def parents(ui, repo, file_=None, **opts):
4997 def parents(ui, repo, file_=None, **opts):
4998 """show the parents of the working directory or revision (DEPRECATED)
4998 """show the parents of the working directory or revision (DEPRECATED)
4999
4999
5000 Print the working directory's parent revisions. If a revision is
5000 Print the working directory's parent revisions. If a revision is
5001 given via -r/--rev, the parent of that revision will be printed.
5001 given via -r/--rev, the parent of that revision will be printed.
5002 If a file argument is given, the revision in which the file was
5002 If a file argument is given, the revision in which the file was
5003 last changed (before the working directory revision or the
5003 last changed (before the working directory revision or the
5004 argument to --rev if given) is printed.
5004 argument to --rev if given) is printed.
5005
5005
5006 See :hg:`summary` and :hg:`help revsets` for related information.
5006 See :hg:`summary` and :hg:`help revsets` for related information.
5007
5007
5008 Returns 0 on success.
5008 Returns 0 on success.
5009 """
5009 """
5010
5010
5011 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5011 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5012
5012
5013 if file_:
5013 if file_:
5014 m = scmutil.match(ctx, (file_,), opts)
5014 m = scmutil.match(ctx, (file_,), opts)
5015 if m.anypats() or len(m.files()) != 1:
5015 if m.anypats() or len(m.files()) != 1:
5016 raise error.Abort(_('can only specify an explicit filename'))
5016 raise error.Abort(_('can only specify an explicit filename'))
5017 file_ = m.files()[0]
5017 file_ = m.files()[0]
5018 filenodes = []
5018 filenodes = []
5019 for cp in ctx.parents():
5019 for cp in ctx.parents():
5020 if not cp:
5020 if not cp:
5021 continue
5021 continue
5022 try:
5022 try:
5023 filenodes.append(cp.filenode(file_))
5023 filenodes.append(cp.filenode(file_))
5024 except error.LookupError:
5024 except error.LookupError:
5025 pass
5025 pass
5026 if not filenodes:
5026 if not filenodes:
5027 raise error.Abort(_("'%s' not found in manifest!") % file_)
5027 raise error.Abort(_("'%s' not found in manifest!") % file_)
5028 p = []
5028 p = []
5029 for fn in filenodes:
5029 for fn in filenodes:
5030 fctx = repo.filectx(file_, fileid=fn)
5030 fctx = repo.filectx(file_, fileid=fn)
5031 p.append(fctx.node())
5031 p.append(fctx.node())
5032 else:
5032 else:
5033 p = [cp.node() for cp in ctx.parents()]
5033 p = [cp.node() for cp in ctx.parents()]
5034
5034
5035 displayer = cmdutil.show_changeset(ui, repo, opts)
5035 displayer = cmdutil.show_changeset(ui, repo, opts)
5036 for n in p:
5036 for n in p:
5037 if n != nullid:
5037 if n != nullid:
5038 displayer.show(repo[n])
5038 displayer.show(repo[n])
5039 displayer.close()
5039 displayer.close()
5040
5040
5041 @command('paths', [], _('[NAME]'), optionalrepo=True)
5041 @command('paths', [], _('[NAME]'), optionalrepo=True)
5042 def paths(ui, repo, search=None):
5042 def paths(ui, repo, search=None):
5043 """show aliases for remote repositories
5043 """show aliases for remote repositories
5044
5044
5045 Show definition of symbolic path name NAME. If no name is given,
5045 Show definition of symbolic path name NAME. If no name is given,
5046 show definition of all available names.
5046 show definition of all available names.
5047
5047
5048 Option -q/--quiet suppresses all output when searching for NAME
5048 Option -q/--quiet suppresses all output when searching for NAME
5049 and shows only the path names when listing all definitions.
5049 and shows only the path names when listing all definitions.
5050
5050
5051 Path names are defined in the [paths] section of your
5051 Path names are defined in the [paths] section of your
5052 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5052 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5053 repository, ``.hg/hgrc`` is used, too.
5053 repository, ``.hg/hgrc`` is used, too.
5054
5054
5055 The path names ``default`` and ``default-push`` have a special
5055 The path names ``default`` and ``default-push`` have a special
5056 meaning. When performing a push or pull operation, they are used
5056 meaning. When performing a push or pull operation, they are used
5057 as fallbacks if no location is specified on the command-line.
5057 as fallbacks if no location is specified on the command-line.
5058 When ``default-push`` is set, it will be used for push and
5058 When ``default-push`` is set, it will be used for push and
5059 ``default`` will be used for pull; otherwise ``default`` is used
5059 ``default`` will be used for pull; otherwise ``default`` is used
5060 as the fallback for both. When cloning a repository, the clone
5060 as the fallback for both. When cloning a repository, the clone
5061 source is written as ``default`` in ``.hg/hgrc``. Note that
5061 source is written as ``default`` in ``.hg/hgrc``. Note that
5062 ``default`` and ``default-push`` apply to all inbound (e.g.
5062 ``default`` and ``default-push`` apply to all inbound (e.g.
5063 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5063 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5064 :hg:`bundle`) operations.
5064 :hg:`bundle`) operations.
5065
5065
5066 See :hg:`help urls` for more information.
5066 See :hg:`help urls` for more information.
5067
5067
5068 Returns 0 on success.
5068 Returns 0 on success.
5069 """
5069 """
5070 if search:
5070 if search:
5071 for name, path in sorted(ui.paths.iteritems()):
5071 for name, path in sorted(ui.paths.iteritems()):
5072 if name == search:
5072 if name == search:
5073 ui.status("%s\n" % util.hidepassword(path.loc))
5073 ui.status("%s\n" % util.hidepassword(path.loc))
5074 return
5074 return
5075 if not ui.quiet:
5075 if not ui.quiet:
5076 ui.warn(_("not found!\n"))
5076 ui.warn(_("not found!\n"))
5077 return 1
5077 return 1
5078 else:
5078 else:
5079 for name, path in sorted(ui.paths.iteritems()):
5079 for name, path in sorted(ui.paths.iteritems()):
5080 if ui.quiet:
5080 if ui.quiet:
5081 ui.write("%s\n" % name)
5081 ui.write("%s\n" % name)
5082 else:
5082 else:
5083 ui.write("%s = %s\n" % (name,
5083 ui.write("%s = %s\n" % (name,
5084 util.hidepassword(path.loc)))
5084 util.hidepassword(path.loc)))
5085
5085
5086 @command('phase',
5086 @command('phase',
5087 [('p', 'public', False, _('set changeset phase to public')),
5087 [('p', 'public', False, _('set changeset phase to public')),
5088 ('d', 'draft', False, _('set changeset phase to draft')),
5088 ('d', 'draft', False, _('set changeset phase to draft')),
5089 ('s', 'secret', False, _('set changeset phase to secret')),
5089 ('s', 'secret', False, _('set changeset phase to secret')),
5090 ('f', 'force', False, _('allow to move boundary backward')),
5090 ('f', 'force', False, _('allow to move boundary backward')),
5091 ('r', 'rev', [], _('target revision'), _('REV')),
5091 ('r', 'rev', [], _('target revision'), _('REV')),
5092 ],
5092 ],
5093 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5093 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5094 def phase(ui, repo, *revs, **opts):
5094 def phase(ui, repo, *revs, **opts):
5095 """set or show the current phase name
5095 """set or show the current phase name
5096
5096
5097 With no argument, show the phase name of the current revision(s).
5097 With no argument, show the phase name of the current revision(s).
5098
5098
5099 With one of -p/--public, -d/--draft or -s/--secret, change the
5099 With one of -p/--public, -d/--draft or -s/--secret, change the
5100 phase value of the specified revisions.
5100 phase value of the specified revisions.
5101
5101
5102 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5102 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5103 lower phase to an higher phase. Phases are ordered as follows::
5103 lower phase to an higher phase. Phases are ordered as follows::
5104
5104
5105 public < draft < secret
5105 public < draft < secret
5106
5106
5107 Returns 0 on success, 1 if some phases could not be changed.
5107 Returns 0 on success, 1 if some phases could not be changed.
5108
5108
5109 (For more information about the phases concept, see :hg:`help phases`.)
5109 (For more information about the phases concept, see :hg:`help phases`.)
5110 """
5110 """
5111 # search for a unique phase argument
5111 # search for a unique phase argument
5112 targetphase = None
5112 targetphase = None
5113 for idx, name in enumerate(phases.phasenames):
5113 for idx, name in enumerate(phases.phasenames):
5114 if opts[name]:
5114 if opts[name]:
5115 if targetphase is not None:
5115 if targetphase is not None:
5116 raise error.Abort(_('only one phase can be specified'))
5116 raise error.Abort(_('only one phase can be specified'))
5117 targetphase = idx
5117 targetphase = idx
5118
5118
5119 # look for specified revision
5119 # look for specified revision
5120 revs = list(revs)
5120 revs = list(revs)
5121 revs.extend(opts['rev'])
5121 revs.extend(opts['rev'])
5122 if not revs:
5122 if not revs:
5123 # display both parents as the second parent phase can influence
5123 # display both parents as the second parent phase can influence
5124 # the phase of a merge commit
5124 # the phase of a merge commit
5125 revs = [c.rev() for c in repo[None].parents()]
5125 revs = [c.rev() for c in repo[None].parents()]
5126
5126
5127 revs = scmutil.revrange(repo, revs)
5127 revs = scmutil.revrange(repo, revs)
5128
5128
5129 lock = None
5129 lock = None
5130 ret = 0
5130 ret = 0
5131 if targetphase is None:
5131 if targetphase is None:
5132 # display
5132 # display
5133 for r in revs:
5133 for r in revs:
5134 ctx = repo[r]
5134 ctx = repo[r]
5135 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5135 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5136 else:
5136 else:
5137 tr = None
5137 tr = None
5138 lock = repo.lock()
5138 lock = repo.lock()
5139 try:
5139 try:
5140 tr = repo.transaction("phase")
5140 tr = repo.transaction("phase")
5141 # set phase
5141 # set phase
5142 if not revs:
5142 if not revs:
5143 raise error.Abort(_('empty revision set'))
5143 raise error.Abort(_('empty revision set'))
5144 nodes = [repo[r].node() for r in revs]
5144 nodes = [repo[r].node() for r in revs]
5145 # moving revision from public to draft may hide them
5145 # moving revision from public to draft may hide them
5146 # We have to check result on an unfiltered repository
5146 # We have to check result on an unfiltered repository
5147 unfi = repo.unfiltered()
5147 unfi = repo.unfiltered()
5148 getphase = unfi._phasecache.phase
5148 getphase = unfi._phasecache.phase
5149 olddata = [getphase(unfi, r) for r in unfi]
5149 olddata = [getphase(unfi, r) for r in unfi]
5150 phases.advanceboundary(repo, tr, targetphase, nodes)
5150 phases.advanceboundary(repo, tr, targetphase, nodes)
5151 if opts['force']:
5151 if opts['force']:
5152 phases.retractboundary(repo, tr, targetphase, nodes)
5152 phases.retractboundary(repo, tr, targetphase, nodes)
5153 tr.close()
5153 tr.close()
5154 finally:
5154 finally:
5155 if tr is not None:
5155 if tr is not None:
5156 tr.release()
5156 tr.release()
5157 lock.release()
5157 lock.release()
5158 getphase = unfi._phasecache.phase
5158 getphase = unfi._phasecache.phase
5159 newdata = [getphase(unfi, r) for r in unfi]
5159 newdata = [getphase(unfi, r) for r in unfi]
5160 changes = sum(newdata[r] != olddata[r] for r in unfi)
5160 changes = sum(newdata[r] != olddata[r] for r in unfi)
5161 cl = unfi.changelog
5161 cl = unfi.changelog
5162 rejected = [n for n in nodes
5162 rejected = [n for n in nodes
5163 if newdata[cl.rev(n)] < targetphase]
5163 if newdata[cl.rev(n)] < targetphase]
5164 if rejected:
5164 if rejected:
5165 ui.warn(_('cannot move %i changesets to a higher '
5165 ui.warn(_('cannot move %i changesets to a higher '
5166 'phase, use --force\n') % len(rejected))
5166 'phase, use --force\n') % len(rejected))
5167 ret = 1
5167 ret = 1
5168 if changes:
5168 if changes:
5169 msg = _('phase changed for %i changesets\n') % changes
5169 msg = _('phase changed for %i changesets\n') % changes
5170 if ret:
5170 if ret:
5171 ui.status(msg)
5171 ui.status(msg)
5172 else:
5172 else:
5173 ui.note(msg)
5173 ui.note(msg)
5174 else:
5174 else:
5175 ui.warn(_('no phases changed\n'))
5175 ui.warn(_('no phases changed\n'))
5176 return ret
5176 return ret
5177
5177
5178 def postincoming(ui, repo, modheads, optupdate, checkout):
5178 def postincoming(ui, repo, modheads, optupdate, checkout):
5179 if modheads == 0:
5179 if modheads == 0:
5180 return
5180 return
5181 if optupdate:
5181 if optupdate:
5182 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5182 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5183 try:
5183 try:
5184 ret = hg.update(repo, checkout)
5184 ret = hg.update(repo, checkout)
5185 except error.Abort as inst:
5185 except error.Abort as inst:
5186 ui.warn(_("not updating: %s\n") % str(inst))
5186 ui.warn(_("not updating: %s\n") % str(inst))
5187 if inst.hint:
5187 if inst.hint:
5188 ui.warn(_("(%s)\n") % inst.hint)
5188 ui.warn(_("(%s)\n") % inst.hint)
5189 return 0
5189 return 0
5190 if not ret and not checkout:
5190 if not ret and not checkout:
5191 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5191 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5192 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5192 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5193 return ret
5193 return ret
5194 if modheads > 1:
5194 if modheads > 1:
5195 currentbranchheads = len(repo.branchheads())
5195 currentbranchheads = len(repo.branchheads())
5196 if currentbranchheads == modheads:
5196 if currentbranchheads == modheads:
5197 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5197 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5198 elif currentbranchheads > 1:
5198 elif currentbranchheads > 1:
5199 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5199 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5200 "merge)\n"))
5200 "merge)\n"))
5201 else:
5201 else:
5202 ui.status(_("(run 'hg heads' to see heads)\n"))
5202 ui.status(_("(run 'hg heads' to see heads)\n"))
5203 else:
5203 else:
5204 ui.status(_("(run 'hg update' to get a working copy)\n"))
5204 ui.status(_("(run 'hg update' to get a working copy)\n"))
5205
5205
5206 @command('^pull',
5206 @command('^pull',
5207 [('u', 'update', None,
5207 [('u', 'update', None,
5208 _('update to new branch head if changesets were pulled')),
5208 _('update to new branch head if changesets were pulled')),
5209 ('f', 'force', None, _('run even when remote repository is unrelated')),
5209 ('f', 'force', None, _('run even when remote repository is unrelated')),
5210 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5210 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5211 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5211 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5212 ('b', 'branch', [], _('a specific branch you would like to pull'),
5212 ('b', 'branch', [], _('a specific branch you would like to pull'),
5213 _('BRANCH')),
5213 _('BRANCH')),
5214 ] + remoteopts,
5214 ] + remoteopts,
5215 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5215 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5216 def pull(ui, repo, source="default", **opts):
5216 def pull(ui, repo, source="default", **opts):
5217 """pull changes from the specified source
5217 """pull changes from the specified source
5218
5218
5219 Pull changes from a remote repository to a local one.
5219 Pull changes from a remote repository to a local one.
5220
5220
5221 This finds all changes from the repository at the specified path
5221 This finds all changes from the repository at the specified path
5222 or URL and adds them to a local repository (the current one unless
5222 or URL and adds them to a local repository (the current one unless
5223 -R is specified). By default, this does not update the copy of the
5223 -R is specified). By default, this does not update the copy of the
5224 project in the working directory.
5224 project in the working directory.
5225
5225
5226 Use :hg:`incoming` if you want to see what would have been added
5226 Use :hg:`incoming` if you want to see what would have been added
5227 by a pull at the time you issued this command. If you then decide
5227 by a pull at the time you issued this command. If you then decide
5228 to add those changes to the repository, you should use :hg:`pull
5228 to add those changes to the repository, you should use :hg:`pull
5229 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5229 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5230
5230
5231 If SOURCE is omitted, the 'default' path will be used.
5231 If SOURCE is omitted, the 'default' path will be used.
5232 See :hg:`help urls` for more information.
5232 See :hg:`help urls` for more information.
5233
5233
5234 Returns 0 on success, 1 if an update had unresolved files.
5234 Returns 0 on success, 1 if an update had unresolved files.
5235 """
5235 """
5236 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5236 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5237 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5237 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5238 other = hg.peer(repo, opts, source)
5238 other = hg.peer(repo, opts, source)
5239 try:
5239 try:
5240 revs, checkout = hg.addbranchrevs(repo, other, branches,
5240 revs, checkout = hg.addbranchrevs(repo, other, branches,
5241 opts.get('rev'))
5241 opts.get('rev'))
5242
5242
5243
5243
5244 pullopargs = {}
5244 pullopargs = {}
5245 if opts.get('bookmark'):
5245 if opts.get('bookmark'):
5246 if not revs:
5246 if not revs:
5247 revs = []
5247 revs = []
5248 # The list of bookmark used here is not the one used to actually
5248 # The list of bookmark used here is not the one used to actually
5249 # update the bookmark name. This can result in the revision pulled
5249 # update the bookmark name. This can result in the revision pulled
5250 # not ending up with the name of the bookmark because of a race
5250 # not ending up with the name of the bookmark because of a race
5251 # condition on the server. (See issue 4689 for details)
5251 # condition on the server. (See issue 4689 for details)
5252 remotebookmarks = other.listkeys('bookmarks')
5252 remotebookmarks = other.listkeys('bookmarks')
5253 pullopargs['remotebookmarks'] = remotebookmarks
5253 pullopargs['remotebookmarks'] = remotebookmarks
5254 for b in opts['bookmark']:
5254 for b in opts['bookmark']:
5255 if b not in remotebookmarks:
5255 if b not in remotebookmarks:
5256 raise error.Abort(_('remote bookmark %s not found!') % b)
5256 raise error.Abort(_('remote bookmark %s not found!') % b)
5257 revs.append(remotebookmarks[b])
5257 revs.append(remotebookmarks[b])
5258
5258
5259 if revs:
5259 if revs:
5260 try:
5260 try:
5261 # When 'rev' is a bookmark name, we cannot guarantee that it
5261 # When 'rev' is a bookmark name, we cannot guarantee that it
5262 # will be updated with that name because of a race condition
5262 # will be updated with that name because of a race condition
5263 # server side. (See issue 4689 for details)
5263 # server side. (See issue 4689 for details)
5264 oldrevs = revs
5264 oldrevs = revs
5265 revs = [] # actually, nodes
5265 revs = [] # actually, nodes
5266 for r in oldrevs:
5266 for r in oldrevs:
5267 node = other.lookup(r)
5267 node = other.lookup(r)
5268 revs.append(node)
5268 revs.append(node)
5269 if r == checkout:
5269 if r == checkout:
5270 checkout = node
5270 checkout = node
5271 except error.CapabilityError:
5271 except error.CapabilityError:
5272 err = _("other repository doesn't support revision lookup, "
5272 err = _("other repository doesn't support revision lookup, "
5273 "so a rev cannot be specified.")
5273 "so a rev cannot be specified.")
5274 raise error.Abort(err)
5274 raise error.Abort(err)
5275
5275
5276 modheads = exchange.pull(repo, other, heads=revs,
5276 modheads = exchange.pull(repo, other, heads=revs,
5277 force=opts.get('force'),
5277 force=opts.get('force'),
5278 bookmarks=opts.get('bookmark', ()),
5278 bookmarks=opts.get('bookmark', ()),
5279 opargs=pullopargs).cgresult
5279 opargs=pullopargs).cgresult
5280 if checkout:
5280 if checkout:
5281 checkout = str(repo.changelog.rev(checkout))
5281 checkout = str(repo.changelog.rev(checkout))
5282 repo._subtoppath = source
5282 repo._subtoppath = source
5283 try:
5283 try:
5284 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5284 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5285
5285
5286 finally:
5286 finally:
5287 del repo._subtoppath
5287 del repo._subtoppath
5288
5288
5289 finally:
5289 finally:
5290 other.close()
5290 other.close()
5291 return ret
5291 return ret
5292
5292
5293 @command('^push',
5293 @command('^push',
5294 [('f', 'force', None, _('force push')),
5294 [('f', 'force', None, _('force push')),
5295 ('r', 'rev', [],
5295 ('r', 'rev', [],
5296 _('a changeset intended to be included in the destination'),
5296 _('a changeset intended to be included in the destination'),
5297 _('REV')),
5297 _('REV')),
5298 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5298 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5299 ('b', 'branch', [],
5299 ('b', 'branch', [],
5300 _('a specific branch you would like to push'), _('BRANCH')),
5300 _('a specific branch you would like to push'), _('BRANCH')),
5301 ('', 'new-branch', False, _('allow pushing a new branch')),
5301 ('', 'new-branch', False, _('allow pushing a new branch')),
5302 ] + remoteopts,
5302 ] + remoteopts,
5303 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5303 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5304 def push(ui, repo, dest=None, **opts):
5304 def push(ui, repo, dest=None, **opts):
5305 """push changes to the specified destination
5305 """push changes to the specified destination
5306
5306
5307 Push changesets from the local repository to the specified
5307 Push changesets from the local repository to the specified
5308 destination.
5308 destination.
5309
5309
5310 This operation is symmetrical to pull: it is identical to a pull
5310 This operation is symmetrical to pull: it is identical to a pull
5311 in the destination repository from the current one.
5311 in the destination repository from the current one.
5312
5312
5313 By default, push will not allow creation of new heads at the
5313 By default, push will not allow creation of new heads at the
5314 destination, since multiple heads would make it unclear which head
5314 destination, since multiple heads would make it unclear which head
5315 to use. In this situation, it is recommended to pull and merge
5315 to use. In this situation, it is recommended to pull and merge
5316 before pushing.
5316 before pushing.
5317
5317
5318 Use --new-branch if you want to allow push to create a new named
5318 Use --new-branch if you want to allow push to create a new named
5319 branch that is not present at the destination. This allows you to
5319 branch that is not present at the destination. This allows you to
5320 only create a new branch without forcing other changes.
5320 only create a new branch without forcing other changes.
5321
5321
5322 .. note::
5322 .. note::
5323
5323
5324 Extra care should be taken with the -f/--force option,
5324 Extra care should be taken with the -f/--force option,
5325 which will push all new heads on all branches, an action which will
5325 which will push all new heads on all branches, an action which will
5326 almost always cause confusion for collaborators.
5326 almost always cause confusion for collaborators.
5327
5327
5328 If -r/--rev is used, the specified revision and all its ancestors
5328 If -r/--rev is used, the specified revision and all its ancestors
5329 will be pushed to the remote repository.
5329 will be pushed to the remote repository.
5330
5330
5331 If -B/--bookmark is used, the specified bookmarked revision, its
5331 If -B/--bookmark is used, the specified bookmarked revision, its
5332 ancestors, and the bookmark will be pushed to the remote
5332 ancestors, and the bookmark will be pushed to the remote
5333 repository.
5333 repository.
5334
5334
5335 Please see :hg:`help urls` for important details about ``ssh://``
5335 Please see :hg:`help urls` for important details about ``ssh://``
5336 URLs. If DESTINATION is omitted, a default path will be used.
5336 URLs. If DESTINATION is omitted, a default path will be used.
5337
5337
5338 Returns 0 if push was successful, 1 if nothing to push.
5338 Returns 0 if push was successful, 1 if nothing to push.
5339 """
5339 """
5340
5340
5341 if opts.get('bookmark'):
5341 if opts.get('bookmark'):
5342 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5342 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5343 for b in opts['bookmark']:
5343 for b in opts['bookmark']:
5344 # translate -B options to -r so changesets get pushed
5344 # translate -B options to -r so changesets get pushed
5345 if b in repo._bookmarks:
5345 if b in repo._bookmarks:
5346 opts.setdefault('rev', []).append(b)
5346 opts.setdefault('rev', []).append(b)
5347 else:
5347 else:
5348 # if we try to push a deleted bookmark, translate it to null
5348 # if we try to push a deleted bookmark, translate it to null
5349 # this lets simultaneous -r, -b options continue working
5349 # this lets simultaneous -r, -b options continue working
5350 opts.setdefault('rev', []).append("null")
5350 opts.setdefault('rev', []).append("null")
5351
5351
5352 path = ui.paths.getpath(dest, default='default')
5352 path = ui.paths.getpath(dest, default='default')
5353 if not path:
5353 if not path:
5354 raise error.Abort(_('default repository not configured!'),
5354 raise error.Abort(_('default repository not configured!'),
5355 hint=_('see the "path" section in "hg help config"'))
5355 hint=_('see the "path" section in "hg help config"'))
5356 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5356 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5357 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5357 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5358 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5358 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5359 other = hg.peer(repo, opts, dest)
5359 other = hg.peer(repo, opts, dest)
5360
5360
5361 if revs:
5361 if revs:
5362 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5362 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5363 if not revs:
5363 if not revs:
5364 raise error.Abort(_("specified revisions evaluate to an empty set"),
5364 raise error.Abort(_("specified revisions evaluate to an empty set"),
5365 hint=_("use different revision arguments"))
5365 hint=_("use different revision arguments"))
5366
5366
5367 repo._subtoppath = dest
5367 repo._subtoppath = dest
5368 try:
5368 try:
5369 # push subrepos depth-first for coherent ordering
5369 # push subrepos depth-first for coherent ordering
5370 c = repo['']
5370 c = repo['']
5371 subs = c.substate # only repos that are committed
5371 subs = c.substate # only repos that are committed
5372 for s in sorted(subs):
5372 for s in sorted(subs):
5373 result = c.sub(s).push(opts)
5373 result = c.sub(s).push(opts)
5374 if result == 0:
5374 if result == 0:
5375 return not result
5375 return not result
5376 finally:
5376 finally:
5377 del repo._subtoppath
5377 del repo._subtoppath
5378 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5378 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5379 newbranch=opts.get('new_branch'),
5379 newbranch=opts.get('new_branch'),
5380 bookmarks=opts.get('bookmark', ()))
5380 bookmarks=opts.get('bookmark', ()))
5381
5381
5382 result = not pushop.cgresult
5382 result = not pushop.cgresult
5383
5383
5384 if pushop.bkresult is not None:
5384 if pushop.bkresult is not None:
5385 if pushop.bkresult == 2:
5385 if pushop.bkresult == 2:
5386 result = 2
5386 result = 2
5387 elif not result and pushop.bkresult:
5387 elif not result and pushop.bkresult:
5388 result = 2
5388 result = 2
5389
5389
5390 return result
5390 return result
5391
5391
5392 @command('recover', [])
5392 @command('recover', [])
5393 def recover(ui, repo):
5393 def recover(ui, repo):
5394 """roll back an interrupted transaction
5394 """roll back an interrupted transaction
5395
5395
5396 Recover from an interrupted commit or pull.
5396 Recover from an interrupted commit or pull.
5397
5397
5398 This command tries to fix the repository status after an
5398 This command tries to fix the repository status after an
5399 interrupted operation. It should only be necessary when Mercurial
5399 interrupted operation. It should only be necessary when Mercurial
5400 suggests it.
5400 suggests it.
5401
5401
5402 Returns 0 if successful, 1 if nothing to recover or verify fails.
5402 Returns 0 if successful, 1 if nothing to recover or verify fails.
5403 """
5403 """
5404 if repo.recover():
5404 if repo.recover():
5405 return hg.verify(repo)
5405 return hg.verify(repo)
5406 return 1
5406 return 1
5407
5407
5408 @command('^remove|rm',
5408 @command('^remove|rm',
5409 [('A', 'after', None, _('record delete for missing files')),
5409 [('A', 'after', None, _('record delete for missing files')),
5410 ('f', 'force', None,
5410 ('f', 'force', None,
5411 _('remove (and delete) file even if added or modified')),
5411 _('remove (and delete) file even if added or modified')),
5412 ] + subrepoopts + walkopts,
5412 ] + subrepoopts + walkopts,
5413 _('[OPTION]... FILE...'),
5413 _('[OPTION]... FILE...'),
5414 inferrepo=True)
5414 inferrepo=True)
5415 def remove(ui, repo, *pats, **opts):
5415 def remove(ui, repo, *pats, **opts):
5416 """remove the specified files on the next commit
5416 """remove the specified files on the next commit
5417
5417
5418 Schedule the indicated files for removal from the current branch.
5418 Schedule the indicated files for removal from the current branch.
5419
5419
5420 This command schedules the files to be removed at the next commit.
5420 This command schedules the files to be removed at the next commit.
5421 To undo a remove before that, see :hg:`revert`. To undo added
5421 To undo a remove before that, see :hg:`revert`. To undo added
5422 files, see :hg:`forget`.
5422 files, see :hg:`forget`.
5423
5423
5424 .. container:: verbose
5424 .. container:: verbose
5425
5425
5426 -A/--after can be used to remove only files that have already
5426 -A/--after can be used to remove only files that have already
5427 been deleted, -f/--force can be used to force deletion, and -Af
5427 been deleted, -f/--force can be used to force deletion, and -Af
5428 can be used to remove files from the next revision without
5428 can be used to remove files from the next revision without
5429 deleting them from the working directory.
5429 deleting them from the working directory.
5430
5430
5431 The following table details the behavior of remove for different
5431 The following table details the behavior of remove for different
5432 file states (columns) and option combinations (rows). The file
5432 file states (columns) and option combinations (rows). The file
5433 states are Added [A], Clean [C], Modified [M] and Missing [!]
5433 states are Added [A], Clean [C], Modified [M] and Missing [!]
5434 (as reported by :hg:`status`). The actions are Warn, Remove
5434 (as reported by :hg:`status`). The actions are Warn, Remove
5435 (from branch) and Delete (from disk):
5435 (from branch) and Delete (from disk):
5436
5436
5437 ========= == == == ==
5437 ========= == == == ==
5438 opt/state A C M !
5438 opt/state A C M !
5439 ========= == == == ==
5439 ========= == == == ==
5440 none W RD W R
5440 none W RD W R
5441 -f R RD RD R
5441 -f R RD RD R
5442 -A W W W R
5442 -A W W W R
5443 -Af R R R R
5443 -Af R R R R
5444 ========= == == == ==
5444 ========= == == == ==
5445
5445
5446 Note that remove never deletes files in Added [A] state from the
5446 Note that remove never deletes files in Added [A] state from the
5447 working directory, not even if option --force is specified.
5447 working directory, not even if option --force is specified.
5448
5448
5449 Returns 0 on success, 1 if any warnings encountered.
5449 Returns 0 on success, 1 if any warnings encountered.
5450 """
5450 """
5451
5451
5452 after, force = opts.get('after'), opts.get('force')
5452 after, force = opts.get('after'), opts.get('force')
5453 if not pats and not after:
5453 if not pats and not after:
5454 raise error.Abort(_('no files specified'))
5454 raise error.Abort(_('no files specified'))
5455
5455
5456 m = scmutil.match(repo[None], pats, opts)
5456 m = scmutil.match(repo[None], pats, opts)
5457 subrepos = opts.get('subrepos')
5457 subrepos = opts.get('subrepos')
5458 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5458 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5459
5459
5460 @command('rename|move|mv',
5460 @command('rename|move|mv',
5461 [('A', 'after', None, _('record a rename that has already occurred')),
5461 [('A', 'after', None, _('record a rename that has already occurred')),
5462 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5462 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5463 ] + walkopts + dryrunopts,
5463 ] + walkopts + dryrunopts,
5464 _('[OPTION]... SOURCE... DEST'))
5464 _('[OPTION]... SOURCE... DEST'))
5465 def rename(ui, repo, *pats, **opts):
5465 def rename(ui, repo, *pats, **opts):
5466 """rename files; equivalent of copy + remove
5466 """rename files; equivalent of copy + remove
5467
5467
5468 Mark dest as copies of sources; mark sources for deletion. If dest
5468 Mark dest as copies of sources; mark sources for deletion. If dest
5469 is a directory, copies are put in that directory. If dest is a
5469 is a directory, copies are put in that directory. If dest is a
5470 file, there can only be one source.
5470 file, there can only be one source.
5471
5471
5472 By default, this command copies the contents of files as they
5472 By default, this command copies the contents of files as they
5473 exist in the working directory. If invoked with -A/--after, the
5473 exist in the working directory. If invoked with -A/--after, the
5474 operation is recorded, but no copying is performed.
5474 operation is recorded, but no copying is performed.
5475
5475
5476 This command takes effect at the next commit. To undo a rename
5476 This command takes effect at the next commit. To undo a rename
5477 before that, see :hg:`revert`.
5477 before that, see :hg:`revert`.
5478
5478
5479 Returns 0 on success, 1 if errors are encountered.
5479 Returns 0 on success, 1 if errors are encountered.
5480 """
5480 """
5481 wlock = repo.wlock(False)
5481 wlock = repo.wlock(False)
5482 try:
5482 try:
5483 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5483 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5484 finally:
5484 finally:
5485 wlock.release()
5485 wlock.release()
5486
5486
5487 @command('resolve',
5487 @command('resolve',
5488 [('a', 'all', None, _('select all unresolved files')),
5488 [('a', 'all', None, _('select all unresolved files')),
5489 ('l', 'list', None, _('list state of files needing merge')),
5489 ('l', 'list', None, _('list state of files needing merge')),
5490 ('m', 'mark', None, _('mark files as resolved')),
5490 ('m', 'mark', None, _('mark files as resolved')),
5491 ('u', 'unmark', None, _('mark files as unresolved')),
5491 ('u', 'unmark', None, _('mark files as unresolved')),
5492 ('n', 'no-status', None, _('hide status prefix'))]
5492 ('n', 'no-status', None, _('hide status prefix'))]
5493 + mergetoolopts + walkopts + formatteropts,
5493 + mergetoolopts + walkopts + formatteropts,
5494 _('[OPTION]... [FILE]...'),
5494 _('[OPTION]... [FILE]...'),
5495 inferrepo=True)
5495 inferrepo=True)
5496 def resolve(ui, repo, *pats, **opts):
5496 def resolve(ui, repo, *pats, **opts):
5497 """redo merges or set/view the merge status of files
5497 """redo merges or set/view the merge status of files
5498
5498
5499 Merges with unresolved conflicts are often the result of
5499 Merges with unresolved conflicts are often the result of
5500 non-interactive merging using the ``internal:merge`` configuration
5500 non-interactive merging using the ``internal:merge`` configuration
5501 setting, or a command-line merge tool like ``diff3``. The resolve
5501 setting, or a command-line merge tool like ``diff3``. The resolve
5502 command is used to manage the files involved in a merge, after
5502 command is used to manage the files involved in a merge, after
5503 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5503 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5504 working directory must have two parents). See :hg:`help
5504 working directory must have two parents). See :hg:`help
5505 merge-tools` for information on configuring merge tools.
5505 merge-tools` for information on configuring merge tools.
5506
5506
5507 The resolve command can be used in the following ways:
5507 The resolve command can be used in the following ways:
5508
5508
5509 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5509 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5510 files, discarding any previous merge attempts. Re-merging is not
5510 files, discarding any previous merge attempts. Re-merging is not
5511 performed for files already marked as resolved. Use ``--all/-a``
5511 performed for files already marked as resolved. Use ``--all/-a``
5512 to select all unresolved files. ``--tool`` can be used to specify
5512 to select all unresolved files. ``--tool`` can be used to specify
5513 the merge tool used for the given files. It overrides the HGMERGE
5513 the merge tool used for the given files. It overrides the HGMERGE
5514 environment variable and your configuration files. Previous file
5514 environment variable and your configuration files. Previous file
5515 contents are saved with a ``.orig`` suffix.
5515 contents are saved with a ``.orig`` suffix.
5516
5516
5517 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5517 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5518 (e.g. after having manually fixed-up the files). The default is
5518 (e.g. after having manually fixed-up the files). The default is
5519 to mark all unresolved files.
5519 to mark all unresolved files.
5520
5520
5521 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5521 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5522 default is to mark all resolved files.
5522 default is to mark all resolved files.
5523
5523
5524 - :hg:`resolve -l`: list files which had or still have conflicts.
5524 - :hg:`resolve -l`: list files which had or still have conflicts.
5525 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5525 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5526
5526
5527 Note that Mercurial will not let you commit files with unresolved
5527 Note that Mercurial will not let you commit files with unresolved
5528 merge conflicts. You must use :hg:`resolve -m ...` before you can
5528 merge conflicts. You must use :hg:`resolve -m ...` before you can
5529 commit after a conflicting merge.
5529 commit after a conflicting merge.
5530
5530
5531 Returns 0 on success, 1 if any files fail a resolve attempt.
5531 Returns 0 on success, 1 if any files fail a resolve attempt.
5532 """
5532 """
5533
5533
5534 all, mark, unmark, show, nostatus = \
5534 all, mark, unmark, show, nostatus = \
5535 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5535 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5536
5536
5537 if (show and (mark or unmark)) or (mark and unmark):
5537 if (show and (mark or unmark)) or (mark and unmark):
5538 raise error.Abort(_("too many options specified"))
5538 raise error.Abort(_("too many options specified"))
5539 if pats and all:
5539 if pats and all:
5540 raise error.Abort(_("can't specify --all and patterns"))
5540 raise error.Abort(_("can't specify --all and patterns"))
5541 if not (all or pats or show or mark or unmark):
5541 if not (all or pats or show or mark or unmark):
5542 raise error.Abort(_('no files or directories specified'),
5542 raise error.Abort(_('no files or directories specified'),
5543 hint=('use --all to re-merge all unresolved files'))
5543 hint=('use --all to re-merge all unresolved files'))
5544
5544
5545 if show:
5545 if show:
5546 fm = ui.formatter('resolve', opts)
5546 fm = ui.formatter('resolve', opts)
5547 ms = mergemod.mergestate(repo)
5547 ms = mergemod.mergestate(repo)
5548 m = scmutil.match(repo[None], pats, opts)
5548 m = scmutil.match(repo[None], pats, opts)
5549 for f in ms:
5549 for f in ms:
5550 if not m(f):
5550 if not m(f):
5551 continue
5551 continue
5552 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5552 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5553 fm.startitem()
5553 fm.startitem()
5554 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5554 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5555 fm.write('path', '%s\n', f, label=l)
5555 fm.write('path', '%s\n', f, label=l)
5556 fm.end()
5556 fm.end()
5557 return 0
5557 return 0
5558
5558
5559 wlock = repo.wlock()
5559 wlock = repo.wlock()
5560 try:
5560 try:
5561 ms = mergemod.mergestate(repo)
5561 ms = mergemod.mergestate(repo)
5562
5562
5563 if not (ms.active() or repo.dirstate.p2() != nullid):
5563 if not (ms.active() or repo.dirstate.p2() != nullid):
5564 raise error.Abort(
5564 raise error.Abort(
5565 _('resolve command not applicable when not merging'))
5565 _('resolve command not applicable when not merging'))
5566
5566
5567 m = scmutil.match(repo[None], pats, opts)
5567 m = scmutil.match(repo[None], pats, opts)
5568 ret = 0
5568 ret = 0
5569 didwork = False
5569 didwork = False
5570
5570
5571 tocomplete = []
5571 tocomplete = []
5572 for f in ms:
5572 for f in ms:
5573 if not m(f):
5573 if not m(f):
5574 continue
5574 continue
5575
5575
5576 didwork = True
5576 didwork = True
5577
5577
5578 if mark:
5578 if mark:
5579 ms.mark(f, "r")
5579 ms.mark(f, "r")
5580 elif unmark:
5580 elif unmark:
5581 ms.mark(f, "u")
5581 ms.mark(f, "u")
5582 else:
5582 else:
5583 wctx = repo[None]
5583 wctx = repo[None]
5584
5584
5585 # backup pre-resolve (merge uses .orig for its own purposes)
5585 # backup pre-resolve (merge uses .orig for its own purposes)
5586 a = repo.wjoin(f)
5586 a = repo.wjoin(f)
5587 util.copyfile(a, a + ".resolve")
5587 util.copyfile(a, a + ".resolve")
5588
5588
5589 try:
5589 try:
5590 # preresolve file
5590 # preresolve file
5591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5591 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5592 'resolve')
5592 'resolve')
5593 complete, r = ms.preresolve(f, wctx)
5593 complete, r = ms.preresolve(f, wctx)
5594 if not complete:
5594 if not complete:
5595 tocomplete.append(f)
5595 tocomplete.append(f)
5596 elif r:
5596 elif r:
5597 ret = 1
5597 ret = 1
5598 finally:
5598 finally:
5599 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5599 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5600 ms.commit()
5600 ms.commit()
5601
5601
5602 # replace filemerge's .orig file with our resolve file
5602 # replace filemerge's .orig file with our resolve file
5603 # for files in tocomplete, ms.resolve will not overwrite
5603 # for files in tocomplete, ms.resolve will not overwrite
5604 # .orig -- only preresolve does
5604 # .orig -- only preresolve does
5605 util.rename(a + ".resolve", a + ".orig")
5605 util.rename(a + ".resolve", a + ".orig")
5606
5606
5607 for f in tocomplete:
5607 for f in tocomplete:
5608 try:
5608 try:
5609 # resolve file
5609 # resolve file
5610 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5610 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5611 'resolve')
5611 'resolve')
5612 r = ms.resolve(f, wctx)
5612 r = ms.resolve(f, wctx)
5613 if r:
5613 if r:
5614 ret = 1
5614 ret = 1
5615 finally:
5615 finally:
5616 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5616 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5617 ms.commit()
5617 ms.commit()
5618
5618
5619 ms.commit()
5619 ms.commit()
5620
5620
5621 if not didwork and pats:
5621 if not didwork and pats:
5622 ui.warn(_("arguments do not match paths that need resolving\n"))
5622 ui.warn(_("arguments do not match paths that need resolving\n"))
5623
5623
5624 finally:
5624 finally:
5625 wlock.release()
5625 wlock.release()
5626
5626
5627 # Nudge users into finishing an unfinished operation
5627 # Nudge users into finishing an unfinished operation
5628 if not list(ms.unresolved()):
5628 if not list(ms.unresolved()):
5629 ui.status(_('(no more unresolved files)\n'))
5629 ui.status(_('(no more unresolved files)\n'))
5630
5630
5631 return ret
5631 return ret
5632
5632
5633 @command('revert',
5633 @command('revert',
5634 [('a', 'all', None, _('revert all changes when no arguments given')),
5634 [('a', 'all', None, _('revert all changes when no arguments given')),
5635 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5635 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5636 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5636 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5637 ('C', 'no-backup', None, _('do not save backup copies of files')),
5637 ('C', 'no-backup', None, _('do not save backup copies of files')),
5638 ('i', 'interactive', None,
5638 ('i', 'interactive', None,
5639 _('interactively select the changes (EXPERIMENTAL)')),
5639 _('interactively select the changes (EXPERIMENTAL)')),
5640 ] + walkopts + dryrunopts,
5640 ] + walkopts + dryrunopts,
5641 _('[OPTION]... [-r REV] [NAME]...'))
5641 _('[OPTION]... [-r REV] [NAME]...'))
5642 def revert(ui, repo, *pats, **opts):
5642 def revert(ui, repo, *pats, **opts):
5643 """restore files to their checkout state
5643 """restore files to their checkout state
5644
5644
5645 .. note::
5645 .. note::
5646
5646
5647 To check out earlier revisions, you should use :hg:`update REV`.
5647 To check out earlier revisions, you should use :hg:`update REV`.
5648 To cancel an uncommitted merge (and lose your changes),
5648 To cancel an uncommitted merge (and lose your changes),
5649 use :hg:`update --clean .`.
5649 use :hg:`update --clean .`.
5650
5650
5651 With no revision specified, revert the specified files or directories
5651 With no revision specified, revert the specified files or directories
5652 to the contents they had in the parent of the working directory.
5652 to the contents they had in the parent of the working directory.
5653 This restores the contents of files to an unmodified
5653 This restores the contents of files to an unmodified
5654 state and unschedules adds, removes, copies, and renames. If the
5654 state and unschedules adds, removes, copies, and renames. If the
5655 working directory has two parents, you must explicitly specify a
5655 working directory has two parents, you must explicitly specify a
5656 revision.
5656 revision.
5657
5657
5658 Using the -r/--rev or -d/--date options, revert the given files or
5658 Using the -r/--rev or -d/--date options, revert the given files or
5659 directories to their states as of a specific revision. Because
5659 directories to their states as of a specific revision. Because
5660 revert does not change the working directory parents, this will
5660 revert does not change the working directory parents, this will
5661 cause these files to appear modified. This can be helpful to "back
5661 cause these files to appear modified. This can be helpful to "back
5662 out" some or all of an earlier change. See :hg:`backout` for a
5662 out" some or all of an earlier change. See :hg:`backout` for a
5663 related method.
5663 related method.
5664
5664
5665 Modified files are saved with a .orig suffix before reverting.
5665 Modified files are saved with a .orig suffix before reverting.
5666 To disable these backups, use --no-backup.
5666 To disable these backups, use --no-backup.
5667
5667
5668 See :hg:`help dates` for a list of formats valid for -d/--date.
5668 See :hg:`help dates` for a list of formats valid for -d/--date.
5669
5669
5670 See :hg:`help backout` for a way to reverse the effect of an
5670 See :hg:`help backout` for a way to reverse the effect of an
5671 earlier changeset.
5671 earlier changeset.
5672
5672
5673 Returns 0 on success.
5673 Returns 0 on success.
5674 """
5674 """
5675
5675
5676 if opts.get("date"):
5676 if opts.get("date"):
5677 if opts.get("rev"):
5677 if opts.get("rev"):
5678 raise error.Abort(_("you can't specify a revision and a date"))
5678 raise error.Abort(_("you can't specify a revision and a date"))
5679 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5679 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5680
5680
5681 parent, p2 = repo.dirstate.parents()
5681 parent, p2 = repo.dirstate.parents()
5682 if not opts.get('rev') and p2 != nullid:
5682 if not opts.get('rev') and p2 != nullid:
5683 # revert after merge is a trap for new users (issue2915)
5683 # revert after merge is a trap for new users (issue2915)
5684 raise error.Abort(_('uncommitted merge with no revision specified'),
5684 raise error.Abort(_('uncommitted merge with no revision specified'),
5685 hint=_('use "hg update" or see "hg help revert"'))
5685 hint=_('use "hg update" or see "hg help revert"'))
5686
5686
5687 ctx = scmutil.revsingle(repo, opts.get('rev'))
5687 ctx = scmutil.revsingle(repo, opts.get('rev'))
5688
5688
5689 if (not (pats or opts.get('include') or opts.get('exclude') or
5689 if (not (pats or opts.get('include') or opts.get('exclude') or
5690 opts.get('all') or opts.get('interactive'))):
5690 opts.get('all') or opts.get('interactive'))):
5691 msg = _("no files or directories specified")
5691 msg = _("no files or directories specified")
5692 if p2 != nullid:
5692 if p2 != nullid:
5693 hint = _("uncommitted merge, use --all to discard all changes,"
5693 hint = _("uncommitted merge, use --all to discard all changes,"
5694 " or 'hg update -C .' to abort the merge")
5694 " or 'hg update -C .' to abort the merge")
5695 raise error.Abort(msg, hint=hint)
5695 raise error.Abort(msg, hint=hint)
5696 dirty = any(repo.status())
5696 dirty = any(repo.status())
5697 node = ctx.node()
5697 node = ctx.node()
5698 if node != parent:
5698 if node != parent:
5699 if dirty:
5699 if dirty:
5700 hint = _("uncommitted changes, use --all to discard all"
5700 hint = _("uncommitted changes, use --all to discard all"
5701 " changes, or 'hg update %s' to update") % ctx.rev()
5701 " changes, or 'hg update %s' to update") % ctx.rev()
5702 else:
5702 else:
5703 hint = _("use --all to revert all files,"
5703 hint = _("use --all to revert all files,"
5704 " or 'hg update %s' to update") % ctx.rev()
5704 " or 'hg update %s' to update") % ctx.rev()
5705 elif dirty:
5705 elif dirty:
5706 hint = _("uncommitted changes, use --all to discard all changes")
5706 hint = _("uncommitted changes, use --all to discard all changes")
5707 else:
5707 else:
5708 hint = _("use --all to revert all files")
5708 hint = _("use --all to revert all files")
5709 raise error.Abort(msg, hint=hint)
5709 raise error.Abort(msg, hint=hint)
5710
5710
5711 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5711 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5712
5712
5713 @command('rollback', dryrunopts +
5713 @command('rollback', dryrunopts +
5714 [('f', 'force', False, _('ignore safety measures'))])
5714 [('f', 'force', False, _('ignore safety measures'))])
5715 def rollback(ui, repo, **opts):
5715 def rollback(ui, repo, **opts):
5716 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5716 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5717
5717
5718 Please use :hg:`commit --amend` instead of rollback to correct
5718 Please use :hg:`commit --amend` instead of rollback to correct
5719 mistakes in the last commit.
5719 mistakes in the last commit.
5720
5720
5721 This command should be used with care. There is only one level of
5721 This command should be used with care. There is only one level of
5722 rollback, and there is no way to undo a rollback. It will also
5722 rollback, and there is no way to undo a rollback. It will also
5723 restore the dirstate at the time of the last transaction, losing
5723 restore the dirstate at the time of the last transaction, losing
5724 any dirstate changes since that time. This command does not alter
5724 any dirstate changes since that time. This command does not alter
5725 the working directory.
5725 the working directory.
5726
5726
5727 Transactions are used to encapsulate the effects of all commands
5727 Transactions are used to encapsulate the effects of all commands
5728 that create new changesets or propagate existing changesets into a
5728 that create new changesets or propagate existing changesets into a
5729 repository.
5729 repository.
5730
5730
5731 .. container:: verbose
5731 .. container:: verbose
5732
5732
5733 For example, the following commands are transactional, and their
5733 For example, the following commands are transactional, and their
5734 effects can be rolled back:
5734 effects can be rolled back:
5735
5735
5736 - commit
5736 - commit
5737 - import
5737 - import
5738 - pull
5738 - pull
5739 - push (with this repository as the destination)
5739 - push (with this repository as the destination)
5740 - unbundle
5740 - unbundle
5741
5741
5742 To avoid permanent data loss, rollback will refuse to rollback a
5742 To avoid permanent data loss, rollback will refuse to rollback a
5743 commit transaction if it isn't checked out. Use --force to
5743 commit transaction if it isn't checked out. Use --force to
5744 override this protection.
5744 override this protection.
5745
5745
5746 This command is not intended for use on public repositories. Once
5746 This command is not intended for use on public repositories. Once
5747 changes are visible for pull by other users, rolling a transaction
5747 changes are visible for pull by other users, rolling a transaction
5748 back locally is ineffective (someone else may already have pulled
5748 back locally is ineffective (someone else may already have pulled
5749 the changes). Furthermore, a race is possible with readers of the
5749 the changes). Furthermore, a race is possible with readers of the
5750 repository; for example an in-progress pull from the repository
5750 repository; for example an in-progress pull from the repository
5751 may fail if a rollback is performed.
5751 may fail if a rollback is performed.
5752
5752
5753 Returns 0 on success, 1 if no rollback data is available.
5753 Returns 0 on success, 1 if no rollback data is available.
5754 """
5754 """
5755 return repo.rollback(dryrun=opts.get('dry_run'),
5755 return repo.rollback(dryrun=opts.get('dry_run'),
5756 force=opts.get('force'))
5756 force=opts.get('force'))
5757
5757
5758 @command('root', [])
5758 @command('root', [])
5759 def root(ui, repo):
5759 def root(ui, repo):
5760 """print the root (top) of the current working directory
5760 """print the root (top) of the current working directory
5761
5761
5762 Print the root directory of the current repository.
5762 Print the root directory of the current repository.
5763
5763
5764 Returns 0 on success.
5764 Returns 0 on success.
5765 """
5765 """
5766 ui.write(repo.root + "\n")
5766 ui.write(repo.root + "\n")
5767
5767
5768 @command('^serve',
5768 @command('^serve',
5769 [('A', 'accesslog', '', _('name of access log file to write to'),
5769 [('A', 'accesslog', '', _('name of access log file to write to'),
5770 _('FILE')),
5770 _('FILE')),
5771 ('d', 'daemon', None, _('run server in background')),
5771 ('d', 'daemon', None, _('run server in background')),
5772 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5772 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5773 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5773 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5774 # use string type, then we can check if something was passed
5774 # use string type, then we can check if something was passed
5775 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5775 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5776 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5776 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5777 _('ADDR')),
5777 _('ADDR')),
5778 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5778 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5779 _('PREFIX')),
5779 _('PREFIX')),
5780 ('n', 'name', '',
5780 ('n', 'name', '',
5781 _('name to show in web pages (default: working directory)'), _('NAME')),
5781 _('name to show in web pages (default: working directory)'), _('NAME')),
5782 ('', 'web-conf', '',
5782 ('', 'web-conf', '',
5783 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5783 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5784 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5784 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5785 _('FILE')),
5785 _('FILE')),
5786 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5786 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5787 ('', 'stdio', None, _('for remote clients')),
5787 ('', 'stdio', None, _('for remote clients')),
5788 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5788 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5789 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5789 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5790 ('', 'style', '', _('template style to use'), _('STYLE')),
5790 ('', 'style', '', _('template style to use'), _('STYLE')),
5791 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5791 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5792 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5792 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5793 _('[OPTION]...'),
5793 _('[OPTION]...'),
5794 optionalrepo=True)
5794 optionalrepo=True)
5795 def serve(ui, repo, **opts):
5795 def serve(ui, repo, **opts):
5796 """start stand-alone webserver
5796 """start stand-alone webserver
5797
5797
5798 Start a local HTTP repository browser and pull server. You can use
5798 Start a local HTTP repository browser and pull server. You can use
5799 this for ad-hoc sharing and browsing of repositories. It is
5799 this for ad-hoc sharing and browsing of repositories. It is
5800 recommended to use a real web server to serve a repository for
5800 recommended to use a real web server to serve a repository for
5801 longer periods of time.
5801 longer periods of time.
5802
5802
5803 Please note that the server does not implement access control.
5803 Please note that the server does not implement access control.
5804 This means that, by default, anybody can read from the server and
5804 This means that, by default, anybody can read from the server and
5805 nobody can write to it by default. Set the ``web.allow_push``
5805 nobody can write to it by default. Set the ``web.allow_push``
5806 option to ``*`` to allow everybody to push to the server. You
5806 option to ``*`` to allow everybody to push to the server. You
5807 should use a real web server if you need to authenticate users.
5807 should use a real web server if you need to authenticate users.
5808
5808
5809 By default, the server logs accesses to stdout and errors to
5809 By default, the server logs accesses to stdout and errors to
5810 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5810 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5811 files.
5811 files.
5812
5812
5813 To have the server choose a free port number to listen on, specify
5813 To have the server choose a free port number to listen on, specify
5814 a port number of 0; in this case, the server will print the port
5814 a port number of 0; in this case, the server will print the port
5815 number it uses.
5815 number it uses.
5816
5816
5817 Returns 0 on success.
5817 Returns 0 on success.
5818 """
5818 """
5819
5819
5820 if opts["stdio"] and opts["cmdserver"]:
5820 if opts["stdio"] and opts["cmdserver"]:
5821 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5821 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5822
5822
5823 if opts["stdio"]:
5823 if opts["stdio"]:
5824 if repo is None:
5824 if repo is None:
5825 raise error.RepoError(_("there is no Mercurial repository here"
5825 raise error.RepoError(_("there is no Mercurial repository here"
5826 " (.hg not found)"))
5826 " (.hg not found)"))
5827 s = sshserver.sshserver(ui, repo)
5827 s = sshserver.sshserver(ui, repo)
5828 s.serve_forever()
5828 s.serve_forever()
5829
5829
5830 if opts["cmdserver"]:
5830 if opts["cmdserver"]:
5831 import commandserver
5831 import commandserver
5832 service = commandserver.createservice(ui, repo, opts)
5832 service = commandserver.createservice(ui, repo, opts)
5833 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5833 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5834
5834
5835 # this way we can check if something was given in the command-line
5835 # this way we can check if something was given in the command-line
5836 if opts.get('port'):
5836 if opts.get('port'):
5837 opts['port'] = util.getport(opts.get('port'))
5837 opts['port'] = util.getport(opts.get('port'))
5838
5838
5839 if repo:
5839 if repo:
5840 baseui = repo.baseui
5840 baseui = repo.baseui
5841 else:
5841 else:
5842 baseui = ui
5842 baseui = ui
5843 optlist = ("name templates style address port prefix ipv6"
5843 optlist = ("name templates style address port prefix ipv6"
5844 " accesslog errorlog certificate encoding")
5844 " accesslog errorlog certificate encoding")
5845 for o in optlist.split():
5845 for o in optlist.split():
5846 val = opts.get(o, '')
5846 val = opts.get(o, '')
5847 if val in (None, ''): # should check against default options instead
5847 if val in (None, ''): # should check against default options instead
5848 continue
5848 continue
5849 baseui.setconfig("web", o, val, 'serve')
5849 baseui.setconfig("web", o, val, 'serve')
5850 if repo and repo.ui != baseui:
5850 if repo and repo.ui != baseui:
5851 repo.ui.setconfig("web", o, val, 'serve')
5851 repo.ui.setconfig("web", o, val, 'serve')
5852
5852
5853 o = opts.get('web_conf') or opts.get('webdir_conf')
5853 o = opts.get('web_conf') or opts.get('webdir_conf')
5854 if not o:
5854 if not o:
5855 if not repo:
5855 if not repo:
5856 raise error.RepoError(_("there is no Mercurial repository"
5856 raise error.RepoError(_("there is no Mercurial repository"
5857 " here (.hg not found)"))
5857 " here (.hg not found)"))
5858 o = repo
5858 o = repo
5859
5859
5860 app = hgweb.hgweb(o, baseui=baseui)
5860 app = hgweb.hgweb(o, baseui=baseui)
5861 service = httpservice(ui, app, opts)
5861 service = httpservice(ui, app, opts)
5862 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5862 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5863
5863
5864 class httpservice(object):
5864 class httpservice(object):
5865 def __init__(self, ui, app, opts):
5865 def __init__(self, ui, app, opts):
5866 self.ui = ui
5866 self.ui = ui
5867 self.app = app
5867 self.app = app
5868 self.opts = opts
5868 self.opts = opts
5869
5869
5870 def init(self):
5870 def init(self):
5871 util.setsignalhandler()
5871 util.setsignalhandler()
5872 self.httpd = hgweb_server.create_server(self.ui, self.app)
5872 self.httpd = hgweb_server.create_server(self.ui, self.app)
5873
5873
5874 if self.opts['port'] and not self.ui.verbose:
5874 if self.opts['port'] and not self.ui.verbose:
5875 return
5875 return
5876
5876
5877 if self.httpd.prefix:
5877 if self.httpd.prefix:
5878 prefix = self.httpd.prefix.strip('/') + '/'
5878 prefix = self.httpd.prefix.strip('/') + '/'
5879 else:
5879 else:
5880 prefix = ''
5880 prefix = ''
5881
5881
5882 port = ':%d' % self.httpd.port
5882 port = ':%d' % self.httpd.port
5883 if port == ':80':
5883 if port == ':80':
5884 port = ''
5884 port = ''
5885
5885
5886 bindaddr = self.httpd.addr
5886 bindaddr = self.httpd.addr
5887 if bindaddr == '0.0.0.0':
5887 if bindaddr == '0.0.0.0':
5888 bindaddr = '*'
5888 bindaddr = '*'
5889 elif ':' in bindaddr: # IPv6
5889 elif ':' in bindaddr: # IPv6
5890 bindaddr = '[%s]' % bindaddr
5890 bindaddr = '[%s]' % bindaddr
5891
5891
5892 fqaddr = self.httpd.fqaddr
5892 fqaddr = self.httpd.fqaddr
5893 if ':' in fqaddr:
5893 if ':' in fqaddr:
5894 fqaddr = '[%s]' % fqaddr
5894 fqaddr = '[%s]' % fqaddr
5895 if self.opts['port']:
5895 if self.opts['port']:
5896 write = self.ui.status
5896 write = self.ui.status
5897 else:
5897 else:
5898 write = self.ui.write
5898 write = self.ui.write
5899 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5899 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5900 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5900 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5901 self.ui.flush() # avoid buffering of status message
5901 self.ui.flush() # avoid buffering of status message
5902
5902
5903 def run(self):
5903 def run(self):
5904 self.httpd.serve_forever()
5904 self.httpd.serve_forever()
5905
5905
5906
5906
5907 @command('^status|st',
5907 @command('^status|st',
5908 [('A', 'all', None, _('show status of all files')),
5908 [('A', 'all', None, _('show status of all files')),
5909 ('m', 'modified', None, _('show only modified files')),
5909 ('m', 'modified', None, _('show only modified files')),
5910 ('a', 'added', None, _('show only added files')),
5910 ('a', 'added', None, _('show only added files')),
5911 ('r', 'removed', None, _('show only removed files')),
5911 ('r', 'removed', None, _('show only removed files')),
5912 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5912 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5913 ('c', 'clean', None, _('show only files without changes')),
5913 ('c', 'clean', None, _('show only files without changes')),
5914 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5914 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5915 ('i', 'ignored', None, _('show only ignored files')),
5915 ('i', 'ignored', None, _('show only ignored files')),
5916 ('n', 'no-status', None, _('hide status prefix')),
5916 ('n', 'no-status', None, _('hide status prefix')),
5917 ('C', 'copies', None, _('show source of copied files')),
5917 ('C', 'copies', None, _('show source of copied files')),
5918 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5918 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5919 ('', 'rev', [], _('show difference from revision'), _('REV')),
5919 ('', 'rev', [], _('show difference from revision'), _('REV')),
5920 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5920 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5921 ] + walkopts + subrepoopts + formatteropts,
5921 ] + walkopts + subrepoopts + formatteropts,
5922 _('[OPTION]... [FILE]...'),
5922 _('[OPTION]... [FILE]...'),
5923 inferrepo=True)
5923 inferrepo=True)
5924 def status(ui, repo, *pats, **opts):
5924 def status(ui, repo, *pats, **opts):
5925 """show changed files in the working directory
5925 """show changed files in the working directory
5926
5926
5927 Show status of files in the repository. If names are given, only
5927 Show status of files in the repository. If names are given, only
5928 files that match are shown. Files that are clean or ignored or
5928 files that match are shown. Files that are clean or ignored or
5929 the source of a copy/move operation, are not listed unless
5929 the source of a copy/move operation, are not listed unless
5930 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5930 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5931 Unless options described with "show only ..." are given, the
5931 Unless options described with "show only ..." are given, the
5932 options -mardu are used.
5932 options -mardu are used.
5933
5933
5934 Option -q/--quiet hides untracked (unknown and ignored) files
5934 Option -q/--quiet hides untracked (unknown and ignored) files
5935 unless explicitly requested with -u/--unknown or -i/--ignored.
5935 unless explicitly requested with -u/--unknown or -i/--ignored.
5936
5936
5937 .. note::
5937 .. note::
5938
5938
5939 status may appear to disagree with diff if permissions have
5939 status may appear to disagree with diff if permissions have
5940 changed or a merge has occurred. The standard diff format does
5940 changed or a merge has occurred. The standard diff format does
5941 not report permission changes and diff only reports changes
5941 not report permission changes and diff only reports changes
5942 relative to one merge parent.
5942 relative to one merge parent.
5943
5943
5944 If one revision is given, it is used as the base revision.
5944 If one revision is given, it is used as the base revision.
5945 If two revisions are given, the differences between them are
5945 If two revisions are given, the differences between them are
5946 shown. The --change option can also be used as a shortcut to list
5946 shown. The --change option can also be used as a shortcut to list
5947 the changed files of a revision from its first parent.
5947 the changed files of a revision from its first parent.
5948
5948
5949 The codes used to show the status of files are::
5949 The codes used to show the status of files are::
5950
5950
5951 M = modified
5951 M = modified
5952 A = added
5952 A = added
5953 R = removed
5953 R = removed
5954 C = clean
5954 C = clean
5955 ! = missing (deleted by non-hg command, but still tracked)
5955 ! = missing (deleted by non-hg command, but still tracked)
5956 ? = not tracked
5956 ? = not tracked
5957 I = ignored
5957 I = ignored
5958 = origin of the previous file (with --copies)
5958 = origin of the previous file (with --copies)
5959
5959
5960 .. container:: verbose
5960 .. container:: verbose
5961
5961
5962 Examples:
5962 Examples:
5963
5963
5964 - show changes in the working directory relative to a
5964 - show changes in the working directory relative to a
5965 changeset::
5965 changeset::
5966
5966
5967 hg status --rev 9353
5967 hg status --rev 9353
5968
5968
5969 - show changes in the working directory relative to the
5969 - show changes in the working directory relative to the
5970 current directory (see :hg:`help patterns` for more information)::
5970 current directory (see :hg:`help patterns` for more information)::
5971
5971
5972 hg status re:
5972 hg status re:
5973
5973
5974 - show all changes including copies in an existing changeset::
5974 - show all changes including copies in an existing changeset::
5975
5975
5976 hg status --copies --change 9353
5976 hg status --copies --change 9353
5977
5977
5978 - get a NUL separated list of added files, suitable for xargs::
5978 - get a NUL separated list of added files, suitable for xargs::
5979
5979
5980 hg status -an0
5980 hg status -an0
5981
5981
5982 Returns 0 on success.
5982 Returns 0 on success.
5983 """
5983 """
5984
5984
5985 revs = opts.get('rev')
5985 revs = opts.get('rev')
5986 change = opts.get('change')
5986 change = opts.get('change')
5987
5987
5988 if revs and change:
5988 if revs and change:
5989 msg = _('cannot specify --rev and --change at the same time')
5989 msg = _('cannot specify --rev and --change at the same time')
5990 raise error.Abort(msg)
5990 raise error.Abort(msg)
5991 elif change:
5991 elif change:
5992 node2 = scmutil.revsingle(repo, change, None).node()
5992 node2 = scmutil.revsingle(repo, change, None).node()
5993 node1 = repo[node2].p1().node()
5993 node1 = repo[node2].p1().node()
5994 else:
5994 else:
5995 node1, node2 = scmutil.revpair(repo, revs)
5995 node1, node2 = scmutil.revpair(repo, revs)
5996
5996
5997 if pats:
5997 if pats:
5998 cwd = repo.getcwd()
5998 cwd = repo.getcwd()
5999 else:
5999 else:
6000 cwd = ''
6000 cwd = ''
6001
6001
6002 if opts.get('print0'):
6002 if opts.get('print0'):
6003 end = '\0'
6003 end = '\0'
6004 else:
6004 else:
6005 end = '\n'
6005 end = '\n'
6006 copy = {}
6006 copy = {}
6007 states = 'modified added removed deleted unknown ignored clean'.split()
6007 states = 'modified added removed deleted unknown ignored clean'.split()
6008 show = [k for k in states if opts.get(k)]
6008 show = [k for k in states if opts.get(k)]
6009 if opts.get('all'):
6009 if opts.get('all'):
6010 show += ui.quiet and (states[:4] + ['clean']) or states
6010 show += ui.quiet and (states[:4] + ['clean']) or states
6011 if not show:
6011 if not show:
6012 if ui.quiet:
6012 if ui.quiet:
6013 show = states[:4]
6013 show = states[:4]
6014 else:
6014 else:
6015 show = states[:5]
6015 show = states[:5]
6016
6016
6017 m = scmutil.match(repo[node2], pats, opts)
6017 m = scmutil.match(repo[node2], pats, opts)
6018 stat = repo.status(node1, node2, m,
6018 stat = repo.status(node1, node2, m,
6019 'ignored' in show, 'clean' in show, 'unknown' in show,
6019 'ignored' in show, 'clean' in show, 'unknown' in show,
6020 opts.get('subrepos'))
6020 opts.get('subrepos'))
6021 changestates = zip(states, 'MAR!?IC', stat)
6021 changestates = zip(states, 'MAR!?IC', stat)
6022
6022
6023 if (opts.get('all') or opts.get('copies')
6023 if (opts.get('all') or opts.get('copies')
6024 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6024 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6025 copy = copies.pathcopies(repo[node1], repo[node2], m)
6025 copy = copies.pathcopies(repo[node1], repo[node2], m)
6026
6026
6027 fm = ui.formatter('status', opts)
6027 fm = ui.formatter('status', opts)
6028 fmt = '%s' + end
6028 fmt = '%s' + end
6029 showchar = not opts.get('no_status')
6029 showchar = not opts.get('no_status')
6030
6030
6031 for state, char, files in changestates:
6031 for state, char, files in changestates:
6032 if state in show:
6032 if state in show:
6033 label = 'status.' + state
6033 label = 'status.' + state
6034 for f in files:
6034 for f in files:
6035 fm.startitem()
6035 fm.startitem()
6036 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6036 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6037 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6037 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6038 if f in copy:
6038 if f in copy:
6039 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6039 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6040 label='status.copied')
6040 label='status.copied')
6041 fm.end()
6041 fm.end()
6042
6042
6043 @command('^summary|sum',
6043 @command('^summary|sum',
6044 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6044 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6045 def summary(ui, repo, **opts):
6045 def summary(ui, repo, **opts):
6046 """summarize working directory state
6046 """summarize working directory state
6047
6047
6048 This generates a brief summary of the working directory state,
6048 This generates a brief summary of the working directory state,
6049 including parents, branch, commit status, phase and available updates.
6049 including parents, branch, commit status, phase and available updates.
6050
6050
6051 With the --remote option, this will check the default paths for
6051 With the --remote option, this will check the default paths for
6052 incoming and outgoing changes. This can be time-consuming.
6052 incoming and outgoing changes. This can be time-consuming.
6053
6053
6054 Returns 0 on success.
6054 Returns 0 on success.
6055 """
6055 """
6056
6056
6057 ctx = repo[None]
6057 ctx = repo[None]
6058 parents = ctx.parents()
6058 parents = ctx.parents()
6059 pnode = parents[0].node()
6059 pnode = parents[0].node()
6060 marks = []
6060 marks = []
6061
6061
6062 for p in parents:
6062 for p in parents:
6063 # label with log.changeset (instead of log.parent) since this
6063 # label with log.changeset (instead of log.parent) since this
6064 # shows a working directory parent *changeset*:
6064 # shows a working directory parent *changeset*:
6065 # i18n: column positioning for "hg summary"
6065 # i18n: column positioning for "hg summary"
6066 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6066 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6067 label='log.changeset changeset.%s' % p.phasestr())
6067 label='log.changeset changeset.%s' % p.phasestr())
6068 ui.write(' '.join(p.tags()), label='log.tag')
6068 ui.write(' '.join(p.tags()), label='log.tag')
6069 if p.bookmarks():
6069 if p.bookmarks():
6070 marks.extend(p.bookmarks())
6070 marks.extend(p.bookmarks())
6071 if p.rev() == -1:
6071 if p.rev() == -1:
6072 if not len(repo):
6072 if not len(repo):
6073 ui.write(_(' (empty repository)'))
6073 ui.write(_(' (empty repository)'))
6074 else:
6074 else:
6075 ui.write(_(' (no revision checked out)'))
6075 ui.write(_(' (no revision checked out)'))
6076 ui.write('\n')
6076 ui.write('\n')
6077 if p.description():
6077 if p.description():
6078 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6078 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6079 label='log.summary')
6079 label='log.summary')
6080
6080
6081 branch = ctx.branch()
6081 branch = ctx.branch()
6082 bheads = repo.branchheads(branch)
6082 bheads = repo.branchheads(branch)
6083 # i18n: column positioning for "hg summary"
6083 # i18n: column positioning for "hg summary"
6084 m = _('branch: %s\n') % branch
6084 m = _('branch: %s\n') % branch
6085 if branch != 'default':
6085 if branch != 'default':
6086 ui.write(m, label='log.branch')
6086 ui.write(m, label='log.branch')
6087 else:
6087 else:
6088 ui.status(m, label='log.branch')
6088 ui.status(m, label='log.branch')
6089
6089
6090 if marks:
6090 if marks:
6091 active = repo._activebookmark
6091 active = repo._activebookmark
6092 # i18n: column positioning for "hg summary"
6092 # i18n: column positioning for "hg summary"
6093 ui.write(_('bookmarks:'), label='log.bookmark')
6093 ui.write(_('bookmarks:'), label='log.bookmark')
6094 if active is not None:
6094 if active is not None:
6095 if active in marks:
6095 if active in marks:
6096 ui.write(' *' + active, label=activebookmarklabel)
6096 ui.write(' *' + active, label=activebookmarklabel)
6097 marks.remove(active)
6097 marks.remove(active)
6098 else:
6098 else:
6099 ui.write(' [%s]' % active, label=activebookmarklabel)
6099 ui.write(' [%s]' % active, label=activebookmarklabel)
6100 for m in marks:
6100 for m in marks:
6101 ui.write(' ' + m, label='log.bookmark')
6101 ui.write(' ' + m, label='log.bookmark')
6102 ui.write('\n', label='log.bookmark')
6102 ui.write('\n', label='log.bookmark')
6103
6103
6104 status = repo.status(unknown=True)
6104 status = repo.status(unknown=True)
6105
6105
6106 c = repo.dirstate.copies()
6106 c = repo.dirstate.copies()
6107 copied, renamed = [], []
6107 copied, renamed = [], []
6108 for d, s in c.iteritems():
6108 for d, s in c.iteritems():
6109 if s in status.removed:
6109 if s in status.removed:
6110 status.removed.remove(s)
6110 status.removed.remove(s)
6111 renamed.append(d)
6111 renamed.append(d)
6112 else:
6112 else:
6113 copied.append(d)
6113 copied.append(d)
6114 if d in status.added:
6114 if d in status.added:
6115 status.added.remove(d)
6115 status.added.remove(d)
6116
6116
6117 ms = mergemod.mergestate(repo)
6117 ms = mergemod.mergestate(repo)
6118 unresolved = [f for f in ms if ms[f] == 'u']
6118 unresolved = [f for f in ms if ms[f] == 'u']
6119
6119
6120 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6120 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6121
6121
6122 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6122 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6123 (ui.label(_('%d added'), 'status.added'), status.added),
6123 (ui.label(_('%d added'), 'status.added'), status.added),
6124 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6124 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6125 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6125 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6126 (ui.label(_('%d copied'), 'status.copied'), copied),
6126 (ui.label(_('%d copied'), 'status.copied'), copied),
6127 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6127 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6128 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6128 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6129 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6129 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6130 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6130 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6131 t = []
6131 t = []
6132 for l, s in labels:
6132 for l, s in labels:
6133 if s:
6133 if s:
6134 t.append(l % len(s))
6134 t.append(l % len(s))
6135
6135
6136 t = ', '.join(t)
6136 t = ', '.join(t)
6137 cleanworkdir = False
6137 cleanworkdir = False
6138
6138
6139 if repo.vfs.exists('updatestate'):
6139 if repo.vfs.exists('updatestate'):
6140 t += _(' (interrupted update)')
6140 t += _(' (interrupted update)')
6141 elif len(parents) > 1:
6141 elif len(parents) > 1:
6142 t += _(' (merge)')
6142 t += _(' (merge)')
6143 elif branch != parents[0].branch():
6143 elif branch != parents[0].branch():
6144 t += _(' (new branch)')
6144 t += _(' (new branch)')
6145 elif (parents[0].closesbranch() and
6145 elif (parents[0].closesbranch() and
6146 pnode in repo.branchheads(branch, closed=True)):
6146 pnode in repo.branchheads(branch, closed=True)):
6147 t += _(' (head closed)')
6147 t += _(' (head closed)')
6148 elif not (status.modified or status.added or status.removed or renamed or
6148 elif not (status.modified or status.added or status.removed or renamed or
6149 copied or subs):
6149 copied or subs):
6150 t += _(' (clean)')
6150 t += _(' (clean)')
6151 cleanworkdir = True
6151 cleanworkdir = True
6152 elif pnode not in bheads:
6152 elif pnode not in bheads:
6153 t += _(' (new branch head)')
6153 t += _(' (new branch head)')
6154
6154
6155 if parents:
6155 if parents:
6156 pendingphase = max(p.phase() for p in parents)
6156 pendingphase = max(p.phase() for p in parents)
6157 else:
6157 else:
6158 pendingphase = phases.public
6158 pendingphase = phases.public
6159
6159
6160 if pendingphase > phases.newcommitphase(ui):
6160 if pendingphase > phases.newcommitphase(ui):
6161 t += ' (%s)' % phases.phasenames[pendingphase]
6161 t += ' (%s)' % phases.phasenames[pendingphase]
6162
6162
6163 if cleanworkdir:
6163 if cleanworkdir:
6164 # i18n: column positioning for "hg summary"
6164 # i18n: column positioning for "hg summary"
6165 ui.status(_('commit: %s\n') % t.strip())
6165 ui.status(_('commit: %s\n') % t.strip())
6166 else:
6166 else:
6167 # i18n: column positioning for "hg summary"
6167 # i18n: column positioning for "hg summary"
6168 ui.write(_('commit: %s\n') % t.strip())
6168 ui.write(_('commit: %s\n') % t.strip())
6169
6169
6170 # all ancestors of branch heads - all ancestors of parent = new csets
6170 # all ancestors of branch heads - all ancestors of parent = new csets
6171 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6171 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6172 bheads))
6172 bheads))
6173
6173
6174 if new == 0:
6174 if new == 0:
6175 # i18n: column positioning for "hg summary"
6175 # i18n: column positioning for "hg summary"
6176 ui.status(_('update: (current)\n'))
6176 ui.status(_('update: (current)\n'))
6177 elif pnode not in bheads:
6177 elif pnode not in bheads:
6178 # i18n: column positioning for "hg summary"
6178 # i18n: column positioning for "hg summary"
6179 ui.write(_('update: %d new changesets (update)\n') % new)
6179 ui.write(_('update: %d new changesets (update)\n') % new)
6180 else:
6180 else:
6181 # i18n: column positioning for "hg summary"
6181 # i18n: column positioning for "hg summary"
6182 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6182 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6183 (new, len(bheads)))
6183 (new, len(bheads)))
6184
6184
6185 t = []
6185 t = []
6186 draft = len(repo.revs('draft()'))
6186 draft = len(repo.revs('draft()'))
6187 if draft:
6187 if draft:
6188 t.append(_('%d draft') % draft)
6188 t.append(_('%d draft') % draft)
6189 secret = len(repo.revs('secret()'))
6189 secret = len(repo.revs('secret()'))
6190 if secret:
6190 if secret:
6191 t.append(_('%d secret') % secret)
6191 t.append(_('%d secret') % secret)
6192
6192
6193 if draft or secret:
6193 if draft or secret:
6194 ui.status(_('phases: %s\n') % ', '.join(t))
6194 ui.status(_('phases: %s\n') % ', '.join(t))
6195
6195
6196 cmdutil.summaryhooks(ui, repo)
6196 cmdutil.summaryhooks(ui, repo)
6197
6197
6198 if opts.get('remote'):
6198 if opts.get('remote'):
6199 needsincoming, needsoutgoing = True, True
6199 needsincoming, needsoutgoing = True, True
6200 else:
6200 else:
6201 needsincoming, needsoutgoing = False, False
6201 needsincoming, needsoutgoing = False, False
6202 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6202 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6203 if i:
6203 if i:
6204 needsincoming = True
6204 needsincoming = True
6205 if o:
6205 if o:
6206 needsoutgoing = True
6206 needsoutgoing = True
6207 if not needsincoming and not needsoutgoing:
6207 if not needsincoming and not needsoutgoing:
6208 return
6208 return
6209
6209
6210 def getincoming():
6210 def getincoming():
6211 source, branches = hg.parseurl(ui.expandpath('default'))
6211 source, branches = hg.parseurl(ui.expandpath('default'))
6212 sbranch = branches[0]
6212 sbranch = branches[0]
6213 try:
6213 try:
6214 other = hg.peer(repo, {}, source)
6214 other = hg.peer(repo, {}, source)
6215 except error.RepoError:
6215 except error.RepoError:
6216 if opts.get('remote'):
6216 if opts.get('remote'):
6217 raise
6217 raise
6218 return source, sbranch, None, None, None
6218 return source, sbranch, None, None, None
6219 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6219 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6220 if revs:
6220 if revs:
6221 revs = [other.lookup(rev) for rev in revs]
6221 revs = [other.lookup(rev) for rev in revs]
6222 ui.debug('comparing with %s\n' % util.hidepassword(source))
6222 ui.debug('comparing with %s\n' % util.hidepassword(source))
6223 repo.ui.pushbuffer()
6223 repo.ui.pushbuffer()
6224 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6224 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6225 repo.ui.popbuffer()
6225 repo.ui.popbuffer()
6226 return source, sbranch, other, commoninc, commoninc[1]
6226 return source, sbranch, other, commoninc, commoninc[1]
6227
6227
6228 if needsincoming:
6228 if needsincoming:
6229 source, sbranch, sother, commoninc, incoming = getincoming()
6229 source, sbranch, sother, commoninc, incoming = getincoming()
6230 else:
6230 else:
6231 source = sbranch = sother = commoninc = incoming = None
6231 source = sbranch = sother = commoninc = incoming = None
6232
6232
6233 def getoutgoing():
6233 def getoutgoing():
6234 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6234 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6235 dbranch = branches[0]
6235 dbranch = branches[0]
6236 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6236 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6237 if source != dest:
6237 if source != dest:
6238 try:
6238 try:
6239 dother = hg.peer(repo, {}, dest)
6239 dother = hg.peer(repo, {}, dest)
6240 except error.RepoError:
6240 except error.RepoError:
6241 if opts.get('remote'):
6241 if opts.get('remote'):
6242 raise
6242 raise
6243 return dest, dbranch, None, None
6243 return dest, dbranch, None, None
6244 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6244 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6245 elif sother is None:
6245 elif sother is None:
6246 # there is no explicit destination peer, but source one is invalid
6246 # there is no explicit destination peer, but source one is invalid
6247 return dest, dbranch, None, None
6247 return dest, dbranch, None, None
6248 else:
6248 else:
6249 dother = sother
6249 dother = sother
6250 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6250 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6251 common = None
6251 common = None
6252 else:
6252 else:
6253 common = commoninc
6253 common = commoninc
6254 if revs:
6254 if revs:
6255 revs = [repo.lookup(rev) for rev in revs]
6255 revs = [repo.lookup(rev) for rev in revs]
6256 repo.ui.pushbuffer()
6256 repo.ui.pushbuffer()
6257 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6257 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6258 commoninc=common)
6258 commoninc=common)
6259 repo.ui.popbuffer()
6259 repo.ui.popbuffer()
6260 return dest, dbranch, dother, outgoing
6260 return dest, dbranch, dother, outgoing
6261
6261
6262 if needsoutgoing:
6262 if needsoutgoing:
6263 dest, dbranch, dother, outgoing = getoutgoing()
6263 dest, dbranch, dother, outgoing = getoutgoing()
6264 else:
6264 else:
6265 dest = dbranch = dother = outgoing = None
6265 dest = dbranch = dother = outgoing = None
6266
6266
6267 if opts.get('remote'):
6267 if opts.get('remote'):
6268 t = []
6268 t = []
6269 if incoming:
6269 if incoming:
6270 t.append(_('1 or more incoming'))
6270 t.append(_('1 or more incoming'))
6271 o = outgoing.missing
6271 o = outgoing.missing
6272 if o:
6272 if o:
6273 t.append(_('%d outgoing') % len(o))
6273 t.append(_('%d outgoing') % len(o))
6274 other = dother or sother
6274 other = dother or sother
6275 if 'bookmarks' in other.listkeys('namespaces'):
6275 if 'bookmarks' in other.listkeys('namespaces'):
6276 counts = bookmarks.summary(repo, other)
6276 counts = bookmarks.summary(repo, other)
6277 if counts[0] > 0:
6277 if counts[0] > 0:
6278 t.append(_('%d incoming bookmarks') % counts[0])
6278 t.append(_('%d incoming bookmarks') % counts[0])
6279 if counts[1] > 0:
6279 if counts[1] > 0:
6280 t.append(_('%d outgoing bookmarks') % counts[1])
6280 t.append(_('%d outgoing bookmarks') % counts[1])
6281
6281
6282 if t:
6282 if t:
6283 # i18n: column positioning for "hg summary"
6283 # i18n: column positioning for "hg summary"
6284 ui.write(_('remote: %s\n') % (', '.join(t)))
6284 ui.write(_('remote: %s\n') % (', '.join(t)))
6285 else:
6285 else:
6286 # i18n: column positioning for "hg summary"
6286 # i18n: column positioning for "hg summary"
6287 ui.status(_('remote: (synced)\n'))
6287 ui.status(_('remote: (synced)\n'))
6288
6288
6289 cmdutil.summaryremotehooks(ui, repo, opts,
6289 cmdutil.summaryremotehooks(ui, repo, opts,
6290 ((source, sbranch, sother, commoninc),
6290 ((source, sbranch, sother, commoninc),
6291 (dest, dbranch, dother, outgoing)))
6291 (dest, dbranch, dother, outgoing)))
6292
6292
6293 @command('tag',
6293 @command('tag',
6294 [('f', 'force', None, _('force tag')),
6294 [('f', 'force', None, _('force tag')),
6295 ('l', 'local', None, _('make the tag local')),
6295 ('l', 'local', None, _('make the tag local')),
6296 ('r', 'rev', '', _('revision to tag'), _('REV')),
6296 ('r', 'rev', '', _('revision to tag'), _('REV')),
6297 ('', 'remove', None, _('remove a tag')),
6297 ('', 'remove', None, _('remove a tag')),
6298 # -l/--local is already there, commitopts cannot be used
6298 # -l/--local is already there, commitopts cannot be used
6299 ('e', 'edit', None, _('invoke editor on commit messages')),
6299 ('e', 'edit', None, _('invoke editor on commit messages')),
6300 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6300 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6301 ] + commitopts2,
6301 ] + commitopts2,
6302 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6302 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6303 def tag(ui, repo, name1, *names, **opts):
6303 def tag(ui, repo, name1, *names, **opts):
6304 """add one or more tags for the current or given revision
6304 """add one or more tags for the current or given revision
6305
6305
6306 Name a particular revision using <name>.
6306 Name a particular revision using <name>.
6307
6307
6308 Tags are used to name particular revisions of the repository and are
6308 Tags are used to name particular revisions of the repository and are
6309 very useful to compare different revisions, to go back to significant
6309 very useful to compare different revisions, to go back to significant
6310 earlier versions or to mark branch points as releases, etc. Changing
6310 earlier versions or to mark branch points as releases, etc. Changing
6311 an existing tag is normally disallowed; use -f/--force to override.
6311 an existing tag is normally disallowed; use -f/--force to override.
6312
6312
6313 If no revision is given, the parent of the working directory is
6313 If no revision is given, the parent of the working directory is
6314 used.
6314 used.
6315
6315
6316 To facilitate version control, distribution, and merging of tags,
6316 To facilitate version control, distribution, and merging of tags,
6317 they are stored as a file named ".hgtags" which is managed similarly
6317 they are stored as a file named ".hgtags" which is managed similarly
6318 to other project files and can be hand-edited if necessary. This
6318 to other project files and can be hand-edited if necessary. This
6319 also means that tagging creates a new commit. The file
6319 also means that tagging creates a new commit. The file
6320 ".hg/localtags" is used for local tags (not shared among
6320 ".hg/localtags" is used for local tags (not shared among
6321 repositories).
6321 repositories).
6322
6322
6323 Tag commits are usually made at the head of a branch. If the parent
6323 Tag commits are usually made at the head of a branch. If the parent
6324 of the working directory is not a branch head, :hg:`tag` aborts; use
6324 of the working directory is not a branch head, :hg:`tag` aborts; use
6325 -f/--force to force the tag commit to be based on a non-head
6325 -f/--force to force the tag commit to be based on a non-head
6326 changeset.
6326 changeset.
6327
6327
6328 See :hg:`help dates` for a list of formats valid for -d/--date.
6328 See :hg:`help dates` for a list of formats valid for -d/--date.
6329
6329
6330 Since tag names have priority over branch names during revision
6330 Since tag names have priority over branch names during revision
6331 lookup, using an existing branch name as a tag name is discouraged.
6331 lookup, using an existing branch name as a tag name is discouraged.
6332
6332
6333 Returns 0 on success.
6333 Returns 0 on success.
6334 """
6334 """
6335 wlock = lock = None
6335 wlock = lock = None
6336 try:
6336 try:
6337 wlock = repo.wlock()
6337 wlock = repo.wlock()
6338 lock = repo.lock()
6338 lock = repo.lock()
6339 rev_ = "."
6339 rev_ = "."
6340 names = [t.strip() for t in (name1,) + names]
6340 names = [t.strip() for t in (name1,) + names]
6341 if len(names) != len(set(names)):
6341 if len(names) != len(set(names)):
6342 raise error.Abort(_('tag names must be unique'))
6342 raise error.Abort(_('tag names must be unique'))
6343 for n in names:
6343 for n in names:
6344 scmutil.checknewlabel(repo, n, 'tag')
6344 scmutil.checknewlabel(repo, n, 'tag')
6345 if not n:
6345 if not n:
6346 raise error.Abort(_('tag names cannot consist entirely of '
6346 raise error.Abort(_('tag names cannot consist entirely of '
6347 'whitespace'))
6347 'whitespace'))
6348 if opts.get('rev') and opts.get('remove'):
6348 if opts.get('rev') and opts.get('remove'):
6349 raise error.Abort(_("--rev and --remove are incompatible"))
6349 raise error.Abort(_("--rev and --remove are incompatible"))
6350 if opts.get('rev'):
6350 if opts.get('rev'):
6351 rev_ = opts['rev']
6351 rev_ = opts['rev']
6352 message = opts.get('message')
6352 message = opts.get('message')
6353 if opts.get('remove'):
6353 if opts.get('remove'):
6354 if opts.get('local'):
6354 if opts.get('local'):
6355 expectedtype = 'local'
6355 expectedtype = 'local'
6356 else:
6356 else:
6357 expectedtype = 'global'
6357 expectedtype = 'global'
6358
6358
6359 for n in names:
6359 for n in names:
6360 if not repo.tagtype(n):
6360 if not repo.tagtype(n):
6361 raise error.Abort(_("tag '%s' does not exist") % n)
6361 raise error.Abort(_("tag '%s' does not exist") % n)
6362 if repo.tagtype(n) != expectedtype:
6362 if repo.tagtype(n) != expectedtype:
6363 if expectedtype == 'global':
6363 if expectedtype == 'global':
6364 raise error.Abort(_("tag '%s' is not a global tag") % n)
6364 raise error.Abort(_("tag '%s' is not a global tag") % n)
6365 else:
6365 else:
6366 raise error.Abort(_("tag '%s' is not a local tag") % n)
6366 raise error.Abort(_("tag '%s' is not a local tag") % n)
6367 rev_ = 'null'
6367 rev_ = 'null'
6368 if not message:
6368 if not message:
6369 # we don't translate commit messages
6369 # we don't translate commit messages
6370 message = 'Removed tag %s' % ', '.join(names)
6370 message = 'Removed tag %s' % ', '.join(names)
6371 elif not opts.get('force'):
6371 elif not opts.get('force'):
6372 for n in names:
6372 for n in names:
6373 if n in repo.tags():
6373 if n in repo.tags():
6374 raise error.Abort(_("tag '%s' already exists "
6374 raise error.Abort(_("tag '%s' already exists "
6375 "(use -f to force)") % n)
6375 "(use -f to force)") % n)
6376 if not opts.get('local'):
6376 if not opts.get('local'):
6377 p1, p2 = repo.dirstate.parents()
6377 p1, p2 = repo.dirstate.parents()
6378 if p2 != nullid:
6378 if p2 != nullid:
6379 raise error.Abort(_('uncommitted merge'))
6379 raise error.Abort(_('uncommitted merge'))
6380 bheads = repo.branchheads()
6380 bheads = repo.branchheads()
6381 if not opts.get('force') and bheads and p1 not in bheads:
6381 if not opts.get('force') and bheads and p1 not in bheads:
6382 raise error.Abort(_('not at a branch head (use -f to force)'))
6382 raise error.Abort(_('not at a branch head (use -f to force)'))
6383 r = scmutil.revsingle(repo, rev_).node()
6383 r = scmutil.revsingle(repo, rev_).node()
6384
6384
6385 if not message:
6385 if not message:
6386 # we don't translate commit messages
6386 # we don't translate commit messages
6387 message = ('Added tag %s for changeset %s' %
6387 message = ('Added tag %s for changeset %s' %
6388 (', '.join(names), short(r)))
6388 (', '.join(names), short(r)))
6389
6389
6390 date = opts.get('date')
6390 date = opts.get('date')
6391 if date:
6391 if date:
6392 date = util.parsedate(date)
6392 date = util.parsedate(date)
6393
6393
6394 if opts.get('remove'):
6394 if opts.get('remove'):
6395 editform = 'tag.remove'
6395 editform = 'tag.remove'
6396 else:
6396 else:
6397 editform = 'tag.add'
6397 editform = 'tag.add'
6398 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6398 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6399
6399
6400 # don't allow tagging the null rev
6400 # don't allow tagging the null rev
6401 if (not opts.get('remove') and
6401 if (not opts.get('remove') and
6402 scmutil.revsingle(repo, rev_).rev() == nullrev):
6402 scmutil.revsingle(repo, rev_).rev() == nullrev):
6403 raise error.Abort(_("cannot tag null revision"))
6403 raise error.Abort(_("cannot tag null revision"))
6404
6404
6405 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6405 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6406 editor=editor)
6406 editor=editor)
6407 finally:
6407 finally:
6408 release(lock, wlock)
6408 release(lock, wlock)
6409
6409
6410 @command('tags', formatteropts, '')
6410 @command('tags', formatteropts, '')
6411 def tags(ui, repo, **opts):
6411 def tags(ui, repo, **opts):
6412 """list repository tags
6412 """list repository tags
6413
6413
6414 This lists both regular and local tags. When the -v/--verbose
6414 This lists both regular and local tags. When the -v/--verbose
6415 switch is used, a third column "local" is printed for local tags.
6415 switch is used, a third column "local" is printed for local tags.
6416
6416
6417 Returns 0 on success.
6417 Returns 0 on success.
6418 """
6418 """
6419
6419
6420 fm = ui.formatter('tags', opts)
6420 fm = ui.formatter('tags', opts)
6421 hexfunc = fm.hexfunc
6421 hexfunc = fm.hexfunc
6422 tagtype = ""
6422 tagtype = ""
6423
6423
6424 for t, n in reversed(repo.tagslist()):
6424 for t, n in reversed(repo.tagslist()):
6425 hn = hexfunc(n)
6425 hn = hexfunc(n)
6426 label = 'tags.normal'
6426 label = 'tags.normal'
6427 tagtype = ''
6427 tagtype = ''
6428 if repo.tagtype(t) == 'local':
6428 if repo.tagtype(t) == 'local':
6429 label = 'tags.local'
6429 label = 'tags.local'
6430 tagtype = 'local'
6430 tagtype = 'local'
6431
6431
6432 fm.startitem()
6432 fm.startitem()
6433 fm.write('tag', '%s', t, label=label)
6433 fm.write('tag', '%s', t, label=label)
6434 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6434 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6435 fm.condwrite(not ui.quiet, 'rev node', fmt,
6435 fm.condwrite(not ui.quiet, 'rev node', fmt,
6436 repo.changelog.rev(n), hn, label=label)
6436 repo.changelog.rev(n), hn, label=label)
6437 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6437 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6438 tagtype, label=label)
6438 tagtype, label=label)
6439 fm.plain('\n')
6439 fm.plain('\n')
6440 fm.end()
6440 fm.end()
6441
6441
6442 @command('tip',
6442 @command('tip',
6443 [('p', 'patch', None, _('show patch')),
6443 [('p', 'patch', None, _('show patch')),
6444 ('g', 'git', None, _('use git extended diff format')),
6444 ('g', 'git', None, _('use git extended diff format')),
6445 ] + templateopts,
6445 ] + templateopts,
6446 _('[-p] [-g]'))
6446 _('[-p] [-g]'))
6447 def tip(ui, repo, **opts):
6447 def tip(ui, repo, **opts):
6448 """show the tip revision (DEPRECATED)
6448 """show the tip revision (DEPRECATED)
6449
6449
6450 The tip revision (usually just called the tip) is the changeset
6450 The tip revision (usually just called the tip) is the changeset
6451 most recently added to the repository (and therefore the most
6451 most recently added to the repository (and therefore the most
6452 recently changed head).
6452 recently changed head).
6453
6453
6454 If you have just made a commit, that commit will be the tip. If
6454 If you have just made a commit, that commit will be the tip. If
6455 you have just pulled changes from another repository, the tip of
6455 you have just pulled changes from another repository, the tip of
6456 that repository becomes the current tip. The "tip" tag is special
6456 that repository becomes the current tip. The "tip" tag is special
6457 and cannot be renamed or assigned to a different changeset.
6457 and cannot be renamed or assigned to a different changeset.
6458
6458
6459 This command is deprecated, please use :hg:`heads` instead.
6459 This command is deprecated, please use :hg:`heads` instead.
6460
6460
6461 Returns 0 on success.
6461 Returns 0 on success.
6462 """
6462 """
6463 displayer = cmdutil.show_changeset(ui, repo, opts)
6463 displayer = cmdutil.show_changeset(ui, repo, opts)
6464 displayer.show(repo['tip'])
6464 displayer.show(repo['tip'])
6465 displayer.close()
6465 displayer.close()
6466
6466
6467 @command('unbundle',
6467 @command('unbundle',
6468 [('u', 'update', None,
6468 [('u', 'update', None,
6469 _('update to new branch head if changesets were unbundled'))],
6469 _('update to new branch head if changesets were unbundled'))],
6470 _('[-u] FILE...'))
6470 _('[-u] FILE...'))
6471 def unbundle(ui, repo, fname1, *fnames, **opts):
6471 def unbundle(ui, repo, fname1, *fnames, **opts):
6472 """apply one or more changegroup files
6472 """apply one or more changegroup files
6473
6473
6474 Apply one or more compressed changegroup files generated by the
6474 Apply one or more compressed changegroup files generated by the
6475 bundle command.
6475 bundle command.
6476
6476
6477 Returns 0 on success, 1 if an update has unresolved files.
6477 Returns 0 on success, 1 if an update has unresolved files.
6478 """
6478 """
6479 fnames = (fname1,) + fnames
6479 fnames = (fname1,) + fnames
6480
6480
6481 lock = repo.lock()
6481 lock = repo.lock()
6482 try:
6482 try:
6483 for fname in fnames:
6483 for fname in fnames:
6484 f = hg.openpath(ui, fname)
6484 f = hg.openpath(ui, fname)
6485 gen = exchange.readbundle(ui, f, fname)
6485 gen = exchange.readbundle(ui, f, fname)
6486 if isinstance(gen, bundle2.unbundle20):
6486 if isinstance(gen, bundle2.unbundle20):
6487 tr = repo.transaction('unbundle')
6487 tr = repo.transaction('unbundle')
6488 try:
6488 try:
6489 op = bundle2.processbundle(repo, gen, lambda: tr)
6489 op = bundle2.processbundle(repo, gen, lambda: tr)
6490 tr.close()
6490 tr.close()
6491 except error.BundleUnknownFeatureError as exc:
6491 except error.BundleUnknownFeatureError as exc:
6492 raise error.Abort(_('%s: unknown bundle feature, %s')
6492 raise error.Abort(_('%s: unknown bundle feature, %s')
6493 % (fname, exc),
6493 % (fname, exc),
6494 hint=_("see https://mercurial-scm.org/"
6494 hint=_("see https://mercurial-scm.org/"
6495 "wiki/BundleFeature for more "
6495 "wiki/BundleFeature for more "
6496 "information"))
6496 "information"))
6497 finally:
6497 finally:
6498 if tr:
6498 if tr:
6499 tr.release()
6499 tr.release()
6500 changes = [r.get('return', 0)
6500 changes = [r.get('return', 0)
6501 for r in op.records['changegroup']]
6501 for r in op.records['changegroup']]
6502 modheads = changegroup.combineresults(changes)
6502 modheads = changegroup.combineresults(changes)
6503 else:
6503 else:
6504 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6504 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6505 'bundle:' + fname)
6505 'bundle:' + fname)
6506 finally:
6506 finally:
6507 lock.release()
6507 lock.release()
6508
6508
6509 return postincoming(ui, repo, modheads, opts.get('update'), None)
6509 return postincoming(ui, repo, modheads, opts.get('update'), None)
6510
6510
6511 @command('^update|up|checkout|co',
6511 @command('^update|up|checkout|co',
6512 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6512 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6513 ('c', 'check', None,
6513 ('c', 'check', None,
6514 _('update across branches if no uncommitted changes')),
6514 _('update across branches if no uncommitted changes')),
6515 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6515 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6516 ('r', 'rev', '', _('revision'), _('REV'))
6516 ('r', 'rev', '', _('revision'), _('REV'))
6517 ] + mergetoolopts,
6517 ] + mergetoolopts,
6518 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6518 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6519 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6519 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6520 tool=None):
6520 tool=None):
6521 """update working directory (or switch revisions)
6521 """update working directory (or switch revisions)
6522
6522
6523 Update the repository's working directory to the specified
6523 Update the repository's working directory to the specified
6524 changeset. If no changeset is specified, update to the tip of the
6524 changeset. If no changeset is specified, update to the tip of the
6525 current named branch and move the active bookmark (see :hg:`help
6525 current named branch and move the active bookmark (see :hg:`help
6526 bookmarks`).
6526 bookmarks`).
6527
6527
6528 Update sets the working directory's parent revision to the specified
6528 Update sets the working directory's parent revision to the specified
6529 changeset (see :hg:`help parents`).
6529 changeset (see :hg:`help parents`).
6530
6530
6531 If the changeset is not a descendant or ancestor of the working
6531 If the changeset is not a descendant or ancestor of the working
6532 directory's parent, the update is aborted. With the -c/--check
6532 directory's parent, the update is aborted. With the -c/--check
6533 option, the working directory is checked for uncommitted changes; if
6533 option, the working directory is checked for uncommitted changes; if
6534 none are found, the working directory is updated to the specified
6534 none are found, the working directory is updated to the specified
6535 changeset.
6535 changeset.
6536
6536
6537 .. container:: verbose
6537 .. container:: verbose
6538
6538
6539 The following rules apply when the working directory contains
6539 The following rules apply when the working directory contains
6540 uncommitted changes:
6540 uncommitted changes:
6541
6541
6542 1. If neither -c/--check nor -C/--clean is specified, and if
6542 1. If neither -c/--check nor -C/--clean is specified, and if
6543 the requested changeset is an ancestor or descendant of
6543 the requested changeset is an ancestor or descendant of
6544 the working directory's parent, the uncommitted changes
6544 the working directory's parent, the uncommitted changes
6545 are merged into the requested changeset and the merged
6545 are merged into the requested changeset and the merged
6546 result is left uncommitted. If the requested changeset is
6546 result is left uncommitted. If the requested changeset is
6547 not an ancestor or descendant (that is, it is on another
6547 not an ancestor or descendant (that is, it is on another
6548 branch), the update is aborted and the uncommitted changes
6548 branch), the update is aborted and the uncommitted changes
6549 are preserved.
6549 are preserved.
6550
6550
6551 2. With the -c/--check option, the update is aborted and the
6551 2. With the -c/--check option, the update is aborted and the
6552 uncommitted changes are preserved.
6552 uncommitted changes are preserved.
6553
6553
6554 3. With the -C/--clean option, uncommitted changes are discarded and
6554 3. With the -C/--clean option, uncommitted changes are discarded and
6555 the working directory is updated to the requested changeset.
6555 the working directory is updated to the requested changeset.
6556
6556
6557 To cancel an uncommitted merge (and lose your changes), use
6557 To cancel an uncommitted merge (and lose your changes), use
6558 :hg:`update --clean .`.
6558 :hg:`update --clean .`.
6559
6559
6560 Use null as the changeset to remove the working directory (like
6560 Use null as the changeset to remove the working directory (like
6561 :hg:`clone -U`).
6561 :hg:`clone -U`).
6562
6562
6563 If you want to revert just one file to an older revision, use
6563 If you want to revert just one file to an older revision, use
6564 :hg:`revert [-r REV] NAME`.
6564 :hg:`revert [-r REV] NAME`.
6565
6565
6566 See :hg:`help dates` for a list of formats valid for -d/--date.
6566 See :hg:`help dates` for a list of formats valid for -d/--date.
6567
6567
6568 Returns 0 on success, 1 if there are unresolved files.
6568 Returns 0 on success, 1 if there are unresolved files.
6569 """
6569 """
6570 if rev and node:
6570 if rev and node:
6571 raise error.Abort(_("please specify just one revision"))
6571 raise error.Abort(_("please specify just one revision"))
6572
6572
6573 if rev is None or rev == '':
6573 if rev is None or rev == '':
6574 rev = node
6574 rev = node
6575
6575
6576 wlock = repo.wlock()
6576 wlock = repo.wlock()
6577 try:
6577 try:
6578 cmdutil.clearunfinished(repo)
6578 cmdutil.clearunfinished(repo)
6579
6579
6580 if date:
6580 if date:
6581 if rev is not None:
6581 if rev is not None:
6582 raise error.Abort(_("you can't specify a revision and a date"))
6582 raise error.Abort(_("you can't specify a revision and a date"))
6583 rev = cmdutil.finddate(ui, repo, date)
6583 rev = cmdutil.finddate(ui, repo, date)
6584
6584
6585 # with no argument, we also move the active bookmark, if any
6585 # with no argument, we also move the active bookmark, if any
6586 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6586 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6587
6587
6588 # if we defined a bookmark, we have to remember the original name
6588 # if we defined a bookmark, we have to remember the original name
6589 brev = rev
6589 brev = rev
6590 rev = scmutil.revsingle(repo, rev, rev).rev()
6590 rev = scmutil.revsingle(repo, rev, rev).rev()
6591
6591
6592 if check and clean:
6592 if check and clean:
6593 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6593 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6594 )
6594 )
6595
6595
6596 if check:
6596 if check:
6597 cmdutil.bailifchanged(repo, merge=False)
6597 cmdutil.bailifchanged(repo, merge=False)
6598 if rev is None:
6598 if rev is None:
6599 rev = repo[repo[None].branch()].rev()
6599 rev = repo[repo[None].branch()].rev()
6600 elif rev is None:
6601 rev = destutil.destupdate(repo, clean=clean)
6600
6602
6601 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6603 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6602
6604
6603 if clean:
6605 if clean:
6604 ret = hg.clean(repo, rev)
6606 ret = hg.clean(repo, rev)
6605 else:
6607 else:
6606 ret = hg.update(repo, rev)
6608 ret = hg.update(repo, rev)
6607
6609
6608 if not ret and movemarkfrom:
6610 if not ret and movemarkfrom:
6609 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6611 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6610 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6612 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6611 else:
6613 else:
6612 # this can happen with a non-linear update
6614 # this can happen with a non-linear update
6613 ui.status(_("(leaving bookmark %s)\n") %
6615 ui.status(_("(leaving bookmark %s)\n") %
6614 repo._activebookmark)
6616 repo._activebookmark)
6615 bookmarks.deactivate(repo)
6617 bookmarks.deactivate(repo)
6616 elif brev in repo._bookmarks:
6618 elif brev in repo._bookmarks:
6617 bookmarks.activate(repo, brev)
6619 bookmarks.activate(repo, brev)
6618 ui.status(_("(activating bookmark %s)\n") % brev)
6620 ui.status(_("(activating bookmark %s)\n") % brev)
6619 elif brev:
6621 elif brev:
6620 if repo._activebookmark:
6622 if repo._activebookmark:
6621 ui.status(_("(leaving bookmark %s)\n") %
6623 ui.status(_("(leaving bookmark %s)\n") %
6622 repo._activebookmark)
6624 repo._activebookmark)
6623 bookmarks.deactivate(repo)
6625 bookmarks.deactivate(repo)
6624 finally:
6626 finally:
6625 wlock.release()
6627 wlock.release()
6626
6628
6627 return ret
6629 return ret
6628
6630
6629 @command('verify', [])
6631 @command('verify', [])
6630 def verify(ui, repo):
6632 def verify(ui, repo):
6631 """verify the integrity of the repository
6633 """verify the integrity of the repository
6632
6634
6633 Verify the integrity of the current repository.
6635 Verify the integrity of the current repository.
6634
6636
6635 This will perform an extensive check of the repository's
6637 This will perform an extensive check of the repository's
6636 integrity, validating the hashes and checksums of each entry in
6638 integrity, validating the hashes and checksums of each entry in
6637 the changelog, manifest, and tracked files, as well as the
6639 the changelog, manifest, and tracked files, as well as the
6638 integrity of their crosslinks and indices.
6640 integrity of their crosslinks and indices.
6639
6641
6640 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6642 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6641 for more information about recovery from corruption of the
6643 for more information about recovery from corruption of the
6642 repository.
6644 repository.
6643
6645
6644 Returns 0 on success, 1 if errors are encountered.
6646 Returns 0 on success, 1 if errors are encountered.
6645 """
6647 """
6646 return hg.verify(repo)
6648 return hg.verify(repo)
6647
6649
6648 @command('version', [], norepo=True)
6650 @command('version', [], norepo=True)
6649 def version_(ui):
6651 def version_(ui):
6650 """output version and copyright information"""
6652 """output version and copyright information"""
6651 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6653 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6652 % util.version())
6654 % util.version())
6653 ui.status(_(
6655 ui.status(_(
6654 "(see https://mercurial-scm.org for more information)\n"
6656 "(see https://mercurial-scm.org for more information)\n"
6655 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6657 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6656 "This is free software; see the source for copying conditions. "
6658 "This is free software; see the source for copying conditions. "
6657 "There is NO\nwarranty; "
6659 "There is NO\nwarranty; "
6658 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6660 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6659 ))
6661 ))
6660
6662
6661 ui.note(_("\nEnabled extensions:\n\n"))
6663 ui.note(_("\nEnabled extensions:\n\n"))
6662 if ui.verbose:
6664 if ui.verbose:
6663 # format names and versions into columns
6665 # format names and versions into columns
6664 names = []
6666 names = []
6665 vers = []
6667 vers = []
6666 for name, module in extensions.extensions():
6668 for name, module in extensions.extensions():
6667 names.append(name)
6669 names.append(name)
6668 vers.append(extensions.moduleversion(module))
6670 vers.append(extensions.moduleversion(module))
6669 if names:
6671 if names:
6670 maxnamelen = max(len(n) for n in names)
6672 maxnamelen = max(len(n) for n in names)
6671 for i, name in enumerate(names):
6673 for i, name in enumerate(names):
6672 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6674 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,55 +1,79 b''
1 # destutil.py - Mercurial utility function for command destination
1 # destutil.py - Mercurial utility function for command destination
2 #
2 #
3 # Copyright Matt Mackall <mpm@selenic.com> and other
3 # Copyright Matt Mackall <mpm@selenic.com> and other
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 .i18n import _
8 from .i18n import _
9 from . import (
9 from . import (
10 error,
10 error,
11 obsolete,
11 obsolete,
12 )
12 )
13
13
14 def destupdate(repo):
14 def destupdate(repo, clean=False):
15 """destination for bare update operation
15 """destination for bare update operation
16 """
16 """
17 # Here is where we should consider bookmarks, divergent bookmarks, and tip
17 # Here is where we should consider bookmarks, divergent bookmarks, and tip
18 # of current branch; but currently we are only checking the branch tips.
18 # of current branch; but currently we are only checking the branch tips.
19 node = None
19 node = None
20 wc = repo[None]
20 wc = repo[None]
21 p1 = wc.p1()
21 p1 = wc.p1()
22 try:
22 try:
23 node = repo.branchtip(wc.branch())
23 node = repo.branchtip(wc.branch())
24 except error.RepoLookupError:
24 except error.RepoLookupError:
25 if wc.branch() == 'default': # no default branch!
25 if wc.branch() == 'default': # no default branch!
26 node = repo.lookup('tip') # update to tip
26 node = repo.lookup('tip') # update to tip
27 else:
27 else:
28 raise error.Abort(_("branch %s not found") % wc.branch())
28 raise error.Abort(_("branch %s not found") % wc.branch())
29
29
30 if p1.obsolete() and not p1.children():
30 if p1.obsolete() and not p1.children():
31 # allow updating to successors
31 # allow updating to successors
32 successors = obsolete.successorssets(repo, p1.node())
32 successors = obsolete.successorssets(repo, p1.node())
33
33
34 # behavior of certain cases is as follows,
34 # behavior of certain cases is as follows,
35 #
35 #
36 # divergent changesets: update to highest rev, similar to what
36 # divergent changesets: update to highest rev, similar to what
37 # is currently done when there are more than one head
37 # is currently done when there are more than one head
38 # (i.e. 'tip')
38 # (i.e. 'tip')
39 #
39 #
40 # replaced changesets: same as divergent except we know there
40 # replaced changesets: same as divergent except we know there
41 # is no conflict
41 # is no conflict
42 #
42 #
43 # pruned changeset: no update is done; though, we could
43 # pruned changeset: no update is done; though, we could
44 # consider updating to the first non-obsolete parent,
44 # consider updating to the first non-obsolete parent,
45 # similar to what is current done for 'hg prune'
45 # similar to what is current done for 'hg prune'
46
46
47 if successors:
47 if successors:
48 # flatten the list here handles both divergent (len > 1)
48 # flatten the list here handles both divergent (len > 1)
49 # and the usual case (len = 1)
49 # and the usual case (len = 1)
50 successors = [n for sub in successors for n in sub]
50 successors = [n for sub in successors for n in sub]
51
51
52 # get the max revision for the given successors set,
52 # get the max revision for the given successors set,
53 # i.e. the 'tip' of a set
53 # i.e. the 'tip' of a set
54 node = repo.revs('max(%ln)', successors).first()
54 node = repo.revs('max(%ln)', successors).first()
55 return repo[node].rev()
55 rev = repo[node].rev()
56
57 if not clean:
58 # Check that the update is linear.
59 #
60 # Mercurial do not allow update-merge for non linear pattern
61 # (that would be technically possible but was considered too confusing
62 # for user a long time ago)
63 #
64 # See mercurial.merge.update for details
65 if p1.rev() not in repo.changelog.ancestors([rev], inclusive=True):
66 dirty = wc.dirty(missing=True)
67 foreground = obsolete.foreground(repo, [p1.node()])
68 if not repo[rev].node() in foreground:
69 if dirty:
70 msg = _("uncommitted changes")
71 hint = _("commit and merge, or update --clean to"
72 " discard changes")
73 raise error.Abort(msg, hint=hint)
74 else: # destination is not a descendant.
75 msg = _("not a linear update")
76 hint = _("merge or update --check to force update")
77 raise error.Abort(msg, hint=hint)
78
79 return rev
General Comments 0
You need to be logged in to leave comments. Login now