##// END OF EJS Templates
config: use the same hgrc for a cloned repo as for an uninitted repo...
Jordi Gutiérrez Hermoso -
r22837:2be7d5eb default
parent child Browse files
Show More
@@ -1,6326 +1,6325 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod
21 import dagparser, context, simplemerge, graphmod
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange
24 import phases, obsolete, exchange
25 import ui as uimod
25
26
26 table = {}
27 table = {}
27
28
28 command = cmdutil.command(table)
29 command = cmdutil.command(table)
29
30
30 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
31 # 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.
32 norepo = ''
33 norepo = ''
33 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
34 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
35 # decorator.
36 # decorator.
36 optionalrepo = ''
37 optionalrepo = ''
37 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
38 # 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
39 # @command decorator.
40 # @command decorator.
40 inferrepo = ''
41 inferrepo = ''
41
42
42 # common command options
43 # common command options
43
44
44 globalopts = [
45 globalopts = [
45 ('R', 'repository', '',
46 ('R', 'repository', '',
46 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
47 _('REPO')),
48 _('REPO')),
48 ('', 'cwd', '',
49 ('', 'cwd', '',
49 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
50 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
51 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('', 'config', [],
55 ('', 'config', [],
55 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
56 _('CONFIG')),
57 _('CONFIG')),
57 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 _('ENCODE')),
61 _('ENCODE')),
61 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
62 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
63 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
67 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ]
70 ]
70
71
71 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
72 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
73
74
74 remoteopts = [
75 remoteopts = [
75 ('e', 'ssh', '',
76 ('e', 'ssh', '',
76 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
77 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
78 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
79 ('', 'insecure', None,
80 ('', 'insecure', None,
80 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 ]
82 ]
82
83
83 walkopts = [
84 walkopts = [
84 ('I', 'include', [],
85 ('I', 'include', [],
85 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
86 ('X', 'exclude', [],
87 ('X', 'exclude', [],
87 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 ]
89 ]
89
90
90 commitopts = [
91 commitopts = [
91 ('m', 'message', '',
92 ('m', 'message', '',
92 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
93 ('l', 'logfile', '',
94 ('l', 'logfile', '',
94 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
95 ]
96 ]
96
97
97 commitopts2 = [
98 commitopts2 = [
98 ('d', 'date', '',
99 ('d', 'date', '',
99 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
100 ('u', 'user', '',
101 ('u', 'user', '',
101 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
102 ]
103 ]
103
104
104 # hidden for now
105 # hidden for now
105 formatteropts = [
106 formatteropts = [
106 ('T', 'template', '',
107 ('T', 'template', '',
107 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 ]
109 ]
109
110
110 templateopts = [
111 templateopts = [
111 ('', 'style', '',
112 ('', 'style', '',
112 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 ('T', 'template', '',
114 ('T', 'template', '',
114 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
115 ]
116 ]
116
117
117 logopts = [
118 logopts = [
118 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
119 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('l', 'limit', '',
121 ('l', 'limit', '',
121 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
122 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ] + templateopts
126 ] + templateopts
126
127
127 diffopts = [
128 diffopts = [
128 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
129 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ]
132 ]
132
133
133 diffwsopts = [
134 diffwsopts = [
134 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
135 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
136 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
137 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
138 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
139 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
140 ]
141 ]
141
142
142 diffopts2 = [
143 diffopts2 = [
143 ('p', 'show-function', None, _('show which function each change is in')),
144 ('p', 'show-function', None, _('show which function each change is in')),
144 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 ('', 'reverse', None, _('produce a diff that undoes the changes')),
145 ] + diffwsopts + [
146 ] + diffwsopts + [
146 ('U', 'unified', '',
147 ('U', 'unified', '',
147 _('number of lines of context to show'), _('NUM')),
148 _('number of lines of context to show'), _('NUM')),
148 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 ('', 'stat', None, _('output diffstat-style summary of changes')),
149 ]
150 ]
150
151
151 mergetoolopts = [
152 mergetoolopts = [
152 ('t', 'tool', '', _('specify merge tool')),
153 ('t', 'tool', '', _('specify merge tool')),
153 ]
154 ]
154
155
155 similarityopts = [
156 similarityopts = [
156 ('s', 'similarity', '',
157 ('s', 'similarity', '',
157 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
158 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
158 ]
159 ]
159
160
160 subrepoopts = [
161 subrepoopts = [
161 ('S', 'subrepos', None,
162 ('S', 'subrepos', None,
162 _('recurse into subrepositories'))
163 _('recurse into subrepositories'))
163 ]
164 ]
164
165
165 # Commands start here, listed alphabetically
166 # Commands start here, listed alphabetically
166
167
167 @command('^add',
168 @command('^add',
168 walkopts + subrepoopts + dryrunopts,
169 walkopts + subrepoopts + dryrunopts,
169 _('[OPTION]... [FILE]...'),
170 _('[OPTION]... [FILE]...'),
170 inferrepo=True)
171 inferrepo=True)
171 def add(ui, repo, *pats, **opts):
172 def add(ui, repo, *pats, **opts):
172 """add the specified files on the next commit
173 """add the specified files on the next commit
173
174
174 Schedule files to be version controlled and added to the
175 Schedule files to be version controlled and added to the
175 repository.
176 repository.
176
177
177 The files will be added to the repository at the next commit. To
178 The files will be added to the repository at the next commit. To
178 undo an add before that, see :hg:`forget`.
179 undo an add before that, see :hg:`forget`.
179
180
180 If no names are given, add all files to the repository.
181 If no names are given, add all files to the repository.
181
182
182 .. container:: verbose
183 .. container:: verbose
183
184
184 An example showing how new (unknown) files are added
185 An example showing how new (unknown) files are added
185 automatically by :hg:`add`::
186 automatically by :hg:`add`::
186
187
187 $ ls
188 $ ls
188 foo.c
189 foo.c
189 $ hg status
190 $ hg status
190 ? foo.c
191 ? foo.c
191 $ hg add
192 $ hg add
192 adding foo.c
193 adding foo.c
193 $ hg status
194 $ hg status
194 A foo.c
195 A foo.c
195
196
196 Returns 0 if all files are successfully added.
197 Returns 0 if all files are successfully added.
197 """
198 """
198
199
199 m = scmutil.match(repo[None], pats, opts)
200 m = scmutil.match(repo[None], pats, opts)
200 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
201 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
201 opts.get('subrepos'), prefix="", explicitonly=False)
202 opts.get('subrepos'), prefix="", explicitonly=False)
202 return rejected and 1 or 0
203 return rejected and 1 or 0
203
204
204 @command('addremove',
205 @command('addremove',
205 similarityopts + walkopts + dryrunopts,
206 similarityopts + walkopts + dryrunopts,
206 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
207 inferrepo=True)
208 inferrepo=True)
208 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
209 """add all new files, delete all missing files
210 """add all new files, delete all missing files
210
211
211 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
212 repository.
213 repository.
213
214
214 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
215 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
216 commit.
217 commit.
217
218
218 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
219 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
220 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
221 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
222 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
223 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
224 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
225 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
226 identical files are detected.
227 identical files are detected.
227
228
228 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
229 """
230 """
230 try:
231 try:
231 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
232 except ValueError:
233 except ValueError:
233 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
234 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
235 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
237 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
237
238
238 @command('^annotate|blame',
239 @command('^annotate|blame',
239 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
240 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
240 ('', 'follow', None,
241 ('', 'follow', None,
241 _('follow copies/renames and list the filename (DEPRECATED)')),
242 _('follow copies/renames and list the filename (DEPRECATED)')),
242 ('', 'no-follow', None, _("don't follow copies and renames")),
243 ('', 'no-follow', None, _("don't follow copies and renames")),
243 ('a', 'text', None, _('treat all files as text')),
244 ('a', 'text', None, _('treat all files as text')),
244 ('u', 'user', None, _('list the author (long with -v)')),
245 ('u', 'user', None, _('list the author (long with -v)')),
245 ('f', 'file', None, _('list the filename')),
246 ('f', 'file', None, _('list the filename')),
246 ('d', 'date', None, _('list the date (short with -q)')),
247 ('d', 'date', None, _('list the date (short with -q)')),
247 ('n', 'number', None, _('list the revision number (default)')),
248 ('n', 'number', None, _('list the revision number (default)')),
248 ('c', 'changeset', None, _('list the changeset')),
249 ('c', 'changeset', None, _('list the changeset')),
249 ('l', 'line-number', None, _('show line number at the first appearance'))
250 ('l', 'line-number', None, _('show line number at the first appearance'))
250 ] + diffwsopts + walkopts + formatteropts,
251 ] + diffwsopts + walkopts + formatteropts,
251 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
252 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
252 inferrepo=True)
253 inferrepo=True)
253 def annotate(ui, repo, *pats, **opts):
254 def annotate(ui, repo, *pats, **opts):
254 """show changeset information by line for each file
255 """show changeset information by line for each file
255
256
256 List changes in files, showing the revision id responsible for
257 List changes in files, showing the revision id responsible for
257 each line
258 each line
258
259
259 This command is useful for discovering when a change was made and
260 This command is useful for discovering when a change was made and
260 by whom.
261 by whom.
261
262
262 Without the -a/--text option, annotate will avoid processing files
263 Without the -a/--text option, annotate will avoid processing files
263 it detects as binary. With -a, annotate will annotate the file
264 it detects as binary. With -a, annotate will annotate the file
264 anyway, although the results will probably be neither useful
265 anyway, although the results will probably be neither useful
265 nor desirable.
266 nor desirable.
266
267
267 Returns 0 on success.
268 Returns 0 on success.
268 """
269 """
269 if not pats:
270 if not pats:
270 raise util.Abort(_('at least one filename or pattern is required'))
271 raise util.Abort(_('at least one filename or pattern is required'))
271
272
272 if opts.get('follow'):
273 if opts.get('follow'):
273 # --follow is deprecated and now just an alias for -f/--file
274 # --follow is deprecated and now just an alias for -f/--file
274 # to mimic the behavior of Mercurial before version 1.5
275 # to mimic the behavior of Mercurial before version 1.5
275 opts['file'] = True
276 opts['file'] = True
276
277
277 fm = ui.formatter('annotate', opts)
278 fm = ui.formatter('annotate', opts)
278 datefunc = ui.quiet and util.shortdate or util.datestr
279 datefunc = ui.quiet and util.shortdate or util.datestr
279 hexfn = fm.hexfunc
280 hexfn = fm.hexfunc
280
281
281 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
282 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
282 ('number', ' ', lambda x: x[0].rev(), str),
283 ('number', ' ', lambda x: x[0].rev(), str),
283 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
284 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
284 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
285 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
285 ('file', ' ', lambda x: x[0].path(), str),
286 ('file', ' ', lambda x: x[0].path(), str),
286 ('line_number', ':', lambda x: x[1], str),
287 ('line_number', ':', lambda x: x[1], str),
287 ]
288 ]
288 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
289 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
289
290
290 if (not opts.get('user') and not opts.get('changeset')
291 if (not opts.get('user') and not opts.get('changeset')
291 and not opts.get('date') and not opts.get('file')):
292 and not opts.get('date') and not opts.get('file')):
292 opts['number'] = True
293 opts['number'] = True
293
294
294 linenumber = opts.get('line_number') is not None
295 linenumber = opts.get('line_number') is not None
295 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
296 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
296 raise util.Abort(_('at least one of -n/-c is required for -l'))
297 raise util.Abort(_('at least one of -n/-c is required for -l'))
297
298
298 if fm:
299 if fm:
299 def makefunc(get, fmt):
300 def makefunc(get, fmt):
300 return get
301 return get
301 else:
302 else:
302 def makefunc(get, fmt):
303 def makefunc(get, fmt):
303 return lambda x: fmt(get(x))
304 return lambda x: fmt(get(x))
304 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
305 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
305 if opts.get(op)]
306 if opts.get(op)]
306 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
307 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
307 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
308 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
308 if opts.get(op))
309 if opts.get(op))
309
310
310 def bad(x, y):
311 def bad(x, y):
311 raise util.Abort("%s: %s" % (x, y))
312 raise util.Abort("%s: %s" % (x, y))
312
313
313 ctx = scmutil.revsingle(repo, opts.get('rev'))
314 ctx = scmutil.revsingle(repo, opts.get('rev'))
314 m = scmutil.match(ctx, pats, opts)
315 m = scmutil.match(ctx, pats, opts)
315 m.bad = bad
316 m.bad = bad
316 follow = not opts.get('no_follow')
317 follow = not opts.get('no_follow')
317 diffopts = patch.diffopts(ui, opts, section='annotate')
318 diffopts = patch.diffopts(ui, opts, section='annotate')
318 for abs in ctx.walk(m):
319 for abs in ctx.walk(m):
319 fctx = ctx[abs]
320 fctx = ctx[abs]
320 if not opts.get('text') and util.binary(fctx.data()):
321 if not opts.get('text') and util.binary(fctx.data()):
321 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
322 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
322 continue
323 continue
323
324
324 lines = fctx.annotate(follow=follow, linenumber=linenumber,
325 lines = fctx.annotate(follow=follow, linenumber=linenumber,
325 diffopts=diffopts)
326 diffopts=diffopts)
326 formats = []
327 formats = []
327 pieces = []
328 pieces = []
328
329
329 for f, sep in funcmap:
330 for f, sep in funcmap:
330 l = [f(n) for n, dummy in lines]
331 l = [f(n) for n, dummy in lines]
331 if l:
332 if l:
332 if fm:
333 if fm:
333 formats.append(['%s' for x in l])
334 formats.append(['%s' for x in l])
334 else:
335 else:
335 sizes = [encoding.colwidth(x) for x in l]
336 sizes = [encoding.colwidth(x) for x in l]
336 ml = max(sizes)
337 ml = max(sizes)
337 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
338 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
338 pieces.append(l)
339 pieces.append(l)
339
340
340 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
341 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
341 fm.startitem()
342 fm.startitem()
342 fm.write(fields, "".join(f), *p)
343 fm.write(fields, "".join(f), *p)
343 fm.write('line', ": %s", l[1])
344 fm.write('line', ": %s", l[1])
344
345
345 if lines and not lines[-1][1].endswith('\n'):
346 if lines and not lines[-1][1].endswith('\n'):
346 fm.plain('\n')
347 fm.plain('\n')
347
348
348 fm.end()
349 fm.end()
349
350
350 @command('archive',
351 @command('archive',
351 [('', 'no-decode', None, _('do not pass files through decoders')),
352 [('', 'no-decode', None, _('do not pass files through decoders')),
352 ('p', 'prefix', '', _('directory prefix for files in archive'),
353 ('p', 'prefix', '', _('directory prefix for files in archive'),
353 _('PREFIX')),
354 _('PREFIX')),
354 ('r', 'rev', '', _('revision to distribute'), _('REV')),
355 ('r', 'rev', '', _('revision to distribute'), _('REV')),
355 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
356 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
356 ] + subrepoopts + walkopts,
357 ] + subrepoopts + walkopts,
357 _('[OPTION]... DEST'))
358 _('[OPTION]... DEST'))
358 def archive(ui, repo, dest, **opts):
359 def archive(ui, repo, dest, **opts):
359 '''create an unversioned archive of a repository revision
360 '''create an unversioned archive of a repository revision
360
361
361 By default, the revision used is the parent of the working
362 By default, the revision used is the parent of the working
362 directory; use -r/--rev to specify a different revision.
363 directory; use -r/--rev to specify a different revision.
363
364
364 The archive type is automatically detected based on file
365 The archive type is automatically detected based on file
365 extension (or override using -t/--type).
366 extension (or override using -t/--type).
366
367
367 .. container:: verbose
368 .. container:: verbose
368
369
369 Examples:
370 Examples:
370
371
371 - create a zip file containing the 1.0 release::
372 - create a zip file containing the 1.0 release::
372
373
373 hg archive -r 1.0 project-1.0.zip
374 hg archive -r 1.0 project-1.0.zip
374
375
375 - create a tarball excluding .hg files::
376 - create a tarball excluding .hg files::
376
377
377 hg archive project.tar.gz -X ".hg*"
378 hg archive project.tar.gz -X ".hg*"
378
379
379 Valid types are:
380 Valid types are:
380
381
381 :``files``: a directory full of files (default)
382 :``files``: a directory full of files (default)
382 :``tar``: tar archive, uncompressed
383 :``tar``: tar archive, uncompressed
383 :``tbz2``: tar archive, compressed using bzip2
384 :``tbz2``: tar archive, compressed using bzip2
384 :``tgz``: tar archive, compressed using gzip
385 :``tgz``: tar archive, compressed using gzip
385 :``uzip``: zip archive, uncompressed
386 :``uzip``: zip archive, uncompressed
386 :``zip``: zip archive, compressed using deflate
387 :``zip``: zip archive, compressed using deflate
387
388
388 The exact name of the destination archive or directory is given
389 The exact name of the destination archive or directory is given
389 using a format string; see :hg:`help export` for details.
390 using a format string; see :hg:`help export` for details.
390
391
391 Each member added to an archive file has a directory prefix
392 Each member added to an archive file has a directory prefix
392 prepended. Use -p/--prefix to specify a format string for the
393 prepended. Use -p/--prefix to specify a format string for the
393 prefix. The default is the basename of the archive, with suffixes
394 prefix. The default is the basename of the archive, with suffixes
394 removed.
395 removed.
395
396
396 Returns 0 on success.
397 Returns 0 on success.
397 '''
398 '''
398
399
399 ctx = scmutil.revsingle(repo, opts.get('rev'))
400 ctx = scmutil.revsingle(repo, opts.get('rev'))
400 if not ctx:
401 if not ctx:
401 raise util.Abort(_('no working directory: please specify a revision'))
402 raise util.Abort(_('no working directory: please specify a revision'))
402 node = ctx.node()
403 node = ctx.node()
403 dest = cmdutil.makefilename(repo, dest, node)
404 dest = cmdutil.makefilename(repo, dest, node)
404 if os.path.realpath(dest) == repo.root:
405 if os.path.realpath(dest) == repo.root:
405 raise util.Abort(_('repository root cannot be destination'))
406 raise util.Abort(_('repository root cannot be destination'))
406
407
407 kind = opts.get('type') or archival.guesskind(dest) or 'files'
408 kind = opts.get('type') or archival.guesskind(dest) or 'files'
408 prefix = opts.get('prefix')
409 prefix = opts.get('prefix')
409
410
410 if dest == '-':
411 if dest == '-':
411 if kind == 'files':
412 if kind == 'files':
412 raise util.Abort(_('cannot archive plain files to stdout'))
413 raise util.Abort(_('cannot archive plain files to stdout'))
413 dest = cmdutil.makefileobj(repo, dest)
414 dest = cmdutil.makefileobj(repo, dest)
414 if not prefix:
415 if not prefix:
415 prefix = os.path.basename(repo.root) + '-%h'
416 prefix = os.path.basename(repo.root) + '-%h'
416
417
417 prefix = cmdutil.makefilename(repo, prefix, node)
418 prefix = cmdutil.makefilename(repo, prefix, node)
418 matchfn = scmutil.match(ctx, [], opts)
419 matchfn = scmutil.match(ctx, [], opts)
419 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
420 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
420 matchfn, prefix, subrepos=opts.get('subrepos'))
421 matchfn, prefix, subrepos=opts.get('subrepos'))
421
422
422 @command('backout',
423 @command('backout',
423 [('', 'merge', None, _('merge with old dirstate parent after backout')),
424 [('', 'merge', None, _('merge with old dirstate parent after backout')),
424 ('', 'parent', '',
425 ('', 'parent', '',
425 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
426 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
426 ('r', 'rev', '', _('revision to backout'), _('REV')),
427 ('r', 'rev', '', _('revision to backout'), _('REV')),
427 ('e', 'edit', False, _('invoke editor on commit messages')),
428 ('e', 'edit', False, _('invoke editor on commit messages')),
428 ] + mergetoolopts + walkopts + commitopts + commitopts2,
429 ] + mergetoolopts + walkopts + commitopts + commitopts2,
429 _('[OPTION]... [-r] REV'))
430 _('[OPTION]... [-r] REV'))
430 def backout(ui, repo, node=None, rev=None, **opts):
431 def backout(ui, repo, node=None, rev=None, **opts):
431 '''reverse effect of earlier changeset
432 '''reverse effect of earlier changeset
432
433
433 Prepare a new changeset with the effect of REV undone in the
434 Prepare a new changeset with the effect of REV undone in the
434 current working directory.
435 current working directory.
435
436
436 If REV is the parent of the working directory, then this new changeset
437 If REV is the parent of the working directory, then this new changeset
437 is committed automatically. Otherwise, hg needs to merge the
438 is committed automatically. Otherwise, hg needs to merge the
438 changes and the merged result is left uncommitted.
439 changes and the merged result is left uncommitted.
439
440
440 .. note::
441 .. note::
441
442
442 backout cannot be used to fix either an unwanted or
443 backout cannot be used to fix either an unwanted or
443 incorrect merge.
444 incorrect merge.
444
445
445 .. container:: verbose
446 .. container:: verbose
446
447
447 By default, the pending changeset will have one parent,
448 By default, the pending changeset will have one parent,
448 maintaining a linear history. With --merge, the pending
449 maintaining a linear history. With --merge, the pending
449 changeset will instead have two parents: the old parent of the
450 changeset will instead have two parents: the old parent of the
450 working directory and a new child of REV that simply undoes REV.
451 working directory and a new child of REV that simply undoes REV.
451
452
452 Before version 1.7, the behavior without --merge was equivalent
453 Before version 1.7, the behavior without --merge was equivalent
453 to specifying --merge followed by :hg:`update --clean .` to
454 to specifying --merge followed by :hg:`update --clean .` to
454 cancel the merge and leave the child of REV as a head to be
455 cancel the merge and leave the child of REV as a head to be
455 merged separately.
456 merged separately.
456
457
457 See :hg:`help dates` for a list of formats valid for -d/--date.
458 See :hg:`help dates` for a list of formats valid for -d/--date.
458
459
459 Returns 0 on success, 1 if nothing to backout or there are unresolved
460 Returns 0 on success, 1 if nothing to backout or there are unresolved
460 files.
461 files.
461 '''
462 '''
462 if rev and node:
463 if rev and node:
463 raise util.Abort(_("please specify just one revision"))
464 raise util.Abort(_("please specify just one revision"))
464
465
465 if not rev:
466 if not rev:
466 rev = node
467 rev = node
467
468
468 if not rev:
469 if not rev:
469 raise util.Abort(_("please specify a revision to backout"))
470 raise util.Abort(_("please specify a revision to backout"))
470
471
471 date = opts.get('date')
472 date = opts.get('date')
472 if date:
473 if date:
473 opts['date'] = util.parsedate(date)
474 opts['date'] = util.parsedate(date)
474
475
475 cmdutil.checkunfinished(repo)
476 cmdutil.checkunfinished(repo)
476 cmdutil.bailifchanged(repo)
477 cmdutil.bailifchanged(repo)
477 node = scmutil.revsingle(repo, rev).node()
478 node = scmutil.revsingle(repo, rev).node()
478
479
479 op1, op2 = repo.dirstate.parents()
480 op1, op2 = repo.dirstate.parents()
480 if not repo.changelog.isancestor(node, op1):
481 if not repo.changelog.isancestor(node, op1):
481 raise util.Abort(_('cannot backout change that is not an ancestor'))
482 raise util.Abort(_('cannot backout change that is not an ancestor'))
482
483
483 p1, p2 = repo.changelog.parents(node)
484 p1, p2 = repo.changelog.parents(node)
484 if p1 == nullid:
485 if p1 == nullid:
485 raise util.Abort(_('cannot backout a change with no parents'))
486 raise util.Abort(_('cannot backout a change with no parents'))
486 if p2 != nullid:
487 if p2 != nullid:
487 if not opts.get('parent'):
488 if not opts.get('parent'):
488 raise util.Abort(_('cannot backout a merge changeset'))
489 raise util.Abort(_('cannot backout a merge changeset'))
489 p = repo.lookup(opts['parent'])
490 p = repo.lookup(opts['parent'])
490 if p not in (p1, p2):
491 if p not in (p1, p2):
491 raise util.Abort(_('%s is not a parent of %s') %
492 raise util.Abort(_('%s is not a parent of %s') %
492 (short(p), short(node)))
493 (short(p), short(node)))
493 parent = p
494 parent = p
494 else:
495 else:
495 if opts.get('parent'):
496 if opts.get('parent'):
496 raise util.Abort(_('cannot use --parent on non-merge changeset'))
497 raise util.Abort(_('cannot use --parent on non-merge changeset'))
497 parent = p1
498 parent = p1
498
499
499 # the backout should appear on the same branch
500 # the backout should appear on the same branch
500 wlock = repo.wlock()
501 wlock = repo.wlock()
501 try:
502 try:
502 branch = repo.dirstate.branch()
503 branch = repo.dirstate.branch()
503 bheads = repo.branchheads(branch)
504 bheads = repo.branchheads(branch)
504 rctx = scmutil.revsingle(repo, hex(parent))
505 rctx = scmutil.revsingle(repo, hex(parent))
505 if not opts.get('merge') and op1 != node:
506 if not opts.get('merge') and op1 != node:
506 try:
507 try:
507 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
508 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
508 'backout')
509 'backout')
509 repo.dirstate.beginparentchange()
510 repo.dirstate.beginparentchange()
510 stats = mergemod.update(repo, parent, True, True, False,
511 stats = mergemod.update(repo, parent, True, True, False,
511 node, False)
512 node, False)
512 repo.setparents(op1, op2)
513 repo.setparents(op1, op2)
513 repo.dirstate.endparentchange()
514 repo.dirstate.endparentchange()
514 hg._showstats(repo, stats)
515 hg._showstats(repo, stats)
515 if stats[3]:
516 if stats[3]:
516 repo.ui.status(_("use 'hg resolve' to retry unresolved "
517 repo.ui.status(_("use 'hg resolve' to retry unresolved "
517 "file merges\n"))
518 "file merges\n"))
518 else:
519 else:
519 msg = _("changeset %s backed out, "
520 msg = _("changeset %s backed out, "
520 "don't forget to commit.\n")
521 "don't forget to commit.\n")
521 ui.status(msg % short(node))
522 ui.status(msg % short(node))
522 return stats[3] > 0
523 return stats[3] > 0
523 finally:
524 finally:
524 ui.setconfig('ui', 'forcemerge', '', '')
525 ui.setconfig('ui', 'forcemerge', '', '')
525 else:
526 else:
526 hg.clean(repo, node, show_stats=False)
527 hg.clean(repo, node, show_stats=False)
527 repo.dirstate.setbranch(branch)
528 repo.dirstate.setbranch(branch)
528 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
529 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
529
530
530
531
531 def commitfunc(ui, repo, message, match, opts):
532 def commitfunc(ui, repo, message, match, opts):
532 editform = 'backout'
533 editform = 'backout'
533 e = cmdutil.getcommiteditor(editform=editform, **opts)
534 e = cmdutil.getcommiteditor(editform=editform, **opts)
534 if not message:
535 if not message:
535 # we don't translate commit messages
536 # we don't translate commit messages
536 message = "Backed out changeset %s" % short(node)
537 message = "Backed out changeset %s" % short(node)
537 e = cmdutil.getcommiteditor(edit=True, editform=editform)
538 e = cmdutil.getcommiteditor(edit=True, editform=editform)
538 return repo.commit(message, opts.get('user'), opts.get('date'),
539 return repo.commit(message, opts.get('user'), opts.get('date'),
539 match, editor=e)
540 match, editor=e)
540 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
541 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
541 if not newnode:
542 if not newnode:
542 ui.status(_("nothing changed\n"))
543 ui.status(_("nothing changed\n"))
543 return 1
544 return 1
544 cmdutil.commitstatus(repo, newnode, branch, bheads)
545 cmdutil.commitstatus(repo, newnode, branch, bheads)
545
546
546 def nice(node):
547 def nice(node):
547 return '%d:%s' % (repo.changelog.rev(node), short(node))
548 return '%d:%s' % (repo.changelog.rev(node), short(node))
548 ui.status(_('changeset %s backs out changeset %s\n') %
549 ui.status(_('changeset %s backs out changeset %s\n') %
549 (nice(repo.changelog.tip()), nice(node)))
550 (nice(repo.changelog.tip()), nice(node)))
550 if opts.get('merge') and op1 != node:
551 if opts.get('merge') and op1 != node:
551 hg.clean(repo, op1, show_stats=False)
552 hg.clean(repo, op1, show_stats=False)
552 ui.status(_('merging with changeset %s\n')
553 ui.status(_('merging with changeset %s\n')
553 % nice(repo.changelog.tip()))
554 % nice(repo.changelog.tip()))
554 try:
555 try:
555 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
556 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
556 'backout')
557 'backout')
557 return hg.merge(repo, hex(repo.changelog.tip()))
558 return hg.merge(repo, hex(repo.changelog.tip()))
558 finally:
559 finally:
559 ui.setconfig('ui', 'forcemerge', '', '')
560 ui.setconfig('ui', 'forcemerge', '', '')
560 finally:
561 finally:
561 wlock.release()
562 wlock.release()
562 return 0
563 return 0
563
564
564 @command('bisect',
565 @command('bisect',
565 [('r', 'reset', False, _('reset bisect state')),
566 [('r', 'reset', False, _('reset bisect state')),
566 ('g', 'good', False, _('mark changeset good')),
567 ('g', 'good', False, _('mark changeset good')),
567 ('b', 'bad', False, _('mark changeset bad')),
568 ('b', 'bad', False, _('mark changeset bad')),
568 ('s', 'skip', False, _('skip testing changeset')),
569 ('s', 'skip', False, _('skip testing changeset')),
569 ('e', 'extend', False, _('extend the bisect range')),
570 ('e', 'extend', False, _('extend the bisect range')),
570 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
571 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
571 ('U', 'noupdate', False, _('do not update to target'))],
572 ('U', 'noupdate', False, _('do not update to target'))],
572 _("[-gbsr] [-U] [-c CMD] [REV]"))
573 _("[-gbsr] [-U] [-c CMD] [REV]"))
573 def bisect(ui, repo, rev=None, extra=None, command=None,
574 def bisect(ui, repo, rev=None, extra=None, command=None,
574 reset=None, good=None, bad=None, skip=None, extend=None,
575 reset=None, good=None, bad=None, skip=None, extend=None,
575 noupdate=None):
576 noupdate=None):
576 """subdivision search of changesets
577 """subdivision search of changesets
577
578
578 This command helps to find changesets which introduce problems. To
579 This command helps to find changesets which introduce problems. To
579 use, mark the earliest changeset you know exhibits the problem as
580 use, mark the earliest changeset you know exhibits the problem as
580 bad, then mark the latest changeset which is free from the problem
581 bad, then mark the latest changeset which is free from the problem
581 as good. Bisect will update your working directory to a revision
582 as good. Bisect will update your working directory to a revision
582 for testing (unless the -U/--noupdate option is specified). Once
583 for testing (unless the -U/--noupdate option is specified). Once
583 you have performed tests, mark the working directory as good or
584 you have performed tests, mark the working directory as good or
584 bad, and bisect will either update to another candidate changeset
585 bad, and bisect will either update to another candidate changeset
585 or announce that it has found the bad revision.
586 or announce that it has found the bad revision.
586
587
587 As a shortcut, you can also use the revision argument to mark a
588 As a shortcut, you can also use the revision argument to mark a
588 revision as good or bad without checking it out first.
589 revision as good or bad without checking it out first.
589
590
590 If you supply a command, it will be used for automatic bisection.
591 If you supply a command, it will be used for automatic bisection.
591 The environment variable HG_NODE will contain the ID of the
592 The environment variable HG_NODE will contain the ID of the
592 changeset being tested. The exit status of the command will be
593 changeset being tested. The exit status of the command will be
593 used to mark revisions as good or bad: status 0 means good, 125
594 used to mark revisions as good or bad: status 0 means good, 125
594 means to skip the revision, 127 (command not found) will abort the
595 means to skip the revision, 127 (command not found) will abort the
595 bisection, and any other non-zero exit status means the revision
596 bisection, and any other non-zero exit status means the revision
596 is bad.
597 is bad.
597
598
598 .. container:: verbose
599 .. container:: verbose
599
600
600 Some examples:
601 Some examples:
601
602
602 - start a bisection with known bad revision 34, and good revision 12::
603 - start a bisection with known bad revision 34, and good revision 12::
603
604
604 hg bisect --bad 34
605 hg bisect --bad 34
605 hg bisect --good 12
606 hg bisect --good 12
606
607
607 - advance the current bisection by marking current revision as good or
608 - advance the current bisection by marking current revision as good or
608 bad::
609 bad::
609
610
610 hg bisect --good
611 hg bisect --good
611 hg bisect --bad
612 hg bisect --bad
612
613
613 - mark the current revision, or a known revision, to be skipped (e.g. if
614 - mark the current revision, or a known revision, to be skipped (e.g. if
614 that revision is not usable because of another issue)::
615 that revision is not usable because of another issue)::
615
616
616 hg bisect --skip
617 hg bisect --skip
617 hg bisect --skip 23
618 hg bisect --skip 23
618
619
619 - skip all revisions that do not touch directories ``foo`` or ``bar``::
620 - skip all revisions that do not touch directories ``foo`` or ``bar``::
620
621
621 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
622 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
622
623
623 - forget the current bisection::
624 - forget the current bisection::
624
625
625 hg bisect --reset
626 hg bisect --reset
626
627
627 - use 'make && make tests' to automatically find the first broken
628 - use 'make && make tests' to automatically find the first broken
628 revision::
629 revision::
629
630
630 hg bisect --reset
631 hg bisect --reset
631 hg bisect --bad 34
632 hg bisect --bad 34
632 hg bisect --good 12
633 hg bisect --good 12
633 hg bisect --command "make && make tests"
634 hg bisect --command "make && make tests"
634
635
635 - see all changesets whose states are already known in the current
636 - see all changesets whose states are already known in the current
636 bisection::
637 bisection::
637
638
638 hg log -r "bisect(pruned)"
639 hg log -r "bisect(pruned)"
639
640
640 - see the changeset currently being bisected (especially useful
641 - see the changeset currently being bisected (especially useful
641 if running with -U/--noupdate)::
642 if running with -U/--noupdate)::
642
643
643 hg log -r "bisect(current)"
644 hg log -r "bisect(current)"
644
645
645 - see all changesets that took part in the current bisection::
646 - see all changesets that took part in the current bisection::
646
647
647 hg log -r "bisect(range)"
648 hg log -r "bisect(range)"
648
649
649 - you can even get a nice graph::
650 - you can even get a nice graph::
650
651
651 hg log --graph -r "bisect(range)"
652 hg log --graph -r "bisect(range)"
652
653
653 See :hg:`help revsets` for more about the `bisect()` keyword.
654 See :hg:`help revsets` for more about the `bisect()` keyword.
654
655
655 Returns 0 on success.
656 Returns 0 on success.
656 """
657 """
657 def extendbisectrange(nodes, good):
658 def extendbisectrange(nodes, good):
658 # bisect is incomplete when it ends on a merge node and
659 # bisect is incomplete when it ends on a merge node and
659 # one of the parent was not checked.
660 # one of the parent was not checked.
660 parents = repo[nodes[0]].parents()
661 parents = repo[nodes[0]].parents()
661 if len(parents) > 1:
662 if len(parents) > 1:
662 side = good and state['bad'] or state['good']
663 side = good and state['bad'] or state['good']
663 num = len(set(i.node() for i in parents) & set(side))
664 num = len(set(i.node() for i in parents) & set(side))
664 if num == 1:
665 if num == 1:
665 return parents[0].ancestor(parents[1])
666 return parents[0].ancestor(parents[1])
666 return None
667 return None
667
668
668 def print_result(nodes, good):
669 def print_result(nodes, good):
669 displayer = cmdutil.show_changeset(ui, repo, {})
670 displayer = cmdutil.show_changeset(ui, repo, {})
670 if len(nodes) == 1:
671 if len(nodes) == 1:
671 # narrowed it down to a single revision
672 # narrowed it down to a single revision
672 if good:
673 if good:
673 ui.write(_("The first good revision is:\n"))
674 ui.write(_("The first good revision is:\n"))
674 else:
675 else:
675 ui.write(_("The first bad revision is:\n"))
676 ui.write(_("The first bad revision is:\n"))
676 displayer.show(repo[nodes[0]])
677 displayer.show(repo[nodes[0]])
677 extendnode = extendbisectrange(nodes, good)
678 extendnode = extendbisectrange(nodes, good)
678 if extendnode is not None:
679 if extendnode is not None:
679 ui.write(_('Not all ancestors of this changeset have been'
680 ui.write(_('Not all ancestors of this changeset have been'
680 ' checked.\nUse bisect --extend to continue the '
681 ' checked.\nUse bisect --extend to continue the '
681 'bisection from\nthe common ancestor, %s.\n')
682 'bisection from\nthe common ancestor, %s.\n')
682 % extendnode)
683 % extendnode)
683 else:
684 else:
684 # multiple possible revisions
685 # multiple possible revisions
685 if good:
686 if good:
686 ui.write(_("Due to skipped revisions, the first "
687 ui.write(_("Due to skipped revisions, the first "
687 "good revision could be any of:\n"))
688 "good revision could be any of:\n"))
688 else:
689 else:
689 ui.write(_("Due to skipped revisions, the first "
690 ui.write(_("Due to skipped revisions, the first "
690 "bad revision could be any of:\n"))
691 "bad revision could be any of:\n"))
691 for n in nodes:
692 for n in nodes:
692 displayer.show(repo[n])
693 displayer.show(repo[n])
693 displayer.close()
694 displayer.close()
694
695
695 def check_state(state, interactive=True):
696 def check_state(state, interactive=True):
696 if not state['good'] or not state['bad']:
697 if not state['good'] or not state['bad']:
697 if (good or bad or skip or reset) and interactive:
698 if (good or bad or skip or reset) and interactive:
698 return
699 return
699 if not state['good']:
700 if not state['good']:
700 raise util.Abort(_('cannot bisect (no known good revisions)'))
701 raise util.Abort(_('cannot bisect (no known good revisions)'))
701 else:
702 else:
702 raise util.Abort(_('cannot bisect (no known bad revisions)'))
703 raise util.Abort(_('cannot bisect (no known bad revisions)'))
703 return True
704 return True
704
705
705 # backward compatibility
706 # backward compatibility
706 if rev in "good bad reset init".split():
707 if rev in "good bad reset init".split():
707 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
708 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
708 cmd, rev, extra = rev, extra, None
709 cmd, rev, extra = rev, extra, None
709 if cmd == "good":
710 if cmd == "good":
710 good = True
711 good = True
711 elif cmd == "bad":
712 elif cmd == "bad":
712 bad = True
713 bad = True
713 else:
714 else:
714 reset = True
715 reset = True
715 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
716 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
716 raise util.Abort(_('incompatible arguments'))
717 raise util.Abort(_('incompatible arguments'))
717
718
718 cmdutil.checkunfinished(repo)
719 cmdutil.checkunfinished(repo)
719
720
720 if reset:
721 if reset:
721 p = repo.join("bisect.state")
722 p = repo.join("bisect.state")
722 if os.path.exists(p):
723 if os.path.exists(p):
723 os.unlink(p)
724 os.unlink(p)
724 return
725 return
725
726
726 state = hbisect.load_state(repo)
727 state = hbisect.load_state(repo)
727
728
728 if command:
729 if command:
729 changesets = 1
730 changesets = 1
730 if noupdate:
731 if noupdate:
731 try:
732 try:
732 node = state['current'][0]
733 node = state['current'][0]
733 except LookupError:
734 except LookupError:
734 raise util.Abort(_('current bisect revision is unknown - '
735 raise util.Abort(_('current bisect revision is unknown - '
735 'start a new bisect to fix'))
736 'start a new bisect to fix'))
736 else:
737 else:
737 node, p2 = repo.dirstate.parents()
738 node, p2 = repo.dirstate.parents()
738 if p2 != nullid:
739 if p2 != nullid:
739 raise util.Abort(_('current bisect revision is a merge'))
740 raise util.Abort(_('current bisect revision is a merge'))
740 try:
741 try:
741 while changesets:
742 while changesets:
742 # update state
743 # update state
743 state['current'] = [node]
744 state['current'] = [node]
744 hbisect.save_state(repo, state)
745 hbisect.save_state(repo, state)
745 status = util.system(command,
746 status = util.system(command,
746 environ={'HG_NODE': hex(node)},
747 environ={'HG_NODE': hex(node)},
747 out=ui.fout)
748 out=ui.fout)
748 if status == 125:
749 if status == 125:
749 transition = "skip"
750 transition = "skip"
750 elif status == 0:
751 elif status == 0:
751 transition = "good"
752 transition = "good"
752 # status < 0 means process was killed
753 # status < 0 means process was killed
753 elif status == 127:
754 elif status == 127:
754 raise util.Abort(_("failed to execute %s") % command)
755 raise util.Abort(_("failed to execute %s") % command)
755 elif status < 0:
756 elif status < 0:
756 raise util.Abort(_("%s killed") % command)
757 raise util.Abort(_("%s killed") % command)
757 else:
758 else:
758 transition = "bad"
759 transition = "bad"
759 ctx = scmutil.revsingle(repo, rev, node)
760 ctx = scmutil.revsingle(repo, rev, node)
760 rev = None # clear for future iterations
761 rev = None # clear for future iterations
761 state[transition].append(ctx.node())
762 state[transition].append(ctx.node())
762 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
763 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
763 check_state(state, interactive=False)
764 check_state(state, interactive=False)
764 # bisect
765 # bisect
765 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
766 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
766 # update to next check
767 # update to next check
767 node = nodes[0]
768 node = nodes[0]
768 if not noupdate:
769 if not noupdate:
769 cmdutil.bailifchanged(repo)
770 cmdutil.bailifchanged(repo)
770 hg.clean(repo, node, show_stats=False)
771 hg.clean(repo, node, show_stats=False)
771 finally:
772 finally:
772 state['current'] = [node]
773 state['current'] = [node]
773 hbisect.save_state(repo, state)
774 hbisect.save_state(repo, state)
774 print_result(nodes, bgood)
775 print_result(nodes, bgood)
775 return
776 return
776
777
777 # update state
778 # update state
778
779
779 if rev:
780 if rev:
780 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
781 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
781 else:
782 else:
782 nodes = [repo.lookup('.')]
783 nodes = [repo.lookup('.')]
783
784
784 if good or bad or skip:
785 if good or bad or skip:
785 if good:
786 if good:
786 state['good'] += nodes
787 state['good'] += nodes
787 elif bad:
788 elif bad:
788 state['bad'] += nodes
789 state['bad'] += nodes
789 elif skip:
790 elif skip:
790 state['skip'] += nodes
791 state['skip'] += nodes
791 hbisect.save_state(repo, state)
792 hbisect.save_state(repo, state)
792
793
793 if not check_state(state):
794 if not check_state(state):
794 return
795 return
795
796
796 # actually bisect
797 # actually bisect
797 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
798 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
798 if extend:
799 if extend:
799 if not changesets:
800 if not changesets:
800 extendnode = extendbisectrange(nodes, good)
801 extendnode = extendbisectrange(nodes, good)
801 if extendnode is not None:
802 if extendnode is not None:
802 ui.write(_("Extending search to changeset %d:%s\n")
803 ui.write(_("Extending search to changeset %d:%s\n")
803 % (extendnode.rev(), extendnode))
804 % (extendnode.rev(), extendnode))
804 state['current'] = [extendnode.node()]
805 state['current'] = [extendnode.node()]
805 hbisect.save_state(repo, state)
806 hbisect.save_state(repo, state)
806 if noupdate:
807 if noupdate:
807 return
808 return
808 cmdutil.bailifchanged(repo)
809 cmdutil.bailifchanged(repo)
809 return hg.clean(repo, extendnode.node())
810 return hg.clean(repo, extendnode.node())
810 raise util.Abort(_("nothing to extend"))
811 raise util.Abort(_("nothing to extend"))
811
812
812 if changesets == 0:
813 if changesets == 0:
813 print_result(nodes, good)
814 print_result(nodes, good)
814 else:
815 else:
815 assert len(nodes) == 1 # only a single node can be tested next
816 assert len(nodes) == 1 # only a single node can be tested next
816 node = nodes[0]
817 node = nodes[0]
817 # compute the approximate number of remaining tests
818 # compute the approximate number of remaining tests
818 tests, size = 0, 2
819 tests, size = 0, 2
819 while size <= changesets:
820 while size <= changesets:
820 tests, size = tests + 1, size * 2
821 tests, size = tests + 1, size * 2
821 rev = repo.changelog.rev(node)
822 rev = repo.changelog.rev(node)
822 ui.write(_("Testing changeset %d:%s "
823 ui.write(_("Testing changeset %d:%s "
823 "(%d changesets remaining, ~%d tests)\n")
824 "(%d changesets remaining, ~%d tests)\n")
824 % (rev, short(node), changesets, tests))
825 % (rev, short(node), changesets, tests))
825 state['current'] = [node]
826 state['current'] = [node]
826 hbisect.save_state(repo, state)
827 hbisect.save_state(repo, state)
827 if not noupdate:
828 if not noupdate:
828 cmdutil.bailifchanged(repo)
829 cmdutil.bailifchanged(repo)
829 return hg.clean(repo, node)
830 return hg.clean(repo, node)
830
831
831 @command('bookmarks|bookmark',
832 @command('bookmarks|bookmark',
832 [('f', 'force', False, _('force')),
833 [('f', 'force', False, _('force')),
833 ('r', 'rev', '', _('revision'), _('REV')),
834 ('r', 'rev', '', _('revision'), _('REV')),
834 ('d', 'delete', False, _('delete a given bookmark')),
835 ('d', 'delete', False, _('delete a given bookmark')),
835 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
836 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
836 ('i', 'inactive', False, _('mark a bookmark inactive')),
837 ('i', 'inactive', False, _('mark a bookmark inactive')),
837 ] + formatteropts,
838 ] + formatteropts,
838 _('hg bookmarks [OPTIONS]... [NAME]...'))
839 _('hg bookmarks [OPTIONS]... [NAME]...'))
839 def bookmark(ui, repo, *names, **opts):
840 def bookmark(ui, repo, *names, **opts):
840 '''create a new bookmark or list existing bookmarks
841 '''create a new bookmark or list existing bookmarks
841
842
842 Bookmarks are labels on changesets to help track lines of development.
843 Bookmarks are labels on changesets to help track lines of development.
843 Bookmarks are unversioned and can be moved, renamed and deleted.
844 Bookmarks are unversioned and can be moved, renamed and deleted.
844 Deleting or moving a bookmark has no effect on the associated changesets.
845 Deleting or moving a bookmark has no effect on the associated changesets.
845
846
846 Creating or updating to a bookmark causes it to be marked as 'active'.
847 Creating or updating to a bookmark causes it to be marked as 'active'.
847 The active bookmark is indicated with a '*'.
848 The active bookmark is indicated with a '*'.
848 When a commit is made, the active bookmark will advance to the new commit.
849 When a commit is made, the active bookmark will advance to the new commit.
849 A plain :hg:`update` will also advance an active bookmark, if possible.
850 A plain :hg:`update` will also advance an active bookmark, if possible.
850 Updating away from a bookmark will cause it to be deactivated.
851 Updating away from a bookmark will cause it to be deactivated.
851
852
852 Bookmarks can be pushed and pulled between repositories (see
853 Bookmarks can be pushed and pulled between repositories (see
853 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
854 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
854 diverged, a new 'divergent bookmark' of the form 'name@path' will
855 diverged, a new 'divergent bookmark' of the form 'name@path' will
855 be created. Using :hg:'merge' will resolve the divergence.
856 be created. Using :hg:'merge' will resolve the divergence.
856
857
857 A bookmark named '@' has the special property that :hg:`clone` will
858 A bookmark named '@' has the special property that :hg:`clone` will
858 check it out by default if it exists.
859 check it out by default if it exists.
859
860
860 .. container:: verbose
861 .. container:: verbose
861
862
862 Examples:
863 Examples:
863
864
864 - create an active bookmark for a new line of development::
865 - create an active bookmark for a new line of development::
865
866
866 hg book new-feature
867 hg book new-feature
867
868
868 - create an inactive bookmark as a place marker::
869 - create an inactive bookmark as a place marker::
869
870
870 hg book -i reviewed
871 hg book -i reviewed
871
872
872 - create an inactive bookmark on another changeset::
873 - create an inactive bookmark on another changeset::
873
874
874 hg book -r .^ tested
875 hg book -r .^ tested
875
876
876 - move the '@' bookmark from another branch::
877 - move the '@' bookmark from another branch::
877
878
878 hg book -f @
879 hg book -f @
879 '''
880 '''
880 force = opts.get('force')
881 force = opts.get('force')
881 rev = opts.get('rev')
882 rev = opts.get('rev')
882 delete = opts.get('delete')
883 delete = opts.get('delete')
883 rename = opts.get('rename')
884 rename = opts.get('rename')
884 inactive = opts.get('inactive')
885 inactive = opts.get('inactive')
885
886
886 def checkformat(mark):
887 def checkformat(mark):
887 mark = mark.strip()
888 mark = mark.strip()
888 if not mark:
889 if not mark:
889 raise util.Abort(_("bookmark names cannot consist entirely of "
890 raise util.Abort(_("bookmark names cannot consist entirely of "
890 "whitespace"))
891 "whitespace"))
891 scmutil.checknewlabel(repo, mark, 'bookmark')
892 scmutil.checknewlabel(repo, mark, 'bookmark')
892 return mark
893 return mark
893
894
894 def checkconflict(repo, mark, cur, force=False, target=None):
895 def checkconflict(repo, mark, cur, force=False, target=None):
895 if mark in marks and not force:
896 if mark in marks and not force:
896 if target:
897 if target:
897 if marks[mark] == target and target == cur:
898 if marks[mark] == target and target == cur:
898 # re-activating a bookmark
899 # re-activating a bookmark
899 return
900 return
900 anc = repo.changelog.ancestors([repo[target].rev()])
901 anc = repo.changelog.ancestors([repo[target].rev()])
901 bmctx = repo[marks[mark]]
902 bmctx = repo[marks[mark]]
902 divs = [repo[b].node() for b in marks
903 divs = [repo[b].node() for b in marks
903 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
904 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
904
905
905 # allow resolving a single divergent bookmark even if moving
906 # allow resolving a single divergent bookmark even if moving
906 # the bookmark across branches when a revision is specified
907 # the bookmark across branches when a revision is specified
907 # that contains a divergent bookmark
908 # that contains a divergent bookmark
908 if bmctx.rev() not in anc and target in divs:
909 if bmctx.rev() not in anc and target in divs:
909 bookmarks.deletedivergent(repo, [target], mark)
910 bookmarks.deletedivergent(repo, [target], mark)
910 return
911 return
911
912
912 deletefrom = [b for b in divs
913 deletefrom = [b for b in divs
913 if repo[b].rev() in anc or b == target]
914 if repo[b].rev() in anc or b == target]
914 bookmarks.deletedivergent(repo, deletefrom, mark)
915 bookmarks.deletedivergent(repo, deletefrom, mark)
915 if bookmarks.validdest(repo, bmctx, repo[target]):
916 if bookmarks.validdest(repo, bmctx, repo[target]):
916 ui.status(_("moving bookmark '%s' forward from %s\n") %
917 ui.status(_("moving bookmark '%s' forward from %s\n") %
917 (mark, short(bmctx.node())))
918 (mark, short(bmctx.node())))
918 return
919 return
919 raise util.Abort(_("bookmark '%s' already exists "
920 raise util.Abort(_("bookmark '%s' already exists "
920 "(use -f to force)") % mark)
921 "(use -f to force)") % mark)
921 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
922 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
922 and not force):
923 and not force):
923 raise util.Abort(
924 raise util.Abort(
924 _("a bookmark cannot have the name of an existing branch"))
925 _("a bookmark cannot have the name of an existing branch"))
925
926
926 if delete and rename:
927 if delete and rename:
927 raise util.Abort(_("--delete and --rename are incompatible"))
928 raise util.Abort(_("--delete and --rename are incompatible"))
928 if delete and rev:
929 if delete and rev:
929 raise util.Abort(_("--rev is incompatible with --delete"))
930 raise util.Abort(_("--rev is incompatible with --delete"))
930 if rename and rev:
931 if rename and rev:
931 raise util.Abort(_("--rev is incompatible with --rename"))
932 raise util.Abort(_("--rev is incompatible with --rename"))
932 if not names and (delete or rev):
933 if not names and (delete or rev):
933 raise util.Abort(_("bookmark name required"))
934 raise util.Abort(_("bookmark name required"))
934
935
935 if delete or rename or names or inactive:
936 if delete or rename or names or inactive:
936 wlock = repo.wlock()
937 wlock = repo.wlock()
937 try:
938 try:
938 cur = repo.changectx('.').node()
939 cur = repo.changectx('.').node()
939 marks = repo._bookmarks
940 marks = repo._bookmarks
940 if delete:
941 if delete:
941 for mark in names:
942 for mark in names:
942 if mark not in marks:
943 if mark not in marks:
943 raise util.Abort(_("bookmark '%s' does not exist") %
944 raise util.Abort(_("bookmark '%s' does not exist") %
944 mark)
945 mark)
945 if mark == repo._bookmarkcurrent:
946 if mark == repo._bookmarkcurrent:
946 bookmarks.unsetcurrent(repo)
947 bookmarks.unsetcurrent(repo)
947 del marks[mark]
948 del marks[mark]
948 marks.write()
949 marks.write()
949
950
950 elif rename:
951 elif rename:
951 if not names:
952 if not names:
952 raise util.Abort(_("new bookmark name required"))
953 raise util.Abort(_("new bookmark name required"))
953 elif len(names) > 1:
954 elif len(names) > 1:
954 raise util.Abort(_("only one new bookmark name allowed"))
955 raise util.Abort(_("only one new bookmark name allowed"))
955 mark = checkformat(names[0])
956 mark = checkformat(names[0])
956 if rename not in marks:
957 if rename not in marks:
957 raise util.Abort(_("bookmark '%s' does not exist") % rename)
958 raise util.Abort(_("bookmark '%s' does not exist") % rename)
958 checkconflict(repo, mark, cur, force)
959 checkconflict(repo, mark, cur, force)
959 marks[mark] = marks[rename]
960 marks[mark] = marks[rename]
960 if repo._bookmarkcurrent == rename and not inactive:
961 if repo._bookmarkcurrent == rename and not inactive:
961 bookmarks.setcurrent(repo, mark)
962 bookmarks.setcurrent(repo, mark)
962 del marks[rename]
963 del marks[rename]
963 marks.write()
964 marks.write()
964
965
965 elif names:
966 elif names:
966 newact = None
967 newact = None
967 for mark in names:
968 for mark in names:
968 mark = checkformat(mark)
969 mark = checkformat(mark)
969 if newact is None:
970 if newact is None:
970 newact = mark
971 newact = mark
971 if inactive and mark == repo._bookmarkcurrent:
972 if inactive and mark == repo._bookmarkcurrent:
972 bookmarks.unsetcurrent(repo)
973 bookmarks.unsetcurrent(repo)
973 return
974 return
974 tgt = cur
975 tgt = cur
975 if rev:
976 if rev:
976 tgt = scmutil.revsingle(repo, rev).node()
977 tgt = scmutil.revsingle(repo, rev).node()
977 checkconflict(repo, mark, cur, force, tgt)
978 checkconflict(repo, mark, cur, force, tgt)
978 marks[mark] = tgt
979 marks[mark] = tgt
979 if not inactive and cur == marks[newact] and not rev:
980 if not inactive and cur == marks[newact] and not rev:
980 bookmarks.setcurrent(repo, newact)
981 bookmarks.setcurrent(repo, newact)
981 elif cur != tgt and newact == repo._bookmarkcurrent:
982 elif cur != tgt and newact == repo._bookmarkcurrent:
982 bookmarks.unsetcurrent(repo)
983 bookmarks.unsetcurrent(repo)
983 marks.write()
984 marks.write()
984
985
985 elif inactive:
986 elif inactive:
986 if len(marks) == 0:
987 if len(marks) == 0:
987 ui.status(_("no bookmarks set\n"))
988 ui.status(_("no bookmarks set\n"))
988 elif not repo._bookmarkcurrent:
989 elif not repo._bookmarkcurrent:
989 ui.status(_("no active bookmark\n"))
990 ui.status(_("no active bookmark\n"))
990 else:
991 else:
991 bookmarks.unsetcurrent(repo)
992 bookmarks.unsetcurrent(repo)
992 finally:
993 finally:
993 wlock.release()
994 wlock.release()
994 else: # show bookmarks
995 else: # show bookmarks
995 fm = ui.formatter('bookmarks', opts)
996 fm = ui.formatter('bookmarks', opts)
996 hexfn = fm.hexfunc
997 hexfn = fm.hexfunc
997 marks = repo._bookmarks
998 marks = repo._bookmarks
998 if len(marks) == 0 and not fm:
999 if len(marks) == 0 and not fm:
999 ui.status(_("no bookmarks set\n"))
1000 ui.status(_("no bookmarks set\n"))
1000 for bmark, n in sorted(marks.iteritems()):
1001 for bmark, n in sorted(marks.iteritems()):
1001 current = repo._bookmarkcurrent
1002 current = repo._bookmarkcurrent
1002 if bmark == current:
1003 if bmark == current:
1003 prefix, label = '*', 'bookmarks.current'
1004 prefix, label = '*', 'bookmarks.current'
1004 else:
1005 else:
1005 prefix, label = ' ', ''
1006 prefix, label = ' ', ''
1006
1007
1007 fm.startitem()
1008 fm.startitem()
1008 if not ui.quiet:
1009 if not ui.quiet:
1009 fm.plain(' %s ' % prefix, label=label)
1010 fm.plain(' %s ' % prefix, label=label)
1010 fm.write('bookmark', '%s', bmark, label=label)
1011 fm.write('bookmark', '%s', bmark, label=label)
1011 pad = " " * (25 - encoding.colwidth(bmark))
1012 pad = " " * (25 - encoding.colwidth(bmark))
1012 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1013 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1013 repo.changelog.rev(n), hexfn(n), label=label)
1014 repo.changelog.rev(n), hexfn(n), label=label)
1014 fm.data(active=(bmark == current))
1015 fm.data(active=(bmark == current))
1015 fm.plain('\n')
1016 fm.plain('\n')
1016 fm.end()
1017 fm.end()
1017
1018
1018 @command('branch',
1019 @command('branch',
1019 [('f', 'force', None,
1020 [('f', 'force', None,
1020 _('set branch name even if it shadows an existing branch')),
1021 _('set branch name even if it shadows an existing branch')),
1021 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1022 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1022 _('[-fC] [NAME]'))
1023 _('[-fC] [NAME]'))
1023 def branch(ui, repo, label=None, **opts):
1024 def branch(ui, repo, label=None, **opts):
1024 """set or show the current branch name
1025 """set or show the current branch name
1025
1026
1026 .. note::
1027 .. note::
1027
1028
1028 Branch names are permanent and global. Use :hg:`bookmark` to create a
1029 Branch names are permanent and global. Use :hg:`bookmark` to create a
1029 light-weight bookmark instead. See :hg:`help glossary` for more
1030 light-weight bookmark instead. See :hg:`help glossary` for more
1030 information about named branches and bookmarks.
1031 information about named branches and bookmarks.
1031
1032
1032 With no argument, show the current branch name. With one argument,
1033 With no argument, show the current branch name. With one argument,
1033 set the working directory branch name (the branch will not exist
1034 set the working directory branch name (the branch will not exist
1034 in the repository until the next commit). Standard practice
1035 in the repository until the next commit). Standard practice
1035 recommends that primary development take place on the 'default'
1036 recommends that primary development take place on the 'default'
1036 branch.
1037 branch.
1037
1038
1038 Unless -f/--force is specified, branch will not let you set a
1039 Unless -f/--force is specified, branch will not let you set a
1039 branch name that already exists, even if it's inactive.
1040 branch name that already exists, even if it's inactive.
1040
1041
1041 Use -C/--clean to reset the working directory branch to that of
1042 Use -C/--clean to reset the working directory branch to that of
1042 the parent of the working directory, negating a previous branch
1043 the parent of the working directory, negating a previous branch
1043 change.
1044 change.
1044
1045
1045 Use the command :hg:`update` to switch to an existing branch. Use
1046 Use the command :hg:`update` to switch to an existing branch. Use
1046 :hg:`commit --close-branch` to mark this branch as closed.
1047 :hg:`commit --close-branch` to mark this branch as closed.
1047
1048
1048 Returns 0 on success.
1049 Returns 0 on success.
1049 """
1050 """
1050 if label:
1051 if label:
1051 label = label.strip()
1052 label = label.strip()
1052
1053
1053 if not opts.get('clean') and not label:
1054 if not opts.get('clean') and not label:
1054 ui.write("%s\n" % repo.dirstate.branch())
1055 ui.write("%s\n" % repo.dirstate.branch())
1055 return
1056 return
1056
1057
1057 wlock = repo.wlock()
1058 wlock = repo.wlock()
1058 try:
1059 try:
1059 if opts.get('clean'):
1060 if opts.get('clean'):
1060 label = repo[None].p1().branch()
1061 label = repo[None].p1().branch()
1061 repo.dirstate.setbranch(label)
1062 repo.dirstate.setbranch(label)
1062 ui.status(_('reset working directory to branch %s\n') % label)
1063 ui.status(_('reset working directory to branch %s\n') % label)
1063 elif label:
1064 elif label:
1064 if not opts.get('force') and label in repo.branchmap():
1065 if not opts.get('force') and label in repo.branchmap():
1065 if label not in [p.branch() for p in repo.parents()]:
1066 if label not in [p.branch() for p in repo.parents()]:
1066 raise util.Abort(_('a branch of the same name already'
1067 raise util.Abort(_('a branch of the same name already'
1067 ' exists'),
1068 ' exists'),
1068 # i18n: "it" refers to an existing branch
1069 # i18n: "it" refers to an existing branch
1069 hint=_("use 'hg update' to switch to it"))
1070 hint=_("use 'hg update' to switch to it"))
1070 scmutil.checknewlabel(repo, label, 'branch')
1071 scmutil.checknewlabel(repo, label, 'branch')
1071 repo.dirstate.setbranch(label)
1072 repo.dirstate.setbranch(label)
1072 ui.status(_('marked working directory as branch %s\n') % label)
1073 ui.status(_('marked working directory as branch %s\n') % label)
1073 ui.status(_('(branches are permanent and global, '
1074 ui.status(_('(branches are permanent and global, '
1074 'did you want a bookmark?)\n'))
1075 'did you want a bookmark?)\n'))
1075 finally:
1076 finally:
1076 wlock.release()
1077 wlock.release()
1077
1078
1078 @command('branches',
1079 @command('branches',
1079 [('a', 'active', False, _('show only branches that have unmerged heads')),
1080 [('a', 'active', False, _('show only branches that have unmerged heads')),
1080 ('c', 'closed', False, _('show normal and closed branches')),
1081 ('c', 'closed', False, _('show normal and closed branches')),
1081 ] + formatteropts,
1082 ] + formatteropts,
1082 _('[-ac]'))
1083 _('[-ac]'))
1083 def branches(ui, repo, active=False, closed=False, **opts):
1084 def branches(ui, repo, active=False, closed=False, **opts):
1084 """list repository named branches
1085 """list repository named branches
1085
1086
1086 List the repository's named branches, indicating which ones are
1087 List the repository's named branches, indicating which ones are
1087 inactive. If -c/--closed is specified, also list branches which have
1088 inactive. If -c/--closed is specified, also list branches which have
1088 been marked closed (see :hg:`commit --close-branch`).
1089 been marked closed (see :hg:`commit --close-branch`).
1089
1090
1090 If -a/--active is specified, only show active branches. A branch
1091 If -a/--active is specified, only show active branches. A branch
1091 is considered active if it contains repository heads.
1092 is considered active if it contains repository heads.
1092
1093
1093 Use the command :hg:`update` to switch to an existing branch.
1094 Use the command :hg:`update` to switch to an existing branch.
1094
1095
1095 Returns 0.
1096 Returns 0.
1096 """
1097 """
1097
1098
1098 fm = ui.formatter('branches', opts)
1099 fm = ui.formatter('branches', opts)
1099 hexfunc = fm.hexfunc
1100 hexfunc = fm.hexfunc
1100
1101
1101 allheads = set(repo.heads())
1102 allheads = set(repo.heads())
1102 branches = []
1103 branches = []
1103 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1104 isactive = not isclosed and bool(set(heads) & allheads)
1105 isactive = not isclosed and bool(set(heads) & allheads)
1105 branches.append((tag, repo[tip], isactive, not isclosed))
1106 branches.append((tag, repo[tip], isactive, not isclosed))
1106 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1107 reverse=True)
1108 reverse=True)
1108
1109
1109 for tag, ctx, isactive, isopen in branches:
1110 for tag, ctx, isactive, isopen in branches:
1110 if active and not isactive:
1111 if active and not isactive:
1111 continue
1112 continue
1112 if isactive:
1113 if isactive:
1113 label = 'branches.active'
1114 label = 'branches.active'
1114 notice = ''
1115 notice = ''
1115 elif not isopen:
1116 elif not isopen:
1116 if not closed:
1117 if not closed:
1117 continue
1118 continue
1118 label = 'branches.closed'
1119 label = 'branches.closed'
1119 notice = _(' (closed)')
1120 notice = _(' (closed)')
1120 else:
1121 else:
1121 label = 'branches.inactive'
1122 label = 'branches.inactive'
1122 notice = _(' (inactive)')
1123 notice = _(' (inactive)')
1123 current = (tag == repo.dirstate.branch())
1124 current = (tag == repo.dirstate.branch())
1124 if current:
1125 if current:
1125 label = 'branches.current'
1126 label = 'branches.current'
1126
1127
1127 fm.startitem()
1128 fm.startitem()
1128 fm.write('branch', '%s', tag, label=label)
1129 fm.write('branch', '%s', tag, label=label)
1129 rev = ctx.rev()
1130 rev = ctx.rev()
1130 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1131 fmt = ' ' * padsize + ' %d:%s'
1132 fmt = ' ' * padsize + ' %d:%s'
1132 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1133 label='log.changeset changeset.%s' % ctx.phasestr())
1134 label='log.changeset changeset.%s' % ctx.phasestr())
1134 fm.data(active=isactive, closed=not isopen, current=current)
1135 fm.data(active=isactive, closed=not isopen, current=current)
1135 if not ui.quiet:
1136 if not ui.quiet:
1136 fm.plain(notice)
1137 fm.plain(notice)
1137 fm.plain('\n')
1138 fm.plain('\n')
1138 fm.end()
1139 fm.end()
1139
1140
1140 @command('bundle',
1141 @command('bundle',
1141 [('f', 'force', None, _('run even when the destination is unrelated')),
1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1142 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1143 _('REV')),
1144 _('REV')),
1144 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1145 _('BRANCH')),
1146 _('BRANCH')),
1146 ('', 'base', [],
1147 ('', 'base', [],
1147 _('a base changeset assumed to be available at the destination'),
1148 _('a base changeset assumed to be available at the destination'),
1148 _('REV')),
1149 _('REV')),
1149 ('a', 'all', None, _('bundle all changesets in the repository')),
1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1150 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1151 ] + remoteopts,
1152 ] + remoteopts,
1152 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1153 def bundle(ui, repo, fname, dest=None, **opts):
1154 def bundle(ui, repo, fname, dest=None, **opts):
1154 """create a changegroup file
1155 """create a changegroup file
1155
1156
1156 Generate a compressed changegroup file collecting changesets not
1157 Generate a compressed changegroup file collecting changesets not
1157 known to be in another repository.
1158 known to be in another repository.
1158
1159
1159 If you omit the destination repository, then hg assumes the
1160 If you omit the destination repository, then hg assumes the
1160 destination will have all the nodes you specify with --base
1161 destination will have all the nodes you specify with --base
1161 parameters. To create a bundle containing all changesets, use
1162 parameters. To create a bundle containing all changesets, use
1162 -a/--all (or --base null).
1163 -a/--all (or --base null).
1163
1164
1164 You can change compression method with the -t/--type option.
1165 You can change compression method with the -t/--type option.
1165 The available compression methods are: none, bzip2, and
1166 The available compression methods are: none, bzip2, and
1166 gzip (by default, bundles are compressed using bzip2).
1167 gzip (by default, bundles are compressed using bzip2).
1167
1168
1168 The bundle file can then be transferred using conventional means
1169 The bundle file can then be transferred using conventional means
1169 and applied to another repository with the unbundle or pull
1170 and applied to another repository with the unbundle or pull
1170 command. This is useful when direct push and pull are not
1171 command. This is useful when direct push and pull are not
1171 available or when exporting an entire repository is undesirable.
1172 available or when exporting an entire repository is undesirable.
1172
1173
1173 Applying bundles preserves all changeset contents including
1174 Applying bundles preserves all changeset contents including
1174 permissions, copy/rename information, and revision history.
1175 permissions, copy/rename information, and revision history.
1175
1176
1176 Returns 0 on success, 1 if no changes found.
1177 Returns 0 on success, 1 if no changes found.
1177 """
1178 """
1178 revs = None
1179 revs = None
1179 if 'rev' in opts:
1180 if 'rev' in opts:
1180 revs = scmutil.revrange(repo, opts['rev'])
1181 revs = scmutil.revrange(repo, opts['rev'])
1181
1182
1182 bundletype = opts.get('type', 'bzip2').lower()
1183 bundletype = opts.get('type', 'bzip2').lower()
1183 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1184 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1184 bundletype = btypes.get(bundletype)
1185 bundletype = btypes.get(bundletype)
1185 if bundletype not in changegroup.bundletypes:
1186 if bundletype not in changegroup.bundletypes:
1186 raise util.Abort(_('unknown bundle type specified with --type'))
1187 raise util.Abort(_('unknown bundle type specified with --type'))
1187
1188
1188 if opts.get('all'):
1189 if opts.get('all'):
1189 base = ['null']
1190 base = ['null']
1190 else:
1191 else:
1191 base = scmutil.revrange(repo, opts.get('base'))
1192 base = scmutil.revrange(repo, opts.get('base'))
1192 # TODO: get desired bundlecaps from command line.
1193 # TODO: get desired bundlecaps from command line.
1193 bundlecaps = None
1194 bundlecaps = None
1194 if base:
1195 if base:
1195 if dest:
1196 if dest:
1196 raise util.Abort(_("--base is incompatible with specifying "
1197 raise util.Abort(_("--base is incompatible with specifying "
1197 "a destination"))
1198 "a destination"))
1198 common = [repo.lookup(rev) for rev in base]
1199 common = [repo.lookup(rev) for rev in base]
1199 heads = revs and map(repo.lookup, revs) or revs
1200 heads = revs and map(repo.lookup, revs) or revs
1200 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1201 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1201 common=common, bundlecaps=bundlecaps)
1202 common=common, bundlecaps=bundlecaps)
1202 outgoing = None
1203 outgoing = None
1203 else:
1204 else:
1204 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1205 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1205 dest, branches = hg.parseurl(dest, opts.get('branch'))
1206 dest, branches = hg.parseurl(dest, opts.get('branch'))
1206 other = hg.peer(repo, opts, dest)
1207 other = hg.peer(repo, opts, dest)
1207 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1208 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1208 heads = revs and map(repo.lookup, revs) or revs
1209 heads = revs and map(repo.lookup, revs) or revs
1209 outgoing = discovery.findcommonoutgoing(repo, other,
1210 outgoing = discovery.findcommonoutgoing(repo, other,
1210 onlyheads=heads,
1211 onlyheads=heads,
1211 force=opts.get('force'),
1212 force=opts.get('force'),
1212 portable=True)
1213 portable=True)
1213 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1214 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1214 bundlecaps)
1215 bundlecaps)
1215 if not cg:
1216 if not cg:
1216 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1217 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1217 return 1
1218 return 1
1218
1219
1219 changegroup.writebundle(cg, fname, bundletype)
1220 changegroup.writebundle(cg, fname, bundletype)
1220
1221
1221 @command('cat',
1222 @command('cat',
1222 [('o', 'output', '',
1223 [('o', 'output', '',
1223 _('print output to file with formatted name'), _('FORMAT')),
1224 _('print output to file with formatted name'), _('FORMAT')),
1224 ('r', 'rev', '', _('print the given revision'), _('REV')),
1225 ('r', 'rev', '', _('print the given revision'), _('REV')),
1225 ('', 'decode', None, _('apply any matching decode filter')),
1226 ('', 'decode', None, _('apply any matching decode filter')),
1226 ] + walkopts,
1227 ] + walkopts,
1227 _('[OPTION]... FILE...'),
1228 _('[OPTION]... FILE...'),
1228 inferrepo=True)
1229 inferrepo=True)
1229 def cat(ui, repo, file1, *pats, **opts):
1230 def cat(ui, repo, file1, *pats, **opts):
1230 """output the current or given revision of files
1231 """output the current or given revision of files
1231
1232
1232 Print the specified files as they were at the given revision. If
1233 Print the specified files as they were at the given revision. If
1233 no revision is given, the parent of the working directory is used.
1234 no revision is given, the parent of the working directory is used.
1234
1235
1235 Output may be to a file, in which case the name of the file is
1236 Output may be to a file, in which case the name of the file is
1236 given using a format string. The formatting rules as follows:
1237 given using a format string. The formatting rules as follows:
1237
1238
1238 :``%%``: literal "%" character
1239 :``%%``: literal "%" character
1239 :``%s``: basename of file being printed
1240 :``%s``: basename of file being printed
1240 :``%d``: dirname of file being printed, or '.' if in repository root
1241 :``%d``: dirname of file being printed, or '.' if in repository root
1241 :``%p``: root-relative path name of file being printed
1242 :``%p``: root-relative path name of file being printed
1242 :``%H``: changeset hash (40 hexadecimal digits)
1243 :``%H``: changeset hash (40 hexadecimal digits)
1243 :``%R``: changeset revision number
1244 :``%R``: changeset revision number
1244 :``%h``: short-form changeset hash (12 hexadecimal digits)
1245 :``%h``: short-form changeset hash (12 hexadecimal digits)
1245 :``%r``: zero-padded changeset revision number
1246 :``%r``: zero-padded changeset revision number
1246 :``%b``: basename of the exporting repository
1247 :``%b``: basename of the exporting repository
1247
1248
1248 Returns 0 on success.
1249 Returns 0 on success.
1249 """
1250 """
1250 ctx = scmutil.revsingle(repo, opts.get('rev'))
1251 ctx = scmutil.revsingle(repo, opts.get('rev'))
1251 m = scmutil.match(ctx, (file1,) + pats, opts)
1252 m = scmutil.match(ctx, (file1,) + pats, opts)
1252
1253
1253 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1254 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1254
1255
1255 @command('^clone',
1256 @command('^clone',
1256 [('U', 'noupdate', None,
1257 [('U', 'noupdate', None,
1257 _('the clone will include an empty working copy (only a repository)')),
1258 _('the clone will include an empty working copy (only a repository)')),
1258 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1259 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1259 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1260 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1260 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1261 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1261 ('', 'pull', None, _('use pull protocol to copy metadata')),
1262 ('', 'pull', None, _('use pull protocol to copy metadata')),
1262 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1263 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1263 ] + remoteopts,
1264 ] + remoteopts,
1264 _('[OPTION]... SOURCE [DEST]'),
1265 _('[OPTION]... SOURCE [DEST]'),
1265 norepo=True)
1266 norepo=True)
1266 def clone(ui, source, dest=None, **opts):
1267 def clone(ui, source, dest=None, **opts):
1267 """make a copy of an existing repository
1268 """make a copy of an existing repository
1268
1269
1269 Create a copy of an existing repository in a new directory.
1270 Create a copy of an existing repository in a new directory.
1270
1271
1271 If no destination directory name is specified, it defaults to the
1272 If no destination directory name is specified, it defaults to the
1272 basename of the source.
1273 basename of the source.
1273
1274
1274 The location of the source is added to the new repository's
1275 The location of the source is added to the new repository's
1275 ``.hg/hgrc`` file, as the default to be used for future pulls.
1276 ``.hg/hgrc`` file, as the default to be used for future pulls.
1276
1277
1277 Only local paths and ``ssh://`` URLs are supported as
1278 Only local paths and ``ssh://`` URLs are supported as
1278 destinations. For ``ssh://`` destinations, no working directory or
1279 destinations. For ``ssh://`` destinations, no working directory or
1279 ``.hg/hgrc`` will be created on the remote side.
1280 ``.hg/hgrc`` will be created on the remote side.
1280
1281
1281 To pull only a subset of changesets, specify one or more revisions
1282 To pull only a subset of changesets, specify one or more revisions
1282 identifiers with -r/--rev or branches with -b/--branch. The
1283 identifiers with -r/--rev or branches with -b/--branch. The
1283 resulting clone will contain only the specified changesets and
1284 resulting clone will contain only the specified changesets and
1284 their ancestors. These options (or 'clone src#rev dest') imply
1285 their ancestors. These options (or 'clone src#rev dest') imply
1285 --pull, even for local source repositories. Note that specifying a
1286 --pull, even for local source repositories. Note that specifying a
1286 tag will include the tagged changeset but not the changeset
1287 tag will include the tagged changeset but not the changeset
1287 containing the tag.
1288 containing the tag.
1288
1289
1289 If the source repository has a bookmark called '@' set, that
1290 If the source repository has a bookmark called '@' set, that
1290 revision will be checked out in the new repository by default.
1291 revision will be checked out in the new repository by default.
1291
1292
1292 To check out a particular version, use -u/--update, or
1293 To check out a particular version, use -u/--update, or
1293 -U/--noupdate to create a clone with no working directory.
1294 -U/--noupdate to create a clone with no working directory.
1294
1295
1295 .. container:: verbose
1296 .. container:: verbose
1296
1297
1297 For efficiency, hardlinks are used for cloning whenever the
1298 For efficiency, hardlinks are used for cloning whenever the
1298 source and destination are on the same filesystem (note this
1299 source and destination are on the same filesystem (note this
1299 applies only to the repository data, not to the working
1300 applies only to the repository data, not to the working
1300 directory). Some filesystems, such as AFS, implement hardlinking
1301 directory). Some filesystems, such as AFS, implement hardlinking
1301 incorrectly, but do not report errors. In these cases, use the
1302 incorrectly, but do not report errors. In these cases, use the
1302 --pull option to avoid hardlinking.
1303 --pull option to avoid hardlinking.
1303
1304
1304 In some cases, you can clone repositories and the working
1305 In some cases, you can clone repositories and the working
1305 directory using full hardlinks with ::
1306 directory using full hardlinks with ::
1306
1307
1307 $ cp -al REPO REPOCLONE
1308 $ cp -al REPO REPOCLONE
1308
1309
1309 This is the fastest way to clone, but it is not always safe. The
1310 This is the fastest way to clone, but it is not always safe. The
1310 operation is not atomic (making sure REPO is not modified during
1311 operation is not atomic (making sure REPO is not modified during
1311 the operation is up to you) and you have to make sure your
1312 the operation is up to you) and you have to make sure your
1312 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1313 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1313 so). Also, this is not compatible with certain extensions that
1314 so). Also, this is not compatible with certain extensions that
1314 place their metadata under the .hg directory, such as mq.
1315 place their metadata under the .hg directory, such as mq.
1315
1316
1316 Mercurial will update the working directory to the first applicable
1317 Mercurial will update the working directory to the first applicable
1317 revision from this list:
1318 revision from this list:
1318
1319
1319 a) null if -U or the source repository has no changesets
1320 a) null if -U or the source repository has no changesets
1320 b) if -u . and the source repository is local, the first parent of
1321 b) if -u . and the source repository is local, the first parent of
1321 the source repository's working directory
1322 the source repository's working directory
1322 c) the changeset specified with -u (if a branch name, this means the
1323 c) the changeset specified with -u (if a branch name, this means the
1323 latest head of that branch)
1324 latest head of that branch)
1324 d) the changeset specified with -r
1325 d) the changeset specified with -r
1325 e) the tipmost head specified with -b
1326 e) the tipmost head specified with -b
1326 f) the tipmost head specified with the url#branch source syntax
1327 f) the tipmost head specified with the url#branch source syntax
1327 g) the revision marked with the '@' bookmark, if present
1328 g) the revision marked with the '@' bookmark, if present
1328 h) the tipmost head of the default branch
1329 h) the tipmost head of the default branch
1329 i) tip
1330 i) tip
1330
1331
1331 Examples:
1332 Examples:
1332
1333
1333 - clone a remote repository to a new directory named hg/::
1334 - clone a remote repository to a new directory named hg/::
1334
1335
1335 hg clone http://selenic.com/hg
1336 hg clone http://selenic.com/hg
1336
1337
1337 - create a lightweight local clone::
1338 - create a lightweight local clone::
1338
1339
1339 hg clone project/ project-feature/
1340 hg clone project/ project-feature/
1340
1341
1341 - clone from an absolute path on an ssh server (note double-slash)::
1342 - clone from an absolute path on an ssh server (note double-slash)::
1342
1343
1343 hg clone ssh://user@server//home/projects/alpha/
1344 hg clone ssh://user@server//home/projects/alpha/
1344
1345
1345 - do a high-speed clone over a LAN while checking out a
1346 - do a high-speed clone over a LAN while checking out a
1346 specified version::
1347 specified version::
1347
1348
1348 hg clone --uncompressed http://server/repo -u 1.5
1349 hg clone --uncompressed http://server/repo -u 1.5
1349
1350
1350 - create a repository without changesets after a particular revision::
1351 - create a repository without changesets after a particular revision::
1351
1352
1352 hg clone -r 04e544 experimental/ good/
1353 hg clone -r 04e544 experimental/ good/
1353
1354
1354 - clone (and track) a particular named branch::
1355 - clone (and track) a particular named branch::
1355
1356
1356 hg clone http://selenic.com/hg#stable
1357 hg clone http://selenic.com/hg#stable
1357
1358
1358 See :hg:`help urls` for details on specifying URLs.
1359 See :hg:`help urls` for details on specifying URLs.
1359
1360
1360 Returns 0 on success.
1361 Returns 0 on success.
1361 """
1362 """
1362 if opts.get('noupdate') and opts.get('updaterev'):
1363 if opts.get('noupdate') and opts.get('updaterev'):
1363 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1364 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1364
1365
1365 r = hg.clone(ui, opts, source, dest,
1366 r = hg.clone(ui, opts, source, dest,
1366 pull=opts.get('pull'),
1367 pull=opts.get('pull'),
1367 stream=opts.get('uncompressed'),
1368 stream=opts.get('uncompressed'),
1368 rev=opts.get('rev'),
1369 rev=opts.get('rev'),
1369 update=opts.get('updaterev') or not opts.get('noupdate'),
1370 update=opts.get('updaterev') or not opts.get('noupdate'),
1370 branch=opts.get('branch'))
1371 branch=opts.get('branch'))
1371
1372
1372 return r is None
1373 return r is None
1373
1374
1374 @command('^commit|ci',
1375 @command('^commit|ci',
1375 [('A', 'addremove', None,
1376 [('A', 'addremove', None,
1376 _('mark new/missing files as added/removed before committing')),
1377 _('mark new/missing files as added/removed before committing')),
1377 ('', 'close-branch', None,
1378 ('', 'close-branch', None,
1378 _('mark a branch as closed, hiding it from the branch list')),
1379 _('mark a branch as closed, hiding it from the branch list')),
1379 ('', 'amend', None, _('amend the parent of the working dir')),
1380 ('', 'amend', None, _('amend the parent of the working dir')),
1380 ('s', 'secret', None, _('use the secret phase for committing')),
1381 ('s', 'secret', None, _('use the secret phase for committing')),
1381 ('e', 'edit', None, _('invoke editor on commit messages')),
1382 ('e', 'edit', None, _('invoke editor on commit messages')),
1382 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1383 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1383 _('[OPTION]... [FILE]...'),
1384 _('[OPTION]... [FILE]...'),
1384 inferrepo=True)
1385 inferrepo=True)
1385 def commit(ui, repo, *pats, **opts):
1386 def commit(ui, repo, *pats, **opts):
1386 """commit the specified files or all outstanding changes
1387 """commit the specified files or all outstanding changes
1387
1388
1388 Commit changes to the given files into the repository. Unlike a
1389 Commit changes to the given files into the repository. Unlike a
1389 centralized SCM, this operation is a local operation. See
1390 centralized SCM, this operation is a local operation. See
1390 :hg:`push` for a way to actively distribute your changes.
1391 :hg:`push` for a way to actively distribute your changes.
1391
1392
1392 If a list of files is omitted, all changes reported by :hg:`status`
1393 If a list of files is omitted, all changes reported by :hg:`status`
1393 will be committed.
1394 will be committed.
1394
1395
1395 If you are committing the result of a merge, do not provide any
1396 If you are committing the result of a merge, do not provide any
1396 filenames or -I/-X filters.
1397 filenames or -I/-X filters.
1397
1398
1398 If no commit message is specified, Mercurial starts your
1399 If no commit message is specified, Mercurial starts your
1399 configured editor where you can enter a message. In case your
1400 configured editor where you can enter a message. In case your
1400 commit fails, you will find a backup of your message in
1401 commit fails, you will find a backup of your message in
1401 ``.hg/last-message.txt``.
1402 ``.hg/last-message.txt``.
1402
1403
1403 The --amend flag can be used to amend the parent of the
1404 The --amend flag can be used to amend the parent of the
1404 working directory with a new commit that contains the changes
1405 working directory with a new commit that contains the changes
1405 in the parent in addition to those currently reported by :hg:`status`,
1406 in the parent in addition to those currently reported by :hg:`status`,
1406 if there are any. The old commit is stored in a backup bundle in
1407 if there are any. The old commit is stored in a backup bundle in
1407 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1408 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1408 on how to restore it).
1409 on how to restore it).
1409
1410
1410 Message, user and date are taken from the amended commit unless
1411 Message, user and date are taken from the amended commit unless
1411 specified. When a message isn't specified on the command line,
1412 specified. When a message isn't specified on the command line,
1412 the editor will open with the message of the amended commit.
1413 the editor will open with the message of the amended commit.
1413
1414
1414 It is not possible to amend public changesets (see :hg:`help phases`)
1415 It is not possible to amend public changesets (see :hg:`help phases`)
1415 or changesets that have children.
1416 or changesets that have children.
1416
1417
1417 See :hg:`help dates` for a list of formats valid for -d/--date.
1418 See :hg:`help dates` for a list of formats valid for -d/--date.
1418
1419
1419 Returns 0 on success, 1 if nothing changed.
1420 Returns 0 on success, 1 if nothing changed.
1420 """
1421 """
1421 if opts.get('subrepos'):
1422 if opts.get('subrepos'):
1422 if opts.get('amend'):
1423 if opts.get('amend'):
1423 raise util.Abort(_('cannot amend with --subrepos'))
1424 raise util.Abort(_('cannot amend with --subrepos'))
1424 # Let --subrepos on the command line override config setting.
1425 # Let --subrepos on the command line override config setting.
1425 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1426 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1426
1427
1427 cmdutil.checkunfinished(repo, commit=True)
1428 cmdutil.checkunfinished(repo, commit=True)
1428
1429
1429 branch = repo[None].branch()
1430 branch = repo[None].branch()
1430 bheads = repo.branchheads(branch)
1431 bheads = repo.branchheads(branch)
1431
1432
1432 extra = {}
1433 extra = {}
1433 if opts.get('close_branch'):
1434 if opts.get('close_branch'):
1434 extra['close'] = 1
1435 extra['close'] = 1
1435
1436
1436 if not bheads:
1437 if not bheads:
1437 raise util.Abort(_('can only close branch heads'))
1438 raise util.Abort(_('can only close branch heads'))
1438 elif opts.get('amend'):
1439 elif opts.get('amend'):
1439 if repo.parents()[0].p1().branch() != branch and \
1440 if repo.parents()[0].p1().branch() != branch and \
1440 repo.parents()[0].p2().branch() != branch:
1441 repo.parents()[0].p2().branch() != branch:
1441 raise util.Abort(_('can only close branch heads'))
1442 raise util.Abort(_('can only close branch heads'))
1442
1443
1443 if opts.get('amend'):
1444 if opts.get('amend'):
1444 if ui.configbool('ui', 'commitsubrepos'):
1445 if ui.configbool('ui', 'commitsubrepos'):
1445 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1446 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1446
1447
1447 old = repo['.']
1448 old = repo['.']
1448 if not old.mutable():
1449 if not old.mutable():
1449 raise util.Abort(_('cannot amend public changesets'))
1450 raise util.Abort(_('cannot amend public changesets'))
1450 if len(repo[None].parents()) > 1:
1451 if len(repo[None].parents()) > 1:
1451 raise util.Abort(_('cannot amend while merging'))
1452 raise util.Abort(_('cannot amend while merging'))
1452 if (not obsolete._enabled) and old.children():
1453 if (not obsolete._enabled) and old.children():
1453 raise util.Abort(_('cannot amend changeset with children'))
1454 raise util.Abort(_('cannot amend changeset with children'))
1454
1455
1455 # commitfunc is used only for temporary amend commit by cmdutil.amend
1456 # commitfunc is used only for temporary amend commit by cmdutil.amend
1456 def commitfunc(ui, repo, message, match, opts):
1457 def commitfunc(ui, repo, message, match, opts):
1457 return repo.commit(message,
1458 return repo.commit(message,
1458 opts.get('user') or old.user(),
1459 opts.get('user') or old.user(),
1459 opts.get('date') or old.date(),
1460 opts.get('date') or old.date(),
1460 match,
1461 match,
1461 extra=extra)
1462 extra=extra)
1462
1463
1463 current = repo._bookmarkcurrent
1464 current = repo._bookmarkcurrent
1464 marks = old.bookmarks()
1465 marks = old.bookmarks()
1465 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1466 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1466 if node == old.node():
1467 if node == old.node():
1467 ui.status(_("nothing changed\n"))
1468 ui.status(_("nothing changed\n"))
1468 return 1
1469 return 1
1469 elif marks:
1470 elif marks:
1470 ui.debug('moving bookmarks %r from %s to %s\n' %
1471 ui.debug('moving bookmarks %r from %s to %s\n' %
1471 (marks, old.hex(), hex(node)))
1472 (marks, old.hex(), hex(node)))
1472 newmarks = repo._bookmarks
1473 newmarks = repo._bookmarks
1473 for bm in marks:
1474 for bm in marks:
1474 newmarks[bm] = node
1475 newmarks[bm] = node
1475 if bm == current:
1476 if bm == current:
1476 bookmarks.setcurrent(repo, bm)
1477 bookmarks.setcurrent(repo, bm)
1477 newmarks.write()
1478 newmarks.write()
1478 else:
1479 else:
1479 def commitfunc(ui, repo, message, match, opts):
1480 def commitfunc(ui, repo, message, match, opts):
1480 backup = ui.backupconfig('phases', 'new-commit')
1481 backup = ui.backupconfig('phases', 'new-commit')
1481 baseui = repo.baseui
1482 baseui = repo.baseui
1482 basebackup = baseui.backupconfig('phases', 'new-commit')
1483 basebackup = baseui.backupconfig('phases', 'new-commit')
1483 try:
1484 try:
1484 if opts.get('secret'):
1485 if opts.get('secret'):
1485 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1486 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1486 # Propagate to subrepos
1487 # Propagate to subrepos
1487 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488
1489
1489 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1490 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1490 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1491 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1491 return repo.commit(message, opts.get('user'), opts.get('date'),
1492 return repo.commit(message, opts.get('user'), opts.get('date'),
1492 match,
1493 match,
1493 editor=editor,
1494 editor=editor,
1494 extra=extra)
1495 extra=extra)
1495 finally:
1496 finally:
1496 ui.restoreconfig(backup)
1497 ui.restoreconfig(backup)
1497 repo.baseui.restoreconfig(basebackup)
1498 repo.baseui.restoreconfig(basebackup)
1498
1499
1499
1500
1500 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1501 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1501
1502
1502 if not node:
1503 if not node:
1503 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1504 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1504 if stat[3]:
1505 if stat[3]:
1505 ui.status(_("nothing changed (%d missing files, see "
1506 ui.status(_("nothing changed (%d missing files, see "
1506 "'hg status')\n") % len(stat[3]))
1507 "'hg status')\n") % len(stat[3]))
1507 else:
1508 else:
1508 ui.status(_("nothing changed\n"))
1509 ui.status(_("nothing changed\n"))
1509 return 1
1510 return 1
1510
1511
1511 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1512 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1512
1513
1513 @command('config|showconfig|debugconfig',
1514 @command('config|showconfig|debugconfig',
1514 [('u', 'untrusted', None, _('show untrusted configuration options')),
1515 [('u', 'untrusted', None, _('show untrusted configuration options')),
1515 ('e', 'edit', None, _('edit user config')),
1516 ('e', 'edit', None, _('edit user config')),
1516 ('l', 'local', None, _('edit repository config')),
1517 ('l', 'local', None, _('edit repository config')),
1517 ('g', 'global', None, _('edit global config'))],
1518 ('g', 'global', None, _('edit global config'))],
1518 _('[-u] [NAME]...'),
1519 _('[-u] [NAME]...'),
1519 optionalrepo=True)
1520 optionalrepo=True)
1520 def config(ui, repo, *values, **opts):
1521 def config(ui, repo, *values, **opts):
1521 """show combined config settings from all hgrc files
1522 """show combined config settings from all hgrc files
1522
1523
1523 With no arguments, print names and values of all config items.
1524 With no arguments, print names and values of all config items.
1524
1525
1525 With one argument of the form section.name, print just the value
1526 With one argument of the form section.name, print just the value
1526 of that config item.
1527 of that config item.
1527
1528
1528 With multiple arguments, print names and values of all config
1529 With multiple arguments, print names and values of all config
1529 items with matching section names.
1530 items with matching section names.
1530
1531
1531 With --edit, start an editor on the user-level config file. With
1532 With --edit, start an editor on the user-level config file. With
1532 --global, edit the system-wide config file. With --local, edit the
1533 --global, edit the system-wide config file. With --local, edit the
1533 repository-level config file.
1534 repository-level config file.
1534
1535
1535 With --debug, the source (filename and line number) is printed
1536 With --debug, the source (filename and line number) is printed
1536 for each config item.
1537 for each config item.
1537
1538
1538 See :hg:`help config` for more information about config files.
1539 See :hg:`help config` for more information about config files.
1539
1540
1540 Returns 0 on success, 1 if NAME does not exist.
1541 Returns 0 on success, 1 if NAME does not exist.
1541
1542
1542 """
1543 """
1543
1544
1544 if opts.get('edit') or opts.get('local') or opts.get('global'):
1545 if opts.get('edit') or opts.get('local') or opts.get('global'):
1545 if opts.get('local') and opts.get('global'):
1546 if opts.get('local') and opts.get('global'):
1546 raise util.Abort(_("can't use --local and --global together"))
1547 raise util.Abort(_("can't use --local and --global together"))
1547
1548
1548 if opts.get('local'):
1549 if opts.get('local'):
1549 if not repo:
1550 if not repo:
1550 raise util.Abort(_("can't use --local outside a repository"))
1551 raise util.Abort(_("can't use --local outside a repository"))
1551 paths = [repo.join('hgrc')]
1552 paths = [repo.join('hgrc')]
1552 elif opts.get('global'):
1553 elif opts.get('global'):
1553 paths = scmutil.systemrcpath()
1554 paths = scmutil.systemrcpath()
1554 else:
1555 else:
1555 paths = scmutil.userrcpath()
1556 paths = scmutil.userrcpath()
1556
1557
1557 for f in paths:
1558 for f in paths:
1558 if os.path.exists(f):
1559 if os.path.exists(f):
1559 break
1560 break
1560 else:
1561 else:
1561 from ui import samplehgrcs
1562
1563 if opts.get('global'):
1562 if opts.get('global'):
1564 samplehgrc = samplehgrcs['global']
1563 samplehgrc = uimod.samplehgrcs['global']
1565 elif opts.get('local'):
1564 elif opts.get('local'):
1566 samplehgrc = samplehgrcs['local']
1565 samplehgrc = uimod.samplehgrcs['local']
1567 else:
1566 else:
1568 samplehgrc = samplehgrcs['user']
1567 samplehgrc = uimod.samplehgrcs['user']
1569
1568
1570 f = paths[0]
1569 f = paths[0]
1571 fp = open(f, "w")
1570 fp = open(f, "w")
1572 fp.write(samplehgrc)
1571 fp.write(samplehgrc)
1573 fp.close()
1572 fp.close()
1574
1573
1575 editor = ui.geteditor()
1574 editor = ui.geteditor()
1576 util.system("%s \"%s\"" % (editor, f),
1575 util.system("%s \"%s\"" % (editor, f),
1577 onerr=util.Abort, errprefix=_("edit failed"),
1576 onerr=util.Abort, errprefix=_("edit failed"),
1578 out=ui.fout)
1577 out=ui.fout)
1579 return
1578 return
1580
1579
1581 for f in scmutil.rcpath():
1580 for f in scmutil.rcpath():
1582 ui.debug('read config from: %s\n' % f)
1581 ui.debug('read config from: %s\n' % f)
1583 untrusted = bool(opts.get('untrusted'))
1582 untrusted = bool(opts.get('untrusted'))
1584 if values:
1583 if values:
1585 sections = [v for v in values if '.' not in v]
1584 sections = [v for v in values if '.' not in v]
1586 items = [v for v in values if '.' in v]
1585 items = [v for v in values if '.' in v]
1587 if len(items) > 1 or items and sections:
1586 if len(items) > 1 or items and sections:
1588 raise util.Abort(_('only one config item permitted'))
1587 raise util.Abort(_('only one config item permitted'))
1589 matched = False
1588 matched = False
1590 for section, name, value in ui.walkconfig(untrusted=untrusted):
1589 for section, name, value in ui.walkconfig(untrusted=untrusted):
1591 value = str(value).replace('\n', '\\n')
1590 value = str(value).replace('\n', '\\n')
1592 sectname = section + '.' + name
1591 sectname = section + '.' + name
1593 if values:
1592 if values:
1594 for v in values:
1593 for v in values:
1595 if v == section:
1594 if v == section:
1596 ui.debug('%s: ' %
1595 ui.debug('%s: ' %
1597 ui.configsource(section, name, untrusted))
1596 ui.configsource(section, name, untrusted))
1598 ui.write('%s=%s\n' % (sectname, value))
1597 ui.write('%s=%s\n' % (sectname, value))
1599 matched = True
1598 matched = True
1600 elif v == sectname:
1599 elif v == sectname:
1601 ui.debug('%s: ' %
1600 ui.debug('%s: ' %
1602 ui.configsource(section, name, untrusted))
1601 ui.configsource(section, name, untrusted))
1603 ui.write(value, '\n')
1602 ui.write(value, '\n')
1604 matched = True
1603 matched = True
1605 else:
1604 else:
1606 ui.debug('%s: ' %
1605 ui.debug('%s: ' %
1607 ui.configsource(section, name, untrusted))
1606 ui.configsource(section, name, untrusted))
1608 ui.write('%s=%s\n' % (sectname, value))
1607 ui.write('%s=%s\n' % (sectname, value))
1609 matched = True
1608 matched = True
1610 if matched:
1609 if matched:
1611 return 0
1610 return 0
1612 return 1
1611 return 1
1613
1612
1614 @command('copy|cp',
1613 @command('copy|cp',
1615 [('A', 'after', None, _('record a copy that has already occurred')),
1614 [('A', 'after', None, _('record a copy that has already occurred')),
1616 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1615 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1617 ] + walkopts + dryrunopts,
1616 ] + walkopts + dryrunopts,
1618 _('[OPTION]... [SOURCE]... DEST'))
1617 _('[OPTION]... [SOURCE]... DEST'))
1619 def copy(ui, repo, *pats, **opts):
1618 def copy(ui, repo, *pats, **opts):
1620 """mark files as copied for the next commit
1619 """mark files as copied for the next commit
1621
1620
1622 Mark dest as having copies of source files. If dest is a
1621 Mark dest as having copies of source files. If dest is a
1623 directory, copies are put in that directory. If dest is a file,
1622 directory, copies are put in that directory. If dest is a file,
1624 the source must be a single file.
1623 the source must be a single file.
1625
1624
1626 By default, this command copies the contents of files as they
1625 By default, this command copies the contents of files as they
1627 exist in the working directory. If invoked with -A/--after, the
1626 exist in the working directory. If invoked with -A/--after, the
1628 operation is recorded, but no copying is performed.
1627 operation is recorded, but no copying is performed.
1629
1628
1630 This command takes effect with the next commit. To undo a copy
1629 This command takes effect with the next commit. To undo a copy
1631 before that, see :hg:`revert`.
1630 before that, see :hg:`revert`.
1632
1631
1633 Returns 0 on success, 1 if errors are encountered.
1632 Returns 0 on success, 1 if errors are encountered.
1634 """
1633 """
1635 wlock = repo.wlock(False)
1634 wlock = repo.wlock(False)
1636 try:
1635 try:
1637 return cmdutil.copy(ui, repo, pats, opts)
1636 return cmdutil.copy(ui, repo, pats, opts)
1638 finally:
1637 finally:
1639 wlock.release()
1638 wlock.release()
1640
1639
1641 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1640 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1642 def debugancestor(ui, repo, *args):
1641 def debugancestor(ui, repo, *args):
1643 """find the ancestor revision of two revisions in a given index"""
1642 """find the ancestor revision of two revisions in a given index"""
1644 if len(args) == 3:
1643 if len(args) == 3:
1645 index, rev1, rev2 = args
1644 index, rev1, rev2 = args
1646 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1645 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1647 lookup = r.lookup
1646 lookup = r.lookup
1648 elif len(args) == 2:
1647 elif len(args) == 2:
1649 if not repo:
1648 if not repo:
1650 raise util.Abort(_("there is no Mercurial repository here "
1649 raise util.Abort(_("there is no Mercurial repository here "
1651 "(.hg not found)"))
1650 "(.hg not found)"))
1652 rev1, rev2 = args
1651 rev1, rev2 = args
1653 r = repo.changelog
1652 r = repo.changelog
1654 lookup = repo.lookup
1653 lookup = repo.lookup
1655 else:
1654 else:
1656 raise util.Abort(_('either two or three arguments required'))
1655 raise util.Abort(_('either two or three arguments required'))
1657 a = r.ancestor(lookup(rev1), lookup(rev2))
1656 a = r.ancestor(lookup(rev1), lookup(rev2))
1658 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1657 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1659
1658
1660 @command('debugbuilddag',
1659 @command('debugbuilddag',
1661 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1660 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1662 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1661 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1663 ('n', 'new-file', None, _('add new file at each rev'))],
1662 ('n', 'new-file', None, _('add new file at each rev'))],
1664 _('[OPTION]... [TEXT]'))
1663 _('[OPTION]... [TEXT]'))
1665 def debugbuilddag(ui, repo, text=None,
1664 def debugbuilddag(ui, repo, text=None,
1666 mergeable_file=False,
1665 mergeable_file=False,
1667 overwritten_file=False,
1666 overwritten_file=False,
1668 new_file=False):
1667 new_file=False):
1669 """builds a repo with a given DAG from scratch in the current empty repo
1668 """builds a repo with a given DAG from scratch in the current empty repo
1670
1669
1671 The description of the DAG is read from stdin if not given on the
1670 The description of the DAG is read from stdin if not given on the
1672 command line.
1671 command line.
1673
1672
1674 Elements:
1673 Elements:
1675
1674
1676 - "+n" is a linear run of n nodes based on the current default parent
1675 - "+n" is a linear run of n nodes based on the current default parent
1677 - "." is a single node based on the current default parent
1676 - "." is a single node based on the current default parent
1678 - "$" resets the default parent to null (implied at the start);
1677 - "$" resets the default parent to null (implied at the start);
1679 otherwise the default parent is always the last node created
1678 otherwise the default parent is always the last node created
1680 - "<p" sets the default parent to the backref p
1679 - "<p" sets the default parent to the backref p
1681 - "*p" is a fork at parent p, which is a backref
1680 - "*p" is a fork at parent p, which is a backref
1682 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1681 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1683 - "/p2" is a merge of the preceding node and p2
1682 - "/p2" is a merge of the preceding node and p2
1684 - ":tag" defines a local tag for the preceding node
1683 - ":tag" defines a local tag for the preceding node
1685 - "@branch" sets the named branch for subsequent nodes
1684 - "@branch" sets the named branch for subsequent nodes
1686 - "#...\\n" is a comment up to the end of the line
1685 - "#...\\n" is a comment up to the end of the line
1687
1686
1688 Whitespace between the above elements is ignored.
1687 Whitespace between the above elements is ignored.
1689
1688
1690 A backref is either
1689 A backref is either
1691
1690
1692 - a number n, which references the node curr-n, where curr is the current
1691 - a number n, which references the node curr-n, where curr is the current
1693 node, or
1692 node, or
1694 - the name of a local tag you placed earlier using ":tag", or
1693 - the name of a local tag you placed earlier using ":tag", or
1695 - empty to denote the default parent.
1694 - empty to denote the default parent.
1696
1695
1697 All string valued-elements are either strictly alphanumeric, or must
1696 All string valued-elements are either strictly alphanumeric, or must
1698 be enclosed in double quotes ("..."), with "\\" as escape character.
1697 be enclosed in double quotes ("..."), with "\\" as escape character.
1699 """
1698 """
1700
1699
1701 if text is None:
1700 if text is None:
1702 ui.status(_("reading DAG from stdin\n"))
1701 ui.status(_("reading DAG from stdin\n"))
1703 text = ui.fin.read()
1702 text = ui.fin.read()
1704
1703
1705 cl = repo.changelog
1704 cl = repo.changelog
1706 if len(cl) > 0:
1705 if len(cl) > 0:
1707 raise util.Abort(_('repository is not empty'))
1706 raise util.Abort(_('repository is not empty'))
1708
1707
1709 # determine number of revs in DAG
1708 # determine number of revs in DAG
1710 total = 0
1709 total = 0
1711 for type, data in dagparser.parsedag(text):
1710 for type, data in dagparser.parsedag(text):
1712 if type == 'n':
1711 if type == 'n':
1713 total += 1
1712 total += 1
1714
1713
1715 if mergeable_file:
1714 if mergeable_file:
1716 linesperrev = 2
1715 linesperrev = 2
1717 # make a file with k lines per rev
1716 # make a file with k lines per rev
1718 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1717 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1719 initialmergedlines.append("")
1718 initialmergedlines.append("")
1720
1719
1721 tags = []
1720 tags = []
1722
1721
1723 lock = tr = None
1722 lock = tr = None
1724 try:
1723 try:
1725 lock = repo.lock()
1724 lock = repo.lock()
1726 tr = repo.transaction("builddag")
1725 tr = repo.transaction("builddag")
1727
1726
1728 at = -1
1727 at = -1
1729 atbranch = 'default'
1728 atbranch = 'default'
1730 nodeids = []
1729 nodeids = []
1731 id = 0
1730 id = 0
1732 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1731 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1733 for type, data in dagparser.parsedag(text):
1732 for type, data in dagparser.parsedag(text):
1734 if type == 'n':
1733 if type == 'n':
1735 ui.note(('node %s\n' % str(data)))
1734 ui.note(('node %s\n' % str(data)))
1736 id, ps = data
1735 id, ps = data
1737
1736
1738 files = []
1737 files = []
1739 fctxs = {}
1738 fctxs = {}
1740
1739
1741 p2 = None
1740 p2 = None
1742 if mergeable_file:
1741 if mergeable_file:
1743 fn = "mf"
1742 fn = "mf"
1744 p1 = repo[ps[0]]
1743 p1 = repo[ps[0]]
1745 if len(ps) > 1:
1744 if len(ps) > 1:
1746 p2 = repo[ps[1]]
1745 p2 = repo[ps[1]]
1747 pa = p1.ancestor(p2)
1746 pa = p1.ancestor(p2)
1748 base, local, other = [x[fn].data() for x in (pa, p1,
1747 base, local, other = [x[fn].data() for x in (pa, p1,
1749 p2)]
1748 p2)]
1750 m3 = simplemerge.Merge3Text(base, local, other)
1749 m3 = simplemerge.Merge3Text(base, local, other)
1751 ml = [l.strip() for l in m3.merge_lines()]
1750 ml = [l.strip() for l in m3.merge_lines()]
1752 ml.append("")
1751 ml.append("")
1753 elif at > 0:
1752 elif at > 0:
1754 ml = p1[fn].data().split("\n")
1753 ml = p1[fn].data().split("\n")
1755 else:
1754 else:
1756 ml = initialmergedlines
1755 ml = initialmergedlines
1757 ml[id * linesperrev] += " r%i" % id
1756 ml[id * linesperrev] += " r%i" % id
1758 mergedtext = "\n".join(ml)
1757 mergedtext = "\n".join(ml)
1759 files.append(fn)
1758 files.append(fn)
1760 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1759 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1761
1760
1762 if overwritten_file:
1761 if overwritten_file:
1763 fn = "of"
1762 fn = "of"
1764 files.append(fn)
1763 files.append(fn)
1765 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1764 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1766
1765
1767 if new_file:
1766 if new_file:
1768 fn = "nf%i" % id
1767 fn = "nf%i" % id
1769 files.append(fn)
1768 files.append(fn)
1770 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1769 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1771 if len(ps) > 1:
1770 if len(ps) > 1:
1772 if not p2:
1771 if not p2:
1773 p2 = repo[ps[1]]
1772 p2 = repo[ps[1]]
1774 for fn in p2:
1773 for fn in p2:
1775 if fn.startswith("nf"):
1774 if fn.startswith("nf"):
1776 files.append(fn)
1775 files.append(fn)
1777 fctxs[fn] = p2[fn]
1776 fctxs[fn] = p2[fn]
1778
1777
1779 def fctxfn(repo, cx, path):
1778 def fctxfn(repo, cx, path):
1780 return fctxs.get(path)
1779 return fctxs.get(path)
1781
1780
1782 if len(ps) == 0 or ps[0] < 0:
1781 if len(ps) == 0 or ps[0] < 0:
1783 pars = [None, None]
1782 pars = [None, None]
1784 elif len(ps) == 1:
1783 elif len(ps) == 1:
1785 pars = [nodeids[ps[0]], None]
1784 pars = [nodeids[ps[0]], None]
1786 else:
1785 else:
1787 pars = [nodeids[p] for p in ps]
1786 pars = [nodeids[p] for p in ps]
1788 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1787 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1789 date=(id, 0),
1788 date=(id, 0),
1790 user="debugbuilddag",
1789 user="debugbuilddag",
1791 extra={'branch': atbranch})
1790 extra={'branch': atbranch})
1792 nodeid = repo.commitctx(cx)
1791 nodeid = repo.commitctx(cx)
1793 nodeids.append(nodeid)
1792 nodeids.append(nodeid)
1794 at = id
1793 at = id
1795 elif type == 'l':
1794 elif type == 'l':
1796 id, name = data
1795 id, name = data
1797 ui.note(('tag %s\n' % name))
1796 ui.note(('tag %s\n' % name))
1798 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1797 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1799 elif type == 'a':
1798 elif type == 'a':
1800 ui.note(('branch %s\n' % data))
1799 ui.note(('branch %s\n' % data))
1801 atbranch = data
1800 atbranch = data
1802 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1801 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1803 tr.close()
1802 tr.close()
1804
1803
1805 if tags:
1804 if tags:
1806 repo.opener.write("localtags", "".join(tags))
1805 repo.opener.write("localtags", "".join(tags))
1807 finally:
1806 finally:
1808 ui.progress(_('building'), None)
1807 ui.progress(_('building'), None)
1809 release(tr, lock)
1808 release(tr, lock)
1810
1809
1811 @command('debugbundle',
1810 @command('debugbundle',
1812 [('a', 'all', None, _('show all details'))],
1811 [('a', 'all', None, _('show all details'))],
1813 _('FILE'),
1812 _('FILE'),
1814 norepo=True)
1813 norepo=True)
1815 def debugbundle(ui, bundlepath, all=None, **opts):
1814 def debugbundle(ui, bundlepath, all=None, **opts):
1816 """lists the contents of a bundle"""
1815 """lists the contents of a bundle"""
1817 f = hg.openpath(ui, bundlepath)
1816 f = hg.openpath(ui, bundlepath)
1818 try:
1817 try:
1819 gen = exchange.readbundle(ui, f, bundlepath)
1818 gen = exchange.readbundle(ui, f, bundlepath)
1820 if all:
1819 if all:
1821 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1820 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1822
1821
1823 def showchunks(named):
1822 def showchunks(named):
1824 ui.write("\n%s\n" % named)
1823 ui.write("\n%s\n" % named)
1825 chain = None
1824 chain = None
1826 while True:
1825 while True:
1827 chunkdata = gen.deltachunk(chain)
1826 chunkdata = gen.deltachunk(chain)
1828 if not chunkdata:
1827 if not chunkdata:
1829 break
1828 break
1830 node = chunkdata['node']
1829 node = chunkdata['node']
1831 p1 = chunkdata['p1']
1830 p1 = chunkdata['p1']
1832 p2 = chunkdata['p2']
1831 p2 = chunkdata['p2']
1833 cs = chunkdata['cs']
1832 cs = chunkdata['cs']
1834 deltabase = chunkdata['deltabase']
1833 deltabase = chunkdata['deltabase']
1835 delta = chunkdata['delta']
1834 delta = chunkdata['delta']
1836 ui.write("%s %s %s %s %s %s\n" %
1835 ui.write("%s %s %s %s %s %s\n" %
1837 (hex(node), hex(p1), hex(p2),
1836 (hex(node), hex(p1), hex(p2),
1838 hex(cs), hex(deltabase), len(delta)))
1837 hex(cs), hex(deltabase), len(delta)))
1839 chain = node
1838 chain = node
1840
1839
1841 chunkdata = gen.changelogheader()
1840 chunkdata = gen.changelogheader()
1842 showchunks("changelog")
1841 showchunks("changelog")
1843 chunkdata = gen.manifestheader()
1842 chunkdata = gen.manifestheader()
1844 showchunks("manifest")
1843 showchunks("manifest")
1845 while True:
1844 while True:
1846 chunkdata = gen.filelogheader()
1845 chunkdata = gen.filelogheader()
1847 if not chunkdata:
1846 if not chunkdata:
1848 break
1847 break
1849 fname = chunkdata['filename']
1848 fname = chunkdata['filename']
1850 showchunks(fname)
1849 showchunks(fname)
1851 else:
1850 else:
1852 chunkdata = gen.changelogheader()
1851 chunkdata = gen.changelogheader()
1853 chain = None
1852 chain = None
1854 while True:
1853 while True:
1855 chunkdata = gen.deltachunk(chain)
1854 chunkdata = gen.deltachunk(chain)
1856 if not chunkdata:
1855 if not chunkdata:
1857 break
1856 break
1858 node = chunkdata['node']
1857 node = chunkdata['node']
1859 ui.write("%s\n" % hex(node))
1858 ui.write("%s\n" % hex(node))
1860 chain = node
1859 chain = node
1861 finally:
1860 finally:
1862 f.close()
1861 f.close()
1863
1862
1864 @command('debugcheckstate', [], '')
1863 @command('debugcheckstate', [], '')
1865 def debugcheckstate(ui, repo):
1864 def debugcheckstate(ui, repo):
1866 """validate the correctness of the current dirstate"""
1865 """validate the correctness of the current dirstate"""
1867 parent1, parent2 = repo.dirstate.parents()
1866 parent1, parent2 = repo.dirstate.parents()
1868 m1 = repo[parent1].manifest()
1867 m1 = repo[parent1].manifest()
1869 m2 = repo[parent2].manifest()
1868 m2 = repo[parent2].manifest()
1870 errors = 0
1869 errors = 0
1871 for f in repo.dirstate:
1870 for f in repo.dirstate:
1872 state = repo.dirstate[f]
1871 state = repo.dirstate[f]
1873 if state in "nr" and f not in m1:
1872 if state in "nr" and f not in m1:
1874 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1873 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1875 errors += 1
1874 errors += 1
1876 if state in "a" and f in m1:
1875 if state in "a" and f in m1:
1877 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1876 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1878 errors += 1
1877 errors += 1
1879 if state in "m" and f not in m1 and f not in m2:
1878 if state in "m" and f not in m1 and f not in m2:
1880 ui.warn(_("%s in state %s, but not in either manifest\n") %
1879 ui.warn(_("%s in state %s, but not in either manifest\n") %
1881 (f, state))
1880 (f, state))
1882 errors += 1
1881 errors += 1
1883 for f in m1:
1882 for f in m1:
1884 state = repo.dirstate[f]
1883 state = repo.dirstate[f]
1885 if state not in "nrm":
1884 if state not in "nrm":
1886 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1885 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1887 errors += 1
1886 errors += 1
1888 if errors:
1887 if errors:
1889 error = _(".hg/dirstate inconsistent with current parent's manifest")
1888 error = _(".hg/dirstate inconsistent with current parent's manifest")
1890 raise util.Abort(error)
1889 raise util.Abort(error)
1891
1890
1892 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1891 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1893 def debugcommands(ui, cmd='', *args):
1892 def debugcommands(ui, cmd='', *args):
1894 """list all available commands and options"""
1893 """list all available commands and options"""
1895 for cmd, vals in sorted(table.iteritems()):
1894 for cmd, vals in sorted(table.iteritems()):
1896 cmd = cmd.split('|')[0].strip('^')
1895 cmd = cmd.split('|')[0].strip('^')
1897 opts = ', '.join([i[1] for i in vals[1]])
1896 opts = ', '.join([i[1] for i in vals[1]])
1898 ui.write('%s: %s\n' % (cmd, opts))
1897 ui.write('%s: %s\n' % (cmd, opts))
1899
1898
1900 @command('debugcomplete',
1899 @command('debugcomplete',
1901 [('o', 'options', None, _('show the command options'))],
1900 [('o', 'options', None, _('show the command options'))],
1902 _('[-o] CMD'),
1901 _('[-o] CMD'),
1903 norepo=True)
1902 norepo=True)
1904 def debugcomplete(ui, cmd='', **opts):
1903 def debugcomplete(ui, cmd='', **opts):
1905 """returns the completion list associated with the given command"""
1904 """returns the completion list associated with the given command"""
1906
1905
1907 if opts.get('options'):
1906 if opts.get('options'):
1908 options = []
1907 options = []
1909 otables = [globalopts]
1908 otables = [globalopts]
1910 if cmd:
1909 if cmd:
1911 aliases, entry = cmdutil.findcmd(cmd, table, False)
1910 aliases, entry = cmdutil.findcmd(cmd, table, False)
1912 otables.append(entry[1])
1911 otables.append(entry[1])
1913 for t in otables:
1912 for t in otables:
1914 for o in t:
1913 for o in t:
1915 if "(DEPRECATED)" in o[3]:
1914 if "(DEPRECATED)" in o[3]:
1916 continue
1915 continue
1917 if o[0]:
1916 if o[0]:
1918 options.append('-%s' % o[0])
1917 options.append('-%s' % o[0])
1919 options.append('--%s' % o[1])
1918 options.append('--%s' % o[1])
1920 ui.write("%s\n" % "\n".join(options))
1919 ui.write("%s\n" % "\n".join(options))
1921 return
1920 return
1922
1921
1923 cmdlist = cmdutil.findpossible(cmd, table)
1922 cmdlist = cmdutil.findpossible(cmd, table)
1924 if ui.verbose:
1923 if ui.verbose:
1925 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1924 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1926 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1925 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1927
1926
1928 @command('debugdag',
1927 @command('debugdag',
1929 [('t', 'tags', None, _('use tags as labels')),
1928 [('t', 'tags', None, _('use tags as labels')),
1930 ('b', 'branches', None, _('annotate with branch names')),
1929 ('b', 'branches', None, _('annotate with branch names')),
1931 ('', 'dots', None, _('use dots for runs')),
1930 ('', 'dots', None, _('use dots for runs')),
1932 ('s', 'spaces', None, _('separate elements by spaces'))],
1931 ('s', 'spaces', None, _('separate elements by spaces'))],
1933 _('[OPTION]... [FILE [REV]...]'),
1932 _('[OPTION]... [FILE [REV]...]'),
1934 optionalrepo=True)
1933 optionalrepo=True)
1935 def debugdag(ui, repo, file_=None, *revs, **opts):
1934 def debugdag(ui, repo, file_=None, *revs, **opts):
1936 """format the changelog or an index DAG as a concise textual description
1935 """format the changelog or an index DAG as a concise textual description
1937
1936
1938 If you pass a revlog index, the revlog's DAG is emitted. If you list
1937 If you pass a revlog index, the revlog's DAG is emitted. If you list
1939 revision numbers, they get labeled in the output as rN.
1938 revision numbers, they get labeled in the output as rN.
1940
1939
1941 Otherwise, the changelog DAG of the current repo is emitted.
1940 Otherwise, the changelog DAG of the current repo is emitted.
1942 """
1941 """
1943 spaces = opts.get('spaces')
1942 spaces = opts.get('spaces')
1944 dots = opts.get('dots')
1943 dots = opts.get('dots')
1945 if file_:
1944 if file_:
1946 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1945 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1947 revs = set((int(r) for r in revs))
1946 revs = set((int(r) for r in revs))
1948 def events():
1947 def events():
1949 for r in rlog:
1948 for r in rlog:
1950 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1949 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1951 if p != -1))
1950 if p != -1))
1952 if r in revs:
1951 if r in revs:
1953 yield 'l', (r, "r%i" % r)
1952 yield 'l', (r, "r%i" % r)
1954 elif repo:
1953 elif repo:
1955 cl = repo.changelog
1954 cl = repo.changelog
1956 tags = opts.get('tags')
1955 tags = opts.get('tags')
1957 branches = opts.get('branches')
1956 branches = opts.get('branches')
1958 if tags:
1957 if tags:
1959 labels = {}
1958 labels = {}
1960 for l, n in repo.tags().items():
1959 for l, n in repo.tags().items():
1961 labels.setdefault(cl.rev(n), []).append(l)
1960 labels.setdefault(cl.rev(n), []).append(l)
1962 def events():
1961 def events():
1963 b = "default"
1962 b = "default"
1964 for r in cl:
1963 for r in cl:
1965 if branches:
1964 if branches:
1966 newb = cl.read(cl.node(r))[5]['branch']
1965 newb = cl.read(cl.node(r))[5]['branch']
1967 if newb != b:
1966 if newb != b:
1968 yield 'a', newb
1967 yield 'a', newb
1969 b = newb
1968 b = newb
1970 yield 'n', (r, list(p for p in cl.parentrevs(r)
1969 yield 'n', (r, list(p for p in cl.parentrevs(r)
1971 if p != -1))
1970 if p != -1))
1972 if tags:
1971 if tags:
1973 ls = labels.get(r)
1972 ls = labels.get(r)
1974 if ls:
1973 if ls:
1975 for l in ls:
1974 for l in ls:
1976 yield 'l', (r, l)
1975 yield 'l', (r, l)
1977 else:
1976 else:
1978 raise util.Abort(_('need repo for changelog dag'))
1977 raise util.Abort(_('need repo for changelog dag'))
1979
1978
1980 for line in dagparser.dagtextlines(events(),
1979 for line in dagparser.dagtextlines(events(),
1981 addspaces=spaces,
1980 addspaces=spaces,
1982 wraplabels=True,
1981 wraplabels=True,
1983 wrapannotations=True,
1982 wrapannotations=True,
1984 wrapnonlinear=dots,
1983 wrapnonlinear=dots,
1985 usedots=dots,
1984 usedots=dots,
1986 maxlinewidth=70):
1985 maxlinewidth=70):
1987 ui.write(line)
1986 ui.write(line)
1988 ui.write("\n")
1987 ui.write("\n")
1989
1988
1990 @command('debugdata',
1989 @command('debugdata',
1991 [('c', 'changelog', False, _('open changelog')),
1990 [('c', 'changelog', False, _('open changelog')),
1992 ('m', 'manifest', False, _('open manifest'))],
1991 ('m', 'manifest', False, _('open manifest'))],
1993 _('-c|-m|FILE REV'))
1992 _('-c|-m|FILE REV'))
1994 def debugdata(ui, repo, file_, rev=None, **opts):
1993 def debugdata(ui, repo, file_, rev=None, **opts):
1995 """dump the contents of a data file revision"""
1994 """dump the contents of a data file revision"""
1996 if opts.get('changelog') or opts.get('manifest'):
1995 if opts.get('changelog') or opts.get('manifest'):
1997 file_, rev = None, file_
1996 file_, rev = None, file_
1998 elif rev is None:
1997 elif rev is None:
1999 raise error.CommandError('debugdata', _('invalid arguments'))
1998 raise error.CommandError('debugdata', _('invalid arguments'))
2000 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1999 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2001 try:
2000 try:
2002 ui.write(r.revision(r.lookup(rev)))
2001 ui.write(r.revision(r.lookup(rev)))
2003 except KeyError:
2002 except KeyError:
2004 raise util.Abort(_('invalid revision identifier %s') % rev)
2003 raise util.Abort(_('invalid revision identifier %s') % rev)
2005
2004
2006 @command('debugdate',
2005 @command('debugdate',
2007 [('e', 'extended', None, _('try extended date formats'))],
2006 [('e', 'extended', None, _('try extended date formats'))],
2008 _('[-e] DATE [RANGE]'),
2007 _('[-e] DATE [RANGE]'),
2009 norepo=True, optionalrepo=True)
2008 norepo=True, optionalrepo=True)
2010 def debugdate(ui, date, range=None, **opts):
2009 def debugdate(ui, date, range=None, **opts):
2011 """parse and display a date"""
2010 """parse and display a date"""
2012 if opts["extended"]:
2011 if opts["extended"]:
2013 d = util.parsedate(date, util.extendeddateformats)
2012 d = util.parsedate(date, util.extendeddateformats)
2014 else:
2013 else:
2015 d = util.parsedate(date)
2014 d = util.parsedate(date)
2016 ui.write(("internal: %s %s\n") % d)
2015 ui.write(("internal: %s %s\n") % d)
2017 ui.write(("standard: %s\n") % util.datestr(d))
2016 ui.write(("standard: %s\n") % util.datestr(d))
2018 if range:
2017 if range:
2019 m = util.matchdate(range)
2018 m = util.matchdate(range)
2020 ui.write(("match: %s\n") % m(d[0]))
2019 ui.write(("match: %s\n") % m(d[0]))
2021
2020
2022 @command('debugdiscovery',
2021 @command('debugdiscovery',
2023 [('', 'old', None, _('use old-style discovery')),
2022 [('', 'old', None, _('use old-style discovery')),
2024 ('', 'nonheads', None,
2023 ('', 'nonheads', None,
2025 _('use old-style discovery with non-heads included')),
2024 _('use old-style discovery with non-heads included')),
2026 ] + remoteopts,
2025 ] + remoteopts,
2027 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2026 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2028 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2027 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2029 """runs the changeset discovery protocol in isolation"""
2028 """runs the changeset discovery protocol in isolation"""
2030 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2029 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2031 opts.get('branch'))
2030 opts.get('branch'))
2032 remote = hg.peer(repo, opts, remoteurl)
2031 remote = hg.peer(repo, opts, remoteurl)
2033 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2032 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2034
2033
2035 # make sure tests are repeatable
2034 # make sure tests are repeatable
2036 random.seed(12323)
2035 random.seed(12323)
2037
2036
2038 def doit(localheads, remoteheads, remote=remote):
2037 def doit(localheads, remoteheads, remote=remote):
2039 if opts.get('old'):
2038 if opts.get('old'):
2040 if localheads:
2039 if localheads:
2041 raise util.Abort('cannot use localheads with old style '
2040 raise util.Abort('cannot use localheads with old style '
2042 'discovery')
2041 'discovery')
2043 if not util.safehasattr(remote, 'branches'):
2042 if not util.safehasattr(remote, 'branches'):
2044 # enable in-client legacy support
2043 # enable in-client legacy support
2045 remote = localrepo.locallegacypeer(remote.local())
2044 remote = localrepo.locallegacypeer(remote.local())
2046 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2045 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2047 force=True)
2046 force=True)
2048 common = set(common)
2047 common = set(common)
2049 if not opts.get('nonheads'):
2048 if not opts.get('nonheads'):
2050 ui.write(("unpruned common: %s\n") %
2049 ui.write(("unpruned common: %s\n") %
2051 " ".join(sorted(short(n) for n in common)))
2050 " ".join(sorted(short(n) for n in common)))
2052 dag = dagutil.revlogdag(repo.changelog)
2051 dag = dagutil.revlogdag(repo.changelog)
2053 all = dag.ancestorset(dag.internalizeall(common))
2052 all = dag.ancestorset(dag.internalizeall(common))
2054 common = dag.externalizeall(dag.headsetofconnecteds(all))
2053 common = dag.externalizeall(dag.headsetofconnecteds(all))
2055 else:
2054 else:
2056 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2055 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2057 common = set(common)
2056 common = set(common)
2058 rheads = set(hds)
2057 rheads = set(hds)
2059 lheads = set(repo.heads())
2058 lheads = set(repo.heads())
2060 ui.write(("common heads: %s\n") %
2059 ui.write(("common heads: %s\n") %
2061 " ".join(sorted(short(n) for n in common)))
2060 " ".join(sorted(short(n) for n in common)))
2062 if lheads <= common:
2061 if lheads <= common:
2063 ui.write(("local is subset\n"))
2062 ui.write(("local is subset\n"))
2064 elif rheads <= common:
2063 elif rheads <= common:
2065 ui.write(("remote is subset\n"))
2064 ui.write(("remote is subset\n"))
2066
2065
2067 serverlogs = opts.get('serverlog')
2066 serverlogs = opts.get('serverlog')
2068 if serverlogs:
2067 if serverlogs:
2069 for filename in serverlogs:
2068 for filename in serverlogs:
2070 logfile = open(filename, 'r')
2069 logfile = open(filename, 'r')
2071 try:
2070 try:
2072 line = logfile.readline()
2071 line = logfile.readline()
2073 while line:
2072 while line:
2074 parts = line.strip().split(';')
2073 parts = line.strip().split(';')
2075 op = parts[1]
2074 op = parts[1]
2076 if op == 'cg':
2075 if op == 'cg':
2077 pass
2076 pass
2078 elif op == 'cgss':
2077 elif op == 'cgss':
2079 doit(parts[2].split(' '), parts[3].split(' '))
2078 doit(parts[2].split(' '), parts[3].split(' '))
2080 elif op == 'unb':
2079 elif op == 'unb':
2081 doit(parts[3].split(' '), parts[2].split(' '))
2080 doit(parts[3].split(' '), parts[2].split(' '))
2082 line = logfile.readline()
2081 line = logfile.readline()
2083 finally:
2082 finally:
2084 logfile.close()
2083 logfile.close()
2085
2084
2086 else:
2085 else:
2087 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2086 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2088 opts.get('remote_head'))
2087 opts.get('remote_head'))
2089 localrevs = opts.get('local_head')
2088 localrevs = opts.get('local_head')
2090 doit(localrevs, remoterevs)
2089 doit(localrevs, remoterevs)
2091
2090
2092 @command('debugfileset',
2091 @command('debugfileset',
2093 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2092 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2094 _('[-r REV] FILESPEC'))
2093 _('[-r REV] FILESPEC'))
2095 def debugfileset(ui, repo, expr, **opts):
2094 def debugfileset(ui, repo, expr, **opts):
2096 '''parse and apply a fileset specification'''
2095 '''parse and apply a fileset specification'''
2097 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2096 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2098 if ui.verbose:
2097 if ui.verbose:
2099 tree = fileset.parse(expr)[0]
2098 tree = fileset.parse(expr)[0]
2100 ui.note(tree, "\n")
2099 ui.note(tree, "\n")
2101
2100
2102 for f in ctx.getfileset(expr):
2101 for f in ctx.getfileset(expr):
2103 ui.write("%s\n" % f)
2102 ui.write("%s\n" % f)
2104
2103
2105 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2104 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2106 def debugfsinfo(ui, path="."):
2105 def debugfsinfo(ui, path="."):
2107 """show information detected about current filesystem"""
2106 """show information detected about current filesystem"""
2108 util.writefile('.debugfsinfo', '')
2107 util.writefile('.debugfsinfo', '')
2109 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2108 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2110 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2109 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2111 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2110 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2112 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2111 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2113 and 'yes' or 'no'))
2112 and 'yes' or 'no'))
2114 os.unlink('.debugfsinfo')
2113 os.unlink('.debugfsinfo')
2115
2114
2116 @command('debuggetbundle',
2115 @command('debuggetbundle',
2117 [('H', 'head', [], _('id of head node'), _('ID')),
2116 [('H', 'head', [], _('id of head node'), _('ID')),
2118 ('C', 'common', [], _('id of common node'), _('ID')),
2117 ('C', 'common', [], _('id of common node'), _('ID')),
2119 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2118 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2120 _('REPO FILE [-H|-C ID]...'),
2119 _('REPO FILE [-H|-C ID]...'),
2121 norepo=True)
2120 norepo=True)
2122 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2121 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2123 """retrieves a bundle from a repo
2122 """retrieves a bundle from a repo
2124
2123
2125 Every ID must be a full-length hex node id string. Saves the bundle to the
2124 Every ID must be a full-length hex node id string. Saves the bundle to the
2126 given file.
2125 given file.
2127 """
2126 """
2128 repo = hg.peer(ui, opts, repopath)
2127 repo = hg.peer(ui, opts, repopath)
2129 if not repo.capable('getbundle'):
2128 if not repo.capable('getbundle'):
2130 raise util.Abort("getbundle() not supported by target repository")
2129 raise util.Abort("getbundle() not supported by target repository")
2131 args = {}
2130 args = {}
2132 if common:
2131 if common:
2133 args['common'] = [bin(s) for s in common]
2132 args['common'] = [bin(s) for s in common]
2134 if head:
2133 if head:
2135 args['heads'] = [bin(s) for s in head]
2134 args['heads'] = [bin(s) for s in head]
2136 # TODO: get desired bundlecaps from command line.
2135 # TODO: get desired bundlecaps from command line.
2137 args['bundlecaps'] = None
2136 args['bundlecaps'] = None
2138 bundle = repo.getbundle('debug', **args)
2137 bundle = repo.getbundle('debug', **args)
2139
2138
2140 bundletype = opts.get('type', 'bzip2').lower()
2139 bundletype = opts.get('type', 'bzip2').lower()
2141 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2140 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2142 bundletype = btypes.get(bundletype)
2141 bundletype = btypes.get(bundletype)
2143 if bundletype not in changegroup.bundletypes:
2142 if bundletype not in changegroup.bundletypes:
2144 raise util.Abort(_('unknown bundle type specified with --type'))
2143 raise util.Abort(_('unknown bundle type specified with --type'))
2145 changegroup.writebundle(bundle, bundlepath, bundletype)
2144 changegroup.writebundle(bundle, bundlepath, bundletype)
2146
2145
2147 @command('debugignore', [], '')
2146 @command('debugignore', [], '')
2148 def debugignore(ui, repo, *values, **opts):
2147 def debugignore(ui, repo, *values, **opts):
2149 """display the combined ignore pattern"""
2148 """display the combined ignore pattern"""
2150 ignore = repo.dirstate._ignore
2149 ignore = repo.dirstate._ignore
2151 includepat = getattr(ignore, 'includepat', None)
2150 includepat = getattr(ignore, 'includepat', None)
2152 if includepat is not None:
2151 if includepat is not None:
2153 ui.write("%s\n" % includepat)
2152 ui.write("%s\n" % includepat)
2154 else:
2153 else:
2155 raise util.Abort(_("no ignore patterns found"))
2154 raise util.Abort(_("no ignore patterns found"))
2156
2155
2157 @command('debugindex',
2156 @command('debugindex',
2158 [('c', 'changelog', False, _('open changelog')),
2157 [('c', 'changelog', False, _('open changelog')),
2159 ('m', 'manifest', False, _('open manifest')),
2158 ('m', 'manifest', False, _('open manifest')),
2160 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2159 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2161 _('[-f FORMAT] -c|-m|FILE'),
2160 _('[-f FORMAT] -c|-m|FILE'),
2162 optionalrepo=True)
2161 optionalrepo=True)
2163 def debugindex(ui, repo, file_=None, **opts):
2162 def debugindex(ui, repo, file_=None, **opts):
2164 """dump the contents of an index file"""
2163 """dump the contents of an index file"""
2165 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2164 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2166 format = opts.get('format', 0)
2165 format = opts.get('format', 0)
2167 if format not in (0, 1):
2166 if format not in (0, 1):
2168 raise util.Abort(_("unknown format %d") % format)
2167 raise util.Abort(_("unknown format %d") % format)
2169
2168
2170 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2169 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2171 if generaldelta:
2170 if generaldelta:
2172 basehdr = ' delta'
2171 basehdr = ' delta'
2173 else:
2172 else:
2174 basehdr = ' base'
2173 basehdr = ' base'
2175
2174
2176 if format == 0:
2175 if format == 0:
2177 ui.write(" rev offset length " + basehdr + " linkrev"
2176 ui.write(" rev offset length " + basehdr + " linkrev"
2178 " nodeid p1 p2\n")
2177 " nodeid p1 p2\n")
2179 elif format == 1:
2178 elif format == 1:
2180 ui.write(" rev flag offset length"
2179 ui.write(" rev flag offset length"
2181 " size " + basehdr + " link p1 p2"
2180 " size " + basehdr + " link p1 p2"
2182 " nodeid\n")
2181 " nodeid\n")
2183
2182
2184 for i in r:
2183 for i in r:
2185 node = r.node(i)
2184 node = r.node(i)
2186 if generaldelta:
2185 if generaldelta:
2187 base = r.deltaparent(i)
2186 base = r.deltaparent(i)
2188 else:
2187 else:
2189 base = r.chainbase(i)
2188 base = r.chainbase(i)
2190 if format == 0:
2189 if format == 0:
2191 try:
2190 try:
2192 pp = r.parents(node)
2191 pp = r.parents(node)
2193 except Exception:
2192 except Exception:
2194 pp = [nullid, nullid]
2193 pp = [nullid, nullid]
2195 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2194 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2196 i, r.start(i), r.length(i), base, r.linkrev(i),
2195 i, r.start(i), r.length(i), base, r.linkrev(i),
2197 short(node), short(pp[0]), short(pp[1])))
2196 short(node), short(pp[0]), short(pp[1])))
2198 elif format == 1:
2197 elif format == 1:
2199 pr = r.parentrevs(i)
2198 pr = r.parentrevs(i)
2200 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2199 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2201 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2200 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2202 base, r.linkrev(i), pr[0], pr[1], short(node)))
2201 base, r.linkrev(i), pr[0], pr[1], short(node)))
2203
2202
2204 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2203 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2205 def debugindexdot(ui, repo, file_):
2204 def debugindexdot(ui, repo, file_):
2206 """dump an index DAG as a graphviz dot file"""
2205 """dump an index DAG as a graphviz dot file"""
2207 r = None
2206 r = None
2208 if repo:
2207 if repo:
2209 filelog = repo.file(file_)
2208 filelog = repo.file(file_)
2210 if len(filelog):
2209 if len(filelog):
2211 r = filelog
2210 r = filelog
2212 if not r:
2211 if not r:
2213 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2212 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2214 ui.write(("digraph G {\n"))
2213 ui.write(("digraph G {\n"))
2215 for i in r:
2214 for i in r:
2216 node = r.node(i)
2215 node = r.node(i)
2217 pp = r.parents(node)
2216 pp = r.parents(node)
2218 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2217 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2219 if pp[1] != nullid:
2218 if pp[1] != nullid:
2220 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2219 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2221 ui.write("}\n")
2220 ui.write("}\n")
2222
2221
2223 @command('debuginstall', [], '', norepo=True)
2222 @command('debuginstall', [], '', norepo=True)
2224 def debuginstall(ui):
2223 def debuginstall(ui):
2225 '''test Mercurial installation
2224 '''test Mercurial installation
2226
2225
2227 Returns 0 on success.
2226 Returns 0 on success.
2228 '''
2227 '''
2229
2228
2230 def writetemp(contents):
2229 def writetemp(contents):
2231 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2230 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2232 f = os.fdopen(fd, "wb")
2231 f = os.fdopen(fd, "wb")
2233 f.write(contents)
2232 f.write(contents)
2234 f.close()
2233 f.close()
2235 return name
2234 return name
2236
2235
2237 problems = 0
2236 problems = 0
2238
2237
2239 # encoding
2238 # encoding
2240 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2239 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2241 try:
2240 try:
2242 encoding.fromlocal("test")
2241 encoding.fromlocal("test")
2243 except util.Abort, inst:
2242 except util.Abort, inst:
2244 ui.write(" %s\n" % inst)
2243 ui.write(" %s\n" % inst)
2245 ui.write(_(" (check that your locale is properly set)\n"))
2244 ui.write(_(" (check that your locale is properly set)\n"))
2246 problems += 1
2245 problems += 1
2247
2246
2248 # Python
2247 # Python
2249 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2248 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2250 ui.status(_("checking Python version (%s)\n")
2249 ui.status(_("checking Python version (%s)\n")
2251 % ("%s.%s.%s" % sys.version_info[:3]))
2250 % ("%s.%s.%s" % sys.version_info[:3]))
2252 ui.status(_("checking Python lib (%s)...\n")
2251 ui.status(_("checking Python lib (%s)...\n")
2253 % os.path.dirname(os.__file__))
2252 % os.path.dirname(os.__file__))
2254
2253
2255 # compiled modules
2254 # compiled modules
2256 ui.status(_("checking installed modules (%s)...\n")
2255 ui.status(_("checking installed modules (%s)...\n")
2257 % os.path.dirname(__file__))
2256 % os.path.dirname(__file__))
2258 try:
2257 try:
2259 import bdiff, mpatch, base85, osutil
2258 import bdiff, mpatch, base85, osutil
2260 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2259 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2261 except Exception, inst:
2260 except Exception, inst:
2262 ui.write(" %s\n" % inst)
2261 ui.write(" %s\n" % inst)
2263 ui.write(_(" One or more extensions could not be found"))
2262 ui.write(_(" One or more extensions could not be found"))
2264 ui.write(_(" (check that you compiled the extensions)\n"))
2263 ui.write(_(" (check that you compiled the extensions)\n"))
2265 problems += 1
2264 problems += 1
2266
2265
2267 # templates
2266 # templates
2268 import templater
2267 import templater
2269 p = templater.templatepaths()
2268 p = templater.templatepaths()
2270 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2269 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2271 if p:
2270 if p:
2272 m = templater.templatepath("map-cmdline.default")
2271 m = templater.templatepath("map-cmdline.default")
2273 if m:
2272 if m:
2274 # template found, check if it is working
2273 # template found, check if it is working
2275 try:
2274 try:
2276 templater.templater(m)
2275 templater.templater(m)
2277 except Exception, inst:
2276 except Exception, inst:
2278 ui.write(" %s\n" % inst)
2277 ui.write(" %s\n" % inst)
2279 p = None
2278 p = None
2280 else:
2279 else:
2281 ui.write(_(" template 'default' not found\n"))
2280 ui.write(_(" template 'default' not found\n"))
2282 p = None
2281 p = None
2283 else:
2282 else:
2284 ui.write(_(" no template directories found\n"))
2283 ui.write(_(" no template directories found\n"))
2285 if not p:
2284 if not p:
2286 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2285 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2287 problems += 1
2286 problems += 1
2288
2287
2289 # editor
2288 # editor
2290 ui.status(_("checking commit editor...\n"))
2289 ui.status(_("checking commit editor...\n"))
2291 editor = ui.geteditor()
2290 editor = ui.geteditor()
2292 cmdpath = util.findexe(shlex.split(editor)[0])
2291 cmdpath = util.findexe(shlex.split(editor)[0])
2293 if not cmdpath:
2292 if not cmdpath:
2294 if editor == 'vi':
2293 if editor == 'vi':
2295 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2294 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2296 ui.write(_(" (specify a commit editor in your configuration"
2295 ui.write(_(" (specify a commit editor in your configuration"
2297 " file)\n"))
2296 " file)\n"))
2298 else:
2297 else:
2299 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2298 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2300 ui.write(_(" (specify a commit editor in your configuration"
2299 ui.write(_(" (specify a commit editor in your configuration"
2301 " file)\n"))
2300 " file)\n"))
2302 problems += 1
2301 problems += 1
2303
2302
2304 # check username
2303 # check username
2305 ui.status(_("checking username...\n"))
2304 ui.status(_("checking username...\n"))
2306 try:
2305 try:
2307 ui.username()
2306 ui.username()
2308 except util.Abort, e:
2307 except util.Abort, e:
2309 ui.write(" %s\n" % e)
2308 ui.write(" %s\n" % e)
2310 ui.write(_(" (specify a username in your configuration file)\n"))
2309 ui.write(_(" (specify a username in your configuration file)\n"))
2311 problems += 1
2310 problems += 1
2312
2311
2313 if not problems:
2312 if not problems:
2314 ui.status(_("no problems detected\n"))
2313 ui.status(_("no problems detected\n"))
2315 else:
2314 else:
2316 ui.write(_("%s problems detected,"
2315 ui.write(_("%s problems detected,"
2317 " please check your install!\n") % problems)
2316 " please check your install!\n") % problems)
2318
2317
2319 return problems
2318 return problems
2320
2319
2321 @command('debugknown', [], _('REPO ID...'), norepo=True)
2320 @command('debugknown', [], _('REPO ID...'), norepo=True)
2322 def debugknown(ui, repopath, *ids, **opts):
2321 def debugknown(ui, repopath, *ids, **opts):
2323 """test whether node ids are known to a repo
2322 """test whether node ids are known to a repo
2324
2323
2325 Every ID must be a full-length hex node id string. Returns a list of 0s
2324 Every ID must be a full-length hex node id string. Returns a list of 0s
2326 and 1s indicating unknown/known.
2325 and 1s indicating unknown/known.
2327 """
2326 """
2328 repo = hg.peer(ui, opts, repopath)
2327 repo = hg.peer(ui, opts, repopath)
2329 if not repo.capable('known'):
2328 if not repo.capable('known'):
2330 raise util.Abort("known() not supported by target repository")
2329 raise util.Abort("known() not supported by target repository")
2331 flags = repo.known([bin(s) for s in ids])
2330 flags = repo.known([bin(s) for s in ids])
2332 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2331 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2333
2332
2334 @command('debuglabelcomplete', [], _('LABEL...'))
2333 @command('debuglabelcomplete', [], _('LABEL...'))
2335 def debuglabelcomplete(ui, repo, *args):
2334 def debuglabelcomplete(ui, repo, *args):
2336 '''complete "labels" - tags, open branch names, bookmark names'''
2335 '''complete "labels" - tags, open branch names, bookmark names'''
2337
2336
2338 labels = set()
2337 labels = set()
2339 labels.update(t[0] for t in repo.tagslist())
2338 labels.update(t[0] for t in repo.tagslist())
2340 labels.update(repo._bookmarks.keys())
2339 labels.update(repo._bookmarks.keys())
2341 labels.update(tag for (tag, heads, tip, closed)
2340 labels.update(tag for (tag, heads, tip, closed)
2342 in repo.branchmap().iterbranches() if not closed)
2341 in repo.branchmap().iterbranches() if not closed)
2343 completions = set()
2342 completions = set()
2344 if not args:
2343 if not args:
2345 args = ['']
2344 args = ['']
2346 for a in args:
2345 for a in args:
2347 completions.update(l for l in labels if l.startswith(a))
2346 completions.update(l for l in labels if l.startswith(a))
2348 ui.write('\n'.join(sorted(completions)))
2347 ui.write('\n'.join(sorted(completions)))
2349 ui.write('\n')
2348 ui.write('\n')
2350
2349
2351 @command('debuglocks',
2350 @command('debuglocks',
2352 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2351 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2353 ('W', 'force-wlock', None,
2352 ('W', 'force-wlock', None,
2354 _('free the working state lock (DANGEROUS)'))],
2353 _('free the working state lock (DANGEROUS)'))],
2355 _(''))
2354 _(''))
2356 def debuglocks(ui, repo, **opts):
2355 def debuglocks(ui, repo, **opts):
2357 """show or modify state of locks
2356 """show or modify state of locks
2358
2357
2359 By default, this command will show which locks are held. This
2358 By default, this command will show which locks are held. This
2360 includes the user and process holding the lock, the amount of time
2359 includes the user and process holding the lock, the amount of time
2361 the lock has been held, and the machine name where the process is
2360 the lock has been held, and the machine name where the process is
2362 running if it's not local.
2361 running if it's not local.
2363
2362
2364 Locks protect the integrity of Mercurial's data, so should be
2363 Locks protect the integrity of Mercurial's data, so should be
2365 treated with care. System crashes or other interruptions may cause
2364 treated with care. System crashes or other interruptions may cause
2366 locks to not be properly released, though Mercurial will usually
2365 locks to not be properly released, though Mercurial will usually
2367 detect and remove such stale locks automatically.
2366 detect and remove such stale locks automatically.
2368
2367
2369 However, detecting stale locks may not always be possible (for
2368 However, detecting stale locks may not always be possible (for
2370 instance, on a shared filesystem). Removing locks may also be
2369 instance, on a shared filesystem). Removing locks may also be
2371 blocked by filesystem permissions.
2370 blocked by filesystem permissions.
2372
2371
2373 Returns 0 if no locks are held.
2372 Returns 0 if no locks are held.
2374
2373
2375 """
2374 """
2376
2375
2377 if opts.get('force_lock'):
2376 if opts.get('force_lock'):
2378 repo.svfs.unlink('lock')
2377 repo.svfs.unlink('lock')
2379 if opts.get('force_wlock'):
2378 if opts.get('force_wlock'):
2380 repo.vfs.unlink('wlock')
2379 repo.vfs.unlink('wlock')
2381 if opts.get('force_lock') or opts.get('force_lock'):
2380 if opts.get('force_lock') or opts.get('force_lock'):
2382 return 0
2381 return 0
2383
2382
2384 now = time.time()
2383 now = time.time()
2385 held = 0
2384 held = 0
2386
2385
2387 def report(vfs, name, method):
2386 def report(vfs, name, method):
2388 # this causes stale locks to get reaped for more accurate reporting
2387 # this causes stale locks to get reaped for more accurate reporting
2389 try:
2388 try:
2390 l = method(False)
2389 l = method(False)
2391 except error.LockHeld:
2390 except error.LockHeld:
2392 l = None
2391 l = None
2393
2392
2394 if l:
2393 if l:
2395 l.release()
2394 l.release()
2396 else:
2395 else:
2397 try:
2396 try:
2398 stat = repo.svfs.lstat(name)
2397 stat = repo.svfs.lstat(name)
2399 age = now - stat.st_mtime
2398 age = now - stat.st_mtime
2400 user = util.username(stat.st_uid)
2399 user = util.username(stat.st_uid)
2401 locker = vfs.readlock(name)
2400 locker = vfs.readlock(name)
2402 if ":" in locker:
2401 if ":" in locker:
2403 host, pid = locker.split(':')
2402 host, pid = locker.split(':')
2404 if host == socket.gethostname():
2403 if host == socket.gethostname():
2405 locker = 'user %s, process %s' % (user, pid)
2404 locker = 'user %s, process %s' % (user, pid)
2406 else:
2405 else:
2407 locker = 'user %s, process %s, host %s' \
2406 locker = 'user %s, process %s, host %s' \
2408 % (user, pid, host)
2407 % (user, pid, host)
2409 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2408 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2410 return 1
2409 return 1
2411 except OSError, e:
2410 except OSError, e:
2412 if e.errno != errno.ENOENT:
2411 if e.errno != errno.ENOENT:
2413 raise
2412 raise
2414
2413
2415 ui.write("%-6s free\n" % (name + ":"))
2414 ui.write("%-6s free\n" % (name + ":"))
2416 return 0
2415 return 0
2417
2416
2418 held += report(repo.svfs, "lock", repo.lock)
2417 held += report(repo.svfs, "lock", repo.lock)
2419 held += report(repo.vfs, "wlock", repo.wlock)
2418 held += report(repo.vfs, "wlock", repo.wlock)
2420
2419
2421 return held
2420 return held
2422
2421
2423 @command('debugobsolete',
2422 @command('debugobsolete',
2424 [('', 'flags', 0, _('markers flag')),
2423 [('', 'flags', 0, _('markers flag')),
2425 ('', 'record-parents', False,
2424 ('', 'record-parents', False,
2426 _('record parent information for the precursor')),
2425 _('record parent information for the precursor')),
2427 ('r', 'rev', [], _('display markers relevant to REV')),
2426 ('r', 'rev', [], _('display markers relevant to REV')),
2428 ] + commitopts2,
2427 ] + commitopts2,
2429 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2428 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2430 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2429 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2431 """create arbitrary obsolete marker
2430 """create arbitrary obsolete marker
2432
2431
2433 With no arguments, displays the list of obsolescence markers."""
2432 With no arguments, displays the list of obsolescence markers."""
2434
2433
2435 def parsenodeid(s):
2434 def parsenodeid(s):
2436 try:
2435 try:
2437 # We do not use revsingle/revrange functions here to accept
2436 # We do not use revsingle/revrange functions here to accept
2438 # arbitrary node identifiers, possibly not present in the
2437 # arbitrary node identifiers, possibly not present in the
2439 # local repository.
2438 # local repository.
2440 n = bin(s)
2439 n = bin(s)
2441 if len(n) != len(nullid):
2440 if len(n) != len(nullid):
2442 raise TypeError()
2441 raise TypeError()
2443 return n
2442 return n
2444 except TypeError:
2443 except TypeError:
2445 raise util.Abort('changeset references must be full hexadecimal '
2444 raise util.Abort('changeset references must be full hexadecimal '
2446 'node identifiers')
2445 'node identifiers')
2447
2446
2448 if precursor is not None:
2447 if precursor is not None:
2449 if opts['rev']:
2448 if opts['rev']:
2450 raise util.Abort('cannot select revision when creating marker')
2449 raise util.Abort('cannot select revision when creating marker')
2451 metadata = {}
2450 metadata = {}
2452 metadata['user'] = opts['user'] or ui.username()
2451 metadata['user'] = opts['user'] or ui.username()
2453 succs = tuple(parsenodeid(succ) for succ in successors)
2452 succs = tuple(parsenodeid(succ) for succ in successors)
2454 l = repo.lock()
2453 l = repo.lock()
2455 try:
2454 try:
2456 tr = repo.transaction('debugobsolete')
2455 tr = repo.transaction('debugobsolete')
2457 try:
2456 try:
2458 try:
2457 try:
2459 date = opts.get('date')
2458 date = opts.get('date')
2460 if date:
2459 if date:
2461 date = util.parsedate(date)
2460 date = util.parsedate(date)
2462 else:
2461 else:
2463 date = None
2462 date = None
2464 prec = parsenodeid(precursor)
2463 prec = parsenodeid(precursor)
2465 parents = None
2464 parents = None
2466 if opts['record_parents']:
2465 if opts['record_parents']:
2467 if prec not in repo.unfiltered():
2466 if prec not in repo.unfiltered():
2468 raise util.Abort('cannot used --record-parents on '
2467 raise util.Abort('cannot used --record-parents on '
2469 'unknown changesets')
2468 'unknown changesets')
2470 parents = repo.unfiltered()[prec].parents()
2469 parents = repo.unfiltered()[prec].parents()
2471 parents = tuple(p.node() for p in parents)
2470 parents = tuple(p.node() for p in parents)
2472 repo.obsstore.create(tr, prec, succs, opts['flags'],
2471 repo.obsstore.create(tr, prec, succs, opts['flags'],
2473 parents=parents, date=date,
2472 parents=parents, date=date,
2474 metadata=metadata)
2473 metadata=metadata)
2475 tr.close()
2474 tr.close()
2476 except ValueError, exc:
2475 except ValueError, exc:
2477 raise util.Abort(_('bad obsmarker input: %s') % exc)
2476 raise util.Abort(_('bad obsmarker input: %s') % exc)
2478 finally:
2477 finally:
2479 tr.release()
2478 tr.release()
2480 finally:
2479 finally:
2481 l.release()
2480 l.release()
2482 else:
2481 else:
2483 if opts['rev']:
2482 if opts['rev']:
2484 revs = scmutil.revrange(repo, opts['rev'])
2483 revs = scmutil.revrange(repo, opts['rev'])
2485 nodes = [repo[r].node() for r in revs]
2484 nodes = [repo[r].node() for r in revs]
2486 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2485 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2487 markers.sort(key=lambda x: x._data)
2486 markers.sort(key=lambda x: x._data)
2488 else:
2487 else:
2489 markers = obsolete.getmarkers(repo)
2488 markers = obsolete.getmarkers(repo)
2490
2489
2491 for m in markers:
2490 for m in markers:
2492 cmdutil.showmarker(ui, m)
2491 cmdutil.showmarker(ui, m)
2493
2492
2494 @command('debugpathcomplete',
2493 @command('debugpathcomplete',
2495 [('f', 'full', None, _('complete an entire path')),
2494 [('f', 'full', None, _('complete an entire path')),
2496 ('n', 'normal', None, _('show only normal files')),
2495 ('n', 'normal', None, _('show only normal files')),
2497 ('a', 'added', None, _('show only added files')),
2496 ('a', 'added', None, _('show only added files')),
2498 ('r', 'removed', None, _('show only removed files'))],
2497 ('r', 'removed', None, _('show only removed files'))],
2499 _('FILESPEC...'))
2498 _('FILESPEC...'))
2500 def debugpathcomplete(ui, repo, *specs, **opts):
2499 def debugpathcomplete(ui, repo, *specs, **opts):
2501 '''complete part or all of a tracked path
2500 '''complete part or all of a tracked path
2502
2501
2503 This command supports shells that offer path name completion. It
2502 This command supports shells that offer path name completion. It
2504 currently completes only files already known to the dirstate.
2503 currently completes only files already known to the dirstate.
2505
2504
2506 Completion extends only to the next path segment unless
2505 Completion extends only to the next path segment unless
2507 --full is specified, in which case entire paths are used.'''
2506 --full is specified, in which case entire paths are used.'''
2508
2507
2509 def complete(path, acceptable):
2508 def complete(path, acceptable):
2510 dirstate = repo.dirstate
2509 dirstate = repo.dirstate
2511 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2510 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2512 rootdir = repo.root + os.sep
2511 rootdir = repo.root + os.sep
2513 if spec != repo.root and not spec.startswith(rootdir):
2512 if spec != repo.root and not spec.startswith(rootdir):
2514 return [], []
2513 return [], []
2515 if os.path.isdir(spec):
2514 if os.path.isdir(spec):
2516 spec += '/'
2515 spec += '/'
2517 spec = spec[len(rootdir):]
2516 spec = spec[len(rootdir):]
2518 fixpaths = os.sep != '/'
2517 fixpaths = os.sep != '/'
2519 if fixpaths:
2518 if fixpaths:
2520 spec = spec.replace(os.sep, '/')
2519 spec = spec.replace(os.sep, '/')
2521 speclen = len(spec)
2520 speclen = len(spec)
2522 fullpaths = opts['full']
2521 fullpaths = opts['full']
2523 files, dirs = set(), set()
2522 files, dirs = set(), set()
2524 adddir, addfile = dirs.add, files.add
2523 adddir, addfile = dirs.add, files.add
2525 for f, st in dirstate.iteritems():
2524 for f, st in dirstate.iteritems():
2526 if f.startswith(spec) and st[0] in acceptable:
2525 if f.startswith(spec) and st[0] in acceptable:
2527 if fixpaths:
2526 if fixpaths:
2528 f = f.replace('/', os.sep)
2527 f = f.replace('/', os.sep)
2529 if fullpaths:
2528 if fullpaths:
2530 addfile(f)
2529 addfile(f)
2531 continue
2530 continue
2532 s = f.find(os.sep, speclen)
2531 s = f.find(os.sep, speclen)
2533 if s >= 0:
2532 if s >= 0:
2534 adddir(f[:s])
2533 adddir(f[:s])
2535 else:
2534 else:
2536 addfile(f)
2535 addfile(f)
2537 return files, dirs
2536 return files, dirs
2538
2537
2539 acceptable = ''
2538 acceptable = ''
2540 if opts['normal']:
2539 if opts['normal']:
2541 acceptable += 'nm'
2540 acceptable += 'nm'
2542 if opts['added']:
2541 if opts['added']:
2543 acceptable += 'a'
2542 acceptable += 'a'
2544 if opts['removed']:
2543 if opts['removed']:
2545 acceptable += 'r'
2544 acceptable += 'r'
2546 cwd = repo.getcwd()
2545 cwd = repo.getcwd()
2547 if not specs:
2546 if not specs:
2548 specs = ['.']
2547 specs = ['.']
2549
2548
2550 files, dirs = set(), set()
2549 files, dirs = set(), set()
2551 for spec in specs:
2550 for spec in specs:
2552 f, d = complete(spec, acceptable or 'nmar')
2551 f, d = complete(spec, acceptable or 'nmar')
2553 files.update(f)
2552 files.update(f)
2554 dirs.update(d)
2553 dirs.update(d)
2555 files.update(dirs)
2554 files.update(dirs)
2556 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2555 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2557 ui.write('\n')
2556 ui.write('\n')
2558
2557
2559 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2558 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2560 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2559 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2561 '''access the pushkey key/value protocol
2560 '''access the pushkey key/value protocol
2562
2561
2563 With two args, list the keys in the given namespace.
2562 With two args, list the keys in the given namespace.
2564
2563
2565 With five args, set a key to new if it currently is set to old.
2564 With five args, set a key to new if it currently is set to old.
2566 Reports success or failure.
2565 Reports success or failure.
2567 '''
2566 '''
2568
2567
2569 target = hg.peer(ui, {}, repopath)
2568 target = hg.peer(ui, {}, repopath)
2570 if keyinfo:
2569 if keyinfo:
2571 key, old, new = keyinfo
2570 key, old, new = keyinfo
2572 r = target.pushkey(namespace, key, old, new)
2571 r = target.pushkey(namespace, key, old, new)
2573 ui.status(str(r) + '\n')
2572 ui.status(str(r) + '\n')
2574 return not r
2573 return not r
2575 else:
2574 else:
2576 for k, v in sorted(target.listkeys(namespace).iteritems()):
2575 for k, v in sorted(target.listkeys(namespace).iteritems()):
2577 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2576 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2578 v.encode('string-escape')))
2577 v.encode('string-escape')))
2579
2578
2580 @command('debugpvec', [], _('A B'))
2579 @command('debugpvec', [], _('A B'))
2581 def debugpvec(ui, repo, a, b=None):
2580 def debugpvec(ui, repo, a, b=None):
2582 ca = scmutil.revsingle(repo, a)
2581 ca = scmutil.revsingle(repo, a)
2583 cb = scmutil.revsingle(repo, b)
2582 cb = scmutil.revsingle(repo, b)
2584 pa = pvec.ctxpvec(ca)
2583 pa = pvec.ctxpvec(ca)
2585 pb = pvec.ctxpvec(cb)
2584 pb = pvec.ctxpvec(cb)
2586 if pa == pb:
2585 if pa == pb:
2587 rel = "="
2586 rel = "="
2588 elif pa > pb:
2587 elif pa > pb:
2589 rel = ">"
2588 rel = ">"
2590 elif pa < pb:
2589 elif pa < pb:
2591 rel = "<"
2590 rel = "<"
2592 elif pa | pb:
2591 elif pa | pb:
2593 rel = "|"
2592 rel = "|"
2594 ui.write(_("a: %s\n") % pa)
2593 ui.write(_("a: %s\n") % pa)
2595 ui.write(_("b: %s\n") % pb)
2594 ui.write(_("b: %s\n") % pb)
2596 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2595 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2597 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2596 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2598 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2597 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2599 pa.distance(pb), rel))
2598 pa.distance(pb), rel))
2600
2599
2601 @command('debugrebuilddirstate|debugrebuildstate',
2600 @command('debugrebuilddirstate|debugrebuildstate',
2602 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2601 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2603 _('[-r REV]'))
2602 _('[-r REV]'))
2604 def debugrebuilddirstate(ui, repo, rev):
2603 def debugrebuilddirstate(ui, repo, rev):
2605 """rebuild the dirstate as it would look like for the given revision
2604 """rebuild the dirstate as it would look like for the given revision
2606
2605
2607 If no revision is specified the first current parent will be used.
2606 If no revision is specified the first current parent will be used.
2608
2607
2609 The dirstate will be set to the files of the given revision.
2608 The dirstate will be set to the files of the given revision.
2610 The actual working directory content or existing dirstate
2609 The actual working directory content or existing dirstate
2611 information such as adds or removes is not considered.
2610 information such as adds or removes is not considered.
2612
2611
2613 One use of this command is to make the next :hg:`status` invocation
2612 One use of this command is to make the next :hg:`status` invocation
2614 check the actual file content.
2613 check the actual file content.
2615 """
2614 """
2616 ctx = scmutil.revsingle(repo, rev)
2615 ctx = scmutil.revsingle(repo, rev)
2617 wlock = repo.wlock()
2616 wlock = repo.wlock()
2618 try:
2617 try:
2619 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2618 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2620 finally:
2619 finally:
2621 wlock.release()
2620 wlock.release()
2622
2621
2623 @command('debugrename',
2622 @command('debugrename',
2624 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2623 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2625 _('[-r REV] FILE'))
2624 _('[-r REV] FILE'))
2626 def debugrename(ui, repo, file1, *pats, **opts):
2625 def debugrename(ui, repo, file1, *pats, **opts):
2627 """dump rename information"""
2626 """dump rename information"""
2628
2627
2629 ctx = scmutil.revsingle(repo, opts.get('rev'))
2628 ctx = scmutil.revsingle(repo, opts.get('rev'))
2630 m = scmutil.match(ctx, (file1,) + pats, opts)
2629 m = scmutil.match(ctx, (file1,) + pats, opts)
2631 for abs in ctx.walk(m):
2630 for abs in ctx.walk(m):
2632 fctx = ctx[abs]
2631 fctx = ctx[abs]
2633 o = fctx.filelog().renamed(fctx.filenode())
2632 o = fctx.filelog().renamed(fctx.filenode())
2634 rel = m.rel(abs)
2633 rel = m.rel(abs)
2635 if o:
2634 if o:
2636 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2635 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2637 else:
2636 else:
2638 ui.write(_("%s not renamed\n") % rel)
2637 ui.write(_("%s not renamed\n") % rel)
2639
2638
2640 @command('debugrevlog',
2639 @command('debugrevlog',
2641 [('c', 'changelog', False, _('open changelog')),
2640 [('c', 'changelog', False, _('open changelog')),
2642 ('m', 'manifest', False, _('open manifest')),
2641 ('m', 'manifest', False, _('open manifest')),
2643 ('d', 'dump', False, _('dump index data'))],
2642 ('d', 'dump', False, _('dump index data'))],
2644 _('-c|-m|FILE'),
2643 _('-c|-m|FILE'),
2645 optionalrepo=True)
2644 optionalrepo=True)
2646 def debugrevlog(ui, repo, file_=None, **opts):
2645 def debugrevlog(ui, repo, file_=None, **opts):
2647 """show data and statistics about a revlog"""
2646 """show data and statistics about a revlog"""
2648 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2647 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2649
2648
2650 if opts.get("dump"):
2649 if opts.get("dump"):
2651 numrevs = len(r)
2650 numrevs = len(r)
2652 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2651 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2653 " rawsize totalsize compression heads chainlen\n")
2652 " rawsize totalsize compression heads chainlen\n")
2654 ts = 0
2653 ts = 0
2655 heads = set()
2654 heads = set()
2656 rindex = r.index
2655 rindex = r.index
2657
2656
2658 def chainbaseandlen(rev):
2657 def chainbaseandlen(rev):
2659 clen = 0
2658 clen = 0
2660 base = rindex[rev][3]
2659 base = rindex[rev][3]
2661 while base != rev:
2660 while base != rev:
2662 clen += 1
2661 clen += 1
2663 rev = base
2662 rev = base
2664 base = rindex[rev][3]
2663 base = rindex[rev][3]
2665 return base, clen
2664 return base, clen
2666
2665
2667 for rev in xrange(numrevs):
2666 for rev in xrange(numrevs):
2668 dbase = r.deltaparent(rev)
2667 dbase = r.deltaparent(rev)
2669 if dbase == -1:
2668 if dbase == -1:
2670 dbase = rev
2669 dbase = rev
2671 cbase, clen = chainbaseandlen(rev)
2670 cbase, clen = chainbaseandlen(rev)
2672 p1, p2 = r.parentrevs(rev)
2671 p1, p2 = r.parentrevs(rev)
2673 rs = r.rawsize(rev)
2672 rs = r.rawsize(rev)
2674 ts = ts + rs
2673 ts = ts + rs
2675 heads -= set(r.parentrevs(rev))
2674 heads -= set(r.parentrevs(rev))
2676 heads.add(rev)
2675 heads.add(rev)
2677 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2676 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2678 "%11d %5d %8d\n" %
2677 "%11d %5d %8d\n" %
2679 (rev, p1, p2, r.start(rev), r.end(rev),
2678 (rev, p1, p2, r.start(rev), r.end(rev),
2680 r.start(dbase), r.start(cbase),
2679 r.start(dbase), r.start(cbase),
2681 r.start(p1), r.start(p2),
2680 r.start(p1), r.start(p2),
2682 rs, ts, ts / r.end(rev), len(heads), clen))
2681 rs, ts, ts / r.end(rev), len(heads), clen))
2683 return 0
2682 return 0
2684
2683
2685 v = r.version
2684 v = r.version
2686 format = v & 0xFFFF
2685 format = v & 0xFFFF
2687 flags = []
2686 flags = []
2688 gdelta = False
2687 gdelta = False
2689 if v & revlog.REVLOGNGINLINEDATA:
2688 if v & revlog.REVLOGNGINLINEDATA:
2690 flags.append('inline')
2689 flags.append('inline')
2691 if v & revlog.REVLOGGENERALDELTA:
2690 if v & revlog.REVLOGGENERALDELTA:
2692 gdelta = True
2691 gdelta = True
2693 flags.append('generaldelta')
2692 flags.append('generaldelta')
2694 if not flags:
2693 if not flags:
2695 flags = ['(none)']
2694 flags = ['(none)']
2696
2695
2697 nummerges = 0
2696 nummerges = 0
2698 numfull = 0
2697 numfull = 0
2699 numprev = 0
2698 numprev = 0
2700 nump1 = 0
2699 nump1 = 0
2701 nump2 = 0
2700 nump2 = 0
2702 numother = 0
2701 numother = 0
2703 nump1prev = 0
2702 nump1prev = 0
2704 nump2prev = 0
2703 nump2prev = 0
2705 chainlengths = []
2704 chainlengths = []
2706
2705
2707 datasize = [None, 0, 0L]
2706 datasize = [None, 0, 0L]
2708 fullsize = [None, 0, 0L]
2707 fullsize = [None, 0, 0L]
2709 deltasize = [None, 0, 0L]
2708 deltasize = [None, 0, 0L]
2710
2709
2711 def addsize(size, l):
2710 def addsize(size, l):
2712 if l[0] is None or size < l[0]:
2711 if l[0] is None or size < l[0]:
2713 l[0] = size
2712 l[0] = size
2714 if size > l[1]:
2713 if size > l[1]:
2715 l[1] = size
2714 l[1] = size
2716 l[2] += size
2715 l[2] += size
2717
2716
2718 numrevs = len(r)
2717 numrevs = len(r)
2719 for rev in xrange(numrevs):
2718 for rev in xrange(numrevs):
2720 p1, p2 = r.parentrevs(rev)
2719 p1, p2 = r.parentrevs(rev)
2721 delta = r.deltaparent(rev)
2720 delta = r.deltaparent(rev)
2722 if format > 0:
2721 if format > 0:
2723 addsize(r.rawsize(rev), datasize)
2722 addsize(r.rawsize(rev), datasize)
2724 if p2 != nullrev:
2723 if p2 != nullrev:
2725 nummerges += 1
2724 nummerges += 1
2726 size = r.length(rev)
2725 size = r.length(rev)
2727 if delta == nullrev:
2726 if delta == nullrev:
2728 chainlengths.append(0)
2727 chainlengths.append(0)
2729 numfull += 1
2728 numfull += 1
2730 addsize(size, fullsize)
2729 addsize(size, fullsize)
2731 else:
2730 else:
2732 chainlengths.append(chainlengths[delta] + 1)
2731 chainlengths.append(chainlengths[delta] + 1)
2733 addsize(size, deltasize)
2732 addsize(size, deltasize)
2734 if delta == rev - 1:
2733 if delta == rev - 1:
2735 numprev += 1
2734 numprev += 1
2736 if delta == p1:
2735 if delta == p1:
2737 nump1prev += 1
2736 nump1prev += 1
2738 elif delta == p2:
2737 elif delta == p2:
2739 nump2prev += 1
2738 nump2prev += 1
2740 elif delta == p1:
2739 elif delta == p1:
2741 nump1 += 1
2740 nump1 += 1
2742 elif delta == p2:
2741 elif delta == p2:
2743 nump2 += 1
2742 nump2 += 1
2744 elif delta != nullrev:
2743 elif delta != nullrev:
2745 numother += 1
2744 numother += 1
2746
2745
2747 # Adjust size min value for empty cases
2746 # Adjust size min value for empty cases
2748 for size in (datasize, fullsize, deltasize):
2747 for size in (datasize, fullsize, deltasize):
2749 if size[0] is None:
2748 if size[0] is None:
2750 size[0] = 0
2749 size[0] = 0
2751
2750
2752 numdeltas = numrevs - numfull
2751 numdeltas = numrevs - numfull
2753 numoprev = numprev - nump1prev - nump2prev
2752 numoprev = numprev - nump1prev - nump2prev
2754 totalrawsize = datasize[2]
2753 totalrawsize = datasize[2]
2755 datasize[2] /= numrevs
2754 datasize[2] /= numrevs
2756 fulltotal = fullsize[2]
2755 fulltotal = fullsize[2]
2757 fullsize[2] /= numfull
2756 fullsize[2] /= numfull
2758 deltatotal = deltasize[2]
2757 deltatotal = deltasize[2]
2759 if numrevs - numfull > 0:
2758 if numrevs - numfull > 0:
2760 deltasize[2] /= numrevs - numfull
2759 deltasize[2] /= numrevs - numfull
2761 totalsize = fulltotal + deltatotal
2760 totalsize = fulltotal + deltatotal
2762 avgchainlen = sum(chainlengths) / numrevs
2761 avgchainlen = sum(chainlengths) / numrevs
2763 compratio = totalrawsize / totalsize
2762 compratio = totalrawsize / totalsize
2764
2763
2765 basedfmtstr = '%%%dd\n'
2764 basedfmtstr = '%%%dd\n'
2766 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2765 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2767
2766
2768 def dfmtstr(max):
2767 def dfmtstr(max):
2769 return basedfmtstr % len(str(max))
2768 return basedfmtstr % len(str(max))
2770 def pcfmtstr(max, padding=0):
2769 def pcfmtstr(max, padding=0):
2771 return basepcfmtstr % (len(str(max)), ' ' * padding)
2770 return basepcfmtstr % (len(str(max)), ' ' * padding)
2772
2771
2773 def pcfmt(value, total):
2772 def pcfmt(value, total):
2774 return (value, 100 * float(value) / total)
2773 return (value, 100 * float(value) / total)
2775
2774
2776 ui.write(('format : %d\n') % format)
2775 ui.write(('format : %d\n') % format)
2777 ui.write(('flags : %s\n') % ', '.join(flags))
2776 ui.write(('flags : %s\n') % ', '.join(flags))
2778
2777
2779 ui.write('\n')
2778 ui.write('\n')
2780 fmt = pcfmtstr(totalsize)
2779 fmt = pcfmtstr(totalsize)
2781 fmt2 = dfmtstr(totalsize)
2780 fmt2 = dfmtstr(totalsize)
2782 ui.write(('revisions : ') + fmt2 % numrevs)
2781 ui.write(('revisions : ') + fmt2 % numrevs)
2783 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2782 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2784 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2783 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2785 ui.write(('revisions : ') + fmt2 % numrevs)
2784 ui.write(('revisions : ') + fmt2 % numrevs)
2786 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2785 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2787 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2786 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2788 ui.write(('revision size : ') + fmt2 % totalsize)
2787 ui.write(('revision size : ') + fmt2 % totalsize)
2789 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2788 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2790 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2789 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2791
2790
2792 ui.write('\n')
2791 ui.write('\n')
2793 fmt = dfmtstr(max(avgchainlen, compratio))
2792 fmt = dfmtstr(max(avgchainlen, compratio))
2794 ui.write(('avg chain length : ') + fmt % avgchainlen)
2793 ui.write(('avg chain length : ') + fmt % avgchainlen)
2795 ui.write(('compression ratio : ') + fmt % compratio)
2794 ui.write(('compression ratio : ') + fmt % compratio)
2796
2795
2797 if format > 0:
2796 if format > 0:
2798 ui.write('\n')
2797 ui.write('\n')
2799 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2798 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2800 % tuple(datasize))
2799 % tuple(datasize))
2801 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2800 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2802 % tuple(fullsize))
2801 % tuple(fullsize))
2803 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2802 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2804 % tuple(deltasize))
2803 % tuple(deltasize))
2805
2804
2806 if numdeltas > 0:
2805 if numdeltas > 0:
2807 ui.write('\n')
2806 ui.write('\n')
2808 fmt = pcfmtstr(numdeltas)
2807 fmt = pcfmtstr(numdeltas)
2809 fmt2 = pcfmtstr(numdeltas, 4)
2808 fmt2 = pcfmtstr(numdeltas, 4)
2810 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2809 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2811 if numprev > 0:
2810 if numprev > 0:
2812 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2811 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2813 numprev))
2812 numprev))
2814 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2813 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2815 numprev))
2814 numprev))
2816 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2815 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2817 numprev))
2816 numprev))
2818 if gdelta:
2817 if gdelta:
2819 ui.write(('deltas against p1 : ')
2818 ui.write(('deltas against p1 : ')
2820 + fmt % pcfmt(nump1, numdeltas))
2819 + fmt % pcfmt(nump1, numdeltas))
2821 ui.write(('deltas against p2 : ')
2820 ui.write(('deltas against p2 : ')
2822 + fmt % pcfmt(nump2, numdeltas))
2821 + fmt % pcfmt(nump2, numdeltas))
2823 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2822 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2824 numdeltas))
2823 numdeltas))
2825
2824
2826 @command('debugrevspec',
2825 @command('debugrevspec',
2827 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2826 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2828 ('REVSPEC'))
2827 ('REVSPEC'))
2829 def debugrevspec(ui, repo, expr, **opts):
2828 def debugrevspec(ui, repo, expr, **opts):
2830 """parse and apply a revision specification
2829 """parse and apply a revision specification
2831
2830
2832 Use --verbose to print the parsed tree before and after aliases
2831 Use --verbose to print the parsed tree before and after aliases
2833 expansion.
2832 expansion.
2834 """
2833 """
2835 if ui.verbose:
2834 if ui.verbose:
2836 tree = revset.parse(expr)[0]
2835 tree = revset.parse(expr)[0]
2837 ui.note(revset.prettyformat(tree), "\n")
2836 ui.note(revset.prettyformat(tree), "\n")
2838 newtree = revset.findaliases(ui, tree)
2837 newtree = revset.findaliases(ui, tree)
2839 if newtree != tree:
2838 if newtree != tree:
2840 ui.note(revset.prettyformat(newtree), "\n")
2839 ui.note(revset.prettyformat(newtree), "\n")
2841 if opts["optimize"]:
2840 if opts["optimize"]:
2842 weight, optimizedtree = revset.optimize(newtree, True)
2841 weight, optimizedtree = revset.optimize(newtree, True)
2843 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2842 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2844 func = revset.match(ui, expr)
2843 func = revset.match(ui, expr)
2845 for c in func(repo, revset.spanset(repo)):
2844 for c in func(repo, revset.spanset(repo)):
2846 ui.write("%s\n" % c)
2845 ui.write("%s\n" % c)
2847
2846
2848 @command('debugsetparents', [], _('REV1 [REV2]'))
2847 @command('debugsetparents', [], _('REV1 [REV2]'))
2849 def debugsetparents(ui, repo, rev1, rev2=None):
2848 def debugsetparents(ui, repo, rev1, rev2=None):
2850 """manually set the parents of the current working directory
2849 """manually set the parents of the current working directory
2851
2850
2852 This is useful for writing repository conversion tools, but should
2851 This is useful for writing repository conversion tools, but should
2853 be used with care.
2852 be used with care.
2854
2853
2855 Returns 0 on success.
2854 Returns 0 on success.
2856 """
2855 """
2857
2856
2858 r1 = scmutil.revsingle(repo, rev1).node()
2857 r1 = scmutil.revsingle(repo, rev1).node()
2859 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2858 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2860
2859
2861 wlock = repo.wlock()
2860 wlock = repo.wlock()
2862 try:
2861 try:
2863 repo.dirstate.beginparentchange()
2862 repo.dirstate.beginparentchange()
2864 repo.setparents(r1, r2)
2863 repo.setparents(r1, r2)
2865 repo.dirstate.endparentchange()
2864 repo.dirstate.endparentchange()
2866 finally:
2865 finally:
2867 wlock.release()
2866 wlock.release()
2868
2867
2869 @command('debugdirstate|debugstate',
2868 @command('debugdirstate|debugstate',
2870 [('', 'nodates', None, _('do not display the saved mtime')),
2869 [('', 'nodates', None, _('do not display the saved mtime')),
2871 ('', 'datesort', None, _('sort by saved mtime'))],
2870 ('', 'datesort', None, _('sort by saved mtime'))],
2872 _('[OPTION]...'))
2871 _('[OPTION]...'))
2873 def debugstate(ui, repo, nodates=None, datesort=None):
2872 def debugstate(ui, repo, nodates=None, datesort=None):
2874 """show the contents of the current dirstate"""
2873 """show the contents of the current dirstate"""
2875 timestr = ""
2874 timestr = ""
2876 showdate = not nodates
2875 showdate = not nodates
2877 if datesort:
2876 if datesort:
2878 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2877 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2879 else:
2878 else:
2880 keyfunc = None # sort by filename
2879 keyfunc = None # sort by filename
2881 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2880 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2882 if showdate:
2881 if showdate:
2883 if ent[3] == -1:
2882 if ent[3] == -1:
2884 # Pad or slice to locale representation
2883 # Pad or slice to locale representation
2885 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2884 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2886 time.localtime(0)))
2885 time.localtime(0)))
2887 timestr = 'unset'
2886 timestr = 'unset'
2888 timestr = (timestr[:locale_len] +
2887 timestr = (timestr[:locale_len] +
2889 ' ' * (locale_len - len(timestr)))
2888 ' ' * (locale_len - len(timestr)))
2890 else:
2889 else:
2891 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2890 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2892 time.localtime(ent[3]))
2891 time.localtime(ent[3]))
2893 if ent[1] & 020000:
2892 if ent[1] & 020000:
2894 mode = 'lnk'
2893 mode = 'lnk'
2895 else:
2894 else:
2896 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2895 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2897 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2896 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2898 for f in repo.dirstate.copies():
2897 for f in repo.dirstate.copies():
2899 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2898 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2900
2899
2901 @command('debugsub',
2900 @command('debugsub',
2902 [('r', 'rev', '',
2901 [('r', 'rev', '',
2903 _('revision to check'), _('REV'))],
2902 _('revision to check'), _('REV'))],
2904 _('[-r REV] [REV]'))
2903 _('[-r REV] [REV]'))
2905 def debugsub(ui, repo, rev=None):
2904 def debugsub(ui, repo, rev=None):
2906 ctx = scmutil.revsingle(repo, rev, None)
2905 ctx = scmutil.revsingle(repo, rev, None)
2907 for k, v in sorted(ctx.substate.items()):
2906 for k, v in sorted(ctx.substate.items()):
2908 ui.write(('path %s\n') % k)
2907 ui.write(('path %s\n') % k)
2909 ui.write((' source %s\n') % v[0])
2908 ui.write((' source %s\n') % v[0])
2910 ui.write((' revision %s\n') % v[1])
2909 ui.write((' revision %s\n') % v[1])
2911
2910
2912 @command('debugsuccessorssets',
2911 @command('debugsuccessorssets',
2913 [],
2912 [],
2914 _('[REV]'))
2913 _('[REV]'))
2915 def debugsuccessorssets(ui, repo, *revs):
2914 def debugsuccessorssets(ui, repo, *revs):
2916 """show set of successors for revision
2915 """show set of successors for revision
2917
2916
2918 A successors set of changeset A is a consistent group of revisions that
2917 A successors set of changeset A is a consistent group of revisions that
2919 succeed A. It contains non-obsolete changesets only.
2918 succeed A. It contains non-obsolete changesets only.
2920
2919
2921 In most cases a changeset A has a single successors set containing a single
2920 In most cases a changeset A has a single successors set containing a single
2922 successor (changeset A replaced by A').
2921 successor (changeset A replaced by A').
2923
2922
2924 A changeset that is made obsolete with no successors are called "pruned".
2923 A changeset that is made obsolete with no successors are called "pruned".
2925 Such changesets have no successors sets at all.
2924 Such changesets have no successors sets at all.
2926
2925
2927 A changeset that has been "split" will have a successors set containing
2926 A changeset that has been "split" will have a successors set containing
2928 more than one successor.
2927 more than one successor.
2929
2928
2930 A changeset that has been rewritten in multiple different ways is called
2929 A changeset that has been rewritten in multiple different ways is called
2931 "divergent". Such changesets have multiple successor sets (each of which
2930 "divergent". Such changesets have multiple successor sets (each of which
2932 may also be split, i.e. have multiple successors).
2931 may also be split, i.e. have multiple successors).
2933
2932
2934 Results are displayed as follows::
2933 Results are displayed as follows::
2935
2934
2936 <rev1>
2935 <rev1>
2937 <successors-1A>
2936 <successors-1A>
2938 <rev2>
2937 <rev2>
2939 <successors-2A>
2938 <successors-2A>
2940 <successors-2B1> <successors-2B2> <successors-2B3>
2939 <successors-2B1> <successors-2B2> <successors-2B3>
2941
2940
2942 Here rev2 has two possible (i.e. divergent) successors sets. The first
2941 Here rev2 has two possible (i.e. divergent) successors sets. The first
2943 holds one element, whereas the second holds three (i.e. the changeset has
2942 holds one element, whereas the second holds three (i.e. the changeset has
2944 been split).
2943 been split).
2945 """
2944 """
2946 # passed to successorssets caching computation from one call to another
2945 # passed to successorssets caching computation from one call to another
2947 cache = {}
2946 cache = {}
2948 ctx2str = str
2947 ctx2str = str
2949 node2str = short
2948 node2str = short
2950 if ui.debug():
2949 if ui.debug():
2951 def ctx2str(ctx):
2950 def ctx2str(ctx):
2952 return ctx.hex()
2951 return ctx.hex()
2953 node2str = hex
2952 node2str = hex
2954 for rev in scmutil.revrange(repo, revs):
2953 for rev in scmutil.revrange(repo, revs):
2955 ctx = repo[rev]
2954 ctx = repo[rev]
2956 ui.write('%s\n'% ctx2str(ctx))
2955 ui.write('%s\n'% ctx2str(ctx))
2957 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2956 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2958 if succsset:
2957 if succsset:
2959 ui.write(' ')
2958 ui.write(' ')
2960 ui.write(node2str(succsset[0]))
2959 ui.write(node2str(succsset[0]))
2961 for node in succsset[1:]:
2960 for node in succsset[1:]:
2962 ui.write(' ')
2961 ui.write(' ')
2963 ui.write(node2str(node))
2962 ui.write(node2str(node))
2964 ui.write('\n')
2963 ui.write('\n')
2965
2964
2966 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2965 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2967 def debugwalk(ui, repo, *pats, **opts):
2966 def debugwalk(ui, repo, *pats, **opts):
2968 """show how files match on given patterns"""
2967 """show how files match on given patterns"""
2969 m = scmutil.match(repo[None], pats, opts)
2968 m = scmutil.match(repo[None], pats, opts)
2970 items = list(repo.walk(m))
2969 items = list(repo.walk(m))
2971 if not items:
2970 if not items:
2972 return
2971 return
2973 f = lambda fn: fn
2972 f = lambda fn: fn
2974 if ui.configbool('ui', 'slash') and os.sep != '/':
2973 if ui.configbool('ui', 'slash') and os.sep != '/':
2975 f = lambda fn: util.normpath(fn)
2974 f = lambda fn: util.normpath(fn)
2976 fmt = 'f %%-%ds %%-%ds %%s' % (
2975 fmt = 'f %%-%ds %%-%ds %%s' % (
2977 max([len(abs) for abs in items]),
2976 max([len(abs) for abs in items]),
2978 max([len(m.rel(abs)) for abs in items]))
2977 max([len(m.rel(abs)) for abs in items]))
2979 for abs in items:
2978 for abs in items:
2980 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2979 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2981 ui.write("%s\n" % line.rstrip())
2980 ui.write("%s\n" % line.rstrip())
2982
2981
2983 @command('debugwireargs',
2982 @command('debugwireargs',
2984 [('', 'three', '', 'three'),
2983 [('', 'three', '', 'three'),
2985 ('', 'four', '', 'four'),
2984 ('', 'four', '', 'four'),
2986 ('', 'five', '', 'five'),
2985 ('', 'five', '', 'five'),
2987 ] + remoteopts,
2986 ] + remoteopts,
2988 _('REPO [OPTIONS]... [ONE [TWO]]'),
2987 _('REPO [OPTIONS]... [ONE [TWO]]'),
2989 norepo=True)
2988 norepo=True)
2990 def debugwireargs(ui, repopath, *vals, **opts):
2989 def debugwireargs(ui, repopath, *vals, **opts):
2991 repo = hg.peer(ui, opts, repopath)
2990 repo = hg.peer(ui, opts, repopath)
2992 for opt in remoteopts:
2991 for opt in remoteopts:
2993 del opts[opt[1]]
2992 del opts[opt[1]]
2994 args = {}
2993 args = {}
2995 for k, v in opts.iteritems():
2994 for k, v in opts.iteritems():
2996 if v:
2995 if v:
2997 args[k] = v
2996 args[k] = v
2998 # run twice to check that we don't mess up the stream for the next command
2997 # run twice to check that we don't mess up the stream for the next command
2999 res1 = repo.debugwireargs(*vals, **args)
2998 res1 = repo.debugwireargs(*vals, **args)
3000 res2 = repo.debugwireargs(*vals, **args)
2999 res2 = repo.debugwireargs(*vals, **args)
3001 ui.write("%s\n" % res1)
3000 ui.write("%s\n" % res1)
3002 if res1 != res2:
3001 if res1 != res2:
3003 ui.warn("%s\n" % res2)
3002 ui.warn("%s\n" % res2)
3004
3003
3005 @command('^diff',
3004 @command('^diff',
3006 [('r', 'rev', [], _('revision'), _('REV')),
3005 [('r', 'rev', [], _('revision'), _('REV')),
3007 ('c', 'change', '', _('change made by revision'), _('REV'))
3006 ('c', 'change', '', _('change made by revision'), _('REV'))
3008 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3007 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3009 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3008 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3010 inferrepo=True)
3009 inferrepo=True)
3011 def diff(ui, repo, *pats, **opts):
3010 def diff(ui, repo, *pats, **opts):
3012 """diff repository (or selected files)
3011 """diff repository (or selected files)
3013
3012
3014 Show differences between revisions for the specified files.
3013 Show differences between revisions for the specified files.
3015
3014
3016 Differences between files are shown using the unified diff format.
3015 Differences between files are shown using the unified diff format.
3017
3016
3018 .. note::
3017 .. note::
3019
3018
3020 diff may generate unexpected results for merges, as it will
3019 diff may generate unexpected results for merges, as it will
3021 default to comparing against the working directory's first
3020 default to comparing against the working directory's first
3022 parent changeset if no revisions are specified.
3021 parent changeset if no revisions are specified.
3023
3022
3024 When two revision arguments are given, then changes are shown
3023 When two revision arguments are given, then changes are shown
3025 between those revisions. If only one revision is specified then
3024 between those revisions. If only one revision is specified then
3026 that revision is compared to the working directory, and, when no
3025 that revision is compared to the working directory, and, when no
3027 revisions are specified, the working directory files are compared
3026 revisions are specified, the working directory files are compared
3028 to its parent.
3027 to its parent.
3029
3028
3030 Alternatively you can specify -c/--change with a revision to see
3029 Alternatively you can specify -c/--change with a revision to see
3031 the changes in that changeset relative to its first parent.
3030 the changes in that changeset relative to its first parent.
3032
3031
3033 Without the -a/--text option, diff will avoid generating diffs of
3032 Without the -a/--text option, diff will avoid generating diffs of
3034 files it detects as binary. With -a, diff will generate a diff
3033 files it detects as binary. With -a, diff will generate a diff
3035 anyway, probably with undesirable results.
3034 anyway, probably with undesirable results.
3036
3035
3037 Use the -g/--git option to generate diffs in the git extended diff
3036 Use the -g/--git option to generate diffs in the git extended diff
3038 format. For more information, read :hg:`help diffs`.
3037 format. For more information, read :hg:`help diffs`.
3039
3038
3040 .. container:: verbose
3039 .. container:: verbose
3041
3040
3042 Examples:
3041 Examples:
3043
3042
3044 - compare a file in the current working directory to its parent::
3043 - compare a file in the current working directory to its parent::
3045
3044
3046 hg diff foo.c
3045 hg diff foo.c
3047
3046
3048 - compare two historical versions of a directory, with rename info::
3047 - compare two historical versions of a directory, with rename info::
3049
3048
3050 hg diff --git -r 1.0:1.2 lib/
3049 hg diff --git -r 1.0:1.2 lib/
3051
3050
3052 - get change stats relative to the last change on some date::
3051 - get change stats relative to the last change on some date::
3053
3052
3054 hg diff --stat -r "date('may 2')"
3053 hg diff --stat -r "date('may 2')"
3055
3054
3056 - diff all newly-added files that contain a keyword::
3055 - diff all newly-added files that contain a keyword::
3057
3056
3058 hg diff "set:added() and grep(GNU)"
3057 hg diff "set:added() and grep(GNU)"
3059
3058
3060 - compare a revision and its parents::
3059 - compare a revision and its parents::
3061
3060
3062 hg diff -c 9353 # compare against first parent
3061 hg diff -c 9353 # compare against first parent
3063 hg diff -r 9353^:9353 # same using revset syntax
3062 hg diff -r 9353^:9353 # same using revset syntax
3064 hg diff -r 9353^2:9353 # compare against the second parent
3063 hg diff -r 9353^2:9353 # compare against the second parent
3065
3064
3066 Returns 0 on success.
3065 Returns 0 on success.
3067 """
3066 """
3068
3067
3069 revs = opts.get('rev')
3068 revs = opts.get('rev')
3070 change = opts.get('change')
3069 change = opts.get('change')
3071 stat = opts.get('stat')
3070 stat = opts.get('stat')
3072 reverse = opts.get('reverse')
3071 reverse = opts.get('reverse')
3073
3072
3074 if revs and change:
3073 if revs and change:
3075 msg = _('cannot specify --rev and --change at the same time')
3074 msg = _('cannot specify --rev and --change at the same time')
3076 raise util.Abort(msg)
3075 raise util.Abort(msg)
3077 elif change:
3076 elif change:
3078 node2 = scmutil.revsingle(repo, change, None).node()
3077 node2 = scmutil.revsingle(repo, change, None).node()
3079 node1 = repo[node2].p1().node()
3078 node1 = repo[node2].p1().node()
3080 else:
3079 else:
3081 node1, node2 = scmutil.revpair(repo, revs)
3080 node1, node2 = scmutil.revpair(repo, revs)
3082
3081
3083 if reverse:
3082 if reverse:
3084 node1, node2 = node2, node1
3083 node1, node2 = node2, node1
3085
3084
3086 diffopts = patch.diffopts(ui, opts)
3085 diffopts = patch.diffopts(ui, opts)
3087 m = scmutil.match(repo[node2], pats, opts)
3086 m = scmutil.match(repo[node2], pats, opts)
3088 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3087 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3089 listsubrepos=opts.get('subrepos'))
3088 listsubrepos=opts.get('subrepos'))
3090
3089
3091 @command('^export',
3090 @command('^export',
3092 [('o', 'output', '',
3091 [('o', 'output', '',
3093 _('print output to file with formatted name'), _('FORMAT')),
3092 _('print output to file with formatted name'), _('FORMAT')),
3094 ('', 'switch-parent', None, _('diff against the second parent')),
3093 ('', 'switch-parent', None, _('diff against the second parent')),
3095 ('r', 'rev', [], _('revisions to export'), _('REV')),
3094 ('r', 'rev', [], _('revisions to export'), _('REV')),
3096 ] + diffopts,
3095 ] + diffopts,
3097 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3096 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3098 def export(ui, repo, *changesets, **opts):
3097 def export(ui, repo, *changesets, **opts):
3099 """dump the header and diffs for one or more changesets
3098 """dump the header and diffs for one or more changesets
3100
3099
3101 Print the changeset header and diffs for one or more revisions.
3100 Print the changeset header and diffs for one or more revisions.
3102 If no revision is given, the parent of the working directory is used.
3101 If no revision is given, the parent of the working directory is used.
3103
3102
3104 The information shown in the changeset header is: author, date,
3103 The information shown in the changeset header is: author, date,
3105 branch name (if non-default), changeset hash, parent(s) and commit
3104 branch name (if non-default), changeset hash, parent(s) and commit
3106 comment.
3105 comment.
3107
3106
3108 .. note::
3107 .. note::
3109
3108
3110 export may generate unexpected diff output for merge
3109 export may generate unexpected diff output for merge
3111 changesets, as it will compare the merge changeset against its
3110 changesets, as it will compare the merge changeset against its
3112 first parent only.
3111 first parent only.
3113
3112
3114 Output may be to a file, in which case the name of the file is
3113 Output may be to a file, in which case the name of the file is
3115 given using a format string. The formatting rules are as follows:
3114 given using a format string. The formatting rules are as follows:
3116
3115
3117 :``%%``: literal "%" character
3116 :``%%``: literal "%" character
3118 :``%H``: changeset hash (40 hexadecimal digits)
3117 :``%H``: changeset hash (40 hexadecimal digits)
3119 :``%N``: number of patches being generated
3118 :``%N``: number of patches being generated
3120 :``%R``: changeset revision number
3119 :``%R``: changeset revision number
3121 :``%b``: basename of the exporting repository
3120 :``%b``: basename of the exporting repository
3122 :``%h``: short-form changeset hash (12 hexadecimal digits)
3121 :``%h``: short-form changeset hash (12 hexadecimal digits)
3123 :``%m``: first line of the commit message (only alphanumeric characters)
3122 :``%m``: first line of the commit message (only alphanumeric characters)
3124 :``%n``: zero-padded sequence number, starting at 1
3123 :``%n``: zero-padded sequence number, starting at 1
3125 :``%r``: zero-padded changeset revision number
3124 :``%r``: zero-padded changeset revision number
3126
3125
3127 Without the -a/--text option, export will avoid generating diffs
3126 Without the -a/--text option, export will avoid generating diffs
3128 of files it detects as binary. With -a, export will generate a
3127 of files it detects as binary. With -a, export will generate a
3129 diff anyway, probably with undesirable results.
3128 diff anyway, probably with undesirable results.
3130
3129
3131 Use the -g/--git option to generate diffs in the git extended diff
3130 Use the -g/--git option to generate diffs in the git extended diff
3132 format. See :hg:`help diffs` for more information.
3131 format. See :hg:`help diffs` for more information.
3133
3132
3134 With the --switch-parent option, the diff will be against the
3133 With the --switch-parent option, the diff will be against the
3135 second parent. It can be useful to review a merge.
3134 second parent. It can be useful to review a merge.
3136
3135
3137 .. container:: verbose
3136 .. container:: verbose
3138
3137
3139 Examples:
3138 Examples:
3140
3139
3141 - use export and import to transplant a bugfix to the current
3140 - use export and import to transplant a bugfix to the current
3142 branch::
3141 branch::
3143
3142
3144 hg export -r 9353 | hg import -
3143 hg export -r 9353 | hg import -
3145
3144
3146 - export all the changesets between two revisions to a file with
3145 - export all the changesets between two revisions to a file with
3147 rename information::
3146 rename information::
3148
3147
3149 hg export --git -r 123:150 > changes.txt
3148 hg export --git -r 123:150 > changes.txt
3150
3149
3151 - split outgoing changes into a series of patches with
3150 - split outgoing changes into a series of patches with
3152 descriptive names::
3151 descriptive names::
3153
3152
3154 hg export -r "outgoing()" -o "%n-%m.patch"
3153 hg export -r "outgoing()" -o "%n-%m.patch"
3155
3154
3156 Returns 0 on success.
3155 Returns 0 on success.
3157 """
3156 """
3158 changesets += tuple(opts.get('rev', []))
3157 changesets += tuple(opts.get('rev', []))
3159 if not changesets:
3158 if not changesets:
3160 changesets = ['.']
3159 changesets = ['.']
3161 revs = scmutil.revrange(repo, changesets)
3160 revs = scmutil.revrange(repo, changesets)
3162 if not revs:
3161 if not revs:
3163 raise util.Abort(_("export requires at least one changeset"))
3162 raise util.Abort(_("export requires at least one changeset"))
3164 if len(revs) > 1:
3163 if len(revs) > 1:
3165 ui.note(_('exporting patches:\n'))
3164 ui.note(_('exporting patches:\n'))
3166 else:
3165 else:
3167 ui.note(_('exporting patch:\n'))
3166 ui.note(_('exporting patch:\n'))
3168 cmdutil.export(repo, revs, template=opts.get('output'),
3167 cmdutil.export(repo, revs, template=opts.get('output'),
3169 switch_parent=opts.get('switch_parent'),
3168 switch_parent=opts.get('switch_parent'),
3170 opts=patch.diffopts(ui, opts))
3169 opts=patch.diffopts(ui, opts))
3171
3170
3172 @command('files',
3171 @command('files',
3173 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3172 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3174 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3173 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3175 ] + walkopts + formatteropts,
3174 ] + walkopts + formatteropts,
3176 _('[OPTION]... [PATTERN]...'))
3175 _('[OPTION]... [PATTERN]...'))
3177 def files(ui, repo, *pats, **opts):
3176 def files(ui, repo, *pats, **opts):
3178 """list tracked files
3177 """list tracked files
3179
3178
3180 Print files under Mercurial control in the working directory or
3179 Print files under Mercurial control in the working directory or
3181 specified revision whose names match the given patterns (excluding
3180 specified revision whose names match the given patterns (excluding
3182 removed files).
3181 removed files).
3183
3182
3184 If no patterns are given to match, this command prints the names
3183 If no patterns are given to match, this command prints the names
3185 of all files under Mercurial control in the working copy.
3184 of all files under Mercurial control in the working copy.
3186
3185
3187 .. container:: verbose
3186 .. container:: verbose
3188
3187
3189 Examples:
3188 Examples:
3190
3189
3191 - list all files under the current directory::
3190 - list all files under the current directory::
3192
3191
3193 hg files .
3192 hg files .
3194
3193
3195 - shows sizes and flags for current revision::
3194 - shows sizes and flags for current revision::
3196
3195
3197 hg files -vr .
3196 hg files -vr .
3198
3197
3199 - list all files named README::
3198 - list all files named README::
3200
3199
3201 hg files -I "**/README"
3200 hg files -I "**/README"
3202
3201
3203 - list all binary files::
3202 - list all binary files::
3204
3203
3205 hg files "set:binary()"
3204 hg files "set:binary()"
3206
3205
3207 - find files containing a regular expression:
3206 - find files containing a regular expression:
3208
3207
3209 hg files "set:grep('bob')"
3208 hg files "set:grep('bob')"
3210
3209
3211 - search tracked file contents with xargs and grep::
3210 - search tracked file contents with xargs and grep::
3212
3211
3213 hg files -0 | xargs -0 grep foo
3212 hg files -0 | xargs -0 grep foo
3214
3213
3215 See :hg:'help pattern' and :hg:'help revsets' for more information
3214 See :hg:'help pattern' and :hg:'help revsets' for more information
3216 on specifying file patterns.
3215 on specifying file patterns.
3217
3216
3218 Returns 0 if a match is found, 1 otherwise.
3217 Returns 0 if a match is found, 1 otherwise.
3219
3218
3220 """
3219 """
3221 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3220 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3222 rev = ctx.rev()
3221 rev = ctx.rev()
3223 ret = 1
3222 ret = 1
3224
3223
3225 end = '\n'
3224 end = '\n'
3226 if opts.get('print0'):
3225 if opts.get('print0'):
3227 end = '\0'
3226 end = '\0'
3228 fm = ui.formatter('files', opts)
3227 fm = ui.formatter('files', opts)
3229 fmt = '%s' + end
3228 fmt = '%s' + end
3230
3229
3231 m = scmutil.match(ctx, pats, opts)
3230 m = scmutil.match(ctx, pats, opts)
3232 ds = repo.dirstate
3231 ds = repo.dirstate
3233 for f in ctx.matches(m):
3232 for f in ctx.matches(m):
3234 if rev is None and ds[f] == 'r':
3233 if rev is None and ds[f] == 'r':
3235 continue
3234 continue
3236 fm.startitem()
3235 fm.startitem()
3237 if ui.verbose:
3236 if ui.verbose:
3238 fc = ctx[f]
3237 fc = ctx[f]
3239 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3238 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3240 fm.data(abspath=f)
3239 fm.data(abspath=f)
3241 fm.write('path', fmt, m.rel(f))
3240 fm.write('path', fmt, m.rel(f))
3242 ret = 0
3241 ret = 0
3243
3242
3244 fm.end()
3243 fm.end()
3245
3244
3246 return ret
3245 return ret
3247
3246
3248 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3247 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3249 def forget(ui, repo, *pats, **opts):
3248 def forget(ui, repo, *pats, **opts):
3250 """forget the specified files on the next commit
3249 """forget the specified files on the next commit
3251
3250
3252 Mark the specified files so they will no longer be tracked
3251 Mark the specified files so they will no longer be tracked
3253 after the next commit.
3252 after the next commit.
3254
3253
3255 This only removes files from the current branch, not from the
3254 This only removes files from the current branch, not from the
3256 entire project history, and it does not delete them from the
3255 entire project history, and it does not delete them from the
3257 working directory.
3256 working directory.
3258
3257
3259 To undo a forget before the next commit, see :hg:`add`.
3258 To undo a forget before the next commit, see :hg:`add`.
3260
3259
3261 .. container:: verbose
3260 .. container:: verbose
3262
3261
3263 Examples:
3262 Examples:
3264
3263
3265 - forget newly-added binary files::
3264 - forget newly-added binary files::
3266
3265
3267 hg forget "set:added() and binary()"
3266 hg forget "set:added() and binary()"
3268
3267
3269 - forget files that would be excluded by .hgignore::
3268 - forget files that would be excluded by .hgignore::
3270
3269
3271 hg forget "set:hgignore()"
3270 hg forget "set:hgignore()"
3272
3271
3273 Returns 0 on success.
3272 Returns 0 on success.
3274 """
3273 """
3275
3274
3276 if not pats:
3275 if not pats:
3277 raise util.Abort(_('no files specified'))
3276 raise util.Abort(_('no files specified'))
3278
3277
3279 m = scmutil.match(repo[None], pats, opts)
3278 m = scmutil.match(repo[None], pats, opts)
3280 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3279 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3281 return rejected and 1 or 0
3280 return rejected and 1 or 0
3282
3281
3283 @command(
3282 @command(
3284 'graft',
3283 'graft',
3285 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3284 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3286 ('c', 'continue', False, _('resume interrupted graft')),
3285 ('c', 'continue', False, _('resume interrupted graft')),
3287 ('e', 'edit', False, _('invoke editor on commit messages')),
3286 ('e', 'edit', False, _('invoke editor on commit messages')),
3288 ('', 'log', None, _('append graft info to log message')),
3287 ('', 'log', None, _('append graft info to log message')),
3289 ('f', 'force', False, _('force graft')),
3288 ('f', 'force', False, _('force graft')),
3290 ('D', 'currentdate', False,
3289 ('D', 'currentdate', False,
3291 _('record the current date as commit date')),
3290 _('record the current date as commit date')),
3292 ('U', 'currentuser', False,
3291 ('U', 'currentuser', False,
3293 _('record the current user as committer'), _('DATE'))]
3292 _('record the current user as committer'), _('DATE'))]
3294 + commitopts2 + mergetoolopts + dryrunopts,
3293 + commitopts2 + mergetoolopts + dryrunopts,
3295 _('[OPTION]... [-r] REV...'))
3294 _('[OPTION]... [-r] REV...'))
3296 def graft(ui, repo, *revs, **opts):
3295 def graft(ui, repo, *revs, **opts):
3297 '''copy changes from other branches onto the current branch
3296 '''copy changes from other branches onto the current branch
3298
3297
3299 This command uses Mercurial's merge logic to copy individual
3298 This command uses Mercurial's merge logic to copy individual
3300 changes from other branches without merging branches in the
3299 changes from other branches without merging branches in the
3301 history graph. This is sometimes known as 'backporting' or
3300 history graph. This is sometimes known as 'backporting' or
3302 'cherry-picking'. By default, graft will copy user, date, and
3301 'cherry-picking'. By default, graft will copy user, date, and
3303 description from the source changesets.
3302 description from the source changesets.
3304
3303
3305 Changesets that are ancestors of the current revision, that have
3304 Changesets that are ancestors of the current revision, that have
3306 already been grafted, or that are merges will be skipped.
3305 already been grafted, or that are merges will be skipped.
3307
3306
3308 If --log is specified, log messages will have a comment appended
3307 If --log is specified, log messages will have a comment appended
3309 of the form::
3308 of the form::
3310
3309
3311 (grafted from CHANGESETHASH)
3310 (grafted from CHANGESETHASH)
3312
3311
3313 If --force is specified, revisions will be grafted even if they
3312 If --force is specified, revisions will be grafted even if they
3314 are already ancestors of or have been grafted to the destination.
3313 are already ancestors of or have been grafted to the destination.
3315 This is useful when the revisions have since been backed out.
3314 This is useful when the revisions have since been backed out.
3316
3315
3317 If a graft merge results in conflicts, the graft process is
3316 If a graft merge results in conflicts, the graft process is
3318 interrupted so that the current merge can be manually resolved.
3317 interrupted so that the current merge can be manually resolved.
3319 Once all conflicts are addressed, the graft process can be
3318 Once all conflicts are addressed, the graft process can be
3320 continued with the -c/--continue option.
3319 continued with the -c/--continue option.
3321
3320
3322 .. note::
3321 .. note::
3323
3322
3324 The -c/--continue option does not reapply earlier options, except
3323 The -c/--continue option does not reapply earlier options, except
3325 for --force.
3324 for --force.
3326
3325
3327 .. container:: verbose
3326 .. container:: verbose
3328
3327
3329 Examples:
3328 Examples:
3330
3329
3331 - copy a single change to the stable branch and edit its description::
3330 - copy a single change to the stable branch and edit its description::
3332
3331
3333 hg update stable
3332 hg update stable
3334 hg graft --edit 9393
3333 hg graft --edit 9393
3335
3334
3336 - graft a range of changesets with one exception, updating dates::
3335 - graft a range of changesets with one exception, updating dates::
3337
3336
3338 hg graft -D "2085::2093 and not 2091"
3337 hg graft -D "2085::2093 and not 2091"
3339
3338
3340 - continue a graft after resolving conflicts::
3339 - continue a graft after resolving conflicts::
3341
3340
3342 hg graft -c
3341 hg graft -c
3343
3342
3344 - show the source of a grafted changeset::
3343 - show the source of a grafted changeset::
3345
3344
3346 hg log --debug -r .
3345 hg log --debug -r .
3347
3346
3348 See :hg:`help revisions` and :hg:`help revsets` for more about
3347 See :hg:`help revisions` and :hg:`help revsets` for more about
3349 specifying revisions.
3348 specifying revisions.
3350
3349
3351 Returns 0 on successful completion.
3350 Returns 0 on successful completion.
3352 '''
3351 '''
3353
3352
3354 revs = list(revs)
3353 revs = list(revs)
3355 revs.extend(opts['rev'])
3354 revs.extend(opts['rev'])
3356
3355
3357 if not opts.get('user') and opts.get('currentuser'):
3356 if not opts.get('user') and opts.get('currentuser'):
3358 opts['user'] = ui.username()
3357 opts['user'] = ui.username()
3359 if not opts.get('date') and opts.get('currentdate'):
3358 if not opts.get('date') and opts.get('currentdate'):
3360 opts['date'] = "%d %d" % util.makedate()
3359 opts['date'] = "%d %d" % util.makedate()
3361
3360
3362 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3361 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3363
3362
3364 cont = False
3363 cont = False
3365 if opts['continue']:
3364 if opts['continue']:
3366 cont = True
3365 cont = True
3367 if revs:
3366 if revs:
3368 raise util.Abort(_("can't specify --continue and revisions"))
3367 raise util.Abort(_("can't specify --continue and revisions"))
3369 # read in unfinished revisions
3368 # read in unfinished revisions
3370 try:
3369 try:
3371 nodes = repo.opener.read('graftstate').splitlines()
3370 nodes = repo.opener.read('graftstate').splitlines()
3372 revs = [repo[node].rev() for node in nodes]
3371 revs = [repo[node].rev() for node in nodes]
3373 except IOError, inst:
3372 except IOError, inst:
3374 if inst.errno != errno.ENOENT:
3373 if inst.errno != errno.ENOENT:
3375 raise
3374 raise
3376 raise util.Abort(_("no graft state found, can't continue"))
3375 raise util.Abort(_("no graft state found, can't continue"))
3377 else:
3376 else:
3378 cmdutil.checkunfinished(repo)
3377 cmdutil.checkunfinished(repo)
3379 cmdutil.bailifchanged(repo)
3378 cmdutil.bailifchanged(repo)
3380 if not revs:
3379 if not revs:
3381 raise util.Abort(_('no revisions specified'))
3380 raise util.Abort(_('no revisions specified'))
3382 revs = scmutil.revrange(repo, revs)
3381 revs = scmutil.revrange(repo, revs)
3383
3382
3384 skipped = set()
3383 skipped = set()
3385 # check for merges
3384 # check for merges
3386 for rev in repo.revs('%ld and merge()', revs):
3385 for rev in repo.revs('%ld and merge()', revs):
3387 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3386 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3388 skipped.add(rev)
3387 skipped.add(rev)
3389 revs = [r for r in revs if r not in skipped]
3388 revs = [r for r in revs if r not in skipped]
3390 if not revs:
3389 if not revs:
3391 return -1
3390 return -1
3392
3391
3393 # Don't check in the --continue case, in effect retaining --force across
3392 # Don't check in the --continue case, in effect retaining --force across
3394 # --continues. That's because without --force, any revisions we decided to
3393 # --continues. That's because without --force, any revisions we decided to
3395 # skip would have been filtered out here, so they wouldn't have made their
3394 # skip would have been filtered out here, so they wouldn't have made their
3396 # way to the graftstate. With --force, any revisions we would have otherwise
3395 # way to the graftstate. With --force, any revisions we would have otherwise
3397 # skipped would not have been filtered out, and if they hadn't been applied
3396 # skipped would not have been filtered out, and if they hadn't been applied
3398 # already, they'd have been in the graftstate.
3397 # already, they'd have been in the graftstate.
3399 if not (cont or opts.get('force')):
3398 if not (cont or opts.get('force')):
3400 # check for ancestors of dest branch
3399 # check for ancestors of dest branch
3401 crev = repo['.'].rev()
3400 crev = repo['.'].rev()
3402 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3401 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3403 # Cannot use x.remove(y) on smart set, this has to be a list.
3402 # Cannot use x.remove(y) on smart set, this has to be a list.
3404 # XXX make this lazy in the future
3403 # XXX make this lazy in the future
3405 revs = list(revs)
3404 revs = list(revs)
3406 # don't mutate while iterating, create a copy
3405 # don't mutate while iterating, create a copy
3407 for rev in list(revs):
3406 for rev in list(revs):
3408 if rev in ancestors:
3407 if rev in ancestors:
3409 ui.warn(_('skipping ancestor revision %s\n') % rev)
3408 ui.warn(_('skipping ancestor revision %s\n') % rev)
3410 # XXX remove on list is slow
3409 # XXX remove on list is slow
3411 revs.remove(rev)
3410 revs.remove(rev)
3412 if not revs:
3411 if not revs:
3413 return -1
3412 return -1
3414
3413
3415 # analyze revs for earlier grafts
3414 # analyze revs for earlier grafts
3416 ids = {}
3415 ids = {}
3417 for ctx in repo.set("%ld", revs):
3416 for ctx in repo.set("%ld", revs):
3418 ids[ctx.hex()] = ctx.rev()
3417 ids[ctx.hex()] = ctx.rev()
3419 n = ctx.extra().get('source')
3418 n = ctx.extra().get('source')
3420 if n:
3419 if n:
3421 ids[n] = ctx.rev()
3420 ids[n] = ctx.rev()
3422
3421
3423 # check ancestors for earlier grafts
3422 # check ancestors for earlier grafts
3424 ui.debug('scanning for duplicate grafts\n')
3423 ui.debug('scanning for duplicate grafts\n')
3425
3424
3426 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3425 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3427 ctx = repo[rev]
3426 ctx = repo[rev]
3428 n = ctx.extra().get('source')
3427 n = ctx.extra().get('source')
3429 if n in ids:
3428 if n in ids:
3430 try:
3429 try:
3431 r = repo[n].rev()
3430 r = repo[n].rev()
3432 except error.RepoLookupError:
3431 except error.RepoLookupError:
3433 r = None
3432 r = None
3434 if r in revs:
3433 if r in revs:
3435 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3434 ui.warn(_('skipping revision %s (already grafted to %s)\n')
3436 % (r, rev))
3435 % (r, rev))
3437 revs.remove(r)
3436 revs.remove(r)
3438 elif ids[n] in revs:
3437 elif ids[n] in revs:
3439 if r is None:
3438 if r is None:
3440 ui.warn(_('skipping already grafted revision %s '
3439 ui.warn(_('skipping already grafted revision %s '
3441 '(%s also has unknown origin %s)\n')
3440 '(%s also has unknown origin %s)\n')
3442 % (ids[n], rev, n))
3441 % (ids[n], rev, n))
3443 else:
3442 else:
3444 ui.warn(_('skipping already grafted revision %s '
3443 ui.warn(_('skipping already grafted revision %s '
3445 '(%s also has origin %d)\n')
3444 '(%s also has origin %d)\n')
3446 % (ids[n], rev, r))
3445 % (ids[n], rev, r))
3447 revs.remove(ids[n])
3446 revs.remove(ids[n])
3448 elif ctx.hex() in ids:
3447 elif ctx.hex() in ids:
3449 r = ids[ctx.hex()]
3448 r = ids[ctx.hex()]
3450 ui.warn(_('skipping already grafted revision %s '
3449 ui.warn(_('skipping already grafted revision %s '
3451 '(was grafted from %d)\n') % (r, rev))
3450 '(was grafted from %d)\n') % (r, rev))
3452 revs.remove(r)
3451 revs.remove(r)
3453 if not revs:
3452 if not revs:
3454 return -1
3453 return -1
3455
3454
3456 wlock = repo.wlock()
3455 wlock = repo.wlock()
3457 try:
3456 try:
3458 current = repo['.']
3457 current = repo['.']
3459 for pos, ctx in enumerate(repo.set("%ld", revs)):
3458 for pos, ctx in enumerate(repo.set("%ld", revs)):
3460
3459
3461 ui.status(_('grafting revision %s\n') % ctx.rev())
3460 ui.status(_('grafting revision %s\n') % ctx.rev())
3462 if opts.get('dry_run'):
3461 if opts.get('dry_run'):
3463 continue
3462 continue
3464
3463
3465 source = ctx.extra().get('source')
3464 source = ctx.extra().get('source')
3466 if not source:
3465 if not source:
3467 source = ctx.hex()
3466 source = ctx.hex()
3468 extra = {'source': source}
3467 extra = {'source': source}
3469 user = ctx.user()
3468 user = ctx.user()
3470 if opts.get('user'):
3469 if opts.get('user'):
3471 user = opts['user']
3470 user = opts['user']
3472 date = ctx.date()
3471 date = ctx.date()
3473 if opts.get('date'):
3472 if opts.get('date'):
3474 date = opts['date']
3473 date = opts['date']
3475 message = ctx.description()
3474 message = ctx.description()
3476 if opts.get('log'):
3475 if opts.get('log'):
3477 message += '\n(grafted from %s)' % ctx.hex()
3476 message += '\n(grafted from %s)' % ctx.hex()
3478
3477
3479 # we don't merge the first commit when continuing
3478 # we don't merge the first commit when continuing
3480 if not cont:
3479 if not cont:
3481 # perform the graft merge with p1(rev) as 'ancestor'
3480 # perform the graft merge with p1(rev) as 'ancestor'
3482 try:
3481 try:
3483 # ui.forcemerge is an internal variable, do not document
3482 # ui.forcemerge is an internal variable, do not document
3484 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3483 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3485 'graft')
3484 'graft')
3486 stats = mergemod.update(repo, ctx.node(), True, True, False,
3485 stats = mergemod.update(repo, ctx.node(), True, True, False,
3487 ctx.p1().node(),
3486 ctx.p1().node(),
3488 labels=['local', 'graft'])
3487 labels=['local', 'graft'])
3489 finally:
3488 finally:
3490 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3489 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3491 # report any conflicts
3490 # report any conflicts
3492 if stats and stats[3] > 0:
3491 if stats and stats[3] > 0:
3493 # write out state for --continue
3492 # write out state for --continue
3494 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3493 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3495 repo.opener.write('graftstate', ''.join(nodelines))
3494 repo.opener.write('graftstate', ''.join(nodelines))
3496 raise util.Abort(
3495 raise util.Abort(
3497 _("unresolved conflicts, can't continue"),
3496 _("unresolved conflicts, can't continue"),
3498 hint=_('use hg resolve and hg graft --continue'))
3497 hint=_('use hg resolve and hg graft --continue'))
3499 else:
3498 else:
3500 cont = False
3499 cont = False
3501
3500
3502 # drop the second merge parent
3501 # drop the second merge parent
3503 repo.dirstate.beginparentchange()
3502 repo.dirstate.beginparentchange()
3504 repo.setparents(current.node(), nullid)
3503 repo.setparents(current.node(), nullid)
3505 repo.dirstate.write()
3504 repo.dirstate.write()
3506 # fix up dirstate for copies and renames
3505 # fix up dirstate for copies and renames
3507 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3506 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
3508 repo.dirstate.endparentchange()
3507 repo.dirstate.endparentchange()
3509
3508
3510 # commit
3509 # commit
3511 node = repo.commit(text=message, user=user,
3510 node = repo.commit(text=message, user=user,
3512 date=date, extra=extra, editor=editor)
3511 date=date, extra=extra, editor=editor)
3513 if node is None:
3512 if node is None:
3514 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3513 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
3515 else:
3514 else:
3516 current = repo[node]
3515 current = repo[node]
3517 finally:
3516 finally:
3518 wlock.release()
3517 wlock.release()
3519
3518
3520 # remove state when we complete successfully
3519 # remove state when we complete successfully
3521 if not opts.get('dry_run'):
3520 if not opts.get('dry_run'):
3522 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3521 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3523
3522
3524 return 0
3523 return 0
3525
3524
3526 @command('grep',
3525 @command('grep',
3527 [('0', 'print0', None, _('end fields with NUL')),
3526 [('0', 'print0', None, _('end fields with NUL')),
3528 ('', 'all', None, _('print all revisions that match')),
3527 ('', 'all', None, _('print all revisions that match')),
3529 ('a', 'text', None, _('treat all files as text')),
3528 ('a', 'text', None, _('treat all files as text')),
3530 ('f', 'follow', None,
3529 ('f', 'follow', None,
3531 _('follow changeset history,'
3530 _('follow changeset history,'
3532 ' or file history across copies and renames')),
3531 ' or file history across copies and renames')),
3533 ('i', 'ignore-case', None, _('ignore case when matching')),
3532 ('i', 'ignore-case', None, _('ignore case when matching')),
3534 ('l', 'files-with-matches', None,
3533 ('l', 'files-with-matches', None,
3535 _('print only filenames and revisions that match')),
3534 _('print only filenames and revisions that match')),
3536 ('n', 'line-number', None, _('print matching line numbers')),
3535 ('n', 'line-number', None, _('print matching line numbers')),
3537 ('r', 'rev', [],
3536 ('r', 'rev', [],
3538 _('only search files changed within revision range'), _('REV')),
3537 _('only search files changed within revision range'), _('REV')),
3539 ('u', 'user', None, _('list the author (long with -v)')),
3538 ('u', 'user', None, _('list the author (long with -v)')),
3540 ('d', 'date', None, _('list the date (short with -q)')),
3539 ('d', 'date', None, _('list the date (short with -q)')),
3541 ] + walkopts,
3540 ] + walkopts,
3542 _('[OPTION]... PATTERN [FILE]...'),
3541 _('[OPTION]... PATTERN [FILE]...'),
3543 inferrepo=True)
3542 inferrepo=True)
3544 def grep(ui, repo, pattern, *pats, **opts):
3543 def grep(ui, repo, pattern, *pats, **opts):
3545 """search for a pattern in specified files and revisions
3544 """search for a pattern in specified files and revisions
3546
3545
3547 Search revisions of files for a regular expression.
3546 Search revisions of files for a regular expression.
3548
3547
3549 This command behaves differently than Unix grep. It only accepts
3548 This command behaves differently than Unix grep. It only accepts
3550 Python/Perl regexps. It searches repository history, not the
3549 Python/Perl regexps. It searches repository history, not the
3551 working directory. It always prints the revision number in which a
3550 working directory. It always prints the revision number in which a
3552 match appears.
3551 match appears.
3553
3552
3554 By default, grep only prints output for the first revision of a
3553 By default, grep only prints output for the first revision of a
3555 file in which it finds a match. To get it to print every revision
3554 file in which it finds a match. To get it to print every revision
3556 that contains a change in match status ("-" for a match that
3555 that contains a change in match status ("-" for a match that
3557 becomes a non-match, or "+" for a non-match that becomes a match),
3556 becomes a non-match, or "+" for a non-match that becomes a match),
3558 use the --all flag.
3557 use the --all flag.
3559
3558
3560 Returns 0 if a match is found, 1 otherwise.
3559 Returns 0 if a match is found, 1 otherwise.
3561 """
3560 """
3562 reflags = re.M
3561 reflags = re.M
3563 if opts.get('ignore_case'):
3562 if opts.get('ignore_case'):
3564 reflags |= re.I
3563 reflags |= re.I
3565 try:
3564 try:
3566 regexp = util.re.compile(pattern, reflags)
3565 regexp = util.re.compile(pattern, reflags)
3567 except re.error, inst:
3566 except re.error, inst:
3568 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3567 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3569 return 1
3568 return 1
3570 sep, eol = ':', '\n'
3569 sep, eol = ':', '\n'
3571 if opts.get('print0'):
3570 if opts.get('print0'):
3572 sep = eol = '\0'
3571 sep = eol = '\0'
3573
3572
3574 getfile = util.lrucachefunc(repo.file)
3573 getfile = util.lrucachefunc(repo.file)
3575
3574
3576 def matchlines(body):
3575 def matchlines(body):
3577 begin = 0
3576 begin = 0
3578 linenum = 0
3577 linenum = 0
3579 while begin < len(body):
3578 while begin < len(body):
3580 match = regexp.search(body, begin)
3579 match = regexp.search(body, begin)
3581 if not match:
3580 if not match:
3582 break
3581 break
3583 mstart, mend = match.span()
3582 mstart, mend = match.span()
3584 linenum += body.count('\n', begin, mstart) + 1
3583 linenum += body.count('\n', begin, mstart) + 1
3585 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3584 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3586 begin = body.find('\n', mend) + 1 or len(body) + 1
3585 begin = body.find('\n', mend) + 1 or len(body) + 1
3587 lend = begin - 1
3586 lend = begin - 1
3588 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3587 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3589
3588
3590 class linestate(object):
3589 class linestate(object):
3591 def __init__(self, line, linenum, colstart, colend):
3590 def __init__(self, line, linenum, colstart, colend):
3592 self.line = line
3591 self.line = line
3593 self.linenum = linenum
3592 self.linenum = linenum
3594 self.colstart = colstart
3593 self.colstart = colstart
3595 self.colend = colend
3594 self.colend = colend
3596
3595
3597 def __hash__(self):
3596 def __hash__(self):
3598 return hash((self.linenum, self.line))
3597 return hash((self.linenum, self.line))
3599
3598
3600 def __eq__(self, other):
3599 def __eq__(self, other):
3601 return self.line == other.line
3600 return self.line == other.line
3602
3601
3603 def __iter__(self):
3602 def __iter__(self):
3604 yield (self.line[:self.colstart], '')
3603 yield (self.line[:self.colstart], '')
3605 yield (self.line[self.colstart:self.colend], 'grep.match')
3604 yield (self.line[self.colstart:self.colend], 'grep.match')
3606 rest = self.line[self.colend:]
3605 rest = self.line[self.colend:]
3607 while rest != '':
3606 while rest != '':
3608 match = regexp.search(rest)
3607 match = regexp.search(rest)
3609 if not match:
3608 if not match:
3610 yield (rest, '')
3609 yield (rest, '')
3611 break
3610 break
3612 mstart, mend = match.span()
3611 mstart, mend = match.span()
3613 yield (rest[:mstart], '')
3612 yield (rest[:mstart], '')
3614 yield (rest[mstart:mend], 'grep.match')
3613 yield (rest[mstart:mend], 'grep.match')
3615 rest = rest[mend:]
3614 rest = rest[mend:]
3616
3615
3617 matches = {}
3616 matches = {}
3618 copies = {}
3617 copies = {}
3619 def grepbody(fn, rev, body):
3618 def grepbody(fn, rev, body):
3620 matches[rev].setdefault(fn, [])
3619 matches[rev].setdefault(fn, [])
3621 m = matches[rev][fn]
3620 m = matches[rev][fn]
3622 for lnum, cstart, cend, line in matchlines(body):
3621 for lnum, cstart, cend, line in matchlines(body):
3623 s = linestate(line, lnum, cstart, cend)
3622 s = linestate(line, lnum, cstart, cend)
3624 m.append(s)
3623 m.append(s)
3625
3624
3626 def difflinestates(a, b):
3625 def difflinestates(a, b):
3627 sm = difflib.SequenceMatcher(None, a, b)
3626 sm = difflib.SequenceMatcher(None, a, b)
3628 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3627 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3629 if tag == 'insert':
3628 if tag == 'insert':
3630 for i in xrange(blo, bhi):
3629 for i in xrange(blo, bhi):
3631 yield ('+', b[i])
3630 yield ('+', b[i])
3632 elif tag == 'delete':
3631 elif tag == 'delete':
3633 for i in xrange(alo, ahi):
3632 for i in xrange(alo, ahi):
3634 yield ('-', a[i])
3633 yield ('-', a[i])
3635 elif tag == 'replace':
3634 elif tag == 'replace':
3636 for i in xrange(alo, ahi):
3635 for i in xrange(alo, ahi):
3637 yield ('-', a[i])
3636 yield ('-', a[i])
3638 for i in xrange(blo, bhi):
3637 for i in xrange(blo, bhi):
3639 yield ('+', b[i])
3638 yield ('+', b[i])
3640
3639
3641 def display(fn, ctx, pstates, states):
3640 def display(fn, ctx, pstates, states):
3642 rev = ctx.rev()
3641 rev = ctx.rev()
3643 datefunc = ui.quiet and util.shortdate or util.datestr
3642 datefunc = ui.quiet and util.shortdate or util.datestr
3644 found = False
3643 found = False
3645 @util.cachefunc
3644 @util.cachefunc
3646 def binary():
3645 def binary():
3647 flog = getfile(fn)
3646 flog = getfile(fn)
3648 return util.binary(flog.read(ctx.filenode(fn)))
3647 return util.binary(flog.read(ctx.filenode(fn)))
3649
3648
3650 if opts.get('all'):
3649 if opts.get('all'):
3651 iter = difflinestates(pstates, states)
3650 iter = difflinestates(pstates, states)
3652 else:
3651 else:
3653 iter = [('', l) for l in states]
3652 iter = [('', l) for l in states]
3654 for change, l in iter:
3653 for change, l in iter:
3655 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3654 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3656
3655
3657 if opts.get('line_number'):
3656 if opts.get('line_number'):
3658 cols.append((str(l.linenum), 'grep.linenumber'))
3657 cols.append((str(l.linenum), 'grep.linenumber'))
3659 if opts.get('all'):
3658 if opts.get('all'):
3660 cols.append((change, 'grep.change'))
3659 cols.append((change, 'grep.change'))
3661 if opts.get('user'):
3660 if opts.get('user'):
3662 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3661 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3663 if opts.get('date'):
3662 if opts.get('date'):
3664 cols.append((datefunc(ctx.date()), 'grep.date'))
3663 cols.append((datefunc(ctx.date()), 'grep.date'))
3665 for col, label in cols[:-1]:
3664 for col, label in cols[:-1]:
3666 ui.write(col, label=label)
3665 ui.write(col, label=label)
3667 ui.write(sep, label='grep.sep')
3666 ui.write(sep, label='grep.sep')
3668 ui.write(cols[-1][0], label=cols[-1][1])
3667 ui.write(cols[-1][0], label=cols[-1][1])
3669 if not opts.get('files_with_matches'):
3668 if not opts.get('files_with_matches'):
3670 ui.write(sep, label='grep.sep')
3669 ui.write(sep, label='grep.sep')
3671 if not opts.get('text') and binary():
3670 if not opts.get('text') and binary():
3672 ui.write(" Binary file matches")
3671 ui.write(" Binary file matches")
3673 else:
3672 else:
3674 for s, label in l:
3673 for s, label in l:
3675 ui.write(s, label=label)
3674 ui.write(s, label=label)
3676 ui.write(eol)
3675 ui.write(eol)
3677 found = True
3676 found = True
3678 if opts.get('files_with_matches'):
3677 if opts.get('files_with_matches'):
3679 break
3678 break
3680 return found
3679 return found
3681
3680
3682 skip = {}
3681 skip = {}
3683 revfiles = {}
3682 revfiles = {}
3684 matchfn = scmutil.match(repo[None], pats, opts)
3683 matchfn = scmutil.match(repo[None], pats, opts)
3685 found = False
3684 found = False
3686 follow = opts.get('follow')
3685 follow = opts.get('follow')
3687
3686
3688 def prep(ctx, fns):
3687 def prep(ctx, fns):
3689 rev = ctx.rev()
3688 rev = ctx.rev()
3690 pctx = ctx.p1()
3689 pctx = ctx.p1()
3691 parent = pctx.rev()
3690 parent = pctx.rev()
3692 matches.setdefault(rev, {})
3691 matches.setdefault(rev, {})
3693 matches.setdefault(parent, {})
3692 matches.setdefault(parent, {})
3694 files = revfiles.setdefault(rev, [])
3693 files = revfiles.setdefault(rev, [])
3695 for fn in fns:
3694 for fn in fns:
3696 flog = getfile(fn)
3695 flog = getfile(fn)
3697 try:
3696 try:
3698 fnode = ctx.filenode(fn)
3697 fnode = ctx.filenode(fn)
3699 except error.LookupError:
3698 except error.LookupError:
3700 continue
3699 continue
3701
3700
3702 copied = flog.renamed(fnode)
3701 copied = flog.renamed(fnode)
3703 copy = follow and copied and copied[0]
3702 copy = follow and copied and copied[0]
3704 if copy:
3703 if copy:
3705 copies.setdefault(rev, {})[fn] = copy
3704 copies.setdefault(rev, {})[fn] = copy
3706 if fn in skip:
3705 if fn in skip:
3707 if copy:
3706 if copy:
3708 skip[copy] = True
3707 skip[copy] = True
3709 continue
3708 continue
3710 files.append(fn)
3709 files.append(fn)
3711
3710
3712 if fn not in matches[rev]:
3711 if fn not in matches[rev]:
3713 grepbody(fn, rev, flog.read(fnode))
3712 grepbody(fn, rev, flog.read(fnode))
3714
3713
3715 pfn = copy or fn
3714 pfn = copy or fn
3716 if pfn not in matches[parent]:
3715 if pfn not in matches[parent]:
3717 try:
3716 try:
3718 fnode = pctx.filenode(pfn)
3717 fnode = pctx.filenode(pfn)
3719 grepbody(pfn, parent, flog.read(fnode))
3718 grepbody(pfn, parent, flog.read(fnode))
3720 except error.LookupError:
3719 except error.LookupError:
3721 pass
3720 pass
3722
3721
3723 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3722 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3724 rev = ctx.rev()
3723 rev = ctx.rev()
3725 parent = ctx.p1().rev()
3724 parent = ctx.p1().rev()
3726 for fn in sorted(revfiles.get(rev, [])):
3725 for fn in sorted(revfiles.get(rev, [])):
3727 states = matches[rev][fn]
3726 states = matches[rev][fn]
3728 copy = copies.get(rev, {}).get(fn)
3727 copy = copies.get(rev, {}).get(fn)
3729 if fn in skip:
3728 if fn in skip:
3730 if copy:
3729 if copy:
3731 skip[copy] = True
3730 skip[copy] = True
3732 continue
3731 continue
3733 pstates = matches.get(parent, {}).get(copy or fn, [])
3732 pstates = matches.get(parent, {}).get(copy or fn, [])
3734 if pstates or states:
3733 if pstates or states:
3735 r = display(fn, ctx, pstates, states)
3734 r = display(fn, ctx, pstates, states)
3736 found = found or r
3735 found = found or r
3737 if r and not opts.get('all'):
3736 if r and not opts.get('all'):
3738 skip[fn] = True
3737 skip[fn] = True
3739 if copy:
3738 if copy:
3740 skip[copy] = True
3739 skip[copy] = True
3741 del matches[rev]
3740 del matches[rev]
3742 del revfiles[rev]
3741 del revfiles[rev]
3743
3742
3744 return not found
3743 return not found
3745
3744
3746 @command('heads',
3745 @command('heads',
3747 [('r', 'rev', '',
3746 [('r', 'rev', '',
3748 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3747 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3749 ('t', 'topo', False, _('show topological heads only')),
3748 ('t', 'topo', False, _('show topological heads only')),
3750 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3749 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3751 ('c', 'closed', False, _('show normal and closed branch heads')),
3750 ('c', 'closed', False, _('show normal and closed branch heads')),
3752 ] + templateopts,
3751 ] + templateopts,
3753 _('[-ct] [-r STARTREV] [REV]...'))
3752 _('[-ct] [-r STARTREV] [REV]...'))
3754 def heads(ui, repo, *branchrevs, **opts):
3753 def heads(ui, repo, *branchrevs, **opts):
3755 """show branch heads
3754 """show branch heads
3756
3755
3757 With no arguments, show all open branch heads in the repository.
3756 With no arguments, show all open branch heads in the repository.
3758 Branch heads are changesets that have no descendants on the
3757 Branch heads are changesets that have no descendants on the
3759 same branch. They are where development generally takes place and
3758 same branch. They are where development generally takes place and
3760 are the usual targets for update and merge operations.
3759 are the usual targets for update and merge operations.
3761
3760
3762 If one or more REVs are given, only open branch heads on the
3761 If one or more REVs are given, only open branch heads on the
3763 branches associated with the specified changesets are shown. This
3762 branches associated with the specified changesets are shown. This
3764 means that you can use :hg:`heads .` to see the heads on the
3763 means that you can use :hg:`heads .` to see the heads on the
3765 currently checked-out branch.
3764 currently checked-out branch.
3766
3765
3767 If -c/--closed is specified, also show branch heads marked closed
3766 If -c/--closed is specified, also show branch heads marked closed
3768 (see :hg:`commit --close-branch`).
3767 (see :hg:`commit --close-branch`).
3769
3768
3770 If STARTREV is specified, only those heads that are descendants of
3769 If STARTREV is specified, only those heads that are descendants of
3771 STARTREV will be displayed.
3770 STARTREV will be displayed.
3772
3771
3773 If -t/--topo is specified, named branch mechanics will be ignored and only
3772 If -t/--topo is specified, named branch mechanics will be ignored and only
3774 topological heads (changesets with no children) will be shown.
3773 topological heads (changesets with no children) will be shown.
3775
3774
3776 Returns 0 if matching heads are found, 1 if not.
3775 Returns 0 if matching heads are found, 1 if not.
3777 """
3776 """
3778
3777
3779 start = None
3778 start = None
3780 if 'rev' in opts:
3779 if 'rev' in opts:
3781 start = scmutil.revsingle(repo, opts['rev'], None).node()
3780 start = scmutil.revsingle(repo, opts['rev'], None).node()
3782
3781
3783 if opts.get('topo'):
3782 if opts.get('topo'):
3784 heads = [repo[h] for h in repo.heads(start)]
3783 heads = [repo[h] for h in repo.heads(start)]
3785 else:
3784 else:
3786 heads = []
3785 heads = []
3787 for branch in repo.branchmap():
3786 for branch in repo.branchmap():
3788 heads += repo.branchheads(branch, start, opts.get('closed'))
3787 heads += repo.branchheads(branch, start, opts.get('closed'))
3789 heads = [repo[h] for h in heads]
3788 heads = [repo[h] for h in heads]
3790
3789
3791 if branchrevs:
3790 if branchrevs:
3792 branches = set(repo[br].branch() for br in branchrevs)
3791 branches = set(repo[br].branch() for br in branchrevs)
3793 heads = [h for h in heads if h.branch() in branches]
3792 heads = [h for h in heads if h.branch() in branches]
3794
3793
3795 if opts.get('active') and branchrevs:
3794 if opts.get('active') and branchrevs:
3796 dagheads = repo.heads(start)
3795 dagheads = repo.heads(start)
3797 heads = [h for h in heads if h.node() in dagheads]
3796 heads = [h for h in heads if h.node() in dagheads]
3798
3797
3799 if branchrevs:
3798 if branchrevs:
3800 haveheads = set(h.branch() for h in heads)
3799 haveheads = set(h.branch() for h in heads)
3801 if branches - haveheads:
3800 if branches - haveheads:
3802 headless = ', '.join(b for b in branches - haveheads)
3801 headless = ', '.join(b for b in branches - haveheads)
3803 msg = _('no open branch heads found on branches %s')
3802 msg = _('no open branch heads found on branches %s')
3804 if opts.get('rev'):
3803 if opts.get('rev'):
3805 msg += _(' (started at %s)') % opts['rev']
3804 msg += _(' (started at %s)') % opts['rev']
3806 ui.warn((msg + '\n') % headless)
3805 ui.warn((msg + '\n') % headless)
3807
3806
3808 if not heads:
3807 if not heads:
3809 return 1
3808 return 1
3810
3809
3811 heads = sorted(heads, key=lambda x: -x.rev())
3810 heads = sorted(heads, key=lambda x: -x.rev())
3812 displayer = cmdutil.show_changeset(ui, repo, opts)
3811 displayer = cmdutil.show_changeset(ui, repo, opts)
3813 for ctx in heads:
3812 for ctx in heads:
3814 displayer.show(ctx)
3813 displayer.show(ctx)
3815 displayer.close()
3814 displayer.close()
3816
3815
3817 @command('help',
3816 @command('help',
3818 [('e', 'extension', None, _('show only help for extensions')),
3817 [('e', 'extension', None, _('show only help for extensions')),
3819 ('c', 'command', None, _('show only help for commands')),
3818 ('c', 'command', None, _('show only help for commands')),
3820 ('k', 'keyword', '', _('show topics matching keyword')),
3819 ('k', 'keyword', '', _('show topics matching keyword')),
3821 ],
3820 ],
3822 _('[-ec] [TOPIC]'),
3821 _('[-ec] [TOPIC]'),
3823 norepo=True)
3822 norepo=True)
3824 def help_(ui, name=None, **opts):
3823 def help_(ui, name=None, **opts):
3825 """show help for a given topic or a help overview
3824 """show help for a given topic or a help overview
3826
3825
3827 With no arguments, print a list of commands with short help messages.
3826 With no arguments, print a list of commands with short help messages.
3828
3827
3829 Given a topic, extension, or command name, print help for that
3828 Given a topic, extension, or command name, print help for that
3830 topic.
3829 topic.
3831
3830
3832 Returns 0 if successful.
3831 Returns 0 if successful.
3833 """
3832 """
3834
3833
3835 textwidth = min(ui.termwidth(), 80) - 2
3834 textwidth = min(ui.termwidth(), 80) - 2
3836
3835
3837 keep = []
3836 keep = []
3838 if ui.verbose:
3837 if ui.verbose:
3839 keep.append('verbose')
3838 keep.append('verbose')
3840 if sys.platform.startswith('win'):
3839 if sys.platform.startswith('win'):
3841 keep.append('windows')
3840 keep.append('windows')
3842 elif sys.platform == 'OpenVMS':
3841 elif sys.platform == 'OpenVMS':
3843 keep.append('vms')
3842 keep.append('vms')
3844 elif sys.platform == 'plan9':
3843 elif sys.platform == 'plan9':
3845 keep.append('plan9')
3844 keep.append('plan9')
3846 else:
3845 else:
3847 keep.append('unix')
3846 keep.append('unix')
3848 keep.append(sys.platform.lower())
3847 keep.append(sys.platform.lower())
3849
3848
3850 section = None
3849 section = None
3851 if name and '.' in name:
3850 if name and '.' in name:
3852 name, section = name.split('.')
3851 name, section = name.split('.')
3853
3852
3854 text = help.help_(ui, name, **opts)
3853 text = help.help_(ui, name, **opts)
3855
3854
3856 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3855 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3857 section=section)
3856 section=section)
3858 if section and not formatted:
3857 if section and not formatted:
3859 raise util.Abort(_("help section not found"))
3858 raise util.Abort(_("help section not found"))
3860
3859
3861 if 'verbose' in pruned:
3860 if 'verbose' in pruned:
3862 keep.append('omitted')
3861 keep.append('omitted')
3863 else:
3862 else:
3864 keep.append('notomitted')
3863 keep.append('notomitted')
3865 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3864 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3866 section=section)
3865 section=section)
3867 ui.write(formatted)
3866 ui.write(formatted)
3868
3867
3869
3868
3870 @command('identify|id',
3869 @command('identify|id',
3871 [('r', 'rev', '',
3870 [('r', 'rev', '',
3872 _('identify the specified revision'), _('REV')),
3871 _('identify the specified revision'), _('REV')),
3873 ('n', 'num', None, _('show local revision number')),
3872 ('n', 'num', None, _('show local revision number')),
3874 ('i', 'id', None, _('show global revision id')),
3873 ('i', 'id', None, _('show global revision id')),
3875 ('b', 'branch', None, _('show branch')),
3874 ('b', 'branch', None, _('show branch')),
3876 ('t', 'tags', None, _('show tags')),
3875 ('t', 'tags', None, _('show tags')),
3877 ('B', 'bookmarks', None, _('show bookmarks')),
3876 ('B', 'bookmarks', None, _('show bookmarks')),
3878 ] + remoteopts,
3877 ] + remoteopts,
3879 _('[-nibtB] [-r REV] [SOURCE]'),
3878 _('[-nibtB] [-r REV] [SOURCE]'),
3880 optionalrepo=True)
3879 optionalrepo=True)
3881 def identify(ui, repo, source=None, rev=None,
3880 def identify(ui, repo, source=None, rev=None,
3882 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3881 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3883 """identify the working copy or specified revision
3882 """identify the working copy or specified revision
3884
3883
3885 Print a summary identifying the repository state at REV using one or
3884 Print a summary identifying the repository state at REV using one or
3886 two parent hash identifiers, followed by a "+" if the working
3885 two parent hash identifiers, followed by a "+" if the working
3887 directory has uncommitted changes, the branch name (if not default),
3886 directory has uncommitted changes, the branch name (if not default),
3888 a list of tags, and a list of bookmarks.
3887 a list of tags, and a list of bookmarks.
3889
3888
3890 When REV is not given, print a summary of the current state of the
3889 When REV is not given, print a summary of the current state of the
3891 repository.
3890 repository.
3892
3891
3893 Specifying a path to a repository root or Mercurial bundle will
3892 Specifying a path to a repository root or Mercurial bundle will
3894 cause lookup to operate on that repository/bundle.
3893 cause lookup to operate on that repository/bundle.
3895
3894
3896 .. container:: verbose
3895 .. container:: verbose
3897
3896
3898 Examples:
3897 Examples:
3899
3898
3900 - generate a build identifier for the working directory::
3899 - generate a build identifier for the working directory::
3901
3900
3902 hg id --id > build-id.dat
3901 hg id --id > build-id.dat
3903
3902
3904 - find the revision corresponding to a tag::
3903 - find the revision corresponding to a tag::
3905
3904
3906 hg id -n -r 1.3
3905 hg id -n -r 1.3
3907
3906
3908 - check the most recent revision of a remote repository::
3907 - check the most recent revision of a remote repository::
3909
3908
3910 hg id -r tip http://selenic.com/hg/
3909 hg id -r tip http://selenic.com/hg/
3911
3910
3912 Returns 0 if successful.
3911 Returns 0 if successful.
3913 """
3912 """
3914
3913
3915 if not repo and not source:
3914 if not repo and not source:
3916 raise util.Abort(_("there is no Mercurial repository here "
3915 raise util.Abort(_("there is no Mercurial repository here "
3917 "(.hg not found)"))
3916 "(.hg not found)"))
3918
3917
3919 hexfunc = ui.debugflag and hex or short
3918 hexfunc = ui.debugflag and hex or short
3920 default = not (num or id or branch or tags or bookmarks)
3919 default = not (num or id or branch or tags or bookmarks)
3921 output = []
3920 output = []
3922 revs = []
3921 revs = []
3923
3922
3924 if source:
3923 if source:
3925 source, branches = hg.parseurl(ui.expandpath(source))
3924 source, branches = hg.parseurl(ui.expandpath(source))
3926 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3925 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3927 repo = peer.local()
3926 repo = peer.local()
3928 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3927 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3929
3928
3930 if not repo:
3929 if not repo:
3931 if num or branch or tags:
3930 if num or branch or tags:
3932 raise util.Abort(
3931 raise util.Abort(
3933 _("can't query remote revision number, branch, or tags"))
3932 _("can't query remote revision number, branch, or tags"))
3934 if not rev and revs:
3933 if not rev and revs:
3935 rev = revs[0]
3934 rev = revs[0]
3936 if not rev:
3935 if not rev:
3937 rev = "tip"
3936 rev = "tip"
3938
3937
3939 remoterev = peer.lookup(rev)
3938 remoterev = peer.lookup(rev)
3940 if default or id:
3939 if default or id:
3941 output = [hexfunc(remoterev)]
3940 output = [hexfunc(remoterev)]
3942
3941
3943 def getbms():
3942 def getbms():
3944 bms = []
3943 bms = []
3945
3944
3946 if 'bookmarks' in peer.listkeys('namespaces'):
3945 if 'bookmarks' in peer.listkeys('namespaces'):
3947 hexremoterev = hex(remoterev)
3946 hexremoterev = hex(remoterev)
3948 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3947 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3949 if bmr == hexremoterev]
3948 if bmr == hexremoterev]
3950
3949
3951 return sorted(bms)
3950 return sorted(bms)
3952
3951
3953 if bookmarks:
3952 if bookmarks:
3954 output.extend(getbms())
3953 output.extend(getbms())
3955 elif default and not ui.quiet:
3954 elif default and not ui.quiet:
3956 # multiple bookmarks for a single parent separated by '/'
3955 # multiple bookmarks for a single parent separated by '/'
3957 bm = '/'.join(getbms())
3956 bm = '/'.join(getbms())
3958 if bm:
3957 if bm:
3959 output.append(bm)
3958 output.append(bm)
3960 else:
3959 else:
3961 if not rev:
3960 if not rev:
3962 ctx = repo[None]
3961 ctx = repo[None]
3963 parents = ctx.parents()
3962 parents = ctx.parents()
3964 changed = ""
3963 changed = ""
3965 if default or id or num:
3964 if default or id or num:
3966 if (util.any(repo.status())
3965 if (util.any(repo.status())
3967 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3966 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3968 changed = '+'
3967 changed = '+'
3969 if default or id:
3968 if default or id:
3970 output = ["%s%s" %
3969 output = ["%s%s" %
3971 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3970 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3972 if num:
3971 if num:
3973 output.append("%s%s" %
3972 output.append("%s%s" %
3974 ('+'.join([str(p.rev()) for p in parents]), changed))
3973 ('+'.join([str(p.rev()) for p in parents]), changed))
3975 else:
3974 else:
3976 ctx = scmutil.revsingle(repo, rev)
3975 ctx = scmutil.revsingle(repo, rev)
3977 if default or id:
3976 if default or id:
3978 output = [hexfunc(ctx.node())]
3977 output = [hexfunc(ctx.node())]
3979 if num:
3978 if num:
3980 output.append(str(ctx.rev()))
3979 output.append(str(ctx.rev()))
3981
3980
3982 if default and not ui.quiet:
3981 if default and not ui.quiet:
3983 b = ctx.branch()
3982 b = ctx.branch()
3984 if b != 'default':
3983 if b != 'default':
3985 output.append("(%s)" % b)
3984 output.append("(%s)" % b)
3986
3985
3987 # multiple tags for a single parent separated by '/'
3986 # multiple tags for a single parent separated by '/'
3988 t = '/'.join(ctx.tags())
3987 t = '/'.join(ctx.tags())
3989 if t:
3988 if t:
3990 output.append(t)
3989 output.append(t)
3991
3990
3992 # multiple bookmarks for a single parent separated by '/'
3991 # multiple bookmarks for a single parent separated by '/'
3993 bm = '/'.join(ctx.bookmarks())
3992 bm = '/'.join(ctx.bookmarks())
3994 if bm:
3993 if bm:
3995 output.append(bm)
3994 output.append(bm)
3996 else:
3995 else:
3997 if branch:
3996 if branch:
3998 output.append(ctx.branch())
3997 output.append(ctx.branch())
3999
3998
4000 if tags:
3999 if tags:
4001 output.extend(ctx.tags())
4000 output.extend(ctx.tags())
4002
4001
4003 if bookmarks:
4002 if bookmarks:
4004 output.extend(ctx.bookmarks())
4003 output.extend(ctx.bookmarks())
4005
4004
4006 ui.write("%s\n" % ' '.join(output))
4005 ui.write("%s\n" % ' '.join(output))
4007
4006
4008 @command('import|patch',
4007 @command('import|patch',
4009 [('p', 'strip', 1,
4008 [('p', 'strip', 1,
4010 _('directory strip option for patch. This has the same '
4009 _('directory strip option for patch. This has the same '
4011 'meaning as the corresponding patch option'), _('NUM')),
4010 'meaning as the corresponding patch option'), _('NUM')),
4012 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4011 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4013 ('e', 'edit', False, _('invoke editor on commit messages')),
4012 ('e', 'edit', False, _('invoke editor on commit messages')),
4014 ('f', 'force', None,
4013 ('f', 'force', None,
4015 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4014 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4016 ('', 'no-commit', None,
4015 ('', 'no-commit', None,
4017 _("don't commit, just update the working directory")),
4016 _("don't commit, just update the working directory")),
4018 ('', 'bypass', None,
4017 ('', 'bypass', None,
4019 _("apply patch without touching the working directory")),
4018 _("apply patch without touching the working directory")),
4020 ('', 'partial', None,
4019 ('', 'partial', None,
4021 _('commit even if some hunks fail')),
4020 _('commit even if some hunks fail')),
4022 ('', 'exact', None,
4021 ('', 'exact', None,
4023 _('apply patch to the nodes from which it was generated')),
4022 _('apply patch to the nodes from which it was generated')),
4024 ('', 'import-branch', None,
4023 ('', 'import-branch', None,
4025 _('use any branch information in patch (implied by --exact)'))] +
4024 _('use any branch information in patch (implied by --exact)'))] +
4026 commitopts + commitopts2 + similarityopts,
4025 commitopts + commitopts2 + similarityopts,
4027 _('[OPTION]... PATCH...'))
4026 _('[OPTION]... PATCH...'))
4028 def import_(ui, repo, patch1=None, *patches, **opts):
4027 def import_(ui, repo, patch1=None, *patches, **opts):
4029 """import an ordered set of patches
4028 """import an ordered set of patches
4030
4029
4031 Import a list of patches and commit them individually (unless
4030 Import a list of patches and commit them individually (unless
4032 --no-commit is specified).
4031 --no-commit is specified).
4033
4032
4034 Because import first applies changes to the working directory,
4033 Because import first applies changes to the working directory,
4035 import will abort if there are outstanding changes.
4034 import will abort if there are outstanding changes.
4036
4035
4037 You can import a patch straight from a mail message. Even patches
4036 You can import a patch straight from a mail message. Even patches
4038 as attachments work (to use the body part, it must have type
4037 as attachments work (to use the body part, it must have type
4039 text/plain or text/x-patch). From and Subject headers of email
4038 text/plain or text/x-patch). From and Subject headers of email
4040 message are used as default committer and commit message. All
4039 message are used as default committer and commit message. All
4041 text/plain body parts before first diff are added to commit
4040 text/plain body parts before first diff are added to commit
4042 message.
4041 message.
4043
4042
4044 If the imported patch was generated by :hg:`export`, user and
4043 If the imported patch was generated by :hg:`export`, user and
4045 description from patch override values from message headers and
4044 description from patch override values from message headers and
4046 body. Values given on command line with -m/--message and -u/--user
4045 body. Values given on command line with -m/--message and -u/--user
4047 override these.
4046 override these.
4048
4047
4049 If --exact is specified, import will set the working directory to
4048 If --exact is specified, import will set the working directory to
4050 the parent of each patch before applying it, and will abort if the
4049 the parent of each patch before applying it, and will abort if the
4051 resulting changeset has a different ID than the one recorded in
4050 resulting changeset has a different ID than the one recorded in
4052 the patch. This may happen due to character set problems or other
4051 the patch. This may happen due to character set problems or other
4053 deficiencies in the text patch format.
4052 deficiencies in the text patch format.
4054
4053
4055 Use --bypass to apply and commit patches directly to the
4054 Use --bypass to apply and commit patches directly to the
4056 repository, not touching the working directory. Without --exact,
4055 repository, not touching the working directory. Without --exact,
4057 patches will be applied on top of the working directory parent
4056 patches will be applied on top of the working directory parent
4058 revision.
4057 revision.
4059
4058
4060 With -s/--similarity, hg will attempt to discover renames and
4059 With -s/--similarity, hg will attempt to discover renames and
4061 copies in the patch in the same way as :hg:`addremove`.
4060 copies in the patch in the same way as :hg:`addremove`.
4062
4061
4063 Use --partial to ensure a changeset will be created from the patch
4062 Use --partial to ensure a changeset will be created from the patch
4064 even if some hunks fail to apply. Hunks that fail to apply will be
4063 even if some hunks fail to apply. Hunks that fail to apply will be
4065 written to a <target-file>.rej file. Conflicts can then be resolved
4064 written to a <target-file>.rej file. Conflicts can then be resolved
4066 by hand before :hg:`commit --amend` is run to update the created
4065 by hand before :hg:`commit --amend` is run to update the created
4067 changeset. This flag exists to let people import patches that
4066 changeset. This flag exists to let people import patches that
4068 partially apply without losing the associated metadata (author,
4067 partially apply without losing the associated metadata (author,
4069 date, description, ...). Note that when none of the hunk applies
4068 date, description, ...). Note that when none of the hunk applies
4070 cleanly, :hg:`import --partial` will create an empty changeset,
4069 cleanly, :hg:`import --partial` will create an empty changeset,
4071 importing only the patch metadata.
4070 importing only the patch metadata.
4072
4071
4073 To read a patch from standard input, use "-" as the patch name. If
4072 To read a patch from standard input, use "-" as the patch name. If
4074 a URL is specified, the patch will be downloaded from it.
4073 a URL is specified, the patch will be downloaded from it.
4075 See :hg:`help dates` for a list of formats valid for -d/--date.
4074 See :hg:`help dates` for a list of formats valid for -d/--date.
4076
4075
4077 .. container:: verbose
4076 .. container:: verbose
4078
4077
4079 Examples:
4078 Examples:
4080
4079
4081 - import a traditional patch from a website and detect renames::
4080 - import a traditional patch from a website and detect renames::
4082
4081
4083 hg import -s 80 http://example.com/bugfix.patch
4082 hg import -s 80 http://example.com/bugfix.patch
4084
4083
4085 - import a changeset from an hgweb server::
4084 - import a changeset from an hgweb server::
4086
4085
4087 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4086 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4088
4087
4089 - import all the patches in an Unix-style mbox::
4088 - import all the patches in an Unix-style mbox::
4090
4089
4091 hg import incoming-patches.mbox
4090 hg import incoming-patches.mbox
4092
4091
4093 - attempt to exactly restore an exported changeset (not always
4092 - attempt to exactly restore an exported changeset (not always
4094 possible)::
4093 possible)::
4095
4094
4096 hg import --exact proposed-fix.patch
4095 hg import --exact proposed-fix.patch
4097
4096
4098 Returns 0 on success, 1 on partial success (see --partial).
4097 Returns 0 on success, 1 on partial success (see --partial).
4099 """
4098 """
4100
4099
4101 if not patch1:
4100 if not patch1:
4102 raise util.Abort(_('need at least one patch to import'))
4101 raise util.Abort(_('need at least one patch to import'))
4103
4102
4104 patches = (patch1,) + patches
4103 patches = (patch1,) + patches
4105
4104
4106 date = opts.get('date')
4105 date = opts.get('date')
4107 if date:
4106 if date:
4108 opts['date'] = util.parsedate(date)
4107 opts['date'] = util.parsedate(date)
4109
4108
4110 update = not opts.get('bypass')
4109 update = not opts.get('bypass')
4111 if not update and opts.get('no_commit'):
4110 if not update and opts.get('no_commit'):
4112 raise util.Abort(_('cannot use --no-commit with --bypass'))
4111 raise util.Abort(_('cannot use --no-commit with --bypass'))
4113 try:
4112 try:
4114 sim = float(opts.get('similarity') or 0)
4113 sim = float(opts.get('similarity') or 0)
4115 except ValueError:
4114 except ValueError:
4116 raise util.Abort(_('similarity must be a number'))
4115 raise util.Abort(_('similarity must be a number'))
4117 if sim < 0 or sim > 100:
4116 if sim < 0 or sim > 100:
4118 raise util.Abort(_('similarity must be between 0 and 100'))
4117 raise util.Abort(_('similarity must be between 0 and 100'))
4119 if sim and not update:
4118 if sim and not update:
4120 raise util.Abort(_('cannot use --similarity with --bypass'))
4119 raise util.Abort(_('cannot use --similarity with --bypass'))
4121 if opts.get('exact') and opts.get('edit'):
4120 if opts.get('exact') and opts.get('edit'):
4122 raise util.Abort(_('cannot use --exact with --edit'))
4121 raise util.Abort(_('cannot use --exact with --edit'))
4123
4122
4124 if update:
4123 if update:
4125 cmdutil.checkunfinished(repo)
4124 cmdutil.checkunfinished(repo)
4126 if (opts.get('exact') or not opts.get('force')) and update:
4125 if (opts.get('exact') or not opts.get('force')) and update:
4127 cmdutil.bailifchanged(repo)
4126 cmdutil.bailifchanged(repo)
4128
4127
4129 base = opts["base"]
4128 base = opts["base"]
4130 wlock = lock = tr = None
4129 wlock = lock = tr = None
4131 msgs = []
4130 msgs = []
4132 ret = 0
4131 ret = 0
4133
4132
4134
4133
4135 try:
4134 try:
4136 try:
4135 try:
4137 wlock = repo.wlock()
4136 wlock = repo.wlock()
4138 repo.dirstate.beginparentchange()
4137 repo.dirstate.beginparentchange()
4139 if not opts.get('no_commit'):
4138 if not opts.get('no_commit'):
4140 lock = repo.lock()
4139 lock = repo.lock()
4141 tr = repo.transaction('import')
4140 tr = repo.transaction('import')
4142 parents = repo.parents()
4141 parents = repo.parents()
4143 for patchurl in patches:
4142 for patchurl in patches:
4144 if patchurl == '-':
4143 if patchurl == '-':
4145 ui.status(_('applying patch from stdin\n'))
4144 ui.status(_('applying patch from stdin\n'))
4146 patchfile = ui.fin
4145 patchfile = ui.fin
4147 patchurl = 'stdin' # for error message
4146 patchurl = 'stdin' # for error message
4148 else:
4147 else:
4149 patchurl = os.path.join(base, patchurl)
4148 patchurl = os.path.join(base, patchurl)
4150 ui.status(_('applying %s\n') % patchurl)
4149 ui.status(_('applying %s\n') % patchurl)
4151 patchfile = hg.openpath(ui, patchurl)
4150 patchfile = hg.openpath(ui, patchurl)
4152
4151
4153 haspatch = False
4152 haspatch = False
4154 for hunk in patch.split(patchfile):
4153 for hunk in patch.split(patchfile):
4155 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4154 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4156 parents, opts,
4155 parents, opts,
4157 msgs, hg.clean)
4156 msgs, hg.clean)
4158 if msg:
4157 if msg:
4159 haspatch = True
4158 haspatch = True
4160 ui.note(msg + '\n')
4159 ui.note(msg + '\n')
4161 if update or opts.get('exact'):
4160 if update or opts.get('exact'):
4162 parents = repo.parents()
4161 parents = repo.parents()
4163 else:
4162 else:
4164 parents = [repo[node]]
4163 parents = [repo[node]]
4165 if rej:
4164 if rej:
4166 ui.write_err(_("patch applied partially\n"))
4165 ui.write_err(_("patch applied partially\n"))
4167 ui.write_err(_("(fix the .rej files and run "
4166 ui.write_err(_("(fix the .rej files and run "
4168 "`hg commit --amend`)\n"))
4167 "`hg commit --amend`)\n"))
4169 ret = 1
4168 ret = 1
4170 break
4169 break
4171
4170
4172 if not haspatch:
4171 if not haspatch:
4173 raise util.Abort(_('%s: no diffs found') % patchurl)
4172 raise util.Abort(_('%s: no diffs found') % patchurl)
4174
4173
4175 if tr:
4174 if tr:
4176 tr.close()
4175 tr.close()
4177 if msgs:
4176 if msgs:
4178 repo.savecommitmessage('\n* * *\n'.join(msgs))
4177 repo.savecommitmessage('\n* * *\n'.join(msgs))
4179 repo.dirstate.endparentchange()
4178 repo.dirstate.endparentchange()
4180 return ret
4179 return ret
4181 except: # re-raises
4180 except: # re-raises
4182 # wlock.release() indirectly calls dirstate.write(): since
4181 # wlock.release() indirectly calls dirstate.write(): since
4183 # we're crashing, we do not want to change the working dir
4182 # we're crashing, we do not want to change the working dir
4184 # parent after all, so make sure it writes nothing
4183 # parent after all, so make sure it writes nothing
4185 repo.dirstate.invalidate()
4184 repo.dirstate.invalidate()
4186 raise
4185 raise
4187 finally:
4186 finally:
4188 if tr:
4187 if tr:
4189 tr.release()
4188 tr.release()
4190 release(lock, wlock)
4189 release(lock, wlock)
4191
4190
4192 @command('incoming|in',
4191 @command('incoming|in',
4193 [('f', 'force', None,
4192 [('f', 'force', None,
4194 _('run even if remote repository is unrelated')),
4193 _('run even if remote repository is unrelated')),
4195 ('n', 'newest-first', None, _('show newest record first')),
4194 ('n', 'newest-first', None, _('show newest record first')),
4196 ('', 'bundle', '',
4195 ('', 'bundle', '',
4197 _('file to store the bundles into'), _('FILE')),
4196 _('file to store the bundles into'), _('FILE')),
4198 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4197 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4199 ('B', 'bookmarks', False, _("compare bookmarks")),
4198 ('B', 'bookmarks', False, _("compare bookmarks")),
4200 ('b', 'branch', [],
4199 ('b', 'branch', [],
4201 _('a specific branch you would like to pull'), _('BRANCH')),
4200 _('a specific branch you would like to pull'), _('BRANCH')),
4202 ] + logopts + remoteopts + subrepoopts,
4201 ] + logopts + remoteopts + subrepoopts,
4203 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4202 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4204 def incoming(ui, repo, source="default", **opts):
4203 def incoming(ui, repo, source="default", **opts):
4205 """show new changesets found in source
4204 """show new changesets found in source
4206
4205
4207 Show new changesets found in the specified path/URL or the default
4206 Show new changesets found in the specified path/URL or the default
4208 pull location. These are the changesets that would have been pulled
4207 pull location. These are the changesets that would have been pulled
4209 if a pull at the time you issued this command.
4208 if a pull at the time you issued this command.
4210
4209
4211 For remote repository, using --bundle avoids downloading the
4210 For remote repository, using --bundle avoids downloading the
4212 changesets twice if the incoming is followed by a pull.
4211 changesets twice if the incoming is followed by a pull.
4213
4212
4214 See pull for valid source format details.
4213 See pull for valid source format details.
4215
4214
4216 .. container:: verbose
4215 .. container:: verbose
4217
4216
4218 Examples:
4217 Examples:
4219
4218
4220 - show incoming changes with patches and full description::
4219 - show incoming changes with patches and full description::
4221
4220
4222 hg incoming -vp
4221 hg incoming -vp
4223
4222
4224 - show incoming changes excluding merges, store a bundle::
4223 - show incoming changes excluding merges, store a bundle::
4225
4224
4226 hg in -vpM --bundle incoming.hg
4225 hg in -vpM --bundle incoming.hg
4227 hg pull incoming.hg
4226 hg pull incoming.hg
4228
4227
4229 - briefly list changes inside a bundle::
4228 - briefly list changes inside a bundle::
4230
4229
4231 hg in changes.hg -T "{desc|firstline}\\n"
4230 hg in changes.hg -T "{desc|firstline}\\n"
4232
4231
4233 Returns 0 if there are incoming changes, 1 otherwise.
4232 Returns 0 if there are incoming changes, 1 otherwise.
4234 """
4233 """
4235 if opts.get('graph'):
4234 if opts.get('graph'):
4236 cmdutil.checkunsupportedgraphflags([], opts)
4235 cmdutil.checkunsupportedgraphflags([], opts)
4237 def display(other, chlist, displayer):
4236 def display(other, chlist, displayer):
4238 revdag = cmdutil.graphrevs(other, chlist, opts)
4237 revdag = cmdutil.graphrevs(other, chlist, opts)
4239 showparents = [ctx.node() for ctx in repo[None].parents()]
4238 showparents = [ctx.node() for ctx in repo[None].parents()]
4240 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4239 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4241 graphmod.asciiedges)
4240 graphmod.asciiedges)
4242
4241
4243 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4242 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4244 return 0
4243 return 0
4245
4244
4246 if opts.get('bundle') and opts.get('subrepos'):
4245 if opts.get('bundle') and opts.get('subrepos'):
4247 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4246 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4248
4247
4249 if opts.get('bookmarks'):
4248 if opts.get('bookmarks'):
4250 source, branches = hg.parseurl(ui.expandpath(source),
4249 source, branches = hg.parseurl(ui.expandpath(source),
4251 opts.get('branch'))
4250 opts.get('branch'))
4252 other = hg.peer(repo, opts, source)
4251 other = hg.peer(repo, opts, source)
4253 if 'bookmarks' not in other.listkeys('namespaces'):
4252 if 'bookmarks' not in other.listkeys('namespaces'):
4254 ui.warn(_("remote doesn't support bookmarks\n"))
4253 ui.warn(_("remote doesn't support bookmarks\n"))
4255 return 0
4254 return 0
4256 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4255 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4257 return bookmarks.diff(ui, repo, other)
4256 return bookmarks.diff(ui, repo, other)
4258
4257
4259 repo._subtoppath = ui.expandpath(source)
4258 repo._subtoppath = ui.expandpath(source)
4260 try:
4259 try:
4261 return hg.incoming(ui, repo, source, opts)
4260 return hg.incoming(ui, repo, source, opts)
4262 finally:
4261 finally:
4263 del repo._subtoppath
4262 del repo._subtoppath
4264
4263
4265
4264
4266 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4265 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4267 norepo=True)
4266 norepo=True)
4268 def init(ui, dest=".", **opts):
4267 def init(ui, dest=".", **opts):
4269 """create a new repository in the given directory
4268 """create a new repository in the given directory
4270
4269
4271 Initialize a new repository in the given directory. If the given
4270 Initialize a new repository in the given directory. If the given
4272 directory does not exist, it will be created.
4271 directory does not exist, it will be created.
4273
4272
4274 If no directory is given, the current directory is used.
4273 If no directory is given, the current directory is used.
4275
4274
4276 It is possible to specify an ``ssh://`` URL as the destination.
4275 It is possible to specify an ``ssh://`` URL as the destination.
4277 See :hg:`help urls` for more information.
4276 See :hg:`help urls` for more information.
4278
4277
4279 Returns 0 on success.
4278 Returns 0 on success.
4280 """
4279 """
4281 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4280 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4282
4281
4283 @command('locate',
4282 @command('locate',
4284 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4283 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4285 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4284 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4286 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4285 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4287 ] + walkopts,
4286 ] + walkopts,
4288 _('[OPTION]... [PATTERN]...'))
4287 _('[OPTION]... [PATTERN]...'))
4289 def locate(ui, repo, *pats, **opts):
4288 def locate(ui, repo, *pats, **opts):
4290 """locate files matching specific patterns (DEPRECATED)
4289 """locate files matching specific patterns (DEPRECATED)
4291
4290
4292 Print files under Mercurial control in the working directory whose
4291 Print files under Mercurial control in the working directory whose
4293 names match the given patterns.
4292 names match the given patterns.
4294
4293
4295 By default, this command searches all directories in the working
4294 By default, this command searches all directories in the working
4296 directory. To search just the current directory and its
4295 directory. To search just the current directory and its
4297 subdirectories, use "--include .".
4296 subdirectories, use "--include .".
4298
4297
4299 If no patterns are given to match, this command prints the names
4298 If no patterns are given to match, this command prints the names
4300 of all files under Mercurial control in the working directory.
4299 of all files under Mercurial control in the working directory.
4301
4300
4302 If you want to feed the output of this command into the "xargs"
4301 If you want to feed the output of this command into the "xargs"
4303 command, use the -0 option to both this command and "xargs". This
4302 command, use the -0 option to both this command and "xargs". This
4304 will avoid the problem of "xargs" treating single filenames that
4303 will avoid the problem of "xargs" treating single filenames that
4305 contain whitespace as multiple filenames.
4304 contain whitespace as multiple filenames.
4306
4305
4307 See :hg:`help files` for a more versatile command.
4306 See :hg:`help files` for a more versatile command.
4308
4307
4309 Returns 0 if a match is found, 1 otherwise.
4308 Returns 0 if a match is found, 1 otherwise.
4310 """
4309 """
4311 end = opts.get('print0') and '\0' or '\n'
4310 end = opts.get('print0') and '\0' or '\n'
4312 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4311 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4313
4312
4314 ret = 1
4313 ret = 1
4315 ctx = repo[rev]
4314 ctx = repo[rev]
4316 m = scmutil.match(ctx, pats, opts, default='relglob')
4315 m = scmutil.match(ctx, pats, opts, default='relglob')
4317 m.bad = lambda x, y: False
4316 m.bad = lambda x, y: False
4318
4317
4319 for abs in ctx.matches(m):
4318 for abs in ctx.matches(m):
4320 if opts.get('fullpath'):
4319 if opts.get('fullpath'):
4321 ui.write(repo.wjoin(abs), end)
4320 ui.write(repo.wjoin(abs), end)
4322 else:
4321 else:
4323 ui.write(((pats and m.rel(abs)) or abs), end)
4322 ui.write(((pats and m.rel(abs)) or abs), end)
4324 ret = 0
4323 ret = 0
4325
4324
4326 return ret
4325 return ret
4327
4326
4328 @command('^log|history',
4327 @command('^log|history',
4329 [('f', 'follow', None,
4328 [('f', 'follow', None,
4330 _('follow changeset history, or file history across copies and renames')),
4329 _('follow changeset history, or file history across copies and renames')),
4331 ('', 'follow-first', None,
4330 ('', 'follow-first', None,
4332 _('only follow the first parent of merge changesets (DEPRECATED)')),
4331 _('only follow the first parent of merge changesets (DEPRECATED)')),
4333 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4332 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4334 ('C', 'copies', None, _('show copied files')),
4333 ('C', 'copies', None, _('show copied files')),
4335 ('k', 'keyword', [],
4334 ('k', 'keyword', [],
4336 _('do case-insensitive search for a given text'), _('TEXT')),
4335 _('do case-insensitive search for a given text'), _('TEXT')),
4337 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4336 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
4338 ('', 'removed', None, _('include revisions where files were removed')),
4337 ('', 'removed', None, _('include revisions where files were removed')),
4339 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4338 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4340 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4339 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4341 ('', 'only-branch', [],
4340 ('', 'only-branch', [],
4342 _('show only changesets within the given named branch (DEPRECATED)'),
4341 _('show only changesets within the given named branch (DEPRECATED)'),
4343 _('BRANCH')),
4342 _('BRANCH')),
4344 ('b', 'branch', [],
4343 ('b', 'branch', [],
4345 _('show changesets within the given named branch'), _('BRANCH')),
4344 _('show changesets within the given named branch'), _('BRANCH')),
4346 ('P', 'prune', [],
4345 ('P', 'prune', [],
4347 _('do not display revision or any of its ancestors'), _('REV')),
4346 _('do not display revision or any of its ancestors'), _('REV')),
4348 ] + logopts + walkopts,
4347 ] + logopts + walkopts,
4349 _('[OPTION]... [FILE]'),
4348 _('[OPTION]... [FILE]'),
4350 inferrepo=True)
4349 inferrepo=True)
4351 def log(ui, repo, *pats, **opts):
4350 def log(ui, repo, *pats, **opts):
4352 """show revision history of entire repository or files
4351 """show revision history of entire repository or files
4353
4352
4354 Print the revision history of the specified files or the entire
4353 Print the revision history of the specified files or the entire
4355 project.
4354 project.
4356
4355
4357 If no revision range is specified, the default is ``tip:0`` unless
4356 If no revision range is specified, the default is ``tip:0`` unless
4358 --follow is set, in which case the working directory parent is
4357 --follow is set, in which case the working directory parent is
4359 used as the starting revision.
4358 used as the starting revision.
4360
4359
4361 File history is shown without following rename or copy history of
4360 File history is shown without following rename or copy history of
4362 files. Use -f/--follow with a filename to follow history across
4361 files. Use -f/--follow with a filename to follow history across
4363 renames and copies. --follow without a filename will only show
4362 renames and copies. --follow without a filename will only show
4364 ancestors or descendants of the starting revision.
4363 ancestors or descendants of the starting revision.
4365
4364
4366 By default this command prints revision number and changeset id,
4365 By default this command prints revision number and changeset id,
4367 tags, non-trivial parents, user, date and time, and a summary for
4366 tags, non-trivial parents, user, date and time, and a summary for
4368 each commit. When the -v/--verbose switch is used, the list of
4367 each commit. When the -v/--verbose switch is used, the list of
4369 changed files and full commit message are shown.
4368 changed files and full commit message are shown.
4370
4369
4371 With --graph the revisions are shown as an ASCII art DAG with the most
4370 With --graph the revisions are shown as an ASCII art DAG with the most
4372 recent changeset at the top.
4371 recent changeset at the top.
4373 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4372 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4374 and '+' represents a fork where the changeset from the lines below is a
4373 and '+' represents a fork where the changeset from the lines below is a
4375 parent of the 'o' merge on the same line.
4374 parent of the 'o' merge on the same line.
4376
4375
4377 .. note::
4376 .. note::
4378
4377
4379 log -p/--patch may generate unexpected diff output for merge
4378 log -p/--patch may generate unexpected diff output for merge
4380 changesets, as it will only compare the merge changeset against
4379 changesets, as it will only compare the merge changeset against
4381 its first parent. Also, only files different from BOTH parents
4380 its first parent. Also, only files different from BOTH parents
4382 will appear in files:.
4381 will appear in files:.
4383
4382
4384 .. note::
4383 .. note::
4385
4384
4386 for performance reasons, log FILE may omit duplicate changes
4385 for performance reasons, log FILE may omit duplicate changes
4387 made on branches and will not show removals or mode changes. To
4386 made on branches and will not show removals or mode changes. To
4388 see all such changes, use the --removed switch.
4387 see all such changes, use the --removed switch.
4389
4388
4390 .. container:: verbose
4389 .. container:: verbose
4391
4390
4392 Some examples:
4391 Some examples:
4393
4392
4394 - changesets with full descriptions and file lists::
4393 - changesets with full descriptions and file lists::
4395
4394
4396 hg log -v
4395 hg log -v
4397
4396
4398 - changesets ancestral to the working directory::
4397 - changesets ancestral to the working directory::
4399
4398
4400 hg log -f
4399 hg log -f
4401
4400
4402 - last 10 commits on the current branch::
4401 - last 10 commits on the current branch::
4403
4402
4404 hg log -l 10 -b .
4403 hg log -l 10 -b .
4405
4404
4406 - changesets showing all modifications of a file, including removals::
4405 - changesets showing all modifications of a file, including removals::
4407
4406
4408 hg log --removed file.c
4407 hg log --removed file.c
4409
4408
4410 - all changesets that touch a directory, with diffs, excluding merges::
4409 - all changesets that touch a directory, with diffs, excluding merges::
4411
4410
4412 hg log -Mp lib/
4411 hg log -Mp lib/
4413
4412
4414 - all revision numbers that match a keyword::
4413 - all revision numbers that match a keyword::
4415
4414
4416 hg log -k bug --template "{rev}\\n"
4415 hg log -k bug --template "{rev}\\n"
4417
4416
4418 - list available log templates::
4417 - list available log templates::
4419
4418
4420 hg log -T list
4419 hg log -T list
4421
4420
4422 - check if a given changeset is included in a tagged release::
4421 - check if a given changeset is included in a tagged release::
4423
4422
4424 hg log -r "a21ccf and ancestor(1.9)"
4423 hg log -r "a21ccf and ancestor(1.9)"
4425
4424
4426 - find all changesets by some user in a date range::
4425 - find all changesets by some user in a date range::
4427
4426
4428 hg log -k alice -d "may 2008 to jul 2008"
4427 hg log -k alice -d "may 2008 to jul 2008"
4429
4428
4430 - summary of all changesets after the last tag::
4429 - summary of all changesets after the last tag::
4431
4430
4432 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4431 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4433
4432
4434 See :hg:`help dates` for a list of formats valid for -d/--date.
4433 See :hg:`help dates` for a list of formats valid for -d/--date.
4435
4434
4436 See :hg:`help revisions` and :hg:`help revsets` for more about
4435 See :hg:`help revisions` and :hg:`help revsets` for more about
4437 specifying revisions.
4436 specifying revisions.
4438
4437
4439 See :hg:`help templates` for more about pre-packaged styles and
4438 See :hg:`help templates` for more about pre-packaged styles and
4440 specifying custom templates.
4439 specifying custom templates.
4441
4440
4442 Returns 0 on success.
4441 Returns 0 on success.
4443
4442
4444 """
4443 """
4445 if opts.get('graph'):
4444 if opts.get('graph'):
4446 return cmdutil.graphlog(ui, repo, *pats, **opts)
4445 return cmdutil.graphlog(ui, repo, *pats, **opts)
4447
4446
4448 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4447 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4449 limit = cmdutil.loglimit(opts)
4448 limit = cmdutil.loglimit(opts)
4450 count = 0
4449 count = 0
4451
4450
4452 getrenamed = None
4451 getrenamed = None
4453 if opts.get('copies'):
4452 if opts.get('copies'):
4454 endrev = None
4453 endrev = None
4455 if opts.get('rev'):
4454 if opts.get('rev'):
4456 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4455 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4457 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4456 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4458
4457
4459 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4458 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4460 for rev in revs:
4459 for rev in revs:
4461 if count == limit:
4460 if count == limit:
4462 break
4461 break
4463 ctx = repo[rev]
4462 ctx = repo[rev]
4464 copies = None
4463 copies = None
4465 if getrenamed is not None and rev:
4464 if getrenamed is not None and rev:
4466 copies = []
4465 copies = []
4467 for fn in ctx.files():
4466 for fn in ctx.files():
4468 rename = getrenamed(fn, rev)
4467 rename = getrenamed(fn, rev)
4469 if rename:
4468 if rename:
4470 copies.append((fn, rename[0]))
4469 copies.append((fn, rename[0]))
4471 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4470 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4472 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4471 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4473 if displayer.flush(rev):
4472 if displayer.flush(rev):
4474 count += 1
4473 count += 1
4475
4474
4476 displayer.close()
4475 displayer.close()
4477
4476
4478 @command('manifest',
4477 @command('manifest',
4479 [('r', 'rev', '', _('revision to display'), _('REV')),
4478 [('r', 'rev', '', _('revision to display'), _('REV')),
4480 ('', 'all', False, _("list files from all revisions"))]
4479 ('', 'all', False, _("list files from all revisions"))]
4481 + formatteropts,
4480 + formatteropts,
4482 _('[-r REV]'))
4481 _('[-r REV]'))
4483 def manifest(ui, repo, node=None, rev=None, **opts):
4482 def manifest(ui, repo, node=None, rev=None, **opts):
4484 """output the current or given revision of the project manifest
4483 """output the current or given revision of the project manifest
4485
4484
4486 Print a list of version controlled files for the given revision.
4485 Print a list of version controlled files for the given revision.
4487 If no revision is given, the first parent of the working directory
4486 If no revision is given, the first parent of the working directory
4488 is used, or the null revision if no revision is checked out.
4487 is used, or the null revision if no revision is checked out.
4489
4488
4490 With -v, print file permissions, symlink and executable bits.
4489 With -v, print file permissions, symlink and executable bits.
4491 With --debug, print file revision hashes.
4490 With --debug, print file revision hashes.
4492
4491
4493 If option --all is specified, the list of all files from all revisions
4492 If option --all is specified, the list of all files from all revisions
4494 is printed. This includes deleted and renamed files.
4493 is printed. This includes deleted and renamed files.
4495
4494
4496 Returns 0 on success.
4495 Returns 0 on success.
4497 """
4496 """
4498
4497
4499 fm = ui.formatter('manifest', opts)
4498 fm = ui.formatter('manifest', opts)
4500
4499
4501 if opts.get('all'):
4500 if opts.get('all'):
4502 if rev or node:
4501 if rev or node:
4503 raise util.Abort(_("can't specify a revision with --all"))
4502 raise util.Abort(_("can't specify a revision with --all"))
4504
4503
4505 res = []
4504 res = []
4506 prefix = "data/"
4505 prefix = "data/"
4507 suffix = ".i"
4506 suffix = ".i"
4508 plen = len(prefix)
4507 plen = len(prefix)
4509 slen = len(suffix)
4508 slen = len(suffix)
4510 lock = repo.lock()
4509 lock = repo.lock()
4511 try:
4510 try:
4512 for fn, b, size in repo.store.datafiles():
4511 for fn, b, size in repo.store.datafiles():
4513 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4512 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4514 res.append(fn[plen:-slen])
4513 res.append(fn[plen:-slen])
4515 finally:
4514 finally:
4516 lock.release()
4515 lock.release()
4517 for f in res:
4516 for f in res:
4518 fm.startitem()
4517 fm.startitem()
4519 fm.write("path", '%s\n', f)
4518 fm.write("path", '%s\n', f)
4520 fm.end()
4519 fm.end()
4521 return
4520 return
4522
4521
4523 if rev and node:
4522 if rev and node:
4524 raise util.Abort(_("please specify just one revision"))
4523 raise util.Abort(_("please specify just one revision"))
4525
4524
4526 if not node:
4525 if not node:
4527 node = rev
4526 node = rev
4528
4527
4529 char = {'l': '@', 'x': '*', '': ''}
4528 char = {'l': '@', 'x': '*', '': ''}
4530 mode = {'l': '644', 'x': '755', '': '644'}
4529 mode = {'l': '644', 'x': '755', '': '644'}
4531 ctx = scmutil.revsingle(repo, node)
4530 ctx = scmutil.revsingle(repo, node)
4532 mf = ctx.manifest()
4531 mf = ctx.manifest()
4533 for f in ctx:
4532 for f in ctx:
4534 fm.startitem()
4533 fm.startitem()
4535 fl = ctx[f].flags()
4534 fl = ctx[f].flags()
4536 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4535 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4537 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4536 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4538 fm.write('path', '%s\n', f)
4537 fm.write('path', '%s\n', f)
4539 fm.end()
4538 fm.end()
4540
4539
4541 @command('^merge',
4540 @command('^merge',
4542 [('f', 'force', None,
4541 [('f', 'force', None,
4543 _('force a merge including outstanding changes (DEPRECATED)')),
4542 _('force a merge including outstanding changes (DEPRECATED)')),
4544 ('r', 'rev', '', _('revision to merge'), _('REV')),
4543 ('r', 'rev', '', _('revision to merge'), _('REV')),
4545 ('P', 'preview', None,
4544 ('P', 'preview', None,
4546 _('review revisions to merge (no merge is performed)'))
4545 _('review revisions to merge (no merge is performed)'))
4547 ] + mergetoolopts,
4546 ] + mergetoolopts,
4548 _('[-P] [-f] [[-r] REV]'))
4547 _('[-P] [-f] [[-r] REV]'))
4549 def merge(ui, repo, node=None, **opts):
4548 def merge(ui, repo, node=None, **opts):
4550 """merge working directory with another revision
4549 """merge working directory with another revision
4551
4550
4552 The current working directory is updated with all changes made in
4551 The current working directory is updated with all changes made in
4553 the requested revision since the last common predecessor revision.
4552 the requested revision since the last common predecessor revision.
4554
4553
4555 Files that changed between either parent are marked as changed for
4554 Files that changed between either parent are marked as changed for
4556 the next commit and a commit must be performed before any further
4555 the next commit and a commit must be performed before any further
4557 updates to the repository are allowed. The next commit will have
4556 updates to the repository are allowed. The next commit will have
4558 two parents.
4557 two parents.
4559
4558
4560 ``--tool`` can be used to specify the merge tool used for file
4559 ``--tool`` can be used to specify the merge tool used for file
4561 merges. It overrides the HGMERGE environment variable and your
4560 merges. It overrides the HGMERGE environment variable and your
4562 configuration files. See :hg:`help merge-tools` for options.
4561 configuration files. See :hg:`help merge-tools` for options.
4563
4562
4564 If no revision is specified, the working directory's parent is a
4563 If no revision is specified, the working directory's parent is a
4565 head revision, and the current branch contains exactly one other
4564 head revision, and the current branch contains exactly one other
4566 head, the other head is merged with by default. Otherwise, an
4565 head, the other head is merged with by default. Otherwise, an
4567 explicit revision with which to merge with must be provided.
4566 explicit revision with which to merge with must be provided.
4568
4567
4569 :hg:`resolve` must be used to resolve unresolved files.
4568 :hg:`resolve` must be used to resolve unresolved files.
4570
4569
4571 To undo an uncommitted merge, use :hg:`update --clean .` which
4570 To undo an uncommitted merge, use :hg:`update --clean .` which
4572 will check out a clean copy of the original merge parent, losing
4571 will check out a clean copy of the original merge parent, losing
4573 all changes.
4572 all changes.
4574
4573
4575 Returns 0 on success, 1 if there are unresolved files.
4574 Returns 0 on success, 1 if there are unresolved files.
4576 """
4575 """
4577
4576
4578 if opts.get('rev') and node:
4577 if opts.get('rev') and node:
4579 raise util.Abort(_("please specify just one revision"))
4578 raise util.Abort(_("please specify just one revision"))
4580 if not node:
4579 if not node:
4581 node = opts.get('rev')
4580 node = opts.get('rev')
4582
4581
4583 if node:
4582 if node:
4584 node = scmutil.revsingle(repo, node).node()
4583 node = scmutil.revsingle(repo, node).node()
4585
4584
4586 if not node and repo._bookmarkcurrent:
4585 if not node and repo._bookmarkcurrent:
4587 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4586 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4588 curhead = repo[repo._bookmarkcurrent].node()
4587 curhead = repo[repo._bookmarkcurrent].node()
4589 if len(bmheads) == 2:
4588 if len(bmheads) == 2:
4590 if curhead == bmheads[0]:
4589 if curhead == bmheads[0]:
4591 node = bmheads[1]
4590 node = bmheads[1]
4592 else:
4591 else:
4593 node = bmheads[0]
4592 node = bmheads[0]
4594 elif len(bmheads) > 2:
4593 elif len(bmheads) > 2:
4595 raise util.Abort(_("multiple matching bookmarks to merge - "
4594 raise util.Abort(_("multiple matching bookmarks to merge - "
4596 "please merge with an explicit rev or bookmark"),
4595 "please merge with an explicit rev or bookmark"),
4597 hint=_("run 'hg heads' to see all heads"))
4596 hint=_("run 'hg heads' to see all heads"))
4598 elif len(bmheads) <= 1:
4597 elif len(bmheads) <= 1:
4599 raise util.Abort(_("no matching bookmark to merge - "
4598 raise util.Abort(_("no matching bookmark to merge - "
4600 "please merge with an explicit rev or bookmark"),
4599 "please merge with an explicit rev or bookmark"),
4601 hint=_("run 'hg heads' to see all heads"))
4600 hint=_("run 'hg heads' to see all heads"))
4602
4601
4603 if not node and not repo._bookmarkcurrent:
4602 if not node and not repo._bookmarkcurrent:
4604 branch = repo[None].branch()
4603 branch = repo[None].branch()
4605 bheads = repo.branchheads(branch)
4604 bheads = repo.branchheads(branch)
4606 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4605 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4607
4606
4608 if len(nbhs) > 2:
4607 if len(nbhs) > 2:
4609 raise util.Abort(_("branch '%s' has %d heads - "
4608 raise util.Abort(_("branch '%s' has %d heads - "
4610 "please merge with an explicit rev")
4609 "please merge with an explicit rev")
4611 % (branch, len(bheads)),
4610 % (branch, len(bheads)),
4612 hint=_("run 'hg heads .' to see heads"))
4611 hint=_("run 'hg heads .' to see heads"))
4613
4612
4614 parent = repo.dirstate.p1()
4613 parent = repo.dirstate.p1()
4615 if len(nbhs) <= 1:
4614 if len(nbhs) <= 1:
4616 if len(bheads) > 1:
4615 if len(bheads) > 1:
4617 raise util.Abort(_("heads are bookmarked - "
4616 raise util.Abort(_("heads are bookmarked - "
4618 "please merge with an explicit rev"),
4617 "please merge with an explicit rev"),
4619 hint=_("run 'hg heads' to see all heads"))
4618 hint=_("run 'hg heads' to see all heads"))
4620 if len(repo.heads()) > 1:
4619 if len(repo.heads()) > 1:
4621 raise util.Abort(_("branch '%s' has one head - "
4620 raise util.Abort(_("branch '%s' has one head - "
4622 "please merge with an explicit rev")
4621 "please merge with an explicit rev")
4623 % branch,
4622 % branch,
4624 hint=_("run 'hg heads' to see all heads"))
4623 hint=_("run 'hg heads' to see all heads"))
4625 msg, hint = _('nothing to merge'), None
4624 msg, hint = _('nothing to merge'), None
4626 if parent != repo.lookup(branch):
4625 if parent != repo.lookup(branch):
4627 hint = _("use 'hg update' instead")
4626 hint = _("use 'hg update' instead")
4628 raise util.Abort(msg, hint=hint)
4627 raise util.Abort(msg, hint=hint)
4629
4628
4630 if parent not in bheads:
4629 if parent not in bheads:
4631 raise util.Abort(_('working directory not at a head revision'),
4630 raise util.Abort(_('working directory not at a head revision'),
4632 hint=_("use 'hg update' or merge with an "
4631 hint=_("use 'hg update' or merge with an "
4633 "explicit revision"))
4632 "explicit revision"))
4634 if parent == nbhs[0]:
4633 if parent == nbhs[0]:
4635 node = nbhs[-1]
4634 node = nbhs[-1]
4636 else:
4635 else:
4637 node = nbhs[0]
4636 node = nbhs[0]
4638
4637
4639 if opts.get('preview'):
4638 if opts.get('preview'):
4640 # find nodes that are ancestors of p2 but not of p1
4639 # find nodes that are ancestors of p2 but not of p1
4641 p1 = repo.lookup('.')
4640 p1 = repo.lookup('.')
4642 p2 = repo.lookup(node)
4641 p2 = repo.lookup(node)
4643 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4642 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4644
4643
4645 displayer = cmdutil.show_changeset(ui, repo, opts)
4644 displayer = cmdutil.show_changeset(ui, repo, opts)
4646 for node in nodes:
4645 for node in nodes:
4647 displayer.show(repo[node])
4646 displayer.show(repo[node])
4648 displayer.close()
4647 displayer.close()
4649 return 0
4648 return 0
4650
4649
4651 try:
4650 try:
4652 # ui.forcemerge is an internal variable, do not document
4651 # ui.forcemerge is an internal variable, do not document
4653 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4652 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4654 return hg.merge(repo, node, force=opts.get('force'))
4653 return hg.merge(repo, node, force=opts.get('force'))
4655 finally:
4654 finally:
4656 ui.setconfig('ui', 'forcemerge', '', 'merge')
4655 ui.setconfig('ui', 'forcemerge', '', 'merge')
4657
4656
4658 @command('outgoing|out',
4657 @command('outgoing|out',
4659 [('f', 'force', None, _('run even when the destination is unrelated')),
4658 [('f', 'force', None, _('run even when the destination is unrelated')),
4660 ('r', 'rev', [],
4659 ('r', 'rev', [],
4661 _('a changeset intended to be included in the destination'), _('REV')),
4660 _('a changeset intended to be included in the destination'), _('REV')),
4662 ('n', 'newest-first', None, _('show newest record first')),
4661 ('n', 'newest-first', None, _('show newest record first')),
4663 ('B', 'bookmarks', False, _('compare bookmarks')),
4662 ('B', 'bookmarks', False, _('compare bookmarks')),
4664 ('b', 'branch', [], _('a specific branch you would like to push'),
4663 ('b', 'branch', [], _('a specific branch you would like to push'),
4665 _('BRANCH')),
4664 _('BRANCH')),
4666 ] + logopts + remoteopts + subrepoopts,
4665 ] + logopts + remoteopts + subrepoopts,
4667 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4666 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4668 def outgoing(ui, repo, dest=None, **opts):
4667 def outgoing(ui, repo, dest=None, **opts):
4669 """show changesets not found in the destination
4668 """show changesets not found in the destination
4670
4669
4671 Show changesets not found in the specified destination repository
4670 Show changesets not found in the specified destination repository
4672 or the default push location. These are the changesets that would
4671 or the default push location. These are the changesets that would
4673 be pushed if a push was requested.
4672 be pushed if a push was requested.
4674
4673
4675 See pull for details of valid destination formats.
4674 See pull for details of valid destination formats.
4676
4675
4677 Returns 0 if there are outgoing changes, 1 otherwise.
4676 Returns 0 if there are outgoing changes, 1 otherwise.
4678 """
4677 """
4679 if opts.get('graph'):
4678 if opts.get('graph'):
4680 cmdutil.checkunsupportedgraphflags([], opts)
4679 cmdutil.checkunsupportedgraphflags([], opts)
4681 o, other = hg._outgoing(ui, repo, dest, opts)
4680 o, other = hg._outgoing(ui, repo, dest, opts)
4682 if not o:
4681 if not o:
4683 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4682 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4684 return
4683 return
4685
4684
4686 revdag = cmdutil.graphrevs(repo, o, opts)
4685 revdag = cmdutil.graphrevs(repo, o, opts)
4687 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4686 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4688 showparents = [ctx.node() for ctx in repo[None].parents()]
4687 showparents = [ctx.node() for ctx in repo[None].parents()]
4689 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4688 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4690 graphmod.asciiedges)
4689 graphmod.asciiedges)
4691 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4690 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4692 return 0
4691 return 0
4693
4692
4694 if opts.get('bookmarks'):
4693 if opts.get('bookmarks'):
4695 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4694 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4696 dest, branches = hg.parseurl(dest, opts.get('branch'))
4695 dest, branches = hg.parseurl(dest, opts.get('branch'))
4697 other = hg.peer(repo, opts, dest)
4696 other = hg.peer(repo, opts, dest)
4698 if 'bookmarks' not in other.listkeys('namespaces'):
4697 if 'bookmarks' not in other.listkeys('namespaces'):
4699 ui.warn(_("remote doesn't support bookmarks\n"))
4698 ui.warn(_("remote doesn't support bookmarks\n"))
4700 return 0
4699 return 0
4701 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4700 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4702 return bookmarks.diff(ui, other, repo)
4701 return bookmarks.diff(ui, other, repo)
4703
4702
4704 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4703 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4705 try:
4704 try:
4706 return hg.outgoing(ui, repo, dest, opts)
4705 return hg.outgoing(ui, repo, dest, opts)
4707 finally:
4706 finally:
4708 del repo._subtoppath
4707 del repo._subtoppath
4709
4708
4710 @command('parents',
4709 @command('parents',
4711 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4710 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4712 ] + templateopts,
4711 ] + templateopts,
4713 _('[-r REV] [FILE]'),
4712 _('[-r REV] [FILE]'),
4714 inferrepo=True)
4713 inferrepo=True)
4715 def parents(ui, repo, file_=None, **opts):
4714 def parents(ui, repo, file_=None, **opts):
4716 """show the parents of the working directory or revision (DEPRECATED)
4715 """show the parents of the working directory or revision (DEPRECATED)
4717
4716
4718 Print the working directory's parent revisions. If a revision is
4717 Print the working directory's parent revisions. If a revision is
4719 given via -r/--rev, the parent of that revision will be printed.
4718 given via -r/--rev, the parent of that revision will be printed.
4720 If a file argument is given, the revision in which the file was
4719 If a file argument is given, the revision in which the file was
4721 last changed (before the working directory revision or the
4720 last changed (before the working directory revision or the
4722 argument to --rev if given) is printed.
4721 argument to --rev if given) is printed.
4723
4722
4724 See :hg:`summary` and :hg:`help revsets` for related information.
4723 See :hg:`summary` and :hg:`help revsets` for related information.
4725
4724
4726 Returns 0 on success.
4725 Returns 0 on success.
4727 """
4726 """
4728
4727
4729 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4728 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4730
4729
4731 if file_:
4730 if file_:
4732 m = scmutil.match(ctx, (file_,), opts)
4731 m = scmutil.match(ctx, (file_,), opts)
4733 if m.anypats() or len(m.files()) != 1:
4732 if m.anypats() or len(m.files()) != 1:
4734 raise util.Abort(_('can only specify an explicit filename'))
4733 raise util.Abort(_('can only specify an explicit filename'))
4735 file_ = m.files()[0]
4734 file_ = m.files()[0]
4736 filenodes = []
4735 filenodes = []
4737 for cp in ctx.parents():
4736 for cp in ctx.parents():
4738 if not cp:
4737 if not cp:
4739 continue
4738 continue
4740 try:
4739 try:
4741 filenodes.append(cp.filenode(file_))
4740 filenodes.append(cp.filenode(file_))
4742 except error.LookupError:
4741 except error.LookupError:
4743 pass
4742 pass
4744 if not filenodes:
4743 if not filenodes:
4745 raise util.Abort(_("'%s' not found in manifest!") % file_)
4744 raise util.Abort(_("'%s' not found in manifest!") % file_)
4746 p = []
4745 p = []
4747 for fn in filenodes:
4746 for fn in filenodes:
4748 fctx = repo.filectx(file_, fileid=fn)
4747 fctx = repo.filectx(file_, fileid=fn)
4749 p.append(fctx.node())
4748 p.append(fctx.node())
4750 else:
4749 else:
4751 p = [cp.node() for cp in ctx.parents()]
4750 p = [cp.node() for cp in ctx.parents()]
4752
4751
4753 displayer = cmdutil.show_changeset(ui, repo, opts)
4752 displayer = cmdutil.show_changeset(ui, repo, opts)
4754 for n in p:
4753 for n in p:
4755 if n != nullid:
4754 if n != nullid:
4756 displayer.show(repo[n])
4755 displayer.show(repo[n])
4757 displayer.close()
4756 displayer.close()
4758
4757
4759 @command('paths', [], _('[NAME]'), optionalrepo=True)
4758 @command('paths', [], _('[NAME]'), optionalrepo=True)
4760 def paths(ui, repo, search=None):
4759 def paths(ui, repo, search=None):
4761 """show aliases for remote repositories
4760 """show aliases for remote repositories
4762
4761
4763 Show definition of symbolic path name NAME. If no name is given,
4762 Show definition of symbolic path name NAME. If no name is given,
4764 show definition of all available names.
4763 show definition of all available names.
4765
4764
4766 Option -q/--quiet suppresses all output when searching for NAME
4765 Option -q/--quiet suppresses all output when searching for NAME
4767 and shows only the path names when listing all definitions.
4766 and shows only the path names when listing all definitions.
4768
4767
4769 Path names are defined in the [paths] section of your
4768 Path names are defined in the [paths] section of your
4770 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4769 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4771 repository, ``.hg/hgrc`` is used, too.
4770 repository, ``.hg/hgrc`` is used, too.
4772
4771
4773 The path names ``default`` and ``default-push`` have a special
4772 The path names ``default`` and ``default-push`` have a special
4774 meaning. When performing a push or pull operation, they are used
4773 meaning. When performing a push or pull operation, they are used
4775 as fallbacks if no location is specified on the command-line.
4774 as fallbacks if no location is specified on the command-line.
4776 When ``default-push`` is set, it will be used for push and
4775 When ``default-push`` is set, it will be used for push and
4777 ``default`` will be used for pull; otherwise ``default`` is used
4776 ``default`` will be used for pull; otherwise ``default`` is used
4778 as the fallback for both. When cloning a repository, the clone
4777 as the fallback for both. When cloning a repository, the clone
4779 source is written as ``default`` in ``.hg/hgrc``. Note that
4778 source is written as ``default`` in ``.hg/hgrc``. Note that
4780 ``default`` and ``default-push`` apply to all inbound (e.g.
4779 ``default`` and ``default-push`` apply to all inbound (e.g.
4781 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4780 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4782 :hg:`bundle`) operations.
4781 :hg:`bundle`) operations.
4783
4782
4784 See :hg:`help urls` for more information.
4783 See :hg:`help urls` for more information.
4785
4784
4786 Returns 0 on success.
4785 Returns 0 on success.
4787 """
4786 """
4788 if search:
4787 if search:
4789 for name, path in ui.configitems("paths"):
4788 for name, path in ui.configitems("paths"):
4790 if name == search:
4789 if name == search:
4791 ui.status("%s\n" % util.hidepassword(path))
4790 ui.status("%s\n" % util.hidepassword(path))
4792 return
4791 return
4793 if not ui.quiet:
4792 if not ui.quiet:
4794 ui.warn(_("not found!\n"))
4793 ui.warn(_("not found!\n"))
4795 return 1
4794 return 1
4796 else:
4795 else:
4797 for name, path in ui.configitems("paths"):
4796 for name, path in ui.configitems("paths"):
4798 if ui.quiet:
4797 if ui.quiet:
4799 ui.write("%s\n" % name)
4798 ui.write("%s\n" % name)
4800 else:
4799 else:
4801 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4800 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4802
4801
4803 @command('phase',
4802 @command('phase',
4804 [('p', 'public', False, _('set changeset phase to public')),
4803 [('p', 'public', False, _('set changeset phase to public')),
4805 ('d', 'draft', False, _('set changeset phase to draft')),
4804 ('d', 'draft', False, _('set changeset phase to draft')),
4806 ('s', 'secret', False, _('set changeset phase to secret')),
4805 ('s', 'secret', False, _('set changeset phase to secret')),
4807 ('f', 'force', False, _('allow to move boundary backward')),
4806 ('f', 'force', False, _('allow to move boundary backward')),
4808 ('r', 'rev', [], _('target revision'), _('REV')),
4807 ('r', 'rev', [], _('target revision'), _('REV')),
4809 ],
4808 ],
4810 _('[-p|-d|-s] [-f] [-r] REV...'))
4809 _('[-p|-d|-s] [-f] [-r] REV...'))
4811 def phase(ui, repo, *revs, **opts):
4810 def phase(ui, repo, *revs, **opts):
4812 """set or show the current phase name
4811 """set or show the current phase name
4813
4812
4814 With no argument, show the phase name of specified revisions.
4813 With no argument, show the phase name of specified revisions.
4815
4814
4816 With one of -p/--public, -d/--draft or -s/--secret, change the
4815 With one of -p/--public, -d/--draft or -s/--secret, change the
4817 phase value of the specified revisions.
4816 phase value of the specified revisions.
4818
4817
4819 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4818 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4820 lower phase to an higher phase. Phases are ordered as follows::
4819 lower phase to an higher phase. Phases are ordered as follows::
4821
4820
4822 public < draft < secret
4821 public < draft < secret
4823
4822
4824 Returns 0 on success, 1 if no phases were changed or some could not
4823 Returns 0 on success, 1 if no phases were changed or some could not
4825 be changed.
4824 be changed.
4826 """
4825 """
4827 # search for a unique phase argument
4826 # search for a unique phase argument
4828 targetphase = None
4827 targetphase = None
4829 for idx, name in enumerate(phases.phasenames):
4828 for idx, name in enumerate(phases.phasenames):
4830 if opts[name]:
4829 if opts[name]:
4831 if targetphase is not None:
4830 if targetphase is not None:
4832 raise util.Abort(_('only one phase can be specified'))
4831 raise util.Abort(_('only one phase can be specified'))
4833 targetphase = idx
4832 targetphase = idx
4834
4833
4835 # look for specified revision
4834 # look for specified revision
4836 revs = list(revs)
4835 revs = list(revs)
4837 revs.extend(opts['rev'])
4836 revs.extend(opts['rev'])
4838 if not revs:
4837 if not revs:
4839 raise util.Abort(_('no revisions specified'))
4838 raise util.Abort(_('no revisions specified'))
4840
4839
4841 revs = scmutil.revrange(repo, revs)
4840 revs = scmutil.revrange(repo, revs)
4842
4841
4843 lock = None
4842 lock = None
4844 ret = 0
4843 ret = 0
4845 if targetphase is None:
4844 if targetphase is None:
4846 # display
4845 # display
4847 for r in revs:
4846 for r in revs:
4848 ctx = repo[r]
4847 ctx = repo[r]
4849 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4848 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4850 else:
4849 else:
4851 tr = None
4850 tr = None
4852 lock = repo.lock()
4851 lock = repo.lock()
4853 try:
4852 try:
4854 tr = repo.transaction("phase")
4853 tr = repo.transaction("phase")
4855 # set phase
4854 # set phase
4856 if not revs:
4855 if not revs:
4857 raise util.Abort(_('empty revision set'))
4856 raise util.Abort(_('empty revision set'))
4858 nodes = [repo[r].node() for r in revs]
4857 nodes = [repo[r].node() for r in revs]
4859 olddata = repo._phasecache.getphaserevs(repo)[:]
4858 olddata = repo._phasecache.getphaserevs(repo)[:]
4860 phases.advanceboundary(repo, tr, targetphase, nodes)
4859 phases.advanceboundary(repo, tr, targetphase, nodes)
4861 if opts['force']:
4860 if opts['force']:
4862 phases.retractboundary(repo, tr, targetphase, nodes)
4861 phases.retractboundary(repo, tr, targetphase, nodes)
4863 tr.close()
4862 tr.close()
4864 finally:
4863 finally:
4865 if tr is not None:
4864 if tr is not None:
4866 tr.release()
4865 tr.release()
4867 lock.release()
4866 lock.release()
4868 # moving revision from public to draft may hide them
4867 # moving revision from public to draft may hide them
4869 # We have to check result on an unfiltered repository
4868 # We have to check result on an unfiltered repository
4870 unfi = repo.unfiltered()
4869 unfi = repo.unfiltered()
4871 newdata = repo._phasecache.getphaserevs(unfi)
4870 newdata = repo._phasecache.getphaserevs(unfi)
4872 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4871 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4873 cl = unfi.changelog
4872 cl = unfi.changelog
4874 rejected = [n for n in nodes
4873 rejected = [n for n in nodes
4875 if newdata[cl.rev(n)] < targetphase]
4874 if newdata[cl.rev(n)] < targetphase]
4876 if rejected:
4875 if rejected:
4877 ui.warn(_('cannot move %i changesets to a higher '
4876 ui.warn(_('cannot move %i changesets to a higher '
4878 'phase, use --force\n') % len(rejected))
4877 'phase, use --force\n') % len(rejected))
4879 ret = 1
4878 ret = 1
4880 if changes:
4879 if changes:
4881 msg = _('phase changed for %i changesets\n') % changes
4880 msg = _('phase changed for %i changesets\n') % changes
4882 if ret:
4881 if ret:
4883 ui.status(msg)
4882 ui.status(msg)
4884 else:
4883 else:
4885 ui.note(msg)
4884 ui.note(msg)
4886 else:
4885 else:
4887 ui.warn(_('no phases changed\n'))
4886 ui.warn(_('no phases changed\n'))
4888 ret = 1
4887 ret = 1
4889 return ret
4888 return ret
4890
4889
4891 def postincoming(ui, repo, modheads, optupdate, checkout):
4890 def postincoming(ui, repo, modheads, optupdate, checkout):
4892 if modheads == 0:
4891 if modheads == 0:
4893 return
4892 return
4894 if optupdate:
4893 if optupdate:
4895 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4894 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4896 try:
4895 try:
4897 ret = hg.update(repo, checkout)
4896 ret = hg.update(repo, checkout)
4898 except util.Abort, inst:
4897 except util.Abort, inst:
4899 ui.warn(_("not updating: %s\n") % str(inst))
4898 ui.warn(_("not updating: %s\n") % str(inst))
4900 if inst.hint:
4899 if inst.hint:
4901 ui.warn(_("(%s)\n") % inst.hint)
4900 ui.warn(_("(%s)\n") % inst.hint)
4902 return 0
4901 return 0
4903 if not ret and not checkout:
4902 if not ret and not checkout:
4904 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4903 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4905 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4904 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4906 return ret
4905 return ret
4907 if modheads > 1:
4906 if modheads > 1:
4908 currentbranchheads = len(repo.branchheads())
4907 currentbranchheads = len(repo.branchheads())
4909 if currentbranchheads == modheads:
4908 if currentbranchheads == modheads:
4910 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4909 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4911 elif currentbranchheads > 1:
4910 elif currentbranchheads > 1:
4912 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4911 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4913 "merge)\n"))
4912 "merge)\n"))
4914 else:
4913 else:
4915 ui.status(_("(run 'hg heads' to see heads)\n"))
4914 ui.status(_("(run 'hg heads' to see heads)\n"))
4916 else:
4915 else:
4917 ui.status(_("(run 'hg update' to get a working copy)\n"))
4916 ui.status(_("(run 'hg update' to get a working copy)\n"))
4918
4917
4919 @command('^pull',
4918 @command('^pull',
4920 [('u', 'update', None,
4919 [('u', 'update', None,
4921 _('update to new branch head if changesets were pulled')),
4920 _('update to new branch head if changesets were pulled')),
4922 ('f', 'force', None, _('run even when remote repository is unrelated')),
4921 ('f', 'force', None, _('run even when remote repository is unrelated')),
4923 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4922 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4924 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4923 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4925 ('b', 'branch', [], _('a specific branch you would like to pull'),
4924 ('b', 'branch', [], _('a specific branch you would like to pull'),
4926 _('BRANCH')),
4925 _('BRANCH')),
4927 ] + remoteopts,
4926 ] + remoteopts,
4928 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4927 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4929 def pull(ui, repo, source="default", **opts):
4928 def pull(ui, repo, source="default", **opts):
4930 """pull changes from the specified source
4929 """pull changes from the specified source
4931
4930
4932 Pull changes from a remote repository to a local one.
4931 Pull changes from a remote repository to a local one.
4933
4932
4934 This finds all changes from the repository at the specified path
4933 This finds all changes from the repository at the specified path
4935 or URL and adds them to a local repository (the current one unless
4934 or URL and adds them to a local repository (the current one unless
4936 -R is specified). By default, this does not update the copy of the
4935 -R is specified). By default, this does not update the copy of the
4937 project in the working directory.
4936 project in the working directory.
4938
4937
4939 Use :hg:`incoming` if you want to see what would have been added
4938 Use :hg:`incoming` if you want to see what would have been added
4940 by a pull at the time you issued this command. If you then decide
4939 by a pull at the time you issued this command. If you then decide
4941 to add those changes to the repository, you should use :hg:`pull
4940 to add those changes to the repository, you should use :hg:`pull
4942 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4941 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4943
4942
4944 If SOURCE is omitted, the 'default' path will be used.
4943 If SOURCE is omitted, the 'default' path will be used.
4945 See :hg:`help urls` for more information.
4944 See :hg:`help urls` for more information.
4946
4945
4947 Returns 0 on success, 1 if an update had unresolved files.
4946 Returns 0 on success, 1 if an update had unresolved files.
4948 """
4947 """
4949 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4948 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4950 other = hg.peer(repo, opts, source)
4949 other = hg.peer(repo, opts, source)
4951 try:
4950 try:
4952 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4951 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4953 revs, checkout = hg.addbranchrevs(repo, other, branches,
4952 revs, checkout = hg.addbranchrevs(repo, other, branches,
4954 opts.get('rev'))
4953 opts.get('rev'))
4955
4954
4956 remotebookmarks = other.listkeys('bookmarks')
4955 remotebookmarks = other.listkeys('bookmarks')
4957
4956
4958 if opts.get('bookmark'):
4957 if opts.get('bookmark'):
4959 if not revs:
4958 if not revs:
4960 revs = []
4959 revs = []
4961 for b in opts['bookmark']:
4960 for b in opts['bookmark']:
4962 if b not in remotebookmarks:
4961 if b not in remotebookmarks:
4963 raise util.Abort(_('remote bookmark %s not found!') % b)
4962 raise util.Abort(_('remote bookmark %s not found!') % b)
4964 revs.append(remotebookmarks[b])
4963 revs.append(remotebookmarks[b])
4965
4964
4966 if revs:
4965 if revs:
4967 try:
4966 try:
4968 revs = [other.lookup(rev) for rev in revs]
4967 revs = [other.lookup(rev) for rev in revs]
4969 except error.CapabilityError:
4968 except error.CapabilityError:
4970 err = _("other repository doesn't support revision lookup, "
4969 err = _("other repository doesn't support revision lookup, "
4971 "so a rev cannot be specified.")
4970 "so a rev cannot be specified.")
4972 raise util.Abort(err)
4971 raise util.Abort(err)
4973
4972
4974 modheads = exchange.pull(repo, other, heads=revs,
4973 modheads = exchange.pull(repo, other, heads=revs,
4975 force=opts.get('force'),
4974 force=opts.get('force'),
4976 bookmarks=opts.get('bookmark', ())).cgresult
4975 bookmarks=opts.get('bookmark', ())).cgresult
4977 if checkout:
4976 if checkout:
4978 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4977 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4979 repo._subtoppath = source
4978 repo._subtoppath = source
4980 try:
4979 try:
4981 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4980 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4982
4981
4983 finally:
4982 finally:
4984 del repo._subtoppath
4983 del repo._subtoppath
4985
4984
4986 finally:
4985 finally:
4987 other.close()
4986 other.close()
4988 return ret
4987 return ret
4989
4988
4990 @command('^push',
4989 @command('^push',
4991 [('f', 'force', None, _('force push')),
4990 [('f', 'force', None, _('force push')),
4992 ('r', 'rev', [],
4991 ('r', 'rev', [],
4993 _('a changeset intended to be included in the destination'),
4992 _('a changeset intended to be included in the destination'),
4994 _('REV')),
4993 _('REV')),
4995 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4994 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4996 ('b', 'branch', [],
4995 ('b', 'branch', [],
4997 _('a specific branch you would like to push'), _('BRANCH')),
4996 _('a specific branch you would like to push'), _('BRANCH')),
4998 ('', 'new-branch', False, _('allow pushing a new branch')),
4997 ('', 'new-branch', False, _('allow pushing a new branch')),
4999 ] + remoteopts,
4998 ] + remoteopts,
5000 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4999 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5001 def push(ui, repo, dest=None, **opts):
5000 def push(ui, repo, dest=None, **opts):
5002 """push changes to the specified destination
5001 """push changes to the specified destination
5003
5002
5004 Push changesets from the local repository to the specified
5003 Push changesets from the local repository to the specified
5005 destination.
5004 destination.
5006
5005
5007 This operation is symmetrical to pull: it is identical to a pull
5006 This operation is symmetrical to pull: it is identical to a pull
5008 in the destination repository from the current one.
5007 in the destination repository from the current one.
5009
5008
5010 By default, push will not allow creation of new heads at the
5009 By default, push will not allow creation of new heads at the
5011 destination, since multiple heads would make it unclear which head
5010 destination, since multiple heads would make it unclear which head
5012 to use. In this situation, it is recommended to pull and merge
5011 to use. In this situation, it is recommended to pull and merge
5013 before pushing.
5012 before pushing.
5014
5013
5015 Use --new-branch if you want to allow push to create a new named
5014 Use --new-branch if you want to allow push to create a new named
5016 branch that is not present at the destination. This allows you to
5015 branch that is not present at the destination. This allows you to
5017 only create a new branch without forcing other changes.
5016 only create a new branch without forcing other changes.
5018
5017
5019 .. note::
5018 .. note::
5020
5019
5021 Extra care should be taken with the -f/--force option,
5020 Extra care should be taken with the -f/--force option,
5022 which will push all new heads on all branches, an action which will
5021 which will push all new heads on all branches, an action which will
5023 almost always cause confusion for collaborators.
5022 almost always cause confusion for collaborators.
5024
5023
5025 If -r/--rev is used, the specified revision and all its ancestors
5024 If -r/--rev is used, the specified revision and all its ancestors
5026 will be pushed to the remote repository.
5025 will be pushed to the remote repository.
5027
5026
5028 If -B/--bookmark is used, the specified bookmarked revision, its
5027 If -B/--bookmark is used, the specified bookmarked revision, its
5029 ancestors, and the bookmark will be pushed to the remote
5028 ancestors, and the bookmark will be pushed to the remote
5030 repository.
5029 repository.
5031
5030
5032 Please see :hg:`help urls` for important details about ``ssh://``
5031 Please see :hg:`help urls` for important details about ``ssh://``
5033 URLs. If DESTINATION is omitted, a default path will be used.
5032 URLs. If DESTINATION is omitted, a default path will be used.
5034
5033
5035 Returns 0 if push was successful, 1 if nothing to push.
5034 Returns 0 if push was successful, 1 if nothing to push.
5036 """
5035 """
5037
5036
5038 if opts.get('bookmark'):
5037 if opts.get('bookmark'):
5039 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5038 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5040 for b in opts['bookmark']:
5039 for b in opts['bookmark']:
5041 # translate -B options to -r so changesets get pushed
5040 # translate -B options to -r so changesets get pushed
5042 if b in repo._bookmarks:
5041 if b in repo._bookmarks:
5043 opts.setdefault('rev', []).append(b)
5042 opts.setdefault('rev', []).append(b)
5044 else:
5043 else:
5045 # if we try to push a deleted bookmark, translate it to null
5044 # if we try to push a deleted bookmark, translate it to null
5046 # this lets simultaneous -r, -b options continue working
5045 # this lets simultaneous -r, -b options continue working
5047 opts.setdefault('rev', []).append("null")
5046 opts.setdefault('rev', []).append("null")
5048
5047
5049 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5048 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5050 dest, branches = hg.parseurl(dest, opts.get('branch'))
5049 dest, branches = hg.parseurl(dest, opts.get('branch'))
5051 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5050 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5052 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5051 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5053 try:
5052 try:
5054 other = hg.peer(repo, opts, dest)
5053 other = hg.peer(repo, opts, dest)
5055 except error.RepoError:
5054 except error.RepoError:
5056 if dest == "default-push":
5055 if dest == "default-push":
5057 raise util.Abort(_("default repository not configured!"),
5056 raise util.Abort(_("default repository not configured!"),
5058 hint=_('see the "path" section in "hg help config"'))
5057 hint=_('see the "path" section in "hg help config"'))
5059 else:
5058 else:
5060 raise
5059 raise
5061
5060
5062 if revs:
5061 if revs:
5063 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5062 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5064
5063
5065 repo._subtoppath = dest
5064 repo._subtoppath = dest
5066 try:
5065 try:
5067 # push subrepos depth-first for coherent ordering
5066 # push subrepos depth-first for coherent ordering
5068 c = repo['']
5067 c = repo['']
5069 subs = c.substate # only repos that are committed
5068 subs = c.substate # only repos that are committed
5070 for s in sorted(subs):
5069 for s in sorted(subs):
5071 result = c.sub(s).push(opts)
5070 result = c.sub(s).push(opts)
5072 if result == 0:
5071 if result == 0:
5073 return not result
5072 return not result
5074 finally:
5073 finally:
5075 del repo._subtoppath
5074 del repo._subtoppath
5076 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5075 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5077 newbranch=opts.get('new_branch'),
5076 newbranch=opts.get('new_branch'),
5078 bookmarks=opts.get('bookmark', ()))
5077 bookmarks=opts.get('bookmark', ()))
5079
5078
5080 result = not pushop.cgresult
5079 result = not pushop.cgresult
5081
5080
5082 if pushop.bkresult is not None:
5081 if pushop.bkresult is not None:
5083 if pushop.bkresult == 2:
5082 if pushop.bkresult == 2:
5084 result = 2
5083 result = 2
5085 elif not result and pushop.bkresult:
5084 elif not result and pushop.bkresult:
5086 result = 2
5085 result = 2
5087
5086
5088 return result
5087 return result
5089
5088
5090 @command('recover', [])
5089 @command('recover', [])
5091 def recover(ui, repo):
5090 def recover(ui, repo):
5092 """roll back an interrupted transaction
5091 """roll back an interrupted transaction
5093
5092
5094 Recover from an interrupted commit or pull.
5093 Recover from an interrupted commit or pull.
5095
5094
5096 This command tries to fix the repository status after an
5095 This command tries to fix the repository status after an
5097 interrupted operation. It should only be necessary when Mercurial
5096 interrupted operation. It should only be necessary when Mercurial
5098 suggests it.
5097 suggests it.
5099
5098
5100 Returns 0 if successful, 1 if nothing to recover or verify fails.
5099 Returns 0 if successful, 1 if nothing to recover or verify fails.
5101 """
5100 """
5102 if repo.recover():
5101 if repo.recover():
5103 return hg.verify(repo)
5102 return hg.verify(repo)
5104 return 1
5103 return 1
5105
5104
5106 @command('^remove|rm',
5105 @command('^remove|rm',
5107 [('A', 'after', None, _('record delete for missing files')),
5106 [('A', 'after', None, _('record delete for missing files')),
5108 ('f', 'force', None,
5107 ('f', 'force', None,
5109 _('remove (and delete) file even if added or modified')),
5108 _('remove (and delete) file even if added or modified')),
5110 ] + walkopts,
5109 ] + walkopts,
5111 _('[OPTION]... FILE...'),
5110 _('[OPTION]... FILE...'),
5112 inferrepo=True)
5111 inferrepo=True)
5113 def remove(ui, repo, *pats, **opts):
5112 def remove(ui, repo, *pats, **opts):
5114 """remove the specified files on the next commit
5113 """remove the specified files on the next commit
5115
5114
5116 Schedule the indicated files for removal from the current branch.
5115 Schedule the indicated files for removal from the current branch.
5117
5116
5118 This command schedules the files to be removed at the next commit.
5117 This command schedules the files to be removed at the next commit.
5119 To undo a remove before that, see :hg:`revert`. To undo added
5118 To undo a remove before that, see :hg:`revert`. To undo added
5120 files, see :hg:`forget`.
5119 files, see :hg:`forget`.
5121
5120
5122 .. container:: verbose
5121 .. container:: verbose
5123
5122
5124 -A/--after can be used to remove only files that have already
5123 -A/--after can be used to remove only files that have already
5125 been deleted, -f/--force can be used to force deletion, and -Af
5124 been deleted, -f/--force can be used to force deletion, and -Af
5126 can be used to remove files from the next revision without
5125 can be used to remove files from the next revision without
5127 deleting them from the working directory.
5126 deleting them from the working directory.
5128
5127
5129 The following table details the behavior of remove for different
5128 The following table details the behavior of remove for different
5130 file states (columns) and option combinations (rows). The file
5129 file states (columns) and option combinations (rows). The file
5131 states are Added [A], Clean [C], Modified [M] and Missing [!]
5130 states are Added [A], Clean [C], Modified [M] and Missing [!]
5132 (as reported by :hg:`status`). The actions are Warn, Remove
5131 (as reported by :hg:`status`). The actions are Warn, Remove
5133 (from branch) and Delete (from disk):
5132 (from branch) and Delete (from disk):
5134
5133
5135 ========= == == == ==
5134 ========= == == == ==
5136 opt/state A C M !
5135 opt/state A C M !
5137 ========= == == == ==
5136 ========= == == == ==
5138 none W RD W R
5137 none W RD W R
5139 -f R RD RD R
5138 -f R RD RD R
5140 -A W W W R
5139 -A W W W R
5141 -Af R R R R
5140 -Af R R R R
5142 ========= == == == ==
5141 ========= == == == ==
5143
5142
5144 Note that remove never deletes files in Added [A] state from the
5143 Note that remove never deletes files in Added [A] state from the
5145 working directory, not even if option --force is specified.
5144 working directory, not even if option --force is specified.
5146
5145
5147 Returns 0 on success, 1 if any warnings encountered.
5146 Returns 0 on success, 1 if any warnings encountered.
5148 """
5147 """
5149
5148
5150 ret = 0
5149 ret = 0
5151 after, force = opts.get('after'), opts.get('force')
5150 after, force = opts.get('after'), opts.get('force')
5152 if not pats and not after:
5151 if not pats and not after:
5153 raise util.Abort(_('no files specified'))
5152 raise util.Abort(_('no files specified'))
5154
5153
5155 m = scmutil.match(repo[None], pats, opts)
5154 m = scmutil.match(repo[None], pats, opts)
5156 s = repo.status(match=m, clean=True)
5155 s = repo.status(match=m, clean=True)
5157 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
5156 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
5158
5157
5159 # warn about failure to delete explicit files/dirs
5158 # warn about failure to delete explicit files/dirs
5160 wctx = repo[None]
5159 wctx = repo[None]
5161 for f in m.files():
5160 for f in m.files():
5162 if f in repo.dirstate or f in wctx.dirs():
5161 if f in repo.dirstate or f in wctx.dirs():
5163 continue
5162 continue
5164 if os.path.exists(m.rel(f)):
5163 if os.path.exists(m.rel(f)):
5165 if os.path.isdir(m.rel(f)):
5164 if os.path.isdir(m.rel(f)):
5166 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
5165 ui.warn(_('not removing %s: no tracked files\n') % m.rel(f))
5167 else:
5166 else:
5168 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
5167 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
5169 # missing files will generate a warning elsewhere
5168 # missing files will generate a warning elsewhere
5170 ret = 1
5169 ret = 1
5171
5170
5172 if force:
5171 if force:
5173 list = modified + deleted + clean + added
5172 list = modified + deleted + clean + added
5174 elif after:
5173 elif after:
5175 list = deleted
5174 list = deleted
5176 for f in modified + added + clean:
5175 for f in modified + added + clean:
5177 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
5176 ui.warn(_('not removing %s: file still exists\n') % m.rel(f))
5178 ret = 1
5177 ret = 1
5179 else:
5178 else:
5180 list = deleted + clean
5179 list = deleted + clean
5181 for f in modified:
5180 for f in modified:
5182 ui.warn(_('not removing %s: file is modified (use -f'
5181 ui.warn(_('not removing %s: file is modified (use -f'
5183 ' to force removal)\n') % m.rel(f))
5182 ' to force removal)\n') % m.rel(f))
5184 ret = 1
5183 ret = 1
5185 for f in added:
5184 for f in added:
5186 ui.warn(_('not removing %s: file has been marked for add'
5185 ui.warn(_('not removing %s: file has been marked for add'
5187 ' (use forget to undo)\n') % m.rel(f))
5186 ' (use forget to undo)\n') % m.rel(f))
5188 ret = 1
5187 ret = 1
5189
5188
5190 for f in sorted(list):
5189 for f in sorted(list):
5191 if ui.verbose or not m.exact(f):
5190 if ui.verbose or not m.exact(f):
5192 ui.status(_('removing %s\n') % m.rel(f))
5191 ui.status(_('removing %s\n') % m.rel(f))
5193
5192
5194 wlock = repo.wlock()
5193 wlock = repo.wlock()
5195 try:
5194 try:
5196 if not after:
5195 if not after:
5197 for f in list:
5196 for f in list:
5198 if f in added:
5197 if f in added:
5199 continue # we never unlink added files on remove
5198 continue # we never unlink added files on remove
5200 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
5199 util.unlinkpath(repo.wjoin(f), ignoremissing=True)
5201 repo[None].forget(list)
5200 repo[None].forget(list)
5202 finally:
5201 finally:
5203 wlock.release()
5202 wlock.release()
5204
5203
5205 return ret
5204 return ret
5206
5205
5207 @command('rename|move|mv',
5206 @command('rename|move|mv',
5208 [('A', 'after', None, _('record a rename that has already occurred')),
5207 [('A', 'after', None, _('record a rename that has already occurred')),
5209 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5208 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5210 ] + walkopts + dryrunopts,
5209 ] + walkopts + dryrunopts,
5211 _('[OPTION]... SOURCE... DEST'))
5210 _('[OPTION]... SOURCE... DEST'))
5212 def rename(ui, repo, *pats, **opts):
5211 def rename(ui, repo, *pats, **opts):
5213 """rename files; equivalent of copy + remove
5212 """rename files; equivalent of copy + remove
5214
5213
5215 Mark dest as copies of sources; mark sources for deletion. If dest
5214 Mark dest as copies of sources; mark sources for deletion. If dest
5216 is a directory, copies are put in that directory. If dest is a
5215 is a directory, copies are put in that directory. If dest is a
5217 file, there can only be one source.
5216 file, there can only be one source.
5218
5217
5219 By default, this command copies the contents of files as they
5218 By default, this command copies the contents of files as they
5220 exist in the working directory. If invoked with -A/--after, the
5219 exist in the working directory. If invoked with -A/--after, the
5221 operation is recorded, but no copying is performed.
5220 operation is recorded, but no copying is performed.
5222
5221
5223 This command takes effect at the next commit. To undo a rename
5222 This command takes effect at the next commit. To undo a rename
5224 before that, see :hg:`revert`.
5223 before that, see :hg:`revert`.
5225
5224
5226 Returns 0 on success, 1 if errors are encountered.
5225 Returns 0 on success, 1 if errors are encountered.
5227 """
5226 """
5228 wlock = repo.wlock(False)
5227 wlock = repo.wlock(False)
5229 try:
5228 try:
5230 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5229 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5231 finally:
5230 finally:
5232 wlock.release()
5231 wlock.release()
5233
5232
5234 @command('resolve',
5233 @command('resolve',
5235 [('a', 'all', None, _('select all unresolved files')),
5234 [('a', 'all', None, _('select all unresolved files')),
5236 ('l', 'list', None, _('list state of files needing merge')),
5235 ('l', 'list', None, _('list state of files needing merge')),
5237 ('m', 'mark', None, _('mark files as resolved')),
5236 ('m', 'mark', None, _('mark files as resolved')),
5238 ('u', 'unmark', None, _('mark files as unresolved')),
5237 ('u', 'unmark', None, _('mark files as unresolved')),
5239 ('n', 'no-status', None, _('hide status prefix'))]
5238 ('n', 'no-status', None, _('hide status prefix'))]
5240 + mergetoolopts + walkopts,
5239 + mergetoolopts + walkopts,
5241 _('[OPTION]... [FILE]...'),
5240 _('[OPTION]... [FILE]...'),
5242 inferrepo=True)
5241 inferrepo=True)
5243 def resolve(ui, repo, *pats, **opts):
5242 def resolve(ui, repo, *pats, **opts):
5244 """redo merges or set/view the merge status of files
5243 """redo merges or set/view the merge status of files
5245
5244
5246 Merges with unresolved conflicts are often the result of
5245 Merges with unresolved conflicts are often the result of
5247 non-interactive merging using the ``internal:merge`` configuration
5246 non-interactive merging using the ``internal:merge`` configuration
5248 setting, or a command-line merge tool like ``diff3``. The resolve
5247 setting, or a command-line merge tool like ``diff3``. The resolve
5249 command is used to manage the files involved in a merge, after
5248 command is used to manage the files involved in a merge, after
5250 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5249 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5251 working directory must have two parents). See :hg:`help
5250 working directory must have two parents). See :hg:`help
5252 merge-tools` for information on configuring merge tools.
5251 merge-tools` for information on configuring merge tools.
5253
5252
5254 The resolve command can be used in the following ways:
5253 The resolve command can be used in the following ways:
5255
5254
5256 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5255 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5257 files, discarding any previous merge attempts. Re-merging is not
5256 files, discarding any previous merge attempts. Re-merging is not
5258 performed for files already marked as resolved. Use ``--all/-a``
5257 performed for files already marked as resolved. Use ``--all/-a``
5259 to select all unresolved files. ``--tool`` can be used to specify
5258 to select all unresolved files. ``--tool`` can be used to specify
5260 the merge tool used for the given files. It overrides the HGMERGE
5259 the merge tool used for the given files. It overrides the HGMERGE
5261 environment variable and your configuration files. Previous file
5260 environment variable and your configuration files. Previous file
5262 contents are saved with a ``.orig`` suffix.
5261 contents are saved with a ``.orig`` suffix.
5263
5262
5264 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5263 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5265 (e.g. after having manually fixed-up the files). The default is
5264 (e.g. after having manually fixed-up the files). The default is
5266 to mark all unresolved files.
5265 to mark all unresolved files.
5267
5266
5268 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5267 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5269 default is to mark all resolved files.
5268 default is to mark all resolved files.
5270
5269
5271 - :hg:`resolve -l`: list files which had or still have conflicts.
5270 - :hg:`resolve -l`: list files which had or still have conflicts.
5272 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5271 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5273
5272
5274 Note that Mercurial will not let you commit files with unresolved
5273 Note that Mercurial will not let you commit files with unresolved
5275 merge conflicts. You must use :hg:`resolve -m ...` before you can
5274 merge conflicts. You must use :hg:`resolve -m ...` before you can
5276 commit after a conflicting merge.
5275 commit after a conflicting merge.
5277
5276
5278 Returns 0 on success, 1 if any files fail a resolve attempt.
5277 Returns 0 on success, 1 if any files fail a resolve attempt.
5279 """
5278 """
5280
5279
5281 all, mark, unmark, show, nostatus = \
5280 all, mark, unmark, show, nostatus = \
5282 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5281 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5283
5282
5284 if (show and (mark or unmark)) or (mark and unmark):
5283 if (show and (mark or unmark)) or (mark and unmark):
5285 raise util.Abort(_("too many options specified"))
5284 raise util.Abort(_("too many options specified"))
5286 if pats and all:
5285 if pats and all:
5287 raise util.Abort(_("can't specify --all and patterns"))
5286 raise util.Abort(_("can't specify --all and patterns"))
5288 if not (all or pats or show or mark or unmark):
5287 if not (all or pats or show or mark or unmark):
5289 raise util.Abort(_('no files or directories specified'),
5288 raise util.Abort(_('no files or directories specified'),
5290 hint=('use --all to remerge all files'))
5289 hint=('use --all to remerge all files'))
5291
5290
5292 wlock = repo.wlock()
5291 wlock = repo.wlock()
5293 try:
5292 try:
5294 ms = mergemod.mergestate(repo)
5293 ms = mergemod.mergestate(repo)
5295
5294
5296 if not ms.active() and not show:
5295 if not ms.active() and not show:
5297 raise util.Abort(
5296 raise util.Abort(
5298 _('resolve command not applicable when not merging'))
5297 _('resolve command not applicable when not merging'))
5299
5298
5300 m = scmutil.match(repo[None], pats, opts)
5299 m = scmutil.match(repo[None], pats, opts)
5301 ret = 0
5300 ret = 0
5302 didwork = False
5301 didwork = False
5303
5302
5304 for f in ms:
5303 for f in ms:
5305 if not m(f):
5304 if not m(f):
5306 continue
5305 continue
5307
5306
5308 didwork = True
5307 didwork = True
5309
5308
5310 if show:
5309 if show:
5311 if nostatus:
5310 if nostatus:
5312 ui.write("%s\n" % f)
5311 ui.write("%s\n" % f)
5313 else:
5312 else:
5314 ui.write("%s %s\n" % (ms[f].upper(), f),
5313 ui.write("%s %s\n" % (ms[f].upper(), f),
5315 label='resolve.' +
5314 label='resolve.' +
5316 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5315 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5317 elif mark:
5316 elif mark:
5318 ms.mark(f, "r")
5317 ms.mark(f, "r")
5319 elif unmark:
5318 elif unmark:
5320 ms.mark(f, "u")
5319 ms.mark(f, "u")
5321 else:
5320 else:
5322 wctx = repo[None]
5321 wctx = repo[None]
5323
5322
5324 # backup pre-resolve (merge uses .orig for its own purposes)
5323 # backup pre-resolve (merge uses .orig for its own purposes)
5325 a = repo.wjoin(f)
5324 a = repo.wjoin(f)
5326 util.copyfile(a, a + ".resolve")
5325 util.copyfile(a, a + ".resolve")
5327
5326
5328 try:
5327 try:
5329 # resolve file
5328 # resolve file
5330 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5329 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5331 'resolve')
5330 'resolve')
5332 if ms.resolve(f, wctx):
5331 if ms.resolve(f, wctx):
5333 ret = 1
5332 ret = 1
5334 finally:
5333 finally:
5335 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5334 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5336 ms.commit()
5335 ms.commit()
5337
5336
5338 # replace filemerge's .orig file with our resolve file
5337 # replace filemerge's .orig file with our resolve file
5339 util.rename(a + ".resolve", a + ".orig")
5338 util.rename(a + ".resolve", a + ".orig")
5340
5339
5341 ms.commit()
5340 ms.commit()
5342
5341
5343 if not didwork and pats:
5342 if not didwork and pats:
5344 ui.warn(_("arguments do not match paths that need resolving\n"))
5343 ui.warn(_("arguments do not match paths that need resolving\n"))
5345
5344
5346 finally:
5345 finally:
5347 wlock.release()
5346 wlock.release()
5348
5347
5349 # Nudge users into finishing an unfinished operation. We don't print
5348 # Nudge users into finishing an unfinished operation. We don't print
5350 # this with the list/show operation because we want list/show to remain
5349 # this with the list/show operation because we want list/show to remain
5351 # machine readable.
5350 # machine readable.
5352 if not list(ms.unresolved()) and not show:
5351 if not list(ms.unresolved()) and not show:
5353 ui.status(_('(no more unresolved files)\n'))
5352 ui.status(_('(no more unresolved files)\n'))
5354
5353
5355 return ret
5354 return ret
5356
5355
5357 @command('revert',
5356 @command('revert',
5358 [('a', 'all', None, _('revert all changes when no arguments given')),
5357 [('a', 'all', None, _('revert all changes when no arguments given')),
5359 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5358 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5360 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5359 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5361 ('C', 'no-backup', None, _('do not save backup copies of files')),
5360 ('C', 'no-backup', None, _('do not save backup copies of files')),
5362 ] + walkopts + dryrunopts,
5361 ] + walkopts + dryrunopts,
5363 _('[OPTION]... [-r REV] [NAME]...'))
5362 _('[OPTION]... [-r REV] [NAME]...'))
5364 def revert(ui, repo, *pats, **opts):
5363 def revert(ui, repo, *pats, **opts):
5365 """restore files to their checkout state
5364 """restore files to their checkout state
5366
5365
5367 .. note::
5366 .. note::
5368
5367
5369 To check out earlier revisions, you should use :hg:`update REV`.
5368 To check out earlier revisions, you should use :hg:`update REV`.
5370 To cancel an uncommitted merge (and lose your changes),
5369 To cancel an uncommitted merge (and lose your changes),
5371 use :hg:`update --clean .`.
5370 use :hg:`update --clean .`.
5372
5371
5373 With no revision specified, revert the specified files or directories
5372 With no revision specified, revert the specified files or directories
5374 to the contents they had in the parent of the working directory.
5373 to the contents they had in the parent of the working directory.
5375 This restores the contents of files to an unmodified
5374 This restores the contents of files to an unmodified
5376 state and unschedules adds, removes, copies, and renames. If the
5375 state and unschedules adds, removes, copies, and renames. If the
5377 working directory has two parents, you must explicitly specify a
5376 working directory has two parents, you must explicitly specify a
5378 revision.
5377 revision.
5379
5378
5380 Using the -r/--rev or -d/--date options, revert the given files or
5379 Using the -r/--rev or -d/--date options, revert the given files or
5381 directories to their states as of a specific revision. Because
5380 directories to their states as of a specific revision. Because
5382 revert does not change the working directory parents, this will
5381 revert does not change the working directory parents, this will
5383 cause these files to appear modified. This can be helpful to "back
5382 cause these files to appear modified. This can be helpful to "back
5384 out" some or all of an earlier change. See :hg:`backout` for a
5383 out" some or all of an earlier change. See :hg:`backout` for a
5385 related method.
5384 related method.
5386
5385
5387 Modified files are saved with a .orig suffix before reverting.
5386 Modified files are saved with a .orig suffix before reverting.
5388 To disable these backups, use --no-backup.
5387 To disable these backups, use --no-backup.
5389
5388
5390 See :hg:`help dates` for a list of formats valid for -d/--date.
5389 See :hg:`help dates` for a list of formats valid for -d/--date.
5391
5390
5392 Returns 0 on success.
5391 Returns 0 on success.
5393 """
5392 """
5394
5393
5395 if opts.get("date"):
5394 if opts.get("date"):
5396 if opts.get("rev"):
5395 if opts.get("rev"):
5397 raise util.Abort(_("you can't specify a revision and a date"))
5396 raise util.Abort(_("you can't specify a revision and a date"))
5398 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5397 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5399
5398
5400 parent, p2 = repo.dirstate.parents()
5399 parent, p2 = repo.dirstate.parents()
5401 if not opts.get('rev') and p2 != nullid:
5400 if not opts.get('rev') and p2 != nullid:
5402 # revert after merge is a trap for new users (issue2915)
5401 # revert after merge is a trap for new users (issue2915)
5403 raise util.Abort(_('uncommitted merge with no revision specified'),
5402 raise util.Abort(_('uncommitted merge with no revision specified'),
5404 hint=_('use "hg update" or see "hg help revert"'))
5403 hint=_('use "hg update" or see "hg help revert"'))
5405
5404
5406 ctx = scmutil.revsingle(repo, opts.get('rev'))
5405 ctx = scmutil.revsingle(repo, opts.get('rev'))
5407
5406
5408 if not pats and not opts.get('all'):
5407 if not pats and not opts.get('all'):
5409 msg = _("no files or directories specified")
5408 msg = _("no files or directories specified")
5410 if p2 != nullid:
5409 if p2 != nullid:
5411 hint = _("uncommitted merge, use --all to discard all changes,"
5410 hint = _("uncommitted merge, use --all to discard all changes,"
5412 " or 'hg update -C .' to abort the merge")
5411 " or 'hg update -C .' to abort the merge")
5413 raise util.Abort(msg, hint=hint)
5412 raise util.Abort(msg, hint=hint)
5414 dirty = util.any(repo.status())
5413 dirty = util.any(repo.status())
5415 node = ctx.node()
5414 node = ctx.node()
5416 if node != parent:
5415 if node != parent:
5417 if dirty:
5416 if dirty:
5418 hint = _("uncommitted changes, use --all to discard all"
5417 hint = _("uncommitted changes, use --all to discard all"
5419 " changes, or 'hg update %s' to update") % ctx.rev()
5418 " changes, or 'hg update %s' to update") % ctx.rev()
5420 else:
5419 else:
5421 hint = _("use --all to revert all files,"
5420 hint = _("use --all to revert all files,"
5422 " or 'hg update %s' to update") % ctx.rev()
5421 " or 'hg update %s' to update") % ctx.rev()
5423 elif dirty:
5422 elif dirty:
5424 hint = _("uncommitted changes, use --all to discard all changes")
5423 hint = _("uncommitted changes, use --all to discard all changes")
5425 else:
5424 else:
5426 hint = _("use --all to revert all files")
5425 hint = _("use --all to revert all files")
5427 raise util.Abort(msg, hint=hint)
5426 raise util.Abort(msg, hint=hint)
5428
5427
5429 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5428 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5430
5429
5431 @command('rollback', dryrunopts +
5430 @command('rollback', dryrunopts +
5432 [('f', 'force', False, _('ignore safety measures'))])
5431 [('f', 'force', False, _('ignore safety measures'))])
5433 def rollback(ui, repo, **opts):
5432 def rollback(ui, repo, **opts):
5434 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5433 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5435
5434
5436 Please use :hg:`commit --amend` instead of rollback to correct
5435 Please use :hg:`commit --amend` instead of rollback to correct
5437 mistakes in the last commit.
5436 mistakes in the last commit.
5438
5437
5439 This command should be used with care. There is only one level of
5438 This command should be used with care. There is only one level of
5440 rollback, and there is no way to undo a rollback. It will also
5439 rollback, and there is no way to undo a rollback. It will also
5441 restore the dirstate at the time of the last transaction, losing
5440 restore the dirstate at the time of the last transaction, losing
5442 any dirstate changes since that time. This command does not alter
5441 any dirstate changes since that time. This command does not alter
5443 the working directory.
5442 the working directory.
5444
5443
5445 Transactions are used to encapsulate the effects of all commands
5444 Transactions are used to encapsulate the effects of all commands
5446 that create new changesets or propagate existing changesets into a
5445 that create new changesets or propagate existing changesets into a
5447 repository.
5446 repository.
5448
5447
5449 .. container:: verbose
5448 .. container:: verbose
5450
5449
5451 For example, the following commands are transactional, and their
5450 For example, the following commands are transactional, and their
5452 effects can be rolled back:
5451 effects can be rolled back:
5453
5452
5454 - commit
5453 - commit
5455 - import
5454 - import
5456 - pull
5455 - pull
5457 - push (with this repository as the destination)
5456 - push (with this repository as the destination)
5458 - unbundle
5457 - unbundle
5459
5458
5460 To avoid permanent data loss, rollback will refuse to rollback a
5459 To avoid permanent data loss, rollback will refuse to rollback a
5461 commit transaction if it isn't checked out. Use --force to
5460 commit transaction if it isn't checked out. Use --force to
5462 override this protection.
5461 override this protection.
5463
5462
5464 This command is not intended for use on public repositories. Once
5463 This command is not intended for use on public repositories. Once
5465 changes are visible for pull by other users, rolling a transaction
5464 changes are visible for pull by other users, rolling a transaction
5466 back locally is ineffective (someone else may already have pulled
5465 back locally is ineffective (someone else may already have pulled
5467 the changes). Furthermore, a race is possible with readers of the
5466 the changes). Furthermore, a race is possible with readers of the
5468 repository; for example an in-progress pull from the repository
5467 repository; for example an in-progress pull from the repository
5469 may fail if a rollback is performed.
5468 may fail if a rollback is performed.
5470
5469
5471 Returns 0 on success, 1 if no rollback data is available.
5470 Returns 0 on success, 1 if no rollback data is available.
5472 """
5471 """
5473 return repo.rollback(dryrun=opts.get('dry_run'),
5472 return repo.rollback(dryrun=opts.get('dry_run'),
5474 force=opts.get('force'))
5473 force=opts.get('force'))
5475
5474
5476 @command('root', [])
5475 @command('root', [])
5477 def root(ui, repo):
5476 def root(ui, repo):
5478 """print the root (top) of the current working directory
5477 """print the root (top) of the current working directory
5479
5478
5480 Print the root directory of the current repository.
5479 Print the root directory of the current repository.
5481
5480
5482 Returns 0 on success.
5481 Returns 0 on success.
5483 """
5482 """
5484 ui.write(repo.root + "\n")
5483 ui.write(repo.root + "\n")
5485
5484
5486 @command('^serve',
5485 @command('^serve',
5487 [('A', 'accesslog', '', _('name of access log file to write to'),
5486 [('A', 'accesslog', '', _('name of access log file to write to'),
5488 _('FILE')),
5487 _('FILE')),
5489 ('d', 'daemon', None, _('run server in background')),
5488 ('d', 'daemon', None, _('run server in background')),
5490 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5489 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5491 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5490 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5492 # use string type, then we can check if something was passed
5491 # use string type, then we can check if something was passed
5493 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5492 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5494 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5493 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5495 _('ADDR')),
5494 _('ADDR')),
5496 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5495 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5497 _('PREFIX')),
5496 _('PREFIX')),
5498 ('n', 'name', '',
5497 ('n', 'name', '',
5499 _('name to show in web pages (default: working directory)'), _('NAME')),
5498 _('name to show in web pages (default: working directory)'), _('NAME')),
5500 ('', 'web-conf', '',
5499 ('', 'web-conf', '',
5501 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5500 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5502 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5501 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5503 _('FILE')),
5502 _('FILE')),
5504 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5503 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5505 ('', 'stdio', None, _('for remote clients')),
5504 ('', 'stdio', None, _('for remote clients')),
5506 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5505 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5507 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5506 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5508 ('', 'style', '', _('template style to use'), _('STYLE')),
5507 ('', 'style', '', _('template style to use'), _('STYLE')),
5509 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5508 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5510 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5509 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5511 _('[OPTION]...'),
5510 _('[OPTION]...'),
5512 optionalrepo=True)
5511 optionalrepo=True)
5513 def serve(ui, repo, **opts):
5512 def serve(ui, repo, **opts):
5514 """start stand-alone webserver
5513 """start stand-alone webserver
5515
5514
5516 Start a local HTTP repository browser and pull server. You can use
5515 Start a local HTTP repository browser and pull server. You can use
5517 this for ad-hoc sharing and browsing of repositories. It is
5516 this for ad-hoc sharing and browsing of repositories. It is
5518 recommended to use a real web server to serve a repository for
5517 recommended to use a real web server to serve a repository for
5519 longer periods of time.
5518 longer periods of time.
5520
5519
5521 Please note that the server does not implement access control.
5520 Please note that the server does not implement access control.
5522 This means that, by default, anybody can read from the server and
5521 This means that, by default, anybody can read from the server and
5523 nobody can write to it by default. Set the ``web.allow_push``
5522 nobody can write to it by default. Set the ``web.allow_push``
5524 option to ``*`` to allow everybody to push to the server. You
5523 option to ``*`` to allow everybody to push to the server. You
5525 should use a real web server if you need to authenticate users.
5524 should use a real web server if you need to authenticate users.
5526
5525
5527 By default, the server logs accesses to stdout and errors to
5526 By default, the server logs accesses to stdout and errors to
5528 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5527 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5529 files.
5528 files.
5530
5529
5531 To have the server choose a free port number to listen on, specify
5530 To have the server choose a free port number to listen on, specify
5532 a port number of 0; in this case, the server will print the port
5531 a port number of 0; in this case, the server will print the port
5533 number it uses.
5532 number it uses.
5534
5533
5535 Returns 0 on success.
5534 Returns 0 on success.
5536 """
5535 """
5537
5536
5538 if opts["stdio"] and opts["cmdserver"]:
5537 if opts["stdio"] and opts["cmdserver"]:
5539 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5538 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5540
5539
5541 if opts["stdio"]:
5540 if opts["stdio"]:
5542 if repo is None:
5541 if repo is None:
5543 raise error.RepoError(_("there is no Mercurial repository here"
5542 raise error.RepoError(_("there is no Mercurial repository here"
5544 " (.hg not found)"))
5543 " (.hg not found)"))
5545 s = sshserver.sshserver(ui, repo)
5544 s = sshserver.sshserver(ui, repo)
5546 s.serve_forever()
5545 s.serve_forever()
5547
5546
5548 if opts["cmdserver"]:
5547 if opts["cmdserver"]:
5549 s = commandserver.server(ui, repo, opts["cmdserver"])
5548 s = commandserver.server(ui, repo, opts["cmdserver"])
5550 return s.serve()
5549 return s.serve()
5551
5550
5552 # this way we can check if something was given in the command-line
5551 # this way we can check if something was given in the command-line
5553 if opts.get('port'):
5552 if opts.get('port'):
5554 opts['port'] = util.getport(opts.get('port'))
5553 opts['port'] = util.getport(opts.get('port'))
5555
5554
5556 baseui = repo and repo.baseui or ui
5555 baseui = repo and repo.baseui or ui
5557 optlist = ("name templates style address port prefix ipv6"
5556 optlist = ("name templates style address port prefix ipv6"
5558 " accesslog errorlog certificate encoding")
5557 " accesslog errorlog certificate encoding")
5559 for o in optlist.split():
5558 for o in optlist.split():
5560 val = opts.get(o, '')
5559 val = opts.get(o, '')
5561 if val in (None, ''): # should check against default options instead
5560 if val in (None, ''): # should check against default options instead
5562 continue
5561 continue
5563 baseui.setconfig("web", o, val, 'serve')
5562 baseui.setconfig("web", o, val, 'serve')
5564 if repo and repo.ui != baseui:
5563 if repo and repo.ui != baseui:
5565 repo.ui.setconfig("web", o, val, 'serve')
5564 repo.ui.setconfig("web", o, val, 'serve')
5566
5565
5567 o = opts.get('web_conf') or opts.get('webdir_conf')
5566 o = opts.get('web_conf') or opts.get('webdir_conf')
5568 if not o:
5567 if not o:
5569 if not repo:
5568 if not repo:
5570 raise error.RepoError(_("there is no Mercurial repository"
5569 raise error.RepoError(_("there is no Mercurial repository"
5571 " here (.hg not found)"))
5570 " here (.hg not found)"))
5572 o = repo
5571 o = repo
5573
5572
5574 app = hgweb.hgweb(o, baseui=baseui)
5573 app = hgweb.hgweb(o, baseui=baseui)
5575 service = httpservice(ui, app, opts)
5574 service = httpservice(ui, app, opts)
5576 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5575 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5577
5576
5578 class httpservice(object):
5577 class httpservice(object):
5579 def __init__(self, ui, app, opts):
5578 def __init__(self, ui, app, opts):
5580 self.ui = ui
5579 self.ui = ui
5581 self.app = app
5580 self.app = app
5582 self.opts = opts
5581 self.opts = opts
5583
5582
5584 def init(self):
5583 def init(self):
5585 util.setsignalhandler()
5584 util.setsignalhandler()
5586 self.httpd = hgweb_server.create_server(self.ui, self.app)
5585 self.httpd = hgweb_server.create_server(self.ui, self.app)
5587
5586
5588 if self.opts['port'] and not self.ui.verbose:
5587 if self.opts['port'] and not self.ui.verbose:
5589 return
5588 return
5590
5589
5591 if self.httpd.prefix:
5590 if self.httpd.prefix:
5592 prefix = self.httpd.prefix.strip('/') + '/'
5591 prefix = self.httpd.prefix.strip('/') + '/'
5593 else:
5592 else:
5594 prefix = ''
5593 prefix = ''
5595
5594
5596 port = ':%d' % self.httpd.port
5595 port = ':%d' % self.httpd.port
5597 if port == ':80':
5596 if port == ':80':
5598 port = ''
5597 port = ''
5599
5598
5600 bindaddr = self.httpd.addr
5599 bindaddr = self.httpd.addr
5601 if bindaddr == '0.0.0.0':
5600 if bindaddr == '0.0.0.0':
5602 bindaddr = '*'
5601 bindaddr = '*'
5603 elif ':' in bindaddr: # IPv6
5602 elif ':' in bindaddr: # IPv6
5604 bindaddr = '[%s]' % bindaddr
5603 bindaddr = '[%s]' % bindaddr
5605
5604
5606 fqaddr = self.httpd.fqaddr
5605 fqaddr = self.httpd.fqaddr
5607 if ':' in fqaddr:
5606 if ':' in fqaddr:
5608 fqaddr = '[%s]' % fqaddr
5607 fqaddr = '[%s]' % fqaddr
5609 if self.opts['port']:
5608 if self.opts['port']:
5610 write = self.ui.status
5609 write = self.ui.status
5611 else:
5610 else:
5612 write = self.ui.write
5611 write = self.ui.write
5613 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5612 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5614 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5613 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5615 self.ui.flush() # avoid buffering of status message
5614 self.ui.flush() # avoid buffering of status message
5616
5615
5617 def run(self):
5616 def run(self):
5618 self.httpd.serve_forever()
5617 self.httpd.serve_forever()
5619
5618
5620
5619
5621 @command('^status|st',
5620 @command('^status|st',
5622 [('A', 'all', None, _('show status of all files')),
5621 [('A', 'all', None, _('show status of all files')),
5623 ('m', 'modified', None, _('show only modified files')),
5622 ('m', 'modified', None, _('show only modified files')),
5624 ('a', 'added', None, _('show only added files')),
5623 ('a', 'added', None, _('show only added files')),
5625 ('r', 'removed', None, _('show only removed files')),
5624 ('r', 'removed', None, _('show only removed files')),
5626 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5625 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5627 ('c', 'clean', None, _('show only files without changes')),
5626 ('c', 'clean', None, _('show only files without changes')),
5628 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5627 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5629 ('i', 'ignored', None, _('show only ignored files')),
5628 ('i', 'ignored', None, _('show only ignored files')),
5630 ('n', 'no-status', None, _('hide status prefix')),
5629 ('n', 'no-status', None, _('hide status prefix')),
5631 ('C', 'copies', None, _('show source of copied files')),
5630 ('C', 'copies', None, _('show source of copied files')),
5632 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5631 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5633 ('', 'rev', [], _('show difference from revision'), _('REV')),
5632 ('', 'rev', [], _('show difference from revision'), _('REV')),
5634 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5633 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5635 ] + walkopts + subrepoopts + formatteropts,
5634 ] + walkopts + subrepoopts + formatteropts,
5636 _('[OPTION]... [FILE]...'),
5635 _('[OPTION]... [FILE]...'),
5637 inferrepo=True)
5636 inferrepo=True)
5638 def status(ui, repo, *pats, **opts):
5637 def status(ui, repo, *pats, **opts):
5639 """show changed files in the working directory
5638 """show changed files in the working directory
5640
5639
5641 Show status of files in the repository. If names are given, only
5640 Show status of files in the repository. If names are given, only
5642 files that match are shown. Files that are clean or ignored or
5641 files that match are shown. Files that are clean or ignored or
5643 the source of a copy/move operation, are not listed unless
5642 the source of a copy/move operation, are not listed unless
5644 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5643 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5645 Unless options described with "show only ..." are given, the
5644 Unless options described with "show only ..." are given, the
5646 options -mardu are used.
5645 options -mardu are used.
5647
5646
5648 Option -q/--quiet hides untracked (unknown and ignored) files
5647 Option -q/--quiet hides untracked (unknown and ignored) files
5649 unless explicitly requested with -u/--unknown or -i/--ignored.
5648 unless explicitly requested with -u/--unknown or -i/--ignored.
5650
5649
5651 .. note::
5650 .. note::
5652
5651
5653 status may appear to disagree with diff if permissions have
5652 status may appear to disagree with diff if permissions have
5654 changed or a merge has occurred. The standard diff format does
5653 changed or a merge has occurred. The standard diff format does
5655 not report permission changes and diff only reports changes
5654 not report permission changes and diff only reports changes
5656 relative to one merge parent.
5655 relative to one merge parent.
5657
5656
5658 If one revision is given, it is used as the base revision.
5657 If one revision is given, it is used as the base revision.
5659 If two revisions are given, the differences between them are
5658 If two revisions are given, the differences between them are
5660 shown. The --change option can also be used as a shortcut to list
5659 shown. The --change option can also be used as a shortcut to list
5661 the changed files of a revision from its first parent.
5660 the changed files of a revision from its first parent.
5662
5661
5663 The codes used to show the status of files are::
5662 The codes used to show the status of files are::
5664
5663
5665 M = modified
5664 M = modified
5666 A = added
5665 A = added
5667 R = removed
5666 R = removed
5668 C = clean
5667 C = clean
5669 ! = missing (deleted by non-hg command, but still tracked)
5668 ! = missing (deleted by non-hg command, but still tracked)
5670 ? = not tracked
5669 ? = not tracked
5671 I = ignored
5670 I = ignored
5672 = origin of the previous file (with --copies)
5671 = origin of the previous file (with --copies)
5673
5672
5674 .. container:: verbose
5673 .. container:: verbose
5675
5674
5676 Examples:
5675 Examples:
5677
5676
5678 - show changes in the working directory relative to a
5677 - show changes in the working directory relative to a
5679 changeset::
5678 changeset::
5680
5679
5681 hg status --rev 9353
5680 hg status --rev 9353
5682
5681
5683 - show all changes including copies in an existing changeset::
5682 - show all changes including copies in an existing changeset::
5684
5683
5685 hg status --copies --change 9353
5684 hg status --copies --change 9353
5686
5685
5687 - get a NUL separated list of added files, suitable for xargs::
5686 - get a NUL separated list of added files, suitable for xargs::
5688
5687
5689 hg status -an0
5688 hg status -an0
5690
5689
5691 Returns 0 on success.
5690 Returns 0 on success.
5692 """
5691 """
5693
5692
5694 revs = opts.get('rev')
5693 revs = opts.get('rev')
5695 change = opts.get('change')
5694 change = opts.get('change')
5696
5695
5697 if revs and change:
5696 if revs and change:
5698 msg = _('cannot specify --rev and --change at the same time')
5697 msg = _('cannot specify --rev and --change at the same time')
5699 raise util.Abort(msg)
5698 raise util.Abort(msg)
5700 elif change:
5699 elif change:
5701 node2 = scmutil.revsingle(repo, change, None).node()
5700 node2 = scmutil.revsingle(repo, change, None).node()
5702 node1 = repo[node2].p1().node()
5701 node1 = repo[node2].p1().node()
5703 else:
5702 else:
5704 node1, node2 = scmutil.revpair(repo, revs)
5703 node1, node2 = scmutil.revpair(repo, revs)
5705
5704
5706 cwd = (pats and repo.getcwd()) or ''
5705 cwd = (pats and repo.getcwd()) or ''
5707 end = opts.get('print0') and '\0' or '\n'
5706 end = opts.get('print0') and '\0' or '\n'
5708 copy = {}
5707 copy = {}
5709 states = 'modified added removed deleted unknown ignored clean'.split()
5708 states = 'modified added removed deleted unknown ignored clean'.split()
5710 show = [k for k in states if opts.get(k)]
5709 show = [k for k in states if opts.get(k)]
5711 if opts.get('all'):
5710 if opts.get('all'):
5712 show += ui.quiet and (states[:4] + ['clean']) or states
5711 show += ui.quiet and (states[:4] + ['clean']) or states
5713 if not show:
5712 if not show:
5714 show = ui.quiet and states[:4] or states[:5]
5713 show = ui.quiet and states[:4] or states[:5]
5715
5714
5716 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5715 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5717 'ignored' in show, 'clean' in show, 'unknown' in show,
5716 'ignored' in show, 'clean' in show, 'unknown' in show,
5718 opts.get('subrepos'))
5717 opts.get('subrepos'))
5719 changestates = zip(states, 'MAR!?IC', stat)
5718 changestates = zip(states, 'MAR!?IC', stat)
5720
5719
5721 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5720 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5722 copy = copies.pathcopies(repo[node1], repo[node2])
5721 copy = copies.pathcopies(repo[node1], repo[node2])
5723
5722
5724 fm = ui.formatter('status', opts)
5723 fm = ui.formatter('status', opts)
5725 fmt = '%s' + end
5724 fmt = '%s' + end
5726 showchar = not opts.get('no_status')
5725 showchar = not opts.get('no_status')
5727
5726
5728 for state, char, files in changestates:
5727 for state, char, files in changestates:
5729 if state in show:
5728 if state in show:
5730 label = 'status.' + state
5729 label = 'status.' + state
5731 for f in files:
5730 for f in files:
5732 fm.startitem()
5731 fm.startitem()
5733 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5732 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5734 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5733 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5735 if f in copy:
5734 if f in copy:
5736 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5735 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5737 label='status.copied')
5736 label='status.copied')
5738 fm.end()
5737 fm.end()
5739
5738
5740 @command('^summary|sum',
5739 @command('^summary|sum',
5741 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5740 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5742 def summary(ui, repo, **opts):
5741 def summary(ui, repo, **opts):
5743 """summarize working directory state
5742 """summarize working directory state
5744
5743
5745 This generates a brief summary of the working directory state,
5744 This generates a brief summary of the working directory state,
5746 including parents, branch, commit status, and available updates.
5745 including parents, branch, commit status, and available updates.
5747
5746
5748 With the --remote option, this will check the default paths for
5747 With the --remote option, this will check the default paths for
5749 incoming and outgoing changes. This can be time-consuming.
5748 incoming and outgoing changes. This can be time-consuming.
5750
5749
5751 Returns 0 on success.
5750 Returns 0 on success.
5752 """
5751 """
5753
5752
5754 ctx = repo[None]
5753 ctx = repo[None]
5755 parents = ctx.parents()
5754 parents = ctx.parents()
5756 pnode = parents[0].node()
5755 pnode = parents[0].node()
5757 marks = []
5756 marks = []
5758
5757
5759 for p in parents:
5758 for p in parents:
5760 # label with log.changeset (instead of log.parent) since this
5759 # label with log.changeset (instead of log.parent) since this
5761 # shows a working directory parent *changeset*:
5760 # shows a working directory parent *changeset*:
5762 # i18n: column positioning for "hg summary"
5761 # i18n: column positioning for "hg summary"
5763 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5762 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5764 label='log.changeset changeset.%s' % p.phasestr())
5763 label='log.changeset changeset.%s' % p.phasestr())
5765 ui.write(' '.join(p.tags()), label='log.tag')
5764 ui.write(' '.join(p.tags()), label='log.tag')
5766 if p.bookmarks():
5765 if p.bookmarks():
5767 marks.extend(p.bookmarks())
5766 marks.extend(p.bookmarks())
5768 if p.rev() == -1:
5767 if p.rev() == -1:
5769 if not len(repo):
5768 if not len(repo):
5770 ui.write(_(' (empty repository)'))
5769 ui.write(_(' (empty repository)'))
5771 else:
5770 else:
5772 ui.write(_(' (no revision checked out)'))
5771 ui.write(_(' (no revision checked out)'))
5773 ui.write('\n')
5772 ui.write('\n')
5774 if p.description():
5773 if p.description():
5775 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5774 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5776 label='log.summary')
5775 label='log.summary')
5777
5776
5778 branch = ctx.branch()
5777 branch = ctx.branch()
5779 bheads = repo.branchheads(branch)
5778 bheads = repo.branchheads(branch)
5780 # i18n: column positioning for "hg summary"
5779 # i18n: column positioning for "hg summary"
5781 m = _('branch: %s\n') % branch
5780 m = _('branch: %s\n') % branch
5782 if branch != 'default':
5781 if branch != 'default':
5783 ui.write(m, label='log.branch')
5782 ui.write(m, label='log.branch')
5784 else:
5783 else:
5785 ui.status(m, label='log.branch')
5784 ui.status(m, label='log.branch')
5786
5785
5787 if marks:
5786 if marks:
5788 current = repo._bookmarkcurrent
5787 current = repo._bookmarkcurrent
5789 # i18n: column positioning for "hg summary"
5788 # i18n: column positioning for "hg summary"
5790 ui.write(_('bookmarks:'), label='log.bookmark')
5789 ui.write(_('bookmarks:'), label='log.bookmark')
5791 if current is not None:
5790 if current is not None:
5792 if current in marks:
5791 if current in marks:
5793 ui.write(' *' + current, label='bookmarks.current')
5792 ui.write(' *' + current, label='bookmarks.current')
5794 marks.remove(current)
5793 marks.remove(current)
5795 else:
5794 else:
5796 ui.write(' [%s]' % current, label='bookmarks.current')
5795 ui.write(' [%s]' % current, label='bookmarks.current')
5797 for m in marks:
5796 for m in marks:
5798 ui.write(' ' + m, label='log.bookmark')
5797 ui.write(' ' + m, label='log.bookmark')
5799 ui.write('\n', label='log.bookmark')
5798 ui.write('\n', label='log.bookmark')
5800
5799
5801 st = list(repo.status(unknown=True))[:5]
5800 st = list(repo.status(unknown=True))[:5]
5802
5801
5803 c = repo.dirstate.copies()
5802 c = repo.dirstate.copies()
5804 copied, renamed = [], []
5803 copied, renamed = [], []
5805 for d, s in c.iteritems():
5804 for d, s in c.iteritems():
5806 if s in st[2]:
5805 if s in st[2]:
5807 st[2].remove(s)
5806 st[2].remove(s)
5808 renamed.append(d)
5807 renamed.append(d)
5809 else:
5808 else:
5810 copied.append(d)
5809 copied.append(d)
5811 if d in st[1]:
5810 if d in st[1]:
5812 st[1].remove(d)
5811 st[1].remove(d)
5813 st.insert(3, renamed)
5812 st.insert(3, renamed)
5814 st.insert(4, copied)
5813 st.insert(4, copied)
5815
5814
5816 ms = mergemod.mergestate(repo)
5815 ms = mergemod.mergestate(repo)
5817 st.append([f for f in ms if ms[f] == 'u'])
5816 st.append([f for f in ms if ms[f] == 'u'])
5818
5817
5819 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5818 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5820 st.append(subs)
5819 st.append(subs)
5821
5820
5822 labels = [ui.label(_('%d modified'), 'status.modified'),
5821 labels = [ui.label(_('%d modified'), 'status.modified'),
5823 ui.label(_('%d added'), 'status.added'),
5822 ui.label(_('%d added'), 'status.added'),
5824 ui.label(_('%d removed'), 'status.removed'),
5823 ui.label(_('%d removed'), 'status.removed'),
5825 ui.label(_('%d renamed'), 'status.copied'),
5824 ui.label(_('%d renamed'), 'status.copied'),
5826 ui.label(_('%d copied'), 'status.copied'),
5825 ui.label(_('%d copied'), 'status.copied'),
5827 ui.label(_('%d deleted'), 'status.deleted'),
5826 ui.label(_('%d deleted'), 'status.deleted'),
5828 ui.label(_('%d unknown'), 'status.unknown'),
5827 ui.label(_('%d unknown'), 'status.unknown'),
5829 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5828 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5830 ui.label(_('%d subrepos'), 'status.modified')]
5829 ui.label(_('%d subrepos'), 'status.modified')]
5831 t = []
5830 t = []
5832 for s, l in zip(st, labels):
5831 for s, l in zip(st, labels):
5833 if s:
5832 if s:
5834 t.append(l % len(s))
5833 t.append(l % len(s))
5835
5834
5836 t = ', '.join(t)
5835 t = ', '.join(t)
5837 cleanworkdir = False
5836 cleanworkdir = False
5838
5837
5839 if repo.vfs.exists('updatestate'):
5838 if repo.vfs.exists('updatestate'):
5840 t += _(' (interrupted update)')
5839 t += _(' (interrupted update)')
5841 elif len(parents) > 1:
5840 elif len(parents) > 1:
5842 t += _(' (merge)')
5841 t += _(' (merge)')
5843 elif branch != parents[0].branch():
5842 elif branch != parents[0].branch():
5844 t += _(' (new branch)')
5843 t += _(' (new branch)')
5845 elif (parents[0].closesbranch() and
5844 elif (parents[0].closesbranch() and
5846 pnode in repo.branchheads(branch, closed=True)):
5845 pnode in repo.branchheads(branch, closed=True)):
5847 t += _(' (head closed)')
5846 t += _(' (head closed)')
5848 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[8]):
5847 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[8]):
5849 t += _(' (clean)')
5848 t += _(' (clean)')
5850 cleanworkdir = True
5849 cleanworkdir = True
5851 elif pnode not in bheads:
5850 elif pnode not in bheads:
5852 t += _(' (new branch head)')
5851 t += _(' (new branch head)')
5853
5852
5854 if cleanworkdir:
5853 if cleanworkdir:
5855 # i18n: column positioning for "hg summary"
5854 # i18n: column positioning for "hg summary"
5856 ui.status(_('commit: %s\n') % t.strip())
5855 ui.status(_('commit: %s\n') % t.strip())
5857 else:
5856 else:
5858 # i18n: column positioning for "hg summary"
5857 # i18n: column positioning for "hg summary"
5859 ui.write(_('commit: %s\n') % t.strip())
5858 ui.write(_('commit: %s\n') % t.strip())
5860
5859
5861 # all ancestors of branch heads - all ancestors of parent = new csets
5860 # all ancestors of branch heads - all ancestors of parent = new csets
5862 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5861 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5863 bheads))
5862 bheads))
5864
5863
5865 if new == 0:
5864 if new == 0:
5866 # i18n: column positioning for "hg summary"
5865 # i18n: column positioning for "hg summary"
5867 ui.status(_('update: (current)\n'))
5866 ui.status(_('update: (current)\n'))
5868 elif pnode not in bheads:
5867 elif pnode not in bheads:
5869 # i18n: column positioning for "hg summary"
5868 # i18n: column positioning for "hg summary"
5870 ui.write(_('update: %d new changesets (update)\n') % new)
5869 ui.write(_('update: %d new changesets (update)\n') % new)
5871 else:
5870 else:
5872 # i18n: column positioning for "hg summary"
5871 # i18n: column positioning for "hg summary"
5873 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5872 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5874 (new, len(bheads)))
5873 (new, len(bheads)))
5875
5874
5876 cmdutil.summaryhooks(ui, repo)
5875 cmdutil.summaryhooks(ui, repo)
5877
5876
5878 if opts.get('remote'):
5877 if opts.get('remote'):
5879 needsincoming, needsoutgoing = True, True
5878 needsincoming, needsoutgoing = True, True
5880 else:
5879 else:
5881 needsincoming, needsoutgoing = False, False
5880 needsincoming, needsoutgoing = False, False
5882 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5881 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5883 if i:
5882 if i:
5884 needsincoming = True
5883 needsincoming = True
5885 if o:
5884 if o:
5886 needsoutgoing = True
5885 needsoutgoing = True
5887 if not needsincoming and not needsoutgoing:
5886 if not needsincoming and not needsoutgoing:
5888 return
5887 return
5889
5888
5890 def getincoming():
5889 def getincoming():
5891 source, branches = hg.parseurl(ui.expandpath('default'))
5890 source, branches = hg.parseurl(ui.expandpath('default'))
5892 sbranch = branches[0]
5891 sbranch = branches[0]
5893 try:
5892 try:
5894 other = hg.peer(repo, {}, source)
5893 other = hg.peer(repo, {}, source)
5895 except error.RepoError:
5894 except error.RepoError:
5896 if opts.get('remote'):
5895 if opts.get('remote'):
5897 raise
5896 raise
5898 return source, sbranch, None, None, None
5897 return source, sbranch, None, None, None
5899 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5898 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5900 if revs:
5899 if revs:
5901 revs = [other.lookup(rev) for rev in revs]
5900 revs = [other.lookup(rev) for rev in revs]
5902 ui.debug('comparing with %s\n' % util.hidepassword(source))
5901 ui.debug('comparing with %s\n' % util.hidepassword(source))
5903 repo.ui.pushbuffer()
5902 repo.ui.pushbuffer()
5904 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5903 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5905 repo.ui.popbuffer()
5904 repo.ui.popbuffer()
5906 return source, sbranch, other, commoninc, commoninc[1]
5905 return source, sbranch, other, commoninc, commoninc[1]
5907
5906
5908 if needsincoming:
5907 if needsincoming:
5909 source, sbranch, sother, commoninc, incoming = getincoming()
5908 source, sbranch, sother, commoninc, incoming = getincoming()
5910 else:
5909 else:
5911 source = sbranch = sother = commoninc = incoming = None
5910 source = sbranch = sother = commoninc = incoming = None
5912
5911
5913 def getoutgoing():
5912 def getoutgoing():
5914 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5913 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5915 dbranch = branches[0]
5914 dbranch = branches[0]
5916 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5915 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5917 if source != dest:
5916 if source != dest:
5918 try:
5917 try:
5919 dother = hg.peer(repo, {}, dest)
5918 dother = hg.peer(repo, {}, dest)
5920 except error.RepoError:
5919 except error.RepoError:
5921 if opts.get('remote'):
5920 if opts.get('remote'):
5922 raise
5921 raise
5923 return dest, dbranch, None, None
5922 return dest, dbranch, None, None
5924 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5923 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5925 elif sother is None:
5924 elif sother is None:
5926 # there is no explicit destination peer, but source one is invalid
5925 # there is no explicit destination peer, but source one is invalid
5927 return dest, dbranch, None, None
5926 return dest, dbranch, None, None
5928 else:
5927 else:
5929 dother = sother
5928 dother = sother
5930 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5929 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5931 common = None
5930 common = None
5932 else:
5931 else:
5933 common = commoninc
5932 common = commoninc
5934 if revs:
5933 if revs:
5935 revs = [repo.lookup(rev) for rev in revs]
5934 revs = [repo.lookup(rev) for rev in revs]
5936 repo.ui.pushbuffer()
5935 repo.ui.pushbuffer()
5937 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5936 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5938 commoninc=common)
5937 commoninc=common)
5939 repo.ui.popbuffer()
5938 repo.ui.popbuffer()
5940 return dest, dbranch, dother, outgoing
5939 return dest, dbranch, dother, outgoing
5941
5940
5942 if needsoutgoing:
5941 if needsoutgoing:
5943 dest, dbranch, dother, outgoing = getoutgoing()
5942 dest, dbranch, dother, outgoing = getoutgoing()
5944 else:
5943 else:
5945 dest = dbranch = dother = outgoing = None
5944 dest = dbranch = dother = outgoing = None
5946
5945
5947 if opts.get('remote'):
5946 if opts.get('remote'):
5948 t = []
5947 t = []
5949 if incoming:
5948 if incoming:
5950 t.append(_('1 or more incoming'))
5949 t.append(_('1 or more incoming'))
5951 o = outgoing.missing
5950 o = outgoing.missing
5952 if o:
5951 if o:
5953 t.append(_('%d outgoing') % len(o))
5952 t.append(_('%d outgoing') % len(o))
5954 other = dother or sother
5953 other = dother or sother
5955 if 'bookmarks' in other.listkeys('namespaces'):
5954 if 'bookmarks' in other.listkeys('namespaces'):
5956 lmarks = repo.listkeys('bookmarks')
5955 lmarks = repo.listkeys('bookmarks')
5957 rmarks = other.listkeys('bookmarks')
5956 rmarks = other.listkeys('bookmarks')
5958 diff = set(rmarks) - set(lmarks)
5957 diff = set(rmarks) - set(lmarks)
5959 if len(diff) > 0:
5958 if len(diff) > 0:
5960 t.append(_('%d incoming bookmarks') % len(diff))
5959 t.append(_('%d incoming bookmarks') % len(diff))
5961 diff = set(lmarks) - set(rmarks)
5960 diff = set(lmarks) - set(rmarks)
5962 if len(diff) > 0:
5961 if len(diff) > 0:
5963 t.append(_('%d outgoing bookmarks') % len(diff))
5962 t.append(_('%d outgoing bookmarks') % len(diff))
5964
5963
5965 if t:
5964 if t:
5966 # i18n: column positioning for "hg summary"
5965 # i18n: column positioning for "hg summary"
5967 ui.write(_('remote: %s\n') % (', '.join(t)))
5966 ui.write(_('remote: %s\n') % (', '.join(t)))
5968 else:
5967 else:
5969 # i18n: column positioning for "hg summary"
5968 # i18n: column positioning for "hg summary"
5970 ui.status(_('remote: (synced)\n'))
5969 ui.status(_('remote: (synced)\n'))
5971
5970
5972 cmdutil.summaryremotehooks(ui, repo, opts,
5971 cmdutil.summaryremotehooks(ui, repo, opts,
5973 ((source, sbranch, sother, commoninc),
5972 ((source, sbranch, sother, commoninc),
5974 (dest, dbranch, dother, outgoing)))
5973 (dest, dbranch, dother, outgoing)))
5975
5974
5976 @command('tag',
5975 @command('tag',
5977 [('f', 'force', None, _('force tag')),
5976 [('f', 'force', None, _('force tag')),
5978 ('l', 'local', None, _('make the tag local')),
5977 ('l', 'local', None, _('make the tag local')),
5979 ('r', 'rev', '', _('revision to tag'), _('REV')),
5978 ('r', 'rev', '', _('revision to tag'), _('REV')),
5980 ('', 'remove', None, _('remove a tag')),
5979 ('', 'remove', None, _('remove a tag')),
5981 # -l/--local is already there, commitopts cannot be used
5980 # -l/--local is already there, commitopts cannot be used
5982 ('e', 'edit', None, _('invoke editor on commit messages')),
5981 ('e', 'edit', None, _('invoke editor on commit messages')),
5983 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5982 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5984 ] + commitopts2,
5983 ] + commitopts2,
5985 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5984 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5986 def tag(ui, repo, name1, *names, **opts):
5985 def tag(ui, repo, name1, *names, **opts):
5987 """add one or more tags for the current or given revision
5986 """add one or more tags for the current or given revision
5988
5987
5989 Name a particular revision using <name>.
5988 Name a particular revision using <name>.
5990
5989
5991 Tags are used to name particular revisions of the repository and are
5990 Tags are used to name particular revisions of the repository and are
5992 very useful to compare different revisions, to go back to significant
5991 very useful to compare different revisions, to go back to significant
5993 earlier versions or to mark branch points as releases, etc. Changing
5992 earlier versions or to mark branch points as releases, etc. Changing
5994 an existing tag is normally disallowed; use -f/--force to override.
5993 an existing tag is normally disallowed; use -f/--force to override.
5995
5994
5996 If no revision is given, the parent of the working directory is
5995 If no revision is given, the parent of the working directory is
5997 used.
5996 used.
5998
5997
5999 To facilitate version control, distribution, and merging of tags,
5998 To facilitate version control, distribution, and merging of tags,
6000 they are stored as a file named ".hgtags" which is managed similarly
5999 they are stored as a file named ".hgtags" which is managed similarly
6001 to other project files and can be hand-edited if necessary. This
6000 to other project files and can be hand-edited if necessary. This
6002 also means that tagging creates a new commit. The file
6001 also means that tagging creates a new commit. The file
6003 ".hg/localtags" is used for local tags (not shared among
6002 ".hg/localtags" is used for local tags (not shared among
6004 repositories).
6003 repositories).
6005
6004
6006 Tag commits are usually made at the head of a branch. If the parent
6005 Tag commits are usually made at the head of a branch. If the parent
6007 of the working directory is not a branch head, :hg:`tag` aborts; use
6006 of the working directory is not a branch head, :hg:`tag` aborts; use
6008 -f/--force to force the tag commit to be based on a non-head
6007 -f/--force to force the tag commit to be based on a non-head
6009 changeset.
6008 changeset.
6010
6009
6011 See :hg:`help dates` for a list of formats valid for -d/--date.
6010 See :hg:`help dates` for a list of formats valid for -d/--date.
6012
6011
6013 Since tag names have priority over branch names during revision
6012 Since tag names have priority over branch names during revision
6014 lookup, using an existing branch name as a tag name is discouraged.
6013 lookup, using an existing branch name as a tag name is discouraged.
6015
6014
6016 Returns 0 on success.
6015 Returns 0 on success.
6017 """
6016 """
6018 wlock = lock = None
6017 wlock = lock = None
6019 try:
6018 try:
6020 wlock = repo.wlock()
6019 wlock = repo.wlock()
6021 lock = repo.lock()
6020 lock = repo.lock()
6022 rev_ = "."
6021 rev_ = "."
6023 names = [t.strip() for t in (name1,) + names]
6022 names = [t.strip() for t in (name1,) + names]
6024 if len(names) != len(set(names)):
6023 if len(names) != len(set(names)):
6025 raise util.Abort(_('tag names must be unique'))
6024 raise util.Abort(_('tag names must be unique'))
6026 for n in names:
6025 for n in names:
6027 scmutil.checknewlabel(repo, n, 'tag')
6026 scmutil.checknewlabel(repo, n, 'tag')
6028 if not n:
6027 if not n:
6029 raise util.Abort(_('tag names cannot consist entirely of '
6028 raise util.Abort(_('tag names cannot consist entirely of '
6030 'whitespace'))
6029 'whitespace'))
6031 if opts.get('rev') and opts.get('remove'):
6030 if opts.get('rev') and opts.get('remove'):
6032 raise util.Abort(_("--rev and --remove are incompatible"))
6031 raise util.Abort(_("--rev and --remove are incompatible"))
6033 if opts.get('rev'):
6032 if opts.get('rev'):
6034 rev_ = opts['rev']
6033 rev_ = opts['rev']
6035 message = opts.get('message')
6034 message = opts.get('message')
6036 if opts.get('remove'):
6035 if opts.get('remove'):
6037 expectedtype = opts.get('local') and 'local' or 'global'
6036 expectedtype = opts.get('local') and 'local' or 'global'
6038 for n in names:
6037 for n in names:
6039 if not repo.tagtype(n):
6038 if not repo.tagtype(n):
6040 raise util.Abort(_("tag '%s' does not exist") % n)
6039 raise util.Abort(_("tag '%s' does not exist") % n)
6041 if repo.tagtype(n) != expectedtype:
6040 if repo.tagtype(n) != expectedtype:
6042 if expectedtype == 'global':
6041 if expectedtype == 'global':
6043 raise util.Abort(_("tag '%s' is not a global tag") % n)
6042 raise util.Abort(_("tag '%s' is not a global tag") % n)
6044 else:
6043 else:
6045 raise util.Abort(_("tag '%s' is not a local tag") % n)
6044 raise util.Abort(_("tag '%s' is not a local tag") % n)
6046 rev_ = nullid
6045 rev_ = nullid
6047 if not message:
6046 if not message:
6048 # we don't translate commit messages
6047 # we don't translate commit messages
6049 message = 'Removed tag %s' % ', '.join(names)
6048 message = 'Removed tag %s' % ', '.join(names)
6050 elif not opts.get('force'):
6049 elif not opts.get('force'):
6051 for n in names:
6050 for n in names:
6052 if n in repo.tags():
6051 if n in repo.tags():
6053 raise util.Abort(_("tag '%s' already exists "
6052 raise util.Abort(_("tag '%s' already exists "
6054 "(use -f to force)") % n)
6053 "(use -f to force)") % n)
6055 if not opts.get('local'):
6054 if not opts.get('local'):
6056 p1, p2 = repo.dirstate.parents()
6055 p1, p2 = repo.dirstate.parents()
6057 if p2 != nullid:
6056 if p2 != nullid:
6058 raise util.Abort(_('uncommitted merge'))
6057 raise util.Abort(_('uncommitted merge'))
6059 bheads = repo.branchheads()
6058 bheads = repo.branchheads()
6060 if not opts.get('force') and bheads and p1 not in bheads:
6059 if not opts.get('force') and bheads and p1 not in bheads:
6061 raise util.Abort(_('not at a branch head (use -f to force)'))
6060 raise util.Abort(_('not at a branch head (use -f to force)'))
6062 r = scmutil.revsingle(repo, rev_).node()
6061 r = scmutil.revsingle(repo, rev_).node()
6063
6062
6064 if not message:
6063 if not message:
6065 # we don't translate commit messages
6064 # we don't translate commit messages
6066 message = ('Added tag %s for changeset %s' %
6065 message = ('Added tag %s for changeset %s' %
6067 (', '.join(names), short(r)))
6066 (', '.join(names), short(r)))
6068
6067
6069 date = opts.get('date')
6068 date = opts.get('date')
6070 if date:
6069 if date:
6071 date = util.parsedate(date)
6070 date = util.parsedate(date)
6072
6071
6073 if opts.get('remove'):
6072 if opts.get('remove'):
6074 editform = 'tag.remove'
6073 editform = 'tag.remove'
6075 else:
6074 else:
6076 editform = 'tag.add'
6075 editform = 'tag.add'
6077 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6076 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6078
6077
6079 # don't allow tagging the null rev
6078 # don't allow tagging the null rev
6080 if (not opts.get('remove') and
6079 if (not opts.get('remove') and
6081 scmutil.revsingle(repo, rev_).rev() == nullrev):
6080 scmutil.revsingle(repo, rev_).rev() == nullrev):
6082 raise util.Abort(_("cannot tag null revision"))
6081 raise util.Abort(_("cannot tag null revision"))
6083
6082
6084 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6083 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6085 editor=editor)
6084 editor=editor)
6086 finally:
6085 finally:
6087 release(lock, wlock)
6086 release(lock, wlock)
6088
6087
6089 @command('tags', formatteropts, '')
6088 @command('tags', formatteropts, '')
6090 def tags(ui, repo, **opts):
6089 def tags(ui, repo, **opts):
6091 """list repository tags
6090 """list repository tags
6092
6091
6093 This lists both regular and local tags. When the -v/--verbose
6092 This lists both regular and local tags. When the -v/--verbose
6094 switch is used, a third column "local" is printed for local tags.
6093 switch is used, a third column "local" is printed for local tags.
6095
6094
6096 Returns 0 on success.
6095 Returns 0 on success.
6097 """
6096 """
6098
6097
6099 fm = ui.formatter('tags', opts)
6098 fm = ui.formatter('tags', opts)
6100 hexfunc = fm.hexfunc
6099 hexfunc = fm.hexfunc
6101 tagtype = ""
6100 tagtype = ""
6102
6101
6103 for t, n in reversed(repo.tagslist()):
6102 for t, n in reversed(repo.tagslist()):
6104 hn = hexfunc(n)
6103 hn = hexfunc(n)
6105 label = 'tags.normal'
6104 label = 'tags.normal'
6106 tagtype = ''
6105 tagtype = ''
6107 if repo.tagtype(t) == 'local':
6106 if repo.tagtype(t) == 'local':
6108 label = 'tags.local'
6107 label = 'tags.local'
6109 tagtype = 'local'
6108 tagtype = 'local'
6110
6109
6111 fm.startitem()
6110 fm.startitem()
6112 fm.write('tag', '%s', t, label=label)
6111 fm.write('tag', '%s', t, label=label)
6113 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6112 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6114 fm.condwrite(not ui.quiet, 'rev node', fmt,
6113 fm.condwrite(not ui.quiet, 'rev node', fmt,
6115 repo.changelog.rev(n), hn, label=label)
6114 repo.changelog.rev(n), hn, label=label)
6116 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6115 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6117 tagtype, label=label)
6116 tagtype, label=label)
6118 fm.plain('\n')
6117 fm.plain('\n')
6119 fm.end()
6118 fm.end()
6120
6119
6121 @command('tip',
6120 @command('tip',
6122 [('p', 'patch', None, _('show patch')),
6121 [('p', 'patch', None, _('show patch')),
6123 ('g', 'git', None, _('use git extended diff format')),
6122 ('g', 'git', None, _('use git extended diff format')),
6124 ] + templateopts,
6123 ] + templateopts,
6125 _('[-p] [-g]'))
6124 _('[-p] [-g]'))
6126 def tip(ui, repo, **opts):
6125 def tip(ui, repo, **opts):
6127 """show the tip revision (DEPRECATED)
6126 """show the tip revision (DEPRECATED)
6128
6127
6129 The tip revision (usually just called the tip) is the changeset
6128 The tip revision (usually just called the tip) is the changeset
6130 most recently added to the repository (and therefore the most
6129 most recently added to the repository (and therefore the most
6131 recently changed head).
6130 recently changed head).
6132
6131
6133 If you have just made a commit, that commit will be the tip. If
6132 If you have just made a commit, that commit will be the tip. If
6134 you have just pulled changes from another repository, the tip of
6133 you have just pulled changes from another repository, the tip of
6135 that repository becomes the current tip. The "tip" tag is special
6134 that repository becomes the current tip. The "tip" tag is special
6136 and cannot be renamed or assigned to a different changeset.
6135 and cannot be renamed or assigned to a different changeset.
6137
6136
6138 This command is deprecated, please use :hg:`heads` instead.
6137 This command is deprecated, please use :hg:`heads` instead.
6139
6138
6140 Returns 0 on success.
6139 Returns 0 on success.
6141 """
6140 """
6142 displayer = cmdutil.show_changeset(ui, repo, opts)
6141 displayer = cmdutil.show_changeset(ui, repo, opts)
6143 displayer.show(repo['tip'])
6142 displayer.show(repo['tip'])
6144 displayer.close()
6143 displayer.close()
6145
6144
6146 @command('unbundle',
6145 @command('unbundle',
6147 [('u', 'update', None,
6146 [('u', 'update', None,
6148 _('update to new branch head if changesets were unbundled'))],
6147 _('update to new branch head if changesets were unbundled'))],
6149 _('[-u] FILE...'))
6148 _('[-u] FILE...'))
6150 def unbundle(ui, repo, fname1, *fnames, **opts):
6149 def unbundle(ui, repo, fname1, *fnames, **opts):
6151 """apply one or more changegroup files
6150 """apply one or more changegroup files
6152
6151
6153 Apply one or more compressed changegroup files generated by the
6152 Apply one or more compressed changegroup files generated by the
6154 bundle command.
6153 bundle command.
6155
6154
6156 Returns 0 on success, 1 if an update has unresolved files.
6155 Returns 0 on success, 1 if an update has unresolved files.
6157 """
6156 """
6158 fnames = (fname1,) + fnames
6157 fnames = (fname1,) + fnames
6159
6158
6160 lock = repo.lock()
6159 lock = repo.lock()
6161 try:
6160 try:
6162 for fname in fnames:
6161 for fname in fnames:
6163 f = hg.openpath(ui, fname)
6162 f = hg.openpath(ui, fname)
6164 gen = exchange.readbundle(ui, f, fname)
6163 gen = exchange.readbundle(ui, f, fname)
6165 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6164 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6166 'bundle:' + fname)
6165 'bundle:' + fname)
6167 finally:
6166 finally:
6168 lock.release()
6167 lock.release()
6169
6168
6170 return postincoming(ui, repo, modheads, opts.get('update'), None)
6169 return postincoming(ui, repo, modheads, opts.get('update'), None)
6171
6170
6172 @command('^update|up|checkout|co',
6171 @command('^update|up|checkout|co',
6173 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6172 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6174 ('c', 'check', None,
6173 ('c', 'check', None,
6175 _('update across branches if no uncommitted changes')),
6174 _('update across branches if no uncommitted changes')),
6176 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6175 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6177 ('r', 'rev', '', _('revision'), _('REV'))
6176 ('r', 'rev', '', _('revision'), _('REV'))
6178 ] + mergetoolopts,
6177 ] + mergetoolopts,
6179 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6178 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6180 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6179 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6181 tool=None):
6180 tool=None):
6182 """update working directory (or switch revisions)
6181 """update working directory (or switch revisions)
6183
6182
6184 Update the repository's working directory to the specified
6183 Update the repository's working directory to the specified
6185 changeset. If no changeset is specified, update to the tip of the
6184 changeset. If no changeset is specified, update to the tip of the
6186 current named branch and move the current bookmark (see :hg:`help
6185 current named branch and move the current bookmark (see :hg:`help
6187 bookmarks`).
6186 bookmarks`).
6188
6187
6189 Update sets the working directory's parent revision to the specified
6188 Update sets the working directory's parent revision to the specified
6190 changeset (see :hg:`help parents`).
6189 changeset (see :hg:`help parents`).
6191
6190
6192 If the changeset is not a descendant or ancestor of the working
6191 If the changeset is not a descendant or ancestor of the working
6193 directory's parent, the update is aborted. With the -c/--check
6192 directory's parent, the update is aborted. With the -c/--check
6194 option, the working directory is checked for uncommitted changes; if
6193 option, the working directory is checked for uncommitted changes; if
6195 none are found, the working directory is updated to the specified
6194 none are found, the working directory is updated to the specified
6196 changeset.
6195 changeset.
6197
6196
6198 .. container:: verbose
6197 .. container:: verbose
6199
6198
6200 The following rules apply when the working directory contains
6199 The following rules apply when the working directory contains
6201 uncommitted changes:
6200 uncommitted changes:
6202
6201
6203 1. If neither -c/--check nor -C/--clean is specified, and if
6202 1. If neither -c/--check nor -C/--clean is specified, and if
6204 the requested changeset is an ancestor or descendant of
6203 the requested changeset is an ancestor or descendant of
6205 the working directory's parent, the uncommitted changes
6204 the working directory's parent, the uncommitted changes
6206 are merged into the requested changeset and the merged
6205 are merged into the requested changeset and the merged
6207 result is left uncommitted. If the requested changeset is
6206 result is left uncommitted. If the requested changeset is
6208 not an ancestor or descendant (that is, it is on another
6207 not an ancestor or descendant (that is, it is on another
6209 branch), the update is aborted and the uncommitted changes
6208 branch), the update is aborted and the uncommitted changes
6210 are preserved.
6209 are preserved.
6211
6210
6212 2. With the -c/--check option, the update is aborted and the
6211 2. With the -c/--check option, the update is aborted and the
6213 uncommitted changes are preserved.
6212 uncommitted changes are preserved.
6214
6213
6215 3. With the -C/--clean option, uncommitted changes are discarded and
6214 3. With the -C/--clean option, uncommitted changes are discarded and
6216 the working directory is updated to the requested changeset.
6215 the working directory is updated to the requested changeset.
6217
6216
6218 To cancel an uncommitted merge (and lose your changes), use
6217 To cancel an uncommitted merge (and lose your changes), use
6219 :hg:`update --clean .`.
6218 :hg:`update --clean .`.
6220
6219
6221 Use null as the changeset to remove the working directory (like
6220 Use null as the changeset to remove the working directory (like
6222 :hg:`clone -U`).
6221 :hg:`clone -U`).
6223
6222
6224 If you want to revert just one file to an older revision, use
6223 If you want to revert just one file to an older revision, use
6225 :hg:`revert [-r REV] NAME`.
6224 :hg:`revert [-r REV] NAME`.
6226
6225
6227 See :hg:`help dates` for a list of formats valid for -d/--date.
6226 See :hg:`help dates` for a list of formats valid for -d/--date.
6228
6227
6229 Returns 0 on success, 1 if there are unresolved files.
6228 Returns 0 on success, 1 if there are unresolved files.
6230 """
6229 """
6231 if rev and node:
6230 if rev and node:
6232 raise util.Abort(_("please specify just one revision"))
6231 raise util.Abort(_("please specify just one revision"))
6233
6232
6234 if rev is None or rev == '':
6233 if rev is None or rev == '':
6235 rev = node
6234 rev = node
6236
6235
6237 cmdutil.clearunfinished(repo)
6236 cmdutil.clearunfinished(repo)
6238
6237
6239 # with no argument, we also move the current bookmark, if any
6238 # with no argument, we also move the current bookmark, if any
6240 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6239 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6241
6240
6242 # if we defined a bookmark, we have to remember the original bookmark name
6241 # if we defined a bookmark, we have to remember the original bookmark name
6243 brev = rev
6242 brev = rev
6244 rev = scmutil.revsingle(repo, rev, rev).rev()
6243 rev = scmutil.revsingle(repo, rev, rev).rev()
6245
6244
6246 if check and clean:
6245 if check and clean:
6247 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6246 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6248
6247
6249 if date:
6248 if date:
6250 if rev is not None:
6249 if rev is not None:
6251 raise util.Abort(_("you can't specify a revision and a date"))
6250 raise util.Abort(_("you can't specify a revision and a date"))
6252 rev = cmdutil.finddate(ui, repo, date)
6251 rev = cmdutil.finddate(ui, repo, date)
6253
6252
6254 if check:
6253 if check:
6255 c = repo[None]
6254 c = repo[None]
6256 if c.dirty(merge=False, branch=False, missing=True):
6255 if c.dirty(merge=False, branch=False, missing=True):
6257 raise util.Abort(_("uncommitted changes"))
6256 raise util.Abort(_("uncommitted changes"))
6258 if rev is None:
6257 if rev is None:
6259 rev = repo[repo[None].branch()].rev()
6258 rev = repo[repo[None].branch()].rev()
6260 mergemod._checkunknown(repo, repo[None], repo[rev])
6259 mergemod._checkunknown(repo, repo[None], repo[rev])
6261
6260
6262 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6261 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6263
6262
6264 if clean:
6263 if clean:
6265 ret = hg.clean(repo, rev)
6264 ret = hg.clean(repo, rev)
6266 else:
6265 else:
6267 ret = hg.update(repo, rev)
6266 ret = hg.update(repo, rev)
6268
6267
6269 if not ret and movemarkfrom:
6268 if not ret and movemarkfrom:
6270 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6269 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6271 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6270 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6272 elif brev in repo._bookmarks:
6271 elif brev in repo._bookmarks:
6273 bookmarks.setcurrent(repo, brev)
6272 bookmarks.setcurrent(repo, brev)
6274 ui.status(_("(activating bookmark %s)\n") % brev)
6273 ui.status(_("(activating bookmark %s)\n") % brev)
6275 elif brev:
6274 elif brev:
6276 if repo._bookmarkcurrent:
6275 if repo._bookmarkcurrent:
6277 ui.status(_("(leaving bookmark %s)\n") %
6276 ui.status(_("(leaving bookmark %s)\n") %
6278 repo._bookmarkcurrent)
6277 repo._bookmarkcurrent)
6279 bookmarks.unsetcurrent(repo)
6278 bookmarks.unsetcurrent(repo)
6280
6279
6281 return ret
6280 return ret
6282
6281
6283 @command('verify', [])
6282 @command('verify', [])
6284 def verify(ui, repo):
6283 def verify(ui, repo):
6285 """verify the integrity of the repository
6284 """verify the integrity of the repository
6286
6285
6287 Verify the integrity of the current repository.
6286 Verify the integrity of the current repository.
6288
6287
6289 This will perform an extensive check of the repository's
6288 This will perform an extensive check of the repository's
6290 integrity, validating the hashes and checksums of each entry in
6289 integrity, validating the hashes and checksums of each entry in
6291 the changelog, manifest, and tracked files, as well as the
6290 the changelog, manifest, and tracked files, as well as the
6292 integrity of their crosslinks and indices.
6291 integrity of their crosslinks and indices.
6293
6292
6294 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6293 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6295 for more information about recovery from corruption of the
6294 for more information about recovery from corruption of the
6296 repository.
6295 repository.
6297
6296
6298 Returns 0 on success, 1 if errors are encountered.
6297 Returns 0 on success, 1 if errors are encountered.
6299 """
6298 """
6300 return hg.verify(repo)
6299 return hg.verify(repo)
6301
6300
6302 @command('version', [], norepo=True)
6301 @command('version', [], norepo=True)
6303 def version_(ui):
6302 def version_(ui):
6304 """output version and copyright information"""
6303 """output version and copyright information"""
6305 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6304 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6306 % util.version())
6305 % util.version())
6307 ui.status(_(
6306 ui.status(_(
6308 "(see http://mercurial.selenic.com for more information)\n"
6307 "(see http://mercurial.selenic.com for more information)\n"
6309 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6308 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6310 "This is free software; see the source for copying conditions. "
6309 "This is free software; see the source for copying conditions. "
6311 "There is NO\nwarranty; "
6310 "There is NO\nwarranty; "
6312 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6311 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6313 ))
6312 ))
6314
6313
6315 ui.note(_("\nEnabled extensions:\n\n"))
6314 ui.note(_("\nEnabled extensions:\n\n"))
6316 if ui.verbose:
6315 if ui.verbose:
6317 # format names and versions into columns
6316 # format names and versions into columns
6318 names = []
6317 names = []
6319 vers = []
6318 vers = []
6320 for name, module in extensions.extensions():
6319 for name, module in extensions.extensions():
6321 names.append(name)
6320 names.append(name)
6322 vers.append(extensions.moduleversion(module))
6321 vers.append(extensions.moduleversion(module))
6323 if names:
6322 if names:
6324 maxnamelen = max(len(n) for n in names)
6323 maxnamelen = max(len(n) for n in names)
6325 for i, name in enumerate(names):
6324 for i, name in enumerate(names):
6326 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6325 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,676 +1,667 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import nullid
11 from node import nullid
12
12 import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
13 import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
13 import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
14 import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
14 import cmdutil, discovery, repoview, exchange
15 import cmdutil, discovery, repoview, exchange
16 import ui as uimod
15 import merge as mergemod
17 import merge as mergemod
16 import verify as verifymod
18 import verify as verifymod
17 import errno, os, shutil
19 import errno, os, shutil
18
20
19 def _local(path):
21 def _local(path):
20 path = util.expandpath(util.urllocalpath(path))
22 path = util.expandpath(util.urllocalpath(path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
23 return (os.path.isfile(path) and bundlerepo or localrepo)
22
24
23 def addbranchrevs(lrepo, other, branches, revs):
25 def addbranchrevs(lrepo, other, branches, revs):
24 peer = other.peer() # a courtesy to callers using a localrepo for other
26 peer = other.peer() # a courtesy to callers using a localrepo for other
25 hashbranch, branches = branches
27 hashbranch, branches = branches
26 if not hashbranch and not branches:
28 if not hashbranch and not branches:
27 x = revs or None
29 x = revs or None
28 if util.safehasattr(revs, 'first'):
30 if util.safehasattr(revs, 'first'):
29 y = revs.first()
31 y = revs.first()
30 elif revs:
32 elif revs:
31 y = revs[0]
33 y = revs[0]
32 else:
34 else:
33 y = None
35 y = None
34 return x, y
36 return x, y
35 revs = revs and list(revs) or []
37 revs = revs and list(revs) or []
36 if not peer.capable('branchmap'):
38 if not peer.capable('branchmap'):
37 if branches:
39 if branches:
38 raise util.Abort(_("remote branch lookup not supported"))
40 raise util.Abort(_("remote branch lookup not supported"))
39 revs.append(hashbranch)
41 revs.append(hashbranch)
40 return revs, revs[0]
42 return revs, revs[0]
41 branchmap = peer.branchmap()
43 branchmap = peer.branchmap()
42
44
43 def primary(branch):
45 def primary(branch):
44 if branch == '.':
46 if branch == '.':
45 if not lrepo:
47 if not lrepo:
46 raise util.Abort(_("dirstate branch not accessible"))
48 raise util.Abort(_("dirstate branch not accessible"))
47 branch = lrepo.dirstate.branch()
49 branch = lrepo.dirstate.branch()
48 if branch in branchmap:
50 if branch in branchmap:
49 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
51 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
50 return True
52 return True
51 else:
53 else:
52 return False
54 return False
53
55
54 for branch in branches:
56 for branch in branches:
55 if not primary(branch):
57 if not primary(branch):
56 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
58 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
57 if hashbranch:
59 if hashbranch:
58 if not primary(hashbranch):
60 if not primary(hashbranch):
59 revs.append(hashbranch)
61 revs.append(hashbranch)
60 return revs, revs[0]
62 return revs, revs[0]
61
63
62 def parseurl(path, branches=None):
64 def parseurl(path, branches=None):
63 '''parse url#branch, returning (url, (branch, branches))'''
65 '''parse url#branch, returning (url, (branch, branches))'''
64
66
65 u = util.url(path)
67 u = util.url(path)
66 branch = None
68 branch = None
67 if u.fragment:
69 if u.fragment:
68 branch = u.fragment
70 branch = u.fragment
69 u.fragment = None
71 u.fragment = None
70 return str(u), (branch, branches or [])
72 return str(u), (branch, branches or [])
71
73
72 schemes = {
74 schemes = {
73 'bundle': bundlerepo,
75 'bundle': bundlerepo,
74 'union': unionrepo,
76 'union': unionrepo,
75 'file': _local,
77 'file': _local,
76 'http': httppeer,
78 'http': httppeer,
77 'https': httppeer,
79 'https': httppeer,
78 'ssh': sshpeer,
80 'ssh': sshpeer,
79 'static-http': statichttprepo,
81 'static-http': statichttprepo,
80 }
82 }
81
83
82 def _peerlookup(path):
84 def _peerlookup(path):
83 u = util.url(path)
85 u = util.url(path)
84 scheme = u.scheme or 'file'
86 scheme = u.scheme or 'file'
85 thing = schemes.get(scheme) or schemes['file']
87 thing = schemes.get(scheme) or schemes['file']
86 try:
88 try:
87 return thing(path)
89 return thing(path)
88 except TypeError:
90 except TypeError:
89 return thing
91 return thing
90
92
91 def islocal(repo):
93 def islocal(repo):
92 '''return true if repo (or path pointing to repo) is local'''
94 '''return true if repo (or path pointing to repo) is local'''
93 if isinstance(repo, str):
95 if isinstance(repo, str):
94 try:
96 try:
95 return _peerlookup(repo).islocal(repo)
97 return _peerlookup(repo).islocal(repo)
96 except AttributeError:
98 except AttributeError:
97 return False
99 return False
98 return repo.local()
100 return repo.local()
99
101
100 def openpath(ui, path):
102 def openpath(ui, path):
101 '''open path with open if local, url.open if remote'''
103 '''open path with open if local, url.open if remote'''
102 pathurl = util.url(path, parsequery=False, parsefragment=False)
104 pathurl = util.url(path, parsequery=False, parsefragment=False)
103 if pathurl.islocal():
105 if pathurl.islocal():
104 return util.posixfile(pathurl.localpath(), 'rb')
106 return util.posixfile(pathurl.localpath(), 'rb')
105 else:
107 else:
106 return url.open(ui, path)
108 return url.open(ui, path)
107
109
108 # a list of (ui, repo) functions called for wire peer initialization
110 # a list of (ui, repo) functions called for wire peer initialization
109 wirepeersetupfuncs = []
111 wirepeersetupfuncs = []
110
112
111 def _peerorrepo(ui, path, create=False):
113 def _peerorrepo(ui, path, create=False):
112 """return a repository object for the specified path"""
114 """return a repository object for the specified path"""
113 obj = _peerlookup(path).instance(ui, path, create)
115 obj = _peerlookup(path).instance(ui, path, create)
114 ui = getattr(obj, "ui", ui)
116 ui = getattr(obj, "ui", ui)
115 for name, module in extensions.extensions(ui):
117 for name, module in extensions.extensions(ui):
116 hook = getattr(module, 'reposetup', None)
118 hook = getattr(module, 'reposetup', None)
117 if hook:
119 if hook:
118 hook(ui, obj)
120 hook(ui, obj)
119 if not obj.local():
121 if not obj.local():
120 for f in wirepeersetupfuncs:
122 for f in wirepeersetupfuncs:
121 f(ui, obj)
123 f(ui, obj)
122 return obj
124 return obj
123
125
124 def repository(ui, path='', create=False):
126 def repository(ui, path='', create=False):
125 """return a repository object for the specified path"""
127 """return a repository object for the specified path"""
126 peer = _peerorrepo(ui, path, create)
128 peer = _peerorrepo(ui, path, create)
127 repo = peer.local()
129 repo = peer.local()
128 if not repo:
130 if not repo:
129 raise util.Abort(_("repository '%s' is not local") %
131 raise util.Abort(_("repository '%s' is not local") %
130 (path or peer.url()))
132 (path or peer.url()))
131 return repo.filtered('visible')
133 return repo.filtered('visible')
132
134
133 def peer(uiorrepo, opts, path, create=False):
135 def peer(uiorrepo, opts, path, create=False):
134 '''return a repository peer for the specified path'''
136 '''return a repository peer for the specified path'''
135 rui = remoteui(uiorrepo, opts)
137 rui = remoteui(uiorrepo, opts)
136 return _peerorrepo(rui, path, create).peer()
138 return _peerorrepo(rui, path, create).peer()
137
139
138 def defaultdest(source):
140 def defaultdest(source):
139 '''return default destination of clone if none is given
141 '''return default destination of clone if none is given
140
142
141 >>> defaultdest('foo')
143 >>> defaultdest('foo')
142 'foo'
144 'foo'
143 >>> defaultdest('/foo/bar')
145 >>> defaultdest('/foo/bar')
144 'bar'
146 'bar'
145 >>> defaultdest('/')
147 >>> defaultdest('/')
146 ''
148 ''
147 >>> defaultdest('')
149 >>> defaultdest('')
148 ''
150 ''
149 >>> defaultdest('http://example.org/')
151 >>> defaultdest('http://example.org/')
150 ''
152 ''
151 >>> defaultdest('http://example.org/foo/')
153 >>> defaultdest('http://example.org/foo/')
152 'foo'
154 'foo'
153 '''
155 '''
154 path = util.url(source).path
156 path = util.url(source).path
155 if not path:
157 if not path:
156 return ''
158 return ''
157 return os.path.basename(os.path.normpath(path))
159 return os.path.basename(os.path.normpath(path))
158
160
159 def share(ui, source, dest=None, update=True):
161 def share(ui, source, dest=None, update=True):
160 '''create a shared repository'''
162 '''create a shared repository'''
161
163
162 if not islocal(source):
164 if not islocal(source):
163 raise util.Abort(_('can only share local repositories'))
165 raise util.Abort(_('can only share local repositories'))
164
166
165 if not dest:
167 if not dest:
166 dest = defaultdest(source)
168 dest = defaultdest(source)
167 else:
169 else:
168 dest = ui.expandpath(dest)
170 dest = ui.expandpath(dest)
169
171
170 if isinstance(source, str):
172 if isinstance(source, str):
171 origsource = ui.expandpath(source)
173 origsource = ui.expandpath(source)
172 source, branches = parseurl(origsource)
174 source, branches = parseurl(origsource)
173 srcrepo = repository(ui, source)
175 srcrepo = repository(ui, source)
174 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
176 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
175 else:
177 else:
176 srcrepo = source.local()
178 srcrepo = source.local()
177 origsource = source = srcrepo.url()
179 origsource = source = srcrepo.url()
178 checkout = None
180 checkout = None
179
181
180 sharedpath = srcrepo.sharedpath # if our source is already sharing
182 sharedpath = srcrepo.sharedpath # if our source is already sharing
181
183
182 destwvfs = scmutil.vfs(dest, realpath=True)
184 destwvfs = scmutil.vfs(dest, realpath=True)
183 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
185 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
184
186
185 if destvfs.lexists():
187 if destvfs.lexists():
186 raise util.Abort(_('destination already exists'))
188 raise util.Abort(_('destination already exists'))
187
189
188 if not destwvfs.isdir():
190 if not destwvfs.isdir():
189 destwvfs.mkdir()
191 destwvfs.mkdir()
190 destvfs.makedir()
192 destvfs.makedir()
191
193
192 requirements = ''
194 requirements = ''
193 try:
195 try:
194 requirements = srcrepo.opener.read('requires')
196 requirements = srcrepo.opener.read('requires')
195 except IOError, inst:
197 except IOError, inst:
196 if inst.errno != errno.ENOENT:
198 if inst.errno != errno.ENOENT:
197 raise
199 raise
198
200
199 requirements += 'shared\n'
201 requirements += 'shared\n'
200 destvfs.write('requires', requirements)
202 destvfs.write('requires', requirements)
201 destvfs.write('sharedpath', sharedpath)
203 destvfs.write('sharedpath', sharedpath)
202
204
203 r = repository(ui, destwvfs.base)
205 r = repository(ui, destwvfs.base)
204
206
205 default = srcrepo.ui.config('paths', 'default')
207 default = srcrepo.ui.config('paths', 'default')
206 if default:
208 if default:
207 fp = r.opener("hgrc", "w", text=True)
209 fp = r.opener("hgrc", "w", text=True)
208 fp.write("[paths]\n")
210 fp.write("[paths]\n")
209 fp.write("default = %s\n" % default)
211 fp.write("default = %s\n" % default)
210 fp.close()
212 fp.close()
211
213
212 if update:
214 if update:
213 r.ui.status(_("updating working directory\n"))
215 r.ui.status(_("updating working directory\n"))
214 if update is not True:
216 if update is not True:
215 checkout = update
217 checkout = update
216 for test in (checkout, 'default', 'tip'):
218 for test in (checkout, 'default', 'tip'):
217 if test is None:
219 if test is None:
218 continue
220 continue
219 try:
221 try:
220 uprev = r.lookup(test)
222 uprev = r.lookup(test)
221 break
223 break
222 except error.RepoLookupError:
224 except error.RepoLookupError:
223 continue
225 continue
224 _update(r, uprev)
226 _update(r, uprev)
225
227
226 def copystore(ui, srcrepo, destpath):
228 def copystore(ui, srcrepo, destpath):
227 '''copy files from store of srcrepo in destpath
229 '''copy files from store of srcrepo in destpath
228
230
229 returns destlock
231 returns destlock
230 '''
232 '''
231 destlock = None
233 destlock = None
232 try:
234 try:
233 hardlink = None
235 hardlink = None
234 num = 0
236 num = 0
235 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
237 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
236 srcvfs = scmutil.vfs(srcrepo.sharedpath)
238 srcvfs = scmutil.vfs(srcrepo.sharedpath)
237 dstvfs = scmutil.vfs(destpath)
239 dstvfs = scmutil.vfs(destpath)
238 for f in srcrepo.store.copylist():
240 for f in srcrepo.store.copylist():
239 if srcpublishing and f.endswith('phaseroots'):
241 if srcpublishing and f.endswith('phaseroots'):
240 continue
242 continue
241 dstbase = os.path.dirname(f)
243 dstbase = os.path.dirname(f)
242 if dstbase and not dstvfs.exists(dstbase):
244 if dstbase and not dstvfs.exists(dstbase):
243 dstvfs.mkdir(dstbase)
245 dstvfs.mkdir(dstbase)
244 if srcvfs.exists(f):
246 if srcvfs.exists(f):
245 if f.endswith('data'):
247 if f.endswith('data'):
246 # 'dstbase' may be empty (e.g. revlog format 0)
248 # 'dstbase' may be empty (e.g. revlog format 0)
247 lockfile = os.path.join(dstbase, "lock")
249 lockfile = os.path.join(dstbase, "lock")
248 # lock to avoid premature writing to the target
250 # lock to avoid premature writing to the target
249 destlock = lock.lock(dstvfs, lockfile)
251 destlock = lock.lock(dstvfs, lockfile)
250 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
252 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
251 hardlink)
253 hardlink)
252 num += n
254 num += n
253 if hardlink:
255 if hardlink:
254 ui.debug("linked %d files\n" % num)
256 ui.debug("linked %d files\n" % num)
255 else:
257 else:
256 ui.debug("copied %d files\n" % num)
258 ui.debug("copied %d files\n" % num)
257 return destlock
259 return destlock
258 except: # re-raises
260 except: # re-raises
259 release(destlock)
261 release(destlock)
260 raise
262 raise
261
263
262 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
264 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
263 update=True, stream=False, branch=None):
265 update=True, stream=False, branch=None):
264 """Make a copy of an existing repository.
266 """Make a copy of an existing repository.
265
267
266 Create a copy of an existing repository in a new directory. The
268 Create a copy of an existing repository in a new directory. The
267 source and destination are URLs, as passed to the repository
269 source and destination are URLs, as passed to the repository
268 function. Returns a pair of repository peers, the source and
270 function. Returns a pair of repository peers, the source and
269 newly created destination.
271 newly created destination.
270
272
271 The location of the source is added to the new repository's
273 The location of the source is added to the new repository's
272 .hg/hgrc file, as the default to be used for future pulls and
274 .hg/hgrc file, as the default to be used for future pulls and
273 pushes.
275 pushes.
274
276
275 If an exception is raised, the partly cloned/updated destination
277 If an exception is raised, the partly cloned/updated destination
276 repository will be deleted.
278 repository will be deleted.
277
279
278 Arguments:
280 Arguments:
279
281
280 source: repository object or URL
282 source: repository object or URL
281
283
282 dest: URL of destination repository to create (defaults to base
284 dest: URL of destination repository to create (defaults to base
283 name of source repository)
285 name of source repository)
284
286
285 pull: always pull from source repository, even in local case
287 pull: always pull from source repository, even in local case
286
288
287 stream: stream raw data uncompressed from repository (fast over
289 stream: stream raw data uncompressed from repository (fast over
288 LAN, slow over WAN)
290 LAN, slow over WAN)
289
291
290 rev: revision to clone up to (implies pull=True)
292 rev: revision to clone up to (implies pull=True)
291
293
292 update: update working directory after clone completes, if
294 update: update working directory after clone completes, if
293 destination is local repository (True means update to default rev,
295 destination is local repository (True means update to default rev,
294 anything else is treated as a revision)
296 anything else is treated as a revision)
295
297
296 branch: branches to clone
298 branch: branches to clone
297 """
299 """
298
300
299 if isinstance(source, str):
301 if isinstance(source, str):
300 origsource = ui.expandpath(source)
302 origsource = ui.expandpath(source)
301 source, branch = parseurl(origsource, branch)
303 source, branch = parseurl(origsource, branch)
302 srcpeer = peer(ui, peeropts, source)
304 srcpeer = peer(ui, peeropts, source)
303 else:
305 else:
304 srcpeer = source.peer() # in case we were called with a localrepo
306 srcpeer = source.peer() # in case we were called with a localrepo
305 branch = (None, branch or [])
307 branch = (None, branch or [])
306 origsource = source = srcpeer.url()
308 origsource = source = srcpeer.url()
307 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
309 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
308
310
309 if dest is None:
311 if dest is None:
310 dest = defaultdest(source)
312 dest = defaultdest(source)
311 if dest:
313 if dest:
312 ui.status(_("destination directory: %s\n") % dest)
314 ui.status(_("destination directory: %s\n") % dest)
313 else:
315 else:
314 dest = ui.expandpath(dest)
316 dest = ui.expandpath(dest)
315
317
316 dest = util.urllocalpath(dest)
318 dest = util.urllocalpath(dest)
317 source = util.urllocalpath(source)
319 source = util.urllocalpath(source)
318
320
319 if not dest:
321 if not dest:
320 raise util.Abort(_("empty destination path is not valid"))
322 raise util.Abort(_("empty destination path is not valid"))
321
323
322 destvfs = scmutil.vfs(dest, expandpath=True)
324 destvfs = scmutil.vfs(dest, expandpath=True)
323 if destvfs.lexists():
325 if destvfs.lexists():
324 if not destvfs.isdir():
326 if not destvfs.isdir():
325 raise util.Abort(_("destination '%s' already exists") % dest)
327 raise util.Abort(_("destination '%s' already exists") % dest)
326 elif destvfs.listdir():
328 elif destvfs.listdir():
327 raise util.Abort(_("destination '%s' is not empty") % dest)
329 raise util.Abort(_("destination '%s' is not empty") % dest)
328
330
329 srclock = destlock = cleandir = None
331 srclock = destlock = cleandir = None
330 srcrepo = srcpeer.local()
332 srcrepo = srcpeer.local()
331 try:
333 try:
332 abspath = origsource
334 abspath = origsource
333 if islocal(origsource):
335 if islocal(origsource):
334 abspath = os.path.abspath(util.urllocalpath(origsource))
336 abspath = os.path.abspath(util.urllocalpath(origsource))
335
337
336 if islocal(dest):
338 if islocal(dest):
337 cleandir = dest
339 cleandir = dest
338
340
339 copy = False
341 copy = False
340 if (srcrepo and srcrepo.cancopy() and islocal(dest)
342 if (srcrepo and srcrepo.cancopy() and islocal(dest)
341 and not phases.hassecret(srcrepo)):
343 and not phases.hassecret(srcrepo)):
342 copy = not pull and not rev
344 copy = not pull and not rev
343
345
344 if copy:
346 if copy:
345 try:
347 try:
346 # we use a lock here because if we race with commit, we
348 # we use a lock here because if we race with commit, we
347 # can end up with extra data in the cloned revlogs that's
349 # can end up with extra data in the cloned revlogs that's
348 # not pointed to by changesets, thus causing verify to
350 # not pointed to by changesets, thus causing verify to
349 # fail
351 # fail
350 srclock = srcrepo.lock(wait=False)
352 srclock = srcrepo.lock(wait=False)
351 except error.LockError:
353 except error.LockError:
352 copy = False
354 copy = False
353
355
354 if copy:
356 if copy:
355 srcrepo.hook('preoutgoing', throw=True, source='clone')
357 srcrepo.hook('preoutgoing', throw=True, source='clone')
356 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
358 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
357 if not os.path.exists(dest):
359 if not os.path.exists(dest):
358 os.mkdir(dest)
360 os.mkdir(dest)
359 else:
361 else:
360 # only clean up directories we create ourselves
362 # only clean up directories we create ourselves
361 cleandir = hgdir
363 cleandir = hgdir
362 try:
364 try:
363 destpath = hgdir
365 destpath = hgdir
364 util.makedir(destpath, notindexed=True)
366 util.makedir(destpath, notindexed=True)
365 except OSError, inst:
367 except OSError, inst:
366 if inst.errno == errno.EEXIST:
368 if inst.errno == errno.EEXIST:
367 cleandir = None
369 cleandir = None
368 raise util.Abort(_("destination '%s' already exists")
370 raise util.Abort(_("destination '%s' already exists")
369 % dest)
371 % dest)
370 raise
372 raise
371
373
372 destlock = copystore(ui, srcrepo, destpath)
374 destlock = copystore(ui, srcrepo, destpath)
373 # copy bookmarks over
375 # copy bookmarks over
374 srcbookmarks = srcrepo.join('bookmarks')
376 srcbookmarks = srcrepo.join('bookmarks')
375 dstbookmarks = os.path.join(destpath, 'bookmarks')
377 dstbookmarks = os.path.join(destpath, 'bookmarks')
376 if os.path.exists(srcbookmarks):
378 if os.path.exists(srcbookmarks):
377 util.copyfile(srcbookmarks, dstbookmarks)
379 util.copyfile(srcbookmarks, dstbookmarks)
378
380
379 # Recomputing branch cache might be slow on big repos,
381 # Recomputing branch cache might be slow on big repos,
380 # so just copy it
382 # so just copy it
381 def copybranchcache(fname):
383 def copybranchcache(fname):
382 srcbranchcache = srcrepo.join('cache/%s' % fname)
384 srcbranchcache = srcrepo.join('cache/%s' % fname)
383 dstbranchcache = os.path.join(dstcachedir, fname)
385 dstbranchcache = os.path.join(dstcachedir, fname)
384 if os.path.exists(srcbranchcache):
386 if os.path.exists(srcbranchcache):
385 if not os.path.exists(dstcachedir):
387 if not os.path.exists(dstcachedir):
386 os.mkdir(dstcachedir)
388 os.mkdir(dstcachedir)
387 util.copyfile(srcbranchcache, dstbranchcache)
389 util.copyfile(srcbranchcache, dstbranchcache)
388
390
389 dstcachedir = os.path.join(destpath, 'cache')
391 dstcachedir = os.path.join(destpath, 'cache')
390 # In local clones we're copying all nodes, not just served
392 # In local clones we're copying all nodes, not just served
391 # ones. Therefore copy all branchcaches over.
393 # ones. Therefore copy all branchcaches over.
392 copybranchcache('branch2')
394 copybranchcache('branch2')
393 for cachename in repoview.filtertable:
395 for cachename in repoview.filtertable:
394 copybranchcache('branch2-%s' % cachename)
396 copybranchcache('branch2-%s' % cachename)
395
397
396 # we need to re-init the repo after manually copying the data
398 # we need to re-init the repo after manually copying the data
397 # into it
399 # into it
398 destpeer = peer(srcrepo, peeropts, dest)
400 destpeer = peer(srcrepo, peeropts, dest)
399 srcrepo.hook('outgoing', source='clone',
401 srcrepo.hook('outgoing', source='clone',
400 node=node.hex(node.nullid))
402 node=node.hex(node.nullid))
401 else:
403 else:
402 try:
404 try:
403 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
405 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
404 # only pass ui when no srcrepo
406 # only pass ui when no srcrepo
405 except OSError, inst:
407 except OSError, inst:
406 if inst.errno == errno.EEXIST:
408 if inst.errno == errno.EEXIST:
407 cleandir = None
409 cleandir = None
408 raise util.Abort(_("destination '%s' already exists")
410 raise util.Abort(_("destination '%s' already exists")
409 % dest)
411 % dest)
410 raise
412 raise
411
413
412 revs = None
414 revs = None
413 if rev:
415 if rev:
414 if not srcpeer.capable('lookup'):
416 if not srcpeer.capable('lookup'):
415 raise util.Abort(_("src repository does not support "
417 raise util.Abort(_("src repository does not support "
416 "revision lookup and so doesn't "
418 "revision lookup and so doesn't "
417 "support clone by revision"))
419 "support clone by revision"))
418 revs = [srcpeer.lookup(r) for r in rev]
420 revs = [srcpeer.lookup(r) for r in rev]
419 checkout = revs[0]
421 checkout = revs[0]
420 if destpeer.local():
422 if destpeer.local():
421 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
423 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
422 elif srcrepo:
424 elif srcrepo:
423 exchange.push(srcrepo, destpeer, revs=revs,
425 exchange.push(srcrepo, destpeer, revs=revs,
424 bookmarks=srcrepo._bookmarks.keys())
426 bookmarks=srcrepo._bookmarks.keys())
425 else:
427 else:
426 raise util.Abort(_("clone from remote to remote not supported"))
428 raise util.Abort(_("clone from remote to remote not supported"))
427
429
428 cleandir = None
430 cleandir = None
429
431
430 destrepo = destpeer.local()
432 destrepo = destpeer.local()
431 if destrepo:
433 if destrepo:
432 template = (
434 template = uimod.samplehgrcs['cloned']
433 '# You may want to set your username here if it is not set\n'
434 "# globally, or this repository requires a different\n"
435 '# username from your usual configuration. If you want to\n'
436 '# set something for all of your repositories on this\n'
437 '# computer, try running the command\n'
438 "# 'hg config --edit --global'\n"
439 '# [ui]\n'
440 '# username = Jane Doe <jdoe@example.com>\n'
441 '[paths]\n'
442 'default = %s\n'
443 )
444 fp = destrepo.opener("hgrc", "w", text=True)
435 fp = destrepo.opener("hgrc", "w", text=True)
445 u = util.url(abspath)
436 u = util.url(abspath)
446 u.passwd = None
437 u.passwd = None
447 defaulturl = str(u)
438 defaulturl = str(u)
448 fp.write(template % defaulturl)
439 fp.write(template % defaulturl)
449 fp.close()
440 fp.close()
450
441
451 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
442 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
452
443
453 if update:
444 if update:
454 if update is not True:
445 if update is not True:
455 checkout = srcpeer.lookup(update)
446 checkout = srcpeer.lookup(update)
456 uprev = None
447 uprev = None
457 status = None
448 status = None
458 if checkout is not None:
449 if checkout is not None:
459 try:
450 try:
460 uprev = destrepo.lookup(checkout)
451 uprev = destrepo.lookup(checkout)
461 except error.RepoLookupError:
452 except error.RepoLookupError:
462 pass
453 pass
463 if uprev is None:
454 if uprev is None:
464 try:
455 try:
465 uprev = destrepo._bookmarks['@']
456 uprev = destrepo._bookmarks['@']
466 update = '@'
457 update = '@'
467 bn = destrepo[uprev].branch()
458 bn = destrepo[uprev].branch()
468 if bn == 'default':
459 if bn == 'default':
469 status = _("updating to bookmark @\n")
460 status = _("updating to bookmark @\n")
470 else:
461 else:
471 status = (_("updating to bookmark @ on branch %s\n")
462 status = (_("updating to bookmark @ on branch %s\n")
472 % bn)
463 % bn)
473 except KeyError:
464 except KeyError:
474 try:
465 try:
475 uprev = destrepo.branchtip('default')
466 uprev = destrepo.branchtip('default')
476 except error.RepoLookupError:
467 except error.RepoLookupError:
477 uprev = destrepo.lookup('tip')
468 uprev = destrepo.lookup('tip')
478 if not status:
469 if not status:
479 bn = destrepo[uprev].branch()
470 bn = destrepo[uprev].branch()
480 status = _("updating to branch %s\n") % bn
471 status = _("updating to branch %s\n") % bn
481 destrepo.ui.status(status)
472 destrepo.ui.status(status)
482 _update(destrepo, uprev)
473 _update(destrepo, uprev)
483 if update in destrepo._bookmarks:
474 if update in destrepo._bookmarks:
484 bookmarks.setcurrent(destrepo, update)
475 bookmarks.setcurrent(destrepo, update)
485 finally:
476 finally:
486 release(srclock, destlock)
477 release(srclock, destlock)
487 if cleandir is not None:
478 if cleandir is not None:
488 shutil.rmtree(cleandir, True)
479 shutil.rmtree(cleandir, True)
489 if srcpeer is not None:
480 if srcpeer is not None:
490 srcpeer.close()
481 srcpeer.close()
491 return srcpeer, destpeer
482 return srcpeer, destpeer
492
483
493 def _showstats(repo, stats):
484 def _showstats(repo, stats):
494 repo.ui.status(_("%d files updated, %d files merged, "
485 repo.ui.status(_("%d files updated, %d files merged, "
495 "%d files removed, %d files unresolved\n") % stats)
486 "%d files removed, %d files unresolved\n") % stats)
496
487
497 def updaterepo(repo, node, overwrite):
488 def updaterepo(repo, node, overwrite):
498 """Update the working directory to node.
489 """Update the working directory to node.
499
490
500 When overwrite is set, changes are clobbered, merged else
491 When overwrite is set, changes are clobbered, merged else
501
492
502 returns stats (see pydoc mercurial.merge.applyupdates)"""
493 returns stats (see pydoc mercurial.merge.applyupdates)"""
503 return mergemod.update(repo, node, False, overwrite, None,
494 return mergemod.update(repo, node, False, overwrite, None,
504 labels=['working copy', 'destination'])
495 labels=['working copy', 'destination'])
505
496
506 def update(repo, node):
497 def update(repo, node):
507 """update the working directory to node, merging linear changes"""
498 """update the working directory to node, merging linear changes"""
508 stats = updaterepo(repo, node, False)
499 stats = updaterepo(repo, node, False)
509 _showstats(repo, stats)
500 _showstats(repo, stats)
510 if stats[3]:
501 if stats[3]:
511 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
502 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
512 return stats[3] > 0
503 return stats[3] > 0
513
504
514 # naming conflict in clone()
505 # naming conflict in clone()
515 _update = update
506 _update = update
516
507
517 def clean(repo, node, show_stats=True):
508 def clean(repo, node, show_stats=True):
518 """forcibly switch the working directory to node, clobbering changes"""
509 """forcibly switch the working directory to node, clobbering changes"""
519 stats = updaterepo(repo, node, True)
510 stats = updaterepo(repo, node, True)
520 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
511 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
521 if show_stats:
512 if show_stats:
522 _showstats(repo, stats)
513 _showstats(repo, stats)
523 return stats[3] > 0
514 return stats[3] > 0
524
515
525 def merge(repo, node, force=None, remind=True):
516 def merge(repo, node, force=None, remind=True):
526 """Branch merge with node, resolving changes. Return true if any
517 """Branch merge with node, resolving changes. Return true if any
527 unresolved conflicts."""
518 unresolved conflicts."""
528 stats = mergemod.update(repo, node, True, force, False)
519 stats = mergemod.update(repo, node, True, force, False)
529 _showstats(repo, stats)
520 _showstats(repo, stats)
530 if stats[3]:
521 if stats[3]:
531 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
522 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
532 "or 'hg update -C .' to abandon\n"))
523 "or 'hg update -C .' to abandon\n"))
533 elif remind:
524 elif remind:
534 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
525 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
535 return stats[3] > 0
526 return stats[3] > 0
536
527
537 def _incoming(displaychlist, subreporecurse, ui, repo, source,
528 def _incoming(displaychlist, subreporecurse, ui, repo, source,
538 opts, buffered=False):
529 opts, buffered=False):
539 """
530 """
540 Helper for incoming / gincoming.
531 Helper for incoming / gincoming.
541 displaychlist gets called with
532 displaychlist gets called with
542 (remoterepo, incomingchangesetlist, displayer) parameters,
533 (remoterepo, incomingchangesetlist, displayer) parameters,
543 and is supposed to contain only code that can't be unified.
534 and is supposed to contain only code that can't be unified.
544 """
535 """
545 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
536 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
546 other = peer(repo, opts, source)
537 other = peer(repo, opts, source)
547 ui.status(_('comparing with %s\n') % util.hidepassword(source))
538 ui.status(_('comparing with %s\n') % util.hidepassword(source))
548 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
539 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
549
540
550 if revs:
541 if revs:
551 revs = [other.lookup(rev) for rev in revs]
542 revs = [other.lookup(rev) for rev in revs]
552 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
543 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
553 revs, opts["bundle"], opts["force"])
544 revs, opts["bundle"], opts["force"])
554 try:
545 try:
555 if not chlist:
546 if not chlist:
556 ui.status(_("no changes found\n"))
547 ui.status(_("no changes found\n"))
557 return subreporecurse()
548 return subreporecurse()
558
549
559 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
550 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
560 displaychlist(other, chlist, displayer)
551 displaychlist(other, chlist, displayer)
561 displayer.close()
552 displayer.close()
562 finally:
553 finally:
563 cleanupfn()
554 cleanupfn()
564 subreporecurse()
555 subreporecurse()
565 return 0 # exit code is zero since we found incoming changes
556 return 0 # exit code is zero since we found incoming changes
566
557
567 def incoming(ui, repo, source, opts):
558 def incoming(ui, repo, source, opts):
568 def subreporecurse():
559 def subreporecurse():
569 ret = 1
560 ret = 1
570 if opts.get('subrepos'):
561 if opts.get('subrepos'):
571 ctx = repo[None]
562 ctx = repo[None]
572 for subpath in sorted(ctx.substate):
563 for subpath in sorted(ctx.substate):
573 sub = ctx.sub(subpath)
564 sub = ctx.sub(subpath)
574 ret = min(ret, sub.incoming(ui, source, opts))
565 ret = min(ret, sub.incoming(ui, source, opts))
575 return ret
566 return ret
576
567
577 def display(other, chlist, displayer):
568 def display(other, chlist, displayer):
578 limit = cmdutil.loglimit(opts)
569 limit = cmdutil.loglimit(opts)
579 if opts.get('newest_first'):
570 if opts.get('newest_first'):
580 chlist.reverse()
571 chlist.reverse()
581 count = 0
572 count = 0
582 for n in chlist:
573 for n in chlist:
583 if limit is not None and count >= limit:
574 if limit is not None and count >= limit:
584 break
575 break
585 parents = [p for p in other.changelog.parents(n) if p != nullid]
576 parents = [p for p in other.changelog.parents(n) if p != nullid]
586 if opts.get('no_merges') and len(parents) == 2:
577 if opts.get('no_merges') and len(parents) == 2:
587 continue
578 continue
588 count += 1
579 count += 1
589 displayer.show(other[n])
580 displayer.show(other[n])
590 return _incoming(display, subreporecurse, ui, repo, source, opts)
581 return _incoming(display, subreporecurse, ui, repo, source, opts)
591
582
592 def _outgoing(ui, repo, dest, opts):
583 def _outgoing(ui, repo, dest, opts):
593 dest = ui.expandpath(dest or 'default-push', dest or 'default')
584 dest = ui.expandpath(dest or 'default-push', dest or 'default')
594 dest, branches = parseurl(dest, opts.get('branch'))
585 dest, branches = parseurl(dest, opts.get('branch'))
595 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
586 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
596 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
587 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
597 if revs:
588 if revs:
598 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
589 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
599
590
600 other = peer(repo, opts, dest)
591 other = peer(repo, opts, dest)
601 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
592 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
602 force=opts.get('force'))
593 force=opts.get('force'))
603 o = outgoing.missing
594 o = outgoing.missing
604 if not o:
595 if not o:
605 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
596 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
606 return o, other
597 return o, other
607
598
608 def outgoing(ui, repo, dest, opts):
599 def outgoing(ui, repo, dest, opts):
609 def recurse():
600 def recurse():
610 ret = 1
601 ret = 1
611 if opts.get('subrepos'):
602 if opts.get('subrepos'):
612 ctx = repo[None]
603 ctx = repo[None]
613 for subpath in sorted(ctx.substate):
604 for subpath in sorted(ctx.substate):
614 sub = ctx.sub(subpath)
605 sub = ctx.sub(subpath)
615 ret = min(ret, sub.outgoing(ui, dest, opts))
606 ret = min(ret, sub.outgoing(ui, dest, opts))
616 return ret
607 return ret
617
608
618 limit = cmdutil.loglimit(opts)
609 limit = cmdutil.loglimit(opts)
619 o, other = _outgoing(ui, repo, dest, opts)
610 o, other = _outgoing(ui, repo, dest, opts)
620 if not o:
611 if not o:
621 cmdutil.outgoinghooks(ui, repo, other, opts, o)
612 cmdutil.outgoinghooks(ui, repo, other, opts, o)
622 return recurse()
613 return recurse()
623
614
624 if opts.get('newest_first'):
615 if opts.get('newest_first'):
625 o.reverse()
616 o.reverse()
626 displayer = cmdutil.show_changeset(ui, repo, opts)
617 displayer = cmdutil.show_changeset(ui, repo, opts)
627 count = 0
618 count = 0
628 for n in o:
619 for n in o:
629 if limit is not None and count >= limit:
620 if limit is not None and count >= limit:
630 break
621 break
631 parents = [p for p in repo.changelog.parents(n) if p != nullid]
622 parents = [p for p in repo.changelog.parents(n) if p != nullid]
632 if opts.get('no_merges') and len(parents) == 2:
623 if opts.get('no_merges') and len(parents) == 2:
633 continue
624 continue
634 count += 1
625 count += 1
635 displayer.show(repo[n])
626 displayer.show(repo[n])
636 displayer.close()
627 displayer.close()
637 cmdutil.outgoinghooks(ui, repo, other, opts, o)
628 cmdutil.outgoinghooks(ui, repo, other, opts, o)
638 recurse()
629 recurse()
639 return 0 # exit code is zero since we found outgoing changes
630 return 0 # exit code is zero since we found outgoing changes
640
631
641 def revert(repo, node, choose):
632 def revert(repo, node, choose):
642 """revert changes to revision in node without updating dirstate"""
633 """revert changes to revision in node without updating dirstate"""
643 return mergemod.update(repo, node, False, True, choose)[3] > 0
634 return mergemod.update(repo, node, False, True, choose)[3] > 0
644
635
645 def verify(repo):
636 def verify(repo):
646 """verify the consistency of a repository"""
637 """verify the consistency of a repository"""
647 return verifymod.verify(repo)
638 return verifymod.verify(repo)
648
639
649 def remoteui(src, opts):
640 def remoteui(src, opts):
650 'build a remote ui from ui or repo and opts'
641 'build a remote ui from ui or repo and opts'
651 if util.safehasattr(src, 'baseui'): # looks like a repository
642 if util.safehasattr(src, 'baseui'): # looks like a repository
652 dst = src.baseui.copy() # drop repo-specific config
643 dst = src.baseui.copy() # drop repo-specific config
653 src = src.ui # copy target options from repo
644 src = src.ui # copy target options from repo
654 else: # assume it's a global ui object
645 else: # assume it's a global ui object
655 dst = src.copy() # keep all global options
646 dst = src.copy() # keep all global options
656
647
657 # copy ssh-specific options
648 # copy ssh-specific options
658 for o in 'ssh', 'remotecmd':
649 for o in 'ssh', 'remotecmd':
659 v = opts.get(o) or src.config('ui', o)
650 v = opts.get(o) or src.config('ui', o)
660 if v:
651 if v:
661 dst.setconfig("ui", o, v, 'copied')
652 dst.setconfig("ui", o, v, 'copied')
662
653
663 # copy bundle-specific options
654 # copy bundle-specific options
664 r = src.config('bundle', 'mainreporoot')
655 r = src.config('bundle', 'mainreporoot')
665 if r:
656 if r:
666 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
657 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
667
658
668 # copy selected local settings to the remote ui
659 # copy selected local settings to the remote ui
669 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
660 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
670 for key, val in src.configitems(sect):
661 for key, val in src.configitems(sect):
671 dst.setconfig(sect, key, val, 'copied')
662 dst.setconfig(sect, key, val, 'copied')
672 v = src.config('web', 'cacerts')
663 v = src.config('web', 'cacerts')
673 if v:
664 if v:
674 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
665 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
675
666
676 return dst
667 return dst
@@ -1,906 +1,923 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits 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 i18n import _
8 from i18n import _
9 import errno, getpass, os, socket, sys, tempfile, traceback
9 import errno, getpass, os, socket, sys, tempfile, traceback
10 import config, scmutil, util, error, formatter
10 import config, scmutil, util, error, formatter
11 from node import hex
11 from node import hex
12
12
13 samplehgrcs = {
13 samplehgrcs = {
14 'user':
14 'user':
15 """# example user config (see "hg help config" for more info)
15 """# example user config (see "hg help config" for more info)
16 [ui]
16 [ui]
17 # name and email, e.g.
17 # name and email, e.g.
18 # username = Jane Doe <jdoe@example.com>
18 # username = Jane Doe <jdoe@example.com>
19 username =
19 username =
20
20
21 [extensions]
21 [extensions]
22 # uncomment these lines to enable some popular extensions
22 # uncomment these lines to enable some popular extensions
23 # (see "hg help extensions" for more info)
23 # (see "hg help extensions" for more info)
24 #
24 #
25 # pager =
25 # pager =
26 # progress =
26 # progress =
27 # color =""",
27 # color =""",
28
28
29 'cloned':
30 """# example repository config (see "hg help config" for more info)
31 [paths]
32 default = %s
33
34 # path aliases to other clones of this repo in URLs or filesystem paths
35 # (see "hg help config.paths" for more info)
36 #
37 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
39 # my-clone = /home/jdoe/jdoes-clone
40
41 [ui]
42 # name and email (local to this repository, optional), e.g.
43 # username = Jane Doe <jdoe@example.com>
44 """,
45
29 'local':
46 'local':
30 """# example repository config (see "hg help config" for more info)
47 """# example repository config (see "hg help config" for more info)
31 [paths]
48 [paths]
32 # path aliases to other clones of this repo in URLs or filesystem paths
49 # path aliases to other clones of this repo in URLs or filesystem paths
33 # (see "hg help config.paths" for more info)
50 # (see "hg help config.paths" for more info)
34 #
51 #
35 # default = http://example.com/hg/example-repo
52 # default = http://example.com/hg/example-repo
36 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
53 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
37 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
54 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-clone = /home/jdoe/jdoes-clone
55 # my-clone = /home/jdoe/jdoes-clone
39
56
40 [ui]
57 [ui]
41 # name and email (local to this repository, optional), e.g.
58 # name and email (local to this repository, optional), e.g.
42 # username = Jane Doe <jdoe@example.com>
59 # username = Jane Doe <jdoe@example.com>
43 """,
60 """,
44
61
45 'global':
62 'global':
46 """# example system-wide hg config (see "hg help config" for more info)
63 """# example system-wide hg config (see "hg help config" for more info)
47
64
48 [extensions]
65 [extensions]
49 # uncomment these lines to enable some popular extensions
66 # uncomment these lines to enable some popular extensions
50 # (see "hg help extensions" for more info)
67 # (see "hg help extensions" for more info)
51 #
68 #
52 # blackbox =
69 # blackbox =
53 # progress =
70 # progress =
54 # color =
71 # color =
55 # pager =""",
72 # pager =""",
56 }
73 }
57
74
58 class ui(object):
75 class ui(object):
59 def __init__(self, src=None):
76 def __init__(self, src=None):
60 # _buffers: used for temporary capture of output
77 # _buffers: used for temporary capture of output
61 self._buffers = []
78 self._buffers = []
62 # _bufferstates: Should the temporary capture includes stderr
79 # _bufferstates: Should the temporary capture includes stderr
63 self._bufferstates = []
80 self._bufferstates = []
64 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
81 self.quiet = self.verbose = self.debugflag = self.tracebackflag = False
65 self._reportuntrusted = True
82 self._reportuntrusted = True
66 self._ocfg = config.config() # overlay
83 self._ocfg = config.config() # overlay
67 self._tcfg = config.config() # trusted
84 self._tcfg = config.config() # trusted
68 self._ucfg = config.config() # untrusted
85 self._ucfg = config.config() # untrusted
69 self._trustusers = set()
86 self._trustusers = set()
70 self._trustgroups = set()
87 self._trustgroups = set()
71 self.callhooks = True
88 self.callhooks = True
72
89
73 if src:
90 if src:
74 self.fout = src.fout
91 self.fout = src.fout
75 self.ferr = src.ferr
92 self.ferr = src.ferr
76 self.fin = src.fin
93 self.fin = src.fin
77
94
78 self._tcfg = src._tcfg.copy()
95 self._tcfg = src._tcfg.copy()
79 self._ucfg = src._ucfg.copy()
96 self._ucfg = src._ucfg.copy()
80 self._ocfg = src._ocfg.copy()
97 self._ocfg = src._ocfg.copy()
81 self._trustusers = src._trustusers.copy()
98 self._trustusers = src._trustusers.copy()
82 self._trustgroups = src._trustgroups.copy()
99 self._trustgroups = src._trustgroups.copy()
83 self.environ = src.environ
100 self.environ = src.environ
84 self.callhooks = src.callhooks
101 self.callhooks = src.callhooks
85 self.fixconfig()
102 self.fixconfig()
86 else:
103 else:
87 self.fout = sys.stdout
104 self.fout = sys.stdout
88 self.ferr = sys.stderr
105 self.ferr = sys.stderr
89 self.fin = sys.stdin
106 self.fin = sys.stdin
90
107
91 # shared read-only environment
108 # shared read-only environment
92 self.environ = os.environ
109 self.environ = os.environ
93 # we always trust global config files
110 # we always trust global config files
94 for f in scmutil.rcpath():
111 for f in scmutil.rcpath():
95 self.readconfig(f, trust=True)
112 self.readconfig(f, trust=True)
96
113
97 def copy(self):
114 def copy(self):
98 return self.__class__(self)
115 return self.__class__(self)
99
116
100 def formatter(self, topic, opts):
117 def formatter(self, topic, opts):
101 return formatter.formatter(self, topic, opts)
118 return formatter.formatter(self, topic, opts)
102
119
103 def _trusted(self, fp, f):
120 def _trusted(self, fp, f):
104 st = util.fstat(fp)
121 st = util.fstat(fp)
105 if util.isowner(st):
122 if util.isowner(st):
106 return True
123 return True
107
124
108 tusers, tgroups = self._trustusers, self._trustgroups
125 tusers, tgroups = self._trustusers, self._trustgroups
109 if '*' in tusers or '*' in tgroups:
126 if '*' in tusers or '*' in tgroups:
110 return True
127 return True
111
128
112 user = util.username(st.st_uid)
129 user = util.username(st.st_uid)
113 group = util.groupname(st.st_gid)
130 group = util.groupname(st.st_gid)
114 if user in tusers or group in tgroups or user == util.username():
131 if user in tusers or group in tgroups or user == util.username():
115 return True
132 return True
116
133
117 if self._reportuntrusted:
134 if self._reportuntrusted:
118 self.warn(_('not trusting file %s from untrusted '
135 self.warn(_('not trusting file %s from untrusted '
119 'user %s, group %s\n') % (f, user, group))
136 'user %s, group %s\n') % (f, user, group))
120 return False
137 return False
121
138
122 def readconfig(self, filename, root=None, trust=False,
139 def readconfig(self, filename, root=None, trust=False,
123 sections=None, remap=None):
140 sections=None, remap=None):
124 try:
141 try:
125 fp = open(filename)
142 fp = open(filename)
126 except IOError:
143 except IOError:
127 if not sections: # ignore unless we were looking for something
144 if not sections: # ignore unless we were looking for something
128 return
145 return
129 raise
146 raise
130
147
131 cfg = config.config()
148 cfg = config.config()
132 trusted = sections or trust or self._trusted(fp, filename)
149 trusted = sections or trust or self._trusted(fp, filename)
133
150
134 try:
151 try:
135 cfg.read(filename, fp, sections=sections, remap=remap)
152 cfg.read(filename, fp, sections=sections, remap=remap)
136 fp.close()
153 fp.close()
137 except error.ConfigError, inst:
154 except error.ConfigError, inst:
138 if trusted:
155 if trusted:
139 raise
156 raise
140 self.warn(_("ignored: %s\n") % str(inst))
157 self.warn(_("ignored: %s\n") % str(inst))
141
158
142 if self.plain():
159 if self.plain():
143 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
160 for k in ('debug', 'fallbackencoding', 'quiet', 'slash',
144 'logtemplate', 'style',
161 'logtemplate', 'style',
145 'traceback', 'verbose'):
162 'traceback', 'verbose'):
146 if k in cfg['ui']:
163 if k in cfg['ui']:
147 del cfg['ui'][k]
164 del cfg['ui'][k]
148 for k, v in cfg.items('defaults'):
165 for k, v in cfg.items('defaults'):
149 del cfg['defaults'][k]
166 del cfg['defaults'][k]
150 # Don't remove aliases from the configuration if in the exceptionlist
167 # Don't remove aliases from the configuration if in the exceptionlist
151 if self.plain('alias'):
168 if self.plain('alias'):
152 for k, v in cfg.items('alias'):
169 for k, v in cfg.items('alias'):
153 del cfg['alias'][k]
170 del cfg['alias'][k]
154
171
155 if trusted:
172 if trusted:
156 self._tcfg.update(cfg)
173 self._tcfg.update(cfg)
157 self._tcfg.update(self._ocfg)
174 self._tcfg.update(self._ocfg)
158 self._ucfg.update(cfg)
175 self._ucfg.update(cfg)
159 self._ucfg.update(self._ocfg)
176 self._ucfg.update(self._ocfg)
160
177
161 if root is None:
178 if root is None:
162 root = os.path.expanduser('~')
179 root = os.path.expanduser('~')
163 self.fixconfig(root=root)
180 self.fixconfig(root=root)
164
181
165 def fixconfig(self, root=None, section=None):
182 def fixconfig(self, root=None, section=None):
166 if section in (None, 'paths'):
183 if section in (None, 'paths'):
167 # expand vars and ~
184 # expand vars and ~
168 # translate paths relative to root (or home) into absolute paths
185 # translate paths relative to root (or home) into absolute paths
169 root = root or os.getcwd()
186 root = root or os.getcwd()
170 for c in self._tcfg, self._ucfg, self._ocfg:
187 for c in self._tcfg, self._ucfg, self._ocfg:
171 for n, p in c.items('paths'):
188 for n, p in c.items('paths'):
172 if not p:
189 if not p:
173 continue
190 continue
174 if '%%' in p:
191 if '%%' in p:
175 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
192 self.warn(_("(deprecated '%%' in path %s=%s from %s)\n")
176 % (n, p, self.configsource('paths', n)))
193 % (n, p, self.configsource('paths', n)))
177 p = p.replace('%%', '%')
194 p = p.replace('%%', '%')
178 p = util.expandpath(p)
195 p = util.expandpath(p)
179 if not util.hasscheme(p) and not os.path.isabs(p):
196 if not util.hasscheme(p) and not os.path.isabs(p):
180 p = os.path.normpath(os.path.join(root, p))
197 p = os.path.normpath(os.path.join(root, p))
181 c.set("paths", n, p)
198 c.set("paths", n, p)
182
199
183 if section in (None, 'ui'):
200 if section in (None, 'ui'):
184 # update ui options
201 # update ui options
185 self.debugflag = self.configbool('ui', 'debug')
202 self.debugflag = self.configbool('ui', 'debug')
186 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
203 self.verbose = self.debugflag or self.configbool('ui', 'verbose')
187 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
204 self.quiet = not self.debugflag and self.configbool('ui', 'quiet')
188 if self.verbose and self.quiet:
205 if self.verbose and self.quiet:
189 self.quiet = self.verbose = False
206 self.quiet = self.verbose = False
190 self._reportuntrusted = self.debugflag or self.configbool("ui",
207 self._reportuntrusted = self.debugflag or self.configbool("ui",
191 "report_untrusted", True)
208 "report_untrusted", True)
192 self.tracebackflag = self.configbool('ui', 'traceback', False)
209 self.tracebackflag = self.configbool('ui', 'traceback', False)
193
210
194 if section in (None, 'trusted'):
211 if section in (None, 'trusted'):
195 # update trust information
212 # update trust information
196 self._trustusers.update(self.configlist('trusted', 'users'))
213 self._trustusers.update(self.configlist('trusted', 'users'))
197 self._trustgroups.update(self.configlist('trusted', 'groups'))
214 self._trustgroups.update(self.configlist('trusted', 'groups'))
198
215
199 def backupconfig(self, section, item):
216 def backupconfig(self, section, item):
200 return (self._ocfg.backup(section, item),
217 return (self._ocfg.backup(section, item),
201 self._tcfg.backup(section, item),
218 self._tcfg.backup(section, item),
202 self._ucfg.backup(section, item),)
219 self._ucfg.backup(section, item),)
203 def restoreconfig(self, data):
220 def restoreconfig(self, data):
204 self._ocfg.restore(data[0])
221 self._ocfg.restore(data[0])
205 self._tcfg.restore(data[1])
222 self._tcfg.restore(data[1])
206 self._ucfg.restore(data[2])
223 self._ucfg.restore(data[2])
207
224
208 def setconfig(self, section, name, value, source=''):
225 def setconfig(self, section, name, value, source=''):
209 for cfg in (self._ocfg, self._tcfg, self._ucfg):
226 for cfg in (self._ocfg, self._tcfg, self._ucfg):
210 cfg.set(section, name, value, source)
227 cfg.set(section, name, value, source)
211 self.fixconfig(section=section)
228 self.fixconfig(section=section)
212
229
213 def _data(self, untrusted):
230 def _data(self, untrusted):
214 return untrusted and self._ucfg or self._tcfg
231 return untrusted and self._ucfg or self._tcfg
215
232
216 def configsource(self, section, name, untrusted=False):
233 def configsource(self, section, name, untrusted=False):
217 return self._data(untrusted).source(section, name) or 'none'
234 return self._data(untrusted).source(section, name) or 'none'
218
235
219 def config(self, section, name, default=None, untrusted=False):
236 def config(self, section, name, default=None, untrusted=False):
220 if isinstance(name, list):
237 if isinstance(name, list):
221 alternates = name
238 alternates = name
222 else:
239 else:
223 alternates = [name]
240 alternates = [name]
224
241
225 for n in alternates:
242 for n in alternates:
226 value = self._data(untrusted).get(section, n, None)
243 value = self._data(untrusted).get(section, n, None)
227 if value is not None:
244 if value is not None:
228 name = n
245 name = n
229 break
246 break
230 else:
247 else:
231 value = default
248 value = default
232
249
233 if self.debugflag and not untrusted and self._reportuntrusted:
250 if self.debugflag and not untrusted and self._reportuntrusted:
234 for n in alternates:
251 for n in alternates:
235 uvalue = self._ucfg.get(section, n)
252 uvalue = self._ucfg.get(section, n)
236 if uvalue is not None and uvalue != value:
253 if uvalue is not None and uvalue != value:
237 self.debug("ignoring untrusted configuration option "
254 self.debug("ignoring untrusted configuration option "
238 "%s.%s = %s\n" % (section, n, uvalue))
255 "%s.%s = %s\n" % (section, n, uvalue))
239 return value
256 return value
240
257
241 def configpath(self, section, name, default=None, untrusted=False):
258 def configpath(self, section, name, default=None, untrusted=False):
242 'get a path config item, expanded relative to repo root or config file'
259 'get a path config item, expanded relative to repo root or config file'
243 v = self.config(section, name, default, untrusted)
260 v = self.config(section, name, default, untrusted)
244 if v is None:
261 if v is None:
245 return None
262 return None
246 if not os.path.isabs(v) or "://" not in v:
263 if not os.path.isabs(v) or "://" not in v:
247 src = self.configsource(section, name, untrusted)
264 src = self.configsource(section, name, untrusted)
248 if ':' in src:
265 if ':' in src:
249 base = os.path.dirname(src.rsplit(':')[0])
266 base = os.path.dirname(src.rsplit(':')[0])
250 v = os.path.join(base, os.path.expanduser(v))
267 v = os.path.join(base, os.path.expanduser(v))
251 return v
268 return v
252
269
253 def configbool(self, section, name, default=False, untrusted=False):
270 def configbool(self, section, name, default=False, untrusted=False):
254 """parse a configuration element as a boolean
271 """parse a configuration element as a boolean
255
272
256 >>> u = ui(); s = 'foo'
273 >>> u = ui(); s = 'foo'
257 >>> u.setconfig(s, 'true', 'yes')
274 >>> u.setconfig(s, 'true', 'yes')
258 >>> u.configbool(s, 'true')
275 >>> u.configbool(s, 'true')
259 True
276 True
260 >>> u.setconfig(s, 'false', 'no')
277 >>> u.setconfig(s, 'false', 'no')
261 >>> u.configbool(s, 'false')
278 >>> u.configbool(s, 'false')
262 False
279 False
263 >>> u.configbool(s, 'unknown')
280 >>> u.configbool(s, 'unknown')
264 False
281 False
265 >>> u.configbool(s, 'unknown', True)
282 >>> u.configbool(s, 'unknown', True)
266 True
283 True
267 >>> u.setconfig(s, 'invalid', 'somevalue')
284 >>> u.setconfig(s, 'invalid', 'somevalue')
268 >>> u.configbool(s, 'invalid')
285 >>> u.configbool(s, 'invalid')
269 Traceback (most recent call last):
286 Traceback (most recent call last):
270 ...
287 ...
271 ConfigError: foo.invalid is not a boolean ('somevalue')
288 ConfigError: foo.invalid is not a boolean ('somevalue')
272 """
289 """
273
290
274 v = self.config(section, name, None, untrusted)
291 v = self.config(section, name, None, untrusted)
275 if v is None:
292 if v is None:
276 return default
293 return default
277 if isinstance(v, bool):
294 if isinstance(v, bool):
278 return v
295 return v
279 b = util.parsebool(v)
296 b = util.parsebool(v)
280 if b is None:
297 if b is None:
281 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
298 raise error.ConfigError(_("%s.%s is not a boolean ('%s')")
282 % (section, name, v))
299 % (section, name, v))
283 return b
300 return b
284
301
285 def configint(self, section, name, default=None, untrusted=False):
302 def configint(self, section, name, default=None, untrusted=False):
286 """parse a configuration element as an integer
303 """parse a configuration element as an integer
287
304
288 >>> u = ui(); s = 'foo'
305 >>> u = ui(); s = 'foo'
289 >>> u.setconfig(s, 'int1', '42')
306 >>> u.setconfig(s, 'int1', '42')
290 >>> u.configint(s, 'int1')
307 >>> u.configint(s, 'int1')
291 42
308 42
292 >>> u.setconfig(s, 'int2', '-42')
309 >>> u.setconfig(s, 'int2', '-42')
293 >>> u.configint(s, 'int2')
310 >>> u.configint(s, 'int2')
294 -42
311 -42
295 >>> u.configint(s, 'unknown', 7)
312 >>> u.configint(s, 'unknown', 7)
296 7
313 7
297 >>> u.setconfig(s, 'invalid', 'somevalue')
314 >>> u.setconfig(s, 'invalid', 'somevalue')
298 >>> u.configint(s, 'invalid')
315 >>> u.configint(s, 'invalid')
299 Traceback (most recent call last):
316 Traceback (most recent call last):
300 ...
317 ...
301 ConfigError: foo.invalid is not an integer ('somevalue')
318 ConfigError: foo.invalid is not an integer ('somevalue')
302 """
319 """
303
320
304 v = self.config(section, name, None, untrusted)
321 v = self.config(section, name, None, untrusted)
305 if v is None:
322 if v is None:
306 return default
323 return default
307 try:
324 try:
308 return int(v)
325 return int(v)
309 except ValueError:
326 except ValueError:
310 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
327 raise error.ConfigError(_("%s.%s is not an integer ('%s')")
311 % (section, name, v))
328 % (section, name, v))
312
329
313 def configbytes(self, section, name, default=0, untrusted=False):
330 def configbytes(self, section, name, default=0, untrusted=False):
314 """parse a configuration element as a quantity in bytes
331 """parse a configuration element as a quantity in bytes
315
332
316 Units can be specified as b (bytes), k or kb (kilobytes), m or
333 Units can be specified as b (bytes), k or kb (kilobytes), m or
317 mb (megabytes), g or gb (gigabytes).
334 mb (megabytes), g or gb (gigabytes).
318
335
319 >>> u = ui(); s = 'foo'
336 >>> u = ui(); s = 'foo'
320 >>> u.setconfig(s, 'val1', '42')
337 >>> u.setconfig(s, 'val1', '42')
321 >>> u.configbytes(s, 'val1')
338 >>> u.configbytes(s, 'val1')
322 42
339 42
323 >>> u.setconfig(s, 'val2', '42.5 kb')
340 >>> u.setconfig(s, 'val2', '42.5 kb')
324 >>> u.configbytes(s, 'val2')
341 >>> u.configbytes(s, 'val2')
325 43520
342 43520
326 >>> u.configbytes(s, 'unknown', '7 MB')
343 >>> u.configbytes(s, 'unknown', '7 MB')
327 7340032
344 7340032
328 >>> u.setconfig(s, 'invalid', 'somevalue')
345 >>> u.setconfig(s, 'invalid', 'somevalue')
329 >>> u.configbytes(s, 'invalid')
346 >>> u.configbytes(s, 'invalid')
330 Traceback (most recent call last):
347 Traceback (most recent call last):
331 ...
348 ...
332 ConfigError: foo.invalid is not a byte quantity ('somevalue')
349 ConfigError: foo.invalid is not a byte quantity ('somevalue')
333 """
350 """
334
351
335 value = self.config(section, name)
352 value = self.config(section, name)
336 if value is None:
353 if value is None:
337 if not isinstance(default, str):
354 if not isinstance(default, str):
338 return default
355 return default
339 value = default
356 value = default
340 try:
357 try:
341 return util.sizetoint(value)
358 return util.sizetoint(value)
342 except error.ParseError:
359 except error.ParseError:
343 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
360 raise error.ConfigError(_("%s.%s is not a byte quantity ('%s')")
344 % (section, name, value))
361 % (section, name, value))
345
362
346 def configlist(self, section, name, default=None, untrusted=False):
363 def configlist(self, section, name, default=None, untrusted=False):
347 """parse a configuration element as a list of comma/space separated
364 """parse a configuration element as a list of comma/space separated
348 strings
365 strings
349
366
350 >>> u = ui(); s = 'foo'
367 >>> u = ui(); s = 'foo'
351 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
368 >>> u.setconfig(s, 'list1', 'this,is "a small" ,test')
352 >>> u.configlist(s, 'list1')
369 >>> u.configlist(s, 'list1')
353 ['this', 'is', 'a small', 'test']
370 ['this', 'is', 'a small', 'test']
354 """
371 """
355
372
356 def _parse_plain(parts, s, offset):
373 def _parse_plain(parts, s, offset):
357 whitespace = False
374 whitespace = False
358 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
375 while offset < len(s) and (s[offset].isspace() or s[offset] == ','):
359 whitespace = True
376 whitespace = True
360 offset += 1
377 offset += 1
361 if offset >= len(s):
378 if offset >= len(s):
362 return None, parts, offset
379 return None, parts, offset
363 if whitespace:
380 if whitespace:
364 parts.append('')
381 parts.append('')
365 if s[offset] == '"' and not parts[-1]:
382 if s[offset] == '"' and not parts[-1]:
366 return _parse_quote, parts, offset + 1
383 return _parse_quote, parts, offset + 1
367 elif s[offset] == '"' and parts[-1][-1] == '\\':
384 elif s[offset] == '"' and parts[-1][-1] == '\\':
368 parts[-1] = parts[-1][:-1] + s[offset]
385 parts[-1] = parts[-1][:-1] + s[offset]
369 return _parse_plain, parts, offset + 1
386 return _parse_plain, parts, offset + 1
370 parts[-1] += s[offset]
387 parts[-1] += s[offset]
371 return _parse_plain, parts, offset + 1
388 return _parse_plain, parts, offset + 1
372
389
373 def _parse_quote(parts, s, offset):
390 def _parse_quote(parts, s, offset):
374 if offset < len(s) and s[offset] == '"': # ""
391 if offset < len(s) and s[offset] == '"': # ""
375 parts.append('')
392 parts.append('')
376 offset += 1
393 offset += 1
377 while offset < len(s) and (s[offset].isspace() or
394 while offset < len(s) and (s[offset].isspace() or
378 s[offset] == ','):
395 s[offset] == ','):
379 offset += 1
396 offset += 1
380 return _parse_plain, parts, offset
397 return _parse_plain, parts, offset
381
398
382 while offset < len(s) and s[offset] != '"':
399 while offset < len(s) and s[offset] != '"':
383 if (s[offset] == '\\' and offset + 1 < len(s)
400 if (s[offset] == '\\' and offset + 1 < len(s)
384 and s[offset + 1] == '"'):
401 and s[offset + 1] == '"'):
385 offset += 1
402 offset += 1
386 parts[-1] += '"'
403 parts[-1] += '"'
387 else:
404 else:
388 parts[-1] += s[offset]
405 parts[-1] += s[offset]
389 offset += 1
406 offset += 1
390
407
391 if offset >= len(s):
408 if offset >= len(s):
392 real_parts = _configlist(parts[-1])
409 real_parts = _configlist(parts[-1])
393 if not real_parts:
410 if not real_parts:
394 parts[-1] = '"'
411 parts[-1] = '"'
395 else:
412 else:
396 real_parts[0] = '"' + real_parts[0]
413 real_parts[0] = '"' + real_parts[0]
397 parts = parts[:-1]
414 parts = parts[:-1]
398 parts.extend(real_parts)
415 parts.extend(real_parts)
399 return None, parts, offset
416 return None, parts, offset
400
417
401 offset += 1
418 offset += 1
402 while offset < len(s) and s[offset] in [' ', ',']:
419 while offset < len(s) and s[offset] in [' ', ',']:
403 offset += 1
420 offset += 1
404
421
405 if offset < len(s):
422 if offset < len(s):
406 if offset + 1 == len(s) and s[offset] == '"':
423 if offset + 1 == len(s) and s[offset] == '"':
407 parts[-1] += '"'
424 parts[-1] += '"'
408 offset += 1
425 offset += 1
409 else:
426 else:
410 parts.append('')
427 parts.append('')
411 else:
428 else:
412 return None, parts, offset
429 return None, parts, offset
413
430
414 return _parse_plain, parts, offset
431 return _parse_plain, parts, offset
415
432
416 def _configlist(s):
433 def _configlist(s):
417 s = s.rstrip(' ,')
434 s = s.rstrip(' ,')
418 if not s:
435 if not s:
419 return []
436 return []
420 parser, parts, offset = _parse_plain, [''], 0
437 parser, parts, offset = _parse_plain, [''], 0
421 while parser:
438 while parser:
422 parser, parts, offset = parser(parts, s, offset)
439 parser, parts, offset = parser(parts, s, offset)
423 return parts
440 return parts
424
441
425 result = self.config(section, name, untrusted=untrusted)
442 result = self.config(section, name, untrusted=untrusted)
426 if result is None:
443 if result is None:
427 result = default or []
444 result = default or []
428 if isinstance(result, basestring):
445 if isinstance(result, basestring):
429 result = _configlist(result.lstrip(' ,\n'))
446 result = _configlist(result.lstrip(' ,\n'))
430 if result is None:
447 if result is None:
431 result = default or []
448 result = default or []
432 return result
449 return result
433
450
434 def has_section(self, section, untrusted=False):
451 def has_section(self, section, untrusted=False):
435 '''tell whether section exists in config.'''
452 '''tell whether section exists in config.'''
436 return section in self._data(untrusted)
453 return section in self._data(untrusted)
437
454
438 def configitems(self, section, untrusted=False):
455 def configitems(self, section, untrusted=False):
439 items = self._data(untrusted).items(section)
456 items = self._data(untrusted).items(section)
440 if self.debugflag and not untrusted and self._reportuntrusted:
457 if self.debugflag and not untrusted and self._reportuntrusted:
441 for k, v in self._ucfg.items(section):
458 for k, v in self._ucfg.items(section):
442 if self._tcfg.get(section, k) != v:
459 if self._tcfg.get(section, k) != v:
443 self.debug("ignoring untrusted configuration option "
460 self.debug("ignoring untrusted configuration option "
444 "%s.%s = %s\n" % (section, k, v))
461 "%s.%s = %s\n" % (section, k, v))
445 return items
462 return items
446
463
447 def walkconfig(self, untrusted=False):
464 def walkconfig(self, untrusted=False):
448 cfg = self._data(untrusted)
465 cfg = self._data(untrusted)
449 for section in cfg.sections():
466 for section in cfg.sections():
450 for name, value in self.configitems(section, untrusted):
467 for name, value in self.configitems(section, untrusted):
451 yield section, name, value
468 yield section, name, value
452
469
453 def plain(self, feature=None):
470 def plain(self, feature=None):
454 '''is plain mode active?
471 '''is plain mode active?
455
472
456 Plain mode means that all configuration variables which affect
473 Plain mode means that all configuration variables which affect
457 the behavior and output of Mercurial should be
474 the behavior and output of Mercurial should be
458 ignored. Additionally, the output should be stable,
475 ignored. Additionally, the output should be stable,
459 reproducible and suitable for use in scripts or applications.
476 reproducible and suitable for use in scripts or applications.
460
477
461 The only way to trigger plain mode is by setting either the
478 The only way to trigger plain mode is by setting either the
462 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
479 `HGPLAIN' or `HGPLAINEXCEPT' environment variables.
463
480
464 The return value can either be
481 The return value can either be
465 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
482 - False if HGPLAIN is not set, or feature is in HGPLAINEXCEPT
466 - True otherwise
483 - True otherwise
467 '''
484 '''
468 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
485 if 'HGPLAIN' not in os.environ and 'HGPLAINEXCEPT' not in os.environ:
469 return False
486 return False
470 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
487 exceptions = os.environ.get('HGPLAINEXCEPT', '').strip().split(',')
471 if feature and exceptions:
488 if feature and exceptions:
472 return feature not in exceptions
489 return feature not in exceptions
473 return True
490 return True
474
491
475 def username(self):
492 def username(self):
476 """Return default username to be used in commits.
493 """Return default username to be used in commits.
477
494
478 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
495 Searched in this order: $HGUSER, [ui] section of hgrcs, $EMAIL
479 and stop searching if one of these is set.
496 and stop searching if one of these is set.
480 If not found and ui.askusername is True, ask the user, else use
497 If not found and ui.askusername is True, ask the user, else use
481 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
498 ($LOGNAME or $USER or $LNAME or $USERNAME) + "@full.hostname".
482 """
499 """
483 user = os.environ.get("HGUSER")
500 user = os.environ.get("HGUSER")
484 if user is None:
501 if user is None:
485 user = self.config("ui", ["username", "user"])
502 user = self.config("ui", ["username", "user"])
486 if user is not None:
503 if user is not None:
487 user = os.path.expandvars(user)
504 user = os.path.expandvars(user)
488 if user is None:
505 if user is None:
489 user = os.environ.get("EMAIL")
506 user = os.environ.get("EMAIL")
490 if user is None and self.configbool("ui", "askusername"):
507 if user is None and self.configbool("ui", "askusername"):
491 user = self.prompt(_("enter a commit username:"), default=None)
508 user = self.prompt(_("enter a commit username:"), default=None)
492 if user is None and not self.interactive():
509 if user is None and not self.interactive():
493 try:
510 try:
494 user = '%s@%s' % (util.getuser(), socket.getfqdn())
511 user = '%s@%s' % (util.getuser(), socket.getfqdn())
495 self.warn(_("no username found, using '%s' instead\n") % user)
512 self.warn(_("no username found, using '%s' instead\n") % user)
496 except KeyError:
513 except KeyError:
497 pass
514 pass
498 if not user:
515 if not user:
499 raise util.Abort(_('no username supplied'),
516 raise util.Abort(_('no username supplied'),
500 hint=_('use "hg config --edit" '
517 hint=_('use "hg config --edit" '
501 'to set your username'))
518 'to set your username'))
502 if "\n" in user:
519 if "\n" in user:
503 raise util.Abort(_("username %s contains a newline\n") % repr(user))
520 raise util.Abort(_("username %s contains a newline\n") % repr(user))
504 return user
521 return user
505
522
506 def shortuser(self, user):
523 def shortuser(self, user):
507 """Return a short representation of a user name or email address."""
524 """Return a short representation of a user name or email address."""
508 if not self.verbose:
525 if not self.verbose:
509 user = util.shortuser(user)
526 user = util.shortuser(user)
510 return user
527 return user
511
528
512 def expandpath(self, loc, default=None):
529 def expandpath(self, loc, default=None):
513 """Return repository location relative to cwd or from [paths]"""
530 """Return repository location relative to cwd or from [paths]"""
514 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
531 if util.hasscheme(loc) or os.path.isdir(os.path.join(loc, '.hg')):
515 return loc
532 return loc
516
533
517 path = self.config('paths', loc)
534 path = self.config('paths', loc)
518 if not path and default is not None:
535 if not path and default is not None:
519 path = self.config('paths', default)
536 path = self.config('paths', default)
520 return path or loc
537 return path or loc
521
538
522 def pushbuffer(self, error=False):
539 def pushbuffer(self, error=False):
523 """install a buffer to capture standar output of the ui object
540 """install a buffer to capture standar output of the ui object
524
541
525 If error is True, the error output will be captured too."""
542 If error is True, the error output will be captured too."""
526 self._buffers.append([])
543 self._buffers.append([])
527 self._bufferstates.append(error)
544 self._bufferstates.append(error)
528
545
529 def popbuffer(self, labeled=False):
546 def popbuffer(self, labeled=False):
530 '''pop the last buffer and return the buffered output
547 '''pop the last buffer and return the buffered output
531
548
532 If labeled is True, any labels associated with buffered
549 If labeled is True, any labels associated with buffered
533 output will be handled. By default, this has no effect
550 output will be handled. By default, this has no effect
534 on the output returned, but extensions and GUI tools may
551 on the output returned, but extensions and GUI tools may
535 handle this argument and returned styled output. If output
552 handle this argument and returned styled output. If output
536 is being buffered so it can be captured and parsed or
553 is being buffered so it can be captured and parsed or
537 processed, labeled should not be set to True.
554 processed, labeled should not be set to True.
538 '''
555 '''
539 self._bufferstates.pop()
556 self._bufferstates.pop()
540 return "".join(self._buffers.pop())
557 return "".join(self._buffers.pop())
541
558
542 def write(self, *args, **opts):
559 def write(self, *args, **opts):
543 '''write args to output
560 '''write args to output
544
561
545 By default, this method simply writes to the buffer or stdout,
562 By default, this method simply writes to the buffer or stdout,
546 but extensions or GUI tools may override this method,
563 but extensions or GUI tools may override this method,
547 write_err(), popbuffer(), and label() to style output from
564 write_err(), popbuffer(), and label() to style output from
548 various parts of hg.
565 various parts of hg.
549
566
550 An optional keyword argument, "label", can be passed in.
567 An optional keyword argument, "label", can be passed in.
551 This should be a string containing label names separated by
568 This should be a string containing label names separated by
552 space. Label names take the form of "topic.type". For example,
569 space. Label names take the form of "topic.type". For example,
553 ui.debug() issues a label of "ui.debug".
570 ui.debug() issues a label of "ui.debug".
554
571
555 When labeling output for a specific command, a label of
572 When labeling output for a specific command, a label of
556 "cmdname.type" is recommended. For example, status issues
573 "cmdname.type" is recommended. For example, status issues
557 a label of "status.modified" for modified files.
574 a label of "status.modified" for modified files.
558 '''
575 '''
559 if self._buffers:
576 if self._buffers:
560 self._buffers[-1].extend([str(a) for a in args])
577 self._buffers[-1].extend([str(a) for a in args])
561 else:
578 else:
562 for a in args:
579 for a in args:
563 self.fout.write(str(a))
580 self.fout.write(str(a))
564
581
565 def write_err(self, *args, **opts):
582 def write_err(self, *args, **opts):
566 try:
583 try:
567 if self._bufferstates and self._bufferstates[-1]:
584 if self._bufferstates and self._bufferstates[-1]:
568 return self.write(*args, **opts)
585 return self.write(*args, **opts)
569 if not getattr(self.fout, 'closed', False):
586 if not getattr(self.fout, 'closed', False):
570 self.fout.flush()
587 self.fout.flush()
571 for a in args:
588 for a in args:
572 self.ferr.write(str(a))
589 self.ferr.write(str(a))
573 # stderr may be buffered under win32 when redirected to files,
590 # stderr may be buffered under win32 when redirected to files,
574 # including stdout.
591 # including stdout.
575 if not getattr(self.ferr, 'closed', False):
592 if not getattr(self.ferr, 'closed', False):
576 self.ferr.flush()
593 self.ferr.flush()
577 except IOError, inst:
594 except IOError, inst:
578 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
595 if inst.errno not in (errno.EPIPE, errno.EIO, errno.EBADF):
579 raise
596 raise
580
597
581 def flush(self):
598 def flush(self):
582 try: self.fout.flush()
599 try: self.fout.flush()
583 except (IOError, ValueError): pass
600 except (IOError, ValueError): pass
584 try: self.ferr.flush()
601 try: self.ferr.flush()
585 except (IOError, ValueError): pass
602 except (IOError, ValueError): pass
586
603
587 def _isatty(self, fh):
604 def _isatty(self, fh):
588 if self.configbool('ui', 'nontty', False):
605 if self.configbool('ui', 'nontty', False):
589 return False
606 return False
590 return util.isatty(fh)
607 return util.isatty(fh)
591
608
592 def interactive(self):
609 def interactive(self):
593 '''is interactive input allowed?
610 '''is interactive input allowed?
594
611
595 An interactive session is a session where input can be reasonably read
612 An interactive session is a session where input can be reasonably read
596 from `sys.stdin'. If this function returns false, any attempt to read
613 from `sys.stdin'. If this function returns false, any attempt to read
597 from stdin should fail with an error, unless a sensible default has been
614 from stdin should fail with an error, unless a sensible default has been
598 specified.
615 specified.
599
616
600 Interactiveness is triggered by the value of the `ui.interactive'
617 Interactiveness is triggered by the value of the `ui.interactive'
601 configuration variable or - if it is unset - when `sys.stdin' points
618 configuration variable or - if it is unset - when `sys.stdin' points
602 to a terminal device.
619 to a terminal device.
603
620
604 This function refers to input only; for output, see `ui.formatted()'.
621 This function refers to input only; for output, see `ui.formatted()'.
605 '''
622 '''
606 i = self.configbool("ui", "interactive", None)
623 i = self.configbool("ui", "interactive", None)
607 if i is None:
624 if i is None:
608 # some environments replace stdin without implementing isatty
625 # some environments replace stdin without implementing isatty
609 # usually those are non-interactive
626 # usually those are non-interactive
610 return self._isatty(self.fin)
627 return self._isatty(self.fin)
611
628
612 return i
629 return i
613
630
614 def termwidth(self):
631 def termwidth(self):
615 '''how wide is the terminal in columns?
632 '''how wide is the terminal in columns?
616 '''
633 '''
617 if 'COLUMNS' in os.environ:
634 if 'COLUMNS' in os.environ:
618 try:
635 try:
619 return int(os.environ['COLUMNS'])
636 return int(os.environ['COLUMNS'])
620 except ValueError:
637 except ValueError:
621 pass
638 pass
622 return util.termwidth()
639 return util.termwidth()
623
640
624 def formatted(self):
641 def formatted(self):
625 '''should formatted output be used?
642 '''should formatted output be used?
626
643
627 It is often desirable to format the output to suite the output medium.
644 It is often desirable to format the output to suite the output medium.
628 Examples of this are truncating long lines or colorizing messages.
645 Examples of this are truncating long lines or colorizing messages.
629 However, this is not often not desirable when piping output into other
646 However, this is not often not desirable when piping output into other
630 utilities, e.g. `grep'.
647 utilities, e.g. `grep'.
631
648
632 Formatted output is triggered by the value of the `ui.formatted'
649 Formatted output is triggered by the value of the `ui.formatted'
633 configuration variable or - if it is unset - when `sys.stdout' points
650 configuration variable or - if it is unset - when `sys.stdout' points
634 to a terminal device. Please note that `ui.formatted' should be
651 to a terminal device. Please note that `ui.formatted' should be
635 considered an implementation detail; it is not intended for use outside
652 considered an implementation detail; it is not intended for use outside
636 Mercurial or its extensions.
653 Mercurial or its extensions.
637
654
638 This function refers to output only; for input, see `ui.interactive()'.
655 This function refers to output only; for input, see `ui.interactive()'.
639 This function always returns false when in plain mode, see `ui.plain()'.
656 This function always returns false when in plain mode, see `ui.plain()'.
640 '''
657 '''
641 if self.plain():
658 if self.plain():
642 return False
659 return False
643
660
644 i = self.configbool("ui", "formatted", None)
661 i = self.configbool("ui", "formatted", None)
645 if i is None:
662 if i is None:
646 # some environments replace stdout without implementing isatty
663 # some environments replace stdout without implementing isatty
647 # usually those are non-interactive
664 # usually those are non-interactive
648 return self._isatty(self.fout)
665 return self._isatty(self.fout)
649
666
650 return i
667 return i
651
668
652 def _readline(self, prompt=''):
669 def _readline(self, prompt=''):
653 if self._isatty(self.fin):
670 if self._isatty(self.fin):
654 try:
671 try:
655 # magically add command line editing support, where
672 # magically add command line editing support, where
656 # available
673 # available
657 import readline
674 import readline
658 # force demandimport to really load the module
675 # force demandimport to really load the module
659 readline.read_history_file
676 readline.read_history_file
660 # windows sometimes raises something other than ImportError
677 # windows sometimes raises something other than ImportError
661 except Exception:
678 except Exception:
662 pass
679 pass
663
680
664 # call write() so output goes through subclassed implementation
681 # call write() so output goes through subclassed implementation
665 # e.g. color extension on Windows
682 # e.g. color extension on Windows
666 self.write(prompt)
683 self.write(prompt)
667
684
668 # instead of trying to emulate raw_input, swap (self.fin,
685 # instead of trying to emulate raw_input, swap (self.fin,
669 # self.fout) with (sys.stdin, sys.stdout)
686 # self.fout) with (sys.stdin, sys.stdout)
670 oldin = sys.stdin
687 oldin = sys.stdin
671 oldout = sys.stdout
688 oldout = sys.stdout
672 sys.stdin = self.fin
689 sys.stdin = self.fin
673 sys.stdout = self.fout
690 sys.stdout = self.fout
674 # prompt ' ' must exist; otherwise readline may delete entire line
691 # prompt ' ' must exist; otherwise readline may delete entire line
675 # - http://bugs.python.org/issue12833
692 # - http://bugs.python.org/issue12833
676 line = raw_input(' ')
693 line = raw_input(' ')
677 sys.stdin = oldin
694 sys.stdin = oldin
678 sys.stdout = oldout
695 sys.stdout = oldout
679
696
680 # When stdin is in binary mode on Windows, it can cause
697 # When stdin is in binary mode on Windows, it can cause
681 # raw_input() to emit an extra trailing carriage return
698 # raw_input() to emit an extra trailing carriage return
682 if os.linesep == '\r\n' and line and line[-1] == '\r':
699 if os.linesep == '\r\n' and line and line[-1] == '\r':
683 line = line[:-1]
700 line = line[:-1]
684 return line
701 return line
685
702
686 def prompt(self, msg, default="y"):
703 def prompt(self, msg, default="y"):
687 """Prompt user with msg, read response.
704 """Prompt user with msg, read response.
688 If ui is not interactive, the default is returned.
705 If ui is not interactive, the default is returned.
689 """
706 """
690 if not self.interactive():
707 if not self.interactive():
691 self.write(msg, ' ', default, "\n")
708 self.write(msg, ' ', default, "\n")
692 return default
709 return default
693 try:
710 try:
694 r = self._readline(self.label(msg, 'ui.prompt'))
711 r = self._readline(self.label(msg, 'ui.prompt'))
695 if not r:
712 if not r:
696 r = default
713 r = default
697 # sometimes self.interactive disagrees with isatty,
714 # sometimes self.interactive disagrees with isatty,
698 # show response provided on stdin when simulating
715 # show response provided on stdin when simulating
699 # but commandserver
716 # but commandserver
700 if (not util.isatty(self.fin)
717 if (not util.isatty(self.fin)
701 and not self.configbool('ui', 'nontty')):
718 and not self.configbool('ui', 'nontty')):
702 self.write(r, "\n")
719 self.write(r, "\n")
703 return r
720 return r
704 except EOFError:
721 except EOFError:
705 raise util.Abort(_('response expected'))
722 raise util.Abort(_('response expected'))
706
723
707 @staticmethod
724 @staticmethod
708 def extractchoices(prompt):
725 def extractchoices(prompt):
709 """Extract prompt message and list of choices from specified prompt.
726 """Extract prompt message and list of choices from specified prompt.
710
727
711 This returns tuple "(message, choices)", and "choices" is the
728 This returns tuple "(message, choices)", and "choices" is the
712 list of tuple "(response character, text without &)".
729 list of tuple "(response character, text without &)".
713 """
730 """
714 parts = prompt.split('$$')
731 parts = prompt.split('$$')
715 msg = parts[0].rstrip(' ')
732 msg = parts[0].rstrip(' ')
716 choices = [p.strip(' ') for p in parts[1:]]
733 choices = [p.strip(' ') for p in parts[1:]]
717 return (msg,
734 return (msg,
718 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
735 [(s[s.index('&') + 1].lower(), s.replace('&', '', 1))
719 for s in choices])
736 for s in choices])
720
737
721 def promptchoice(self, prompt, default=0):
738 def promptchoice(self, prompt, default=0):
722 """Prompt user with a message, read response, and ensure it matches
739 """Prompt user with a message, read response, and ensure it matches
723 one of the provided choices. The prompt is formatted as follows:
740 one of the provided choices. The prompt is formatted as follows:
724
741
725 "would you like fries with that (Yn)? $$ &Yes $$ &No"
742 "would you like fries with that (Yn)? $$ &Yes $$ &No"
726
743
727 The index of the choice is returned. Responses are case
744 The index of the choice is returned. Responses are case
728 insensitive. If ui is not interactive, the default is
745 insensitive. If ui is not interactive, the default is
729 returned.
746 returned.
730 """
747 """
731
748
732 msg, choices = self.extractchoices(prompt)
749 msg, choices = self.extractchoices(prompt)
733 resps = [r for r, t in choices]
750 resps = [r for r, t in choices]
734 while True:
751 while True:
735 r = self.prompt(msg, resps[default])
752 r = self.prompt(msg, resps[default])
736 if r.lower() in resps:
753 if r.lower() in resps:
737 return resps.index(r.lower())
754 return resps.index(r.lower())
738 self.write(_("unrecognized response\n"))
755 self.write(_("unrecognized response\n"))
739
756
740 def getpass(self, prompt=None, default=None):
757 def getpass(self, prompt=None, default=None):
741 if not self.interactive():
758 if not self.interactive():
742 return default
759 return default
743 try:
760 try:
744 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
761 self.write_err(self.label(prompt or _('password: '), 'ui.prompt'))
745 # disable getpass() only if explicitly specified. it's still valid
762 # disable getpass() only if explicitly specified. it's still valid
746 # to interact with tty even if fin is not a tty.
763 # to interact with tty even if fin is not a tty.
747 if self.configbool('ui', 'nontty'):
764 if self.configbool('ui', 'nontty'):
748 return self.fin.readline().rstrip('\n')
765 return self.fin.readline().rstrip('\n')
749 else:
766 else:
750 return getpass.getpass('')
767 return getpass.getpass('')
751 except EOFError:
768 except EOFError:
752 raise util.Abort(_('response expected'))
769 raise util.Abort(_('response expected'))
753 def status(self, *msg, **opts):
770 def status(self, *msg, **opts):
754 '''write status message to output (if ui.quiet is False)
771 '''write status message to output (if ui.quiet is False)
755
772
756 This adds an output label of "ui.status".
773 This adds an output label of "ui.status".
757 '''
774 '''
758 if not self.quiet:
775 if not self.quiet:
759 opts['label'] = opts.get('label', '') + ' ui.status'
776 opts['label'] = opts.get('label', '') + ' ui.status'
760 self.write(*msg, **opts)
777 self.write(*msg, **opts)
761 def warn(self, *msg, **opts):
778 def warn(self, *msg, **opts):
762 '''write warning message to output (stderr)
779 '''write warning message to output (stderr)
763
780
764 This adds an output label of "ui.warning".
781 This adds an output label of "ui.warning".
765 '''
782 '''
766 opts['label'] = opts.get('label', '') + ' ui.warning'
783 opts['label'] = opts.get('label', '') + ' ui.warning'
767 self.write_err(*msg, **opts)
784 self.write_err(*msg, **opts)
768 def note(self, *msg, **opts):
785 def note(self, *msg, **opts):
769 '''write note to output (if ui.verbose is True)
786 '''write note to output (if ui.verbose is True)
770
787
771 This adds an output label of "ui.note".
788 This adds an output label of "ui.note".
772 '''
789 '''
773 if self.verbose:
790 if self.verbose:
774 opts['label'] = opts.get('label', '') + ' ui.note'
791 opts['label'] = opts.get('label', '') + ' ui.note'
775 self.write(*msg, **opts)
792 self.write(*msg, **opts)
776 def debug(self, *msg, **opts):
793 def debug(self, *msg, **opts):
777 '''write debug message to output (if ui.debugflag is True)
794 '''write debug message to output (if ui.debugflag is True)
778
795
779 This adds an output label of "ui.debug".
796 This adds an output label of "ui.debug".
780 '''
797 '''
781 if self.debugflag:
798 if self.debugflag:
782 opts['label'] = opts.get('label', '') + ' ui.debug'
799 opts['label'] = opts.get('label', '') + ' ui.debug'
783 self.write(*msg, **opts)
800 self.write(*msg, **opts)
784 def edit(self, text, user, extra={}, editform=None):
801 def edit(self, text, user, extra={}, editform=None):
785 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
802 (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt",
786 text=True)
803 text=True)
787 try:
804 try:
788 f = os.fdopen(fd, "w")
805 f = os.fdopen(fd, "w")
789 f.write(text)
806 f.write(text)
790 f.close()
807 f.close()
791
808
792 environ = {'HGUSER': user}
809 environ = {'HGUSER': user}
793 if 'transplant_source' in extra:
810 if 'transplant_source' in extra:
794 environ.update({'HGREVISION': hex(extra['transplant_source'])})
811 environ.update({'HGREVISION': hex(extra['transplant_source'])})
795 for label in ('source', 'rebase_source'):
812 for label in ('source', 'rebase_source'):
796 if label in extra:
813 if label in extra:
797 environ.update({'HGREVISION': extra[label]})
814 environ.update({'HGREVISION': extra[label]})
798 break
815 break
799 if editform:
816 if editform:
800 environ.update({'HGEDITFORM': editform})
817 environ.update({'HGEDITFORM': editform})
801
818
802 editor = self.geteditor()
819 editor = self.geteditor()
803
820
804 util.system("%s \"%s\"" % (editor, name),
821 util.system("%s \"%s\"" % (editor, name),
805 environ=environ,
822 environ=environ,
806 onerr=util.Abort, errprefix=_("edit failed"),
823 onerr=util.Abort, errprefix=_("edit failed"),
807 out=self.fout)
824 out=self.fout)
808
825
809 f = open(name)
826 f = open(name)
810 t = f.read()
827 t = f.read()
811 f.close()
828 f.close()
812 finally:
829 finally:
813 os.unlink(name)
830 os.unlink(name)
814
831
815 return t
832 return t
816
833
817 def traceback(self, exc=None, force=False):
834 def traceback(self, exc=None, force=False):
818 '''print exception traceback if traceback printing enabled or forced.
835 '''print exception traceback if traceback printing enabled or forced.
819 only to call in exception handler. returns true if traceback
836 only to call in exception handler. returns true if traceback
820 printed.'''
837 printed.'''
821 if self.tracebackflag or force:
838 if self.tracebackflag or force:
822 if exc is None:
839 if exc is None:
823 exc = sys.exc_info()
840 exc = sys.exc_info()
824 cause = getattr(exc[1], 'cause', None)
841 cause = getattr(exc[1], 'cause', None)
825
842
826 if cause is not None:
843 if cause is not None:
827 causetb = traceback.format_tb(cause[2])
844 causetb = traceback.format_tb(cause[2])
828 exctb = traceback.format_tb(exc[2])
845 exctb = traceback.format_tb(exc[2])
829 exconly = traceback.format_exception_only(cause[0], cause[1])
846 exconly = traceback.format_exception_only(cause[0], cause[1])
830
847
831 # exclude frame where 'exc' was chained and rethrown from exctb
848 # exclude frame where 'exc' was chained and rethrown from exctb
832 self.write_err('Traceback (most recent call last):\n',
849 self.write_err('Traceback (most recent call last):\n',
833 ''.join(exctb[:-1]),
850 ''.join(exctb[:-1]),
834 ''.join(causetb),
851 ''.join(causetb),
835 ''.join(exconly))
852 ''.join(exconly))
836 else:
853 else:
837 traceback.print_exception(exc[0], exc[1], exc[2],
854 traceback.print_exception(exc[0], exc[1], exc[2],
838 file=self.ferr)
855 file=self.ferr)
839 return self.tracebackflag or force
856 return self.tracebackflag or force
840
857
841 def geteditor(self):
858 def geteditor(self):
842 '''return editor to use'''
859 '''return editor to use'''
843 if sys.platform == 'plan9':
860 if sys.platform == 'plan9':
844 # vi is the MIPS instruction simulator on Plan 9. We
861 # vi is the MIPS instruction simulator on Plan 9. We
845 # instead default to E to plumb commit messages to
862 # instead default to E to plumb commit messages to
846 # avoid confusion.
863 # avoid confusion.
847 editor = 'E'
864 editor = 'E'
848 else:
865 else:
849 editor = 'vi'
866 editor = 'vi'
850 return (os.environ.get("HGEDITOR") or
867 return (os.environ.get("HGEDITOR") or
851 self.config("ui", "editor") or
868 self.config("ui", "editor") or
852 os.environ.get("VISUAL") or
869 os.environ.get("VISUAL") or
853 os.environ.get("EDITOR", editor))
870 os.environ.get("EDITOR", editor))
854
871
855 def progress(self, topic, pos, item="", unit="", total=None):
872 def progress(self, topic, pos, item="", unit="", total=None):
856 '''show a progress message
873 '''show a progress message
857
874
858 With stock hg, this is simply a debug message that is hidden
875 With stock hg, this is simply a debug message that is hidden
859 by default, but with extensions or GUI tools it may be
876 by default, but with extensions or GUI tools it may be
860 visible. 'topic' is the current operation, 'item' is a
877 visible. 'topic' is the current operation, 'item' is a
861 non-numeric marker of the current position (i.e. the currently
878 non-numeric marker of the current position (i.e. the currently
862 in-process file), 'pos' is the current numeric position (i.e.
879 in-process file), 'pos' is the current numeric position (i.e.
863 revision, bytes, etc.), unit is a corresponding unit label,
880 revision, bytes, etc.), unit is a corresponding unit label,
864 and total is the highest expected pos.
881 and total is the highest expected pos.
865
882
866 Multiple nested topics may be active at a time.
883 Multiple nested topics may be active at a time.
867
884
868 All topics should be marked closed by setting pos to None at
885 All topics should be marked closed by setting pos to None at
869 termination.
886 termination.
870 '''
887 '''
871
888
872 if pos is None or not self.debugflag:
889 if pos is None or not self.debugflag:
873 return
890 return
874
891
875 if unit:
892 if unit:
876 unit = ' ' + unit
893 unit = ' ' + unit
877 if item:
894 if item:
878 item = ' ' + item
895 item = ' ' + item
879
896
880 if total:
897 if total:
881 pct = 100.0 * pos / total
898 pct = 100.0 * pos / total
882 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
899 self.debug('%s:%s %s/%s%s (%4.2f%%)\n'
883 % (topic, item, pos, total, unit, pct))
900 % (topic, item, pos, total, unit, pct))
884 else:
901 else:
885 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
902 self.debug('%s:%s %s%s\n' % (topic, item, pos, unit))
886
903
887 def log(self, service, *msg, **opts):
904 def log(self, service, *msg, **opts):
888 '''hook for logging facility extensions
905 '''hook for logging facility extensions
889
906
890 service should be a readily-identifiable subsystem, which will
907 service should be a readily-identifiable subsystem, which will
891 allow filtering.
908 allow filtering.
892 message should be a newline-terminated string to log.
909 message should be a newline-terminated string to log.
893 '''
910 '''
894 pass
911 pass
895
912
896 def label(self, msg, label):
913 def label(self, msg, label):
897 '''style msg based on supplied label
914 '''style msg based on supplied label
898
915
899 Like ui.write(), this just returns msg unchanged, but extensions
916 Like ui.write(), this just returns msg unchanged, but extensions
900 and GUI tools can override it to allow styling output without
917 and GUI tools can override it to allow styling output without
901 writing it.
918 writing it.
902
919
903 ui.write(s, 'label') is equivalent to
920 ui.write(s, 'label') is equivalent to
904 ui.write(ui.label(s, 'label')).
921 ui.write(ui.label(s, 'label')).
905 '''
922 '''
906 return msg
923 return msg
@@ -1,48 +1,48 b''
1 $ hg init a
1 $ hg init a
2
2
3 $ echo a > a/a
3 $ echo a > a/a
4 $ hg --cwd a ci -Ama
4 $ hg --cwd a ci -Ama
5 adding a
5 adding a
6
6
7 $ hg clone a c
7 $ hg clone a c
8 updating to branch default
8 updating to branch default
9 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
9 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
10
10
11 $ hg clone a b
11 $ hg clone a b
12 updating to branch default
12 updating to branch default
13 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
13 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
14
14
15 $ echo b >> b/a
15 $ echo b >> b/a
16 $ hg --cwd b ci -mb
16 $ hg --cwd b ci -mb
17
17
18 Push should provide a hint when both 'default' and 'default-push' not set:
18 Push should provide a hint when both 'default' and 'default-push' not set:
19 $ cd c
19 $ cd c
20 $ hg push --config paths.default=
20 $ hg push --config paths.default=
21 pushing to default-push
21 pushing to default-push
22 abort: default repository not configured!
22 abort: default repository not configured!
23 (see the "path" section in "hg help config")
23 (see the "path" section in "hg help config")
24 [255]
24 [255]
25
25
26 $ cd ..
26 $ cd ..
27
27
28 Push should push to 'default' when 'default-push' not set:
28 Push should push to 'default' when 'default-push' not set:
29
29
30 $ hg --cwd b push
30 $ hg --cwd b push
31 pushing to $TESTTMP/a (glob)
31 pushing to $TESTTMP/a (glob)
32 searching for changes
32 searching for changes
33 adding changesets
33 adding changesets
34 adding manifests
34 adding manifests
35 adding file changes
35 adding file changes
36 added 1 changesets with 1 changes to 1 files
36 added 1 changesets with 1 changes to 1 files
37
37
38 Push should push to 'default-push' when set:
38 Push should push to 'default-push' when set:
39
39
40 $ echo '[paths]' >> b/.hg/hgrc
40 $ echo 'default-push = ../c' >> b/.hg/hgrc
41 $ echo 'default-push = ../c' >> b/.hg/hgrc
41 $ hg --cwd b push
42 $ hg --cwd b push
42 pushing to $TESTTMP/c (glob)
43 pushing to $TESTTMP/c (glob)
43 searching for changes
44 searching for changes
44 adding changesets
45 adding changesets
45 adding manifests
46 adding manifests
46 adding file changes
47 adding file changes
47 added 1 changesets with 1 changes to 1 files
48 added 1 changesets with 1 changes to 1 files
48
@@ -1,223 +1,227 b''
1 hide outer repo
1 hide outer repo
2 $ hg init
2 $ hg init
3
3
4 Use hgrc within $TESTTMP
4 Use hgrc within $TESTTMP
5
5
6 $ HGRCPATH=`pwd`/hgrc
6 $ HGRCPATH=`pwd`/hgrc
7 $ export HGRCPATH
7 $ export HGRCPATH
8
8
9 Use an alternate var for scribbling on hgrc to keep check-code from
9 Use an alternate var for scribbling on hgrc to keep check-code from
10 complaining about the important settings we may be overwriting:
10 complaining about the important settings we may be overwriting:
11
11
12 $ HGRC=`pwd`/hgrc
12 $ HGRC=`pwd`/hgrc
13 $ export HGRC
13 $ export HGRC
14
14
15 Basic syntax error
15 Basic syntax error
16
16
17 $ echo "invalid" > $HGRC
17 $ echo "invalid" > $HGRC
18 $ hg version
18 $ hg version
19 hg: parse error at $TESTTMP/hgrc:1: invalid
19 hg: parse error at $TESTTMP/hgrc:1: invalid
20 [255]
20 [255]
21 $ echo "" > $HGRC
21 $ echo "" > $HGRC
22
22
23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
23 Issue1199: Can't use '%' in hgrc (eg url encoded username)
24
24
25 $ hg init "foo%bar"
25 $ hg init "foo%bar"
26 $ hg clone "foo%bar" foobar
26 $ hg clone "foo%bar" foobar
27 updating to branch default
27 updating to branch default
28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
29 $ cd foobar
29 $ cd foobar
30 $ cat .hg/hgrc
30 $ cat .hg/hgrc
31 # You may want to set your username here if it is not set
31 # example repository config (see "hg help config" for more info)
32 # globally, or this repository requires a different
32 [paths]
33 # username from your usual configuration. If you want to
33 default = $TESTTMP/foo%bar
34 # set something for all of your repositories on this
34
35 # computer, try running the command
35 # path aliases to other clones of this repo in URLs or filesystem paths
36 # 'hg config --edit --global'
36 # (see "hg help config.paths" for more info)
37 # [ui]
37 #
38 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
39 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
40 # my-clone = /home/jdoe/jdoes-clone
41
42 [ui]
43 # name and email (local to this repository, optional), e.g.
38 # username = Jane Doe <jdoe@example.com>
44 # username = Jane Doe <jdoe@example.com>
39 [paths]
40 default = $TESTTMP/foo%bar (glob)
41 $ hg paths
45 $ hg paths
42 default = $TESTTMP/foo%bar (glob)
46 default = $TESTTMP/foo%bar (glob)
43 $ hg showconfig
47 $ hg showconfig
44 bundle.mainreporoot=$TESTTMP/foobar (glob)
48 bundle.mainreporoot=$TESTTMP/foobar (glob)
45 paths.default=$TESTTMP/foo%bar (glob)
49 paths.default=$TESTTMP/foo%bar (glob)
46 $ cd ..
50 $ cd ..
47
51
48 issue1829: wrong indentation
52 issue1829: wrong indentation
49
53
50 $ echo '[foo]' > $HGRC
54 $ echo '[foo]' > $HGRC
51 $ echo ' x = y' >> $HGRC
55 $ echo ' x = y' >> $HGRC
52 $ hg version
56 $ hg version
53 hg: parse error at $TESTTMP/hgrc:2: x = y
57 hg: parse error at $TESTTMP/hgrc:2: x = y
54 unexpected leading whitespace
58 unexpected leading whitespace
55 [255]
59 [255]
56
60
57 $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
61 $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
58 > > $HGRC
62 > > $HGRC
59 $ hg showconfig foo
63 $ hg showconfig foo
60 foo.bar=a\nb\nc\nde\nfg
64 foo.bar=a\nb\nc\nde\nfg
61 foo.baz=bif cb
65 foo.baz=bif cb
62
66
63 $ FAKEPATH=/path/to/nowhere
67 $ FAKEPATH=/path/to/nowhere
64 $ export FAKEPATH
68 $ export FAKEPATH
65 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
69 $ echo '%include $FAKEPATH/no-such-file' > $HGRC
66 $ hg version
70 $ hg version
67 Mercurial Distributed SCM (version *) (glob)
71 Mercurial Distributed SCM (version *) (glob)
68 (see http://mercurial.selenic.com for more information)
72 (see http://mercurial.selenic.com for more information)
69
73
70 Copyright (C) 2005-2014 Matt Mackall and others
74 Copyright (C) 2005-2014 Matt Mackall and others
71 This is free software; see the source for copying conditions. There is NO
75 This is free software; see the source for copying conditions. There is NO
72 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
76 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
73 $ unset FAKEPATH
77 $ unset FAKEPATH
74
78
75 make sure global options given on the cmdline take precedence
79 make sure global options given on the cmdline take precedence
76
80
77 $ hg showconfig --config ui.verbose=True --quiet
81 $ hg showconfig --config ui.verbose=True --quiet
78 bundle.mainreporoot=$TESTTMP
82 bundle.mainreporoot=$TESTTMP
79 ui.verbose=False
83 ui.verbose=False
80 ui.debug=False
84 ui.debug=False
81 ui.quiet=True
85 ui.quiet=True
82
86
83 $ touch foobar/untracked
87 $ touch foobar/untracked
84 $ cat >> foobar/.hg/hgrc <<EOF
88 $ cat >> foobar/.hg/hgrc <<EOF
85 > [ui]
89 > [ui]
86 > verbose=True
90 > verbose=True
87 > EOF
91 > EOF
88 $ hg -R foobar st -q
92 $ hg -R foobar st -q
89
93
90 username expansion
94 username expansion
91
95
92 $ olduser=$HGUSER
96 $ olduser=$HGUSER
93 $ unset HGUSER
97 $ unset HGUSER
94
98
95 $ FAKEUSER='John Doe'
99 $ FAKEUSER='John Doe'
96 $ export FAKEUSER
100 $ export FAKEUSER
97 $ echo '[ui]' > $HGRC
101 $ echo '[ui]' > $HGRC
98 $ echo 'username = $FAKEUSER' >> $HGRC
102 $ echo 'username = $FAKEUSER' >> $HGRC
99
103
100 $ hg init usertest
104 $ hg init usertest
101 $ cd usertest
105 $ cd usertest
102 $ touch bar
106 $ touch bar
103 $ hg commit --addremove --quiet -m "added bar"
107 $ hg commit --addremove --quiet -m "added bar"
104 $ hg log --template "{author}\n"
108 $ hg log --template "{author}\n"
105 John Doe
109 John Doe
106 $ cd ..
110 $ cd ..
107
111
108 $ hg showconfig
112 $ hg showconfig
109 bundle.mainreporoot=$TESTTMP
113 bundle.mainreporoot=$TESTTMP
110 ui.username=$FAKEUSER
114 ui.username=$FAKEUSER
111
115
112 $ unset FAKEUSER
116 $ unset FAKEUSER
113 $ HGUSER=$olduser
117 $ HGUSER=$olduser
114 $ export HGUSER
118 $ export HGUSER
115
119
116 showconfig with multiple arguments
120 showconfig with multiple arguments
117
121
118 $ echo "[alias]" > $HGRC
122 $ echo "[alias]" > $HGRC
119 $ echo "log = log -g" >> $HGRC
123 $ echo "log = log -g" >> $HGRC
120 $ echo "[defaults]" >> $HGRC
124 $ echo "[defaults]" >> $HGRC
121 $ echo "identify = -n" >> $HGRC
125 $ echo "identify = -n" >> $HGRC
122 $ hg showconfig alias defaults
126 $ hg showconfig alias defaults
123 alias.log=log -g
127 alias.log=log -g
124 defaults.identify=-n
128 defaults.identify=-n
125 $ hg showconfig alias defaults.identify
129 $ hg showconfig alias defaults.identify
126 abort: only one config item permitted
130 abort: only one config item permitted
127 [255]
131 [255]
128 $ hg showconfig alias.log defaults.identify
132 $ hg showconfig alias.log defaults.identify
129 abort: only one config item permitted
133 abort: only one config item permitted
130 [255]
134 [255]
131
135
132 HGPLAIN
136 HGPLAIN
133
137
134 $ echo "[ui]" > $HGRC
138 $ echo "[ui]" > $HGRC
135 $ echo "debug=true" >> $HGRC
139 $ echo "debug=true" >> $HGRC
136 $ echo "fallbackencoding=ASCII" >> $HGRC
140 $ echo "fallbackencoding=ASCII" >> $HGRC
137 $ echo "quiet=true" >> $HGRC
141 $ echo "quiet=true" >> $HGRC
138 $ echo "slash=true" >> $HGRC
142 $ echo "slash=true" >> $HGRC
139 $ echo "traceback=true" >> $HGRC
143 $ echo "traceback=true" >> $HGRC
140 $ echo "verbose=true" >> $HGRC
144 $ echo "verbose=true" >> $HGRC
141 $ echo "style=~/.hgstyle" >> $HGRC
145 $ echo "style=~/.hgstyle" >> $HGRC
142 $ echo "logtemplate={node}" >> $HGRC
146 $ echo "logtemplate={node}" >> $HGRC
143 $ echo "[defaults]" >> $HGRC
147 $ echo "[defaults]" >> $HGRC
144 $ echo "identify=-n" >> $HGRC
148 $ echo "identify=-n" >> $HGRC
145 $ echo "[alias]" >> $HGRC
149 $ echo "[alias]" >> $HGRC
146 $ echo "log=log -g" >> $HGRC
150 $ echo "log=log -g" >> $HGRC
147
151
148 customized hgrc
152 customized hgrc
149
153
150 $ hg showconfig
154 $ hg showconfig
151 read config from: $TESTTMP/hgrc
155 read config from: $TESTTMP/hgrc
152 $TESTTMP/hgrc:13: alias.log=log -g
156 $TESTTMP/hgrc:13: alias.log=log -g
153 repo: bundle.mainreporoot=$TESTTMP
157 repo: bundle.mainreporoot=$TESTTMP
154 $TESTTMP/hgrc:11: defaults.identify=-n
158 $TESTTMP/hgrc:11: defaults.identify=-n
155 $TESTTMP/hgrc:2: ui.debug=true
159 $TESTTMP/hgrc:2: ui.debug=true
156 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
160 $TESTTMP/hgrc:3: ui.fallbackencoding=ASCII
157 $TESTTMP/hgrc:4: ui.quiet=true
161 $TESTTMP/hgrc:4: ui.quiet=true
158 $TESTTMP/hgrc:5: ui.slash=true
162 $TESTTMP/hgrc:5: ui.slash=true
159 $TESTTMP/hgrc:6: ui.traceback=true
163 $TESTTMP/hgrc:6: ui.traceback=true
160 $TESTTMP/hgrc:7: ui.verbose=true
164 $TESTTMP/hgrc:7: ui.verbose=true
161 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
165 $TESTTMP/hgrc:8: ui.style=~/.hgstyle
162 $TESTTMP/hgrc:9: ui.logtemplate={node}
166 $TESTTMP/hgrc:9: ui.logtemplate={node}
163
167
164 plain hgrc
168 plain hgrc
165
169
166 $ HGPLAIN=; export HGPLAIN
170 $ HGPLAIN=; export HGPLAIN
167 $ hg showconfig --config ui.traceback=True --debug
171 $ hg showconfig --config ui.traceback=True --debug
168 read config from: $TESTTMP/hgrc
172 read config from: $TESTTMP/hgrc
169 repo: bundle.mainreporoot=$TESTTMP
173 repo: bundle.mainreporoot=$TESTTMP
170 --config: ui.traceback=True
174 --config: ui.traceback=True
171 --verbose: ui.verbose=False
175 --verbose: ui.verbose=False
172 --debug: ui.debug=True
176 --debug: ui.debug=True
173 --quiet: ui.quiet=False
177 --quiet: ui.quiet=False
174
178
175 plain mode with exceptions
179 plain mode with exceptions
176
180
177 $ cat > plain.py <<EOF
181 $ cat > plain.py <<EOF
178 > def uisetup(ui):
182 > def uisetup(ui):
179 > ui.write('plain: %r\n' % ui.plain())
183 > ui.write('plain: %r\n' % ui.plain())
180 > EOF
184 > EOF
181 $ echo "[extensions]" >> $HGRC
185 $ echo "[extensions]" >> $HGRC
182 $ echo "plain=./plain.py" >> $HGRC
186 $ echo "plain=./plain.py" >> $HGRC
183 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
187 $ HGPLAINEXCEPT=; export HGPLAINEXCEPT
184 $ hg showconfig --config ui.traceback=True --debug
188 $ hg showconfig --config ui.traceback=True --debug
185 plain: True
189 plain: True
186 read config from: $TESTTMP/hgrc
190 read config from: $TESTTMP/hgrc
187 repo: bundle.mainreporoot=$TESTTMP
191 repo: bundle.mainreporoot=$TESTTMP
188 $TESTTMP/hgrc:15: extensions.plain=./plain.py
192 $TESTTMP/hgrc:15: extensions.plain=./plain.py
189 --config: ui.traceback=True
193 --config: ui.traceback=True
190 --verbose: ui.verbose=False
194 --verbose: ui.verbose=False
191 --debug: ui.debug=True
195 --debug: ui.debug=True
192 --quiet: ui.quiet=False
196 --quiet: ui.quiet=False
193 $ unset HGPLAIN
197 $ unset HGPLAIN
194 $ hg showconfig --config ui.traceback=True --debug
198 $ hg showconfig --config ui.traceback=True --debug
195 plain: True
199 plain: True
196 read config from: $TESTTMP/hgrc
200 read config from: $TESTTMP/hgrc
197 repo: bundle.mainreporoot=$TESTTMP
201 repo: bundle.mainreporoot=$TESTTMP
198 $TESTTMP/hgrc:15: extensions.plain=./plain.py
202 $TESTTMP/hgrc:15: extensions.plain=./plain.py
199 --config: ui.traceback=True
203 --config: ui.traceback=True
200 --verbose: ui.verbose=False
204 --verbose: ui.verbose=False
201 --debug: ui.debug=True
205 --debug: ui.debug=True
202 --quiet: ui.quiet=False
206 --quiet: ui.quiet=False
203 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
207 $ HGPLAINEXCEPT=i18n; export HGPLAINEXCEPT
204 $ hg showconfig --config ui.traceback=True --debug
208 $ hg showconfig --config ui.traceback=True --debug
205 plain: True
209 plain: True
206 read config from: $TESTTMP/hgrc
210 read config from: $TESTTMP/hgrc
207 repo: bundle.mainreporoot=$TESTTMP
211 repo: bundle.mainreporoot=$TESTTMP
208 $TESTTMP/hgrc:15: extensions.plain=./plain.py
212 $TESTTMP/hgrc:15: extensions.plain=./plain.py
209 --config: ui.traceback=True
213 --config: ui.traceback=True
210 --verbose: ui.verbose=False
214 --verbose: ui.verbose=False
211 --debug: ui.debug=True
215 --debug: ui.debug=True
212 --quiet: ui.quiet=False
216 --quiet: ui.quiet=False
213
217
214 source of paths is not mangled
218 source of paths is not mangled
215
219
216 $ cat >> $HGRCPATH <<EOF
220 $ cat >> $HGRCPATH <<EOF
217 > [paths]
221 > [paths]
218 > foo = bar
222 > foo = bar
219 > EOF
223 > EOF
220 $ hg showconfig --debug paths
224 $ hg showconfig --debug paths
221 plain: True
225 plain: True
222 read config from: $TESTTMP/hgrc
226 read config from: $TESTTMP/hgrc
223 $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar
227 $TESTTMP/hgrc:17: paths.foo=$TESTTMP/bar
@@ -1,71 +1,75 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -Ama
6 $ hg ci -Ama
7 adding a
7 adding a
8 $ cd ..
8 $ cd ..
9 $ hg clone test test2
9 $ hg clone test test2
10 updating to branch default
10 updating to branch default
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 $ cd test2
12 $ cd test2
13 $ echo a >> a
13 $ echo a >> a
14 $ hg ci -mb
14 $ hg ci -mb
15
15
16 Cloning with a password in the URL should not save the password in .hg/hgrc:
16 Cloning with a password in the URL should not save the password in .hg/hgrc:
17
17
18 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
18 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
19 $ cat hg.pid >> $DAEMON_PIDS
19 $ cat hg.pid >> $DAEMON_PIDS
20 $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
20 $ hg clone http://foo:xyzzy@localhost:$HGPORT/ test3
21 requesting all changes
21 requesting all changes
22 adding changesets
22 adding changesets
23 adding manifests
23 adding manifests
24 adding file changes
24 adding file changes
25 added 2 changesets with 2 changes to 1 files
25 added 2 changesets with 2 changes to 1 files
26 updating to branch default
26 updating to branch default
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
27 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
28 $ cat test3/.hg/hgrc
28 $ cat test3/.hg/hgrc
29 # You may want to set your username here if it is not set
29 # example repository config (see "hg help config" for more info)
30 # globally, or this repository requires a different
31 # username from your usual configuration. If you want to
32 # set something for all of your repositories on this
33 # computer, try running the command
34 # 'hg config --edit --global'
35 # [ui]
36 # username = Jane Doe <jdoe@example.com>
37 [paths]
30 [paths]
38 default = http://foo@localhost:$HGPORT/
31 default = http://foo@localhost:$HGPORT/
32
33 # path aliases to other clones of this repo in URLs or filesystem paths
34 # (see "hg help config.paths" for more info)
35 #
36 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
37 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
38 # my-clone = /home/jdoe/jdoes-clone
39
40 [ui]
41 # name and email (local to this repository, optional), e.g.
42 # username = Jane Doe <jdoe@example.com>
39 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
43 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
40
44
41 expect error, cloning not allowed
45 expect error, cloning not allowed
42
46
43 $ echo '[web]' > .hg/hgrc
47 $ echo '[web]' > .hg/hgrc
44 $ echo 'allowpull = false' >> .hg/hgrc
48 $ echo 'allowpull = false' >> .hg/hgrc
45 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
49 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
46 $ cat hg.pid >> $DAEMON_PIDS
50 $ cat hg.pid >> $DAEMON_PIDS
47 $ hg clone http://localhost:$HGPORT/ test4
51 $ hg clone http://localhost:$HGPORT/ test4
48 abort: authorization failed
52 abort: authorization failed
49 [255]
53 [255]
50 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
54 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
51
55
52 serve errors
56 serve errors
53
57
54 $ cat errors.log
58 $ cat errors.log
55 $ req() {
59 $ req() {
56 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
60 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
57 > cat hg.pid >> $DAEMON_PIDS
61 > cat hg.pid >> $DAEMON_PIDS
58 > hg --cwd ../test pull http://localhost:$HGPORT/
62 > hg --cwd ../test pull http://localhost:$HGPORT/
59 > "$TESTDIR/killdaemons.py" hg.pid
63 > "$TESTDIR/killdaemons.py" hg.pid
60 > echo % serve errors
64 > echo % serve errors
61 > cat errors.log
65 > cat errors.log
62 > }
66 > }
63
67
64 expect error, pulling not allowed
68 expect error, pulling not allowed
65
69
66 $ req
70 $ req
67 pulling from http://localhost:$HGPORT/
71 pulling from http://localhost:$HGPORT/
68 abort: authorization failed
72 abort: authorization failed
69 % serve errors
73 % serve errors
70
74
71 $ cd ..
75 $ cd ..
@@ -1,107 +1,116 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [alias]
2 > [alias]
3 > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
3 > tlog = log --template "{rev}:{node|short}: '{desc}' {branches}\n"
4 > tglog = tlog -G
4 > tglog = tlog -G
5 > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
5 > tout = out --template "{rev}:{node|short}: '{desc}' {branches}\n"
6 > EOF
6 > EOF
7
7
8 $ hg init a
8 $ hg init a
9 $ cd a
9 $ cd a
10
10
11 $ echo a > a
11 $ echo a > a
12 $ hg ci -Aqm0
12 $ hg ci -Aqm0
13
13
14 $ echo foo >> a
14 $ echo foo >> a
15 $ hg ci -Aqm1
15 $ hg ci -Aqm1
16
16
17 $ hg up -q 0
17 $ hg up -q 0
18
18
19 $ hg branch stable
19 $ hg branch stable
20 marked working directory as branch stable
20 marked working directory as branch stable
21 (branches are permanent and global, did you want a bookmark?)
21 (branches are permanent and global, did you want a bookmark?)
22 $ echo bar >> a
22 $ echo bar >> a
23 $ hg ci -qm2
23 $ hg ci -qm2
24
24
25 $ hg tglog
25 $ hg tglog
26 @ 2:7bee6c3bea3a: '2' stable
26 @ 2:7bee6c3bea3a: '2' stable
27 |
27 |
28 | o 1:3560197d8331: '1'
28 | o 1:3560197d8331: '1'
29 |/
29 |/
30 o 0:f7b1eb17ad24: '0'
30 o 0:f7b1eb17ad24: '0'
31
31
32
32
33 $ cd ..
33 $ cd ..
34
34
35 $ hg clone -q a#stable b
35 $ hg clone -q a#stable b
36
36
37 $ cd b
37 $ cd b
38 $ cat .hg/hgrc
38 $ cat .hg/hgrc
39 # You may want to set your username here if it is not set
39 # example repository config (see "hg help config" for more info)
40 # globally, or this repository requires a different
40 [paths]
41 # username from your usual configuration. If you want to
41 default = $TESTTMP/a#stable
42 # set something for all of your repositories on this
42
43 # computer, try running the command
43 # path aliases to other clones of this repo in URLs or filesystem paths
44 # 'hg config --edit --global'
44 # (see "hg help config.paths" for more info)
45 # [ui]
45 #
46 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
47 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
48 # my-clone = /home/jdoe/jdoes-clone
49
50 [ui]
51 # name and email (local to this repository, optional), e.g.
46 # username = Jane Doe <jdoe@example.com>
52 # username = Jane Doe <jdoe@example.com>
47 [paths]
48 default = $TESTTMP/a#stable (glob)
49
53
50 $ echo red >> a
54 $ echo red >> a
51 $ hg ci -qm3
55 $ hg ci -qm3
52
56
53 $ hg up -q default
57 $ hg up -q default
54
58
55 $ echo blue >> a
59 $ echo blue >> a
56 $ hg ci -qm4
60 $ hg ci -qm4
57
61
58 $ hg tglog
62 $ hg tglog
59 @ 3:f0461977a3db: '4'
63 @ 3:f0461977a3db: '4'
60 |
64 |
61 | o 2:1d4099801a4e: '3' stable
65 | o 2:1d4099801a4e: '3' stable
62 | |
66 | |
63 | o 1:7bee6c3bea3a: '2' stable
67 | o 1:7bee6c3bea3a: '2' stable
64 |/
68 |/
65 o 0:f7b1eb17ad24: '0'
69 o 0:f7b1eb17ad24: '0'
66
70
67
71
68 $ hg tout
72 $ hg tout
69 comparing with $TESTTMP/a (glob)
73 comparing with $TESTTMP/a (glob)
70 searching for changes
74 searching for changes
71 2:1d4099801a4e: '3' stable
75 2:1d4099801a4e: '3' stable
72
76
73 $ hg tlog -r 'outgoing()'
77 $ hg tlog -r 'outgoing()'
74 2:1d4099801a4e: '3' stable
78 2:1d4099801a4e: '3' stable
75
79
76 $ hg tout ../a#default
80 $ hg tout ../a#default
77 comparing with ../a
81 comparing with ../a
78 searching for changes
82 searching for changes
79 3:f0461977a3db: '4'
83 3:f0461977a3db: '4'
80
84
81 $ hg tlog -r 'outgoing("../a#default")'
85 $ hg tlog -r 'outgoing("../a#default")'
82 3:f0461977a3db: '4'
86 3:f0461977a3db: '4'
83
87
84 $ echo "green = ../a#default" >> .hg/hgrc
88 $ echo "green = ../a#default" >> .hg/hgrc
85
89
86 $ cat .hg/hgrc
90 $ cat .hg/hgrc
87 # You may want to set your username here if it is not set
91 # example repository config (see "hg help config" for more info)
88 # globally, or this repository requires a different
92 [paths]
89 # username from your usual configuration. If you want to
93 default = $TESTTMP/a#stable
90 # set something for all of your repositories on this
94
91 # computer, try running the command
95 # path aliases to other clones of this repo in URLs or filesystem paths
92 # 'hg config --edit --global'
96 # (see "hg help config.paths" for more info)
93 # [ui]
97 #
98 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
99 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
100 # my-clone = /home/jdoe/jdoes-clone
101
102 [ui]
103 # name and email (local to this repository, optional), e.g.
94 # username = Jane Doe <jdoe@example.com>
104 # username = Jane Doe <jdoe@example.com>
95 [paths]
96 default = $TESTTMP/a#stable (glob)
97 green = ../a#default
105 green = ../a#default
98
106
99 $ hg tout green
107 $ hg tout green
100 comparing with $TESTTMP/a (glob)
108 comparing with green
101 searching for changes
109 abort: repository green not found!
102 3:f0461977a3db: '4'
110 [255]
103
111
104 $ hg tlog -r 'outgoing("green")'
112 $ hg tlog -r 'outgoing("green")'
105 3:f0461977a3db: '4'
113 abort: repository green not found!
114 [255]
106
115
107 $ cd ..
116 $ cd ..
@@ -1,312 +1,316 b''
1 Test basic functionality of url#rev syntax
1 Test basic functionality of url#rev syntax
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -qAm 'add a'
6 $ hg ci -qAm 'add a'
7 $ hg branch foo
7 $ hg branch foo
8 marked working directory as branch foo
8 marked working directory as branch foo
9 (branches are permanent and global, did you want a bookmark?)
9 (branches are permanent and global, did you want a bookmark?)
10 $ echo >> a
10 $ echo >> a
11 $ hg ci -m 'change a'
11 $ hg ci -m 'change a'
12 $ cd ..
12 $ cd ..
13
13
14 $ hg clone 'repo#foo' clone
14 $ hg clone 'repo#foo' clone
15 adding changesets
15 adding changesets
16 adding manifests
16 adding manifests
17 adding file changes
17 adding file changes
18 added 2 changesets with 2 changes to 1 files
18 added 2 changesets with 2 changes to 1 files
19 updating to branch foo
19 updating to branch foo
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21
21
22 $ hg --cwd clone heads
22 $ hg --cwd clone heads
23 changeset: 1:cd2a86ecc814
23 changeset: 1:cd2a86ecc814
24 branch: foo
24 branch: foo
25 tag: tip
25 tag: tip
26 user: test
26 user: test
27 date: Thu Jan 01 00:00:00 1970 +0000
27 date: Thu Jan 01 00:00:00 1970 +0000
28 summary: change a
28 summary: change a
29
29
30 changeset: 0:1f0dee641bb7
30 changeset: 0:1f0dee641bb7
31 user: test
31 user: test
32 date: Thu Jan 01 00:00:00 1970 +0000
32 date: Thu Jan 01 00:00:00 1970 +0000
33 summary: add a
33 summary: add a
34
34
35 $ hg --cwd clone parents
35 $ hg --cwd clone parents
36 changeset: 1:cd2a86ecc814
36 changeset: 1:cd2a86ecc814
37 branch: foo
37 branch: foo
38 tag: tip
38 tag: tip
39 user: test
39 user: test
40 date: Thu Jan 01 00:00:00 1970 +0000
40 date: Thu Jan 01 00:00:00 1970 +0000
41 summary: change a
41 summary: change a
42
42
43 $ cat clone/.hg/hgrc
43 $ cat clone/.hg/hgrc
44 # You may want to set your username here if it is not set
44 # example repository config (see "hg help config" for more info)
45 # globally, or this repository requires a different
45 [paths]
46 # username from your usual configuration. If you want to
46 default = $TESTTMP/repo#foo
47 # set something for all of your repositories on this
47
48 # computer, try running the command
48 # path aliases to other clones of this repo in URLs or filesystem paths
49 # 'hg config --edit --global'
49 # (see "hg help config.paths" for more info)
50 # [ui]
50 #
51 # default-push = ssh://jdoe@example.net/hg/jdoes-fork
52 # my-fork = ssh://jdoe@example.net/hg/jdoes-fork
53 # my-clone = /home/jdoe/jdoes-clone
54
55 [ui]
56 # name and email (local to this repository, optional), e.g.
51 # username = Jane Doe <jdoe@example.com>
57 # username = Jane Doe <jdoe@example.com>
52 [paths]
53 default = $TESTTMP/repo#foo (glob)
54
58
55 Changing original repo:
59 Changing original repo:
56
60
57 $ cd repo
61 $ cd repo
58
62
59 $ echo >> a
63 $ echo >> a
60 $ hg ci -m 'new head of branch foo'
64 $ hg ci -m 'new head of branch foo'
61
65
62 $ hg up -qC default
66 $ hg up -qC default
63 $ echo bar > bar
67 $ echo bar > bar
64 $ hg ci -qAm 'add bar'
68 $ hg ci -qAm 'add bar'
65
69
66 $ hg log
70 $ hg log
67 changeset: 3:4cd725637392
71 changeset: 3:4cd725637392
68 tag: tip
72 tag: tip
69 parent: 0:1f0dee641bb7
73 parent: 0:1f0dee641bb7
70 user: test
74 user: test
71 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
72 summary: add bar
76 summary: add bar
73
77
74 changeset: 2:faba9097cad4
78 changeset: 2:faba9097cad4
75 branch: foo
79 branch: foo
76 user: test
80 user: test
77 date: Thu Jan 01 00:00:00 1970 +0000
81 date: Thu Jan 01 00:00:00 1970 +0000
78 summary: new head of branch foo
82 summary: new head of branch foo
79
83
80 changeset: 1:cd2a86ecc814
84 changeset: 1:cd2a86ecc814
81 branch: foo
85 branch: foo
82 user: test
86 user: test
83 date: Thu Jan 01 00:00:00 1970 +0000
87 date: Thu Jan 01 00:00:00 1970 +0000
84 summary: change a
88 summary: change a
85
89
86 changeset: 0:1f0dee641bb7
90 changeset: 0:1f0dee641bb7
87 user: test
91 user: test
88 date: Thu Jan 01 00:00:00 1970 +0000
92 date: Thu Jan 01 00:00:00 1970 +0000
89 summary: add a
93 summary: add a
90
94
91 $ hg -q outgoing '../clone'
95 $ hg -q outgoing '../clone'
92 2:faba9097cad4
96 2:faba9097cad4
93 3:4cd725637392
97 3:4cd725637392
94 $ hg summary --remote --config paths.default='../clone'
98 $ hg summary --remote --config paths.default='../clone'
95 parent: 3:4cd725637392 tip
99 parent: 3:4cd725637392 tip
96 add bar
100 add bar
97 branch: default
101 branch: default
98 commit: (clean)
102 commit: (clean)
99 update: (current)
103 update: (current)
100 remote: 2 outgoing
104 remote: 2 outgoing
101 $ hg -q outgoing '../clone#foo'
105 $ hg -q outgoing '../clone#foo'
102 2:faba9097cad4
106 2:faba9097cad4
103 $ hg summary --remote --config paths.default='../clone#foo'
107 $ hg summary --remote --config paths.default='../clone#foo'
104 parent: 3:4cd725637392 tip
108 parent: 3:4cd725637392 tip
105 add bar
109 add bar
106 branch: default
110 branch: default
107 commit: (clean)
111 commit: (clean)
108 update: (current)
112 update: (current)
109 remote: 1 outgoing
113 remote: 1 outgoing
110
114
111 $ hg -q --cwd ../clone incoming '../repo#foo'
115 $ hg -q --cwd ../clone incoming '../repo#foo'
112 2:faba9097cad4
116 2:faba9097cad4
113 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
117 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
114 parent: 1:cd2a86ecc814 tip
118 parent: 1:cd2a86ecc814 tip
115 change a
119 change a
116 branch: foo
120 branch: foo
117 commit: (clean)
121 commit: (clean)
118 update: (current)
122 update: (current)
119 remote: 1 or more incoming
123 remote: 1 or more incoming
120
124
121 $ hg -q push '../clone#foo'
125 $ hg -q push '../clone#foo'
122
126
123 $ hg --cwd ../clone heads
127 $ hg --cwd ../clone heads
124 changeset: 2:faba9097cad4
128 changeset: 2:faba9097cad4
125 branch: foo
129 branch: foo
126 tag: tip
130 tag: tip
127 user: test
131 user: test
128 date: Thu Jan 01 00:00:00 1970 +0000
132 date: Thu Jan 01 00:00:00 1970 +0000
129 summary: new head of branch foo
133 summary: new head of branch foo
130
134
131 changeset: 0:1f0dee641bb7
135 changeset: 0:1f0dee641bb7
132 user: test
136 user: test
133 date: Thu Jan 01 00:00:00 1970 +0000
137 date: Thu Jan 01 00:00:00 1970 +0000
134 summary: add a
138 summary: add a
135
139
136 $ hg -q --cwd ../clone incoming '../repo#foo'
140 $ hg -q --cwd ../clone incoming '../repo#foo'
137 [1]
141 [1]
138 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
142 $ hg --cwd ../clone summary --remote --config paths.default='../repo#foo'
139 parent: 1:cd2a86ecc814
143 parent: 1:cd2a86ecc814
140 change a
144 change a
141 branch: foo
145 branch: foo
142 commit: (clean)
146 commit: (clean)
143 update: 1 new changesets (update)
147 update: 1 new changesets (update)
144 remote: (synced)
148 remote: (synced)
145
149
146 $ cd ..
150 $ cd ..
147
151
148 $ cd clone
152 $ cd clone
149 $ hg rollback
153 $ hg rollback
150 repository tip rolled back to revision 1 (undo push)
154 repository tip rolled back to revision 1 (undo push)
151
155
152 $ hg -q incoming
156 $ hg -q incoming
153 2:faba9097cad4
157 2:faba9097cad4
154
158
155 $ hg -q pull
159 $ hg -q pull
156
160
157 $ hg heads
161 $ hg heads
158 changeset: 2:faba9097cad4
162 changeset: 2:faba9097cad4
159 branch: foo
163 branch: foo
160 tag: tip
164 tag: tip
161 user: test
165 user: test
162 date: Thu Jan 01 00:00:00 1970 +0000
166 date: Thu Jan 01 00:00:00 1970 +0000
163 summary: new head of branch foo
167 summary: new head of branch foo
164
168
165 changeset: 0:1f0dee641bb7
169 changeset: 0:1f0dee641bb7
166 user: test
170 user: test
167 date: Thu Jan 01 00:00:00 1970 +0000
171 date: Thu Jan 01 00:00:00 1970 +0000
168 summary: add a
172 summary: add a
169
173
170 Pull should not have updated:
174 Pull should not have updated:
171
175
172 $ hg parents -q
176 $ hg parents -q
173 1:cd2a86ecc814
177 1:cd2a86ecc814
174
178
175 Going back to the default branch:
179 Going back to the default branch:
176
180
177 $ hg up -C 0
181 $ hg up -C 0
178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
182 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
179
183
180 $ hg parents
184 $ hg parents
181 changeset: 0:1f0dee641bb7
185 changeset: 0:1f0dee641bb7
182 user: test
186 user: test
183 date: Thu Jan 01 00:00:00 1970 +0000
187 date: Thu Jan 01 00:00:00 1970 +0000
184 summary: add a
188 summary: add a
185
189
186 No new revs, no update:
190 No new revs, no update:
187
191
188 $ hg pull -qu
192 $ hg pull -qu
189
193
190 $ hg parents -q
194 $ hg parents -q
191 0:1f0dee641bb7
195 0:1f0dee641bb7
192
196
193 $ hg rollback
197 $ hg rollback
194 repository tip rolled back to revision 1 (undo pull)
198 repository tip rolled back to revision 1 (undo pull)
195
199
196 $ hg parents -q
200 $ hg parents -q
197 0:1f0dee641bb7
201 0:1f0dee641bb7
198
202
199 Pull -u takes us back to branch foo:
203 Pull -u takes us back to branch foo:
200
204
201 $ hg pull -qu
205 $ hg pull -qu
202
206
203 $ hg parents
207 $ hg parents
204 changeset: 2:faba9097cad4
208 changeset: 2:faba9097cad4
205 branch: foo
209 branch: foo
206 tag: tip
210 tag: tip
207 user: test
211 user: test
208 date: Thu Jan 01 00:00:00 1970 +0000
212 date: Thu Jan 01 00:00:00 1970 +0000
209 summary: new head of branch foo
213 summary: new head of branch foo
210
214
211 $ hg rollback
215 $ hg rollback
212 repository tip rolled back to revision 1 (undo pull)
216 repository tip rolled back to revision 1 (undo pull)
213 working directory now based on revision 0
217 working directory now based on revision 0
214
218
215 $ hg up -C 0
219 $ hg up -C 0
216 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
217
221
218 $ hg parents -q
222 $ hg parents -q
219 0:1f0dee641bb7
223 0:1f0dee641bb7
220
224
221 $ hg heads -q
225 $ hg heads -q
222 1:cd2a86ecc814
226 1:cd2a86ecc814
223 0:1f0dee641bb7
227 0:1f0dee641bb7
224
228
225 $ hg pull -qur default default
229 $ hg pull -qur default default
226
230
227 $ hg parents
231 $ hg parents
228 changeset: 3:4cd725637392
232 changeset: 3:4cd725637392
229 tag: tip
233 tag: tip
230 parent: 0:1f0dee641bb7
234 parent: 0:1f0dee641bb7
231 user: test
235 user: test
232 date: Thu Jan 01 00:00:00 1970 +0000
236 date: Thu Jan 01 00:00:00 1970 +0000
233 summary: add bar
237 summary: add bar
234
238
235 $ hg heads
239 $ hg heads
236 changeset: 3:4cd725637392
240 changeset: 3:4cd725637392
237 tag: tip
241 tag: tip
238 parent: 0:1f0dee641bb7
242 parent: 0:1f0dee641bb7
239 user: test
243 user: test
240 date: Thu Jan 01 00:00:00 1970 +0000
244 date: Thu Jan 01 00:00:00 1970 +0000
241 summary: add bar
245 summary: add bar
242
246
243 changeset: 2:faba9097cad4
247 changeset: 2:faba9097cad4
244 branch: foo
248 branch: foo
245 user: test
249 user: test
246 date: Thu Jan 01 00:00:00 1970 +0000
250 date: Thu Jan 01 00:00:00 1970 +0000
247 summary: new head of branch foo
251 summary: new head of branch foo
248
252
249 Test handling of invalid urls
253 Test handling of invalid urls
250
254
251 $ hg id http://foo/?bar
255 $ hg id http://foo/?bar
252 abort: unsupported URL component: "bar"
256 abort: unsupported URL component: "bar"
253 [255]
257 [255]
254
258
255 $ cd ..
259 $ cd ..
256
260
257 Test handling common incoming revisions between "default" and
261 Test handling common incoming revisions between "default" and
258 "default-push"
262 "default-push"
259
263
260 $ hg -R clone rollback
264 $ hg -R clone rollback
261 repository tip rolled back to revision 1 (undo pull)
265 repository tip rolled back to revision 1 (undo pull)
262 working directory now based on revision 0
266 working directory now based on revision 0
263
267
264 $ cd repo
268 $ cd repo
265
269
266 $ hg update -q -C default
270 $ hg update -q -C default
267 $ echo modified >> bar
271 $ echo modified >> bar
268 $ hg commit -m "new head to push current default head"
272 $ hg commit -m "new head to push current default head"
269 $ hg -q push -r ".^1" '../clone'
273 $ hg -q push -r ".^1" '../clone'
270
274
271 $ hg -q outgoing '../clone'
275 $ hg -q outgoing '../clone'
272 2:faba9097cad4
276 2:faba9097cad4
273 4:d515801a8f3d
277 4:d515801a8f3d
274
278
275 $ hg summary --remote --config paths.default='../clone#default' --config paths.default-push='../clone#foo'
279 $ hg summary --remote --config paths.default='../clone#default' --config paths.default-push='../clone#foo'
276 parent: 4:d515801a8f3d tip
280 parent: 4:d515801a8f3d tip
277 new head to push current default head
281 new head to push current default head
278 branch: default
282 branch: default
279 commit: (clean)
283 commit: (clean)
280 update: (current)
284 update: (current)
281 remote: 1 outgoing
285 remote: 1 outgoing
282
286
283 $ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
287 $ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
284 parent: 4:d515801a8f3d tip
288 parent: 4:d515801a8f3d tip
285 new head to push current default head
289 new head to push current default head
286 branch: default
290 branch: default
287 commit: (clean)
291 commit: (clean)
288 update: (current)
292 update: (current)
289 remote: 2 outgoing
293 remote: 2 outgoing
290
294
291 $ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
295 $ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
292 parent: 4:d515801a8f3d tip
296 parent: 4:d515801a8f3d tip
293 new head to push current default head
297 new head to push current default head
294 branch: default
298 branch: default
295 commit: (clean)
299 commit: (clean)
296 update: (current)
300 update: (current)
297 remote: 1 outgoing
301 remote: 1 outgoing
298
302
299 $ hg clone -q -r 0 . ../another
303 $ hg clone -q -r 0 . ../another
300 $ hg -q outgoing '../another#default'
304 $ hg -q outgoing '../another#default'
301 3:4cd725637392
305 3:4cd725637392
302 4:d515801a8f3d
306 4:d515801a8f3d
303
307
304 $ hg summary --remote --config paths.default='../another#default' --config paths.default-push='../clone#default'
308 $ hg summary --remote --config paths.default='../another#default' --config paths.default-push='../clone#default'
305 parent: 4:d515801a8f3d tip
309 parent: 4:d515801a8f3d tip
306 new head to push current default head
310 new head to push current default head
307 branch: default
311 branch: default
308 commit: (clean)
312 commit: (clean)
309 update: (current)
313 update: (current)
310 remote: 1 outgoing
314 remote: 1 outgoing
311
315
312 $ cd ..
316 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now