##// END OF EJS Templates
merge with stable
Matt Mackall -
r25427:d0c7ffc4 merge default
parent child Browse files
Show More
@@ -1,6508 +1,6514
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # label constants
43 # label constants
44 # until 3.5, bookmarks.current was the advertised name, not
44 # until 3.5, bookmarks.current was the advertised name, not
45 # bookmarks.active, so we must use both to avoid breaking old
45 # bookmarks.active, so we must use both to avoid breaking old
46 # custom styles
46 # custom styles
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
48
48
49 # common command options
49 # common command options
50
50
51 globalopts = [
51 globalopts = [
52 ('R', 'repository', '',
52 ('R', 'repository', '',
53 _('repository root directory or name of overlay bundle file'),
53 _('repository root directory or name of overlay bundle file'),
54 _('REPO')),
54 _('REPO')),
55 ('', 'cwd', '',
55 ('', 'cwd', '',
56 _('change working directory'), _('DIR')),
56 _('change working directory'), _('DIR')),
57 ('y', 'noninteractive', None,
57 ('y', 'noninteractive', None,
58 _('do not prompt, automatically pick the first choice for all prompts')),
58 _('do not prompt, automatically pick the first choice for all prompts')),
59 ('q', 'quiet', None, _('suppress output')),
59 ('q', 'quiet', None, _('suppress output')),
60 ('v', 'verbose', None, _('enable additional output')),
60 ('v', 'verbose', None, _('enable additional output')),
61 ('', 'config', [],
61 ('', 'config', [],
62 _('set/override config option (use \'section.name=value\')'),
62 _('set/override config option (use \'section.name=value\')'),
63 _('CONFIG')),
63 _('CONFIG')),
64 ('', 'debug', None, _('enable debugging output')),
64 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debugger', None, _('start debugger')),
65 ('', 'debugger', None, _('start debugger')),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 _('ENCODE')),
67 _('ENCODE')),
68 ('', 'encodingmode', encoding.encodingmode,
68 ('', 'encodingmode', encoding.encodingmode,
69 _('set the charset encoding mode'), _('MODE')),
69 _('set the charset encoding mode'), _('MODE')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'time', None, _('time how long the command takes')),
71 ('', 'time', None, _('time how long the command takes')),
72 ('', 'profile', None, _('print command execution profile')),
72 ('', 'profile', None, _('print command execution profile')),
73 ('', 'version', None, _('output version information and exit')),
73 ('', 'version', None, _('output version information and exit')),
74 ('h', 'help', None, _('display help and exit')),
74 ('h', 'help', None, _('display help and exit')),
75 ('', 'hidden', False, _('consider hidden changesets')),
75 ('', 'hidden', False, _('consider hidden changesets')),
76 ]
76 ]
77
77
78 dryrunopts = [('n', 'dry-run', None,
78 dryrunopts = [('n', 'dry-run', None,
79 _('do not perform actions, just print output'))]
79 _('do not perform actions, just print output'))]
80
80
81 remoteopts = [
81 remoteopts = [
82 ('e', 'ssh', '',
82 ('e', 'ssh', '',
83 _('specify ssh command to use'), _('CMD')),
83 _('specify ssh command to use'), _('CMD')),
84 ('', 'remotecmd', '',
84 ('', 'remotecmd', '',
85 _('specify hg command to run on the remote side'), _('CMD')),
85 _('specify hg command to run on the remote side'), _('CMD')),
86 ('', 'insecure', None,
86 ('', 'insecure', None,
87 _('do not verify server certificate (ignoring web.cacerts config)')),
87 _('do not verify server certificate (ignoring web.cacerts config)')),
88 ]
88 ]
89
89
90 walkopts = [
90 walkopts = [
91 ('I', 'include', [],
91 ('I', 'include', [],
92 _('include names matching the given patterns'), _('PATTERN')),
92 _('include names matching the given patterns'), _('PATTERN')),
93 ('X', 'exclude', [],
93 ('X', 'exclude', [],
94 _('exclude names matching the given patterns'), _('PATTERN')),
94 _('exclude names matching the given patterns'), _('PATTERN')),
95 ]
95 ]
96
96
97 commitopts = [
97 commitopts = [
98 ('m', 'message', '',
98 ('m', 'message', '',
99 _('use text as commit message'), _('TEXT')),
99 _('use text as commit message'), _('TEXT')),
100 ('l', 'logfile', '',
100 ('l', 'logfile', '',
101 _('read commit message from file'), _('FILE')),
101 _('read commit message from file'), _('FILE')),
102 ]
102 ]
103
103
104 commitopts2 = [
104 commitopts2 = [
105 ('d', 'date', '',
105 ('d', 'date', '',
106 _('record the specified date as commit date'), _('DATE')),
106 _('record the specified date as commit date'), _('DATE')),
107 ('u', 'user', '',
107 ('u', 'user', '',
108 _('record the specified user as committer'), _('USER')),
108 _('record the specified user as committer'), _('USER')),
109 ]
109 ]
110
110
111 # hidden for now
111 # hidden for now
112 formatteropts = [
112 formatteropts = [
113 ('T', 'template', '',
113 ('T', 'template', '',
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 ]
115 ]
116
116
117 templateopts = [
117 templateopts = [
118 ('', 'style', '',
118 ('', 'style', '',
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 ('T', 'template', '',
120 ('T', 'template', '',
121 _('display with template'), _('TEMPLATE')),
121 _('display with template'), _('TEMPLATE')),
122 ]
122 ]
123
123
124 logopts = [
124 logopts = [
125 ('p', 'patch', None, _('show patch')),
125 ('p', 'patch', None, _('show patch')),
126 ('g', 'git', None, _('use git extended diff format')),
126 ('g', 'git', None, _('use git extended diff format')),
127 ('l', 'limit', '',
127 ('l', 'limit', '',
128 _('limit number of changes displayed'), _('NUM')),
128 _('limit number of changes displayed'), _('NUM')),
129 ('M', 'no-merges', None, _('do not show merges')),
129 ('M', 'no-merges', None, _('do not show merges')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('G', 'graph', None, _("show the revision DAG")),
131 ('G', 'graph', None, _("show the revision DAG")),
132 ] + templateopts
132 ] + templateopts
133
133
134 diffopts = [
134 diffopts = [
135 ('a', 'text', None, _('treat all files as text')),
135 ('a', 'text', None, _('treat all files as text')),
136 ('g', 'git', None, _('use git extended diff format')),
136 ('g', 'git', None, _('use git extended diff format')),
137 ('', 'nodates', None, _('omit dates from diff headers'))
137 ('', 'nodates', None, _('omit dates from diff headers'))
138 ]
138 ]
139
139
140 diffwsopts = [
140 diffwsopts = [
141 ('w', 'ignore-all-space', None,
141 ('w', 'ignore-all-space', None,
142 _('ignore white space when comparing lines')),
142 _('ignore white space when comparing lines')),
143 ('b', 'ignore-space-change', None,
143 ('b', 'ignore-space-change', None,
144 _('ignore changes in the amount of white space')),
144 _('ignore changes in the amount of white space')),
145 ('B', 'ignore-blank-lines', None,
145 ('B', 'ignore-blank-lines', None,
146 _('ignore changes whose lines are all blank')),
146 _('ignore changes whose lines are all blank')),
147 ]
147 ]
148
148
149 diffopts2 = [
149 diffopts2 = [
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('p', 'show-function', None, _('show which function each change is in')),
151 ('p', 'show-function', None, _('show which function each change is in')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ] + diffwsopts + [
153 ] + diffwsopts + [
154 ('U', 'unified', '',
154 ('U', 'unified', '',
155 _('number of lines of context to show'), _('NUM')),
155 _('number of lines of context to show'), _('NUM')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ]
158 ]
159
159
160 mergetoolopts = [
160 mergetoolopts = [
161 ('t', 'tool', '', _('specify merge tool')),
161 ('t', 'tool', '', _('specify merge tool')),
162 ]
162 ]
163
163
164 similarityopts = [
164 similarityopts = [
165 ('s', 'similarity', '',
165 ('s', 'similarity', '',
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 ]
167 ]
168
168
169 subrepoopts = [
169 subrepoopts = [
170 ('S', 'subrepos', None,
170 ('S', 'subrepos', None,
171 _('recurse into subrepositories'))
171 _('recurse into subrepositories'))
172 ]
172 ]
173
173
174 # Commands start here, listed alphabetically
174 # Commands start here, listed alphabetically
175
175
176 @command('^add',
176 @command('^add',
177 walkopts + subrepoopts + dryrunopts,
177 walkopts + subrepoopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def add(ui, repo, *pats, **opts):
180 def add(ui, repo, *pats, **opts):
181 """add the specified files on the next commit
181 """add the specified files on the next commit
182
182
183 Schedule files to be version controlled and added to the
183 Schedule files to be version controlled and added to the
184 repository.
184 repository.
185
185
186 The files will be added to the repository at the next commit. To
186 The files will be added to the repository at the next commit. To
187 undo an add before that, see :hg:`forget`.
187 undo an add before that, see :hg:`forget`.
188
188
189 If no names are given, add all files to the repository.
189 If no names are given, add all files to the repository.
190
190
191 .. container:: verbose
191 .. container:: verbose
192
192
193 An example showing how new (unknown) files are added
193 An example showing how new (unknown) files are added
194 automatically by :hg:`add`::
194 automatically by :hg:`add`::
195
195
196 $ ls
196 $ ls
197 foo.c
197 foo.c
198 $ hg status
198 $ hg status
199 ? foo.c
199 ? foo.c
200 $ hg add
200 $ hg add
201 adding foo.c
201 adding foo.c
202 $ hg status
202 $ hg status
203 A foo.c
203 A foo.c
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207
207
208 m = scmutil.match(repo[None], pats, opts)
208 m = scmutil.match(repo[None], pats, opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
210 return rejected and 1 or 0
210 return rejected and 1 or 0
211
211
212 @command('addremove',
212 @command('addremove',
213 similarityopts + subrepoopts + walkopts + dryrunopts,
213 similarityopts + subrepoopts + walkopts + dryrunopts,
214 _('[OPTION]... [FILE]...'),
214 _('[OPTION]... [FILE]...'),
215 inferrepo=True)
215 inferrepo=True)
216 def addremove(ui, repo, *pats, **opts):
216 def addremove(ui, repo, *pats, **opts):
217 """add all new files, delete all missing files
217 """add all new files, delete all missing files
218
218
219 Add all new files and remove all missing files from the
219 Add all new files and remove all missing files from the
220 repository.
220 repository.
221
221
222 New files are ignored if they match any of the patterns in
222 New files are ignored if they match any of the patterns in
223 ``.hgignore``. As with add, these changes take effect at the next
223 ``.hgignore``. As with add, these changes take effect at the next
224 commit.
224 commit.
225
225
226 Use the -s/--similarity option to detect renamed files. This
226 Use the -s/--similarity option to detect renamed files. This
227 option takes a percentage between 0 (disabled) and 100 (files must
227 option takes a percentage between 0 (disabled) and 100 (files must
228 be identical) as its parameter. With a parameter greater than 0,
228 be identical) as its parameter. With a parameter greater than 0,
229 this compares every removed file with every added file and records
229 this compares every removed file with every added file and records
230 those similar enough as renames. Detecting renamed files this way
230 those similar enough as renames. Detecting renamed files this way
231 can be expensive. After using this option, :hg:`status -C` can be
231 can be expensive. After using this option, :hg:`status -C` can be
232 used to check which files were identified as moved or renamed. If
232 used to check which files were identified as moved or renamed. If
233 not specified, -s/--similarity defaults to 100 and only renames of
233 not specified, -s/--similarity defaults to 100 and only renames of
234 identical files are detected.
234 identical files are detected.
235
235
236 Returns 0 if all files are successfully added.
236 Returns 0 if all files are successfully added.
237 """
237 """
238 try:
238 try:
239 sim = float(opts.get('similarity') or 100)
239 sim = float(opts.get('similarity') or 100)
240 except ValueError:
240 except ValueError:
241 raise util.Abort(_('similarity must be a number'))
241 raise util.Abort(_('similarity must be a number'))
242 if sim < 0 or sim > 100:
242 if sim < 0 or sim > 100:
243 raise util.Abort(_('similarity must be between 0 and 100'))
243 raise util.Abort(_('similarity must be between 0 and 100'))
244 matcher = scmutil.match(repo[None], pats, opts)
244 matcher = scmutil.match(repo[None], pats, opts)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
246
246
247 @command('^annotate|blame',
247 @command('^annotate|blame',
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
249 ('', 'follow', None,
249 ('', 'follow', None,
250 _('follow copies/renames and list the filename (DEPRECATED)')),
250 _('follow copies/renames and list the filename (DEPRECATED)')),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
252 ('a', 'text', None, _('treat all files as text')),
252 ('a', 'text', None, _('treat all files as text')),
253 ('u', 'user', None, _('list the author (long with -v)')),
253 ('u', 'user', None, _('list the author (long with -v)')),
254 ('f', 'file', None, _('list the filename')),
254 ('f', 'file', None, _('list the filename')),
255 ('d', 'date', None, _('list the date (short with -q)')),
255 ('d', 'date', None, _('list the date (short with -q)')),
256 ('n', 'number', None, _('list the revision number (default)')),
256 ('n', 'number', None, _('list the revision number (default)')),
257 ('c', 'changeset', None, _('list the changeset')),
257 ('c', 'changeset', None, _('list the changeset')),
258 ('l', 'line-number', None, _('show line number at the first appearance'))
258 ('l', 'line-number', None, _('show line number at the first appearance'))
259 ] + diffwsopts + walkopts + formatteropts,
259 ] + diffwsopts + walkopts + formatteropts,
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
261 inferrepo=True)
261 inferrepo=True)
262 def annotate(ui, repo, *pats, **opts):
262 def annotate(ui, repo, *pats, **opts):
263 """show changeset information by line for each file
263 """show changeset information by line for each file
264
264
265 List changes in files, showing the revision id responsible for
265 List changes in files, showing the revision id responsible for
266 each line
266 each line
267
267
268 This command is useful for discovering when a change was made and
268 This command is useful for discovering when a change was made and
269 by whom.
269 by whom.
270
270
271 Without the -a/--text option, annotate will avoid processing files
271 Without the -a/--text option, annotate will avoid processing files
272 it detects as binary. With -a, annotate will annotate the file
272 it detects as binary. With -a, annotate will annotate the file
273 anyway, although the results will probably be neither useful
273 anyway, although the results will probably be neither useful
274 nor desirable.
274 nor desirable.
275
275
276 Returns 0 on success.
276 Returns 0 on success.
277 """
277 """
278 if not pats:
278 if not pats:
279 raise util.Abort(_('at least one filename or pattern is required'))
279 raise util.Abort(_('at least one filename or pattern is required'))
280
280
281 if opts.get('follow'):
281 if opts.get('follow'):
282 # --follow is deprecated and now just an alias for -f/--file
282 # --follow is deprecated and now just an alias for -f/--file
283 # to mimic the behavior of Mercurial before version 1.5
283 # to mimic the behavior of Mercurial before version 1.5
284 opts['file'] = True
284 opts['file'] = True
285
285
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
287
287
288 fm = ui.formatter('annotate', opts)
288 fm = ui.formatter('annotate', opts)
289 if ui.quiet:
289 if ui.quiet:
290 datefunc = util.shortdate
290 datefunc = util.shortdate
291 else:
291 else:
292 datefunc = util.datestr
292 datefunc = util.datestr
293 if ctx.rev() is None:
293 if ctx.rev() is None:
294 def hexfn(node):
294 def hexfn(node):
295 if node is None:
295 if node is None:
296 return None
296 return None
297 else:
297 else:
298 return fm.hexfunc(node)
298 return fm.hexfunc(node)
299 if opts.get('changeset'):
299 if opts.get('changeset'):
300 # omit "+" suffix which is appended to node hex
300 # omit "+" suffix which is appended to node hex
301 def formatrev(rev):
301 def formatrev(rev):
302 if rev is None:
302 if rev is None:
303 return '%d' % ctx.p1().rev()
303 return '%d' % ctx.p1().rev()
304 else:
304 else:
305 return '%d' % rev
305 return '%d' % rev
306 else:
306 else:
307 def formatrev(rev):
307 def formatrev(rev):
308 if rev is None:
308 if rev is None:
309 return '%d+' % ctx.p1().rev()
309 return '%d+' % ctx.p1().rev()
310 else:
310 else:
311 return '%d ' % rev
311 return '%d ' % rev
312 def formathex(hex):
312 def formathex(hex):
313 if hex is None:
313 if hex is None:
314 return '%s+' % fm.hexfunc(ctx.p1().node())
314 return '%s+' % fm.hexfunc(ctx.p1().node())
315 else:
315 else:
316 return '%s ' % hex
316 return '%s ' % hex
317 else:
317 else:
318 hexfn = fm.hexfunc
318 hexfn = fm.hexfunc
319 formatrev = formathex = str
319 formatrev = formathex = str
320
320
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
325 ('file', ' ', lambda x: x[0].path(), str),
325 ('file', ' ', lambda x: x[0].path(), str),
326 ('line_number', ':', lambda x: x[1], str),
326 ('line_number', ':', lambda x: x[1], str),
327 ]
327 ]
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
329
329
330 if (not opts.get('user') and not opts.get('changeset')
330 if (not opts.get('user') and not opts.get('changeset')
331 and not opts.get('date') and not opts.get('file')):
331 and not opts.get('date') and not opts.get('file')):
332 opts['number'] = True
332 opts['number'] = True
333
333
334 linenumber = opts.get('line_number') is not None
334 linenumber = opts.get('line_number') is not None
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
336 raise util.Abort(_('at least one of -n/-c is required for -l'))
336 raise util.Abort(_('at least one of -n/-c is required for -l'))
337
337
338 if fm:
338 if fm:
339 def makefunc(get, fmt):
339 def makefunc(get, fmt):
340 return get
340 return get
341 else:
341 else:
342 def makefunc(get, fmt):
342 def makefunc(get, fmt):
343 return lambda x: fmt(get(x))
343 return lambda x: fmt(get(x))
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
345 if opts.get(op)]
345 if opts.get(op)]
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
348 if opts.get(op))
348 if opts.get(op))
349
349
350 def bad(x, y):
350 def bad(x, y):
351 raise util.Abort("%s: %s" % (x, y))
351 raise util.Abort("%s: %s" % (x, y))
352
352
353 m = scmutil.match(ctx, pats, opts)
353 m = scmutil.match(ctx, pats, opts)
354 m.bad = bad
354 m.bad = bad
355 follow = not opts.get('no_follow')
355 follow = not opts.get('no_follow')
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
357 whitespace=True)
357 whitespace=True)
358 for abs in ctx.walk(m):
358 for abs in ctx.walk(m):
359 fctx = ctx[abs]
359 fctx = ctx[abs]
360 if not opts.get('text') and util.binary(fctx.data()):
360 if not opts.get('text') and util.binary(fctx.data()):
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
362 continue
362 continue
363
363
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
365 diffopts=diffopts)
365 diffopts=diffopts)
366 formats = []
366 formats = []
367 pieces = []
367 pieces = []
368
368
369 for f, sep in funcmap:
369 for f, sep in funcmap:
370 l = [f(n) for n, dummy in lines]
370 l = [f(n) for n, dummy in lines]
371 if l:
371 if l:
372 if fm:
372 if fm:
373 formats.append(['%s' for x in l])
373 formats.append(['%s' for x in l])
374 else:
374 else:
375 sizes = [encoding.colwidth(x) for x in l]
375 sizes = [encoding.colwidth(x) for x in l]
376 ml = max(sizes)
376 ml = max(sizes)
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
378 pieces.append(l)
378 pieces.append(l)
379
379
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
381 fm.startitem()
381 fm.startitem()
382 fm.write(fields, "".join(f), *p)
382 fm.write(fields, "".join(f), *p)
383 fm.write('line', ": %s", l[1])
383 fm.write('line', ": %s", l[1])
384
384
385 if lines and not lines[-1][1].endswith('\n'):
385 if lines and not lines[-1][1].endswith('\n'):
386 fm.plain('\n')
386 fm.plain('\n')
387
387
388 fm.end()
388 fm.end()
389
389
390 @command('archive',
390 @command('archive',
391 [('', 'no-decode', None, _('do not pass files through decoders')),
391 [('', 'no-decode', None, _('do not pass files through decoders')),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
393 _('PREFIX')),
393 _('PREFIX')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
396 ] + subrepoopts + walkopts,
396 ] + subrepoopts + walkopts,
397 _('[OPTION]... DEST'))
397 _('[OPTION]... DEST'))
398 def archive(ui, repo, dest, **opts):
398 def archive(ui, repo, dest, **opts):
399 '''create an unversioned archive of a repository revision
399 '''create an unversioned archive of a repository revision
400
400
401 By default, the revision used is the parent of the working
401 By default, the revision used is the parent of the working
402 directory; use -r/--rev to specify a different revision.
402 directory; use -r/--rev to specify a different revision.
403
403
404 The archive type is automatically detected based on file
404 The archive type is automatically detected based on file
405 extension (or override using -t/--type).
405 extension (or override using -t/--type).
406
406
407 .. container:: verbose
407 .. container:: verbose
408
408
409 Examples:
409 Examples:
410
410
411 - create a zip file containing the 1.0 release::
411 - create a zip file containing the 1.0 release::
412
412
413 hg archive -r 1.0 project-1.0.zip
413 hg archive -r 1.0 project-1.0.zip
414
414
415 - create a tarball excluding .hg files::
415 - create a tarball excluding .hg files::
416
416
417 hg archive project.tar.gz -X ".hg*"
417 hg archive project.tar.gz -X ".hg*"
418
418
419 Valid types are:
419 Valid types are:
420
420
421 :``files``: a directory full of files (default)
421 :``files``: a directory full of files (default)
422 :``tar``: tar archive, uncompressed
422 :``tar``: tar archive, uncompressed
423 :``tbz2``: tar archive, compressed using bzip2
423 :``tbz2``: tar archive, compressed using bzip2
424 :``tgz``: tar archive, compressed using gzip
424 :``tgz``: tar archive, compressed using gzip
425 :``uzip``: zip archive, uncompressed
425 :``uzip``: zip archive, uncompressed
426 :``zip``: zip archive, compressed using deflate
426 :``zip``: zip archive, compressed using deflate
427
427
428 The exact name of the destination archive or directory is given
428 The exact name of the destination archive or directory is given
429 using a format string; see :hg:`help export` for details.
429 using a format string; see :hg:`help export` for details.
430
430
431 Each member added to an archive file has a directory prefix
431 Each member added to an archive file has a directory prefix
432 prepended. Use -p/--prefix to specify a format string for the
432 prepended. Use -p/--prefix to specify a format string for the
433 prefix. The default is the basename of the archive, with suffixes
433 prefix. The default is the basename of the archive, with suffixes
434 removed.
434 removed.
435
435
436 Returns 0 on success.
436 Returns 0 on success.
437 '''
437 '''
438
438
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
440 if not ctx:
440 if not ctx:
441 raise util.Abort(_('no working directory: please specify a revision'))
441 raise util.Abort(_('no working directory: please specify a revision'))
442 node = ctx.node()
442 node = ctx.node()
443 dest = cmdutil.makefilename(repo, dest, node)
443 dest = cmdutil.makefilename(repo, dest, node)
444 if os.path.realpath(dest) == repo.root:
444 if os.path.realpath(dest) == repo.root:
445 raise util.Abort(_('repository root cannot be destination'))
445 raise util.Abort(_('repository root cannot be destination'))
446
446
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
448 prefix = opts.get('prefix')
448 prefix = opts.get('prefix')
449
449
450 if dest == '-':
450 if dest == '-':
451 if kind == 'files':
451 if kind == 'files':
452 raise util.Abort(_('cannot archive plain files to stdout'))
452 raise util.Abort(_('cannot archive plain files to stdout'))
453 dest = cmdutil.makefileobj(repo, dest)
453 dest = cmdutil.makefileobj(repo, dest)
454 if not prefix:
454 if not prefix:
455 prefix = os.path.basename(repo.root) + '-%h'
455 prefix = os.path.basename(repo.root) + '-%h'
456
456
457 prefix = cmdutil.makefilename(repo, prefix, node)
457 prefix = cmdutil.makefilename(repo, prefix, node)
458 matchfn = scmutil.match(ctx, [], opts)
458 matchfn = scmutil.match(ctx, [], opts)
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
460 matchfn, prefix, subrepos=opts.get('subrepos'))
460 matchfn, prefix, subrepos=opts.get('subrepos'))
461
461
462 @command('backout',
462 @command('backout',
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
465 ('', 'parent', '',
465 ('', 'parent', '',
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
470 _('[OPTION]... [-r] REV'))
470 _('[OPTION]... [-r] REV'))
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
472 '''reverse effect of earlier changeset
472 '''reverse effect of earlier changeset
473
473
474 Prepare a new changeset with the effect of REV undone in the
474 Prepare a new changeset with the effect of REV undone in the
475 current working directory.
475 current working directory.
476
476
477 If REV is the parent of the working directory, then this new changeset
477 If REV is the parent of the working directory, then this new changeset
478 is committed automatically. Otherwise, hg needs to merge the
478 is committed automatically. Otherwise, hg needs to merge the
479 changes and the merged result is left uncommitted.
479 changes and the merged result is left uncommitted.
480
480
481 .. note::
481 .. note::
482
482
483 backout cannot be used to fix either an unwanted or
483 backout cannot be used to fix either an unwanted or
484 incorrect merge.
484 incorrect merge.
485
485
486 .. container:: verbose
486 .. container:: verbose
487
487
488 By default, the pending changeset will have one parent,
488 By default, the pending changeset will have one parent,
489 maintaining a linear history. With --merge, the pending
489 maintaining a linear history. With --merge, the pending
490 changeset will instead have two parents: the old parent of the
490 changeset will instead have two parents: the old parent of the
491 working directory and a new child of REV that simply undoes REV.
491 working directory and a new child of REV that simply undoes REV.
492
492
493 Before version 1.7, the behavior without --merge was equivalent
493 Before version 1.7, the behavior without --merge was equivalent
494 to specifying --merge followed by :hg:`update --clean .` to
494 to specifying --merge followed by :hg:`update --clean .` to
495 cancel the merge and leave the child of REV as a head to be
495 cancel the merge and leave the child of REV as a head to be
496 merged separately.
496 merged separately.
497
497
498 See :hg:`help dates` for a list of formats valid for -d/--date.
498 See :hg:`help dates` for a list of formats valid for -d/--date.
499
499
500 Returns 0 on success, 1 if nothing to backout or there are unresolved
500 Returns 0 on success, 1 if nothing to backout or there are unresolved
501 files.
501 files.
502 '''
502 '''
503 if rev and node:
503 if rev and node:
504 raise util.Abort(_("please specify just one revision"))
504 raise util.Abort(_("please specify just one revision"))
505
505
506 if not rev:
506 if not rev:
507 rev = node
507 rev = node
508
508
509 if not rev:
509 if not rev:
510 raise util.Abort(_("please specify a revision to backout"))
510 raise util.Abort(_("please specify a revision to backout"))
511
511
512 date = opts.get('date')
512 date = opts.get('date')
513 if date:
513 if date:
514 opts['date'] = util.parsedate(date)
514 opts['date'] = util.parsedate(date)
515
515
516 cmdutil.checkunfinished(repo)
516 cmdutil.checkunfinished(repo)
517 cmdutil.bailifchanged(repo)
517 cmdutil.bailifchanged(repo)
518 node = scmutil.revsingle(repo, rev).node()
518 node = scmutil.revsingle(repo, rev).node()
519
519
520 op1, op2 = repo.dirstate.parents()
520 op1, op2 = repo.dirstate.parents()
521 if not repo.changelog.isancestor(node, op1):
521 if not repo.changelog.isancestor(node, op1):
522 raise util.Abort(_('cannot backout change that is not an ancestor'))
522 raise util.Abort(_('cannot backout change that is not an ancestor'))
523
523
524 p1, p2 = repo.changelog.parents(node)
524 p1, p2 = repo.changelog.parents(node)
525 if p1 == nullid:
525 if p1 == nullid:
526 raise util.Abort(_('cannot backout a change with no parents'))
526 raise util.Abort(_('cannot backout a change with no parents'))
527 if p2 != nullid:
527 if p2 != nullid:
528 if not opts.get('parent'):
528 if not opts.get('parent'):
529 raise util.Abort(_('cannot backout a merge changeset'))
529 raise util.Abort(_('cannot backout a merge changeset'))
530 p = repo.lookup(opts['parent'])
530 p = repo.lookup(opts['parent'])
531 if p not in (p1, p2):
531 if p not in (p1, p2):
532 raise util.Abort(_('%s is not a parent of %s') %
532 raise util.Abort(_('%s is not a parent of %s') %
533 (short(p), short(node)))
533 (short(p), short(node)))
534 parent = p
534 parent = p
535 else:
535 else:
536 if opts.get('parent'):
536 if opts.get('parent'):
537 raise util.Abort(_('cannot use --parent on non-merge changeset'))
537 raise util.Abort(_('cannot use --parent on non-merge changeset'))
538 parent = p1
538 parent = p1
539
539
540 # the backout should appear on the same branch
540 # the backout should appear on the same branch
541 wlock = repo.wlock()
541 wlock = repo.wlock()
542 try:
542 try:
543 branch = repo.dirstate.branch()
543 branch = repo.dirstate.branch()
544 bheads = repo.branchheads(branch)
544 bheads = repo.branchheads(branch)
545 rctx = scmutil.revsingle(repo, hex(parent))
545 rctx = scmutil.revsingle(repo, hex(parent))
546 if not opts.get('merge') and op1 != node:
546 if not opts.get('merge') and op1 != node:
547 try:
547 try:
548 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
548 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
549 'backout')
549 'backout')
550 repo.dirstate.beginparentchange()
550 repo.dirstate.beginparentchange()
551 stats = mergemod.update(repo, parent, True, True, False,
551 stats = mergemod.update(repo, parent, True, True, False,
552 node, False)
552 node, False)
553 repo.setparents(op1, op2)
553 repo.setparents(op1, op2)
554 repo.dirstate.endparentchange()
554 repo.dirstate.endparentchange()
555 hg._showstats(repo, stats)
555 hg._showstats(repo, stats)
556 if stats[3]:
556 if stats[3]:
557 repo.ui.status(_("use 'hg resolve' to retry unresolved "
557 repo.ui.status(_("use 'hg resolve' to retry unresolved "
558 "file merges\n"))
558 "file merges\n"))
559 return 1
559 return 1
560 elif not commit:
560 elif not commit:
561 msg = _("changeset %s backed out, "
561 msg = _("changeset %s backed out, "
562 "don't forget to commit.\n")
562 "don't forget to commit.\n")
563 ui.status(msg % short(node))
563 ui.status(msg % short(node))
564 return 0
564 return 0
565 finally:
565 finally:
566 ui.setconfig('ui', 'forcemerge', '', '')
566 ui.setconfig('ui', 'forcemerge', '', '')
567 else:
567 else:
568 hg.clean(repo, node, show_stats=False)
568 hg.clean(repo, node, show_stats=False)
569 repo.dirstate.setbranch(branch)
569 repo.dirstate.setbranch(branch)
570 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
570 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
571
571
572
572
573 def commitfunc(ui, repo, message, match, opts):
573 def commitfunc(ui, repo, message, match, opts):
574 editform = 'backout'
574 editform = 'backout'
575 e = cmdutil.getcommiteditor(editform=editform, **opts)
575 e = cmdutil.getcommiteditor(editform=editform, **opts)
576 if not message:
576 if not message:
577 # we don't translate commit messages
577 # we don't translate commit messages
578 message = "Backed out changeset %s" % short(node)
578 message = "Backed out changeset %s" % short(node)
579 e = cmdutil.getcommiteditor(edit=True, editform=editform)
579 e = cmdutil.getcommiteditor(edit=True, editform=editform)
580 return repo.commit(message, opts.get('user'), opts.get('date'),
580 return repo.commit(message, opts.get('user'), opts.get('date'),
581 match, editor=e)
581 match, editor=e)
582 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
582 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
583 if not newnode:
583 if not newnode:
584 ui.status(_("nothing changed\n"))
584 ui.status(_("nothing changed\n"))
585 return 1
585 return 1
586 cmdutil.commitstatus(repo, newnode, branch, bheads)
586 cmdutil.commitstatus(repo, newnode, branch, bheads)
587
587
588 def nice(node):
588 def nice(node):
589 return '%d:%s' % (repo.changelog.rev(node), short(node))
589 return '%d:%s' % (repo.changelog.rev(node), short(node))
590 ui.status(_('changeset %s backs out changeset %s\n') %
590 ui.status(_('changeset %s backs out changeset %s\n') %
591 (nice(repo.changelog.tip()), nice(node)))
591 (nice(repo.changelog.tip()), nice(node)))
592 if opts.get('merge') and op1 != node:
592 if opts.get('merge') and op1 != node:
593 hg.clean(repo, op1, show_stats=False)
593 hg.clean(repo, op1, show_stats=False)
594 ui.status(_('merging with changeset %s\n')
594 ui.status(_('merging with changeset %s\n')
595 % nice(repo.changelog.tip()))
595 % nice(repo.changelog.tip()))
596 try:
596 try:
597 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
597 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
598 'backout')
598 'backout')
599 return hg.merge(repo, hex(repo.changelog.tip()))
599 return hg.merge(repo, hex(repo.changelog.tip()))
600 finally:
600 finally:
601 ui.setconfig('ui', 'forcemerge', '', '')
601 ui.setconfig('ui', 'forcemerge', '', '')
602 finally:
602 finally:
603 wlock.release()
603 wlock.release()
604 return 0
604 return 0
605
605
606 @command('bisect',
606 @command('bisect',
607 [('r', 'reset', False, _('reset bisect state')),
607 [('r', 'reset', False, _('reset bisect state')),
608 ('g', 'good', False, _('mark changeset good')),
608 ('g', 'good', False, _('mark changeset good')),
609 ('b', 'bad', False, _('mark changeset bad')),
609 ('b', 'bad', False, _('mark changeset bad')),
610 ('s', 'skip', False, _('skip testing changeset')),
610 ('s', 'skip', False, _('skip testing changeset')),
611 ('e', 'extend', False, _('extend the bisect range')),
611 ('e', 'extend', False, _('extend the bisect range')),
612 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
612 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
613 ('U', 'noupdate', False, _('do not update to target'))],
613 ('U', 'noupdate', False, _('do not update to target'))],
614 _("[-gbsr] [-U] [-c CMD] [REV]"))
614 _("[-gbsr] [-U] [-c CMD] [REV]"))
615 def bisect(ui, repo, rev=None, extra=None, command=None,
615 def bisect(ui, repo, rev=None, extra=None, command=None,
616 reset=None, good=None, bad=None, skip=None, extend=None,
616 reset=None, good=None, bad=None, skip=None, extend=None,
617 noupdate=None):
617 noupdate=None):
618 """subdivision search of changesets
618 """subdivision search of changesets
619
619
620 This command helps to find changesets which introduce problems. To
620 This command helps to find changesets which introduce problems. To
621 use, mark the earliest changeset you know exhibits the problem as
621 use, mark the earliest changeset you know exhibits the problem as
622 bad, then mark the latest changeset which is free from the problem
622 bad, then mark the latest changeset which is free from the problem
623 as good. Bisect will update your working directory to a revision
623 as good. Bisect will update your working directory to a revision
624 for testing (unless the -U/--noupdate option is specified). Once
624 for testing (unless the -U/--noupdate option is specified). Once
625 you have performed tests, mark the working directory as good or
625 you have performed tests, mark the working directory as good or
626 bad, and bisect will either update to another candidate changeset
626 bad, and bisect will either update to another candidate changeset
627 or announce that it has found the bad revision.
627 or announce that it has found the bad revision.
628
628
629 As a shortcut, you can also use the revision argument to mark a
629 As a shortcut, you can also use the revision argument to mark a
630 revision as good or bad without checking it out first.
630 revision as good or bad without checking it out first.
631
631
632 If you supply a command, it will be used for automatic bisection.
632 If you supply a command, it will be used for automatic bisection.
633 The environment variable HG_NODE will contain the ID of the
633 The environment variable HG_NODE will contain the ID of the
634 changeset being tested. The exit status of the command will be
634 changeset being tested. The exit status of the command will be
635 used to mark revisions as good or bad: status 0 means good, 125
635 used to mark revisions as good or bad: status 0 means good, 125
636 means to skip the revision, 127 (command not found) will abort the
636 means to skip the revision, 127 (command not found) will abort the
637 bisection, and any other non-zero exit status means the revision
637 bisection, and any other non-zero exit status means the revision
638 is bad.
638 is bad.
639
639
640 .. container:: verbose
640 .. container:: verbose
641
641
642 Some examples:
642 Some examples:
643
643
644 - start a bisection with known bad revision 34, and good revision 12::
644 - start a bisection with known bad revision 34, and good revision 12::
645
645
646 hg bisect --bad 34
646 hg bisect --bad 34
647 hg bisect --good 12
647 hg bisect --good 12
648
648
649 - advance the current bisection by marking current revision as good or
649 - advance the current bisection by marking current revision as good or
650 bad::
650 bad::
651
651
652 hg bisect --good
652 hg bisect --good
653 hg bisect --bad
653 hg bisect --bad
654
654
655 - mark the current revision, or a known revision, to be skipped (e.g. if
655 - mark the current revision, or a known revision, to be skipped (e.g. if
656 that revision is not usable because of another issue)::
656 that revision is not usable because of another issue)::
657
657
658 hg bisect --skip
658 hg bisect --skip
659 hg bisect --skip 23
659 hg bisect --skip 23
660
660
661 - skip all revisions that do not touch directories ``foo`` or ``bar``::
661 - skip all revisions that do not touch directories ``foo`` or ``bar``::
662
662
663 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
663 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
664
664
665 - forget the current bisection::
665 - forget the current bisection::
666
666
667 hg bisect --reset
667 hg bisect --reset
668
668
669 - use 'make && make tests' to automatically find the first broken
669 - use 'make && make tests' to automatically find the first broken
670 revision::
670 revision::
671
671
672 hg bisect --reset
672 hg bisect --reset
673 hg bisect --bad 34
673 hg bisect --bad 34
674 hg bisect --good 12
674 hg bisect --good 12
675 hg bisect --command "make && make tests"
675 hg bisect --command "make && make tests"
676
676
677 - see all changesets whose states are already known in the current
677 - see all changesets whose states are already known in the current
678 bisection::
678 bisection::
679
679
680 hg log -r "bisect(pruned)"
680 hg log -r "bisect(pruned)"
681
681
682 - see the changeset currently being bisected (especially useful
682 - see the changeset currently being bisected (especially useful
683 if running with -U/--noupdate)::
683 if running with -U/--noupdate)::
684
684
685 hg log -r "bisect(current)"
685 hg log -r "bisect(current)"
686
686
687 - see all changesets that took part in the current bisection::
687 - see all changesets that took part in the current bisection::
688
688
689 hg log -r "bisect(range)"
689 hg log -r "bisect(range)"
690
690
691 - you can even get a nice graph::
691 - you can even get a nice graph::
692
692
693 hg log --graph -r "bisect(range)"
693 hg log --graph -r "bisect(range)"
694
694
695 See :hg:`help revsets` for more about the `bisect()` keyword.
695 See :hg:`help revsets` for more about the `bisect()` keyword.
696
696
697 Returns 0 on success.
697 Returns 0 on success.
698 """
698 """
699 def extendbisectrange(nodes, good):
699 def extendbisectrange(nodes, good):
700 # bisect is incomplete when it ends on a merge node and
700 # bisect is incomplete when it ends on a merge node and
701 # one of the parent was not checked.
701 # one of the parent was not checked.
702 parents = repo[nodes[0]].parents()
702 parents = repo[nodes[0]].parents()
703 if len(parents) > 1:
703 if len(parents) > 1:
704 if good:
704 if good:
705 side = state['bad']
705 side = state['bad']
706 else:
706 else:
707 side = state['good']
707 side = state['good']
708 num = len(set(i.node() for i in parents) & set(side))
708 num = len(set(i.node() for i in parents) & set(side))
709 if num == 1:
709 if num == 1:
710 return parents[0].ancestor(parents[1])
710 return parents[0].ancestor(parents[1])
711 return None
711 return None
712
712
713 def print_result(nodes, good):
713 def print_result(nodes, good):
714 displayer = cmdutil.show_changeset(ui, repo, {})
714 displayer = cmdutil.show_changeset(ui, repo, {})
715 if len(nodes) == 1:
715 if len(nodes) == 1:
716 # narrowed it down to a single revision
716 # narrowed it down to a single revision
717 if good:
717 if good:
718 ui.write(_("The first good revision is:\n"))
718 ui.write(_("The first good revision is:\n"))
719 else:
719 else:
720 ui.write(_("The first bad revision is:\n"))
720 ui.write(_("The first bad revision is:\n"))
721 displayer.show(repo[nodes[0]])
721 displayer.show(repo[nodes[0]])
722 extendnode = extendbisectrange(nodes, good)
722 extendnode = extendbisectrange(nodes, good)
723 if extendnode is not None:
723 if extendnode is not None:
724 ui.write(_('Not all ancestors of this changeset have been'
724 ui.write(_('Not all ancestors of this changeset have been'
725 ' checked.\nUse bisect --extend to continue the '
725 ' checked.\nUse bisect --extend to continue the '
726 'bisection from\nthe common ancestor, %s.\n')
726 'bisection from\nthe common ancestor, %s.\n')
727 % extendnode)
727 % extendnode)
728 else:
728 else:
729 # multiple possible revisions
729 # multiple possible revisions
730 if good:
730 if good:
731 ui.write(_("Due to skipped revisions, the first "
731 ui.write(_("Due to skipped revisions, the first "
732 "good revision could be any of:\n"))
732 "good revision could be any of:\n"))
733 else:
733 else:
734 ui.write(_("Due to skipped revisions, the first "
734 ui.write(_("Due to skipped revisions, the first "
735 "bad revision could be any of:\n"))
735 "bad revision could be any of:\n"))
736 for n in nodes:
736 for n in nodes:
737 displayer.show(repo[n])
737 displayer.show(repo[n])
738 displayer.close()
738 displayer.close()
739
739
740 def check_state(state, interactive=True):
740 def check_state(state, interactive=True):
741 if not state['good'] or not state['bad']:
741 if not state['good'] or not state['bad']:
742 if (good or bad or skip or reset) and interactive:
742 if (good or bad or skip or reset) and interactive:
743 return
743 return
744 if not state['good']:
744 if not state['good']:
745 raise util.Abort(_('cannot bisect (no known good revisions)'))
745 raise util.Abort(_('cannot bisect (no known good revisions)'))
746 else:
746 else:
747 raise util.Abort(_('cannot bisect (no known bad revisions)'))
747 raise util.Abort(_('cannot bisect (no known bad revisions)'))
748 return True
748 return True
749
749
750 # backward compatibility
750 # backward compatibility
751 if rev in "good bad reset init".split():
751 if rev in "good bad reset init".split():
752 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
752 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
753 cmd, rev, extra = rev, extra, None
753 cmd, rev, extra = rev, extra, None
754 if cmd == "good":
754 if cmd == "good":
755 good = True
755 good = True
756 elif cmd == "bad":
756 elif cmd == "bad":
757 bad = True
757 bad = True
758 else:
758 else:
759 reset = True
759 reset = True
760 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
760 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
761 raise util.Abort(_('incompatible arguments'))
761 raise util.Abort(_('incompatible arguments'))
762
762
763 cmdutil.checkunfinished(repo)
763 cmdutil.checkunfinished(repo)
764
764
765 if reset:
765 if reset:
766 p = repo.join("bisect.state")
766 p = repo.join("bisect.state")
767 if os.path.exists(p):
767 if os.path.exists(p):
768 os.unlink(p)
768 os.unlink(p)
769 return
769 return
770
770
771 state = hbisect.load_state(repo)
771 state = hbisect.load_state(repo)
772
772
773 if command:
773 if command:
774 changesets = 1
774 changesets = 1
775 if noupdate:
775 if noupdate:
776 try:
776 try:
777 node = state['current'][0]
777 node = state['current'][0]
778 except LookupError:
778 except LookupError:
779 raise util.Abort(_('current bisect revision is unknown - '
779 raise util.Abort(_('current bisect revision is unknown - '
780 'start a new bisect to fix'))
780 'start a new bisect to fix'))
781 else:
781 else:
782 node, p2 = repo.dirstate.parents()
782 node, p2 = repo.dirstate.parents()
783 if p2 != nullid:
783 if p2 != nullid:
784 raise util.Abort(_('current bisect revision is a merge'))
784 raise util.Abort(_('current bisect revision is a merge'))
785 try:
785 try:
786 while changesets:
786 while changesets:
787 # update state
787 # update state
788 state['current'] = [node]
788 state['current'] = [node]
789 hbisect.save_state(repo, state)
789 hbisect.save_state(repo, state)
790 status = ui.system(command, environ={'HG_NODE': hex(node)})
790 status = ui.system(command, environ={'HG_NODE': hex(node)})
791 if status == 125:
791 if status == 125:
792 transition = "skip"
792 transition = "skip"
793 elif status == 0:
793 elif status == 0:
794 transition = "good"
794 transition = "good"
795 # status < 0 means process was killed
795 # status < 0 means process was killed
796 elif status == 127:
796 elif status == 127:
797 raise util.Abort(_("failed to execute %s") % command)
797 raise util.Abort(_("failed to execute %s") % command)
798 elif status < 0:
798 elif status < 0:
799 raise util.Abort(_("%s killed") % command)
799 raise util.Abort(_("%s killed") % command)
800 else:
800 else:
801 transition = "bad"
801 transition = "bad"
802 ctx = scmutil.revsingle(repo, rev, node)
802 ctx = scmutil.revsingle(repo, rev, node)
803 rev = None # clear for future iterations
803 rev = None # clear for future iterations
804 state[transition].append(ctx.node())
804 state[transition].append(ctx.node())
805 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
805 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
806 check_state(state, interactive=False)
806 check_state(state, interactive=False)
807 # bisect
807 # bisect
808 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
808 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
809 # update to next check
809 # update to next check
810 node = nodes[0]
810 node = nodes[0]
811 if not noupdate:
811 if not noupdate:
812 cmdutil.bailifchanged(repo)
812 cmdutil.bailifchanged(repo)
813 hg.clean(repo, node, show_stats=False)
813 hg.clean(repo, node, show_stats=False)
814 finally:
814 finally:
815 state['current'] = [node]
815 state['current'] = [node]
816 hbisect.save_state(repo, state)
816 hbisect.save_state(repo, state)
817 print_result(nodes, bgood)
817 print_result(nodes, bgood)
818 return
818 return
819
819
820 # update state
820 # update state
821
821
822 if rev:
822 if rev:
823 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
823 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
824 else:
824 else:
825 nodes = [repo.lookup('.')]
825 nodes = [repo.lookup('.')]
826
826
827 if good or bad or skip:
827 if good or bad or skip:
828 if good:
828 if good:
829 state['good'] += nodes
829 state['good'] += nodes
830 elif bad:
830 elif bad:
831 state['bad'] += nodes
831 state['bad'] += nodes
832 elif skip:
832 elif skip:
833 state['skip'] += nodes
833 state['skip'] += nodes
834 hbisect.save_state(repo, state)
834 hbisect.save_state(repo, state)
835
835
836 if not check_state(state):
836 if not check_state(state):
837 return
837 return
838
838
839 # actually bisect
839 # actually bisect
840 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
840 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
841 if extend:
841 if extend:
842 if not changesets:
842 if not changesets:
843 extendnode = extendbisectrange(nodes, good)
843 extendnode = extendbisectrange(nodes, good)
844 if extendnode is not None:
844 if extendnode is not None:
845 ui.write(_("Extending search to changeset %d:%s\n")
845 ui.write(_("Extending search to changeset %d:%s\n")
846 % (extendnode.rev(), extendnode))
846 % (extendnode.rev(), extendnode))
847 state['current'] = [extendnode.node()]
847 state['current'] = [extendnode.node()]
848 hbisect.save_state(repo, state)
848 hbisect.save_state(repo, state)
849 if noupdate:
849 if noupdate:
850 return
850 return
851 cmdutil.bailifchanged(repo)
851 cmdutil.bailifchanged(repo)
852 return hg.clean(repo, extendnode.node())
852 return hg.clean(repo, extendnode.node())
853 raise util.Abort(_("nothing to extend"))
853 raise util.Abort(_("nothing to extend"))
854
854
855 if changesets == 0:
855 if changesets == 0:
856 print_result(nodes, good)
856 print_result(nodes, good)
857 else:
857 else:
858 assert len(nodes) == 1 # only a single node can be tested next
858 assert len(nodes) == 1 # only a single node can be tested next
859 node = nodes[0]
859 node = nodes[0]
860 # compute the approximate number of remaining tests
860 # compute the approximate number of remaining tests
861 tests, size = 0, 2
861 tests, size = 0, 2
862 while size <= changesets:
862 while size <= changesets:
863 tests, size = tests + 1, size * 2
863 tests, size = tests + 1, size * 2
864 rev = repo.changelog.rev(node)
864 rev = repo.changelog.rev(node)
865 ui.write(_("Testing changeset %d:%s "
865 ui.write(_("Testing changeset %d:%s "
866 "(%d changesets remaining, ~%d tests)\n")
866 "(%d changesets remaining, ~%d tests)\n")
867 % (rev, short(node), changesets, tests))
867 % (rev, short(node), changesets, tests))
868 state['current'] = [node]
868 state['current'] = [node]
869 hbisect.save_state(repo, state)
869 hbisect.save_state(repo, state)
870 if not noupdate:
870 if not noupdate:
871 cmdutil.bailifchanged(repo)
871 cmdutil.bailifchanged(repo)
872 return hg.clean(repo, node)
872 return hg.clean(repo, node)
873
873
874 @command('bookmarks|bookmark',
874 @command('bookmarks|bookmark',
875 [('f', 'force', False, _('force')),
875 [('f', 'force', False, _('force')),
876 ('r', 'rev', '', _('revision'), _('REV')),
876 ('r', 'rev', '', _('revision'), _('REV')),
877 ('d', 'delete', False, _('delete a given bookmark')),
877 ('d', 'delete', False, _('delete a given bookmark')),
878 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
878 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
879 ('i', 'inactive', False, _('mark a bookmark inactive')),
879 ('i', 'inactive', False, _('mark a bookmark inactive')),
880 ] + formatteropts,
880 ] + formatteropts,
881 _('hg bookmarks [OPTIONS]... [NAME]...'))
881 _('hg bookmarks [OPTIONS]... [NAME]...'))
882 def bookmark(ui, repo, *names, **opts):
882 def bookmark(ui, repo, *names, **opts):
883 '''create a new bookmark or list existing bookmarks
883 '''create a new bookmark or list existing bookmarks
884
884
885 Bookmarks are labels on changesets to help track lines of development.
885 Bookmarks are labels on changesets to help track lines of development.
886 Bookmarks are unversioned and can be moved, renamed and deleted.
886 Bookmarks are unversioned and can be moved, renamed and deleted.
887 Deleting or moving a bookmark has no effect on the associated changesets.
887 Deleting or moving a bookmark has no effect on the associated changesets.
888
888
889 Creating or updating to a bookmark causes it to be marked as 'active'.
889 Creating or updating to a bookmark causes it to be marked as 'active'.
890 The active bookmark is indicated with a '*'.
890 The active bookmark is indicated with a '*'.
891 When a commit is made, the active bookmark will advance to the new commit.
891 When a commit is made, the active bookmark will advance to the new commit.
892 A plain :hg:`update` will also advance an active bookmark, if possible.
892 A plain :hg:`update` will also advance an active bookmark, if possible.
893 Updating away from a bookmark will cause it to be deactivated.
893 Updating away from a bookmark will cause it to be deactivated.
894
894
895 Bookmarks can be pushed and pulled between repositories (see
895 Bookmarks can be pushed and pulled between repositories (see
896 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
896 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
897 diverged, a new 'divergent bookmark' of the form 'name@path' will
897 diverged, a new 'divergent bookmark' of the form 'name@path' will
898 be created. Using :hg:`merge` will resolve the divergence.
898 be created. Using :hg:`merge` will resolve the divergence.
899
899
900 A bookmark named '@' has the special property that :hg:`clone` will
900 A bookmark named '@' has the special property that :hg:`clone` will
901 check it out by default if it exists.
901 check it out by default if it exists.
902
902
903 .. container:: verbose
903 .. container:: verbose
904
904
905 Examples:
905 Examples:
906
906
907 - create an active bookmark for a new line of development::
907 - create an active bookmark for a new line of development::
908
908
909 hg book new-feature
909 hg book new-feature
910
910
911 - create an inactive bookmark as a place marker::
911 - create an inactive bookmark as a place marker::
912
912
913 hg book -i reviewed
913 hg book -i reviewed
914
914
915 - create an inactive bookmark on another changeset::
915 - create an inactive bookmark on another changeset::
916
916
917 hg book -r .^ tested
917 hg book -r .^ tested
918
918
919 - move the '@' bookmark from another branch::
919 - move the '@' bookmark from another branch::
920
920
921 hg book -f @
921 hg book -f @
922 '''
922 '''
923 force = opts.get('force')
923 force = opts.get('force')
924 rev = opts.get('rev')
924 rev = opts.get('rev')
925 delete = opts.get('delete')
925 delete = opts.get('delete')
926 rename = opts.get('rename')
926 rename = opts.get('rename')
927 inactive = opts.get('inactive')
927 inactive = opts.get('inactive')
928
928
929 def checkformat(mark):
929 def checkformat(mark):
930 mark = mark.strip()
930 mark = mark.strip()
931 if not mark:
931 if not mark:
932 raise util.Abort(_("bookmark names cannot consist entirely of "
932 raise util.Abort(_("bookmark names cannot consist entirely of "
933 "whitespace"))
933 "whitespace"))
934 scmutil.checknewlabel(repo, mark, 'bookmark')
934 scmutil.checknewlabel(repo, mark, 'bookmark')
935 return mark
935 return mark
936
936
937 def checkconflict(repo, mark, cur, force=False, target=None):
937 def checkconflict(repo, mark, cur, force=False, target=None):
938 if mark in marks and not force:
938 if mark in marks and not force:
939 if target:
939 if target:
940 if marks[mark] == target and target == cur:
940 if marks[mark] == target and target == cur:
941 # re-activating a bookmark
941 # re-activating a bookmark
942 return
942 return
943 anc = repo.changelog.ancestors([repo[target].rev()])
943 anc = repo.changelog.ancestors([repo[target].rev()])
944 bmctx = repo[marks[mark]]
944 bmctx = repo[marks[mark]]
945 divs = [repo[b].node() for b in marks
945 divs = [repo[b].node() for b in marks
946 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
946 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
947
947
948 # allow resolving a single divergent bookmark even if moving
948 # allow resolving a single divergent bookmark even if moving
949 # the bookmark across branches when a revision is specified
949 # the bookmark across branches when a revision is specified
950 # that contains a divergent bookmark
950 # that contains a divergent bookmark
951 if bmctx.rev() not in anc and target in divs:
951 if bmctx.rev() not in anc and target in divs:
952 bookmarks.deletedivergent(repo, [target], mark)
952 bookmarks.deletedivergent(repo, [target], mark)
953 return
953 return
954
954
955 deletefrom = [b for b in divs
955 deletefrom = [b for b in divs
956 if repo[b].rev() in anc or b == target]
956 if repo[b].rev() in anc or b == target]
957 bookmarks.deletedivergent(repo, deletefrom, mark)
957 bookmarks.deletedivergent(repo, deletefrom, mark)
958 if bookmarks.validdest(repo, bmctx, repo[target]):
958 if bookmarks.validdest(repo, bmctx, repo[target]):
959 ui.status(_("moving bookmark '%s' forward from %s\n") %
959 ui.status(_("moving bookmark '%s' forward from %s\n") %
960 (mark, short(bmctx.node())))
960 (mark, short(bmctx.node())))
961 return
961 return
962 raise util.Abort(_("bookmark '%s' already exists "
962 raise util.Abort(_("bookmark '%s' already exists "
963 "(use -f to force)") % mark)
963 "(use -f to force)") % mark)
964 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
964 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
965 and not force):
965 and not force):
966 raise util.Abort(
966 raise util.Abort(
967 _("a bookmark cannot have the name of an existing branch"))
967 _("a bookmark cannot have the name of an existing branch"))
968
968
969 if delete and rename:
969 if delete and rename:
970 raise util.Abort(_("--delete and --rename are incompatible"))
970 raise util.Abort(_("--delete and --rename are incompatible"))
971 if delete and rev:
971 if delete and rev:
972 raise util.Abort(_("--rev is incompatible with --delete"))
972 raise util.Abort(_("--rev is incompatible with --delete"))
973 if rename and rev:
973 if rename and rev:
974 raise util.Abort(_("--rev is incompatible with --rename"))
974 raise util.Abort(_("--rev is incompatible with --rename"))
975 if not names and (delete or rev):
975 if not names and (delete or rev):
976 raise util.Abort(_("bookmark name required"))
976 raise util.Abort(_("bookmark name required"))
977
977
978 if delete or rename or names or inactive:
978 if delete or rename or names or inactive:
979 wlock = repo.wlock()
979 wlock = repo.wlock()
980 try:
980 try:
981 cur = repo.changectx('.').node()
981 cur = repo.changectx('.').node()
982 marks = repo._bookmarks
982 marks = repo._bookmarks
983 if delete:
983 if delete:
984 for mark in names:
984 for mark in names:
985 if mark not in marks:
985 if mark not in marks:
986 raise util.Abort(_("bookmark '%s' does not exist") %
986 raise util.Abort(_("bookmark '%s' does not exist") %
987 mark)
987 mark)
988 if mark == repo._activebookmark:
988 if mark == repo._activebookmark:
989 bookmarks.deactivate(repo)
989 bookmarks.deactivate(repo)
990 del marks[mark]
990 del marks[mark]
991 marks.write()
991 marks.write()
992
992
993 elif rename:
993 elif rename:
994 if not names:
994 if not names:
995 raise util.Abort(_("new bookmark name required"))
995 raise util.Abort(_("new bookmark name required"))
996 elif len(names) > 1:
996 elif len(names) > 1:
997 raise util.Abort(_("only one new bookmark name allowed"))
997 raise util.Abort(_("only one new bookmark name allowed"))
998 mark = checkformat(names[0])
998 mark = checkformat(names[0])
999 if rename not in marks:
999 if rename not in marks:
1000 raise util.Abort(_("bookmark '%s' does not exist") % rename)
1000 raise util.Abort(_("bookmark '%s' does not exist") % rename)
1001 checkconflict(repo, mark, cur, force)
1001 checkconflict(repo, mark, cur, force)
1002 marks[mark] = marks[rename]
1002 marks[mark] = marks[rename]
1003 if repo._activebookmark == rename and not inactive:
1003 if repo._activebookmark == rename and not inactive:
1004 bookmarks.activate(repo, mark)
1004 bookmarks.activate(repo, mark)
1005 del marks[rename]
1005 del marks[rename]
1006 marks.write()
1006 marks.write()
1007
1007
1008 elif names:
1008 elif names:
1009 newact = None
1009 newact = None
1010 for mark in names:
1010 for mark in names:
1011 mark = checkformat(mark)
1011 mark = checkformat(mark)
1012 if newact is None:
1012 if newact is None:
1013 newact = mark
1013 newact = mark
1014 if inactive and mark == repo._activebookmark:
1014 if inactive and mark == repo._activebookmark:
1015 bookmarks.deactivate(repo)
1015 bookmarks.deactivate(repo)
1016 return
1016 return
1017 tgt = cur
1017 tgt = cur
1018 if rev:
1018 if rev:
1019 tgt = scmutil.revsingle(repo, rev).node()
1019 tgt = scmutil.revsingle(repo, rev).node()
1020 checkconflict(repo, mark, cur, force, tgt)
1020 checkconflict(repo, mark, cur, force, tgt)
1021 marks[mark] = tgt
1021 marks[mark] = tgt
1022 if not inactive and cur == marks[newact] and not rev:
1022 if not inactive and cur == marks[newact] and not rev:
1023 bookmarks.activate(repo, newact)
1023 bookmarks.activate(repo, newact)
1024 elif cur != tgt and newact == repo._activebookmark:
1024 elif cur != tgt and newact == repo._activebookmark:
1025 bookmarks.deactivate(repo)
1025 bookmarks.deactivate(repo)
1026 marks.write()
1026 marks.write()
1027
1027
1028 elif inactive:
1028 elif inactive:
1029 if len(marks) == 0:
1029 if len(marks) == 0:
1030 ui.status(_("no bookmarks set\n"))
1030 ui.status(_("no bookmarks set\n"))
1031 elif not repo._activebookmark:
1031 elif not repo._activebookmark:
1032 ui.status(_("no active bookmark\n"))
1032 ui.status(_("no active bookmark\n"))
1033 else:
1033 else:
1034 bookmarks.deactivate(repo)
1034 bookmarks.deactivate(repo)
1035 finally:
1035 finally:
1036 wlock.release()
1036 wlock.release()
1037 else: # show bookmarks
1037 else: # show bookmarks
1038 fm = ui.formatter('bookmarks', opts)
1038 fm = ui.formatter('bookmarks', opts)
1039 hexfn = fm.hexfunc
1039 hexfn = fm.hexfunc
1040 marks = repo._bookmarks
1040 marks = repo._bookmarks
1041 if len(marks) == 0 and not fm:
1041 if len(marks) == 0 and not fm:
1042 ui.status(_("no bookmarks set\n"))
1042 ui.status(_("no bookmarks set\n"))
1043 for bmark, n in sorted(marks.iteritems()):
1043 for bmark, n in sorted(marks.iteritems()):
1044 active = repo._activebookmark
1044 active = repo._activebookmark
1045 if bmark == active:
1045 if bmark == active:
1046 prefix, label = '*', activebookmarklabel
1046 prefix, label = '*', activebookmarklabel
1047 else:
1047 else:
1048 prefix, label = ' ', ''
1048 prefix, label = ' ', ''
1049
1049
1050 fm.startitem()
1050 fm.startitem()
1051 if not ui.quiet:
1051 if not ui.quiet:
1052 fm.plain(' %s ' % prefix, label=label)
1052 fm.plain(' %s ' % prefix, label=label)
1053 fm.write('bookmark', '%s', bmark, label=label)
1053 fm.write('bookmark', '%s', bmark, label=label)
1054 pad = " " * (25 - encoding.colwidth(bmark))
1054 pad = " " * (25 - encoding.colwidth(bmark))
1055 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1055 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1056 repo.changelog.rev(n), hexfn(n), label=label)
1056 repo.changelog.rev(n), hexfn(n), label=label)
1057 fm.data(active=(bmark == active))
1057 fm.data(active=(bmark == active))
1058 fm.plain('\n')
1058 fm.plain('\n')
1059 fm.end()
1059 fm.end()
1060
1060
1061 @command('branch',
1061 @command('branch',
1062 [('f', 'force', None,
1062 [('f', 'force', None,
1063 _('set branch name even if it shadows an existing branch')),
1063 _('set branch name even if it shadows an existing branch')),
1064 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1064 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1065 _('[-fC] [NAME]'))
1065 _('[-fC] [NAME]'))
1066 def branch(ui, repo, label=None, **opts):
1066 def branch(ui, repo, label=None, **opts):
1067 """set or show the current branch name
1067 """set or show the current branch name
1068
1068
1069 .. note::
1069 .. note::
1070
1070
1071 Branch names are permanent and global. Use :hg:`bookmark` to create a
1071 Branch names are permanent and global. Use :hg:`bookmark` to create a
1072 light-weight bookmark instead. See :hg:`help glossary` for more
1072 light-weight bookmark instead. See :hg:`help glossary` for more
1073 information about named branches and bookmarks.
1073 information about named branches and bookmarks.
1074
1074
1075 With no argument, show the current branch name. With one argument,
1075 With no argument, show the current branch name. With one argument,
1076 set the working directory branch name (the branch will not exist
1076 set the working directory branch name (the branch will not exist
1077 in the repository until the next commit). Standard practice
1077 in the repository until the next commit). Standard practice
1078 recommends that primary development take place on the 'default'
1078 recommends that primary development take place on the 'default'
1079 branch.
1079 branch.
1080
1080
1081 Unless -f/--force is specified, branch will not let you set a
1081 Unless -f/--force is specified, branch will not let you set a
1082 branch name that already exists.
1082 branch name that already exists.
1083
1083
1084 Use -C/--clean to reset the working directory branch to that of
1084 Use -C/--clean to reset the working directory branch to that of
1085 the parent of the working directory, negating a previous branch
1085 the parent of the working directory, negating a previous branch
1086 change.
1086 change.
1087
1087
1088 Use the command :hg:`update` to switch to an existing branch. Use
1088 Use the command :hg:`update` to switch to an existing branch. Use
1089 :hg:`commit --close-branch` to mark this branch head as closed.
1089 :hg:`commit --close-branch` to mark this branch head as closed.
1090 When all heads of the branch are closed, the branch will be
1090 When all heads of the branch are closed, the branch will be
1091 considered closed.
1091 considered closed.
1092
1092
1093 Returns 0 on success.
1093 Returns 0 on success.
1094 """
1094 """
1095 if label:
1095 if label:
1096 label = label.strip()
1096 label = label.strip()
1097
1097
1098 if not opts.get('clean') and not label:
1098 if not opts.get('clean') and not label:
1099 ui.write("%s\n" % repo.dirstate.branch())
1099 ui.write("%s\n" % repo.dirstate.branch())
1100 return
1100 return
1101
1101
1102 wlock = repo.wlock()
1102 wlock = repo.wlock()
1103 try:
1103 try:
1104 if opts.get('clean'):
1104 if opts.get('clean'):
1105 label = repo[None].p1().branch()
1105 label = repo[None].p1().branch()
1106 repo.dirstate.setbranch(label)
1106 repo.dirstate.setbranch(label)
1107 ui.status(_('reset working directory to branch %s\n') % label)
1107 ui.status(_('reset working directory to branch %s\n') % label)
1108 elif label:
1108 elif label:
1109 if not opts.get('force') and label in repo.branchmap():
1109 if not opts.get('force') and label in repo.branchmap():
1110 if label not in [p.branch() for p in repo.parents()]:
1110 if label not in [p.branch() for p in repo.parents()]:
1111 raise util.Abort(_('a branch of the same name already'
1111 raise util.Abort(_('a branch of the same name already'
1112 ' exists'),
1112 ' exists'),
1113 # i18n: "it" refers to an existing branch
1113 # i18n: "it" refers to an existing branch
1114 hint=_("use 'hg update' to switch to it"))
1114 hint=_("use 'hg update' to switch to it"))
1115 scmutil.checknewlabel(repo, label, 'branch')
1115 scmutil.checknewlabel(repo, label, 'branch')
1116 repo.dirstate.setbranch(label)
1116 repo.dirstate.setbranch(label)
1117 ui.status(_('marked working directory as branch %s\n') % label)
1117 ui.status(_('marked working directory as branch %s\n') % label)
1118
1118
1119 # find any open named branches aside from default
1119 # find any open named branches aside from default
1120 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1120 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1121 if n != "default" and not c]
1121 if n != "default" and not c]
1122 if not others:
1122 if not others:
1123 ui.status(_('(branches are permanent and global, '
1123 ui.status(_('(branches are permanent and global, '
1124 'did you want a bookmark?)\n'))
1124 'did you want a bookmark?)\n'))
1125 finally:
1125 finally:
1126 wlock.release()
1126 wlock.release()
1127
1127
1128 @command('branches',
1128 @command('branches',
1129 [('a', 'active', False,
1129 [('a', 'active', False,
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1130 _('show only branches that have unmerged heads (DEPRECATED)')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1131 ('c', 'closed', False, _('show normal and closed branches')),
1132 ] + formatteropts,
1132 ] + formatteropts,
1133 _('[-ac]'))
1133 _('[-ac]'))
1134 def branches(ui, repo, active=False, closed=False, **opts):
1134 def branches(ui, repo, active=False, closed=False, **opts):
1135 """list repository named branches
1135 """list repository named branches
1136
1136
1137 List the repository's named branches, indicating which ones are
1137 List the repository's named branches, indicating which ones are
1138 inactive. If -c/--closed is specified, also list branches which have
1138 inactive. If -c/--closed is specified, also list branches which have
1139 been marked closed (see :hg:`commit --close-branch`).
1139 been marked closed (see :hg:`commit --close-branch`).
1140
1140
1141 Use the command :hg:`update` to switch to an existing branch.
1141 Use the command :hg:`update` to switch to an existing branch.
1142
1142
1143 Returns 0.
1143 Returns 0.
1144 """
1144 """
1145
1145
1146 fm = ui.formatter('branches', opts)
1146 fm = ui.formatter('branches', opts)
1147 hexfunc = fm.hexfunc
1147 hexfunc = fm.hexfunc
1148
1148
1149 allheads = set(repo.heads())
1149 allheads = set(repo.heads())
1150 branches = []
1150 branches = []
1151 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1151 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1152 isactive = not isclosed and bool(set(heads) & allheads)
1152 isactive = not isclosed and bool(set(heads) & allheads)
1153 branches.append((tag, repo[tip], isactive, not isclosed))
1153 branches.append((tag, repo[tip], isactive, not isclosed))
1154 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1154 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1155 reverse=True)
1155 reverse=True)
1156
1156
1157 for tag, ctx, isactive, isopen in branches:
1157 for tag, ctx, isactive, isopen in branches:
1158 if active and not isactive:
1158 if active and not isactive:
1159 continue
1159 continue
1160 if isactive:
1160 if isactive:
1161 label = 'branches.active'
1161 label = 'branches.active'
1162 notice = ''
1162 notice = ''
1163 elif not isopen:
1163 elif not isopen:
1164 if not closed:
1164 if not closed:
1165 continue
1165 continue
1166 label = 'branches.closed'
1166 label = 'branches.closed'
1167 notice = _(' (closed)')
1167 notice = _(' (closed)')
1168 else:
1168 else:
1169 label = 'branches.inactive'
1169 label = 'branches.inactive'
1170 notice = _(' (inactive)')
1170 notice = _(' (inactive)')
1171 current = (tag == repo.dirstate.branch())
1171 current = (tag == repo.dirstate.branch())
1172 if current:
1172 if current:
1173 label = 'branches.current'
1173 label = 'branches.current'
1174
1174
1175 fm.startitem()
1175 fm.startitem()
1176 fm.write('branch', '%s', tag, label=label)
1176 fm.write('branch', '%s', tag, label=label)
1177 rev = ctx.rev()
1177 rev = ctx.rev()
1178 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1178 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1179 fmt = ' ' * padsize + ' %d:%s'
1179 fmt = ' ' * padsize + ' %d:%s'
1180 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1180 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1181 label='log.changeset changeset.%s' % ctx.phasestr())
1181 label='log.changeset changeset.%s' % ctx.phasestr())
1182 fm.data(active=isactive, closed=not isopen, current=current)
1182 fm.data(active=isactive, closed=not isopen, current=current)
1183 if not ui.quiet:
1183 if not ui.quiet:
1184 fm.plain(notice)
1184 fm.plain(notice)
1185 fm.plain('\n')
1185 fm.plain('\n')
1186 fm.end()
1186 fm.end()
1187
1187
1188 @command('bundle',
1188 @command('bundle',
1189 [('f', 'force', None, _('run even when the destination is unrelated')),
1189 [('f', 'force', None, _('run even when the destination is unrelated')),
1190 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1190 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1191 _('REV')),
1191 _('REV')),
1192 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1192 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1193 _('BRANCH')),
1193 _('BRANCH')),
1194 ('', 'base', [],
1194 ('', 'base', [],
1195 _('a base changeset assumed to be available at the destination'),
1195 _('a base changeset assumed to be available at the destination'),
1196 _('REV')),
1196 _('REV')),
1197 ('a', 'all', None, _('bundle all changesets in the repository')),
1197 ('a', 'all', None, _('bundle all changesets in the repository')),
1198 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1198 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1199 ] + remoteopts,
1199 ] + remoteopts,
1200 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1200 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1201 def bundle(ui, repo, fname, dest=None, **opts):
1201 def bundle(ui, repo, fname, dest=None, **opts):
1202 """create a changegroup file
1202 """create a changegroup file
1203
1203
1204 Generate a compressed changegroup file collecting changesets not
1204 Generate a compressed changegroup file collecting changesets not
1205 known to be in another repository.
1205 known to be in another repository.
1206
1206
1207 If you omit the destination repository, then hg assumes the
1207 If you omit the destination repository, then hg assumes the
1208 destination will have all the nodes you specify with --base
1208 destination will have all the nodes you specify with --base
1209 parameters. To create a bundle containing all changesets, use
1209 parameters. To create a bundle containing all changesets, use
1210 -a/--all (or --base null).
1210 -a/--all (or --base null).
1211
1211
1212 You can change compression method with the -t/--type option.
1212 You can change compression method with the -t/--type option.
1213 The available compression methods are: none, bzip2, and
1213 The available compression methods are: none, bzip2, and
1214 gzip (by default, bundles are compressed using bzip2).
1214 gzip (by default, bundles are compressed using bzip2).
1215
1215
1216 The bundle file can then be transferred using conventional means
1216 The bundle file can then be transferred using conventional means
1217 and applied to another repository with the unbundle or pull
1217 and applied to another repository with the unbundle or pull
1218 command. This is useful when direct push and pull are not
1218 command. This is useful when direct push and pull are not
1219 available or when exporting an entire repository is undesirable.
1219 available or when exporting an entire repository is undesirable.
1220
1220
1221 Applying bundles preserves all changeset contents including
1221 Applying bundles preserves all changeset contents including
1222 permissions, copy/rename information, and revision history.
1222 permissions, copy/rename information, and revision history.
1223
1223
1224 Returns 0 on success, 1 if no changes found.
1224 Returns 0 on success, 1 if no changes found.
1225 """
1225 """
1226 revs = None
1226 revs = None
1227 if 'rev' in opts:
1227 if 'rev' in opts:
1228 revs = scmutil.revrange(repo, opts['rev'])
1228 revs = scmutil.revrange(repo, opts['rev'])
1229
1229
1230 bundletype = opts.get('type', 'bzip2').lower()
1230 bundletype = opts.get('type', 'bzip2').lower()
1231 btypes = {'none': 'HG10UN',
1231 btypes = {'none': 'HG10UN',
1232 'bzip2': 'HG10BZ',
1232 'bzip2': 'HG10BZ',
1233 'gzip': 'HG10GZ',
1233 'gzip': 'HG10GZ',
1234 'bundle2': 'HG20'}
1234 'bundle2': 'HG20'}
1235 bundletype = btypes.get(bundletype)
1235 bundletype = btypes.get(bundletype)
1236 if bundletype not in changegroup.bundletypes:
1236 if bundletype not in changegroup.bundletypes:
1237 raise util.Abort(_('unknown bundle type specified with --type'))
1237 raise util.Abort(_('unknown bundle type specified with --type'))
1238
1238
1239 if opts.get('all'):
1239 if opts.get('all'):
1240 base = ['null']
1240 base = ['null']
1241 else:
1241 else:
1242 base = scmutil.revrange(repo, opts.get('base'))
1242 base = scmutil.revrange(repo, opts.get('base'))
1243 # TODO: get desired bundlecaps from command line.
1243 # TODO: get desired bundlecaps from command line.
1244 bundlecaps = None
1244 bundlecaps = None
1245 if base:
1245 if base:
1246 if dest:
1246 if dest:
1247 raise util.Abort(_("--base is incompatible with specifying "
1247 raise util.Abort(_("--base is incompatible with specifying "
1248 "a destination"))
1248 "a destination"))
1249 common = [repo.lookup(rev) for rev in base]
1249 common = [repo.lookup(rev) for rev in base]
1250 heads = revs and map(repo.lookup, revs) or revs
1250 heads = revs and map(repo.lookup, revs) or revs
1251 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1251 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1252 common=common, bundlecaps=bundlecaps)
1252 common=common, bundlecaps=bundlecaps)
1253 outgoing = None
1253 outgoing = None
1254 else:
1254 else:
1255 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1255 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1256 dest, branches = hg.parseurl(dest, opts.get('branch'))
1256 dest, branches = hg.parseurl(dest, opts.get('branch'))
1257 other = hg.peer(repo, opts, dest)
1257 other = hg.peer(repo, opts, dest)
1258 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1258 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1259 heads = revs and map(repo.lookup, revs) or revs
1259 heads = revs and map(repo.lookup, revs) or revs
1260 outgoing = discovery.findcommonoutgoing(repo, other,
1260 outgoing = discovery.findcommonoutgoing(repo, other,
1261 onlyheads=heads,
1261 onlyheads=heads,
1262 force=opts.get('force'),
1262 force=opts.get('force'),
1263 portable=True)
1263 portable=True)
1264 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1264 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1265 bundlecaps)
1265 bundlecaps)
1266 if not cg:
1266 if not cg:
1267 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1267 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1268 return 1
1268 return 1
1269
1269
1270 changegroup.writebundle(ui, cg, fname, bundletype)
1270 changegroup.writebundle(ui, cg, fname, bundletype)
1271
1271
1272 @command('cat',
1272 @command('cat',
1273 [('o', 'output', '',
1273 [('o', 'output', '',
1274 _('print output to file with formatted name'), _('FORMAT')),
1274 _('print output to file with formatted name'), _('FORMAT')),
1275 ('r', 'rev', '', _('print the given revision'), _('REV')),
1275 ('r', 'rev', '', _('print the given revision'), _('REV')),
1276 ('', 'decode', None, _('apply any matching decode filter')),
1276 ('', 'decode', None, _('apply any matching decode filter')),
1277 ] + walkopts,
1277 ] + walkopts,
1278 _('[OPTION]... FILE...'),
1278 _('[OPTION]... FILE...'),
1279 inferrepo=True)
1279 inferrepo=True)
1280 def cat(ui, repo, file1, *pats, **opts):
1280 def cat(ui, repo, file1, *pats, **opts):
1281 """output the current or given revision of files
1281 """output the current or given revision of files
1282
1282
1283 Print the specified files as they were at the given revision. If
1283 Print the specified files as they were at the given revision. If
1284 no revision is given, the parent of the working directory is used.
1284 no revision is given, the parent of the working directory is used.
1285
1285
1286 Output may be to a file, in which case the name of the file is
1286 Output may be to a file, in which case the name of the file is
1287 given using a format string. The formatting rules as follows:
1287 given using a format string. The formatting rules as follows:
1288
1288
1289 :``%%``: literal "%" character
1289 :``%%``: literal "%" character
1290 :``%s``: basename of file being printed
1290 :``%s``: basename of file being printed
1291 :``%d``: dirname of file being printed, or '.' if in repository root
1291 :``%d``: dirname of file being printed, or '.' if in repository root
1292 :``%p``: root-relative path name of file being printed
1292 :``%p``: root-relative path name of file being printed
1293 :``%H``: changeset hash (40 hexadecimal digits)
1293 :``%H``: changeset hash (40 hexadecimal digits)
1294 :``%R``: changeset revision number
1294 :``%R``: changeset revision number
1295 :``%h``: short-form changeset hash (12 hexadecimal digits)
1295 :``%h``: short-form changeset hash (12 hexadecimal digits)
1296 :``%r``: zero-padded changeset revision number
1296 :``%r``: zero-padded changeset revision number
1297 :``%b``: basename of the exporting repository
1297 :``%b``: basename of the exporting repository
1298
1298
1299 Returns 0 on success.
1299 Returns 0 on success.
1300 """
1300 """
1301 ctx = scmutil.revsingle(repo, opts.get('rev'))
1301 ctx = scmutil.revsingle(repo, opts.get('rev'))
1302 m = scmutil.match(ctx, (file1,) + pats, opts)
1302 m = scmutil.match(ctx, (file1,) + pats, opts)
1303
1303
1304 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1304 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1305
1305
1306 @command('^clone',
1306 @command('^clone',
1307 [('U', 'noupdate', None, _('the clone will include an empty working '
1307 [('U', 'noupdate', None, _('the clone will include an empty working '
1308 'directory (only a repository)')),
1308 'directory (only a repository)')),
1309 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1309 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1310 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1310 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1311 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1311 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1312 ('', 'pull', None, _('use pull protocol to copy metadata')),
1312 ('', 'pull', None, _('use pull protocol to copy metadata')),
1313 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1313 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1314 ] + remoteopts,
1314 ] + remoteopts,
1315 _('[OPTION]... SOURCE [DEST]'),
1315 _('[OPTION]... SOURCE [DEST]'),
1316 norepo=True)
1316 norepo=True)
1317 def clone(ui, source, dest=None, **opts):
1317 def clone(ui, source, dest=None, **opts):
1318 """make a copy of an existing repository
1318 """make a copy of an existing repository
1319
1319
1320 Create a copy of an existing repository in a new directory.
1320 Create a copy of an existing repository in a new directory.
1321
1321
1322 If no destination directory name is specified, it defaults to the
1322 If no destination directory name is specified, it defaults to the
1323 basename of the source.
1323 basename of the source.
1324
1324
1325 The location of the source is added to the new repository's
1325 The location of the source is added to the new repository's
1326 ``.hg/hgrc`` file, as the default to be used for future pulls.
1326 ``.hg/hgrc`` file, as the default to be used for future pulls.
1327
1327
1328 Only local paths and ``ssh://`` URLs are supported as
1328 Only local paths and ``ssh://`` URLs are supported as
1329 destinations. For ``ssh://`` destinations, no working directory or
1329 destinations. For ``ssh://`` destinations, no working directory or
1330 ``.hg/hgrc`` will be created on the remote side.
1330 ``.hg/hgrc`` will be created on the remote side.
1331
1331
1332 To pull only a subset of changesets, specify one or more revisions
1332 To pull only a subset of changesets, specify one or more revisions
1333 identifiers with -r/--rev or branches with -b/--branch. The
1333 identifiers with -r/--rev or branches with -b/--branch. The
1334 resulting clone will contain only the specified changesets and
1334 resulting clone will contain only the specified changesets and
1335 their ancestors. These options (or 'clone src#rev dest') imply
1335 their ancestors. These options (or 'clone src#rev dest') imply
1336 --pull, even for local source repositories. Note that specifying a
1336 --pull, even for local source repositories. Note that specifying a
1337 tag will include the tagged changeset but not the changeset
1337 tag will include the tagged changeset but not the changeset
1338 containing the tag.
1338 containing the tag.
1339
1339
1340 If the source repository has a bookmark called '@' set, that
1340 If the source repository has a bookmark called '@' set, that
1341 revision will be checked out in the new repository by default.
1341 revision will be checked out in the new repository by default.
1342
1342
1343 To check out a particular version, use -u/--update, or
1343 To check out a particular version, use -u/--update, or
1344 -U/--noupdate to create a clone with no working directory.
1344 -U/--noupdate to create a clone with no working directory.
1345
1345
1346 .. container:: verbose
1346 .. container:: verbose
1347
1347
1348 For efficiency, hardlinks are used for cloning whenever the
1348 For efficiency, hardlinks are used for cloning whenever the
1349 source and destination are on the same filesystem (note this
1349 source and destination are on the same filesystem (note this
1350 applies only to the repository data, not to the working
1350 applies only to the repository data, not to the working
1351 directory). Some filesystems, such as AFS, implement hardlinking
1351 directory). Some filesystems, such as AFS, implement hardlinking
1352 incorrectly, but do not report errors. In these cases, use the
1352 incorrectly, but do not report errors. In these cases, use the
1353 --pull option to avoid hardlinking.
1353 --pull option to avoid hardlinking.
1354
1354
1355 In some cases, you can clone repositories and the working
1355 In some cases, you can clone repositories and the working
1356 directory using full hardlinks with ::
1356 directory using full hardlinks with ::
1357
1357
1358 $ cp -al REPO REPOCLONE
1358 $ cp -al REPO REPOCLONE
1359
1359
1360 This is the fastest way to clone, but it is not always safe. The
1360 This is the fastest way to clone, but it is not always safe. The
1361 operation is not atomic (making sure REPO is not modified during
1361 operation is not atomic (making sure REPO is not modified during
1362 the operation is up to you) and you have to make sure your
1362 the operation is up to you) and you have to make sure your
1363 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1363 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1364 so). Also, this is not compatible with certain extensions that
1364 so). Also, this is not compatible with certain extensions that
1365 place their metadata under the .hg directory, such as mq.
1365 place their metadata under the .hg directory, such as mq.
1366
1366
1367 Mercurial will update the working directory to the first applicable
1367 Mercurial will update the working directory to the first applicable
1368 revision from this list:
1368 revision from this list:
1369
1369
1370 a) null if -U or the source repository has no changesets
1370 a) null if -U or the source repository has no changesets
1371 b) if -u . and the source repository is local, the first parent of
1371 b) if -u . and the source repository is local, the first parent of
1372 the source repository's working directory
1372 the source repository's working directory
1373 c) the changeset specified with -u (if a branch name, this means the
1373 c) the changeset specified with -u (if a branch name, this means the
1374 latest head of that branch)
1374 latest head of that branch)
1375 d) the changeset specified with -r
1375 d) the changeset specified with -r
1376 e) the tipmost head specified with -b
1376 e) the tipmost head specified with -b
1377 f) the tipmost head specified with the url#branch source syntax
1377 f) the tipmost head specified with the url#branch source syntax
1378 g) the revision marked with the '@' bookmark, if present
1378 g) the revision marked with the '@' bookmark, if present
1379 h) the tipmost head of the default branch
1379 h) the tipmost head of the default branch
1380 i) tip
1380 i) tip
1381
1381
1382 Examples:
1382 Examples:
1383
1383
1384 - clone a remote repository to a new directory named hg/::
1384 - clone a remote repository to a new directory named hg/::
1385
1385
1386 hg clone http://selenic.com/hg
1386 hg clone http://selenic.com/hg
1387
1387
1388 - create a lightweight local clone::
1388 - create a lightweight local clone::
1389
1389
1390 hg clone project/ project-feature/
1390 hg clone project/ project-feature/
1391
1391
1392 - clone from an absolute path on an ssh server (note double-slash)::
1392 - clone from an absolute path on an ssh server (note double-slash)::
1393
1393
1394 hg clone ssh://user@server//home/projects/alpha/
1394 hg clone ssh://user@server//home/projects/alpha/
1395
1395
1396 - do a high-speed clone over a LAN while checking out a
1396 - do a high-speed clone over a LAN while checking out a
1397 specified version::
1397 specified version::
1398
1398
1399 hg clone --uncompressed http://server/repo -u 1.5
1399 hg clone --uncompressed http://server/repo -u 1.5
1400
1400
1401 - create a repository without changesets after a particular revision::
1401 - create a repository without changesets after a particular revision::
1402
1402
1403 hg clone -r 04e544 experimental/ good/
1403 hg clone -r 04e544 experimental/ good/
1404
1404
1405 - clone (and track) a particular named branch::
1405 - clone (and track) a particular named branch::
1406
1406
1407 hg clone http://selenic.com/hg#stable
1407 hg clone http://selenic.com/hg#stable
1408
1408
1409 See :hg:`help urls` for details on specifying URLs.
1409 See :hg:`help urls` for details on specifying URLs.
1410
1410
1411 Returns 0 on success.
1411 Returns 0 on success.
1412 """
1412 """
1413 if opts.get('noupdate') and opts.get('updaterev'):
1413 if opts.get('noupdate') and opts.get('updaterev'):
1414 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1414 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1415
1415
1416 r = hg.clone(ui, opts, source, dest,
1416 r = hg.clone(ui, opts, source, dest,
1417 pull=opts.get('pull'),
1417 pull=opts.get('pull'),
1418 stream=opts.get('uncompressed'),
1418 stream=opts.get('uncompressed'),
1419 rev=opts.get('rev'),
1419 rev=opts.get('rev'),
1420 update=opts.get('updaterev') or not opts.get('noupdate'),
1420 update=opts.get('updaterev') or not opts.get('noupdate'),
1421 branch=opts.get('branch'))
1421 branch=opts.get('branch'))
1422
1422
1423 return r is None
1423 return r is None
1424
1424
1425 @command('^commit|ci',
1425 @command('^commit|ci',
1426 [('A', 'addremove', None,
1426 [('A', 'addremove', None,
1427 _('mark new/missing files as added/removed before committing')),
1427 _('mark new/missing files as added/removed before committing')),
1428 ('', 'close-branch', None,
1428 ('', 'close-branch', None,
1429 _('mark a branch head as closed')),
1429 _('mark a branch head as closed')),
1430 ('', 'amend', None, _('amend the parent of the working directory')),
1430 ('', 'amend', None, _('amend the parent of the working directory')),
1431 ('s', 'secret', None, _('use the secret phase for committing')),
1431 ('s', 'secret', None, _('use the secret phase for committing')),
1432 ('e', 'edit', None, _('invoke editor on commit messages')),
1432 ('e', 'edit', None, _('invoke editor on commit messages')),
1433 ('i', 'interactive', None, _('use interactive mode')),
1433 ('i', 'interactive', None, _('use interactive mode')),
1434 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1434 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1435 _('[OPTION]... [FILE]...'),
1435 _('[OPTION]... [FILE]...'),
1436 inferrepo=True)
1436 inferrepo=True)
1437 def commit(ui, repo, *pats, **opts):
1437 def commit(ui, repo, *pats, **opts):
1438 """commit the specified files or all outstanding changes
1438 """commit the specified files or all outstanding changes
1439
1439
1440 Commit changes to the given files into the repository. Unlike a
1440 Commit changes to the given files into the repository. Unlike a
1441 centralized SCM, this operation is a local operation. See
1441 centralized SCM, this operation is a local operation. See
1442 :hg:`push` for a way to actively distribute your changes.
1442 :hg:`push` for a way to actively distribute your changes.
1443
1443
1444 If a list of files is omitted, all changes reported by :hg:`status`
1444 If a list of files is omitted, all changes reported by :hg:`status`
1445 will be committed.
1445 will be committed.
1446
1446
1447 If you are committing the result of a merge, do not provide any
1447 If you are committing the result of a merge, do not provide any
1448 filenames or -I/-X filters.
1448 filenames or -I/-X filters.
1449
1449
1450 If no commit message is specified, Mercurial starts your
1450 If no commit message is specified, Mercurial starts your
1451 configured editor where you can enter a message. In case your
1451 configured editor where you can enter a message. In case your
1452 commit fails, you will find a backup of your message in
1452 commit fails, you will find a backup of your message in
1453 ``.hg/last-message.txt``.
1453 ``.hg/last-message.txt``.
1454
1454
1455 The --close-branch flag can be used to mark the current branch
1455 The --close-branch flag can be used to mark the current branch
1456 head closed. When all heads of a branch are closed, the branch
1456 head closed. When all heads of a branch are closed, the branch
1457 will be considered closed and no longer listed.
1457 will be considered closed and no longer listed.
1458
1458
1459 The --amend flag can be used to amend the parent of the
1459 The --amend flag can be used to amend the parent of the
1460 working directory with a new commit that contains the changes
1460 working directory with a new commit that contains the changes
1461 in the parent in addition to those currently reported by :hg:`status`,
1461 in the parent in addition to those currently reported by :hg:`status`,
1462 if there are any. The old commit is stored in a backup bundle in
1462 if there are any. The old commit is stored in a backup bundle in
1463 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1463 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1464 on how to restore it).
1464 on how to restore it).
1465
1465
1466 Message, user and date are taken from the amended commit unless
1466 Message, user and date are taken from the amended commit unless
1467 specified. When a message isn't specified on the command line,
1467 specified. When a message isn't specified on the command line,
1468 the editor will open with the message of the amended commit.
1468 the editor will open with the message of the amended commit.
1469
1469
1470 It is not possible to amend public changesets (see :hg:`help phases`)
1470 It is not possible to amend public changesets (see :hg:`help phases`)
1471 or changesets that have children.
1471 or changesets that have children.
1472
1472
1473 See :hg:`help dates` for a list of formats valid for -d/--date.
1473 See :hg:`help dates` for a list of formats valid for -d/--date.
1474
1474
1475 Returns 0 on success, 1 if nothing changed.
1475 Returns 0 on success, 1 if nothing changed.
1476 """
1476 """
1477 if opts.get('interactive'):
1477 if opts.get('interactive'):
1478 opts.pop('interactive')
1478 opts.pop('interactive')
1479 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1479 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1480 cmdutil.recordfilter, *pats, **opts)
1480 cmdutil.recordfilter, *pats, **opts)
1481 return
1481 return
1482
1482
1483 if opts.get('subrepos'):
1483 if opts.get('subrepos'):
1484 if opts.get('amend'):
1484 if opts.get('amend'):
1485 raise util.Abort(_('cannot amend with --subrepos'))
1485 raise util.Abort(_('cannot amend with --subrepos'))
1486 # Let --subrepos on the command line override config setting.
1486 # Let --subrepos on the command line override config setting.
1487 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1487 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1488
1488
1489 cmdutil.checkunfinished(repo, commit=True)
1489 cmdutil.checkunfinished(repo, commit=True)
1490
1490
1491 branch = repo[None].branch()
1491 branch = repo[None].branch()
1492 bheads = repo.branchheads(branch)
1492 bheads = repo.branchheads(branch)
1493
1493
1494 extra = {}
1494 extra = {}
1495 if opts.get('close_branch'):
1495 if opts.get('close_branch'):
1496 extra['close'] = 1
1496 extra['close'] = 1
1497
1497
1498 if not bheads:
1498 if not bheads:
1499 raise util.Abort(_('can only close branch heads'))
1499 raise util.Abort(_('can only close branch heads'))
1500 elif opts.get('amend'):
1500 elif opts.get('amend'):
1501 if repo.parents()[0].p1().branch() != branch and \
1501 if repo.parents()[0].p1().branch() != branch and \
1502 repo.parents()[0].p2().branch() != branch:
1502 repo.parents()[0].p2().branch() != branch:
1503 raise util.Abort(_('can only close branch heads'))
1503 raise util.Abort(_('can only close branch heads'))
1504
1504
1505 if opts.get('amend'):
1505 if opts.get('amend'):
1506 if ui.configbool('ui', 'commitsubrepos'):
1506 if ui.configbool('ui', 'commitsubrepos'):
1507 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1507 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1508
1508
1509 old = repo['.']
1509 old = repo['.']
1510 if not old.mutable():
1510 if not old.mutable():
1511 raise util.Abort(_('cannot amend public changesets'))
1511 raise util.Abort(_('cannot amend public changesets'))
1512 if len(repo[None].parents()) > 1:
1512 if len(repo[None].parents()) > 1:
1513 raise util.Abort(_('cannot amend while merging'))
1513 raise util.Abort(_('cannot amend while merging'))
1514 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1514 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1515 if not allowunstable and old.children():
1515 if not allowunstable and old.children():
1516 raise util.Abort(_('cannot amend changeset with children'))
1516 raise util.Abort(_('cannot amend changeset with children'))
1517
1517
1518 # commitfunc is used only for temporary amend commit by cmdutil.amend
1518 # commitfunc is used only for temporary amend commit by cmdutil.amend
1519 def commitfunc(ui, repo, message, match, opts):
1519 def commitfunc(ui, repo, message, match, opts):
1520 return repo.commit(message,
1520 return repo.commit(message,
1521 opts.get('user') or old.user(),
1521 opts.get('user') or old.user(),
1522 opts.get('date') or old.date(),
1522 opts.get('date') or old.date(),
1523 match,
1523 match,
1524 extra=extra)
1524 extra=extra)
1525
1525
1526 active = repo._activebookmark
1526 active = repo._activebookmark
1527 marks = old.bookmarks()
1527 marks = old.bookmarks()
1528 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1528 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1529 if node == old.node():
1529 if node == old.node():
1530 ui.status(_("nothing changed\n"))
1530 ui.status(_("nothing changed\n"))
1531 return 1
1531 return 1
1532 elif marks:
1532 elif marks:
1533 ui.debug('moving bookmarks %r from %s to %s\n' %
1533 ui.debug('moving bookmarks %r from %s to %s\n' %
1534 (marks, old.hex(), hex(node)))
1534 (marks, old.hex(), hex(node)))
1535 newmarks = repo._bookmarks
1535 newmarks = repo._bookmarks
1536 for bm in marks:
1536 for bm in marks:
1537 newmarks[bm] = node
1537 newmarks[bm] = node
1538 if bm == active:
1538 if bm == active:
1539 bookmarks.activate(repo, bm)
1539 bookmarks.activate(repo, bm)
1540 newmarks.write()
1540 newmarks.write()
1541 else:
1541 else:
1542 def commitfunc(ui, repo, message, match, opts):
1542 def commitfunc(ui, repo, message, match, opts):
1543 backup = ui.backupconfig('phases', 'new-commit')
1543 backup = ui.backupconfig('phases', 'new-commit')
1544 baseui = repo.baseui
1544 baseui = repo.baseui
1545 basebackup = baseui.backupconfig('phases', 'new-commit')
1545 basebackup = baseui.backupconfig('phases', 'new-commit')
1546 try:
1546 try:
1547 if opts.get('secret'):
1547 if opts.get('secret'):
1548 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1548 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1549 # Propagate to subrepos
1549 # Propagate to subrepos
1550 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1550 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1551
1551
1552 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1552 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1553 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1553 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1554 return repo.commit(message, opts.get('user'), opts.get('date'),
1554 return repo.commit(message, opts.get('user'), opts.get('date'),
1555 match,
1555 match,
1556 editor=editor,
1556 editor=editor,
1557 extra=extra)
1557 extra=extra)
1558 finally:
1558 finally:
1559 ui.restoreconfig(backup)
1559 ui.restoreconfig(backup)
1560 repo.baseui.restoreconfig(basebackup)
1560 repo.baseui.restoreconfig(basebackup)
1561
1561
1562
1562
1563 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1563 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1564
1564
1565 if not node:
1565 if not node:
1566 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1566 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1567 if stat[3]:
1567 if stat[3]:
1568 ui.status(_("nothing changed (%d missing files, see "
1568 ui.status(_("nothing changed (%d missing files, see "
1569 "'hg status')\n") % len(stat[3]))
1569 "'hg status')\n") % len(stat[3]))
1570 else:
1570 else:
1571 ui.status(_("nothing changed\n"))
1571 ui.status(_("nothing changed\n"))
1572 return 1
1572 return 1
1573
1573
1574 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1574 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1575
1575
1576 @command('config|showconfig|debugconfig',
1576 @command('config|showconfig|debugconfig',
1577 [('u', 'untrusted', None, _('show untrusted configuration options')),
1577 [('u', 'untrusted', None, _('show untrusted configuration options')),
1578 ('e', 'edit', None, _('edit user config')),
1578 ('e', 'edit', None, _('edit user config')),
1579 ('l', 'local', None, _('edit repository config')),
1579 ('l', 'local', None, _('edit repository config')),
1580 ('g', 'global', None, _('edit global config'))],
1580 ('g', 'global', None, _('edit global config'))],
1581 _('[-u] [NAME]...'),
1581 _('[-u] [NAME]...'),
1582 optionalrepo=True)
1582 optionalrepo=True)
1583 def config(ui, repo, *values, **opts):
1583 def config(ui, repo, *values, **opts):
1584 """show combined config settings from all hgrc files
1584 """show combined config settings from all hgrc files
1585
1585
1586 With no arguments, print names and values of all config items.
1586 With no arguments, print names and values of all config items.
1587
1587
1588 With one argument of the form section.name, print just the value
1588 With one argument of the form section.name, print just the value
1589 of that config item.
1589 of that config item.
1590
1590
1591 With multiple arguments, print names and values of all config
1591 With multiple arguments, print names and values of all config
1592 items with matching section names.
1592 items with matching section names.
1593
1593
1594 With --edit, start an editor on the user-level config file. With
1594 With --edit, start an editor on the user-level config file. With
1595 --global, edit the system-wide config file. With --local, edit the
1595 --global, edit the system-wide config file. With --local, edit the
1596 repository-level config file.
1596 repository-level config file.
1597
1597
1598 With --debug, the source (filename and line number) is printed
1598 With --debug, the source (filename and line number) is printed
1599 for each config item.
1599 for each config item.
1600
1600
1601 See :hg:`help config` for more information about config files.
1601 See :hg:`help config` for more information about config files.
1602
1602
1603 Returns 0 on success, 1 if NAME does not exist.
1603 Returns 0 on success, 1 if NAME does not exist.
1604
1604
1605 """
1605 """
1606
1606
1607 if opts.get('edit') or opts.get('local') or opts.get('global'):
1607 if opts.get('edit') or opts.get('local') or opts.get('global'):
1608 if opts.get('local') and opts.get('global'):
1608 if opts.get('local') and opts.get('global'):
1609 raise util.Abort(_("can't use --local and --global together"))
1609 raise util.Abort(_("can't use --local and --global together"))
1610
1610
1611 if opts.get('local'):
1611 if opts.get('local'):
1612 if not repo:
1612 if not repo:
1613 raise util.Abort(_("can't use --local outside a repository"))
1613 raise util.Abort(_("can't use --local outside a repository"))
1614 paths = [repo.join('hgrc')]
1614 paths = [repo.join('hgrc')]
1615 elif opts.get('global'):
1615 elif opts.get('global'):
1616 paths = scmutil.systemrcpath()
1616 paths = scmutil.systemrcpath()
1617 else:
1617 else:
1618 paths = scmutil.userrcpath()
1618 paths = scmutil.userrcpath()
1619
1619
1620 for f in paths:
1620 for f in paths:
1621 if os.path.exists(f):
1621 if os.path.exists(f):
1622 break
1622 break
1623 else:
1623 else:
1624 if opts.get('global'):
1624 if opts.get('global'):
1625 samplehgrc = uimod.samplehgrcs['global']
1625 samplehgrc = uimod.samplehgrcs['global']
1626 elif opts.get('local'):
1626 elif opts.get('local'):
1627 samplehgrc = uimod.samplehgrcs['local']
1627 samplehgrc = uimod.samplehgrcs['local']
1628 else:
1628 else:
1629 samplehgrc = uimod.samplehgrcs['user']
1629 samplehgrc = uimod.samplehgrcs['user']
1630
1630
1631 f = paths[0]
1631 f = paths[0]
1632 fp = open(f, "w")
1632 fp = open(f, "w")
1633 fp.write(samplehgrc)
1633 fp.write(samplehgrc)
1634 fp.close()
1634 fp.close()
1635
1635
1636 editor = ui.geteditor()
1636 editor = ui.geteditor()
1637 ui.system("%s \"%s\"" % (editor, f),
1637 ui.system("%s \"%s\"" % (editor, f),
1638 onerr=util.Abort, errprefix=_("edit failed"))
1638 onerr=util.Abort, errprefix=_("edit failed"))
1639 return
1639 return
1640
1640
1641 for f in scmutil.rcpath():
1641 for f in scmutil.rcpath():
1642 ui.debug('read config from: %s\n' % f)
1642 ui.debug('read config from: %s\n' % f)
1643 untrusted = bool(opts.get('untrusted'))
1643 untrusted = bool(opts.get('untrusted'))
1644 if values:
1644 if values:
1645 sections = [v for v in values if '.' not in v]
1645 sections = [v for v in values if '.' not in v]
1646 items = [v for v in values if '.' in v]
1646 items = [v for v in values if '.' in v]
1647 if len(items) > 1 or items and sections:
1647 if len(items) > 1 or items and sections:
1648 raise util.Abort(_('only one config item permitted'))
1648 raise util.Abort(_('only one config item permitted'))
1649 matched = False
1649 matched = False
1650 for section, name, value in ui.walkconfig(untrusted=untrusted):
1650 for section, name, value in ui.walkconfig(untrusted=untrusted):
1651 value = str(value).replace('\n', '\\n')
1651 value = str(value).replace('\n', '\\n')
1652 sectname = section + '.' + name
1652 sectname = section + '.' + name
1653 if values:
1653 if values:
1654 for v in values:
1654 for v in values:
1655 if v == section:
1655 if v == section:
1656 ui.debug('%s: ' %
1656 ui.debug('%s: ' %
1657 ui.configsource(section, name, untrusted))
1657 ui.configsource(section, name, untrusted))
1658 ui.write('%s=%s\n' % (sectname, value))
1658 ui.write('%s=%s\n' % (sectname, value))
1659 matched = True
1659 matched = True
1660 elif v == sectname:
1660 elif v == sectname:
1661 ui.debug('%s: ' %
1661 ui.debug('%s: ' %
1662 ui.configsource(section, name, untrusted))
1662 ui.configsource(section, name, untrusted))
1663 ui.write(value, '\n')
1663 ui.write(value, '\n')
1664 matched = True
1664 matched = True
1665 else:
1665 else:
1666 ui.debug('%s: ' %
1666 ui.debug('%s: ' %
1667 ui.configsource(section, name, untrusted))
1667 ui.configsource(section, name, untrusted))
1668 ui.write('%s=%s\n' % (sectname, value))
1668 ui.write('%s=%s\n' % (sectname, value))
1669 matched = True
1669 matched = True
1670 if matched:
1670 if matched:
1671 return 0
1671 return 0
1672 return 1
1672 return 1
1673
1673
1674 @command('copy|cp',
1674 @command('copy|cp',
1675 [('A', 'after', None, _('record a copy that has already occurred')),
1675 [('A', 'after', None, _('record a copy that has already occurred')),
1676 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1676 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1677 ] + walkopts + dryrunopts,
1677 ] + walkopts + dryrunopts,
1678 _('[OPTION]... [SOURCE]... DEST'))
1678 _('[OPTION]... [SOURCE]... DEST'))
1679 def copy(ui, repo, *pats, **opts):
1679 def copy(ui, repo, *pats, **opts):
1680 """mark files as copied for the next commit
1680 """mark files as copied for the next commit
1681
1681
1682 Mark dest as having copies of source files. If dest is a
1682 Mark dest as having copies of source files. If dest is a
1683 directory, copies are put in that directory. If dest is a file,
1683 directory, copies are put in that directory. If dest is a file,
1684 the source must be a single file.
1684 the source must be a single file.
1685
1685
1686 By default, this command copies the contents of files as they
1686 By default, this command copies the contents of files as they
1687 exist in the working directory. If invoked with -A/--after, the
1687 exist in the working directory. If invoked with -A/--after, the
1688 operation is recorded, but no copying is performed.
1688 operation is recorded, but no copying is performed.
1689
1689
1690 This command takes effect with the next commit. To undo a copy
1690 This command takes effect with the next commit. To undo a copy
1691 before that, see :hg:`revert`.
1691 before that, see :hg:`revert`.
1692
1692
1693 Returns 0 on success, 1 if errors are encountered.
1693 Returns 0 on success, 1 if errors are encountered.
1694 """
1694 """
1695 wlock = repo.wlock(False)
1695 wlock = repo.wlock(False)
1696 try:
1696 try:
1697 return cmdutil.copy(ui, repo, pats, opts)
1697 return cmdutil.copy(ui, repo, pats, opts)
1698 finally:
1698 finally:
1699 wlock.release()
1699 wlock.release()
1700
1700
1701 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1701 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1702 def debugancestor(ui, repo, *args):
1702 def debugancestor(ui, repo, *args):
1703 """find the ancestor revision of two revisions in a given index"""
1703 """find the ancestor revision of two revisions in a given index"""
1704 if len(args) == 3:
1704 if len(args) == 3:
1705 index, rev1, rev2 = args
1705 index, rev1, rev2 = args
1706 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1706 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1707 lookup = r.lookup
1707 lookup = r.lookup
1708 elif len(args) == 2:
1708 elif len(args) == 2:
1709 if not repo:
1709 if not repo:
1710 raise util.Abort(_("there is no Mercurial repository here "
1710 raise util.Abort(_("there is no Mercurial repository here "
1711 "(.hg not found)"))
1711 "(.hg not found)"))
1712 rev1, rev2 = args
1712 rev1, rev2 = args
1713 r = repo.changelog
1713 r = repo.changelog
1714 lookup = repo.lookup
1714 lookup = repo.lookup
1715 else:
1715 else:
1716 raise util.Abort(_('either two or three arguments required'))
1716 raise util.Abort(_('either two or three arguments required'))
1717 a = r.ancestor(lookup(rev1), lookup(rev2))
1717 a = r.ancestor(lookup(rev1), lookup(rev2))
1718 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1718 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1719
1719
1720 @command('debugbuilddag',
1720 @command('debugbuilddag',
1721 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1721 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1722 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1722 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1723 ('n', 'new-file', None, _('add new file at each rev'))],
1723 ('n', 'new-file', None, _('add new file at each rev'))],
1724 _('[OPTION]... [TEXT]'))
1724 _('[OPTION]... [TEXT]'))
1725 def debugbuilddag(ui, repo, text=None,
1725 def debugbuilddag(ui, repo, text=None,
1726 mergeable_file=False,
1726 mergeable_file=False,
1727 overwritten_file=False,
1727 overwritten_file=False,
1728 new_file=False):
1728 new_file=False):
1729 """builds a repo with a given DAG from scratch in the current empty repo
1729 """builds a repo with a given DAG from scratch in the current empty repo
1730
1730
1731 The description of the DAG is read from stdin if not given on the
1731 The description of the DAG is read from stdin if not given on the
1732 command line.
1732 command line.
1733
1733
1734 Elements:
1734 Elements:
1735
1735
1736 - "+n" is a linear run of n nodes based on the current default parent
1736 - "+n" is a linear run of n nodes based on the current default parent
1737 - "." is a single node based on the current default parent
1737 - "." is a single node based on the current default parent
1738 - "$" resets the default parent to null (implied at the start);
1738 - "$" resets the default parent to null (implied at the start);
1739 otherwise the default parent is always the last node created
1739 otherwise the default parent is always the last node created
1740 - "<p" sets the default parent to the backref p
1740 - "<p" sets the default parent to the backref p
1741 - "*p" is a fork at parent p, which is a backref
1741 - "*p" is a fork at parent p, which is a backref
1742 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1742 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1743 - "/p2" is a merge of the preceding node and p2
1743 - "/p2" is a merge of the preceding node and p2
1744 - ":tag" defines a local tag for the preceding node
1744 - ":tag" defines a local tag for the preceding node
1745 - "@branch" sets the named branch for subsequent nodes
1745 - "@branch" sets the named branch for subsequent nodes
1746 - "#...\\n" is a comment up to the end of the line
1746 - "#...\\n" is a comment up to the end of the line
1747
1747
1748 Whitespace between the above elements is ignored.
1748 Whitespace between the above elements is ignored.
1749
1749
1750 A backref is either
1750 A backref is either
1751
1751
1752 - a number n, which references the node curr-n, where curr is the current
1752 - a number n, which references the node curr-n, where curr is the current
1753 node, or
1753 node, or
1754 - the name of a local tag you placed earlier using ":tag", or
1754 - the name of a local tag you placed earlier using ":tag", or
1755 - empty to denote the default parent.
1755 - empty to denote the default parent.
1756
1756
1757 All string valued-elements are either strictly alphanumeric, or must
1757 All string valued-elements are either strictly alphanumeric, or must
1758 be enclosed in double quotes ("..."), with "\\" as escape character.
1758 be enclosed in double quotes ("..."), with "\\" as escape character.
1759 """
1759 """
1760
1760
1761 if text is None:
1761 if text is None:
1762 ui.status(_("reading DAG from stdin\n"))
1762 ui.status(_("reading DAG from stdin\n"))
1763 text = ui.fin.read()
1763 text = ui.fin.read()
1764
1764
1765 cl = repo.changelog
1765 cl = repo.changelog
1766 if len(cl) > 0:
1766 if len(cl) > 0:
1767 raise util.Abort(_('repository is not empty'))
1767 raise util.Abort(_('repository is not empty'))
1768
1768
1769 # determine number of revs in DAG
1769 # determine number of revs in DAG
1770 total = 0
1770 total = 0
1771 for type, data in dagparser.parsedag(text):
1771 for type, data in dagparser.parsedag(text):
1772 if type == 'n':
1772 if type == 'n':
1773 total += 1
1773 total += 1
1774
1774
1775 if mergeable_file:
1775 if mergeable_file:
1776 linesperrev = 2
1776 linesperrev = 2
1777 # make a file with k lines per rev
1777 # make a file with k lines per rev
1778 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1778 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1779 initialmergedlines.append("")
1779 initialmergedlines.append("")
1780
1780
1781 tags = []
1781 tags = []
1782
1782
1783 lock = tr = None
1783 lock = tr = None
1784 try:
1784 try:
1785 lock = repo.lock()
1785 lock = repo.lock()
1786 tr = repo.transaction("builddag")
1786 tr = repo.transaction("builddag")
1787
1787
1788 at = -1
1788 at = -1
1789 atbranch = 'default'
1789 atbranch = 'default'
1790 nodeids = []
1790 nodeids = []
1791 id = 0
1791 id = 0
1792 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1792 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1793 for type, data in dagparser.parsedag(text):
1793 for type, data in dagparser.parsedag(text):
1794 if type == 'n':
1794 if type == 'n':
1795 ui.note(('node %s\n' % str(data)))
1795 ui.note(('node %s\n' % str(data)))
1796 id, ps = data
1796 id, ps = data
1797
1797
1798 files = []
1798 files = []
1799 fctxs = {}
1799 fctxs = {}
1800
1800
1801 p2 = None
1801 p2 = None
1802 if mergeable_file:
1802 if mergeable_file:
1803 fn = "mf"
1803 fn = "mf"
1804 p1 = repo[ps[0]]
1804 p1 = repo[ps[0]]
1805 if len(ps) > 1:
1805 if len(ps) > 1:
1806 p2 = repo[ps[1]]
1806 p2 = repo[ps[1]]
1807 pa = p1.ancestor(p2)
1807 pa = p1.ancestor(p2)
1808 base, local, other = [x[fn].data() for x in (pa, p1,
1808 base, local, other = [x[fn].data() for x in (pa, p1,
1809 p2)]
1809 p2)]
1810 m3 = simplemerge.Merge3Text(base, local, other)
1810 m3 = simplemerge.Merge3Text(base, local, other)
1811 ml = [l.strip() for l in m3.merge_lines()]
1811 ml = [l.strip() for l in m3.merge_lines()]
1812 ml.append("")
1812 ml.append("")
1813 elif at > 0:
1813 elif at > 0:
1814 ml = p1[fn].data().split("\n")
1814 ml = p1[fn].data().split("\n")
1815 else:
1815 else:
1816 ml = initialmergedlines
1816 ml = initialmergedlines
1817 ml[id * linesperrev] += " r%i" % id
1817 ml[id * linesperrev] += " r%i" % id
1818 mergedtext = "\n".join(ml)
1818 mergedtext = "\n".join(ml)
1819 files.append(fn)
1819 files.append(fn)
1820 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1820 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1821
1821
1822 if overwritten_file:
1822 if overwritten_file:
1823 fn = "of"
1823 fn = "of"
1824 files.append(fn)
1824 files.append(fn)
1825 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1825 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1826
1826
1827 if new_file:
1827 if new_file:
1828 fn = "nf%i" % id
1828 fn = "nf%i" % id
1829 files.append(fn)
1829 files.append(fn)
1830 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1830 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1831 if len(ps) > 1:
1831 if len(ps) > 1:
1832 if not p2:
1832 if not p2:
1833 p2 = repo[ps[1]]
1833 p2 = repo[ps[1]]
1834 for fn in p2:
1834 for fn in p2:
1835 if fn.startswith("nf"):
1835 if fn.startswith("nf"):
1836 files.append(fn)
1836 files.append(fn)
1837 fctxs[fn] = p2[fn]
1837 fctxs[fn] = p2[fn]
1838
1838
1839 def fctxfn(repo, cx, path):
1839 def fctxfn(repo, cx, path):
1840 return fctxs.get(path)
1840 return fctxs.get(path)
1841
1841
1842 if len(ps) == 0 or ps[0] < 0:
1842 if len(ps) == 0 or ps[0] < 0:
1843 pars = [None, None]
1843 pars = [None, None]
1844 elif len(ps) == 1:
1844 elif len(ps) == 1:
1845 pars = [nodeids[ps[0]], None]
1845 pars = [nodeids[ps[0]], None]
1846 else:
1846 else:
1847 pars = [nodeids[p] for p in ps]
1847 pars = [nodeids[p] for p in ps]
1848 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1848 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1849 date=(id, 0),
1849 date=(id, 0),
1850 user="debugbuilddag",
1850 user="debugbuilddag",
1851 extra={'branch': atbranch})
1851 extra={'branch': atbranch})
1852 nodeid = repo.commitctx(cx)
1852 nodeid = repo.commitctx(cx)
1853 nodeids.append(nodeid)
1853 nodeids.append(nodeid)
1854 at = id
1854 at = id
1855 elif type == 'l':
1855 elif type == 'l':
1856 id, name = data
1856 id, name = data
1857 ui.note(('tag %s\n' % name))
1857 ui.note(('tag %s\n' % name))
1858 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1858 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1859 elif type == 'a':
1859 elif type == 'a':
1860 ui.note(('branch %s\n' % data))
1860 ui.note(('branch %s\n' % data))
1861 atbranch = data
1861 atbranch = data
1862 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1862 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1863 tr.close()
1863 tr.close()
1864
1864
1865 if tags:
1865 if tags:
1866 repo.vfs.write("localtags", "".join(tags))
1866 repo.vfs.write("localtags", "".join(tags))
1867 finally:
1867 finally:
1868 ui.progress(_('building'), None)
1868 ui.progress(_('building'), None)
1869 release(tr, lock)
1869 release(tr, lock)
1870
1870
1871 @command('debugbundle',
1871 @command('debugbundle',
1872 [('a', 'all', None, _('show all details'))],
1872 [('a', 'all', None, _('show all details'))],
1873 _('FILE'),
1873 _('FILE'),
1874 norepo=True)
1874 norepo=True)
1875 def debugbundle(ui, bundlepath, all=None, **opts):
1875 def debugbundle(ui, bundlepath, all=None, **opts):
1876 """lists the contents of a bundle"""
1876 """lists the contents of a bundle"""
1877 f = hg.openpath(ui, bundlepath)
1877 f = hg.openpath(ui, bundlepath)
1878 try:
1878 try:
1879 gen = exchange.readbundle(ui, f, bundlepath)
1879 gen = exchange.readbundle(ui, f, bundlepath)
1880 if isinstance(gen, bundle2.unbundle20):
1880 if isinstance(gen, bundle2.unbundle20):
1881 return _debugbundle2(ui, gen, all=all, **opts)
1881 return _debugbundle2(ui, gen, all=all, **opts)
1882 if all:
1882 if all:
1883 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1883 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1884
1884
1885 def showchunks(named):
1885 def showchunks(named):
1886 ui.write("\n%s\n" % named)
1886 ui.write("\n%s\n" % named)
1887 chain = None
1887 chain = None
1888 while True:
1888 while True:
1889 chunkdata = gen.deltachunk(chain)
1889 chunkdata = gen.deltachunk(chain)
1890 if not chunkdata:
1890 if not chunkdata:
1891 break
1891 break
1892 node = chunkdata['node']
1892 node = chunkdata['node']
1893 p1 = chunkdata['p1']
1893 p1 = chunkdata['p1']
1894 p2 = chunkdata['p2']
1894 p2 = chunkdata['p2']
1895 cs = chunkdata['cs']
1895 cs = chunkdata['cs']
1896 deltabase = chunkdata['deltabase']
1896 deltabase = chunkdata['deltabase']
1897 delta = chunkdata['delta']
1897 delta = chunkdata['delta']
1898 ui.write("%s %s %s %s %s %s\n" %
1898 ui.write("%s %s %s %s %s %s\n" %
1899 (hex(node), hex(p1), hex(p2),
1899 (hex(node), hex(p1), hex(p2),
1900 hex(cs), hex(deltabase), len(delta)))
1900 hex(cs), hex(deltabase), len(delta)))
1901 chain = node
1901 chain = node
1902
1902
1903 chunkdata = gen.changelogheader()
1903 chunkdata = gen.changelogheader()
1904 showchunks("changelog")
1904 showchunks("changelog")
1905 chunkdata = gen.manifestheader()
1905 chunkdata = gen.manifestheader()
1906 showchunks("manifest")
1906 showchunks("manifest")
1907 while True:
1907 while True:
1908 chunkdata = gen.filelogheader()
1908 chunkdata = gen.filelogheader()
1909 if not chunkdata:
1909 if not chunkdata:
1910 break
1910 break
1911 fname = chunkdata['filename']
1911 fname = chunkdata['filename']
1912 showchunks(fname)
1912 showchunks(fname)
1913 else:
1913 else:
1914 if isinstance(gen, bundle2.unbundle20):
1914 if isinstance(gen, bundle2.unbundle20):
1915 raise util.Abort(_('use debugbundle2 for this file'))
1915 raise util.Abort(_('use debugbundle2 for this file'))
1916 chunkdata = gen.changelogheader()
1916 chunkdata = gen.changelogheader()
1917 chain = None
1917 chain = None
1918 while True:
1918 while True:
1919 chunkdata = gen.deltachunk(chain)
1919 chunkdata = gen.deltachunk(chain)
1920 if not chunkdata:
1920 if not chunkdata:
1921 break
1921 break
1922 node = chunkdata['node']
1922 node = chunkdata['node']
1923 ui.write("%s\n" % hex(node))
1923 ui.write("%s\n" % hex(node))
1924 chain = node
1924 chain = node
1925 finally:
1925 finally:
1926 f.close()
1926 f.close()
1927
1927
1928 def _debugbundle2(ui, gen, **opts):
1928 def _debugbundle2(ui, gen, **opts):
1929 """lists the contents of a bundle2"""
1929 """lists the contents of a bundle2"""
1930 if not isinstance(gen, bundle2.unbundle20):
1930 if not isinstance(gen, bundle2.unbundle20):
1931 raise util.Abort(_('not a bundle2 file'))
1931 raise util.Abort(_('not a bundle2 file'))
1932 ui.write(('Stream params: %s\n' % repr(gen.params)))
1932 ui.write(('Stream params: %s\n' % repr(gen.params)))
1933 for part in gen.iterparts():
1933 for part in gen.iterparts():
1934 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1934 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1935 if part.type == 'changegroup':
1935 if part.type == 'changegroup':
1936 version = part.params.get('version', '01')
1936 version = part.params.get('version', '01')
1937 cg = changegroup.packermap[version][1](part, 'UN')
1937 cg = changegroup.packermap[version][1](part, 'UN')
1938 chunkdata = cg.changelogheader()
1938 chunkdata = cg.changelogheader()
1939 chain = None
1939 chain = None
1940 while True:
1940 while True:
1941 chunkdata = cg.deltachunk(chain)
1941 chunkdata = cg.deltachunk(chain)
1942 if not chunkdata:
1942 if not chunkdata:
1943 break
1943 break
1944 node = chunkdata['node']
1944 node = chunkdata['node']
1945 ui.write(" %s\n" % hex(node))
1945 ui.write(" %s\n" % hex(node))
1946 chain = node
1946 chain = node
1947
1947
1948 @command('debugcheckstate', [], '')
1948 @command('debugcheckstate', [], '')
1949 def debugcheckstate(ui, repo):
1949 def debugcheckstate(ui, repo):
1950 """validate the correctness of the current dirstate"""
1950 """validate the correctness of the current dirstate"""
1951 parent1, parent2 = repo.dirstate.parents()
1951 parent1, parent2 = repo.dirstate.parents()
1952 m1 = repo[parent1].manifest()
1952 m1 = repo[parent1].manifest()
1953 m2 = repo[parent2].manifest()
1953 m2 = repo[parent2].manifest()
1954 errors = 0
1954 errors = 0
1955 for f in repo.dirstate:
1955 for f in repo.dirstate:
1956 state = repo.dirstate[f]
1956 state = repo.dirstate[f]
1957 if state in "nr" and f not in m1:
1957 if state in "nr" and f not in m1:
1958 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1958 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1959 errors += 1
1959 errors += 1
1960 if state in "a" and f in m1:
1960 if state in "a" and f in m1:
1961 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1961 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1962 errors += 1
1962 errors += 1
1963 if state in "m" and f not in m1 and f not in m2:
1963 if state in "m" and f not in m1 and f not in m2:
1964 ui.warn(_("%s in state %s, but not in either manifest\n") %
1964 ui.warn(_("%s in state %s, but not in either manifest\n") %
1965 (f, state))
1965 (f, state))
1966 errors += 1
1966 errors += 1
1967 for f in m1:
1967 for f in m1:
1968 state = repo.dirstate[f]
1968 state = repo.dirstate[f]
1969 if state not in "nrm":
1969 if state not in "nrm":
1970 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1970 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1971 errors += 1
1971 errors += 1
1972 if errors:
1972 if errors:
1973 error = _(".hg/dirstate inconsistent with current parent's manifest")
1973 error = _(".hg/dirstate inconsistent with current parent's manifest")
1974 raise util.Abort(error)
1974 raise util.Abort(error)
1975
1975
1976 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1976 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1977 def debugcommands(ui, cmd='', *args):
1977 def debugcommands(ui, cmd='', *args):
1978 """list all available commands and options"""
1978 """list all available commands and options"""
1979 for cmd, vals in sorted(table.iteritems()):
1979 for cmd, vals in sorted(table.iteritems()):
1980 cmd = cmd.split('|')[0].strip('^')
1980 cmd = cmd.split('|')[0].strip('^')
1981 opts = ', '.join([i[1] for i in vals[1]])
1981 opts = ', '.join([i[1] for i in vals[1]])
1982 ui.write('%s: %s\n' % (cmd, opts))
1982 ui.write('%s: %s\n' % (cmd, opts))
1983
1983
1984 @command('debugcomplete',
1984 @command('debugcomplete',
1985 [('o', 'options', None, _('show the command options'))],
1985 [('o', 'options', None, _('show the command options'))],
1986 _('[-o] CMD'),
1986 _('[-o] CMD'),
1987 norepo=True)
1987 norepo=True)
1988 def debugcomplete(ui, cmd='', **opts):
1988 def debugcomplete(ui, cmd='', **opts):
1989 """returns the completion list associated with the given command"""
1989 """returns the completion list associated with the given command"""
1990
1990
1991 if opts.get('options'):
1991 if opts.get('options'):
1992 options = []
1992 options = []
1993 otables = [globalopts]
1993 otables = [globalopts]
1994 if cmd:
1994 if cmd:
1995 aliases, entry = cmdutil.findcmd(cmd, table, False)
1995 aliases, entry = cmdutil.findcmd(cmd, table, False)
1996 otables.append(entry[1])
1996 otables.append(entry[1])
1997 for t in otables:
1997 for t in otables:
1998 for o in t:
1998 for o in t:
1999 if "(DEPRECATED)" in o[3]:
1999 if "(DEPRECATED)" in o[3]:
2000 continue
2000 continue
2001 if o[0]:
2001 if o[0]:
2002 options.append('-%s' % o[0])
2002 options.append('-%s' % o[0])
2003 options.append('--%s' % o[1])
2003 options.append('--%s' % o[1])
2004 ui.write("%s\n" % "\n".join(options))
2004 ui.write("%s\n" % "\n".join(options))
2005 return
2005 return
2006
2006
2007 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2007 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2008 if ui.verbose:
2008 if ui.verbose:
2009 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2009 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2010 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2010 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2011
2011
2012 @command('debugdag',
2012 @command('debugdag',
2013 [('t', 'tags', None, _('use tags as labels')),
2013 [('t', 'tags', None, _('use tags as labels')),
2014 ('b', 'branches', None, _('annotate with branch names')),
2014 ('b', 'branches', None, _('annotate with branch names')),
2015 ('', 'dots', None, _('use dots for runs')),
2015 ('', 'dots', None, _('use dots for runs')),
2016 ('s', 'spaces', None, _('separate elements by spaces'))],
2016 ('s', 'spaces', None, _('separate elements by spaces'))],
2017 _('[OPTION]... [FILE [REV]...]'),
2017 _('[OPTION]... [FILE [REV]...]'),
2018 optionalrepo=True)
2018 optionalrepo=True)
2019 def debugdag(ui, repo, file_=None, *revs, **opts):
2019 def debugdag(ui, repo, file_=None, *revs, **opts):
2020 """format the changelog or an index DAG as a concise textual description
2020 """format the changelog or an index DAG as a concise textual description
2021
2021
2022 If you pass a revlog index, the revlog's DAG is emitted. If you list
2022 If you pass a revlog index, the revlog's DAG is emitted. If you list
2023 revision numbers, they get labeled in the output as rN.
2023 revision numbers, they get labeled in the output as rN.
2024
2024
2025 Otherwise, the changelog DAG of the current repo is emitted.
2025 Otherwise, the changelog DAG of the current repo is emitted.
2026 """
2026 """
2027 spaces = opts.get('spaces')
2027 spaces = opts.get('spaces')
2028 dots = opts.get('dots')
2028 dots = opts.get('dots')
2029 if file_:
2029 if file_:
2030 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2030 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2031 revs = set((int(r) for r in revs))
2031 revs = set((int(r) for r in revs))
2032 def events():
2032 def events():
2033 for r in rlog:
2033 for r in rlog:
2034 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2034 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2035 if p != -1))
2035 if p != -1))
2036 if r in revs:
2036 if r in revs:
2037 yield 'l', (r, "r%i" % r)
2037 yield 'l', (r, "r%i" % r)
2038 elif repo:
2038 elif repo:
2039 cl = repo.changelog
2039 cl = repo.changelog
2040 tags = opts.get('tags')
2040 tags = opts.get('tags')
2041 branches = opts.get('branches')
2041 branches = opts.get('branches')
2042 if tags:
2042 if tags:
2043 labels = {}
2043 labels = {}
2044 for l, n in repo.tags().items():
2044 for l, n in repo.tags().items():
2045 labels.setdefault(cl.rev(n), []).append(l)
2045 labels.setdefault(cl.rev(n), []).append(l)
2046 def events():
2046 def events():
2047 b = "default"
2047 b = "default"
2048 for r in cl:
2048 for r in cl:
2049 if branches:
2049 if branches:
2050 newb = cl.read(cl.node(r))[5]['branch']
2050 newb = cl.read(cl.node(r))[5]['branch']
2051 if newb != b:
2051 if newb != b:
2052 yield 'a', newb
2052 yield 'a', newb
2053 b = newb
2053 b = newb
2054 yield 'n', (r, list(p for p in cl.parentrevs(r)
2054 yield 'n', (r, list(p for p in cl.parentrevs(r)
2055 if p != -1))
2055 if p != -1))
2056 if tags:
2056 if tags:
2057 ls = labels.get(r)
2057 ls = labels.get(r)
2058 if ls:
2058 if ls:
2059 for l in ls:
2059 for l in ls:
2060 yield 'l', (r, l)
2060 yield 'l', (r, l)
2061 else:
2061 else:
2062 raise util.Abort(_('need repo for changelog dag'))
2062 raise util.Abort(_('need repo for changelog dag'))
2063
2063
2064 for line in dagparser.dagtextlines(events(),
2064 for line in dagparser.dagtextlines(events(),
2065 addspaces=spaces,
2065 addspaces=spaces,
2066 wraplabels=True,
2066 wraplabels=True,
2067 wrapannotations=True,
2067 wrapannotations=True,
2068 wrapnonlinear=dots,
2068 wrapnonlinear=dots,
2069 usedots=dots,
2069 usedots=dots,
2070 maxlinewidth=70):
2070 maxlinewidth=70):
2071 ui.write(line)
2071 ui.write(line)
2072 ui.write("\n")
2072 ui.write("\n")
2073
2073
2074 @command('debugdata',
2074 @command('debugdata',
2075 [('c', 'changelog', False, _('open changelog')),
2075 [('c', 'changelog', False, _('open changelog')),
2076 ('m', 'manifest', False, _('open manifest')),
2076 ('m', 'manifest', False, _('open manifest')),
2077 ('', 'dir', False, _('open directory manifest'))],
2077 ('', 'dir', False, _('open directory manifest'))],
2078 _('-c|-m|FILE REV'))
2078 _('-c|-m|FILE REV'))
2079 def debugdata(ui, repo, file_, rev=None, **opts):
2079 def debugdata(ui, repo, file_, rev=None, **opts):
2080 """dump the contents of a data file revision"""
2080 """dump the contents of a data file revision"""
2081 if opts.get('changelog') or opts.get('manifest'):
2081 if opts.get('changelog') or opts.get('manifest'):
2082 file_, rev = None, file_
2082 file_, rev = None, file_
2083 elif rev is None:
2083 elif rev is None:
2084 raise error.CommandError('debugdata', _('invalid arguments'))
2084 raise error.CommandError('debugdata', _('invalid arguments'))
2085 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2085 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2086 try:
2086 try:
2087 ui.write(r.revision(r.lookup(rev)))
2087 ui.write(r.revision(r.lookup(rev)))
2088 except KeyError:
2088 except KeyError:
2089 raise util.Abort(_('invalid revision identifier %s') % rev)
2089 raise util.Abort(_('invalid revision identifier %s') % rev)
2090
2090
2091 @command('debugdate',
2091 @command('debugdate',
2092 [('e', 'extended', None, _('try extended date formats'))],
2092 [('e', 'extended', None, _('try extended date formats'))],
2093 _('[-e] DATE [RANGE]'),
2093 _('[-e] DATE [RANGE]'),
2094 norepo=True, optionalrepo=True)
2094 norepo=True, optionalrepo=True)
2095 def debugdate(ui, date, range=None, **opts):
2095 def debugdate(ui, date, range=None, **opts):
2096 """parse and display a date"""
2096 """parse and display a date"""
2097 if opts["extended"]:
2097 if opts["extended"]:
2098 d = util.parsedate(date, util.extendeddateformats)
2098 d = util.parsedate(date, util.extendeddateformats)
2099 else:
2099 else:
2100 d = util.parsedate(date)
2100 d = util.parsedate(date)
2101 ui.write(("internal: %s %s\n") % d)
2101 ui.write(("internal: %s %s\n") % d)
2102 ui.write(("standard: %s\n") % util.datestr(d))
2102 ui.write(("standard: %s\n") % util.datestr(d))
2103 if range:
2103 if range:
2104 m = util.matchdate(range)
2104 m = util.matchdate(range)
2105 ui.write(("match: %s\n") % m(d[0]))
2105 ui.write(("match: %s\n") % m(d[0]))
2106
2106
2107 @command('debugdiscovery',
2107 @command('debugdiscovery',
2108 [('', 'old', None, _('use old-style discovery')),
2108 [('', 'old', None, _('use old-style discovery')),
2109 ('', 'nonheads', None,
2109 ('', 'nonheads', None,
2110 _('use old-style discovery with non-heads included')),
2110 _('use old-style discovery with non-heads included')),
2111 ] + remoteopts,
2111 ] + remoteopts,
2112 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2112 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2113 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2113 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2114 """runs the changeset discovery protocol in isolation"""
2114 """runs the changeset discovery protocol in isolation"""
2115 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2115 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2116 opts.get('branch'))
2116 opts.get('branch'))
2117 remote = hg.peer(repo, opts, remoteurl)
2117 remote = hg.peer(repo, opts, remoteurl)
2118 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2118 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2119
2119
2120 # make sure tests are repeatable
2120 # make sure tests are repeatable
2121 random.seed(12323)
2121 random.seed(12323)
2122
2122
2123 def doit(localheads, remoteheads, remote=remote):
2123 def doit(localheads, remoteheads, remote=remote):
2124 if opts.get('old'):
2124 if opts.get('old'):
2125 if localheads:
2125 if localheads:
2126 raise util.Abort('cannot use localheads with old style '
2126 raise util.Abort('cannot use localheads with old style '
2127 'discovery')
2127 'discovery')
2128 if not util.safehasattr(remote, 'branches'):
2128 if not util.safehasattr(remote, 'branches'):
2129 # enable in-client legacy support
2129 # enable in-client legacy support
2130 remote = localrepo.locallegacypeer(remote.local())
2130 remote = localrepo.locallegacypeer(remote.local())
2131 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2131 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2132 force=True)
2132 force=True)
2133 common = set(common)
2133 common = set(common)
2134 if not opts.get('nonheads'):
2134 if not opts.get('nonheads'):
2135 ui.write(("unpruned common: %s\n") %
2135 ui.write(("unpruned common: %s\n") %
2136 " ".join(sorted(short(n) for n in common)))
2136 " ".join(sorted(short(n) for n in common)))
2137 dag = dagutil.revlogdag(repo.changelog)
2137 dag = dagutil.revlogdag(repo.changelog)
2138 all = dag.ancestorset(dag.internalizeall(common))
2138 all = dag.ancestorset(dag.internalizeall(common))
2139 common = dag.externalizeall(dag.headsetofconnecteds(all))
2139 common = dag.externalizeall(dag.headsetofconnecteds(all))
2140 else:
2140 else:
2141 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2141 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2142 common = set(common)
2142 common = set(common)
2143 rheads = set(hds)
2143 rheads = set(hds)
2144 lheads = set(repo.heads())
2144 lheads = set(repo.heads())
2145 ui.write(("common heads: %s\n") %
2145 ui.write(("common heads: %s\n") %
2146 " ".join(sorted(short(n) for n in common)))
2146 " ".join(sorted(short(n) for n in common)))
2147 if lheads <= common:
2147 if lheads <= common:
2148 ui.write(("local is subset\n"))
2148 ui.write(("local is subset\n"))
2149 elif rheads <= common:
2149 elif rheads <= common:
2150 ui.write(("remote is subset\n"))
2150 ui.write(("remote is subset\n"))
2151
2151
2152 serverlogs = opts.get('serverlog')
2152 serverlogs = opts.get('serverlog')
2153 if serverlogs:
2153 if serverlogs:
2154 for filename in serverlogs:
2154 for filename in serverlogs:
2155 logfile = open(filename, 'r')
2155 logfile = open(filename, 'r')
2156 try:
2156 try:
2157 line = logfile.readline()
2157 line = logfile.readline()
2158 while line:
2158 while line:
2159 parts = line.strip().split(';')
2159 parts = line.strip().split(';')
2160 op = parts[1]
2160 op = parts[1]
2161 if op == 'cg':
2161 if op == 'cg':
2162 pass
2162 pass
2163 elif op == 'cgss':
2163 elif op == 'cgss':
2164 doit(parts[2].split(' '), parts[3].split(' '))
2164 doit(parts[2].split(' '), parts[3].split(' '))
2165 elif op == 'unb':
2165 elif op == 'unb':
2166 doit(parts[3].split(' '), parts[2].split(' '))
2166 doit(parts[3].split(' '), parts[2].split(' '))
2167 line = logfile.readline()
2167 line = logfile.readline()
2168 finally:
2168 finally:
2169 logfile.close()
2169 logfile.close()
2170
2170
2171 else:
2171 else:
2172 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2172 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2173 opts.get('remote_head'))
2173 opts.get('remote_head'))
2174 localrevs = opts.get('local_head')
2174 localrevs = opts.get('local_head')
2175 doit(localrevs, remoterevs)
2175 doit(localrevs, remoterevs)
2176
2176
2177 @command('debugfileset',
2177 @command('debugfileset',
2178 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2178 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2179 _('[-r REV] FILESPEC'))
2179 _('[-r REV] FILESPEC'))
2180 def debugfileset(ui, repo, expr, **opts):
2180 def debugfileset(ui, repo, expr, **opts):
2181 '''parse and apply a fileset specification'''
2181 '''parse and apply a fileset specification'''
2182 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2182 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2183 if ui.verbose:
2183 if ui.verbose:
2184 tree = fileset.parse(expr)
2184 tree = fileset.parse(expr)
2185 ui.note(fileset.prettyformat(tree), "\n")
2185 ui.note(fileset.prettyformat(tree), "\n")
2186
2186
2187 for f in ctx.getfileset(expr):
2187 for f in ctx.getfileset(expr):
2188 ui.write("%s\n" % f)
2188 ui.write("%s\n" % f)
2189
2189
2190 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2190 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2191 def debugfsinfo(ui, path="."):
2191 def debugfsinfo(ui, path="."):
2192 """show information detected about current filesystem"""
2192 """show information detected about current filesystem"""
2193 util.writefile('.debugfsinfo', '')
2193 util.writefile('.debugfsinfo', '')
2194 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2194 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2195 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2195 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2196 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2196 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2197 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2197 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2198 and 'yes' or 'no'))
2198 and 'yes' or 'no'))
2199 os.unlink('.debugfsinfo')
2199 os.unlink('.debugfsinfo')
2200
2200
2201 @command('debuggetbundle',
2201 @command('debuggetbundle',
2202 [('H', 'head', [], _('id of head node'), _('ID')),
2202 [('H', 'head', [], _('id of head node'), _('ID')),
2203 ('C', 'common', [], _('id of common node'), _('ID')),
2203 ('C', 'common', [], _('id of common node'), _('ID')),
2204 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2204 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2205 _('REPO FILE [-H|-C ID]...'),
2205 _('REPO FILE [-H|-C ID]...'),
2206 norepo=True)
2206 norepo=True)
2207 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2207 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2208 """retrieves a bundle from a repo
2208 """retrieves a bundle from a repo
2209
2209
2210 Every ID must be a full-length hex node id string. Saves the bundle to the
2210 Every ID must be a full-length hex node id string. Saves the bundle to the
2211 given file.
2211 given file.
2212 """
2212 """
2213 repo = hg.peer(ui, opts, repopath)
2213 repo = hg.peer(ui, opts, repopath)
2214 if not repo.capable('getbundle'):
2214 if not repo.capable('getbundle'):
2215 raise util.Abort("getbundle() not supported by target repository")
2215 raise util.Abort("getbundle() not supported by target repository")
2216 args = {}
2216 args = {}
2217 if common:
2217 if common:
2218 args['common'] = [bin(s) for s in common]
2218 args['common'] = [bin(s) for s in common]
2219 if head:
2219 if head:
2220 args['heads'] = [bin(s) for s in head]
2220 args['heads'] = [bin(s) for s in head]
2221 # TODO: get desired bundlecaps from command line.
2221 # TODO: get desired bundlecaps from command line.
2222 args['bundlecaps'] = None
2222 args['bundlecaps'] = None
2223 bundle = repo.getbundle('debug', **args)
2223 bundle = repo.getbundle('debug', **args)
2224
2224
2225 bundletype = opts.get('type', 'bzip2').lower()
2225 bundletype = opts.get('type', 'bzip2').lower()
2226 btypes = {'none': 'HG10UN',
2226 btypes = {'none': 'HG10UN',
2227 'bzip2': 'HG10BZ',
2227 'bzip2': 'HG10BZ',
2228 'gzip': 'HG10GZ',
2228 'gzip': 'HG10GZ',
2229 'bundle2': 'HG20'}
2229 'bundle2': 'HG20'}
2230 bundletype = btypes.get(bundletype)
2230 bundletype = btypes.get(bundletype)
2231 if bundletype not in changegroup.bundletypes:
2231 if bundletype not in changegroup.bundletypes:
2232 raise util.Abort(_('unknown bundle type specified with --type'))
2232 raise util.Abort(_('unknown bundle type specified with --type'))
2233 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2233 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2234
2234
2235 @command('debugignore', [], '')
2235 @command('debugignore', [], '')
2236 def debugignore(ui, repo, *values, **opts):
2236 def debugignore(ui, repo, *values, **opts):
2237 """display the combined ignore pattern"""
2237 """display the combined ignore pattern"""
2238 ignore = repo.dirstate._ignore
2238 ignore = repo.dirstate._ignore
2239 includepat = getattr(ignore, 'includepat', None)
2239 includepat = getattr(ignore, 'includepat', None)
2240 if includepat is not None:
2240 if includepat is not None:
2241 ui.write("%s\n" % includepat)
2241 ui.write("%s\n" % includepat)
2242 else:
2242 else:
2243 raise util.Abort(_("no ignore patterns found"))
2243 raise util.Abort(_("no ignore patterns found"))
2244
2244
2245 @command('debugindex',
2245 @command('debugindex',
2246 [('c', 'changelog', False, _('open changelog')),
2246 [('c', 'changelog', False, _('open changelog')),
2247 ('m', 'manifest', False, _('open manifest')),
2247 ('m', 'manifest', False, _('open manifest')),
2248 ('', 'dir', False, _('open directory manifest')),
2248 ('', 'dir', False, _('open directory manifest')),
2249 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2249 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2250 _('[-f FORMAT] -c|-m|FILE'),
2250 _('[-f FORMAT] -c|-m|FILE'),
2251 optionalrepo=True)
2251 optionalrepo=True)
2252 def debugindex(ui, repo, file_=None, **opts):
2252 def debugindex(ui, repo, file_=None, **opts):
2253 """dump the contents of an index file"""
2253 """dump the contents of an index file"""
2254 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2254 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2255 format = opts.get('format', 0)
2255 format = opts.get('format', 0)
2256 if format not in (0, 1):
2256 if format not in (0, 1):
2257 raise util.Abort(_("unknown format %d") % format)
2257 raise util.Abort(_("unknown format %d") % format)
2258
2258
2259 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2259 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2260 if generaldelta:
2260 if generaldelta:
2261 basehdr = ' delta'
2261 basehdr = ' delta'
2262 else:
2262 else:
2263 basehdr = ' base'
2263 basehdr = ' base'
2264
2264
2265 if ui.debugflag:
2265 if ui.debugflag:
2266 shortfn = hex
2266 shortfn = hex
2267 else:
2267 else:
2268 shortfn = short
2268 shortfn = short
2269
2269
2270 # There might not be anything in r, so have a sane default
2270 # There might not be anything in r, so have a sane default
2271 idlen = 12
2271 idlen = 12
2272 for i in r:
2272 for i in r:
2273 idlen = len(shortfn(r.node(i)))
2273 idlen = len(shortfn(r.node(i)))
2274 break
2274 break
2275
2275
2276 if format == 0:
2276 if format == 0:
2277 ui.write(" rev offset length " + basehdr + " linkrev"
2277 ui.write(" rev offset length " + basehdr + " linkrev"
2278 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2278 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2279 elif format == 1:
2279 elif format == 1:
2280 ui.write(" rev flag offset length"
2280 ui.write(" rev flag offset length"
2281 " size " + basehdr + " link p1 p2"
2281 " size " + basehdr + " link p1 p2"
2282 " %s\n" % "nodeid".rjust(idlen))
2282 " %s\n" % "nodeid".rjust(idlen))
2283
2283
2284 for i in r:
2284 for i in r:
2285 node = r.node(i)
2285 node = r.node(i)
2286 if generaldelta:
2286 if generaldelta:
2287 base = r.deltaparent(i)
2287 base = r.deltaparent(i)
2288 else:
2288 else:
2289 base = r.chainbase(i)
2289 base = r.chainbase(i)
2290 if format == 0:
2290 if format == 0:
2291 try:
2291 try:
2292 pp = r.parents(node)
2292 pp = r.parents(node)
2293 except Exception:
2293 except Exception:
2294 pp = [nullid, nullid]
2294 pp = [nullid, nullid]
2295 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2295 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2296 i, r.start(i), r.length(i), base, r.linkrev(i),
2296 i, r.start(i), r.length(i), base, r.linkrev(i),
2297 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2297 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2298 elif format == 1:
2298 elif format == 1:
2299 pr = r.parentrevs(i)
2299 pr = r.parentrevs(i)
2300 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2300 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2301 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2301 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2302 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2302 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2303
2303
2304 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2304 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2305 def debugindexdot(ui, repo, file_):
2305 def debugindexdot(ui, repo, file_):
2306 """dump an index DAG as a graphviz dot file"""
2306 """dump an index DAG as a graphviz dot file"""
2307 r = None
2307 r = None
2308 if repo:
2308 if repo:
2309 filelog = repo.file(file_)
2309 filelog = repo.file(file_)
2310 if len(filelog):
2310 if len(filelog):
2311 r = filelog
2311 r = filelog
2312 if not r:
2312 if not r:
2313 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2313 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2314 ui.write(("digraph G {\n"))
2314 ui.write(("digraph G {\n"))
2315 for i in r:
2315 for i in r:
2316 node = r.node(i)
2316 node = r.node(i)
2317 pp = r.parents(node)
2317 pp = r.parents(node)
2318 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2318 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2319 if pp[1] != nullid:
2319 if pp[1] != nullid:
2320 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2320 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2321 ui.write("}\n")
2321 ui.write("}\n")
2322
2322
2323 @command('debuginstall', [], '', norepo=True)
2323 @command('debuginstall', [], '', norepo=True)
2324 def debuginstall(ui):
2324 def debuginstall(ui):
2325 '''test Mercurial installation
2325 '''test Mercurial installation
2326
2326
2327 Returns 0 on success.
2327 Returns 0 on success.
2328 '''
2328 '''
2329
2329
2330 def writetemp(contents):
2330 def writetemp(contents):
2331 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2331 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2332 f = os.fdopen(fd, "wb")
2332 f = os.fdopen(fd, "wb")
2333 f.write(contents)
2333 f.write(contents)
2334 f.close()
2334 f.close()
2335 return name
2335 return name
2336
2336
2337 problems = 0
2337 problems = 0
2338
2338
2339 # encoding
2339 # encoding
2340 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2340 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2341 try:
2341 try:
2342 encoding.fromlocal("test")
2342 encoding.fromlocal("test")
2343 except util.Abort, inst:
2343 except util.Abort, inst:
2344 ui.write(" %s\n" % inst)
2344 ui.write(" %s\n" % inst)
2345 ui.write(_(" (check that your locale is properly set)\n"))
2345 ui.write(_(" (check that your locale is properly set)\n"))
2346 problems += 1
2346 problems += 1
2347
2347
2348 # Python
2348 # Python
2349 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2349 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2350 ui.status(_("checking Python version (%s)\n")
2350 ui.status(_("checking Python version (%s)\n")
2351 % ("%s.%s.%s" % sys.version_info[:3]))
2351 % ("%s.%s.%s" % sys.version_info[:3]))
2352 ui.status(_("checking Python lib (%s)...\n")
2352 ui.status(_("checking Python lib (%s)...\n")
2353 % os.path.dirname(os.__file__))
2353 % os.path.dirname(os.__file__))
2354
2354
2355 # compiled modules
2355 # compiled modules
2356 ui.status(_("checking installed modules (%s)...\n")
2356 ui.status(_("checking installed modules (%s)...\n")
2357 % os.path.dirname(__file__))
2357 % os.path.dirname(__file__))
2358 try:
2358 try:
2359 import bdiff, mpatch, base85, osutil
2359 import bdiff, mpatch, base85, osutil
2360 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2360 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2361 except Exception, inst:
2361 except Exception, inst:
2362 ui.write(" %s\n" % inst)
2362 ui.write(" %s\n" % inst)
2363 ui.write(_(" One or more extensions could not be found"))
2363 ui.write(_(" One or more extensions could not be found"))
2364 ui.write(_(" (check that you compiled the extensions)\n"))
2364 ui.write(_(" (check that you compiled the extensions)\n"))
2365 problems += 1
2365 problems += 1
2366
2366
2367 # templates
2367 # templates
2368 import templater
2368 import templater
2369 p = templater.templatepaths()
2369 p = templater.templatepaths()
2370 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2370 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2371 if p:
2371 if p:
2372 m = templater.templatepath("map-cmdline.default")
2372 m = templater.templatepath("map-cmdline.default")
2373 if m:
2373 if m:
2374 # template found, check if it is working
2374 # template found, check if it is working
2375 try:
2375 try:
2376 templater.templater(m)
2376 templater.templater(m)
2377 except Exception, inst:
2377 except Exception, inst:
2378 ui.write(" %s\n" % inst)
2378 ui.write(" %s\n" % inst)
2379 p = None
2379 p = None
2380 else:
2380 else:
2381 ui.write(_(" template 'default' not found\n"))
2381 ui.write(_(" template 'default' not found\n"))
2382 p = None
2382 p = None
2383 else:
2383 else:
2384 ui.write(_(" no template directories found\n"))
2384 ui.write(_(" no template directories found\n"))
2385 if not p:
2385 if not p:
2386 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2386 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2387 problems += 1
2387 problems += 1
2388
2388
2389 # editor
2389 # editor
2390 ui.status(_("checking commit editor...\n"))
2390 ui.status(_("checking commit editor...\n"))
2391 editor = ui.geteditor()
2391 editor = ui.geteditor()
2392 editor = util.expandpath(editor)
2392 editor = util.expandpath(editor)
2393 cmdpath = util.findexe(shlex.split(editor)[0])
2393 cmdpath = util.findexe(shlex.split(editor)[0])
2394 if not cmdpath:
2394 if not cmdpath:
2395 if editor == 'vi':
2395 if editor == 'vi':
2396 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2396 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2397 ui.write(_(" (specify a commit editor in your configuration"
2397 ui.write(_(" (specify a commit editor in your configuration"
2398 " file)\n"))
2398 " file)\n"))
2399 else:
2399 else:
2400 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2400 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2401 ui.write(_(" (specify a commit editor in your configuration"
2401 ui.write(_(" (specify a commit editor in your configuration"
2402 " file)\n"))
2402 " file)\n"))
2403 problems += 1
2403 problems += 1
2404
2404
2405 # check username
2405 # check username
2406 ui.status(_("checking username...\n"))
2406 ui.status(_("checking username...\n"))
2407 try:
2407 try:
2408 ui.username()
2408 ui.username()
2409 except util.Abort, e:
2409 except util.Abort, e:
2410 ui.write(" %s\n" % e)
2410 ui.write(" %s\n" % e)
2411 ui.write(_(" (specify a username in your configuration file)\n"))
2411 ui.write(_(" (specify a username in your configuration file)\n"))
2412 problems += 1
2412 problems += 1
2413
2413
2414 if not problems:
2414 if not problems:
2415 ui.status(_("no problems detected\n"))
2415 ui.status(_("no problems detected\n"))
2416 else:
2416 else:
2417 ui.write(_("%s problems detected,"
2417 ui.write(_("%s problems detected,"
2418 " please check your install!\n") % problems)
2418 " please check your install!\n") % problems)
2419
2419
2420 return problems
2420 return problems
2421
2421
2422 @command('debugknown', [], _('REPO ID...'), norepo=True)
2422 @command('debugknown', [], _('REPO ID...'), norepo=True)
2423 def debugknown(ui, repopath, *ids, **opts):
2423 def debugknown(ui, repopath, *ids, **opts):
2424 """test whether node ids are known to a repo
2424 """test whether node ids are known to a repo
2425
2425
2426 Every ID must be a full-length hex node id string. Returns a list of 0s
2426 Every ID must be a full-length hex node id string. Returns a list of 0s
2427 and 1s indicating unknown/known.
2427 and 1s indicating unknown/known.
2428 """
2428 """
2429 repo = hg.peer(ui, opts, repopath)
2429 repo = hg.peer(ui, opts, repopath)
2430 if not repo.capable('known'):
2430 if not repo.capable('known'):
2431 raise util.Abort("known() not supported by target repository")
2431 raise util.Abort("known() not supported by target repository")
2432 flags = repo.known([bin(s) for s in ids])
2432 flags = repo.known([bin(s) for s in ids])
2433 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2433 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2434
2434
2435 @command('debuglabelcomplete', [], _('LABEL...'))
2435 @command('debuglabelcomplete', [], _('LABEL...'))
2436 def debuglabelcomplete(ui, repo, *args):
2436 def debuglabelcomplete(ui, repo, *args):
2437 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2437 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2438 debugnamecomplete(ui, repo, *args)
2438 debugnamecomplete(ui, repo, *args)
2439
2439
2440 @command('debugnamecomplete', [], _('NAME...'))
2440 @command('debugnamecomplete', [], _('NAME...'))
2441 def debugnamecomplete(ui, repo, *args):
2441 def debugnamecomplete(ui, repo, *args):
2442 '''complete "names" - tags, open branch names, bookmark names'''
2442 '''complete "names" - tags, open branch names, bookmark names'''
2443
2443
2444 names = set()
2444 names = set()
2445 # since we previously only listed open branches, we will handle that
2445 # since we previously only listed open branches, we will handle that
2446 # specially (after this for loop)
2446 # specially (after this for loop)
2447 for name, ns in repo.names.iteritems():
2447 for name, ns in repo.names.iteritems():
2448 if name != 'branches':
2448 if name != 'branches':
2449 names.update(ns.listnames(repo))
2449 names.update(ns.listnames(repo))
2450 names.update(tag for (tag, heads, tip, closed)
2450 names.update(tag for (tag, heads, tip, closed)
2451 in repo.branchmap().iterbranches() if not closed)
2451 in repo.branchmap().iterbranches() if not closed)
2452 completions = set()
2452 completions = set()
2453 if not args:
2453 if not args:
2454 args = ['']
2454 args = ['']
2455 for a in args:
2455 for a in args:
2456 completions.update(n for n in names if n.startswith(a))
2456 completions.update(n for n in names if n.startswith(a))
2457 ui.write('\n'.join(sorted(completions)))
2457 ui.write('\n'.join(sorted(completions)))
2458 ui.write('\n')
2458 ui.write('\n')
2459
2459
2460 @command('debuglocks',
2460 @command('debuglocks',
2461 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2461 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2462 ('W', 'force-wlock', None,
2462 ('W', 'force-wlock', None,
2463 _('free the working state lock (DANGEROUS)'))],
2463 _('free the working state lock (DANGEROUS)'))],
2464 _('[OPTION]...'))
2464 _('[OPTION]...'))
2465 def debuglocks(ui, repo, **opts):
2465 def debuglocks(ui, repo, **opts):
2466 """show or modify state of locks
2466 """show or modify state of locks
2467
2467
2468 By default, this command will show which locks are held. This
2468 By default, this command will show which locks are held. This
2469 includes the user and process holding the lock, the amount of time
2469 includes the user and process holding the lock, the amount of time
2470 the lock has been held, and the machine name where the process is
2470 the lock has been held, and the machine name where the process is
2471 running if it's not local.
2471 running if it's not local.
2472
2472
2473 Locks protect the integrity of Mercurial's data, so should be
2473 Locks protect the integrity of Mercurial's data, so should be
2474 treated with care. System crashes or other interruptions may cause
2474 treated with care. System crashes or other interruptions may cause
2475 locks to not be properly released, though Mercurial will usually
2475 locks to not be properly released, though Mercurial will usually
2476 detect and remove such stale locks automatically.
2476 detect and remove such stale locks automatically.
2477
2477
2478 However, detecting stale locks may not always be possible (for
2478 However, detecting stale locks may not always be possible (for
2479 instance, on a shared filesystem). Removing locks may also be
2479 instance, on a shared filesystem). Removing locks may also be
2480 blocked by filesystem permissions.
2480 blocked by filesystem permissions.
2481
2481
2482 Returns 0 if no locks are held.
2482 Returns 0 if no locks are held.
2483
2483
2484 """
2484 """
2485
2485
2486 if opts.get('force_lock'):
2486 if opts.get('force_lock'):
2487 repo.svfs.unlink('lock')
2487 repo.svfs.unlink('lock')
2488 if opts.get('force_wlock'):
2488 if opts.get('force_wlock'):
2489 repo.vfs.unlink('wlock')
2489 repo.vfs.unlink('wlock')
2490 if opts.get('force_lock') or opts.get('force_lock'):
2490 if opts.get('force_lock') or opts.get('force_lock'):
2491 return 0
2491 return 0
2492
2492
2493 now = time.time()
2493 now = time.time()
2494 held = 0
2494 held = 0
2495
2495
2496 def report(vfs, name, method):
2496 def report(vfs, name, method):
2497 # this causes stale locks to get reaped for more accurate reporting
2497 # this causes stale locks to get reaped for more accurate reporting
2498 try:
2498 try:
2499 l = method(False)
2499 l = method(False)
2500 except error.LockHeld:
2500 except error.LockHeld:
2501 l = None
2501 l = None
2502
2502
2503 if l:
2503 if l:
2504 l.release()
2504 l.release()
2505 else:
2505 else:
2506 try:
2506 try:
2507 stat = vfs.lstat(name)
2507 stat = vfs.lstat(name)
2508 age = now - stat.st_mtime
2508 age = now - stat.st_mtime
2509 user = util.username(stat.st_uid)
2509 user = util.username(stat.st_uid)
2510 locker = vfs.readlock(name)
2510 locker = vfs.readlock(name)
2511 if ":" in locker:
2511 if ":" in locker:
2512 host, pid = locker.split(':')
2512 host, pid = locker.split(':')
2513 if host == socket.gethostname():
2513 if host == socket.gethostname():
2514 locker = 'user %s, process %s' % (user, pid)
2514 locker = 'user %s, process %s' % (user, pid)
2515 else:
2515 else:
2516 locker = 'user %s, process %s, host %s' \
2516 locker = 'user %s, process %s, host %s' \
2517 % (user, pid, host)
2517 % (user, pid, host)
2518 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2518 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2519 return 1
2519 return 1
2520 except OSError, e:
2520 except OSError, e:
2521 if e.errno != errno.ENOENT:
2521 if e.errno != errno.ENOENT:
2522 raise
2522 raise
2523
2523
2524 ui.write("%-6s free\n" % (name + ":"))
2524 ui.write("%-6s free\n" % (name + ":"))
2525 return 0
2525 return 0
2526
2526
2527 held += report(repo.svfs, "lock", repo.lock)
2527 held += report(repo.svfs, "lock", repo.lock)
2528 held += report(repo.vfs, "wlock", repo.wlock)
2528 held += report(repo.vfs, "wlock", repo.wlock)
2529
2529
2530 return held
2530 return held
2531
2531
2532 @command('debugobsolete',
2532 @command('debugobsolete',
2533 [('', 'flags', 0, _('markers flag')),
2533 [('', 'flags', 0, _('markers flag')),
2534 ('', 'record-parents', False,
2534 ('', 'record-parents', False,
2535 _('record parent information for the precursor')),
2535 _('record parent information for the precursor')),
2536 ('r', 'rev', [], _('display markers relevant to REV')),
2536 ('r', 'rev', [], _('display markers relevant to REV')),
2537 ] + commitopts2,
2537 ] + commitopts2,
2538 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2538 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2539 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2539 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2540 """create arbitrary obsolete marker
2540 """create arbitrary obsolete marker
2541
2541
2542 With no arguments, displays the list of obsolescence markers."""
2542 With no arguments, displays the list of obsolescence markers."""
2543
2543
2544 def parsenodeid(s):
2544 def parsenodeid(s):
2545 try:
2545 try:
2546 # We do not use revsingle/revrange functions here to accept
2546 # We do not use revsingle/revrange functions here to accept
2547 # arbitrary node identifiers, possibly not present in the
2547 # arbitrary node identifiers, possibly not present in the
2548 # local repository.
2548 # local repository.
2549 n = bin(s)
2549 n = bin(s)
2550 if len(n) != len(nullid):
2550 if len(n) != len(nullid):
2551 raise TypeError()
2551 raise TypeError()
2552 return n
2552 return n
2553 except TypeError:
2553 except TypeError:
2554 raise util.Abort('changeset references must be full hexadecimal '
2554 raise util.Abort('changeset references must be full hexadecimal '
2555 'node identifiers')
2555 'node identifiers')
2556
2556
2557 if precursor is not None:
2557 if precursor is not None:
2558 if opts['rev']:
2558 if opts['rev']:
2559 raise util.Abort('cannot select revision when creating marker')
2559 raise util.Abort('cannot select revision when creating marker')
2560 metadata = {}
2560 metadata = {}
2561 metadata['user'] = opts['user'] or ui.username()
2561 metadata['user'] = opts['user'] or ui.username()
2562 succs = tuple(parsenodeid(succ) for succ in successors)
2562 succs = tuple(parsenodeid(succ) for succ in successors)
2563 l = repo.lock()
2563 l = repo.lock()
2564 try:
2564 try:
2565 tr = repo.transaction('debugobsolete')
2565 tr = repo.transaction('debugobsolete')
2566 try:
2566 try:
2567 date = opts.get('date')
2567 date = opts.get('date')
2568 if date:
2568 if date:
2569 date = util.parsedate(date)
2569 date = util.parsedate(date)
2570 else:
2570 else:
2571 date = None
2571 date = None
2572 prec = parsenodeid(precursor)
2572 prec = parsenodeid(precursor)
2573 parents = None
2573 parents = None
2574 if opts['record_parents']:
2574 if opts['record_parents']:
2575 if prec not in repo.unfiltered():
2575 if prec not in repo.unfiltered():
2576 raise util.Abort('cannot used --record-parents on '
2576 raise util.Abort('cannot used --record-parents on '
2577 'unknown changesets')
2577 'unknown changesets')
2578 parents = repo.unfiltered()[prec].parents()
2578 parents = repo.unfiltered()[prec].parents()
2579 parents = tuple(p.node() for p in parents)
2579 parents = tuple(p.node() for p in parents)
2580 repo.obsstore.create(tr, prec, succs, opts['flags'],
2580 repo.obsstore.create(tr, prec, succs, opts['flags'],
2581 parents=parents, date=date,
2581 parents=parents, date=date,
2582 metadata=metadata)
2582 metadata=metadata)
2583 tr.close()
2583 tr.close()
2584 except ValueError, exc:
2584 except ValueError, exc:
2585 raise util.Abort(_('bad obsmarker input: %s') % exc)
2585 raise util.Abort(_('bad obsmarker input: %s') % exc)
2586 finally:
2586 finally:
2587 tr.release()
2587 tr.release()
2588 finally:
2588 finally:
2589 l.release()
2589 l.release()
2590 else:
2590 else:
2591 if opts['rev']:
2591 if opts['rev']:
2592 revs = scmutil.revrange(repo, opts['rev'])
2592 revs = scmutil.revrange(repo, opts['rev'])
2593 nodes = [repo[r].node() for r in revs]
2593 nodes = [repo[r].node() for r in revs]
2594 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2594 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2595 markers.sort(key=lambda x: x._data)
2595 markers.sort(key=lambda x: x._data)
2596 else:
2596 else:
2597 markers = obsolete.getmarkers(repo)
2597 markers = obsolete.getmarkers(repo)
2598
2598
2599 for m in markers:
2599 for m in markers:
2600 cmdutil.showmarker(ui, m)
2600 cmdutil.showmarker(ui, m)
2601
2601
2602 @command('debugpathcomplete',
2602 @command('debugpathcomplete',
2603 [('f', 'full', None, _('complete an entire path')),
2603 [('f', 'full', None, _('complete an entire path')),
2604 ('n', 'normal', None, _('show only normal files')),
2604 ('n', 'normal', None, _('show only normal files')),
2605 ('a', 'added', None, _('show only added files')),
2605 ('a', 'added', None, _('show only added files')),
2606 ('r', 'removed', None, _('show only removed files'))],
2606 ('r', 'removed', None, _('show only removed files'))],
2607 _('FILESPEC...'))
2607 _('FILESPEC...'))
2608 def debugpathcomplete(ui, repo, *specs, **opts):
2608 def debugpathcomplete(ui, repo, *specs, **opts):
2609 '''complete part or all of a tracked path
2609 '''complete part or all of a tracked path
2610
2610
2611 This command supports shells that offer path name completion. It
2611 This command supports shells that offer path name completion. It
2612 currently completes only files already known to the dirstate.
2612 currently completes only files already known to the dirstate.
2613
2613
2614 Completion extends only to the next path segment unless
2614 Completion extends only to the next path segment unless
2615 --full is specified, in which case entire paths are used.'''
2615 --full is specified, in which case entire paths are used.'''
2616
2616
2617 def complete(path, acceptable):
2617 def complete(path, acceptable):
2618 dirstate = repo.dirstate
2618 dirstate = repo.dirstate
2619 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2619 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2620 rootdir = repo.root + os.sep
2620 rootdir = repo.root + os.sep
2621 if spec != repo.root and not spec.startswith(rootdir):
2621 if spec != repo.root and not spec.startswith(rootdir):
2622 return [], []
2622 return [], []
2623 if os.path.isdir(spec):
2623 if os.path.isdir(spec):
2624 spec += '/'
2624 spec += '/'
2625 spec = spec[len(rootdir):]
2625 spec = spec[len(rootdir):]
2626 fixpaths = os.sep != '/'
2626 fixpaths = os.sep != '/'
2627 if fixpaths:
2627 if fixpaths:
2628 spec = spec.replace(os.sep, '/')
2628 spec = spec.replace(os.sep, '/')
2629 speclen = len(spec)
2629 speclen = len(spec)
2630 fullpaths = opts['full']
2630 fullpaths = opts['full']
2631 files, dirs = set(), set()
2631 files, dirs = set(), set()
2632 adddir, addfile = dirs.add, files.add
2632 adddir, addfile = dirs.add, files.add
2633 for f, st in dirstate.iteritems():
2633 for f, st in dirstate.iteritems():
2634 if f.startswith(spec) and st[0] in acceptable:
2634 if f.startswith(spec) and st[0] in acceptable:
2635 if fixpaths:
2635 if fixpaths:
2636 f = f.replace('/', os.sep)
2636 f = f.replace('/', os.sep)
2637 if fullpaths:
2637 if fullpaths:
2638 addfile(f)
2638 addfile(f)
2639 continue
2639 continue
2640 s = f.find(os.sep, speclen)
2640 s = f.find(os.sep, speclen)
2641 if s >= 0:
2641 if s >= 0:
2642 adddir(f[:s])
2642 adddir(f[:s])
2643 else:
2643 else:
2644 addfile(f)
2644 addfile(f)
2645 return files, dirs
2645 return files, dirs
2646
2646
2647 acceptable = ''
2647 acceptable = ''
2648 if opts['normal']:
2648 if opts['normal']:
2649 acceptable += 'nm'
2649 acceptable += 'nm'
2650 if opts['added']:
2650 if opts['added']:
2651 acceptable += 'a'
2651 acceptable += 'a'
2652 if opts['removed']:
2652 if opts['removed']:
2653 acceptable += 'r'
2653 acceptable += 'r'
2654 cwd = repo.getcwd()
2654 cwd = repo.getcwd()
2655 if not specs:
2655 if not specs:
2656 specs = ['.']
2656 specs = ['.']
2657
2657
2658 files, dirs = set(), set()
2658 files, dirs = set(), set()
2659 for spec in specs:
2659 for spec in specs:
2660 f, d = complete(spec, acceptable or 'nmar')
2660 f, d = complete(spec, acceptable or 'nmar')
2661 files.update(f)
2661 files.update(f)
2662 dirs.update(d)
2662 dirs.update(d)
2663 files.update(dirs)
2663 files.update(dirs)
2664 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2664 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2665 ui.write('\n')
2665 ui.write('\n')
2666
2666
2667 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2667 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2668 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2668 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2669 '''access the pushkey key/value protocol
2669 '''access the pushkey key/value protocol
2670
2670
2671 With two args, list the keys in the given namespace.
2671 With two args, list the keys in the given namespace.
2672
2672
2673 With five args, set a key to new if it currently is set to old.
2673 With five args, set a key to new if it currently is set to old.
2674 Reports success or failure.
2674 Reports success or failure.
2675 '''
2675 '''
2676
2676
2677 target = hg.peer(ui, {}, repopath)
2677 target = hg.peer(ui, {}, repopath)
2678 if keyinfo:
2678 if keyinfo:
2679 key, old, new = keyinfo
2679 key, old, new = keyinfo
2680 r = target.pushkey(namespace, key, old, new)
2680 r = target.pushkey(namespace, key, old, new)
2681 ui.status(str(r) + '\n')
2681 ui.status(str(r) + '\n')
2682 return not r
2682 return not r
2683 else:
2683 else:
2684 for k, v in sorted(target.listkeys(namespace).iteritems()):
2684 for k, v in sorted(target.listkeys(namespace).iteritems()):
2685 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2685 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2686 v.encode('string-escape')))
2686 v.encode('string-escape')))
2687
2687
2688 @command('debugpvec', [], _('A B'))
2688 @command('debugpvec', [], _('A B'))
2689 def debugpvec(ui, repo, a, b=None):
2689 def debugpvec(ui, repo, a, b=None):
2690 ca = scmutil.revsingle(repo, a)
2690 ca = scmutil.revsingle(repo, a)
2691 cb = scmutil.revsingle(repo, b)
2691 cb = scmutil.revsingle(repo, b)
2692 pa = pvec.ctxpvec(ca)
2692 pa = pvec.ctxpvec(ca)
2693 pb = pvec.ctxpvec(cb)
2693 pb = pvec.ctxpvec(cb)
2694 if pa == pb:
2694 if pa == pb:
2695 rel = "="
2695 rel = "="
2696 elif pa > pb:
2696 elif pa > pb:
2697 rel = ">"
2697 rel = ">"
2698 elif pa < pb:
2698 elif pa < pb:
2699 rel = "<"
2699 rel = "<"
2700 elif pa | pb:
2700 elif pa | pb:
2701 rel = "|"
2701 rel = "|"
2702 ui.write(_("a: %s\n") % pa)
2702 ui.write(_("a: %s\n") % pa)
2703 ui.write(_("b: %s\n") % pb)
2703 ui.write(_("b: %s\n") % pb)
2704 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2704 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2705 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2705 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2706 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2706 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2707 pa.distance(pb), rel))
2707 pa.distance(pb), rel))
2708
2708
2709 @command('debugrebuilddirstate|debugrebuildstate',
2709 @command('debugrebuilddirstate|debugrebuildstate',
2710 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2710 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2711 _('[-r REV]'))
2711 _('[-r REV]'))
2712 def debugrebuilddirstate(ui, repo, rev):
2712 def debugrebuilddirstate(ui, repo, rev):
2713 """rebuild the dirstate as it would look like for the given revision
2713 """rebuild the dirstate as it would look like for the given revision
2714
2714
2715 If no revision is specified the first current parent will be used.
2715 If no revision is specified the first current parent will be used.
2716
2716
2717 The dirstate will be set to the files of the given revision.
2717 The dirstate will be set to the files of the given revision.
2718 The actual working directory content or existing dirstate
2718 The actual working directory content or existing dirstate
2719 information such as adds or removes is not considered.
2719 information such as adds or removes is not considered.
2720
2720
2721 One use of this command is to make the next :hg:`status` invocation
2721 One use of this command is to make the next :hg:`status` invocation
2722 check the actual file content.
2722 check the actual file content.
2723 """
2723 """
2724 ctx = scmutil.revsingle(repo, rev)
2724 ctx = scmutil.revsingle(repo, rev)
2725 wlock = repo.wlock()
2725 wlock = repo.wlock()
2726 try:
2726 try:
2727 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2727 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2728 finally:
2728 finally:
2729 wlock.release()
2729 wlock.release()
2730
2730
2731 @command('debugrename',
2731 @command('debugrename',
2732 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2732 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2733 _('[-r REV] FILE'))
2733 _('[-r REV] FILE'))
2734 def debugrename(ui, repo, file1, *pats, **opts):
2734 def debugrename(ui, repo, file1, *pats, **opts):
2735 """dump rename information"""
2735 """dump rename information"""
2736
2736
2737 ctx = scmutil.revsingle(repo, opts.get('rev'))
2737 ctx = scmutil.revsingle(repo, opts.get('rev'))
2738 m = scmutil.match(ctx, (file1,) + pats, opts)
2738 m = scmutil.match(ctx, (file1,) + pats, opts)
2739 for abs in ctx.walk(m):
2739 for abs in ctx.walk(m):
2740 fctx = ctx[abs]
2740 fctx = ctx[abs]
2741 o = fctx.filelog().renamed(fctx.filenode())
2741 o = fctx.filelog().renamed(fctx.filenode())
2742 rel = m.rel(abs)
2742 rel = m.rel(abs)
2743 if o:
2743 if o:
2744 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2744 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2745 else:
2745 else:
2746 ui.write(_("%s not renamed\n") % rel)
2746 ui.write(_("%s not renamed\n") % rel)
2747
2747
2748 @command('debugrevlog',
2748 @command('debugrevlog',
2749 [('c', 'changelog', False, _('open changelog')),
2749 [('c', 'changelog', False, _('open changelog')),
2750 ('m', 'manifest', False, _('open manifest')),
2750 ('m', 'manifest', False, _('open manifest')),
2751 ('', 'dir', False, _('open directory manifest')),
2751 ('', 'dir', False, _('open directory manifest')),
2752 ('d', 'dump', False, _('dump index data'))],
2752 ('d', 'dump', False, _('dump index data'))],
2753 _('-c|-m|FILE'),
2753 _('-c|-m|FILE'),
2754 optionalrepo=True)
2754 optionalrepo=True)
2755 def debugrevlog(ui, repo, file_=None, **opts):
2755 def debugrevlog(ui, repo, file_=None, **opts):
2756 """show data and statistics about a revlog"""
2756 """show data and statistics about a revlog"""
2757 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2757 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2758
2758
2759 if opts.get("dump"):
2759 if opts.get("dump"):
2760 numrevs = len(r)
2760 numrevs = len(r)
2761 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2761 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2762 " rawsize totalsize compression heads chainlen\n")
2762 " rawsize totalsize compression heads chainlen\n")
2763 ts = 0
2763 ts = 0
2764 heads = set()
2764 heads = set()
2765
2765
2766 for rev in xrange(numrevs):
2766 for rev in xrange(numrevs):
2767 dbase = r.deltaparent(rev)
2767 dbase = r.deltaparent(rev)
2768 if dbase == -1:
2768 if dbase == -1:
2769 dbase = rev
2769 dbase = rev
2770 cbase = r.chainbase(rev)
2770 cbase = r.chainbase(rev)
2771 clen = r.chainlen(rev)
2771 clen = r.chainlen(rev)
2772 p1, p2 = r.parentrevs(rev)
2772 p1, p2 = r.parentrevs(rev)
2773 rs = r.rawsize(rev)
2773 rs = r.rawsize(rev)
2774 ts = ts + rs
2774 ts = ts + rs
2775 heads -= set(r.parentrevs(rev))
2775 heads -= set(r.parentrevs(rev))
2776 heads.add(rev)
2776 heads.add(rev)
2777 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2777 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2778 "%11d %5d %8d\n" %
2778 "%11d %5d %8d\n" %
2779 (rev, p1, p2, r.start(rev), r.end(rev),
2779 (rev, p1, p2, r.start(rev), r.end(rev),
2780 r.start(dbase), r.start(cbase),
2780 r.start(dbase), r.start(cbase),
2781 r.start(p1), r.start(p2),
2781 r.start(p1), r.start(p2),
2782 rs, ts, ts / r.end(rev), len(heads), clen))
2782 rs, ts, ts / r.end(rev), len(heads), clen))
2783 return 0
2783 return 0
2784
2784
2785 v = r.version
2785 v = r.version
2786 format = v & 0xFFFF
2786 format = v & 0xFFFF
2787 flags = []
2787 flags = []
2788 gdelta = False
2788 gdelta = False
2789 if v & revlog.REVLOGNGINLINEDATA:
2789 if v & revlog.REVLOGNGINLINEDATA:
2790 flags.append('inline')
2790 flags.append('inline')
2791 if v & revlog.REVLOGGENERALDELTA:
2791 if v & revlog.REVLOGGENERALDELTA:
2792 gdelta = True
2792 gdelta = True
2793 flags.append('generaldelta')
2793 flags.append('generaldelta')
2794 if not flags:
2794 if not flags:
2795 flags = ['(none)']
2795 flags = ['(none)']
2796
2796
2797 nummerges = 0
2797 nummerges = 0
2798 numfull = 0
2798 numfull = 0
2799 numprev = 0
2799 numprev = 0
2800 nump1 = 0
2800 nump1 = 0
2801 nump2 = 0
2801 nump2 = 0
2802 numother = 0
2802 numother = 0
2803 nump1prev = 0
2803 nump1prev = 0
2804 nump2prev = 0
2804 nump2prev = 0
2805 chainlengths = []
2805 chainlengths = []
2806
2806
2807 datasize = [None, 0, 0L]
2807 datasize = [None, 0, 0L]
2808 fullsize = [None, 0, 0L]
2808 fullsize = [None, 0, 0L]
2809 deltasize = [None, 0, 0L]
2809 deltasize = [None, 0, 0L]
2810
2810
2811 def addsize(size, l):
2811 def addsize(size, l):
2812 if l[0] is None or size < l[0]:
2812 if l[0] is None or size < l[0]:
2813 l[0] = size
2813 l[0] = size
2814 if size > l[1]:
2814 if size > l[1]:
2815 l[1] = size
2815 l[1] = size
2816 l[2] += size
2816 l[2] += size
2817
2817
2818 numrevs = len(r)
2818 numrevs = len(r)
2819 for rev in xrange(numrevs):
2819 for rev in xrange(numrevs):
2820 p1, p2 = r.parentrevs(rev)
2820 p1, p2 = r.parentrevs(rev)
2821 delta = r.deltaparent(rev)
2821 delta = r.deltaparent(rev)
2822 if format > 0:
2822 if format > 0:
2823 addsize(r.rawsize(rev), datasize)
2823 addsize(r.rawsize(rev), datasize)
2824 if p2 != nullrev:
2824 if p2 != nullrev:
2825 nummerges += 1
2825 nummerges += 1
2826 size = r.length(rev)
2826 size = r.length(rev)
2827 if delta == nullrev:
2827 if delta == nullrev:
2828 chainlengths.append(0)
2828 chainlengths.append(0)
2829 numfull += 1
2829 numfull += 1
2830 addsize(size, fullsize)
2830 addsize(size, fullsize)
2831 else:
2831 else:
2832 chainlengths.append(chainlengths[delta] + 1)
2832 chainlengths.append(chainlengths[delta] + 1)
2833 addsize(size, deltasize)
2833 addsize(size, deltasize)
2834 if delta == rev - 1:
2834 if delta == rev - 1:
2835 numprev += 1
2835 numprev += 1
2836 if delta == p1:
2836 if delta == p1:
2837 nump1prev += 1
2837 nump1prev += 1
2838 elif delta == p2:
2838 elif delta == p2:
2839 nump2prev += 1
2839 nump2prev += 1
2840 elif delta == p1:
2840 elif delta == p1:
2841 nump1 += 1
2841 nump1 += 1
2842 elif delta == p2:
2842 elif delta == p2:
2843 nump2 += 1
2843 nump2 += 1
2844 elif delta != nullrev:
2844 elif delta != nullrev:
2845 numother += 1
2845 numother += 1
2846
2846
2847 # Adjust size min value for empty cases
2847 # Adjust size min value for empty cases
2848 for size in (datasize, fullsize, deltasize):
2848 for size in (datasize, fullsize, deltasize):
2849 if size[0] is None:
2849 if size[0] is None:
2850 size[0] = 0
2850 size[0] = 0
2851
2851
2852 numdeltas = numrevs - numfull
2852 numdeltas = numrevs - numfull
2853 numoprev = numprev - nump1prev - nump2prev
2853 numoprev = numprev - nump1prev - nump2prev
2854 totalrawsize = datasize[2]
2854 totalrawsize = datasize[2]
2855 datasize[2] /= numrevs
2855 datasize[2] /= numrevs
2856 fulltotal = fullsize[2]
2856 fulltotal = fullsize[2]
2857 fullsize[2] /= numfull
2857 fullsize[2] /= numfull
2858 deltatotal = deltasize[2]
2858 deltatotal = deltasize[2]
2859 if numrevs - numfull > 0:
2859 if numrevs - numfull > 0:
2860 deltasize[2] /= numrevs - numfull
2860 deltasize[2] /= numrevs - numfull
2861 totalsize = fulltotal + deltatotal
2861 totalsize = fulltotal + deltatotal
2862 avgchainlen = sum(chainlengths) / numrevs
2862 avgchainlen = sum(chainlengths) / numrevs
2863 maxchainlen = max(chainlengths)
2863 maxchainlen = max(chainlengths)
2864 compratio = totalrawsize / totalsize
2864 compratio = totalrawsize / totalsize
2865
2865
2866 basedfmtstr = '%%%dd\n'
2866 basedfmtstr = '%%%dd\n'
2867 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2867 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2868
2868
2869 def dfmtstr(max):
2869 def dfmtstr(max):
2870 return basedfmtstr % len(str(max))
2870 return basedfmtstr % len(str(max))
2871 def pcfmtstr(max, padding=0):
2871 def pcfmtstr(max, padding=0):
2872 return basepcfmtstr % (len(str(max)), ' ' * padding)
2872 return basepcfmtstr % (len(str(max)), ' ' * padding)
2873
2873
2874 def pcfmt(value, total):
2874 def pcfmt(value, total):
2875 return (value, 100 * float(value) / total)
2875 return (value, 100 * float(value) / total)
2876
2876
2877 ui.write(('format : %d\n') % format)
2877 ui.write(('format : %d\n') % format)
2878 ui.write(('flags : %s\n') % ', '.join(flags))
2878 ui.write(('flags : %s\n') % ', '.join(flags))
2879
2879
2880 ui.write('\n')
2880 ui.write('\n')
2881 fmt = pcfmtstr(totalsize)
2881 fmt = pcfmtstr(totalsize)
2882 fmt2 = dfmtstr(totalsize)
2882 fmt2 = dfmtstr(totalsize)
2883 ui.write(('revisions : ') + fmt2 % numrevs)
2883 ui.write(('revisions : ') + fmt2 % numrevs)
2884 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2884 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2885 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2885 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2886 ui.write(('revisions : ') + fmt2 % numrevs)
2886 ui.write(('revisions : ') + fmt2 % numrevs)
2887 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2887 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2888 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2888 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2889 ui.write(('revision size : ') + fmt2 % totalsize)
2889 ui.write(('revision size : ') + fmt2 % totalsize)
2890 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2890 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2891 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2891 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2892
2892
2893 ui.write('\n')
2893 ui.write('\n')
2894 fmt = dfmtstr(max(avgchainlen, compratio))
2894 fmt = dfmtstr(max(avgchainlen, compratio))
2895 ui.write(('avg chain length : ') + fmt % avgchainlen)
2895 ui.write(('avg chain length : ') + fmt % avgchainlen)
2896 ui.write(('max chain length : ') + fmt % maxchainlen)
2896 ui.write(('max chain length : ') + fmt % maxchainlen)
2897 ui.write(('compression ratio : ') + fmt % compratio)
2897 ui.write(('compression ratio : ') + fmt % compratio)
2898
2898
2899 if format > 0:
2899 if format > 0:
2900 ui.write('\n')
2900 ui.write('\n')
2901 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2901 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2902 % tuple(datasize))
2902 % tuple(datasize))
2903 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2903 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2904 % tuple(fullsize))
2904 % tuple(fullsize))
2905 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2905 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2906 % tuple(deltasize))
2906 % tuple(deltasize))
2907
2907
2908 if numdeltas > 0:
2908 if numdeltas > 0:
2909 ui.write('\n')
2909 ui.write('\n')
2910 fmt = pcfmtstr(numdeltas)
2910 fmt = pcfmtstr(numdeltas)
2911 fmt2 = pcfmtstr(numdeltas, 4)
2911 fmt2 = pcfmtstr(numdeltas, 4)
2912 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2912 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2913 if numprev > 0:
2913 if numprev > 0:
2914 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2914 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2915 numprev))
2915 numprev))
2916 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2916 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2917 numprev))
2917 numprev))
2918 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2918 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2919 numprev))
2919 numprev))
2920 if gdelta:
2920 if gdelta:
2921 ui.write(('deltas against p1 : ')
2921 ui.write(('deltas against p1 : ')
2922 + fmt % pcfmt(nump1, numdeltas))
2922 + fmt % pcfmt(nump1, numdeltas))
2923 ui.write(('deltas against p2 : ')
2923 ui.write(('deltas against p2 : ')
2924 + fmt % pcfmt(nump2, numdeltas))
2924 + fmt % pcfmt(nump2, numdeltas))
2925 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2925 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2926 numdeltas))
2926 numdeltas))
2927
2927
2928 @command('debugrevspec',
2928 @command('debugrevspec',
2929 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2929 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2930 ('REVSPEC'))
2930 ('REVSPEC'))
2931 def debugrevspec(ui, repo, expr, **opts):
2931 def debugrevspec(ui, repo, expr, **opts):
2932 """parse and apply a revision specification
2932 """parse and apply a revision specification
2933
2933
2934 Use --verbose to print the parsed tree before and after aliases
2934 Use --verbose to print the parsed tree before and after aliases
2935 expansion.
2935 expansion.
2936 """
2936 """
2937 if ui.verbose:
2937 if ui.verbose:
2938 tree = revset.parse(expr)
2938 tree = revset.parse(expr)
2939 ui.note(revset.prettyformat(tree), "\n")
2939 ui.note(revset.prettyformat(tree), "\n")
2940 newtree = revset.findaliases(ui, tree)
2940 newtree = revset.findaliases(ui, tree)
2941 if newtree != tree:
2941 if newtree != tree:
2942 ui.note(revset.prettyformat(newtree), "\n")
2942 ui.note(revset.prettyformat(newtree), "\n")
2943 tree = newtree
2943 tree = newtree
2944 newtree = revset.foldconcat(tree)
2944 newtree = revset.foldconcat(tree)
2945 if newtree != tree:
2945 if newtree != tree:
2946 ui.note(revset.prettyformat(newtree), "\n")
2946 ui.note(revset.prettyformat(newtree), "\n")
2947 if opts["optimize"]:
2947 if opts["optimize"]:
2948 weight, optimizedtree = revset.optimize(newtree, True)
2948 weight, optimizedtree = revset.optimize(newtree, True)
2949 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2949 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2950 func = revset.match(ui, expr)
2950 func = revset.match(ui, expr)
2951 revs = func(repo)
2951 revs = func(repo)
2952 if ui.verbose:
2952 if ui.verbose:
2953 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2953 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
2954 for c in revs:
2954 for c in revs:
2955 ui.write("%s\n" % c)
2955 ui.write("%s\n" % c)
2956
2956
2957 @command('debugsetparents', [], _('REV1 [REV2]'))
2957 @command('debugsetparents', [], _('REV1 [REV2]'))
2958 def debugsetparents(ui, repo, rev1, rev2=None):
2958 def debugsetparents(ui, repo, rev1, rev2=None):
2959 """manually set the parents of the current working directory
2959 """manually set the parents of the current working directory
2960
2960
2961 This is useful for writing repository conversion tools, but should
2961 This is useful for writing repository conversion tools, but should
2962 be used with care. For example, neither the working directory nor the
2962 be used with care. For example, neither the working directory nor the
2963 dirstate is updated, so file status may be incorrect after running this
2963 dirstate is updated, so file status may be incorrect after running this
2964 command.
2964 command.
2965
2965
2966 Returns 0 on success.
2966 Returns 0 on success.
2967 """
2967 """
2968
2968
2969 r1 = scmutil.revsingle(repo, rev1).node()
2969 r1 = scmutil.revsingle(repo, rev1).node()
2970 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2970 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2971
2971
2972 wlock = repo.wlock()
2972 wlock = repo.wlock()
2973 try:
2973 try:
2974 repo.dirstate.beginparentchange()
2974 repo.dirstate.beginparentchange()
2975 repo.setparents(r1, r2)
2975 repo.setparents(r1, r2)
2976 repo.dirstate.endparentchange()
2976 repo.dirstate.endparentchange()
2977 finally:
2977 finally:
2978 wlock.release()
2978 wlock.release()
2979
2979
2980 @command('debugdirstate|debugstate',
2980 @command('debugdirstate|debugstate',
2981 [('', 'nodates', None, _('do not display the saved mtime')),
2981 [('', 'nodates', None, _('do not display the saved mtime')),
2982 ('', 'datesort', None, _('sort by saved mtime'))],
2982 ('', 'datesort', None, _('sort by saved mtime'))],
2983 _('[OPTION]...'))
2983 _('[OPTION]...'))
2984 def debugstate(ui, repo, nodates=None, datesort=None):
2984 def debugstate(ui, repo, nodates=None, datesort=None):
2985 """show the contents of the current dirstate"""
2985 """show the contents of the current dirstate"""
2986 timestr = ""
2986 timestr = ""
2987 if datesort:
2987 if datesort:
2988 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2988 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2989 else:
2989 else:
2990 keyfunc = None # sort by filename
2990 keyfunc = None # sort by filename
2991 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2991 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2992 if ent[3] == -1:
2992 if ent[3] == -1:
2993 timestr = 'unset '
2993 timestr = 'unset '
2994 elif nodates:
2994 elif nodates:
2995 timestr = 'set '
2995 timestr = 'set '
2996 else:
2996 else:
2997 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2997 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2998 time.localtime(ent[3]))
2998 time.localtime(ent[3]))
2999 if ent[1] & 020000:
2999 if ent[1] & 020000:
3000 mode = 'lnk'
3000 mode = 'lnk'
3001 else:
3001 else:
3002 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
3002 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
3003 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3003 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3004 for f in repo.dirstate.copies():
3004 for f in repo.dirstate.copies():
3005 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3005 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3006
3006
3007 @command('debugsub',
3007 @command('debugsub',
3008 [('r', 'rev', '',
3008 [('r', 'rev', '',
3009 _('revision to check'), _('REV'))],
3009 _('revision to check'), _('REV'))],
3010 _('[-r REV] [REV]'))
3010 _('[-r REV] [REV]'))
3011 def debugsub(ui, repo, rev=None):
3011 def debugsub(ui, repo, rev=None):
3012 ctx = scmutil.revsingle(repo, rev, None)
3012 ctx = scmutil.revsingle(repo, rev, None)
3013 for k, v in sorted(ctx.substate.items()):
3013 for k, v in sorted(ctx.substate.items()):
3014 ui.write(('path %s\n') % k)
3014 ui.write(('path %s\n') % k)
3015 ui.write((' source %s\n') % v[0])
3015 ui.write((' source %s\n') % v[0])
3016 ui.write((' revision %s\n') % v[1])
3016 ui.write((' revision %s\n') % v[1])
3017
3017
3018 @command('debugsuccessorssets',
3018 @command('debugsuccessorssets',
3019 [],
3019 [],
3020 _('[REV]'))
3020 _('[REV]'))
3021 def debugsuccessorssets(ui, repo, *revs):
3021 def debugsuccessorssets(ui, repo, *revs):
3022 """show set of successors for revision
3022 """show set of successors for revision
3023
3023
3024 A successors set of changeset A is a consistent group of revisions that
3024 A successors set of changeset A is a consistent group of revisions that
3025 succeed A. It contains non-obsolete changesets only.
3025 succeed A. It contains non-obsolete changesets only.
3026
3026
3027 In most cases a changeset A has a single successors set containing a single
3027 In most cases a changeset A has a single successors set containing a single
3028 successor (changeset A replaced by A').
3028 successor (changeset A replaced by A').
3029
3029
3030 A changeset that is made obsolete with no successors are called "pruned".
3030 A changeset that is made obsolete with no successors are called "pruned".
3031 Such changesets have no successors sets at all.
3031 Such changesets have no successors sets at all.
3032
3032
3033 A changeset that has been "split" will have a successors set containing
3033 A changeset that has been "split" will have a successors set containing
3034 more than one successor.
3034 more than one successor.
3035
3035
3036 A changeset that has been rewritten in multiple different ways is called
3036 A changeset that has been rewritten in multiple different ways is called
3037 "divergent". Such changesets have multiple successor sets (each of which
3037 "divergent". Such changesets have multiple successor sets (each of which
3038 may also be split, i.e. have multiple successors).
3038 may also be split, i.e. have multiple successors).
3039
3039
3040 Results are displayed as follows::
3040 Results are displayed as follows::
3041
3041
3042 <rev1>
3042 <rev1>
3043 <successors-1A>
3043 <successors-1A>
3044 <rev2>
3044 <rev2>
3045 <successors-2A>
3045 <successors-2A>
3046 <successors-2B1> <successors-2B2> <successors-2B3>
3046 <successors-2B1> <successors-2B2> <successors-2B3>
3047
3047
3048 Here rev2 has two possible (i.e. divergent) successors sets. The first
3048 Here rev2 has two possible (i.e. divergent) successors sets. The first
3049 holds one element, whereas the second holds three (i.e. the changeset has
3049 holds one element, whereas the second holds three (i.e. the changeset has
3050 been split).
3050 been split).
3051 """
3051 """
3052 # passed to successorssets caching computation from one call to another
3052 # passed to successorssets caching computation from one call to another
3053 cache = {}
3053 cache = {}
3054 ctx2str = str
3054 ctx2str = str
3055 node2str = short
3055 node2str = short
3056 if ui.debug():
3056 if ui.debug():
3057 def ctx2str(ctx):
3057 def ctx2str(ctx):
3058 return ctx.hex()
3058 return ctx.hex()
3059 node2str = hex
3059 node2str = hex
3060 for rev in scmutil.revrange(repo, revs):
3060 for rev in scmutil.revrange(repo, revs):
3061 ctx = repo[rev]
3061 ctx = repo[rev]
3062 ui.write('%s\n'% ctx2str(ctx))
3062 ui.write('%s\n'% ctx2str(ctx))
3063 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3063 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3064 if succsset:
3064 if succsset:
3065 ui.write(' ')
3065 ui.write(' ')
3066 ui.write(node2str(succsset[0]))
3066 ui.write(node2str(succsset[0]))
3067 for node in succsset[1:]:
3067 for node in succsset[1:]:
3068 ui.write(' ')
3068 ui.write(' ')
3069 ui.write(node2str(node))
3069 ui.write(node2str(node))
3070 ui.write('\n')
3070 ui.write('\n')
3071
3071
3072 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3072 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3073 def debugwalk(ui, repo, *pats, **opts):
3073 def debugwalk(ui, repo, *pats, **opts):
3074 """show how files match on given patterns"""
3074 """show how files match on given patterns"""
3075 m = scmutil.match(repo[None], pats, opts)
3075 m = scmutil.match(repo[None], pats, opts)
3076 items = list(repo.walk(m))
3076 items = list(repo.walk(m))
3077 if not items:
3077 if not items:
3078 return
3078 return
3079 f = lambda fn: fn
3079 f = lambda fn: fn
3080 if ui.configbool('ui', 'slash') and os.sep != '/':
3080 if ui.configbool('ui', 'slash') and os.sep != '/':
3081 f = lambda fn: util.normpath(fn)
3081 f = lambda fn: util.normpath(fn)
3082 fmt = 'f %%-%ds %%-%ds %%s' % (
3082 fmt = 'f %%-%ds %%-%ds %%s' % (
3083 max([len(abs) for abs in items]),
3083 max([len(abs) for abs in items]),
3084 max([len(m.rel(abs)) for abs in items]))
3084 max([len(m.rel(abs)) for abs in items]))
3085 for abs in items:
3085 for abs in items:
3086 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3086 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3087 ui.write("%s\n" % line.rstrip())
3087 ui.write("%s\n" % line.rstrip())
3088
3088
3089 @command('debugwireargs',
3089 @command('debugwireargs',
3090 [('', 'three', '', 'three'),
3090 [('', 'three', '', 'three'),
3091 ('', 'four', '', 'four'),
3091 ('', 'four', '', 'four'),
3092 ('', 'five', '', 'five'),
3092 ('', 'five', '', 'five'),
3093 ] + remoteopts,
3093 ] + remoteopts,
3094 _('REPO [OPTIONS]... [ONE [TWO]]'),
3094 _('REPO [OPTIONS]... [ONE [TWO]]'),
3095 norepo=True)
3095 norepo=True)
3096 def debugwireargs(ui, repopath, *vals, **opts):
3096 def debugwireargs(ui, repopath, *vals, **opts):
3097 repo = hg.peer(ui, opts, repopath)
3097 repo = hg.peer(ui, opts, repopath)
3098 for opt in remoteopts:
3098 for opt in remoteopts:
3099 del opts[opt[1]]
3099 del opts[opt[1]]
3100 args = {}
3100 args = {}
3101 for k, v in opts.iteritems():
3101 for k, v in opts.iteritems():
3102 if v:
3102 if v:
3103 args[k] = v
3103 args[k] = v
3104 # run twice to check that we don't mess up the stream for the next command
3104 # run twice to check that we don't mess up the stream for the next command
3105 res1 = repo.debugwireargs(*vals, **args)
3105 res1 = repo.debugwireargs(*vals, **args)
3106 res2 = repo.debugwireargs(*vals, **args)
3106 res2 = repo.debugwireargs(*vals, **args)
3107 ui.write("%s\n" % res1)
3107 ui.write("%s\n" % res1)
3108 if res1 != res2:
3108 if res1 != res2:
3109 ui.warn("%s\n" % res2)
3109 ui.warn("%s\n" % res2)
3110
3110
3111 @command('^diff',
3111 @command('^diff',
3112 [('r', 'rev', [], _('revision'), _('REV')),
3112 [('r', 'rev', [], _('revision'), _('REV')),
3113 ('c', 'change', '', _('change made by revision'), _('REV'))
3113 ('c', 'change', '', _('change made by revision'), _('REV'))
3114 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3114 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3115 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3115 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3116 inferrepo=True)
3116 inferrepo=True)
3117 def diff(ui, repo, *pats, **opts):
3117 def diff(ui, repo, *pats, **opts):
3118 """diff repository (or selected files)
3118 """diff repository (or selected files)
3119
3119
3120 Show differences between revisions for the specified files.
3120 Show differences between revisions for the specified files.
3121
3121
3122 Differences between files are shown using the unified diff format.
3122 Differences between files are shown using the unified diff format.
3123
3123
3124 .. note::
3124 .. note::
3125
3125
3126 diff may generate unexpected results for merges, as it will
3126 diff may generate unexpected results for merges, as it will
3127 default to comparing against the working directory's first
3127 default to comparing against the working directory's first
3128 parent changeset if no revisions are specified.
3128 parent changeset if no revisions are specified.
3129
3129
3130 When two revision arguments are given, then changes are shown
3130 When two revision arguments are given, then changes are shown
3131 between those revisions. If only one revision is specified then
3131 between those revisions. If only one revision is specified then
3132 that revision is compared to the working directory, and, when no
3132 that revision is compared to the working directory, and, when no
3133 revisions are specified, the working directory files are compared
3133 revisions are specified, the working directory files are compared
3134 to its parent.
3134 to its parent.
3135
3135
3136 Alternatively you can specify -c/--change with a revision to see
3136 Alternatively you can specify -c/--change with a revision to see
3137 the changes in that changeset relative to its first parent.
3137 the changes in that changeset relative to its first parent.
3138
3138
3139 Without the -a/--text option, diff will avoid generating diffs of
3139 Without the -a/--text option, diff will avoid generating diffs of
3140 files it detects as binary. With -a, diff will generate a diff
3140 files it detects as binary. With -a, diff will generate a diff
3141 anyway, probably with undesirable results.
3141 anyway, probably with undesirable results.
3142
3142
3143 Use the -g/--git option to generate diffs in the git extended diff
3143 Use the -g/--git option to generate diffs in the git extended diff
3144 format. For more information, read :hg:`help diffs`.
3144 format. For more information, read :hg:`help diffs`.
3145
3145
3146 .. container:: verbose
3146 .. container:: verbose
3147
3147
3148 Examples:
3148 Examples:
3149
3149
3150 - compare a file in the current working directory to its parent::
3150 - compare a file in the current working directory to its parent::
3151
3151
3152 hg diff foo.c
3152 hg diff foo.c
3153
3153
3154 - compare two historical versions of a directory, with rename info::
3154 - compare two historical versions of a directory, with rename info::
3155
3155
3156 hg diff --git -r 1.0:1.2 lib/
3156 hg diff --git -r 1.0:1.2 lib/
3157
3157
3158 - get change stats relative to the last change on some date::
3158 - get change stats relative to the last change on some date::
3159
3159
3160 hg diff --stat -r "date('may 2')"
3160 hg diff --stat -r "date('may 2')"
3161
3161
3162 - diff all newly-added files that contain a keyword::
3162 - diff all newly-added files that contain a keyword::
3163
3163
3164 hg diff "set:added() and grep(GNU)"
3164 hg diff "set:added() and grep(GNU)"
3165
3165
3166 - compare a revision and its parents::
3166 - compare a revision and its parents::
3167
3167
3168 hg diff -c 9353 # compare against first parent
3168 hg diff -c 9353 # compare against first parent
3169 hg diff -r 9353^:9353 # same using revset syntax
3169 hg diff -r 9353^:9353 # same using revset syntax
3170 hg diff -r 9353^2:9353 # compare against the second parent
3170 hg diff -r 9353^2:9353 # compare against the second parent
3171
3171
3172 Returns 0 on success.
3172 Returns 0 on success.
3173 """
3173 """
3174
3174
3175 revs = opts.get('rev')
3175 revs = opts.get('rev')
3176 change = opts.get('change')
3176 change = opts.get('change')
3177 stat = opts.get('stat')
3177 stat = opts.get('stat')
3178 reverse = opts.get('reverse')
3178 reverse = opts.get('reverse')
3179
3179
3180 if revs and change:
3180 if revs and change:
3181 msg = _('cannot specify --rev and --change at the same time')
3181 msg = _('cannot specify --rev and --change at the same time')
3182 raise util.Abort(msg)
3182 raise util.Abort(msg)
3183 elif change:
3183 elif change:
3184 node2 = scmutil.revsingle(repo, change, None).node()
3184 node2 = scmutil.revsingle(repo, change, None).node()
3185 node1 = repo[node2].p1().node()
3185 node1 = repo[node2].p1().node()
3186 else:
3186 else:
3187 node1, node2 = scmutil.revpair(repo, revs)
3187 node1, node2 = scmutil.revpair(repo, revs)
3188
3188
3189 if reverse:
3189 if reverse:
3190 node1, node2 = node2, node1
3190 node1, node2 = node2, node1
3191
3191
3192 diffopts = patch.diffallopts(ui, opts)
3192 diffopts = patch.diffallopts(ui, opts)
3193 m = scmutil.match(repo[node2], pats, opts)
3193 m = scmutil.match(repo[node2], pats, opts)
3194 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3194 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3195 listsubrepos=opts.get('subrepos'),
3195 listsubrepos=opts.get('subrepos'),
3196 root=opts.get('root'))
3196 root=opts.get('root'))
3197
3197
3198 @command('^export',
3198 @command('^export',
3199 [('o', 'output', '',
3199 [('o', 'output', '',
3200 _('print output to file with formatted name'), _('FORMAT')),
3200 _('print output to file with formatted name'), _('FORMAT')),
3201 ('', 'switch-parent', None, _('diff against the second parent')),
3201 ('', 'switch-parent', None, _('diff against the second parent')),
3202 ('r', 'rev', [], _('revisions to export'), _('REV')),
3202 ('r', 'rev', [], _('revisions to export'), _('REV')),
3203 ] + diffopts,
3203 ] + diffopts,
3204 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3204 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3205 def export(ui, repo, *changesets, **opts):
3205 def export(ui, repo, *changesets, **opts):
3206 """dump the header and diffs for one or more changesets
3206 """dump the header and diffs for one or more changesets
3207
3207
3208 Print the changeset header and diffs for one or more revisions.
3208 Print the changeset header and diffs for one or more revisions.
3209 If no revision is given, the parent of the working directory is used.
3209 If no revision is given, the parent of the working directory is used.
3210
3210
3211 The information shown in the changeset header is: author, date,
3211 The information shown in the changeset header is: author, date,
3212 branch name (if non-default), changeset hash, parent(s) and commit
3212 branch name (if non-default), changeset hash, parent(s) and commit
3213 comment.
3213 comment.
3214
3214
3215 .. note::
3215 .. note::
3216
3216
3217 export may generate unexpected diff output for merge
3217 export may generate unexpected diff output for merge
3218 changesets, as it will compare the merge changeset against its
3218 changesets, as it will compare the merge changeset against its
3219 first parent only.
3219 first parent only.
3220
3220
3221 Output may be to a file, in which case the name of the file is
3221 Output may be to a file, in which case the name of the file is
3222 given using a format string. The formatting rules are as follows:
3222 given using a format string. The formatting rules are as follows:
3223
3223
3224 :``%%``: literal "%" character
3224 :``%%``: literal "%" character
3225 :``%H``: changeset hash (40 hexadecimal digits)
3225 :``%H``: changeset hash (40 hexadecimal digits)
3226 :``%N``: number of patches being generated
3226 :``%N``: number of patches being generated
3227 :``%R``: changeset revision number
3227 :``%R``: changeset revision number
3228 :``%b``: basename of the exporting repository
3228 :``%b``: basename of the exporting repository
3229 :``%h``: short-form changeset hash (12 hexadecimal digits)
3229 :``%h``: short-form changeset hash (12 hexadecimal digits)
3230 :``%m``: first line of the commit message (only alphanumeric characters)
3230 :``%m``: first line of the commit message (only alphanumeric characters)
3231 :``%n``: zero-padded sequence number, starting at 1
3231 :``%n``: zero-padded sequence number, starting at 1
3232 :``%r``: zero-padded changeset revision number
3232 :``%r``: zero-padded changeset revision number
3233
3233
3234 Without the -a/--text option, export will avoid generating diffs
3234 Without the -a/--text option, export will avoid generating diffs
3235 of files it detects as binary. With -a, export will generate a
3235 of files it detects as binary. With -a, export will generate a
3236 diff anyway, probably with undesirable results.
3236 diff anyway, probably with undesirable results.
3237
3237
3238 Use the -g/--git option to generate diffs in the git extended diff
3238 Use the -g/--git option to generate diffs in the git extended diff
3239 format. See :hg:`help diffs` for more information.
3239 format. See :hg:`help diffs` for more information.
3240
3240
3241 With the --switch-parent option, the diff will be against the
3241 With the --switch-parent option, the diff will be against the
3242 second parent. It can be useful to review a merge.
3242 second parent. It can be useful to review a merge.
3243
3243
3244 .. container:: verbose
3244 .. container:: verbose
3245
3245
3246 Examples:
3246 Examples:
3247
3247
3248 - use export and import to transplant a bugfix to the current
3248 - use export and import to transplant a bugfix to the current
3249 branch::
3249 branch::
3250
3250
3251 hg export -r 9353 | hg import -
3251 hg export -r 9353 | hg import -
3252
3252
3253 - export all the changesets between two revisions to a file with
3253 - export all the changesets between two revisions to a file with
3254 rename information::
3254 rename information::
3255
3255
3256 hg export --git -r 123:150 > changes.txt
3256 hg export --git -r 123:150 > changes.txt
3257
3257
3258 - split outgoing changes into a series of patches with
3258 - split outgoing changes into a series of patches with
3259 descriptive names::
3259 descriptive names::
3260
3260
3261 hg export -r "outgoing()" -o "%n-%m.patch"
3261 hg export -r "outgoing()" -o "%n-%m.patch"
3262
3262
3263 Returns 0 on success.
3263 Returns 0 on success.
3264 """
3264 """
3265 changesets += tuple(opts.get('rev', []))
3265 changesets += tuple(opts.get('rev', []))
3266 if not changesets:
3266 if not changesets:
3267 changesets = ['.']
3267 changesets = ['.']
3268 revs = scmutil.revrange(repo, changesets)
3268 revs = scmutil.revrange(repo, changesets)
3269 if not revs:
3269 if not revs:
3270 raise util.Abort(_("export requires at least one changeset"))
3270 raise util.Abort(_("export requires at least one changeset"))
3271 if len(revs) > 1:
3271 if len(revs) > 1:
3272 ui.note(_('exporting patches:\n'))
3272 ui.note(_('exporting patches:\n'))
3273 else:
3273 else:
3274 ui.note(_('exporting patch:\n'))
3274 ui.note(_('exporting patch:\n'))
3275 cmdutil.export(repo, revs, template=opts.get('output'),
3275 cmdutil.export(repo, revs, template=opts.get('output'),
3276 switch_parent=opts.get('switch_parent'),
3276 switch_parent=opts.get('switch_parent'),
3277 opts=patch.diffallopts(ui, opts))
3277 opts=patch.diffallopts(ui, opts))
3278
3278
3279 @command('files',
3279 @command('files',
3280 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3280 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3281 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3281 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3282 ] + walkopts + formatteropts + subrepoopts,
3282 ] + walkopts + formatteropts + subrepoopts,
3283 _('[OPTION]... [PATTERN]...'))
3283 _('[OPTION]... [PATTERN]...'))
3284 def files(ui, repo, *pats, **opts):
3284 def files(ui, repo, *pats, **opts):
3285 """list tracked files
3285 """list tracked files
3286
3286
3287 Print files under Mercurial control in the working directory or
3287 Print files under Mercurial control in the working directory or
3288 specified revision whose names match the given patterns (excluding
3288 specified revision whose names match the given patterns (excluding
3289 removed files).
3289 removed files).
3290
3290
3291 If no patterns are given to match, this command prints the names
3291 If no patterns are given to match, this command prints the names
3292 of all files under Mercurial control in the working directory.
3292 of all files under Mercurial control in the working directory.
3293
3293
3294 .. container:: verbose
3294 .. container:: verbose
3295
3295
3296 Examples:
3296 Examples:
3297
3297
3298 - list all files under the current directory::
3298 - list all files under the current directory::
3299
3299
3300 hg files .
3300 hg files .
3301
3301
3302 - shows sizes and flags for current revision::
3302 - shows sizes and flags for current revision::
3303
3303
3304 hg files -vr .
3304 hg files -vr .
3305
3305
3306 - list all files named README::
3306 - list all files named README::
3307
3307
3308 hg files -I "**/README"
3308 hg files -I "**/README"
3309
3309
3310 - list all binary files::
3310 - list all binary files::
3311
3311
3312 hg files "set:binary()"
3312 hg files "set:binary()"
3313
3313
3314 - find files containing a regular expression::
3314 - find files containing a regular expression::
3315
3315
3316 hg files "set:grep('bob')"
3316 hg files "set:grep('bob')"
3317
3317
3318 - search tracked file contents with xargs and grep::
3318 - search tracked file contents with xargs and grep::
3319
3319
3320 hg files -0 | xargs -0 grep foo
3320 hg files -0 | xargs -0 grep foo
3321
3321
3322 See :hg:`help patterns` and :hg:`help filesets` for more information
3322 See :hg:`help patterns` and :hg:`help filesets` for more information
3323 on specifying file patterns.
3323 on specifying file patterns.
3324
3324
3325 Returns 0 if a match is found, 1 otherwise.
3325 Returns 0 if a match is found, 1 otherwise.
3326
3326
3327 """
3327 """
3328 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3328 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3329
3329
3330 end = '\n'
3330 end = '\n'
3331 if opts.get('print0'):
3331 if opts.get('print0'):
3332 end = '\0'
3332 end = '\0'
3333 fm = ui.formatter('files', opts)
3333 fm = ui.formatter('files', opts)
3334 fmt = '%s' + end
3334 fmt = '%s' + end
3335
3335
3336 m = scmutil.match(ctx, pats, opts)
3336 m = scmutil.match(ctx, pats, opts)
3337 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3337 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3338
3338
3339 fm.end()
3339 fm.end()
3340
3340
3341 return ret
3341 return ret
3342
3342
3343 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3343 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3344 def forget(ui, repo, *pats, **opts):
3344 def forget(ui, repo, *pats, **opts):
3345 """forget the specified files on the next commit
3345 """forget the specified files on the next commit
3346
3346
3347 Mark the specified files so they will no longer be tracked
3347 Mark the specified files so they will no longer be tracked
3348 after the next commit.
3348 after the next commit.
3349
3349
3350 This only removes files from the current branch, not from the
3350 This only removes files from the current branch, not from the
3351 entire project history, and it does not delete them from the
3351 entire project history, and it does not delete them from the
3352 working directory.
3352 working directory.
3353
3353
3354 To undo a forget before the next commit, see :hg:`add`.
3354 To undo a forget before the next commit, see :hg:`add`.
3355
3355
3356 .. container:: verbose
3356 .. container:: verbose
3357
3357
3358 Examples:
3358 Examples:
3359
3359
3360 - forget newly-added binary files::
3360 - forget newly-added binary files::
3361
3361
3362 hg forget "set:added() and binary()"
3362 hg forget "set:added() and binary()"
3363
3363
3364 - forget files that would be excluded by .hgignore::
3364 - forget files that would be excluded by .hgignore::
3365
3365
3366 hg forget "set:hgignore()"
3366 hg forget "set:hgignore()"
3367
3367
3368 Returns 0 on success.
3368 Returns 0 on success.
3369 """
3369 """
3370
3370
3371 if not pats:
3371 if not pats:
3372 raise util.Abort(_('no files specified'))
3372 raise util.Abort(_('no files specified'))
3373
3373
3374 m = scmutil.match(repo[None], pats, opts)
3374 m = scmutil.match(repo[None], pats, opts)
3375 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3375 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3376 return rejected and 1 or 0
3376 return rejected and 1 or 0
3377
3377
3378 @command(
3378 @command(
3379 'graft',
3379 'graft',
3380 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3380 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3381 ('c', 'continue', False, _('resume interrupted graft')),
3381 ('c', 'continue', False, _('resume interrupted graft')),
3382 ('e', 'edit', False, _('invoke editor on commit messages')),
3382 ('e', 'edit', False, _('invoke editor on commit messages')),
3383 ('', 'log', None, _('append graft info to log message')),
3383 ('', 'log', None, _('append graft info to log message')),
3384 ('f', 'force', False, _('force graft')),
3384 ('f', 'force', False, _('force graft')),
3385 ('D', 'currentdate', False,
3385 ('D', 'currentdate', False,
3386 _('record the current date as commit date')),
3386 _('record the current date as commit date')),
3387 ('U', 'currentuser', False,
3387 ('U', 'currentuser', False,
3388 _('record the current user as committer'), _('DATE'))]
3388 _('record the current user as committer'), _('DATE'))]
3389 + commitopts2 + mergetoolopts + dryrunopts,
3389 + commitopts2 + mergetoolopts + dryrunopts,
3390 _('[OPTION]... [-r] REV...'))
3390 _('[OPTION]... [-r] REV...'))
3391 def graft(ui, repo, *revs, **opts):
3391 def graft(ui, repo, *revs, **opts):
3392 '''copy changes from other branches onto the current branch
3392 '''copy changes from other branches onto the current branch
3393
3393
3394 This command uses Mercurial's merge logic to copy individual
3394 This command uses Mercurial's merge logic to copy individual
3395 changes from other branches without merging branches in the
3395 changes from other branches without merging branches in the
3396 history graph. This is sometimes known as 'backporting' or
3396 history graph. This is sometimes known as 'backporting' or
3397 'cherry-picking'. By default, graft will copy user, date, and
3397 'cherry-picking'. By default, graft will copy user, date, and
3398 description from the source changesets.
3398 description from the source changesets.
3399
3399
3400 Changesets that are ancestors of the current revision, that have
3400 Changesets that are ancestors of the current revision, that have
3401 already been grafted, or that are merges will be skipped.
3401 already been grafted, or that are merges will be skipped.
3402
3402
3403 If --log is specified, log messages will have a comment appended
3403 If --log is specified, log messages will have a comment appended
3404 of the form::
3404 of the form::
3405
3405
3406 (grafted from CHANGESETHASH)
3406 (grafted from CHANGESETHASH)
3407
3407
3408 If --force is specified, revisions will be grafted even if they
3408 If --force is specified, revisions will be grafted even if they
3409 are already ancestors of or have been grafted to the destination.
3409 are already ancestors of or have been grafted to the destination.
3410 This is useful when the revisions have since been backed out.
3410 This is useful when the revisions have since been backed out.
3411
3411
3412 If a graft merge results in conflicts, the graft process is
3412 If a graft merge results in conflicts, the graft process is
3413 interrupted so that the current merge can be manually resolved.
3413 interrupted so that the current merge can be manually resolved.
3414 Once all conflicts are addressed, the graft process can be
3414 Once all conflicts are addressed, the graft process can be
3415 continued with the -c/--continue option.
3415 continued with the -c/--continue option.
3416
3416
3417 .. note::
3417 .. note::
3418
3418
3419 The -c/--continue option does not reapply earlier options, except
3419 The -c/--continue option does not reapply earlier options, except
3420 for --force.
3420 for --force.
3421
3421
3422 .. container:: verbose
3422 .. container:: verbose
3423
3423
3424 Examples:
3424 Examples:
3425
3425
3426 - copy a single change to the stable branch and edit its description::
3426 - copy a single change to the stable branch and edit its description::
3427
3427
3428 hg update stable
3428 hg update stable
3429 hg graft --edit 9393
3429 hg graft --edit 9393
3430
3430
3431 - graft a range of changesets with one exception, updating dates::
3431 - graft a range of changesets with one exception, updating dates::
3432
3432
3433 hg graft -D "2085::2093 and not 2091"
3433 hg graft -D "2085::2093 and not 2091"
3434
3434
3435 - continue a graft after resolving conflicts::
3435 - continue a graft after resolving conflicts::
3436
3436
3437 hg graft -c
3437 hg graft -c
3438
3438
3439 - show the source of a grafted changeset::
3439 - show the source of a grafted changeset::
3440
3440
3441 hg log --debug -r .
3441 hg log --debug -r .
3442
3442
3443 See :hg:`help revisions` and :hg:`help revsets` for more about
3443 See :hg:`help revisions` and :hg:`help revsets` for more about
3444 specifying revisions.
3444 specifying revisions.
3445
3445
3446 Returns 0 on successful completion.
3446 Returns 0 on successful completion.
3447 '''
3447 '''
3448
3448
3449 revs = list(revs)
3449 revs = list(revs)
3450 revs.extend(opts['rev'])
3450 revs.extend(opts['rev'])
3451
3451
3452 if not opts.get('user') and opts.get('currentuser'):
3452 if not opts.get('user') and opts.get('currentuser'):
3453 opts['user'] = ui.username()
3453 opts['user'] = ui.username()
3454 if not opts.get('date') and opts.get('currentdate'):
3454 if not opts.get('date') and opts.get('currentdate'):
3455 opts['date'] = "%d %d" % util.makedate()
3455 opts['date'] = "%d %d" % util.makedate()
3456
3456
3457 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3457 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3458
3458
3459 cont = False
3459 cont = False
3460 if opts['continue']:
3460 if opts['continue']:
3461 cont = True
3461 cont = True
3462 if revs:
3462 if revs:
3463 raise util.Abort(_("can't specify --continue and revisions"))
3463 raise util.Abort(_("can't specify --continue and revisions"))
3464 # read in unfinished revisions
3464 # read in unfinished revisions
3465 try:
3465 try:
3466 nodes = repo.vfs.read('graftstate').splitlines()
3466 nodes = repo.vfs.read('graftstate').splitlines()
3467 revs = [repo[node].rev() for node in nodes]
3467 revs = [repo[node].rev() for node in nodes]
3468 except IOError, inst:
3468 except IOError, inst:
3469 if inst.errno != errno.ENOENT:
3469 if inst.errno != errno.ENOENT:
3470 raise
3470 raise
3471 raise util.Abort(_("no graft state found, can't continue"))
3471 raise util.Abort(_("no graft state found, can't continue"))
3472 else:
3472 else:
3473 cmdutil.checkunfinished(repo)
3473 cmdutil.checkunfinished(repo)
3474 cmdutil.bailifchanged(repo)
3474 cmdutil.bailifchanged(repo)
3475 if not revs:
3475 if not revs:
3476 raise util.Abort(_('no revisions specified'))
3476 raise util.Abort(_('no revisions specified'))
3477 revs = scmutil.revrange(repo, revs)
3477 revs = scmutil.revrange(repo, revs)
3478
3478
3479 skipped = set()
3479 skipped = set()
3480 # check for merges
3480 # check for merges
3481 for rev in repo.revs('%ld and merge()', revs):
3481 for rev in repo.revs('%ld and merge()', revs):
3482 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3482 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3483 skipped.add(rev)
3483 skipped.add(rev)
3484 revs = [r for r in revs if r not in skipped]
3484 revs = [r for r in revs if r not in skipped]
3485 if not revs:
3485 if not revs:
3486 return -1
3486 return -1
3487
3487
3488 # Don't check in the --continue case, in effect retaining --force across
3488 # Don't check in the --continue case, in effect retaining --force across
3489 # --continues. That's because without --force, any revisions we decided to
3489 # --continues. That's because without --force, any revisions we decided to
3490 # skip would have been filtered out here, so they wouldn't have made their
3490 # skip would have been filtered out here, so they wouldn't have made their
3491 # way to the graftstate. With --force, any revisions we would have otherwise
3491 # way to the graftstate. With --force, any revisions we would have otherwise
3492 # skipped would not have been filtered out, and if they hadn't been applied
3492 # skipped would not have been filtered out, and if they hadn't been applied
3493 # already, they'd have been in the graftstate.
3493 # already, they'd have been in the graftstate.
3494 if not (cont or opts.get('force')):
3494 if not (cont or opts.get('force')):
3495 # check for ancestors of dest branch
3495 # check for ancestors of dest branch
3496 crev = repo['.'].rev()
3496 crev = repo['.'].rev()
3497 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3497 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3498 # Cannot use x.remove(y) on smart set, this has to be a list.
3498 # Cannot use x.remove(y) on smart set, this has to be a list.
3499 # XXX make this lazy in the future
3499 # XXX make this lazy in the future
3500 revs = list(revs)
3500 revs = list(revs)
3501 # don't mutate while iterating, create a copy
3501 # don't mutate while iterating, create a copy
3502 for rev in list(revs):
3502 for rev in list(revs):
3503 if rev in ancestors:
3503 if rev in ancestors:
3504 ui.warn(_('skipping ancestor revision %d:%s\n') %
3504 ui.warn(_('skipping ancestor revision %d:%s\n') %
3505 (rev, repo[rev]))
3505 (rev, repo[rev]))
3506 # XXX remove on list is slow
3506 # XXX remove on list is slow
3507 revs.remove(rev)
3507 revs.remove(rev)
3508 if not revs:
3508 if not revs:
3509 return -1
3509 return -1
3510
3510
3511 # analyze revs for earlier grafts
3511 # analyze revs for earlier grafts
3512 ids = {}
3512 ids = {}
3513 for ctx in repo.set("%ld", revs):
3513 for ctx in repo.set("%ld", revs):
3514 ids[ctx.hex()] = ctx.rev()
3514 ids[ctx.hex()] = ctx.rev()
3515 n = ctx.extra().get('source')
3515 n = ctx.extra().get('source')
3516 if n:
3516 if n:
3517 ids[n] = ctx.rev()
3517 ids[n] = ctx.rev()
3518
3518
3519 # check ancestors for earlier grafts
3519 # check ancestors for earlier grafts
3520 ui.debug('scanning for duplicate grafts\n')
3520 ui.debug('scanning for duplicate grafts\n')
3521
3521
3522 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3522 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3523 ctx = repo[rev]
3523 ctx = repo[rev]
3524 n = ctx.extra().get('source')
3524 n = ctx.extra().get('source')
3525 if n in ids:
3525 if n in ids:
3526 try:
3526 try:
3527 r = repo[n].rev()
3527 r = repo[n].rev()
3528 except error.RepoLookupError:
3528 except error.RepoLookupError:
3529 r = None
3529 r = None
3530 if r in revs:
3530 if r in revs:
3531 ui.warn(_('skipping revision %d:%s '
3531 ui.warn(_('skipping revision %d:%s '
3532 '(already grafted to %d:%s)\n')
3532 '(already grafted to %d:%s)\n')
3533 % (r, repo[r], rev, ctx))
3533 % (r, repo[r], rev, ctx))
3534 revs.remove(r)
3534 revs.remove(r)
3535 elif ids[n] in revs:
3535 elif ids[n] in revs:
3536 if r is None:
3536 if r is None:
3537 ui.warn(_('skipping already grafted revision %d:%s '
3537 ui.warn(_('skipping already grafted revision %d:%s '
3538 '(%d:%s also has unknown origin %s)\n')
3538 '(%d:%s also has unknown origin %s)\n')
3539 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3539 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3540 else:
3540 else:
3541 ui.warn(_('skipping already grafted revision %d:%s '
3541 ui.warn(_('skipping already grafted revision %d:%s '
3542 '(%d:%s also has origin %d:%s)\n')
3542 '(%d:%s also has origin %d:%s)\n')
3543 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3543 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3544 revs.remove(ids[n])
3544 revs.remove(ids[n])
3545 elif ctx.hex() in ids:
3545 elif ctx.hex() in ids:
3546 r = ids[ctx.hex()]
3546 r = ids[ctx.hex()]
3547 ui.warn(_('skipping already grafted revision %d:%s '
3547 ui.warn(_('skipping already grafted revision %d:%s '
3548 '(was grafted from %d:%s)\n') %
3548 '(was grafted from %d:%s)\n') %
3549 (r, repo[r], rev, ctx))
3549 (r, repo[r], rev, ctx))
3550 revs.remove(r)
3550 revs.remove(r)
3551 if not revs:
3551 if not revs:
3552 return -1
3552 return -1
3553
3553
3554 wlock = repo.wlock()
3554 wlock = repo.wlock()
3555 try:
3555 try:
3556 for pos, ctx in enumerate(repo.set("%ld", revs)):
3556 for pos, ctx in enumerate(repo.set("%ld", revs)):
3557 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3557 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3558 ctx.description().split('\n', 1)[0])
3558 ctx.description().split('\n', 1)[0])
3559 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3559 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3560 if names:
3560 if names:
3561 desc += ' (%s)' % ' '.join(names)
3561 desc += ' (%s)' % ' '.join(names)
3562 ui.status(_('grafting %s\n') % desc)
3562 ui.status(_('grafting %s\n') % desc)
3563 if opts.get('dry_run'):
3563 if opts.get('dry_run'):
3564 continue
3564 continue
3565
3565
3566 source = ctx.extra().get('source')
3566 source = ctx.extra().get('source')
3567 extra = {}
3567 extra = {}
3568 if source:
3568 if source:
3569 extra['source'] = source
3569 extra['source'] = source
3570 extra['intermediate-source'] = ctx.hex()
3570 extra['intermediate-source'] = ctx.hex()
3571 else:
3571 else:
3572 extra['source'] = ctx.hex()
3572 extra['source'] = ctx.hex()
3573 user = ctx.user()
3573 user = ctx.user()
3574 if opts.get('user'):
3574 if opts.get('user'):
3575 user = opts['user']
3575 user = opts['user']
3576 date = ctx.date()
3576 date = ctx.date()
3577 if opts.get('date'):
3577 if opts.get('date'):
3578 date = opts['date']
3578 date = opts['date']
3579 message = ctx.description()
3579 message = ctx.description()
3580 if opts.get('log'):
3580 if opts.get('log'):
3581 message += '\n(grafted from %s)' % ctx.hex()
3581 message += '\n(grafted from %s)' % ctx.hex()
3582
3582
3583 # we don't merge the first commit when continuing
3583 # we don't merge the first commit when continuing
3584 if not cont:
3584 if not cont:
3585 # perform the graft merge with p1(rev) as 'ancestor'
3585 # perform the graft merge with p1(rev) as 'ancestor'
3586 try:
3586 try:
3587 # ui.forcemerge is an internal variable, do not document
3587 # ui.forcemerge is an internal variable, do not document
3588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3589 'graft')
3589 'graft')
3590 stats = mergemod.graft(repo, ctx, ctx.p1(),
3590 stats = mergemod.graft(repo, ctx, ctx.p1(),
3591 ['local', 'graft'])
3591 ['local', 'graft'])
3592 finally:
3592 finally:
3593 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3593 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3594 # report any conflicts
3594 # report any conflicts
3595 if stats and stats[3] > 0:
3595 if stats and stats[3] > 0:
3596 # write out state for --continue
3596 # write out state for --continue
3597 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3597 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3598 repo.vfs.write('graftstate', ''.join(nodelines))
3598 repo.vfs.write('graftstate', ''.join(nodelines))
3599 raise util.Abort(
3599 raise util.Abort(
3600 _("unresolved conflicts, can't continue"),
3600 _("unresolved conflicts, can't continue"),
3601 hint=_('use hg resolve and hg graft --continue'))
3601 hint=_('use hg resolve and hg graft --continue'))
3602 else:
3602 else:
3603 cont = False
3603 cont = False
3604
3604
3605 # commit
3605 # commit
3606 node = repo.commit(text=message, user=user,
3606 node = repo.commit(text=message, user=user,
3607 date=date, extra=extra, editor=editor)
3607 date=date, extra=extra, editor=editor)
3608 if node is None:
3608 if node is None:
3609 ui.warn(
3609 ui.warn(
3610 _('note: graft of %d:%s created no changes to commit\n') %
3610 _('note: graft of %d:%s created no changes to commit\n') %
3611 (ctx.rev(), ctx))
3611 (ctx.rev(), ctx))
3612 finally:
3612 finally:
3613 wlock.release()
3613 wlock.release()
3614
3614
3615 # remove state when we complete successfully
3615 # remove state when we complete successfully
3616 if not opts.get('dry_run'):
3616 if not opts.get('dry_run'):
3617 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3617 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3618
3618
3619 return 0
3619 return 0
3620
3620
3621 @command('grep',
3621 @command('grep',
3622 [('0', 'print0', None, _('end fields with NUL')),
3622 [('0', 'print0', None, _('end fields with NUL')),
3623 ('', 'all', None, _('print all revisions that match')),
3623 ('', 'all', None, _('print all revisions that match')),
3624 ('a', 'text', None, _('treat all files as text')),
3624 ('a', 'text', None, _('treat all files as text')),
3625 ('f', 'follow', None,
3625 ('f', 'follow', None,
3626 _('follow changeset history,'
3626 _('follow changeset history,'
3627 ' or file history across copies and renames')),
3627 ' or file history across copies and renames')),
3628 ('i', 'ignore-case', None, _('ignore case when matching')),
3628 ('i', 'ignore-case', None, _('ignore case when matching')),
3629 ('l', 'files-with-matches', None,
3629 ('l', 'files-with-matches', None,
3630 _('print only filenames and revisions that match')),
3630 _('print only filenames and revisions that match')),
3631 ('n', 'line-number', None, _('print matching line numbers')),
3631 ('n', 'line-number', None, _('print matching line numbers')),
3632 ('r', 'rev', [],
3632 ('r', 'rev', [],
3633 _('only search files changed within revision range'), _('REV')),
3633 _('only search files changed within revision range'), _('REV')),
3634 ('u', 'user', None, _('list the author (long with -v)')),
3634 ('u', 'user', None, _('list the author (long with -v)')),
3635 ('d', 'date', None, _('list the date (short with -q)')),
3635 ('d', 'date', None, _('list the date (short with -q)')),
3636 ] + walkopts,
3636 ] + walkopts,
3637 _('[OPTION]... PATTERN [FILE]...'),
3637 _('[OPTION]... PATTERN [FILE]...'),
3638 inferrepo=True)
3638 inferrepo=True)
3639 def grep(ui, repo, pattern, *pats, **opts):
3639 def grep(ui, repo, pattern, *pats, **opts):
3640 """search for a pattern in specified files and revisions
3640 """search for a pattern in specified files and revisions
3641
3641
3642 Search revisions of files for a regular expression.
3642 Search revisions of files for a regular expression.
3643
3643
3644 This command behaves differently than Unix grep. It only accepts
3644 This command behaves differently than Unix grep. It only accepts
3645 Python/Perl regexps. It searches repository history, not the
3645 Python/Perl regexps. It searches repository history, not the
3646 working directory. It always prints the revision number in which a
3646 working directory. It always prints the revision number in which a
3647 match appears.
3647 match appears.
3648
3648
3649 By default, grep only prints output for the first revision of a
3649 By default, grep only prints output for the first revision of a
3650 file in which it finds a match. To get it to print every revision
3650 file in which it finds a match. To get it to print every revision
3651 that contains a change in match status ("-" for a match that
3651 that contains a change in match status ("-" for a match that
3652 becomes a non-match, or "+" for a non-match that becomes a match),
3652 becomes a non-match, or "+" for a non-match that becomes a match),
3653 use the --all flag.
3653 use the --all flag.
3654
3654
3655 Returns 0 if a match is found, 1 otherwise.
3655 Returns 0 if a match is found, 1 otherwise.
3656 """
3656 """
3657 reflags = re.M
3657 reflags = re.M
3658 if opts.get('ignore_case'):
3658 if opts.get('ignore_case'):
3659 reflags |= re.I
3659 reflags |= re.I
3660 try:
3660 try:
3661 regexp = util.re.compile(pattern, reflags)
3661 regexp = util.re.compile(pattern, reflags)
3662 except re.error, inst:
3662 except re.error, inst:
3663 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3663 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3664 return 1
3664 return 1
3665 sep, eol = ':', '\n'
3665 sep, eol = ':', '\n'
3666 if opts.get('print0'):
3666 if opts.get('print0'):
3667 sep = eol = '\0'
3667 sep = eol = '\0'
3668
3668
3669 getfile = util.lrucachefunc(repo.file)
3669 getfile = util.lrucachefunc(repo.file)
3670
3670
3671 def matchlines(body):
3671 def matchlines(body):
3672 begin = 0
3672 begin = 0
3673 linenum = 0
3673 linenum = 0
3674 while begin < len(body):
3674 while begin < len(body):
3675 match = regexp.search(body, begin)
3675 match = regexp.search(body, begin)
3676 if not match:
3676 if not match:
3677 break
3677 break
3678 mstart, mend = match.span()
3678 mstart, mend = match.span()
3679 linenum += body.count('\n', begin, mstart) + 1
3679 linenum += body.count('\n', begin, mstart) + 1
3680 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3680 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3681 begin = body.find('\n', mend) + 1 or len(body) + 1
3681 begin = body.find('\n', mend) + 1 or len(body) + 1
3682 lend = begin - 1
3682 lend = begin - 1
3683 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3683 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3684
3684
3685 class linestate(object):
3685 class linestate(object):
3686 def __init__(self, line, linenum, colstart, colend):
3686 def __init__(self, line, linenum, colstart, colend):
3687 self.line = line
3687 self.line = line
3688 self.linenum = linenum
3688 self.linenum = linenum
3689 self.colstart = colstart
3689 self.colstart = colstart
3690 self.colend = colend
3690 self.colend = colend
3691
3691
3692 def __hash__(self):
3692 def __hash__(self):
3693 return hash((self.linenum, self.line))
3693 return hash((self.linenum, self.line))
3694
3694
3695 def __eq__(self, other):
3695 def __eq__(self, other):
3696 return self.line == other.line
3696 return self.line == other.line
3697
3697
3698 def __iter__(self):
3698 def __iter__(self):
3699 yield (self.line[:self.colstart], '')
3699 yield (self.line[:self.colstart], '')
3700 yield (self.line[self.colstart:self.colend], 'grep.match')
3700 yield (self.line[self.colstart:self.colend], 'grep.match')
3701 rest = self.line[self.colend:]
3701 rest = self.line[self.colend:]
3702 while rest != '':
3702 while rest != '':
3703 match = regexp.search(rest)
3703 match = regexp.search(rest)
3704 if not match:
3704 if not match:
3705 yield (rest, '')
3705 yield (rest, '')
3706 break
3706 break
3707 mstart, mend = match.span()
3707 mstart, mend = match.span()
3708 yield (rest[:mstart], '')
3708 yield (rest[:mstart], '')
3709 yield (rest[mstart:mend], 'grep.match')
3709 yield (rest[mstart:mend], 'grep.match')
3710 rest = rest[mend:]
3710 rest = rest[mend:]
3711
3711
3712 matches = {}
3712 matches = {}
3713 copies = {}
3713 copies = {}
3714 def grepbody(fn, rev, body):
3714 def grepbody(fn, rev, body):
3715 matches[rev].setdefault(fn, [])
3715 matches[rev].setdefault(fn, [])
3716 m = matches[rev][fn]
3716 m = matches[rev][fn]
3717 for lnum, cstart, cend, line in matchlines(body):
3717 for lnum, cstart, cend, line in matchlines(body):
3718 s = linestate(line, lnum, cstart, cend)
3718 s = linestate(line, lnum, cstart, cend)
3719 m.append(s)
3719 m.append(s)
3720
3720
3721 def difflinestates(a, b):
3721 def difflinestates(a, b):
3722 sm = difflib.SequenceMatcher(None, a, b)
3722 sm = difflib.SequenceMatcher(None, a, b)
3723 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3723 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3724 if tag == 'insert':
3724 if tag == 'insert':
3725 for i in xrange(blo, bhi):
3725 for i in xrange(blo, bhi):
3726 yield ('+', b[i])
3726 yield ('+', b[i])
3727 elif tag == 'delete':
3727 elif tag == 'delete':
3728 for i in xrange(alo, ahi):
3728 for i in xrange(alo, ahi):
3729 yield ('-', a[i])
3729 yield ('-', a[i])
3730 elif tag == 'replace':
3730 elif tag == 'replace':
3731 for i in xrange(alo, ahi):
3731 for i in xrange(alo, ahi):
3732 yield ('-', a[i])
3732 yield ('-', a[i])
3733 for i in xrange(blo, bhi):
3733 for i in xrange(blo, bhi):
3734 yield ('+', b[i])
3734 yield ('+', b[i])
3735
3735
3736 def display(fn, ctx, pstates, states):
3736 def display(fn, ctx, pstates, states):
3737 rev = ctx.rev()
3737 rev = ctx.rev()
3738 if ui.quiet:
3738 if ui.quiet:
3739 datefunc = util.shortdate
3739 datefunc = util.shortdate
3740 else:
3740 else:
3741 datefunc = util.datestr
3741 datefunc = util.datestr
3742 found = False
3742 found = False
3743 @util.cachefunc
3743 @util.cachefunc
3744 def binary():
3744 def binary():
3745 flog = getfile(fn)
3745 flog = getfile(fn)
3746 return util.binary(flog.read(ctx.filenode(fn)))
3746 return util.binary(flog.read(ctx.filenode(fn)))
3747
3747
3748 if opts.get('all'):
3748 if opts.get('all'):
3749 iter = difflinestates(pstates, states)
3749 iter = difflinestates(pstates, states)
3750 else:
3750 else:
3751 iter = [('', l) for l in states]
3751 iter = [('', l) for l in states]
3752 for change, l in iter:
3752 for change, l in iter:
3753 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3753 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3754
3754
3755 if opts.get('line_number'):
3755 if opts.get('line_number'):
3756 cols.append((str(l.linenum), 'grep.linenumber'))
3756 cols.append((str(l.linenum), 'grep.linenumber'))
3757 if opts.get('all'):
3757 if opts.get('all'):
3758 cols.append((change, 'grep.change'))
3758 cols.append((change, 'grep.change'))
3759 if opts.get('user'):
3759 if opts.get('user'):
3760 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3760 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3761 if opts.get('date'):
3761 if opts.get('date'):
3762 cols.append((datefunc(ctx.date()), 'grep.date'))
3762 cols.append((datefunc(ctx.date()), 'grep.date'))
3763 for col, label in cols[:-1]:
3763 for col, label in cols[:-1]:
3764 ui.write(col, label=label)
3764 ui.write(col, label=label)
3765 ui.write(sep, label='grep.sep')
3765 ui.write(sep, label='grep.sep')
3766 ui.write(cols[-1][0], label=cols[-1][1])
3766 ui.write(cols[-1][0], label=cols[-1][1])
3767 if not opts.get('files_with_matches'):
3767 if not opts.get('files_with_matches'):
3768 ui.write(sep, label='grep.sep')
3768 ui.write(sep, label='grep.sep')
3769 if not opts.get('text') and binary():
3769 if not opts.get('text') and binary():
3770 ui.write(" Binary file matches")
3770 ui.write(" Binary file matches")
3771 else:
3771 else:
3772 for s, label in l:
3772 for s, label in l:
3773 ui.write(s, label=label)
3773 ui.write(s, label=label)
3774 ui.write(eol)
3774 ui.write(eol)
3775 found = True
3775 found = True
3776 if opts.get('files_with_matches'):
3776 if opts.get('files_with_matches'):
3777 break
3777 break
3778 return found
3778 return found
3779
3779
3780 skip = {}
3780 skip = {}
3781 revfiles = {}
3781 revfiles = {}
3782 matchfn = scmutil.match(repo[None], pats, opts)
3782 matchfn = scmutil.match(repo[None], pats, opts)
3783 found = False
3783 found = False
3784 follow = opts.get('follow')
3784 follow = opts.get('follow')
3785
3785
3786 def prep(ctx, fns):
3786 def prep(ctx, fns):
3787 rev = ctx.rev()
3787 rev = ctx.rev()
3788 pctx = ctx.p1()
3788 pctx = ctx.p1()
3789 parent = pctx.rev()
3789 parent = pctx.rev()
3790 matches.setdefault(rev, {})
3790 matches.setdefault(rev, {})
3791 matches.setdefault(parent, {})
3791 matches.setdefault(parent, {})
3792 files = revfiles.setdefault(rev, [])
3792 files = revfiles.setdefault(rev, [])
3793 for fn in fns:
3793 for fn in fns:
3794 flog = getfile(fn)
3794 flog = getfile(fn)
3795 try:
3795 try:
3796 fnode = ctx.filenode(fn)
3796 fnode = ctx.filenode(fn)
3797 except error.LookupError:
3797 except error.LookupError:
3798 continue
3798 continue
3799
3799
3800 copied = flog.renamed(fnode)
3800 copied = flog.renamed(fnode)
3801 copy = follow and copied and copied[0]
3801 copy = follow and copied and copied[0]
3802 if copy:
3802 if copy:
3803 copies.setdefault(rev, {})[fn] = copy
3803 copies.setdefault(rev, {})[fn] = copy
3804 if fn in skip:
3804 if fn in skip:
3805 if copy:
3805 if copy:
3806 skip[copy] = True
3806 skip[copy] = True
3807 continue
3807 continue
3808 files.append(fn)
3808 files.append(fn)
3809
3809
3810 if fn not in matches[rev]:
3810 if fn not in matches[rev]:
3811 grepbody(fn, rev, flog.read(fnode))
3811 grepbody(fn, rev, flog.read(fnode))
3812
3812
3813 pfn = copy or fn
3813 pfn = copy or fn
3814 if pfn not in matches[parent]:
3814 if pfn not in matches[parent]:
3815 try:
3815 try:
3816 fnode = pctx.filenode(pfn)
3816 fnode = pctx.filenode(pfn)
3817 grepbody(pfn, parent, flog.read(fnode))
3817 grepbody(pfn, parent, flog.read(fnode))
3818 except error.LookupError:
3818 except error.LookupError:
3819 pass
3819 pass
3820
3820
3821 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3821 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3822 rev = ctx.rev()
3822 rev = ctx.rev()
3823 parent = ctx.p1().rev()
3823 parent = ctx.p1().rev()
3824 for fn in sorted(revfiles.get(rev, [])):
3824 for fn in sorted(revfiles.get(rev, [])):
3825 states = matches[rev][fn]
3825 states = matches[rev][fn]
3826 copy = copies.get(rev, {}).get(fn)
3826 copy = copies.get(rev, {}).get(fn)
3827 if fn in skip:
3827 if fn in skip:
3828 if copy:
3828 if copy:
3829 skip[copy] = True
3829 skip[copy] = True
3830 continue
3830 continue
3831 pstates = matches.get(parent, {}).get(copy or fn, [])
3831 pstates = matches.get(parent, {}).get(copy or fn, [])
3832 if pstates or states:
3832 if pstates or states:
3833 r = display(fn, ctx, pstates, states)
3833 r = display(fn, ctx, pstates, states)
3834 found = found or r
3834 found = found or r
3835 if r and not opts.get('all'):
3835 if r and not opts.get('all'):
3836 skip[fn] = True
3836 skip[fn] = True
3837 if copy:
3837 if copy:
3838 skip[copy] = True
3838 skip[copy] = True
3839 del matches[rev]
3839 del matches[rev]
3840 del revfiles[rev]
3840 del revfiles[rev]
3841
3841
3842 return not found
3842 return not found
3843
3843
3844 @command('heads',
3844 @command('heads',
3845 [('r', 'rev', '',
3845 [('r', 'rev', '',
3846 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3846 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3847 ('t', 'topo', False, _('show topological heads only')),
3847 ('t', 'topo', False, _('show topological heads only')),
3848 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3848 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3849 ('c', 'closed', False, _('show normal and closed branch heads')),
3849 ('c', 'closed', False, _('show normal and closed branch heads')),
3850 ] + templateopts,
3850 ] + templateopts,
3851 _('[-ct] [-r STARTREV] [REV]...'))
3851 _('[-ct] [-r STARTREV] [REV]...'))
3852 def heads(ui, repo, *branchrevs, **opts):
3852 def heads(ui, repo, *branchrevs, **opts):
3853 """show branch heads
3853 """show branch heads
3854
3854
3855 With no arguments, show all open branch heads in the repository.
3855 With no arguments, show all open branch heads in the repository.
3856 Branch heads are changesets that have no descendants on the
3856 Branch heads are changesets that have no descendants on the
3857 same branch. They are where development generally takes place and
3857 same branch. They are where development generally takes place and
3858 are the usual targets for update and merge operations.
3858 are the usual targets for update and merge operations.
3859
3859
3860 If one or more REVs are given, only open branch heads on the
3860 If one or more REVs are given, only open branch heads on the
3861 branches associated with the specified changesets are shown. This
3861 branches associated with the specified changesets are shown. This
3862 means that you can use :hg:`heads .` to see the heads on the
3862 means that you can use :hg:`heads .` to see the heads on the
3863 currently checked-out branch.
3863 currently checked-out branch.
3864
3864
3865 If -c/--closed is specified, also show branch heads marked closed
3865 If -c/--closed is specified, also show branch heads marked closed
3866 (see :hg:`commit --close-branch`).
3866 (see :hg:`commit --close-branch`).
3867
3867
3868 If STARTREV is specified, only those heads that are descendants of
3868 If STARTREV is specified, only those heads that are descendants of
3869 STARTREV will be displayed.
3869 STARTREV will be displayed.
3870
3870
3871 If -t/--topo is specified, named branch mechanics will be ignored and only
3871 If -t/--topo is specified, named branch mechanics will be ignored and only
3872 topological heads (changesets with no children) will be shown.
3872 topological heads (changesets with no children) will be shown.
3873
3873
3874 Returns 0 if matching heads are found, 1 if not.
3874 Returns 0 if matching heads are found, 1 if not.
3875 """
3875 """
3876
3876
3877 start = None
3877 start = None
3878 if 'rev' in opts:
3878 if 'rev' in opts:
3879 start = scmutil.revsingle(repo, opts['rev'], None).node()
3879 start = scmutil.revsingle(repo, opts['rev'], None).node()
3880
3880
3881 if opts.get('topo'):
3881 if opts.get('topo'):
3882 heads = [repo[h] for h in repo.heads(start)]
3882 heads = [repo[h] for h in repo.heads(start)]
3883 else:
3883 else:
3884 heads = []
3884 heads = []
3885 for branch in repo.branchmap():
3885 for branch in repo.branchmap():
3886 heads += repo.branchheads(branch, start, opts.get('closed'))
3886 heads += repo.branchheads(branch, start, opts.get('closed'))
3887 heads = [repo[h] for h in heads]
3887 heads = [repo[h] for h in heads]
3888
3888
3889 if branchrevs:
3889 if branchrevs:
3890 branches = set(repo[br].branch() for br in branchrevs)
3890 branches = set(repo[br].branch() for br in branchrevs)
3891 heads = [h for h in heads if h.branch() in branches]
3891 heads = [h for h in heads if h.branch() in branches]
3892
3892
3893 if opts.get('active') and branchrevs:
3893 if opts.get('active') and branchrevs:
3894 dagheads = repo.heads(start)
3894 dagheads = repo.heads(start)
3895 heads = [h for h in heads if h.node() in dagheads]
3895 heads = [h for h in heads if h.node() in dagheads]
3896
3896
3897 if branchrevs:
3897 if branchrevs:
3898 haveheads = set(h.branch() for h in heads)
3898 haveheads = set(h.branch() for h in heads)
3899 if branches - haveheads:
3899 if branches - haveheads:
3900 headless = ', '.join(b for b in branches - haveheads)
3900 headless = ', '.join(b for b in branches - haveheads)
3901 msg = _('no open branch heads found on branches %s')
3901 msg = _('no open branch heads found on branches %s')
3902 if opts.get('rev'):
3902 if opts.get('rev'):
3903 msg += _(' (started at %s)') % opts['rev']
3903 msg += _(' (started at %s)') % opts['rev']
3904 ui.warn((msg + '\n') % headless)
3904 ui.warn((msg + '\n') % headless)
3905
3905
3906 if not heads:
3906 if not heads:
3907 return 1
3907 return 1
3908
3908
3909 heads = sorted(heads, key=lambda x: -x.rev())
3909 heads = sorted(heads, key=lambda x: -x.rev())
3910 displayer = cmdutil.show_changeset(ui, repo, opts)
3910 displayer = cmdutil.show_changeset(ui, repo, opts)
3911 for ctx in heads:
3911 for ctx in heads:
3912 displayer.show(ctx)
3912 displayer.show(ctx)
3913 displayer.close()
3913 displayer.close()
3914
3914
3915 @command('help',
3915 @command('help',
3916 [('e', 'extension', None, _('show only help for extensions')),
3916 [('e', 'extension', None, _('show only help for extensions')),
3917 ('c', 'command', None, _('show only help for commands')),
3917 ('c', 'command', None, _('show only help for commands')),
3918 ('k', 'keyword', '', _('show topics matching keyword')),
3918 ('k', 'keyword', '', _('show topics matching keyword')),
3919 ],
3919 ],
3920 _('[-ec] [TOPIC]'),
3920 _('[-ec] [TOPIC]'),
3921 norepo=True)
3921 norepo=True)
3922 def help_(ui, name=None, **opts):
3922 def help_(ui, name=None, **opts):
3923 """show help for a given topic or a help overview
3923 """show help for a given topic or a help overview
3924
3924
3925 With no arguments, print a list of commands with short help messages.
3925 With no arguments, print a list of commands with short help messages.
3926
3926
3927 Given a topic, extension, or command name, print help for that
3927 Given a topic, extension, or command name, print help for that
3928 topic.
3928 topic.
3929
3929
3930 Returns 0 if successful.
3930 Returns 0 if successful.
3931 """
3931 """
3932
3932
3933 textwidth = min(ui.termwidth(), 80) - 2
3933 textwidth = min(ui.termwidth(), 80) - 2
3934
3934
3935 keep = []
3935 keep = []
3936 if ui.verbose:
3936 if ui.verbose:
3937 keep.append('verbose')
3937 keep.append('verbose')
3938 if sys.platform.startswith('win'):
3938 if sys.platform.startswith('win'):
3939 keep.append('windows')
3939 keep.append('windows')
3940 elif sys.platform == 'OpenVMS':
3940 elif sys.platform == 'OpenVMS':
3941 keep.append('vms')
3941 keep.append('vms')
3942 elif sys.platform == 'plan9':
3942 elif sys.platform == 'plan9':
3943 keep.append('plan9')
3943 keep.append('plan9')
3944 else:
3944 else:
3945 keep.append('unix')
3945 keep.append('unix')
3946 keep.append(sys.platform.lower())
3946 keep.append(sys.platform.lower())
3947
3947
3948 section = None
3948 section = None
3949 if name and '.' in name:
3949 if name and '.' in name:
3950 name, section = name.split('.', 1)
3950 name, section = name.split('.', 1)
3951
3951
3952 text = help.help_(ui, name, **opts)
3952 text = help.help_(ui, name, **opts)
3953
3953
3954 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3954 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3955 section=section)
3955 section=section)
3956 if section and not formatted:
3956 if section and not formatted:
3957 raise util.Abort(_("help section not found"))
3957 raise util.Abort(_("help section not found"))
3958
3958
3959 if 'verbose' in pruned:
3959 if 'verbose' in pruned:
3960 keep.append('omitted')
3960 keep.append('omitted')
3961 else:
3961 else:
3962 keep.append('notomitted')
3962 keep.append('notomitted')
3963 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3963 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3964 section=section)
3964 section=section)
3965 ui.write(formatted)
3965 ui.write(formatted)
3966
3966
3967
3967
3968 @command('identify|id',
3968 @command('identify|id',
3969 [('r', 'rev', '',
3969 [('r', 'rev', '',
3970 _('identify the specified revision'), _('REV')),
3970 _('identify the specified revision'), _('REV')),
3971 ('n', 'num', None, _('show local revision number')),
3971 ('n', 'num', None, _('show local revision number')),
3972 ('i', 'id', None, _('show global revision id')),
3972 ('i', 'id', None, _('show global revision id')),
3973 ('b', 'branch', None, _('show branch')),
3973 ('b', 'branch', None, _('show branch')),
3974 ('t', 'tags', None, _('show tags')),
3974 ('t', 'tags', None, _('show tags')),
3975 ('B', 'bookmarks', None, _('show bookmarks')),
3975 ('B', 'bookmarks', None, _('show bookmarks')),
3976 ] + remoteopts,
3976 ] + remoteopts,
3977 _('[-nibtB] [-r REV] [SOURCE]'),
3977 _('[-nibtB] [-r REV] [SOURCE]'),
3978 optionalrepo=True)
3978 optionalrepo=True)
3979 def identify(ui, repo, source=None, rev=None,
3979 def identify(ui, repo, source=None, rev=None,
3980 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3980 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3981 """identify the working directory or specified revision
3981 """identify the working directory or specified revision
3982
3982
3983 Print a summary identifying the repository state at REV using one or
3983 Print a summary identifying the repository state at REV using one or
3984 two parent hash identifiers, followed by a "+" if the working
3984 two parent hash identifiers, followed by a "+" if the working
3985 directory has uncommitted changes, the branch name (if not default),
3985 directory has uncommitted changes, the branch name (if not default),
3986 a list of tags, and a list of bookmarks.
3986 a list of tags, and a list of bookmarks.
3987
3987
3988 When REV is not given, print a summary of the current state of the
3988 When REV is not given, print a summary of the current state of the
3989 repository.
3989 repository.
3990
3990
3991 Specifying a path to a repository root or Mercurial bundle will
3991 Specifying a path to a repository root or Mercurial bundle will
3992 cause lookup to operate on that repository/bundle.
3992 cause lookup to operate on that repository/bundle.
3993
3993
3994 .. container:: verbose
3994 .. container:: verbose
3995
3995
3996 Examples:
3996 Examples:
3997
3997
3998 - generate a build identifier for the working directory::
3998 - generate a build identifier for the working directory::
3999
3999
4000 hg id --id > build-id.dat
4000 hg id --id > build-id.dat
4001
4001
4002 - find the revision corresponding to a tag::
4002 - find the revision corresponding to a tag::
4003
4003
4004 hg id -n -r 1.3
4004 hg id -n -r 1.3
4005
4005
4006 - check the most recent revision of a remote repository::
4006 - check the most recent revision of a remote repository::
4007
4007
4008 hg id -r tip http://selenic.com/hg/
4008 hg id -r tip http://selenic.com/hg/
4009
4009
4010 Returns 0 if successful.
4010 Returns 0 if successful.
4011 """
4011 """
4012
4012
4013 if not repo and not source:
4013 if not repo and not source:
4014 raise util.Abort(_("there is no Mercurial repository here "
4014 raise util.Abort(_("there is no Mercurial repository here "
4015 "(.hg not found)"))
4015 "(.hg not found)"))
4016
4016
4017 if ui.debugflag:
4017 if ui.debugflag:
4018 hexfunc = hex
4018 hexfunc = hex
4019 else:
4019 else:
4020 hexfunc = short
4020 hexfunc = short
4021 default = not (num or id or branch or tags or bookmarks)
4021 default = not (num or id or branch or tags or bookmarks)
4022 output = []
4022 output = []
4023 revs = []
4023 revs = []
4024
4024
4025 if source:
4025 if source:
4026 source, branches = hg.parseurl(ui.expandpath(source))
4026 source, branches = hg.parseurl(ui.expandpath(source))
4027 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4027 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4028 repo = peer.local()
4028 repo = peer.local()
4029 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4029 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4030
4030
4031 if not repo:
4031 if not repo:
4032 if num or branch or tags:
4032 if num or branch or tags:
4033 raise util.Abort(
4033 raise util.Abort(
4034 _("can't query remote revision number, branch, or tags"))
4034 _("can't query remote revision number, branch, or tags"))
4035 if not rev and revs:
4035 if not rev and revs:
4036 rev = revs[0]
4036 rev = revs[0]
4037 if not rev:
4037 if not rev:
4038 rev = "tip"
4038 rev = "tip"
4039
4039
4040 remoterev = peer.lookup(rev)
4040 remoterev = peer.lookup(rev)
4041 if default or id:
4041 if default or id:
4042 output = [hexfunc(remoterev)]
4042 output = [hexfunc(remoterev)]
4043
4043
4044 def getbms():
4044 def getbms():
4045 bms = []
4045 bms = []
4046
4046
4047 if 'bookmarks' in peer.listkeys('namespaces'):
4047 if 'bookmarks' in peer.listkeys('namespaces'):
4048 hexremoterev = hex(remoterev)
4048 hexremoterev = hex(remoterev)
4049 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4049 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4050 if bmr == hexremoterev]
4050 if bmr == hexremoterev]
4051
4051
4052 return sorted(bms)
4052 return sorted(bms)
4053
4053
4054 if bookmarks:
4054 if bookmarks:
4055 output.extend(getbms())
4055 output.extend(getbms())
4056 elif default and not ui.quiet:
4056 elif default and not ui.quiet:
4057 # multiple bookmarks for a single parent separated by '/'
4057 # multiple bookmarks for a single parent separated by '/'
4058 bm = '/'.join(getbms())
4058 bm = '/'.join(getbms())
4059 if bm:
4059 if bm:
4060 output.append(bm)
4060 output.append(bm)
4061 else:
4061 else:
4062 if not rev:
4062 if not rev:
4063 ctx = repo[None]
4063 ctx = repo[None]
4064 parents = ctx.parents()
4064 parents = ctx.parents()
4065 changed = ""
4065 changed = ""
4066 if default or id or num:
4066 if default or id or num:
4067 if (any(repo.status())
4067 if (any(repo.status())
4068 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4068 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4069 changed = '+'
4069 changed = '+'
4070 if default or id:
4070 if default or id:
4071 output = ["%s%s" %
4071 output = ["%s%s" %
4072 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4072 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4073 if num:
4073 if num:
4074 output.append("%s%s" %
4074 output.append("%s%s" %
4075 ('+'.join([str(p.rev()) for p in parents]), changed))
4075 ('+'.join([str(p.rev()) for p in parents]), changed))
4076 else:
4076 else:
4077 ctx = scmutil.revsingle(repo, rev)
4077 ctx = scmutil.revsingle(repo, rev)
4078 if default or id:
4078 if default or id:
4079 output = [hexfunc(ctx.node())]
4079 output = [hexfunc(ctx.node())]
4080 if num:
4080 if num:
4081 output.append(str(ctx.rev()))
4081 output.append(str(ctx.rev()))
4082
4082
4083 if default and not ui.quiet:
4083 if default and not ui.quiet:
4084 b = ctx.branch()
4084 b = ctx.branch()
4085 if b != 'default':
4085 if b != 'default':
4086 output.append("(%s)" % b)
4086 output.append("(%s)" % b)
4087
4087
4088 # multiple tags for a single parent separated by '/'
4088 # multiple tags for a single parent separated by '/'
4089 t = '/'.join(ctx.tags())
4089 t = '/'.join(ctx.tags())
4090 if t:
4090 if t:
4091 output.append(t)
4091 output.append(t)
4092
4092
4093 # multiple bookmarks for a single parent separated by '/'
4093 # multiple bookmarks for a single parent separated by '/'
4094 bm = '/'.join(ctx.bookmarks())
4094 bm = '/'.join(ctx.bookmarks())
4095 if bm:
4095 if bm:
4096 output.append(bm)
4096 output.append(bm)
4097 else:
4097 else:
4098 if branch:
4098 if branch:
4099 output.append(ctx.branch())
4099 output.append(ctx.branch())
4100
4100
4101 if tags:
4101 if tags:
4102 output.extend(ctx.tags())
4102 output.extend(ctx.tags())
4103
4103
4104 if bookmarks:
4104 if bookmarks:
4105 output.extend(ctx.bookmarks())
4105 output.extend(ctx.bookmarks())
4106
4106
4107 ui.write("%s\n" % ' '.join(output))
4107 ui.write("%s\n" % ' '.join(output))
4108
4108
4109 @command('import|patch',
4109 @command('import|patch',
4110 [('p', 'strip', 1,
4110 [('p', 'strip', 1,
4111 _('directory strip option for patch. This has the same '
4111 _('directory strip option for patch. This has the same '
4112 'meaning as the corresponding patch option'), _('NUM')),
4112 'meaning as the corresponding patch option'), _('NUM')),
4113 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4113 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4114 ('e', 'edit', False, _('invoke editor on commit messages')),
4114 ('e', 'edit', False, _('invoke editor on commit messages')),
4115 ('f', 'force', None,
4115 ('f', 'force', None,
4116 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4116 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4117 ('', 'no-commit', None,
4117 ('', 'no-commit', None,
4118 _("don't commit, just update the working directory")),
4118 _("don't commit, just update the working directory")),
4119 ('', 'bypass', None,
4119 ('', 'bypass', None,
4120 _("apply patch without touching the working directory")),
4120 _("apply patch without touching the working directory")),
4121 ('', 'partial', None,
4121 ('', 'partial', None,
4122 _('commit even if some hunks fail')),
4122 _('commit even if some hunks fail')),
4123 ('', 'exact', None,
4123 ('', 'exact', None,
4124 _('apply patch to the nodes from which it was generated')),
4124 _('apply patch to the nodes from which it was generated')),
4125 ('', 'prefix', '',
4125 ('', 'prefix', '',
4126 _('apply patch to subdirectory'), _('DIR')),
4126 _('apply patch to subdirectory'), _('DIR')),
4127 ('', 'import-branch', None,
4127 ('', 'import-branch', None,
4128 _('use any branch information in patch (implied by --exact)'))] +
4128 _('use any branch information in patch (implied by --exact)'))] +
4129 commitopts + commitopts2 + similarityopts,
4129 commitopts + commitopts2 + similarityopts,
4130 _('[OPTION]... PATCH...'))
4130 _('[OPTION]... PATCH...'))
4131 def import_(ui, repo, patch1=None, *patches, **opts):
4131 def import_(ui, repo, patch1=None, *patches, **opts):
4132 """import an ordered set of patches
4132 """import an ordered set of patches
4133
4133
4134 Import a list of patches and commit them individually (unless
4134 Import a list of patches and commit them individually (unless
4135 --no-commit is specified).
4135 --no-commit is specified).
4136
4136
4137 Because import first applies changes to the working directory,
4137 Because import first applies changes to the working directory,
4138 import will abort if there are outstanding changes.
4138 import will abort if there are outstanding changes.
4139
4139
4140 You can import a patch straight from a mail message. Even patches
4140 You can import a patch straight from a mail message. Even patches
4141 as attachments work (to use the body part, it must have type
4141 as attachments work (to use the body part, it must have type
4142 text/plain or text/x-patch). From and Subject headers of email
4142 text/plain or text/x-patch). From and Subject headers of email
4143 message are used as default committer and commit message. All
4143 message are used as default committer and commit message. All
4144 text/plain body parts before first diff are added to commit
4144 text/plain body parts before first diff are added to commit
4145 message.
4145 message.
4146
4146
4147 If the imported patch was generated by :hg:`export`, user and
4147 If the imported patch was generated by :hg:`export`, user and
4148 description from patch override values from message headers and
4148 description from patch override values from message headers and
4149 body. Values given on command line with -m/--message and -u/--user
4149 body. Values given on command line with -m/--message and -u/--user
4150 override these.
4150 override these.
4151
4151
4152 If --exact is specified, import will set the working directory to
4152 If --exact is specified, import will set the working directory to
4153 the parent of each patch before applying it, and will abort if the
4153 the parent of each patch before applying it, and will abort if the
4154 resulting changeset has a different ID than the one recorded in
4154 resulting changeset has a different ID than the one recorded in
4155 the patch. This may happen due to character set problems or other
4155 the patch. This may happen due to character set problems or other
4156 deficiencies in the text patch format.
4156 deficiencies in the text patch format.
4157
4157
4158 Use --bypass to apply and commit patches directly to the
4158 Use --bypass to apply and commit patches directly to the
4159 repository, not touching the working directory. Without --exact,
4159 repository, not touching the working directory. Without --exact,
4160 patches will be applied on top of the working directory parent
4160 patches will be applied on top of the working directory parent
4161 revision.
4161 revision.
4162
4162
4163 With -s/--similarity, hg will attempt to discover renames and
4163 With -s/--similarity, hg will attempt to discover renames and
4164 copies in the patch in the same way as :hg:`addremove`.
4164 copies in the patch in the same way as :hg:`addremove`.
4165
4165
4166 Use --partial to ensure a changeset will be created from the patch
4166 Use --partial to ensure a changeset will be created from the patch
4167 even if some hunks fail to apply. Hunks that fail to apply will be
4167 even if some hunks fail to apply. Hunks that fail to apply will be
4168 written to a <target-file>.rej file. Conflicts can then be resolved
4168 written to a <target-file>.rej file. Conflicts can then be resolved
4169 by hand before :hg:`commit --amend` is run to update the created
4169 by hand before :hg:`commit --amend` is run to update the created
4170 changeset. This flag exists to let people import patches that
4170 changeset. This flag exists to let people import patches that
4171 partially apply without losing the associated metadata (author,
4171 partially apply without losing the associated metadata (author,
4172 date, description, ...). Note that when none of the hunk applies
4172 date, description, ...). Note that when none of the hunk applies
4173 cleanly, :hg:`import --partial` will create an empty changeset,
4173 cleanly, :hg:`import --partial` will create an empty changeset,
4174 importing only the patch metadata.
4174 importing only the patch metadata.
4175
4175
4176 To read a patch from standard input, use "-" as the patch name. If
4176 To read a patch from standard input, use "-" as the patch name. If
4177 a URL is specified, the patch will be downloaded from it.
4177 a URL is specified, the patch will be downloaded from it.
4178 See :hg:`help dates` for a list of formats valid for -d/--date.
4178 See :hg:`help dates` for a list of formats valid for -d/--date.
4179
4179
4180 .. container:: verbose
4180 .. container:: verbose
4181
4181
4182 Examples:
4182 Examples:
4183
4183
4184 - import a traditional patch from a website and detect renames::
4184 - import a traditional patch from a website and detect renames::
4185
4185
4186 hg import -s 80 http://example.com/bugfix.patch
4186 hg import -s 80 http://example.com/bugfix.patch
4187
4187
4188 - import a changeset from an hgweb server::
4188 - import a changeset from an hgweb server::
4189
4189
4190 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4190 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4191
4191
4192 - import all the patches in an Unix-style mbox::
4192 - import all the patches in an Unix-style mbox::
4193
4193
4194 hg import incoming-patches.mbox
4194 hg import incoming-patches.mbox
4195
4195
4196 - attempt to exactly restore an exported changeset (not always
4196 - attempt to exactly restore an exported changeset (not always
4197 possible)::
4197 possible)::
4198
4198
4199 hg import --exact proposed-fix.patch
4199 hg import --exact proposed-fix.patch
4200
4200
4201 Returns 0 on success, 1 on partial success (see --partial).
4201 Returns 0 on success, 1 on partial success (see --partial).
4202 """
4202 """
4203
4203
4204 if not patch1:
4204 if not patch1:
4205 raise util.Abort(_('need at least one patch to import'))
4205 raise util.Abort(_('need at least one patch to import'))
4206
4206
4207 patches = (patch1,) + patches
4207 patches = (patch1,) + patches
4208
4208
4209 date = opts.get('date')
4209 date = opts.get('date')
4210 if date:
4210 if date:
4211 opts['date'] = util.parsedate(date)
4211 opts['date'] = util.parsedate(date)
4212
4212
4213 update = not opts.get('bypass')
4213 update = not opts.get('bypass')
4214 if not update and opts.get('no_commit'):
4214 if not update and opts.get('no_commit'):
4215 raise util.Abort(_('cannot use --no-commit with --bypass'))
4215 raise util.Abort(_('cannot use --no-commit with --bypass'))
4216 try:
4216 try:
4217 sim = float(opts.get('similarity') or 0)
4217 sim = float(opts.get('similarity') or 0)
4218 except ValueError:
4218 except ValueError:
4219 raise util.Abort(_('similarity must be a number'))
4219 raise util.Abort(_('similarity must be a number'))
4220 if sim < 0 or sim > 100:
4220 if sim < 0 or sim > 100:
4221 raise util.Abort(_('similarity must be between 0 and 100'))
4221 raise util.Abort(_('similarity must be between 0 and 100'))
4222 if sim and not update:
4222 if sim and not update:
4223 raise util.Abort(_('cannot use --similarity with --bypass'))
4223 raise util.Abort(_('cannot use --similarity with --bypass'))
4224 if opts.get('exact') and opts.get('edit'):
4224 if opts.get('exact') and opts.get('edit'):
4225 raise util.Abort(_('cannot use --exact with --edit'))
4225 raise util.Abort(_('cannot use --exact with --edit'))
4226 if opts.get('exact') and opts.get('prefix'):
4226 if opts.get('exact') and opts.get('prefix'):
4227 raise util.Abort(_('cannot use --exact with --prefix'))
4227 raise util.Abort(_('cannot use --exact with --prefix'))
4228
4228
4229 if update:
4229 if update:
4230 cmdutil.checkunfinished(repo)
4230 cmdutil.checkunfinished(repo)
4231 if (opts.get('exact') or not opts.get('force')) and update:
4231 if (opts.get('exact') or not opts.get('force')) and update:
4232 cmdutil.bailifchanged(repo)
4232 cmdutil.bailifchanged(repo)
4233
4233
4234 base = opts["base"]
4234 base = opts["base"]
4235 wlock = dsguard = lock = tr = None
4235 wlock = dsguard = lock = tr = None
4236 msgs = []
4236 msgs = []
4237 ret = 0
4237 ret = 0
4238
4238
4239
4239
4240 try:
4240 try:
4241 try:
4241 try:
4242 wlock = repo.wlock()
4242 wlock = repo.wlock()
4243 dsguard = cmdutil.dirstateguard(repo, 'import')
4243 dsguard = cmdutil.dirstateguard(repo, 'import')
4244 if not opts.get('no_commit'):
4244 if not opts.get('no_commit'):
4245 lock = repo.lock()
4245 lock = repo.lock()
4246 tr = repo.transaction('import')
4246 tr = repo.transaction('import')
4247 parents = repo.parents()
4247 parents = repo.parents()
4248 for patchurl in patches:
4248 for patchurl in patches:
4249 if patchurl == '-':
4249 if patchurl == '-':
4250 ui.status(_('applying patch from stdin\n'))
4250 ui.status(_('applying patch from stdin\n'))
4251 patchfile = ui.fin
4251 patchfile = ui.fin
4252 patchurl = 'stdin' # for error message
4252 patchurl = 'stdin' # for error message
4253 else:
4253 else:
4254 patchurl = os.path.join(base, patchurl)
4254 patchurl = os.path.join(base, patchurl)
4255 ui.status(_('applying %s\n') % patchurl)
4255 ui.status(_('applying %s\n') % patchurl)
4256 patchfile = hg.openpath(ui, patchurl)
4256 patchfile = hg.openpath(ui, patchurl)
4257
4257
4258 haspatch = False
4258 haspatch = False
4259 for hunk in patch.split(patchfile):
4259 for hunk in patch.split(patchfile):
4260 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4260 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4261 parents, opts,
4261 parents, opts,
4262 msgs, hg.clean)
4262 msgs, hg.clean)
4263 if msg:
4263 if msg:
4264 haspatch = True
4264 haspatch = True
4265 ui.note(msg + '\n')
4265 ui.note(msg + '\n')
4266 if update or opts.get('exact'):
4266 if update or opts.get('exact'):
4267 parents = repo.parents()
4267 parents = repo.parents()
4268 else:
4268 else:
4269 parents = [repo[node]]
4269 parents = [repo[node]]
4270 if rej:
4270 if rej:
4271 ui.write_err(_("patch applied partially\n"))
4271 ui.write_err(_("patch applied partially\n"))
4272 ui.write_err(_("(fix the .rej files and run "
4272 ui.write_err(_("(fix the .rej files and run "
4273 "`hg commit --amend`)\n"))
4273 "`hg commit --amend`)\n"))
4274 ret = 1
4274 ret = 1
4275 break
4275 break
4276
4276
4277 if not haspatch:
4277 if not haspatch:
4278 raise util.Abort(_('%s: no diffs found') % patchurl)
4278 raise util.Abort(_('%s: no diffs found') % patchurl)
4279
4279
4280 if tr:
4280 if tr:
4281 tr.close()
4281 tr.close()
4282 if msgs:
4282 if msgs:
4283 repo.savecommitmessage('\n* * *\n'.join(msgs))
4283 repo.savecommitmessage('\n* * *\n'.join(msgs))
4284 dsguard.close()
4284 dsguard.close()
4285 return ret
4285 return ret
4286 finally:
4286 finally:
4287 # TODO: get rid of this meaningless try/finally enclosing.
4287 # TODO: get rid of this meaningless try/finally enclosing.
4288 # this is kept only to reduce changes in a patch.
4288 # this is kept only to reduce changes in a patch.
4289 pass
4289 pass
4290 finally:
4290 finally:
4291 if tr:
4291 if tr:
4292 tr.release()
4292 tr.release()
4293 release(lock, dsguard, wlock)
4293 release(lock, dsguard, wlock)
4294
4294
4295 @command('incoming|in',
4295 @command('incoming|in',
4296 [('f', 'force', None,
4296 [('f', 'force', None,
4297 _('run even if remote repository is unrelated')),
4297 _('run even if remote repository is unrelated')),
4298 ('n', 'newest-first', None, _('show newest record first')),
4298 ('n', 'newest-first', None, _('show newest record first')),
4299 ('', 'bundle', '',
4299 ('', 'bundle', '',
4300 _('file to store the bundles into'), _('FILE')),
4300 _('file to store the bundles into'), _('FILE')),
4301 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4301 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4302 ('B', 'bookmarks', False, _("compare bookmarks")),
4302 ('B', 'bookmarks', False, _("compare bookmarks")),
4303 ('b', 'branch', [],
4303 ('b', 'branch', [],
4304 _('a specific branch you would like to pull'), _('BRANCH')),
4304 _('a specific branch you would like to pull'), _('BRANCH')),
4305 ] + logopts + remoteopts + subrepoopts,
4305 ] + logopts + remoteopts + subrepoopts,
4306 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4306 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4307 def incoming(ui, repo, source="default", **opts):
4307 def incoming(ui, repo, source="default", **opts):
4308 """show new changesets found in source
4308 """show new changesets found in source
4309
4309
4310 Show new changesets found in the specified path/URL or the default
4310 Show new changesets found in the specified path/URL or the default
4311 pull location. These are the changesets that would have been pulled
4311 pull location. These are the changesets that would have been pulled
4312 if a pull at the time you issued this command.
4312 if a pull at the time you issued this command.
4313
4313
4314 See pull for valid source format details.
4314 See pull for valid source format details.
4315
4315
4316 .. container:: verbose
4316 .. container:: verbose
4317
4317
4318 With -B/--bookmarks, the result of bookmark comparison between
4318 With -B/--bookmarks, the result of bookmark comparison between
4319 local and remote repositories is displayed. With -v/--verbose,
4319 local and remote repositories is displayed. With -v/--verbose,
4320 status is also displayed for each bookmark like below::
4320 status is also displayed for each bookmark like below::
4321
4321
4322 BM1 01234567890a added
4322 BM1 01234567890a added
4323 BM2 1234567890ab advanced
4323 BM2 1234567890ab advanced
4324 BM3 234567890abc diverged
4324 BM3 234567890abc diverged
4325 BM4 34567890abcd changed
4325 BM4 34567890abcd changed
4326
4326
4327 The action taken locally when pulling depends on the
4327 The action taken locally when pulling depends on the
4328 status of each bookmark:
4328 status of each bookmark:
4329
4329
4330 :``added``: pull will create it
4330 :``added``: pull will create it
4331 :``advanced``: pull will update it
4331 :``advanced``: pull will update it
4332 :``diverged``: pull will create a divergent bookmark
4332 :``diverged``: pull will create a divergent bookmark
4333 :``changed``: result depends on remote changesets
4333 :``changed``: result depends on remote changesets
4334
4334
4335 From the point of view of pulling behavior, bookmark
4335 From the point of view of pulling behavior, bookmark
4336 existing only in the remote repository are treated as ``added``,
4336 existing only in the remote repository are treated as ``added``,
4337 even if it is in fact locally deleted.
4337 even if it is in fact locally deleted.
4338
4338
4339 .. container:: verbose
4339 .. container:: verbose
4340
4340
4341 For remote repository, using --bundle avoids downloading the
4341 For remote repository, using --bundle avoids downloading the
4342 changesets twice if the incoming is followed by a pull.
4342 changesets twice if the incoming is followed by a pull.
4343
4343
4344 Examples:
4344 Examples:
4345
4345
4346 - show incoming changes with patches and full description::
4346 - show incoming changes with patches and full description::
4347
4347
4348 hg incoming -vp
4348 hg incoming -vp
4349
4349
4350 - show incoming changes excluding merges, store a bundle::
4350 - show incoming changes excluding merges, store a bundle::
4351
4351
4352 hg in -vpM --bundle incoming.hg
4352 hg in -vpM --bundle incoming.hg
4353 hg pull incoming.hg
4353 hg pull incoming.hg
4354
4354
4355 - briefly list changes inside a bundle::
4355 - briefly list changes inside a bundle::
4356
4356
4357 hg in changes.hg -T "{desc|firstline}\\n"
4357 hg in changes.hg -T "{desc|firstline}\\n"
4358
4358
4359 Returns 0 if there are incoming changes, 1 otherwise.
4359 Returns 0 if there are incoming changes, 1 otherwise.
4360 """
4360 """
4361 if opts.get('graph'):
4361 if opts.get('graph'):
4362 cmdutil.checkunsupportedgraphflags([], opts)
4362 cmdutil.checkunsupportedgraphflags([], opts)
4363 def display(other, chlist, displayer):
4363 def display(other, chlist, displayer):
4364 revdag = cmdutil.graphrevs(other, chlist, opts)
4364 revdag = cmdutil.graphrevs(other, chlist, opts)
4365 showparents = [ctx.node() for ctx in repo[None].parents()]
4365 showparents = [ctx.node() for ctx in repo[None].parents()]
4366 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4366 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4367 graphmod.asciiedges)
4367 graphmod.asciiedges)
4368
4368
4369 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4369 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4370 return 0
4370 return 0
4371
4371
4372 if opts.get('bundle') and opts.get('subrepos'):
4372 if opts.get('bundle') and opts.get('subrepos'):
4373 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4373 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4374
4374
4375 if opts.get('bookmarks'):
4375 if opts.get('bookmarks'):
4376 source, branches = hg.parseurl(ui.expandpath(source),
4376 source, branches = hg.parseurl(ui.expandpath(source),
4377 opts.get('branch'))
4377 opts.get('branch'))
4378 other = hg.peer(repo, opts, source)
4378 other = hg.peer(repo, opts, source)
4379 if 'bookmarks' not in other.listkeys('namespaces'):
4379 if 'bookmarks' not in other.listkeys('namespaces'):
4380 ui.warn(_("remote doesn't support bookmarks\n"))
4380 ui.warn(_("remote doesn't support bookmarks\n"))
4381 return 0
4381 return 0
4382 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4382 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4383 return bookmarks.incoming(ui, repo, other)
4383 return bookmarks.incoming(ui, repo, other)
4384
4384
4385 repo._subtoppath = ui.expandpath(source)
4385 repo._subtoppath = ui.expandpath(source)
4386 try:
4386 try:
4387 return hg.incoming(ui, repo, source, opts)
4387 return hg.incoming(ui, repo, source, opts)
4388 finally:
4388 finally:
4389 del repo._subtoppath
4389 del repo._subtoppath
4390
4390
4391
4391
4392 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4392 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4393 norepo=True)
4393 norepo=True)
4394 def init(ui, dest=".", **opts):
4394 def init(ui, dest=".", **opts):
4395 """create a new repository in the given directory
4395 """create a new repository in the given directory
4396
4396
4397 Initialize a new repository in the given directory. If the given
4397 Initialize a new repository in the given directory. If the given
4398 directory does not exist, it will be created.
4398 directory does not exist, it will be created.
4399
4399
4400 If no directory is given, the current directory is used.
4400 If no directory is given, the current directory is used.
4401
4401
4402 It is possible to specify an ``ssh://`` URL as the destination.
4402 It is possible to specify an ``ssh://`` URL as the destination.
4403 See :hg:`help urls` for more information.
4403 See :hg:`help urls` for more information.
4404
4404
4405 Returns 0 on success.
4405 Returns 0 on success.
4406 """
4406 """
4407 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4407 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4408
4408
4409 @command('locate',
4409 @command('locate',
4410 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4410 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4411 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4411 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4412 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4412 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4413 ] + walkopts,
4413 ] + walkopts,
4414 _('[OPTION]... [PATTERN]...'))
4414 _('[OPTION]... [PATTERN]...'))
4415 def locate(ui, repo, *pats, **opts):
4415 def locate(ui, repo, *pats, **opts):
4416 """locate files matching specific patterns (DEPRECATED)
4416 """locate files matching specific patterns (DEPRECATED)
4417
4417
4418 Print files under Mercurial control in the working directory whose
4418 Print files under Mercurial control in the working directory whose
4419 names match the given patterns.
4419 names match the given patterns.
4420
4420
4421 By default, this command searches all directories in the working
4421 By default, this command searches all directories in the working
4422 directory. To search just the current directory and its
4422 directory. To search just the current directory and its
4423 subdirectories, use "--include .".
4423 subdirectories, use "--include .".
4424
4424
4425 If no patterns are given to match, this command prints the names
4425 If no patterns are given to match, this command prints the names
4426 of all files under Mercurial control in the working directory.
4426 of all files under Mercurial control in the working directory.
4427
4427
4428 If you want to feed the output of this command into the "xargs"
4428 If you want to feed the output of this command into the "xargs"
4429 command, use the -0 option to both this command and "xargs". This
4429 command, use the -0 option to both this command and "xargs". This
4430 will avoid the problem of "xargs" treating single filenames that
4430 will avoid the problem of "xargs" treating single filenames that
4431 contain whitespace as multiple filenames.
4431 contain whitespace as multiple filenames.
4432
4432
4433 See :hg:`help files` for a more versatile command.
4433 See :hg:`help files` for a more versatile command.
4434
4434
4435 Returns 0 if a match is found, 1 otherwise.
4435 Returns 0 if a match is found, 1 otherwise.
4436 """
4436 """
4437 if opts.get('print0'):
4437 if opts.get('print0'):
4438 end = '\0'
4438 end = '\0'
4439 else:
4439 else:
4440 end = '\n'
4440 end = '\n'
4441 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4441 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4442
4442
4443 ret = 1
4443 ret = 1
4444 ctx = repo[rev]
4444 ctx = repo[rev]
4445 m = scmutil.match(ctx, pats, opts, default='relglob')
4445 m = scmutil.match(ctx, pats, opts, default='relglob')
4446 m.bad = lambda x, y: False
4446 m.bad = lambda x, y: False
4447
4447
4448 for abs in ctx.matches(m):
4448 for abs in ctx.matches(m):
4449 if opts.get('fullpath'):
4449 if opts.get('fullpath'):
4450 ui.write(repo.wjoin(abs), end)
4450 ui.write(repo.wjoin(abs), end)
4451 else:
4451 else:
4452 ui.write(((pats and m.rel(abs)) or abs), end)
4452 ui.write(((pats and m.rel(abs)) or abs), end)
4453 ret = 0
4453 ret = 0
4454
4454
4455 return ret
4455 return ret
4456
4456
4457 @command('^log|history',
4457 @command('^log|history',
4458 [('f', 'follow', None,
4458 [('f', 'follow', None,
4459 _('follow changeset history, or file history across copies and renames')),
4459 _('follow changeset history, or file history across copies and renames')),
4460 ('', 'follow-first', None,
4460 ('', 'follow-first', None,
4461 _('only follow the first parent of merge changesets (DEPRECATED)')),
4461 _('only follow the first parent of merge changesets (DEPRECATED)')),
4462 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4462 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4463 ('C', 'copies', None, _('show copied files')),
4463 ('C', 'copies', None, _('show copied files')),
4464 ('k', 'keyword', [],
4464 ('k', 'keyword', [],
4465 _('do case-insensitive search for a given text'), _('TEXT')),
4465 _('do case-insensitive search for a given text'), _('TEXT')),
4466 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4466 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4467 ('', 'removed', None, _('include revisions where files were removed')),
4467 ('', 'removed', None, _('include revisions where files were removed')),
4468 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4468 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4469 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4469 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4470 ('', 'only-branch', [],
4470 ('', 'only-branch', [],
4471 _('show only changesets within the given named branch (DEPRECATED)'),
4471 _('show only changesets within the given named branch (DEPRECATED)'),
4472 _('BRANCH')),
4472 _('BRANCH')),
4473 ('b', 'branch', [],
4473 ('b', 'branch', [],
4474 _('show changesets within the given named branch'), _('BRANCH')),
4474 _('show changesets within the given named branch'), _('BRANCH')),
4475 ('P', 'prune', [],
4475 ('P', 'prune', [],
4476 _('do not display revision or any of its ancestors'), _('REV')),
4476 _('do not display revision or any of its ancestors'), _('REV')),
4477 ] + logopts + walkopts,
4477 ] + logopts + walkopts,
4478 _('[OPTION]... [FILE]'),
4478 _('[OPTION]... [FILE]'),
4479 inferrepo=True)
4479 inferrepo=True)
4480 def log(ui, repo, *pats, **opts):
4480 def log(ui, repo, *pats, **opts):
4481 """show revision history of entire repository or files
4481 """show revision history of entire repository or files
4482
4482
4483 Print the revision history of the specified files or the entire
4483 Print the revision history of the specified files or the entire
4484 project.
4484 project.
4485
4485
4486 If no revision range is specified, the default is ``tip:0`` unless
4486 If no revision range is specified, the default is ``tip:0`` unless
4487 --follow is set, in which case the working directory parent is
4487 --follow is set, in which case the working directory parent is
4488 used as the starting revision.
4488 used as the starting revision.
4489
4489
4490 File history is shown without following rename or copy history of
4490 File history is shown without following rename or copy history of
4491 files. Use -f/--follow with a filename to follow history across
4491 files. Use -f/--follow with a filename to follow history across
4492 renames and copies. --follow without a filename will only show
4492 renames and copies. --follow without a filename will only show
4493 ancestors or descendants of the starting revision.
4493 ancestors or descendants of the starting revision.
4494
4494
4495 By default this command prints revision number and changeset id,
4495 By default this command prints revision number and changeset id,
4496 tags, non-trivial parents, user, date and time, and a summary for
4496 tags, non-trivial parents, user, date and time, and a summary for
4497 each commit. When the -v/--verbose switch is used, the list of
4497 each commit. When the -v/--verbose switch is used, the list of
4498 changed files and full commit message are shown.
4498 changed files and full commit message are shown.
4499
4499
4500 With --graph the revisions are shown as an ASCII art DAG with the most
4500 With --graph the revisions are shown as an ASCII art DAG with the most
4501 recent changeset at the top.
4501 recent changeset at the top.
4502 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4502 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4503 and '+' represents a fork where the changeset from the lines below is a
4503 and '+' represents a fork where the changeset from the lines below is a
4504 parent of the 'o' merge on the same line.
4504 parent of the 'o' merge on the same line.
4505
4505
4506 .. note::
4506 .. note::
4507
4507
4508 log -p/--patch may generate unexpected diff output for merge
4508 log -p/--patch may generate unexpected diff output for merge
4509 changesets, as it will only compare the merge changeset against
4509 changesets, as it will only compare the merge changeset against
4510 its first parent. Also, only files different from BOTH parents
4510 its first parent. Also, only files different from BOTH parents
4511 will appear in files:.
4511 will appear in files:.
4512
4512
4513 .. note::
4513 .. note::
4514
4514
4515 for performance reasons, log FILE may omit duplicate changes
4515 for performance reasons, log FILE may omit duplicate changes
4516 made on branches and will not show removals or mode changes. To
4516 made on branches and will not show removals or mode changes. To
4517 see all such changes, use the --removed switch.
4517 see all such changes, use the --removed switch.
4518
4518
4519 .. container:: verbose
4519 .. container:: verbose
4520
4520
4521 Some examples:
4521 Some examples:
4522
4522
4523 - changesets with full descriptions and file lists::
4523 - changesets with full descriptions and file lists::
4524
4524
4525 hg log -v
4525 hg log -v
4526
4526
4527 - changesets ancestral to the working directory::
4527 - changesets ancestral to the working directory::
4528
4528
4529 hg log -f
4529 hg log -f
4530
4530
4531 - last 10 commits on the current branch::
4531 - last 10 commits on the current branch::
4532
4532
4533 hg log -l 10 -b .
4533 hg log -l 10 -b .
4534
4534
4535 - changesets showing all modifications of a file, including removals::
4535 - changesets showing all modifications of a file, including removals::
4536
4536
4537 hg log --removed file.c
4537 hg log --removed file.c
4538
4538
4539 - all changesets that touch a directory, with diffs, excluding merges::
4539 - all changesets that touch a directory, with diffs, excluding merges::
4540
4540
4541 hg log -Mp lib/
4541 hg log -Mp lib/
4542
4542
4543 - all revision numbers that match a keyword::
4543 - all revision numbers that match a keyword::
4544
4544
4545 hg log -k bug --template "{rev}\\n"
4545 hg log -k bug --template "{rev}\\n"
4546
4546
4547 - list available log templates::
4547 - list available log templates::
4548
4548
4549 hg log -T list
4549 hg log -T list
4550
4550
4551 - check if a given changeset is included in a tagged release::
4551 - check if a given changeset is included in a tagged release::
4552
4552
4553 hg log -r "a21ccf and ancestor(1.9)"
4553 hg log -r "a21ccf and ancestor(1.9)"
4554
4554
4555 - find all changesets by some user in a date range::
4555 - find all changesets by some user in a date range::
4556
4556
4557 hg log -k alice -d "may 2008 to jul 2008"
4557 hg log -k alice -d "may 2008 to jul 2008"
4558
4558
4559 - summary of all changesets after the last tag::
4559 - summary of all changesets after the last tag::
4560
4560
4561 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4561 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4562
4562
4563 See :hg:`help dates` for a list of formats valid for -d/--date.
4563 See :hg:`help dates` for a list of formats valid for -d/--date.
4564
4564
4565 See :hg:`help revisions` and :hg:`help revsets` for more about
4565 See :hg:`help revisions` and :hg:`help revsets` for more about
4566 specifying revisions.
4566 specifying revisions.
4567
4567
4568 See :hg:`help templates` for more about pre-packaged styles and
4568 See :hg:`help templates` for more about pre-packaged styles and
4569 specifying custom templates.
4569 specifying custom templates.
4570
4570
4571 Returns 0 on success.
4571 Returns 0 on success.
4572
4572
4573 """
4573 """
4574 if opts.get('follow') and opts.get('rev'):
4574 if opts.get('follow') and opts.get('rev'):
4575 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4575 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4576 del opts['follow']
4576 del opts['follow']
4577
4577
4578 if opts.get('graph'):
4578 if opts.get('graph'):
4579 return cmdutil.graphlog(ui, repo, *pats, **opts)
4579 return cmdutil.graphlog(ui, repo, *pats, **opts)
4580
4580
4581 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4581 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4582 limit = cmdutil.loglimit(opts)
4582 limit = cmdutil.loglimit(opts)
4583 count = 0
4583 count = 0
4584
4584
4585 getrenamed = None
4585 getrenamed = None
4586 if opts.get('copies'):
4586 if opts.get('copies'):
4587 endrev = None
4587 endrev = None
4588 if opts.get('rev'):
4588 if opts.get('rev'):
4589 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4589 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4590 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4590 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4591
4591
4592 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4592 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4593 for rev in revs:
4593 for rev in revs:
4594 if count == limit:
4594 if count == limit:
4595 break
4595 break
4596 ctx = repo[rev]
4596 ctx = repo[rev]
4597 copies = None
4597 copies = None
4598 if getrenamed is not None and rev:
4598 if getrenamed is not None and rev:
4599 copies = []
4599 copies = []
4600 for fn in ctx.files():
4600 for fn in ctx.files():
4601 rename = getrenamed(fn, rev)
4601 rename = getrenamed(fn, rev)
4602 if rename:
4602 if rename:
4603 copies.append((fn, rename[0]))
4603 copies.append((fn, rename[0]))
4604 if filematcher:
4604 if filematcher:
4605 revmatchfn = filematcher(ctx.rev())
4605 revmatchfn = filematcher(ctx.rev())
4606 else:
4606 else:
4607 revmatchfn = None
4607 revmatchfn = None
4608 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4608 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4609 if displayer.flush(rev):
4609 if displayer.flush(rev):
4610 count += 1
4610 count += 1
4611
4611
4612 displayer.close()
4612 displayer.close()
4613
4613
4614 @command('manifest',
4614 @command('manifest',
4615 [('r', 'rev', '', _('revision to display'), _('REV')),
4615 [('r', 'rev', '', _('revision to display'), _('REV')),
4616 ('', 'all', False, _("list files from all revisions"))]
4616 ('', 'all', False, _("list files from all revisions"))]
4617 + formatteropts,
4617 + formatteropts,
4618 _('[-r REV]'))
4618 _('[-r REV]'))
4619 def manifest(ui, repo, node=None, rev=None, **opts):
4619 def manifest(ui, repo, node=None, rev=None, **opts):
4620 """output the current or given revision of the project manifest
4620 """output the current or given revision of the project manifest
4621
4621
4622 Print a list of version controlled files for the given revision.
4622 Print a list of version controlled files for the given revision.
4623 If no revision is given, the first parent of the working directory
4623 If no revision is given, the first parent of the working directory
4624 is used, or the null revision if no revision is checked out.
4624 is used, or the null revision if no revision is checked out.
4625
4625
4626 With -v, print file permissions, symlink and executable bits.
4626 With -v, print file permissions, symlink and executable bits.
4627 With --debug, print file revision hashes.
4627 With --debug, print file revision hashes.
4628
4628
4629 If option --all is specified, the list of all files from all revisions
4629 If option --all is specified, the list of all files from all revisions
4630 is printed. This includes deleted and renamed files.
4630 is printed. This includes deleted and renamed files.
4631
4631
4632 Returns 0 on success.
4632 Returns 0 on success.
4633 """
4633 """
4634
4634
4635 fm = ui.formatter('manifest', opts)
4635 fm = ui.formatter('manifest', opts)
4636
4636
4637 if opts.get('all'):
4637 if opts.get('all'):
4638 if rev or node:
4638 if rev or node:
4639 raise util.Abort(_("can't specify a revision with --all"))
4639 raise util.Abort(_("can't specify a revision with --all"))
4640
4640
4641 res = []
4641 res = []
4642 prefix = "data/"
4642 prefix = "data/"
4643 suffix = ".i"
4643 suffix = ".i"
4644 plen = len(prefix)
4644 plen = len(prefix)
4645 slen = len(suffix)
4645 slen = len(suffix)
4646 lock = repo.lock()
4646 lock = repo.lock()
4647 try:
4647 try:
4648 for fn, b, size in repo.store.datafiles():
4648 for fn, b, size in repo.store.datafiles():
4649 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4649 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4650 res.append(fn[plen:-slen])
4650 res.append(fn[plen:-slen])
4651 finally:
4651 finally:
4652 lock.release()
4652 lock.release()
4653 for f in res:
4653 for f in res:
4654 fm.startitem()
4654 fm.startitem()
4655 fm.write("path", '%s\n', f)
4655 fm.write("path", '%s\n', f)
4656 fm.end()
4656 fm.end()
4657 return
4657 return
4658
4658
4659 if rev and node:
4659 if rev and node:
4660 raise util.Abort(_("please specify just one revision"))
4660 raise util.Abort(_("please specify just one revision"))
4661
4661
4662 if not node:
4662 if not node:
4663 node = rev
4663 node = rev
4664
4664
4665 char = {'l': '@', 'x': '*', '': ''}
4665 char = {'l': '@', 'x': '*', '': ''}
4666 mode = {'l': '644', 'x': '755', '': '644'}
4666 mode = {'l': '644', 'x': '755', '': '644'}
4667 ctx = scmutil.revsingle(repo, node)
4667 ctx = scmutil.revsingle(repo, node)
4668 mf = ctx.manifest()
4668 mf = ctx.manifest()
4669 for f in ctx:
4669 for f in ctx:
4670 fm.startitem()
4670 fm.startitem()
4671 fl = ctx[f].flags()
4671 fl = ctx[f].flags()
4672 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4672 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4673 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4673 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4674 fm.write('path', '%s\n', f)
4674 fm.write('path', '%s\n', f)
4675 fm.end()
4675 fm.end()
4676
4676
4677 @command('^merge',
4677 @command('^merge',
4678 [('f', 'force', None,
4678 [('f', 'force', None,
4679 _('force a merge including outstanding changes (DEPRECATED)')),
4679 _('force a merge including outstanding changes (DEPRECATED)')),
4680 ('r', 'rev', '', _('revision to merge'), _('REV')),
4680 ('r', 'rev', '', _('revision to merge'), _('REV')),
4681 ('P', 'preview', None,
4681 ('P', 'preview', None,
4682 _('review revisions to merge (no merge is performed)'))
4682 _('review revisions to merge (no merge is performed)'))
4683 ] + mergetoolopts,
4683 ] + mergetoolopts,
4684 _('[-P] [-f] [[-r] REV]'))
4684 _('[-P] [-f] [[-r] REV]'))
4685 def merge(ui, repo, node=None, **opts):
4685 def merge(ui, repo, node=None, **opts):
4686 """merge another revision into working directory
4686 """merge another revision into working directory
4687
4687
4688 The current working directory is updated with all changes made in
4688 The current working directory is updated with all changes made in
4689 the requested revision since the last common predecessor revision.
4689 the requested revision since the last common predecessor revision.
4690
4690
4691 Files that changed between either parent are marked as changed for
4691 Files that changed between either parent are marked as changed for
4692 the next commit and a commit must be performed before any further
4692 the next commit and a commit must be performed before any further
4693 updates to the repository are allowed. The next commit will have
4693 updates to the repository are allowed. The next commit will have
4694 two parents.
4694 two parents.
4695
4695
4696 ``--tool`` can be used to specify the merge tool used for file
4696 ``--tool`` can be used to specify the merge tool used for file
4697 merges. It overrides the HGMERGE environment variable and your
4697 merges. It overrides the HGMERGE environment variable and your
4698 configuration files. See :hg:`help merge-tools` for options.
4698 configuration files. See :hg:`help merge-tools` for options.
4699
4699
4700 If no revision is specified, the working directory's parent is a
4700 If no revision is specified, the working directory's parent is a
4701 head revision, and the current branch contains exactly one other
4701 head revision, and the current branch contains exactly one other
4702 head, the other head is merged with by default. Otherwise, an
4702 head, the other head is merged with by default. Otherwise, an
4703 explicit revision with which to merge with must be provided.
4703 explicit revision with which to merge with must be provided.
4704
4704
4705 :hg:`resolve` must be used to resolve unresolved files.
4705 :hg:`resolve` must be used to resolve unresolved files.
4706
4706
4707 To undo an uncommitted merge, use :hg:`update --clean .` which
4707 To undo an uncommitted merge, use :hg:`update --clean .` which
4708 will check out a clean copy of the original merge parent, losing
4708 will check out a clean copy of the original merge parent, losing
4709 all changes.
4709 all changes.
4710
4710
4711 Returns 0 on success, 1 if there are unresolved files.
4711 Returns 0 on success, 1 if there are unresolved files.
4712 """
4712 """
4713
4713
4714 if opts.get('rev') and node:
4714 if opts.get('rev') and node:
4715 raise util.Abort(_("please specify just one revision"))
4715 raise util.Abort(_("please specify just one revision"))
4716 if not node:
4716 if not node:
4717 node = opts.get('rev')
4717 node = opts.get('rev')
4718
4718
4719 if node:
4719 if node:
4720 node = scmutil.revsingle(repo, node).node()
4720 node = scmutil.revsingle(repo, node).node()
4721
4721
4722 if not node and repo._activebookmark:
4722 if not node and repo._activebookmark:
4723 bmheads = repo.bookmarkheads(repo._activebookmark)
4723 bmheads = repo.bookmarkheads(repo._activebookmark)
4724 curhead = repo[repo._activebookmark].node()
4724 curhead = repo[repo._activebookmark].node()
4725 if len(bmheads) == 2:
4725 if len(bmheads) == 2:
4726 if curhead == bmheads[0]:
4726 if curhead == bmheads[0]:
4727 node = bmheads[1]
4727 node = bmheads[1]
4728 else:
4728 else:
4729 node = bmheads[0]
4729 node = bmheads[0]
4730 elif len(bmheads) > 2:
4730 elif len(bmheads) > 2:
4731 raise util.Abort(_("multiple matching bookmarks to merge - "
4731 raise util.Abort(_("multiple matching bookmarks to merge - "
4732 "please merge with an explicit rev or bookmark"),
4732 "please merge with an explicit rev or bookmark"),
4733 hint=_("run 'hg heads' to see all heads"))
4733 hint=_("run 'hg heads' to see all heads"))
4734 elif len(bmheads) <= 1:
4734 elif len(bmheads) <= 1:
4735 raise util.Abort(_("no matching bookmark to merge - "
4735 raise util.Abort(_("no matching bookmark to merge - "
4736 "please merge with an explicit rev or bookmark"),
4736 "please merge with an explicit rev or bookmark"),
4737 hint=_("run 'hg heads' to see all heads"))
4737 hint=_("run 'hg heads' to see all heads"))
4738
4738
4739 if not node and not repo._activebookmark:
4739 if not node and not repo._activebookmark:
4740 branch = repo[None].branch()
4740 branch = repo[None].branch()
4741 bheads = repo.branchheads(branch)
4741 bheads = repo.branchheads(branch)
4742 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4742 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4743
4743
4744 if len(nbhs) > 2:
4744 if len(nbhs) > 2:
4745 raise util.Abort(_("branch '%s' has %d heads - "
4745 raise util.Abort(_("branch '%s' has %d heads - "
4746 "please merge with an explicit rev")
4746 "please merge with an explicit rev")
4747 % (branch, len(bheads)),
4747 % (branch, len(bheads)),
4748 hint=_("run 'hg heads .' to see heads"))
4748 hint=_("run 'hg heads .' to see heads"))
4749
4749
4750 parent = repo.dirstate.p1()
4750 parent = repo.dirstate.p1()
4751 if len(nbhs) <= 1:
4751 if len(nbhs) <= 1:
4752 if len(bheads) > 1:
4752 if len(bheads) > 1:
4753 raise util.Abort(_("heads are bookmarked - "
4753 raise util.Abort(_("heads are bookmarked - "
4754 "please merge with an explicit rev"),
4754 "please merge with an explicit rev"),
4755 hint=_("run 'hg heads' to see all heads"))
4755 hint=_("run 'hg heads' to see all heads"))
4756 if len(repo.heads()) > 1:
4756 if len(repo.heads()) > 1:
4757 raise util.Abort(_("branch '%s' has one head - "
4757 raise util.Abort(_("branch '%s' has one head - "
4758 "please merge with an explicit rev")
4758 "please merge with an explicit rev")
4759 % branch,
4759 % branch,
4760 hint=_("run 'hg heads' to see all heads"))
4760 hint=_("run 'hg heads' to see all heads"))
4761 msg, hint = _('nothing to merge'), None
4761 msg, hint = _('nothing to merge'), None
4762 if parent != repo.lookup(branch):
4762 if parent != repo.lookup(branch):
4763 hint = _("use 'hg update' instead")
4763 hint = _("use 'hg update' instead")
4764 raise util.Abort(msg, hint=hint)
4764 raise util.Abort(msg, hint=hint)
4765
4765
4766 if parent not in bheads:
4766 if parent not in bheads:
4767 raise util.Abort(_('working directory not at a head revision'),
4767 raise util.Abort(_('working directory not at a head revision'),
4768 hint=_("use 'hg update' or merge with an "
4768 hint=_("use 'hg update' or merge with an "
4769 "explicit revision"))
4769 "explicit revision"))
4770 if parent == nbhs[0]:
4770 if parent == nbhs[0]:
4771 node = nbhs[-1]
4771 node = nbhs[-1]
4772 else:
4772 else:
4773 node = nbhs[0]
4773 node = nbhs[0]
4774
4774
4775 if opts.get('preview'):
4775 if opts.get('preview'):
4776 # find nodes that are ancestors of p2 but not of p1
4776 # find nodes that are ancestors of p2 but not of p1
4777 p1 = repo.lookup('.')
4777 p1 = repo.lookup('.')
4778 p2 = repo.lookup(node)
4778 p2 = repo.lookup(node)
4779 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4779 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4780
4780
4781 displayer = cmdutil.show_changeset(ui, repo, opts)
4781 displayer = cmdutil.show_changeset(ui, repo, opts)
4782 for node in nodes:
4782 for node in nodes:
4783 displayer.show(repo[node])
4783 displayer.show(repo[node])
4784 displayer.close()
4784 displayer.close()
4785 return 0
4785 return 0
4786
4786
4787 try:
4787 try:
4788 # ui.forcemerge is an internal variable, do not document
4788 # ui.forcemerge is an internal variable, do not document
4789 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4789 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4790 return hg.merge(repo, node, force=opts.get('force'))
4790 return hg.merge(repo, node, force=opts.get('force'))
4791 finally:
4791 finally:
4792 ui.setconfig('ui', 'forcemerge', '', 'merge')
4792 ui.setconfig('ui', 'forcemerge', '', 'merge')
4793
4793
4794 @command('outgoing|out',
4794 @command('outgoing|out',
4795 [('f', 'force', None, _('run even when the destination is unrelated')),
4795 [('f', 'force', None, _('run even when the destination is unrelated')),
4796 ('r', 'rev', [],
4796 ('r', 'rev', [],
4797 _('a changeset intended to be included in the destination'), _('REV')),
4797 _('a changeset intended to be included in the destination'), _('REV')),
4798 ('n', 'newest-first', None, _('show newest record first')),
4798 ('n', 'newest-first', None, _('show newest record first')),
4799 ('B', 'bookmarks', False, _('compare bookmarks')),
4799 ('B', 'bookmarks', False, _('compare bookmarks')),
4800 ('b', 'branch', [], _('a specific branch you would like to push'),
4800 ('b', 'branch', [], _('a specific branch you would like to push'),
4801 _('BRANCH')),
4801 _('BRANCH')),
4802 ] + logopts + remoteopts + subrepoopts,
4802 ] + logopts + remoteopts + subrepoopts,
4803 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4803 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4804 def outgoing(ui, repo, dest=None, **opts):
4804 def outgoing(ui, repo, dest=None, **opts):
4805 """show changesets not found in the destination
4805 """show changesets not found in the destination
4806
4806
4807 Show changesets not found in the specified destination repository
4807 Show changesets not found in the specified destination repository
4808 or the default push location. These are the changesets that would
4808 or the default push location. These are the changesets that would
4809 be pushed if a push was requested.
4809 be pushed if a push was requested.
4810
4810
4811 See pull for details of valid destination formats.
4811 See pull for details of valid destination formats.
4812
4812
4813 .. container:: verbose
4813 .. container:: verbose
4814
4814
4815 With -B/--bookmarks, the result of bookmark comparison between
4815 With -B/--bookmarks, the result of bookmark comparison between
4816 local and remote repositories is displayed. With -v/--verbose,
4816 local and remote repositories is displayed. With -v/--verbose,
4817 status is also displayed for each bookmark like below::
4817 status is also displayed for each bookmark like below::
4818
4818
4819 BM1 01234567890a added
4819 BM1 01234567890a added
4820 BM2 deleted
4820 BM2 deleted
4821 BM3 234567890abc advanced
4821 BM3 234567890abc advanced
4822 BM4 34567890abcd diverged
4822 BM4 34567890abcd diverged
4823 BM5 4567890abcde changed
4823 BM5 4567890abcde changed
4824
4824
4825 The action taken when pushing depends on the
4825 The action taken when pushing depends on the
4826 status of each bookmark:
4826 status of each bookmark:
4827
4827
4828 :``added``: push with ``-B`` will create it
4828 :``added``: push with ``-B`` will create it
4829 :``deleted``: push with ``-B`` will delete it
4829 :``deleted``: push with ``-B`` will delete it
4830 :``advanced``: push will update it
4830 :``advanced``: push will update it
4831 :``diverged``: push with ``-B`` will update it
4831 :``diverged``: push with ``-B`` will update it
4832 :``changed``: push with ``-B`` will update it
4832 :``changed``: push with ``-B`` will update it
4833
4833
4834 From the point of view of pushing behavior, bookmarks
4834 From the point of view of pushing behavior, bookmarks
4835 existing only in the remote repository are treated as
4835 existing only in the remote repository are treated as
4836 ``deleted``, even if it is in fact added remotely.
4836 ``deleted``, even if it is in fact added remotely.
4837
4837
4838 Returns 0 if there are outgoing changes, 1 otherwise.
4838 Returns 0 if there are outgoing changes, 1 otherwise.
4839 """
4839 """
4840 if opts.get('graph'):
4840 if opts.get('graph'):
4841 cmdutil.checkunsupportedgraphflags([], opts)
4841 cmdutil.checkunsupportedgraphflags([], opts)
4842 o, other = hg._outgoing(ui, repo, dest, opts)
4842 o, other = hg._outgoing(ui, repo, dest, opts)
4843 if not o:
4843 if not o:
4844 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4844 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4845 return
4845 return
4846
4846
4847 revdag = cmdutil.graphrevs(repo, o, opts)
4847 revdag = cmdutil.graphrevs(repo, o, opts)
4848 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4848 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4849 showparents = [ctx.node() for ctx in repo[None].parents()]
4849 showparents = [ctx.node() for ctx in repo[None].parents()]
4850 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4850 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4851 graphmod.asciiedges)
4851 graphmod.asciiedges)
4852 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4852 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4853 return 0
4853 return 0
4854
4854
4855 if opts.get('bookmarks'):
4855 if opts.get('bookmarks'):
4856 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4856 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4857 dest, branches = hg.parseurl(dest, opts.get('branch'))
4857 dest, branches = hg.parseurl(dest, opts.get('branch'))
4858 other = hg.peer(repo, opts, dest)
4858 other = hg.peer(repo, opts, dest)
4859 if 'bookmarks' not in other.listkeys('namespaces'):
4859 if 'bookmarks' not in other.listkeys('namespaces'):
4860 ui.warn(_("remote doesn't support bookmarks\n"))
4860 ui.warn(_("remote doesn't support bookmarks\n"))
4861 return 0
4861 return 0
4862 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4862 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4863 return bookmarks.outgoing(ui, repo, other)
4863 return bookmarks.outgoing(ui, repo, other)
4864
4864
4865 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4865 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4866 try:
4866 try:
4867 return hg.outgoing(ui, repo, dest, opts)
4867 return hg.outgoing(ui, repo, dest, opts)
4868 finally:
4868 finally:
4869 del repo._subtoppath
4869 del repo._subtoppath
4870
4870
4871 @command('parents',
4871 @command('parents',
4872 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4872 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4873 ] + templateopts,
4873 ] + templateopts,
4874 _('[-r REV] [FILE]'),
4874 _('[-r REV] [FILE]'),
4875 inferrepo=True)
4875 inferrepo=True)
4876 def parents(ui, repo, file_=None, **opts):
4876 def parents(ui, repo, file_=None, **opts):
4877 """show the parents of the working directory or revision (DEPRECATED)
4877 """show the parents of the working directory or revision (DEPRECATED)
4878
4878
4879 Print the working directory's parent revisions. If a revision is
4879 Print the working directory's parent revisions. If a revision is
4880 given via -r/--rev, the parent of that revision will be printed.
4880 given via -r/--rev, the parent of that revision will be printed.
4881 If a file argument is given, the revision in which the file was
4881 If a file argument is given, the revision in which the file was
4882 last changed (before the working directory revision or the
4882 last changed (before the working directory revision or the
4883 argument to --rev if given) is printed.
4883 argument to --rev if given) is printed.
4884
4884
4885 See :hg:`summary` and :hg:`help revsets` for related information.
4885 See :hg:`summary` and :hg:`help revsets` for related information.
4886
4886
4887 Returns 0 on success.
4887 Returns 0 on success.
4888 """
4888 """
4889
4889
4890 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4890 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4891
4891
4892 if file_:
4892 if file_:
4893 m = scmutil.match(ctx, (file_,), opts)
4893 m = scmutil.match(ctx, (file_,), opts)
4894 if m.anypats() or len(m.files()) != 1:
4894 if m.anypats() or len(m.files()) != 1:
4895 raise util.Abort(_('can only specify an explicit filename'))
4895 raise util.Abort(_('can only specify an explicit filename'))
4896 file_ = m.files()[0]
4896 file_ = m.files()[0]
4897 filenodes = []
4897 filenodes = []
4898 for cp in ctx.parents():
4898 for cp in ctx.parents():
4899 if not cp:
4899 if not cp:
4900 continue
4900 continue
4901 try:
4901 try:
4902 filenodes.append(cp.filenode(file_))
4902 filenodes.append(cp.filenode(file_))
4903 except error.LookupError:
4903 except error.LookupError:
4904 pass
4904 pass
4905 if not filenodes:
4905 if not filenodes:
4906 raise util.Abort(_("'%s' not found in manifest!") % file_)
4906 raise util.Abort(_("'%s' not found in manifest!") % file_)
4907 p = []
4907 p = []
4908 for fn in filenodes:
4908 for fn in filenodes:
4909 fctx = repo.filectx(file_, fileid=fn)
4909 fctx = repo.filectx(file_, fileid=fn)
4910 p.append(fctx.node())
4910 p.append(fctx.node())
4911 else:
4911 else:
4912 p = [cp.node() for cp in ctx.parents()]
4912 p = [cp.node() for cp in ctx.parents()]
4913
4913
4914 displayer = cmdutil.show_changeset(ui, repo, opts)
4914 displayer = cmdutil.show_changeset(ui, repo, opts)
4915 for n in p:
4915 for n in p:
4916 if n != nullid:
4916 if n != nullid:
4917 displayer.show(repo[n])
4917 displayer.show(repo[n])
4918 displayer.close()
4918 displayer.close()
4919
4919
4920 @command('paths', [], _('[NAME]'), optionalrepo=True)
4920 @command('paths', [], _('[NAME]'), optionalrepo=True)
4921 def paths(ui, repo, search=None):
4921 def paths(ui, repo, search=None):
4922 """show aliases for remote repositories
4922 """show aliases for remote repositories
4923
4923
4924 Show definition of symbolic path name NAME. If no name is given,
4924 Show definition of symbolic path name NAME. If no name is given,
4925 show definition of all available names.
4925 show definition of all available names.
4926
4926
4927 Option -q/--quiet suppresses all output when searching for NAME
4927 Option -q/--quiet suppresses all output when searching for NAME
4928 and shows only the path names when listing all definitions.
4928 and shows only the path names when listing all definitions.
4929
4929
4930 Path names are defined in the [paths] section of your
4930 Path names are defined in the [paths] section of your
4931 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4931 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4932 repository, ``.hg/hgrc`` is used, too.
4932 repository, ``.hg/hgrc`` is used, too.
4933
4933
4934 The path names ``default`` and ``default-push`` have a special
4934 The path names ``default`` and ``default-push`` have a special
4935 meaning. When performing a push or pull operation, they are used
4935 meaning. When performing a push or pull operation, they are used
4936 as fallbacks if no location is specified on the command-line.
4936 as fallbacks if no location is specified on the command-line.
4937 When ``default-push`` is set, it will be used for push and
4937 When ``default-push`` is set, it will be used for push and
4938 ``default`` will be used for pull; otherwise ``default`` is used
4938 ``default`` will be used for pull; otherwise ``default`` is used
4939 as the fallback for both. When cloning a repository, the clone
4939 as the fallback for both. When cloning a repository, the clone
4940 source is written as ``default`` in ``.hg/hgrc``. Note that
4940 source is written as ``default`` in ``.hg/hgrc``. Note that
4941 ``default`` and ``default-push`` apply to all inbound (e.g.
4941 ``default`` and ``default-push`` apply to all inbound (e.g.
4942 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4942 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4943 :hg:`bundle`) operations.
4943 :hg:`bundle`) operations.
4944
4944
4945 See :hg:`help urls` for more information.
4945 See :hg:`help urls` for more information.
4946
4946
4947 Returns 0 on success.
4947 Returns 0 on success.
4948 """
4948 """
4949 if search:
4949 if search:
4950 for name, path in sorted(ui.paths.iteritems()):
4950 for name, path in sorted(ui.paths.iteritems()):
4951 if name == search:
4951 if name == search:
4952 ui.status("%s\n" % util.hidepassword(path.loc))
4952 ui.status("%s\n" % util.hidepassword(path.loc))
4953 return
4953 return
4954 if not ui.quiet:
4954 if not ui.quiet:
4955 ui.warn(_("not found!\n"))
4955 ui.warn(_("not found!\n"))
4956 return 1
4956 return 1
4957 else:
4957 else:
4958 for name, path in sorted(ui.paths.iteritems()):
4958 for name, path in sorted(ui.paths.iteritems()):
4959 if ui.quiet:
4959 if ui.quiet:
4960 ui.write("%s\n" % name)
4960 ui.write("%s\n" % name)
4961 else:
4961 else:
4962 ui.write("%s = %s\n" % (name,
4962 ui.write("%s = %s\n" % (name,
4963 util.hidepassword(path.loc)))
4963 util.hidepassword(path.loc)))
4964
4964
4965 @command('phase',
4965 @command('phase',
4966 [('p', 'public', False, _('set changeset phase to public')),
4966 [('p', 'public', False, _('set changeset phase to public')),
4967 ('d', 'draft', False, _('set changeset phase to draft')),
4967 ('d', 'draft', False, _('set changeset phase to draft')),
4968 ('s', 'secret', False, _('set changeset phase to secret')),
4968 ('s', 'secret', False, _('set changeset phase to secret')),
4969 ('f', 'force', False, _('allow to move boundary backward')),
4969 ('f', 'force', False, _('allow to move boundary backward')),
4970 ('r', 'rev', [], _('target revision'), _('REV')),
4970 ('r', 'rev', [], _('target revision'), _('REV')),
4971 ],
4971 ],
4972 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4972 _('[-p|-d|-s] [-f] [-r] [REV...]'))
4973 def phase(ui, repo, *revs, **opts):
4973 def phase(ui, repo, *revs, **opts):
4974 """set or show the current phase name
4974 """set or show the current phase name
4975
4975
4976 With no argument, show the phase name of the current revision(s).
4976 With no argument, show the phase name of the current revision(s).
4977
4977
4978 With one of -p/--public, -d/--draft or -s/--secret, change the
4978 With one of -p/--public, -d/--draft or -s/--secret, change the
4979 phase value of the specified revisions.
4979 phase value of the specified revisions.
4980
4980
4981 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4981 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4982 lower phase to an higher phase. Phases are ordered as follows::
4982 lower phase to an higher phase. Phases are ordered as follows::
4983
4983
4984 public < draft < secret
4984 public < draft < secret
4985
4985
4986 Returns 0 on success, 1 if no phases were changed or some could not
4986 Returns 0 on success, 1 if no phases were changed or some could not
4987 be changed.
4987 be changed.
4988 """
4988 """
4989 # search for a unique phase argument
4989 # search for a unique phase argument
4990 targetphase = None
4990 targetphase = None
4991 for idx, name in enumerate(phases.phasenames):
4991 for idx, name in enumerate(phases.phasenames):
4992 if opts[name]:
4992 if opts[name]:
4993 if targetphase is not None:
4993 if targetphase is not None:
4994 raise util.Abort(_('only one phase can be specified'))
4994 raise util.Abort(_('only one phase can be specified'))
4995 targetphase = idx
4995 targetphase = idx
4996
4996
4997 # look for specified revision
4997 # look for specified revision
4998 revs = list(revs)
4998 revs = list(revs)
4999 revs.extend(opts['rev'])
4999 revs.extend(opts['rev'])
5000 if not revs:
5000 if not revs:
5001 # display both parents as the second parent phase can influence
5001 # display both parents as the second parent phase can influence
5002 # the phase of a merge commit
5002 # the phase of a merge commit
5003 revs = [c.rev() for c in repo[None].parents()]
5003 revs = [c.rev() for c in repo[None].parents()]
5004
5004
5005 revs = scmutil.revrange(repo, revs)
5005 revs = scmutil.revrange(repo, revs)
5006
5006
5007 lock = None
5007 lock = None
5008 ret = 0
5008 ret = 0
5009 if targetphase is None:
5009 if targetphase is None:
5010 # display
5010 # display
5011 for r in revs:
5011 for r in revs:
5012 ctx = repo[r]
5012 ctx = repo[r]
5013 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5013 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5014 else:
5014 else:
5015 tr = None
5015 tr = None
5016 lock = repo.lock()
5016 lock = repo.lock()
5017 try:
5017 try:
5018 tr = repo.transaction("phase")
5018 tr = repo.transaction("phase")
5019 # set phase
5019 # set phase
5020 if not revs:
5020 if not revs:
5021 raise util.Abort(_('empty revision set'))
5021 raise util.Abort(_('empty revision set'))
5022 nodes = [repo[r].node() for r in revs]
5022 nodes = [repo[r].node() for r in revs]
5023 # moving revision from public to draft may hide them
5023 # moving revision from public to draft may hide them
5024 # We have to check result on an unfiltered repository
5024 # We have to check result on an unfiltered repository
5025 unfi = repo.unfiltered()
5025 unfi = repo.unfiltered()
5026 getphase = unfi._phasecache.phase
5026 getphase = unfi._phasecache.phase
5027 olddata = [getphase(unfi, r) for r in unfi]
5027 olddata = [getphase(unfi, r) for r in unfi]
5028 phases.advanceboundary(repo, tr, targetphase, nodes)
5028 phases.advanceboundary(repo, tr, targetphase, nodes)
5029 if opts['force']:
5029 if opts['force']:
5030 phases.retractboundary(repo, tr, targetphase, nodes)
5030 phases.retractboundary(repo, tr, targetphase, nodes)
5031 tr.close()
5031 tr.close()
5032 finally:
5032 finally:
5033 if tr is not None:
5033 if tr is not None:
5034 tr.release()
5034 tr.release()
5035 lock.release()
5035 lock.release()
5036 getphase = unfi._phasecache.phase
5036 getphase = unfi._phasecache.phase
5037 newdata = [getphase(unfi, r) for r in unfi]
5037 newdata = [getphase(unfi, r) for r in unfi]
5038 changes = sum(newdata[r] != olddata[r] for r in unfi)
5038 changes = sum(newdata[r] != olddata[r] for r in unfi)
5039 cl = unfi.changelog
5039 cl = unfi.changelog
5040 rejected = [n for n in nodes
5040 rejected = [n for n in nodes
5041 if newdata[cl.rev(n)] < targetphase]
5041 if newdata[cl.rev(n)] < targetphase]
5042 if rejected:
5042 if rejected:
5043 ui.warn(_('cannot move %i changesets to a higher '
5043 ui.warn(_('cannot move %i changesets to a higher '
5044 'phase, use --force\n') % len(rejected))
5044 'phase, use --force\n') % len(rejected))
5045 ret = 1
5045 ret = 1
5046 if changes:
5046 if changes:
5047 msg = _('phase changed for %i changesets\n') % changes
5047 msg = _('phase changed for %i changesets\n') % changes
5048 if ret:
5048 if ret:
5049 ui.status(msg)
5049 ui.status(msg)
5050 else:
5050 else:
5051 ui.note(msg)
5051 ui.note(msg)
5052 else:
5052 else:
5053 ui.warn(_('no phases changed\n'))
5053 ui.warn(_('no phases changed\n'))
5054 ret = 1
5054 ret = 1
5055 return ret
5055 return ret
5056
5056
5057 def postincoming(ui, repo, modheads, optupdate, checkout):
5057 def postincoming(ui, repo, modheads, optupdate, checkout):
5058 if modheads == 0:
5058 if modheads == 0:
5059 return
5059 return
5060 if optupdate:
5060 if optupdate:
5061 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5061 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
5062 try:
5062 try:
5063 ret = hg.update(repo, checkout)
5063 ret = hg.update(repo, checkout)
5064 except util.Abort, inst:
5064 except util.Abort, inst:
5065 ui.warn(_("not updating: %s\n") % str(inst))
5065 ui.warn(_("not updating: %s\n") % str(inst))
5066 if inst.hint:
5066 if inst.hint:
5067 ui.warn(_("(%s)\n") % inst.hint)
5067 ui.warn(_("(%s)\n") % inst.hint)
5068 return 0
5068 return 0
5069 if not ret and not checkout:
5069 if not ret and not checkout:
5070 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5070 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5071 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5071 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5072 return ret
5072 return ret
5073 if modheads > 1:
5073 if modheads > 1:
5074 currentbranchheads = len(repo.branchheads())
5074 currentbranchheads = len(repo.branchheads())
5075 if currentbranchheads == modheads:
5075 if currentbranchheads == modheads:
5076 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5076 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5077 elif currentbranchheads > 1:
5077 elif currentbranchheads > 1:
5078 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5078 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5079 "merge)\n"))
5079 "merge)\n"))
5080 else:
5080 else:
5081 ui.status(_("(run 'hg heads' to see heads)\n"))
5081 ui.status(_("(run 'hg heads' to see heads)\n"))
5082 else:
5082 else:
5083 ui.status(_("(run 'hg update' to get a working copy)\n"))
5083 ui.status(_("(run 'hg update' to get a working copy)\n"))
5084
5084
5085 @command('^pull',
5085 @command('^pull',
5086 [('u', 'update', None,
5086 [('u', 'update', None,
5087 _('update to new branch head if changesets were pulled')),
5087 _('update to new branch head if changesets were pulled')),
5088 ('f', 'force', None, _('run even when remote repository is unrelated')),
5088 ('f', 'force', None, _('run even when remote repository is unrelated')),
5089 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5089 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5090 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5090 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5091 ('b', 'branch', [], _('a specific branch you would like to pull'),
5091 ('b', 'branch', [], _('a specific branch you would like to pull'),
5092 _('BRANCH')),
5092 _('BRANCH')),
5093 ] + remoteopts,
5093 ] + remoteopts,
5094 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5094 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5095 def pull(ui, repo, source="default", **opts):
5095 def pull(ui, repo, source="default", **opts):
5096 """pull changes from the specified source
5096 """pull changes from the specified source
5097
5097
5098 Pull changes from a remote repository to a local one.
5098 Pull changes from a remote repository to a local one.
5099
5099
5100 This finds all changes from the repository at the specified path
5100 This finds all changes from the repository at the specified path
5101 or URL and adds them to a local repository (the current one unless
5101 or URL and adds them to a local repository (the current one unless
5102 -R is specified). By default, this does not update the copy of the
5102 -R is specified). By default, this does not update the copy of the
5103 project in the working directory.
5103 project in the working directory.
5104
5104
5105 Use :hg:`incoming` if you want to see what would have been added
5105 Use :hg:`incoming` if you want to see what would have been added
5106 by a pull at the time you issued this command. If you then decide
5106 by a pull at the time you issued this command. If you then decide
5107 to add those changes to the repository, you should use :hg:`pull
5107 to add those changes to the repository, you should use :hg:`pull
5108 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5108 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5109
5109
5110 If SOURCE is omitted, the 'default' path will be used.
5110 If SOURCE is omitted, the 'default' path will be used.
5111 See :hg:`help urls` for more information.
5111 See :hg:`help urls` for more information.
5112
5112
5113 Returns 0 on success, 1 if an update had unresolved files.
5113 Returns 0 on success, 1 if an update had unresolved files.
5114 """
5114 """
5115 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5115 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5116 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5116 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5117 other = hg.peer(repo, opts, source)
5117 other = hg.peer(repo, opts, source)
5118 try:
5118 try:
5119 revs, checkout = hg.addbranchrevs(repo, other, branches,
5119 revs, checkout = hg.addbranchrevs(repo, other, branches,
5120 opts.get('rev'))
5120 opts.get('rev'))
5121
5121
5122
5122
5123 if opts.get('bookmark'):
5123 if opts.get('bookmark'):
5124 if not revs:
5124 if not revs:
5125 revs = []
5125 revs = []
5126 # The list of bookmark used here is not the one used to actually
5126 # The list of bookmark used here is not the one used to actually
5127 # update the bookmark name. This can result in the revision pulled
5127 # update the bookmark name. This can result in the revision pulled
5128 # not ending up with the name of the bookmark because of a race
5128 # not ending up with the name of the bookmark because of a race
5129 # condition on the server. (See issue 4689 for details)
5129 # condition on the server. (See issue 4689 for details)
5130 remotebookmarks = other.listkeys('bookmarks')
5130 remotebookmarks = other.listkeys('bookmarks')
5131 for b in opts['bookmark']:
5131 for b in opts['bookmark']:
5132 if b not in remotebookmarks:
5132 if b not in remotebookmarks:
5133 raise util.Abort(_('remote bookmark %s not found!') % b)
5133 raise util.Abort(_('remote bookmark %s not found!') % b)
5134 revs.append(remotebookmarks[b])
5134 revs.append(remotebookmarks[b])
5135
5135
5136 if revs:
5136 if revs:
5137 try:
5137 try:
5138 # When 'rev' is a bookmark name, we cannot guarantee that it
5138 # When 'rev' is a bookmark name, we cannot guarantee that it
5139 # will be updated with that name because of a race condition
5139 # will be updated with that name because of a race condition
5140 # server side. (See issue 4689 for details)
5140 # server side. (See issue 4689 for details)
5141 revs = [other.lookup(rev) for rev in revs]
5141 oldrevs = revs
5142 revs = [] # actually, nodes
5143 for r in oldrevs:
5144 node = other.lookup(r)
5145 revs.append(node)
5146 if r == checkout:
5147 checkout = node
5142 except error.CapabilityError:
5148 except error.CapabilityError:
5143 err = _("other repository doesn't support revision lookup, "
5149 err = _("other repository doesn't support revision lookup, "
5144 "so a rev cannot be specified.")
5150 "so a rev cannot be specified.")
5145 raise util.Abort(err)
5151 raise util.Abort(err)
5146
5152
5147 modheads = exchange.pull(repo, other, heads=revs,
5153 modheads = exchange.pull(repo, other, heads=revs,
5148 force=opts.get('force'),
5154 force=opts.get('force'),
5149 bookmarks=opts.get('bookmark', ())).cgresult
5155 bookmarks=opts.get('bookmark', ())).cgresult
5150 if checkout:
5156 if checkout:
5151 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5157 checkout = str(repo.changelog.rev(checkout))
5152 repo._subtoppath = source
5158 repo._subtoppath = source
5153 try:
5159 try:
5154 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5160 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5155
5161
5156 finally:
5162 finally:
5157 del repo._subtoppath
5163 del repo._subtoppath
5158
5164
5159 finally:
5165 finally:
5160 other.close()
5166 other.close()
5161 return ret
5167 return ret
5162
5168
5163 @command('^push',
5169 @command('^push',
5164 [('f', 'force', None, _('force push')),
5170 [('f', 'force', None, _('force push')),
5165 ('r', 'rev', [],
5171 ('r', 'rev', [],
5166 _('a changeset intended to be included in the destination'),
5172 _('a changeset intended to be included in the destination'),
5167 _('REV')),
5173 _('REV')),
5168 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5174 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5169 ('b', 'branch', [],
5175 ('b', 'branch', [],
5170 _('a specific branch you would like to push'), _('BRANCH')),
5176 _('a specific branch you would like to push'), _('BRANCH')),
5171 ('', 'new-branch', False, _('allow pushing a new branch')),
5177 ('', 'new-branch', False, _('allow pushing a new branch')),
5172 ] + remoteopts,
5178 ] + remoteopts,
5173 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5179 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5174 def push(ui, repo, dest=None, **opts):
5180 def push(ui, repo, dest=None, **opts):
5175 """push changes to the specified destination
5181 """push changes to the specified destination
5176
5182
5177 Push changesets from the local repository to the specified
5183 Push changesets from the local repository to the specified
5178 destination.
5184 destination.
5179
5185
5180 This operation is symmetrical to pull: it is identical to a pull
5186 This operation is symmetrical to pull: it is identical to a pull
5181 in the destination repository from the current one.
5187 in the destination repository from the current one.
5182
5188
5183 By default, push will not allow creation of new heads at the
5189 By default, push will not allow creation of new heads at the
5184 destination, since multiple heads would make it unclear which head
5190 destination, since multiple heads would make it unclear which head
5185 to use. In this situation, it is recommended to pull and merge
5191 to use. In this situation, it is recommended to pull and merge
5186 before pushing.
5192 before pushing.
5187
5193
5188 Use --new-branch if you want to allow push to create a new named
5194 Use --new-branch if you want to allow push to create a new named
5189 branch that is not present at the destination. This allows you to
5195 branch that is not present at the destination. This allows you to
5190 only create a new branch without forcing other changes.
5196 only create a new branch without forcing other changes.
5191
5197
5192 .. note::
5198 .. note::
5193
5199
5194 Extra care should be taken with the -f/--force option,
5200 Extra care should be taken with the -f/--force option,
5195 which will push all new heads on all branches, an action which will
5201 which will push all new heads on all branches, an action which will
5196 almost always cause confusion for collaborators.
5202 almost always cause confusion for collaborators.
5197
5203
5198 If -r/--rev is used, the specified revision and all its ancestors
5204 If -r/--rev is used, the specified revision and all its ancestors
5199 will be pushed to the remote repository.
5205 will be pushed to the remote repository.
5200
5206
5201 If -B/--bookmark is used, the specified bookmarked revision, its
5207 If -B/--bookmark is used, the specified bookmarked revision, its
5202 ancestors, and the bookmark will be pushed to the remote
5208 ancestors, and the bookmark will be pushed to the remote
5203 repository.
5209 repository.
5204
5210
5205 Please see :hg:`help urls` for important details about ``ssh://``
5211 Please see :hg:`help urls` for important details about ``ssh://``
5206 URLs. If DESTINATION is omitted, a default path will be used.
5212 URLs. If DESTINATION is omitted, a default path will be used.
5207
5213
5208 Returns 0 if push was successful, 1 if nothing to push.
5214 Returns 0 if push was successful, 1 if nothing to push.
5209 """
5215 """
5210
5216
5211 if opts.get('bookmark'):
5217 if opts.get('bookmark'):
5212 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5218 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5213 for b in opts['bookmark']:
5219 for b in opts['bookmark']:
5214 # translate -B options to -r so changesets get pushed
5220 # translate -B options to -r so changesets get pushed
5215 if b in repo._bookmarks:
5221 if b in repo._bookmarks:
5216 opts.setdefault('rev', []).append(b)
5222 opts.setdefault('rev', []).append(b)
5217 else:
5223 else:
5218 # if we try to push a deleted bookmark, translate it to null
5224 # if we try to push a deleted bookmark, translate it to null
5219 # this lets simultaneous -r, -b options continue working
5225 # this lets simultaneous -r, -b options continue working
5220 opts.setdefault('rev', []).append("null")
5226 opts.setdefault('rev', []).append("null")
5221
5227
5222 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5228 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5223 dest, branches = hg.parseurl(dest, opts.get('branch'))
5229 dest, branches = hg.parseurl(dest, opts.get('branch'))
5224 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5230 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5225 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5231 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5226 try:
5232 try:
5227 other = hg.peer(repo, opts, dest)
5233 other = hg.peer(repo, opts, dest)
5228 except error.RepoError:
5234 except error.RepoError:
5229 if dest == "default-push":
5235 if dest == "default-push":
5230 raise util.Abort(_("default repository not configured!"),
5236 raise util.Abort(_("default repository not configured!"),
5231 hint=_('see the "path" section in "hg help config"'))
5237 hint=_('see the "path" section in "hg help config"'))
5232 else:
5238 else:
5233 raise
5239 raise
5234
5240
5235 if revs:
5241 if revs:
5236 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5242 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5237 if not revs:
5243 if not revs:
5238 raise util.Abort(_("specified revisions evaluate to an empty set"),
5244 raise util.Abort(_("specified revisions evaluate to an empty set"),
5239 hint=_("use different revision arguments"))
5245 hint=_("use different revision arguments"))
5240
5246
5241 repo._subtoppath = dest
5247 repo._subtoppath = dest
5242 try:
5248 try:
5243 # push subrepos depth-first for coherent ordering
5249 # push subrepos depth-first for coherent ordering
5244 c = repo['']
5250 c = repo['']
5245 subs = c.substate # only repos that are committed
5251 subs = c.substate # only repos that are committed
5246 for s in sorted(subs):
5252 for s in sorted(subs):
5247 result = c.sub(s).push(opts)
5253 result = c.sub(s).push(opts)
5248 if result == 0:
5254 if result == 0:
5249 return not result
5255 return not result
5250 finally:
5256 finally:
5251 del repo._subtoppath
5257 del repo._subtoppath
5252 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5258 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5253 newbranch=opts.get('new_branch'),
5259 newbranch=opts.get('new_branch'),
5254 bookmarks=opts.get('bookmark', ()))
5260 bookmarks=opts.get('bookmark', ()))
5255
5261
5256 result = not pushop.cgresult
5262 result = not pushop.cgresult
5257
5263
5258 if pushop.bkresult is not None:
5264 if pushop.bkresult is not None:
5259 if pushop.bkresult == 2:
5265 if pushop.bkresult == 2:
5260 result = 2
5266 result = 2
5261 elif not result and pushop.bkresult:
5267 elif not result and pushop.bkresult:
5262 result = 2
5268 result = 2
5263
5269
5264 return result
5270 return result
5265
5271
5266 @command('recover', [])
5272 @command('recover', [])
5267 def recover(ui, repo):
5273 def recover(ui, repo):
5268 """roll back an interrupted transaction
5274 """roll back an interrupted transaction
5269
5275
5270 Recover from an interrupted commit or pull.
5276 Recover from an interrupted commit or pull.
5271
5277
5272 This command tries to fix the repository status after an
5278 This command tries to fix the repository status after an
5273 interrupted operation. It should only be necessary when Mercurial
5279 interrupted operation. It should only be necessary when Mercurial
5274 suggests it.
5280 suggests it.
5275
5281
5276 Returns 0 if successful, 1 if nothing to recover or verify fails.
5282 Returns 0 if successful, 1 if nothing to recover or verify fails.
5277 """
5283 """
5278 if repo.recover():
5284 if repo.recover():
5279 return hg.verify(repo)
5285 return hg.verify(repo)
5280 return 1
5286 return 1
5281
5287
5282 @command('^remove|rm',
5288 @command('^remove|rm',
5283 [('A', 'after', None, _('record delete for missing files')),
5289 [('A', 'after', None, _('record delete for missing files')),
5284 ('f', 'force', None,
5290 ('f', 'force', None,
5285 _('remove (and delete) file even if added or modified')),
5291 _('remove (and delete) file even if added or modified')),
5286 ] + subrepoopts + walkopts,
5292 ] + subrepoopts + walkopts,
5287 _('[OPTION]... FILE...'),
5293 _('[OPTION]... FILE...'),
5288 inferrepo=True)
5294 inferrepo=True)
5289 def remove(ui, repo, *pats, **opts):
5295 def remove(ui, repo, *pats, **opts):
5290 """remove the specified files on the next commit
5296 """remove the specified files on the next commit
5291
5297
5292 Schedule the indicated files for removal from the current branch.
5298 Schedule the indicated files for removal from the current branch.
5293
5299
5294 This command schedules the files to be removed at the next commit.
5300 This command schedules the files to be removed at the next commit.
5295 To undo a remove before that, see :hg:`revert`. To undo added
5301 To undo a remove before that, see :hg:`revert`. To undo added
5296 files, see :hg:`forget`.
5302 files, see :hg:`forget`.
5297
5303
5298 .. container:: verbose
5304 .. container:: verbose
5299
5305
5300 -A/--after can be used to remove only files that have already
5306 -A/--after can be used to remove only files that have already
5301 been deleted, -f/--force can be used to force deletion, and -Af
5307 been deleted, -f/--force can be used to force deletion, and -Af
5302 can be used to remove files from the next revision without
5308 can be used to remove files from the next revision without
5303 deleting them from the working directory.
5309 deleting them from the working directory.
5304
5310
5305 The following table details the behavior of remove for different
5311 The following table details the behavior of remove for different
5306 file states (columns) and option combinations (rows). The file
5312 file states (columns) and option combinations (rows). The file
5307 states are Added [A], Clean [C], Modified [M] and Missing [!]
5313 states are Added [A], Clean [C], Modified [M] and Missing [!]
5308 (as reported by :hg:`status`). The actions are Warn, Remove
5314 (as reported by :hg:`status`). The actions are Warn, Remove
5309 (from branch) and Delete (from disk):
5315 (from branch) and Delete (from disk):
5310
5316
5311 ========= == == == ==
5317 ========= == == == ==
5312 opt/state A C M !
5318 opt/state A C M !
5313 ========= == == == ==
5319 ========= == == == ==
5314 none W RD W R
5320 none W RD W R
5315 -f R RD RD R
5321 -f R RD RD R
5316 -A W W W R
5322 -A W W W R
5317 -Af R R R R
5323 -Af R R R R
5318 ========= == == == ==
5324 ========= == == == ==
5319
5325
5320 Note that remove never deletes files in Added [A] state from the
5326 Note that remove never deletes files in Added [A] state from the
5321 working directory, not even if option --force is specified.
5327 working directory, not even if option --force is specified.
5322
5328
5323 Returns 0 on success, 1 if any warnings encountered.
5329 Returns 0 on success, 1 if any warnings encountered.
5324 """
5330 """
5325
5331
5326 after, force = opts.get('after'), opts.get('force')
5332 after, force = opts.get('after'), opts.get('force')
5327 if not pats and not after:
5333 if not pats and not after:
5328 raise util.Abort(_('no files specified'))
5334 raise util.Abort(_('no files specified'))
5329
5335
5330 m = scmutil.match(repo[None], pats, opts)
5336 m = scmutil.match(repo[None], pats, opts)
5331 subrepos = opts.get('subrepos')
5337 subrepos = opts.get('subrepos')
5332 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5338 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5333
5339
5334 @command('rename|move|mv',
5340 @command('rename|move|mv',
5335 [('A', 'after', None, _('record a rename that has already occurred')),
5341 [('A', 'after', None, _('record a rename that has already occurred')),
5336 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5342 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5337 ] + walkopts + dryrunopts,
5343 ] + walkopts + dryrunopts,
5338 _('[OPTION]... SOURCE... DEST'))
5344 _('[OPTION]... SOURCE... DEST'))
5339 def rename(ui, repo, *pats, **opts):
5345 def rename(ui, repo, *pats, **opts):
5340 """rename files; equivalent of copy + remove
5346 """rename files; equivalent of copy + remove
5341
5347
5342 Mark dest as copies of sources; mark sources for deletion. If dest
5348 Mark dest as copies of sources; mark sources for deletion. If dest
5343 is a directory, copies are put in that directory. If dest is a
5349 is a directory, copies are put in that directory. If dest is a
5344 file, there can only be one source.
5350 file, there can only be one source.
5345
5351
5346 By default, this command copies the contents of files as they
5352 By default, this command copies the contents of files as they
5347 exist in the working directory. If invoked with -A/--after, the
5353 exist in the working directory. If invoked with -A/--after, the
5348 operation is recorded, but no copying is performed.
5354 operation is recorded, but no copying is performed.
5349
5355
5350 This command takes effect at the next commit. To undo a rename
5356 This command takes effect at the next commit. To undo a rename
5351 before that, see :hg:`revert`.
5357 before that, see :hg:`revert`.
5352
5358
5353 Returns 0 on success, 1 if errors are encountered.
5359 Returns 0 on success, 1 if errors are encountered.
5354 """
5360 """
5355 wlock = repo.wlock(False)
5361 wlock = repo.wlock(False)
5356 try:
5362 try:
5357 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5363 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5358 finally:
5364 finally:
5359 wlock.release()
5365 wlock.release()
5360
5366
5361 @command('resolve',
5367 @command('resolve',
5362 [('a', 'all', None, _('select all unresolved files')),
5368 [('a', 'all', None, _('select all unresolved files')),
5363 ('l', 'list', None, _('list state of files needing merge')),
5369 ('l', 'list', None, _('list state of files needing merge')),
5364 ('m', 'mark', None, _('mark files as resolved')),
5370 ('m', 'mark', None, _('mark files as resolved')),
5365 ('u', 'unmark', None, _('mark files as unresolved')),
5371 ('u', 'unmark', None, _('mark files as unresolved')),
5366 ('n', 'no-status', None, _('hide status prefix'))]
5372 ('n', 'no-status', None, _('hide status prefix'))]
5367 + mergetoolopts + walkopts + formatteropts,
5373 + mergetoolopts + walkopts + formatteropts,
5368 _('[OPTION]... [FILE]...'),
5374 _('[OPTION]... [FILE]...'),
5369 inferrepo=True)
5375 inferrepo=True)
5370 def resolve(ui, repo, *pats, **opts):
5376 def resolve(ui, repo, *pats, **opts):
5371 """redo merges or set/view the merge status of files
5377 """redo merges or set/view the merge status of files
5372
5378
5373 Merges with unresolved conflicts are often the result of
5379 Merges with unresolved conflicts are often the result of
5374 non-interactive merging using the ``internal:merge`` configuration
5380 non-interactive merging using the ``internal:merge`` configuration
5375 setting, or a command-line merge tool like ``diff3``. The resolve
5381 setting, or a command-line merge tool like ``diff3``. The resolve
5376 command is used to manage the files involved in a merge, after
5382 command is used to manage the files involved in a merge, after
5377 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5383 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5378 working directory must have two parents). See :hg:`help
5384 working directory must have two parents). See :hg:`help
5379 merge-tools` for information on configuring merge tools.
5385 merge-tools` for information on configuring merge tools.
5380
5386
5381 The resolve command can be used in the following ways:
5387 The resolve command can be used in the following ways:
5382
5388
5383 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5389 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5384 files, discarding any previous merge attempts. Re-merging is not
5390 files, discarding any previous merge attempts. Re-merging is not
5385 performed for files already marked as resolved. Use ``--all/-a``
5391 performed for files already marked as resolved. Use ``--all/-a``
5386 to select all unresolved files. ``--tool`` can be used to specify
5392 to select all unresolved files. ``--tool`` can be used to specify
5387 the merge tool used for the given files. It overrides the HGMERGE
5393 the merge tool used for the given files. It overrides the HGMERGE
5388 environment variable and your configuration files. Previous file
5394 environment variable and your configuration files. Previous file
5389 contents are saved with a ``.orig`` suffix.
5395 contents are saved with a ``.orig`` suffix.
5390
5396
5391 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5397 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5392 (e.g. after having manually fixed-up the files). The default is
5398 (e.g. after having manually fixed-up the files). The default is
5393 to mark all unresolved files.
5399 to mark all unresolved files.
5394
5400
5395 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5401 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5396 default is to mark all resolved files.
5402 default is to mark all resolved files.
5397
5403
5398 - :hg:`resolve -l`: list files which had or still have conflicts.
5404 - :hg:`resolve -l`: list files which had or still have conflicts.
5399 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5405 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5400
5406
5401 Note that Mercurial will not let you commit files with unresolved
5407 Note that Mercurial will not let you commit files with unresolved
5402 merge conflicts. You must use :hg:`resolve -m ...` before you can
5408 merge conflicts. You must use :hg:`resolve -m ...` before you can
5403 commit after a conflicting merge.
5409 commit after a conflicting merge.
5404
5410
5405 Returns 0 on success, 1 if any files fail a resolve attempt.
5411 Returns 0 on success, 1 if any files fail a resolve attempt.
5406 """
5412 """
5407
5413
5408 all, mark, unmark, show, nostatus = \
5414 all, mark, unmark, show, nostatus = \
5409 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5415 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5410
5416
5411 if (show and (mark or unmark)) or (mark and unmark):
5417 if (show and (mark or unmark)) or (mark and unmark):
5412 raise util.Abort(_("too many options specified"))
5418 raise util.Abort(_("too many options specified"))
5413 if pats and all:
5419 if pats and all:
5414 raise util.Abort(_("can't specify --all and patterns"))
5420 raise util.Abort(_("can't specify --all and patterns"))
5415 if not (all or pats or show or mark or unmark):
5421 if not (all or pats or show or mark or unmark):
5416 raise util.Abort(_('no files or directories specified'),
5422 raise util.Abort(_('no files or directories specified'),
5417 hint=('use --all to remerge all files'))
5423 hint=('use --all to remerge all files'))
5418
5424
5419 if show:
5425 if show:
5420 fm = ui.formatter('resolve', opts)
5426 fm = ui.formatter('resolve', opts)
5421 ms = mergemod.mergestate(repo)
5427 ms = mergemod.mergestate(repo)
5422 m = scmutil.match(repo[None], pats, opts)
5428 m = scmutil.match(repo[None], pats, opts)
5423 for f in ms:
5429 for f in ms:
5424 if not m(f):
5430 if not m(f):
5425 continue
5431 continue
5426 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5432 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5427 fm.startitem()
5433 fm.startitem()
5428 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5434 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5429 fm.write('path', '%s\n', f, label=l)
5435 fm.write('path', '%s\n', f, label=l)
5430 fm.end()
5436 fm.end()
5431 return 0
5437 return 0
5432
5438
5433 wlock = repo.wlock()
5439 wlock = repo.wlock()
5434 try:
5440 try:
5435 ms = mergemod.mergestate(repo)
5441 ms = mergemod.mergestate(repo)
5436
5442
5437 if not (ms.active() or repo.dirstate.p2() != nullid):
5443 if not (ms.active() or repo.dirstate.p2() != nullid):
5438 raise util.Abort(
5444 raise util.Abort(
5439 _('resolve command not applicable when not merging'))
5445 _('resolve command not applicable when not merging'))
5440
5446
5441 m = scmutil.match(repo[None], pats, opts)
5447 m = scmutil.match(repo[None], pats, opts)
5442 ret = 0
5448 ret = 0
5443 didwork = False
5449 didwork = False
5444
5450
5445 for f in ms:
5451 for f in ms:
5446 if not m(f):
5452 if not m(f):
5447 continue
5453 continue
5448
5454
5449 didwork = True
5455 didwork = True
5450
5456
5451 if mark:
5457 if mark:
5452 ms.mark(f, "r")
5458 ms.mark(f, "r")
5453 elif unmark:
5459 elif unmark:
5454 ms.mark(f, "u")
5460 ms.mark(f, "u")
5455 else:
5461 else:
5456 wctx = repo[None]
5462 wctx = repo[None]
5457
5463
5458 # backup pre-resolve (merge uses .orig for its own purposes)
5464 # backup pre-resolve (merge uses .orig for its own purposes)
5459 a = repo.wjoin(f)
5465 a = repo.wjoin(f)
5460 util.copyfile(a, a + ".resolve")
5466 util.copyfile(a, a + ".resolve")
5461
5467
5462 try:
5468 try:
5463 # resolve file
5469 # resolve file
5464 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5470 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5465 'resolve')
5471 'resolve')
5466 if ms.resolve(f, wctx):
5472 if ms.resolve(f, wctx):
5467 ret = 1
5473 ret = 1
5468 finally:
5474 finally:
5469 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5475 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5470 ms.commit()
5476 ms.commit()
5471
5477
5472 # replace filemerge's .orig file with our resolve file
5478 # replace filemerge's .orig file with our resolve file
5473 util.rename(a + ".resolve", a + ".orig")
5479 util.rename(a + ".resolve", a + ".orig")
5474
5480
5475 ms.commit()
5481 ms.commit()
5476
5482
5477 if not didwork and pats:
5483 if not didwork and pats:
5478 ui.warn(_("arguments do not match paths that need resolving\n"))
5484 ui.warn(_("arguments do not match paths that need resolving\n"))
5479
5485
5480 finally:
5486 finally:
5481 wlock.release()
5487 wlock.release()
5482
5488
5483 # Nudge users into finishing an unfinished operation
5489 # Nudge users into finishing an unfinished operation
5484 if not list(ms.unresolved()):
5490 if not list(ms.unresolved()):
5485 ui.status(_('(no more unresolved files)\n'))
5491 ui.status(_('(no more unresolved files)\n'))
5486
5492
5487 return ret
5493 return ret
5488
5494
5489 @command('revert',
5495 @command('revert',
5490 [('a', 'all', None, _('revert all changes when no arguments given')),
5496 [('a', 'all', None, _('revert all changes when no arguments given')),
5491 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5497 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5492 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5498 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5493 ('C', 'no-backup', None, _('do not save backup copies of files')),
5499 ('C', 'no-backup', None, _('do not save backup copies of files')),
5494 ('i', 'interactive', None,
5500 ('i', 'interactive', None,
5495 _('interactively select the changes (EXPERIMENTAL)')),
5501 _('interactively select the changes (EXPERIMENTAL)')),
5496 ] + walkopts + dryrunopts,
5502 ] + walkopts + dryrunopts,
5497 _('[OPTION]... [-r REV] [NAME]...'))
5503 _('[OPTION]... [-r REV] [NAME]...'))
5498 def revert(ui, repo, *pats, **opts):
5504 def revert(ui, repo, *pats, **opts):
5499 """restore files to their checkout state
5505 """restore files to their checkout state
5500
5506
5501 .. note::
5507 .. note::
5502
5508
5503 To check out earlier revisions, you should use :hg:`update REV`.
5509 To check out earlier revisions, you should use :hg:`update REV`.
5504 To cancel an uncommitted merge (and lose your changes),
5510 To cancel an uncommitted merge (and lose your changes),
5505 use :hg:`update --clean .`.
5511 use :hg:`update --clean .`.
5506
5512
5507 With no revision specified, revert the specified files or directories
5513 With no revision specified, revert the specified files or directories
5508 to the contents they had in the parent of the working directory.
5514 to the contents they had in the parent of the working directory.
5509 This restores the contents of files to an unmodified
5515 This restores the contents of files to an unmodified
5510 state and unschedules adds, removes, copies, and renames. If the
5516 state and unschedules adds, removes, copies, and renames. If the
5511 working directory has two parents, you must explicitly specify a
5517 working directory has two parents, you must explicitly specify a
5512 revision.
5518 revision.
5513
5519
5514 Using the -r/--rev or -d/--date options, revert the given files or
5520 Using the -r/--rev or -d/--date options, revert the given files or
5515 directories to their states as of a specific revision. Because
5521 directories to their states as of a specific revision. Because
5516 revert does not change the working directory parents, this will
5522 revert does not change the working directory parents, this will
5517 cause these files to appear modified. This can be helpful to "back
5523 cause these files to appear modified. This can be helpful to "back
5518 out" some or all of an earlier change. See :hg:`backout` for a
5524 out" some or all of an earlier change. See :hg:`backout` for a
5519 related method.
5525 related method.
5520
5526
5521 Modified files are saved with a .orig suffix before reverting.
5527 Modified files are saved with a .orig suffix before reverting.
5522 To disable these backups, use --no-backup.
5528 To disable these backups, use --no-backup.
5523
5529
5524 See :hg:`help dates` for a list of formats valid for -d/--date.
5530 See :hg:`help dates` for a list of formats valid for -d/--date.
5525
5531
5526 Returns 0 on success.
5532 Returns 0 on success.
5527 """
5533 """
5528
5534
5529 if opts.get("date"):
5535 if opts.get("date"):
5530 if opts.get("rev"):
5536 if opts.get("rev"):
5531 raise util.Abort(_("you can't specify a revision and a date"))
5537 raise util.Abort(_("you can't specify a revision and a date"))
5532 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5538 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5533
5539
5534 parent, p2 = repo.dirstate.parents()
5540 parent, p2 = repo.dirstate.parents()
5535 if not opts.get('rev') and p2 != nullid:
5541 if not opts.get('rev') and p2 != nullid:
5536 # revert after merge is a trap for new users (issue2915)
5542 # revert after merge is a trap for new users (issue2915)
5537 raise util.Abort(_('uncommitted merge with no revision specified'),
5543 raise util.Abort(_('uncommitted merge with no revision specified'),
5538 hint=_('use "hg update" or see "hg help revert"'))
5544 hint=_('use "hg update" or see "hg help revert"'))
5539
5545
5540 ctx = scmutil.revsingle(repo, opts.get('rev'))
5546 ctx = scmutil.revsingle(repo, opts.get('rev'))
5541
5547
5542 if (not (pats or opts.get('include') or opts.get('exclude') or
5548 if (not (pats or opts.get('include') or opts.get('exclude') or
5543 opts.get('all') or opts.get('interactive'))):
5549 opts.get('all') or opts.get('interactive'))):
5544 msg = _("no files or directories specified")
5550 msg = _("no files or directories specified")
5545 if p2 != nullid:
5551 if p2 != nullid:
5546 hint = _("uncommitted merge, use --all to discard all changes,"
5552 hint = _("uncommitted merge, use --all to discard all changes,"
5547 " or 'hg update -C .' to abort the merge")
5553 " or 'hg update -C .' to abort the merge")
5548 raise util.Abort(msg, hint=hint)
5554 raise util.Abort(msg, hint=hint)
5549 dirty = any(repo.status())
5555 dirty = any(repo.status())
5550 node = ctx.node()
5556 node = ctx.node()
5551 if node != parent:
5557 if node != parent:
5552 if dirty:
5558 if dirty:
5553 hint = _("uncommitted changes, use --all to discard all"
5559 hint = _("uncommitted changes, use --all to discard all"
5554 " changes, or 'hg update %s' to update") % ctx.rev()
5560 " changes, or 'hg update %s' to update") % ctx.rev()
5555 else:
5561 else:
5556 hint = _("use --all to revert all files,"
5562 hint = _("use --all to revert all files,"
5557 " or 'hg update %s' to update") % ctx.rev()
5563 " or 'hg update %s' to update") % ctx.rev()
5558 elif dirty:
5564 elif dirty:
5559 hint = _("uncommitted changes, use --all to discard all changes")
5565 hint = _("uncommitted changes, use --all to discard all changes")
5560 else:
5566 else:
5561 hint = _("use --all to revert all files")
5567 hint = _("use --all to revert all files")
5562 raise util.Abort(msg, hint=hint)
5568 raise util.Abort(msg, hint=hint)
5563
5569
5564 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5570 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5565
5571
5566 @command('rollback', dryrunopts +
5572 @command('rollback', dryrunopts +
5567 [('f', 'force', False, _('ignore safety measures'))])
5573 [('f', 'force', False, _('ignore safety measures'))])
5568 def rollback(ui, repo, **opts):
5574 def rollback(ui, repo, **opts):
5569 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5575 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5570
5576
5571 Please use :hg:`commit --amend` instead of rollback to correct
5577 Please use :hg:`commit --amend` instead of rollback to correct
5572 mistakes in the last commit.
5578 mistakes in the last commit.
5573
5579
5574 This command should be used with care. There is only one level of
5580 This command should be used with care. There is only one level of
5575 rollback, and there is no way to undo a rollback. It will also
5581 rollback, and there is no way to undo a rollback. It will also
5576 restore the dirstate at the time of the last transaction, losing
5582 restore the dirstate at the time of the last transaction, losing
5577 any dirstate changes since that time. This command does not alter
5583 any dirstate changes since that time. This command does not alter
5578 the working directory.
5584 the working directory.
5579
5585
5580 Transactions are used to encapsulate the effects of all commands
5586 Transactions are used to encapsulate the effects of all commands
5581 that create new changesets or propagate existing changesets into a
5587 that create new changesets or propagate existing changesets into a
5582 repository.
5588 repository.
5583
5589
5584 .. container:: verbose
5590 .. container:: verbose
5585
5591
5586 For example, the following commands are transactional, and their
5592 For example, the following commands are transactional, and their
5587 effects can be rolled back:
5593 effects can be rolled back:
5588
5594
5589 - commit
5595 - commit
5590 - import
5596 - import
5591 - pull
5597 - pull
5592 - push (with this repository as the destination)
5598 - push (with this repository as the destination)
5593 - unbundle
5599 - unbundle
5594
5600
5595 To avoid permanent data loss, rollback will refuse to rollback a
5601 To avoid permanent data loss, rollback will refuse to rollback a
5596 commit transaction if it isn't checked out. Use --force to
5602 commit transaction if it isn't checked out. Use --force to
5597 override this protection.
5603 override this protection.
5598
5604
5599 This command is not intended for use on public repositories. Once
5605 This command is not intended for use on public repositories. Once
5600 changes are visible for pull by other users, rolling a transaction
5606 changes are visible for pull by other users, rolling a transaction
5601 back locally is ineffective (someone else may already have pulled
5607 back locally is ineffective (someone else may already have pulled
5602 the changes). Furthermore, a race is possible with readers of the
5608 the changes). Furthermore, a race is possible with readers of the
5603 repository; for example an in-progress pull from the repository
5609 repository; for example an in-progress pull from the repository
5604 may fail if a rollback is performed.
5610 may fail if a rollback is performed.
5605
5611
5606 Returns 0 on success, 1 if no rollback data is available.
5612 Returns 0 on success, 1 if no rollback data is available.
5607 """
5613 """
5608 return repo.rollback(dryrun=opts.get('dry_run'),
5614 return repo.rollback(dryrun=opts.get('dry_run'),
5609 force=opts.get('force'))
5615 force=opts.get('force'))
5610
5616
5611 @command('root', [])
5617 @command('root', [])
5612 def root(ui, repo):
5618 def root(ui, repo):
5613 """print the root (top) of the current working directory
5619 """print the root (top) of the current working directory
5614
5620
5615 Print the root directory of the current repository.
5621 Print the root directory of the current repository.
5616
5622
5617 Returns 0 on success.
5623 Returns 0 on success.
5618 """
5624 """
5619 ui.write(repo.root + "\n")
5625 ui.write(repo.root + "\n")
5620
5626
5621 @command('^serve',
5627 @command('^serve',
5622 [('A', 'accesslog', '', _('name of access log file to write to'),
5628 [('A', 'accesslog', '', _('name of access log file to write to'),
5623 _('FILE')),
5629 _('FILE')),
5624 ('d', 'daemon', None, _('run server in background')),
5630 ('d', 'daemon', None, _('run server in background')),
5625 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5631 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5626 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5632 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5627 # use string type, then we can check if something was passed
5633 # use string type, then we can check if something was passed
5628 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5634 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5629 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5635 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5630 _('ADDR')),
5636 _('ADDR')),
5631 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5637 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5632 _('PREFIX')),
5638 _('PREFIX')),
5633 ('n', 'name', '',
5639 ('n', 'name', '',
5634 _('name to show in web pages (default: working directory)'), _('NAME')),
5640 _('name to show in web pages (default: working directory)'), _('NAME')),
5635 ('', 'web-conf', '',
5641 ('', 'web-conf', '',
5636 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5642 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5637 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5643 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5638 _('FILE')),
5644 _('FILE')),
5639 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5645 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5640 ('', 'stdio', None, _('for remote clients')),
5646 ('', 'stdio', None, _('for remote clients')),
5641 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5647 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5642 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5648 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5643 ('', 'style', '', _('template style to use'), _('STYLE')),
5649 ('', 'style', '', _('template style to use'), _('STYLE')),
5644 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5650 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5645 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5651 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5646 _('[OPTION]...'),
5652 _('[OPTION]...'),
5647 optionalrepo=True)
5653 optionalrepo=True)
5648 def serve(ui, repo, **opts):
5654 def serve(ui, repo, **opts):
5649 """start stand-alone webserver
5655 """start stand-alone webserver
5650
5656
5651 Start a local HTTP repository browser and pull server. You can use
5657 Start a local HTTP repository browser and pull server. You can use
5652 this for ad-hoc sharing and browsing of repositories. It is
5658 this for ad-hoc sharing and browsing of repositories. It is
5653 recommended to use a real web server to serve a repository for
5659 recommended to use a real web server to serve a repository for
5654 longer periods of time.
5660 longer periods of time.
5655
5661
5656 Please note that the server does not implement access control.
5662 Please note that the server does not implement access control.
5657 This means that, by default, anybody can read from the server and
5663 This means that, by default, anybody can read from the server and
5658 nobody can write to it by default. Set the ``web.allow_push``
5664 nobody can write to it by default. Set the ``web.allow_push``
5659 option to ``*`` to allow everybody to push to the server. You
5665 option to ``*`` to allow everybody to push to the server. You
5660 should use a real web server if you need to authenticate users.
5666 should use a real web server if you need to authenticate users.
5661
5667
5662 By default, the server logs accesses to stdout and errors to
5668 By default, the server logs accesses to stdout and errors to
5663 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5669 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5664 files.
5670 files.
5665
5671
5666 To have the server choose a free port number to listen on, specify
5672 To have the server choose a free port number to listen on, specify
5667 a port number of 0; in this case, the server will print the port
5673 a port number of 0; in this case, the server will print the port
5668 number it uses.
5674 number it uses.
5669
5675
5670 Returns 0 on success.
5676 Returns 0 on success.
5671 """
5677 """
5672
5678
5673 if opts["stdio"] and opts["cmdserver"]:
5679 if opts["stdio"] and opts["cmdserver"]:
5674 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5680 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5675
5681
5676 if opts["stdio"]:
5682 if opts["stdio"]:
5677 if repo is None:
5683 if repo is None:
5678 raise error.RepoError(_("there is no Mercurial repository here"
5684 raise error.RepoError(_("there is no Mercurial repository here"
5679 " (.hg not found)"))
5685 " (.hg not found)"))
5680 s = sshserver.sshserver(ui, repo)
5686 s = sshserver.sshserver(ui, repo)
5681 s.serve_forever()
5687 s.serve_forever()
5682
5688
5683 if opts["cmdserver"]:
5689 if opts["cmdserver"]:
5684 service = commandserver.createservice(ui, repo, opts)
5690 service = commandserver.createservice(ui, repo, opts)
5685 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5691 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5686
5692
5687 # this way we can check if something was given in the command-line
5693 # this way we can check if something was given in the command-line
5688 if opts.get('port'):
5694 if opts.get('port'):
5689 opts['port'] = util.getport(opts.get('port'))
5695 opts['port'] = util.getport(opts.get('port'))
5690
5696
5691 if repo:
5697 if repo:
5692 baseui = repo.baseui
5698 baseui = repo.baseui
5693 else:
5699 else:
5694 baseui = ui
5700 baseui = ui
5695 optlist = ("name templates style address port prefix ipv6"
5701 optlist = ("name templates style address port prefix ipv6"
5696 " accesslog errorlog certificate encoding")
5702 " accesslog errorlog certificate encoding")
5697 for o in optlist.split():
5703 for o in optlist.split():
5698 val = opts.get(o, '')
5704 val = opts.get(o, '')
5699 if val in (None, ''): # should check against default options instead
5705 if val in (None, ''): # should check against default options instead
5700 continue
5706 continue
5701 baseui.setconfig("web", o, val, 'serve')
5707 baseui.setconfig("web", o, val, 'serve')
5702 if repo and repo.ui != baseui:
5708 if repo and repo.ui != baseui:
5703 repo.ui.setconfig("web", o, val, 'serve')
5709 repo.ui.setconfig("web", o, val, 'serve')
5704
5710
5705 o = opts.get('web_conf') or opts.get('webdir_conf')
5711 o = opts.get('web_conf') or opts.get('webdir_conf')
5706 if not o:
5712 if not o:
5707 if not repo:
5713 if not repo:
5708 raise error.RepoError(_("there is no Mercurial repository"
5714 raise error.RepoError(_("there is no Mercurial repository"
5709 " here (.hg not found)"))
5715 " here (.hg not found)"))
5710 o = repo
5716 o = repo
5711
5717
5712 app = hgweb.hgweb(o, baseui=baseui)
5718 app = hgweb.hgweb(o, baseui=baseui)
5713 service = httpservice(ui, app, opts)
5719 service = httpservice(ui, app, opts)
5714 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5720 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5715
5721
5716 class httpservice(object):
5722 class httpservice(object):
5717 def __init__(self, ui, app, opts):
5723 def __init__(self, ui, app, opts):
5718 self.ui = ui
5724 self.ui = ui
5719 self.app = app
5725 self.app = app
5720 self.opts = opts
5726 self.opts = opts
5721
5727
5722 def init(self):
5728 def init(self):
5723 util.setsignalhandler()
5729 util.setsignalhandler()
5724 self.httpd = hgweb_server.create_server(self.ui, self.app)
5730 self.httpd = hgweb_server.create_server(self.ui, self.app)
5725
5731
5726 if self.opts['port'] and not self.ui.verbose:
5732 if self.opts['port'] and not self.ui.verbose:
5727 return
5733 return
5728
5734
5729 if self.httpd.prefix:
5735 if self.httpd.prefix:
5730 prefix = self.httpd.prefix.strip('/') + '/'
5736 prefix = self.httpd.prefix.strip('/') + '/'
5731 else:
5737 else:
5732 prefix = ''
5738 prefix = ''
5733
5739
5734 port = ':%d' % self.httpd.port
5740 port = ':%d' % self.httpd.port
5735 if port == ':80':
5741 if port == ':80':
5736 port = ''
5742 port = ''
5737
5743
5738 bindaddr = self.httpd.addr
5744 bindaddr = self.httpd.addr
5739 if bindaddr == '0.0.0.0':
5745 if bindaddr == '0.0.0.0':
5740 bindaddr = '*'
5746 bindaddr = '*'
5741 elif ':' in bindaddr: # IPv6
5747 elif ':' in bindaddr: # IPv6
5742 bindaddr = '[%s]' % bindaddr
5748 bindaddr = '[%s]' % bindaddr
5743
5749
5744 fqaddr = self.httpd.fqaddr
5750 fqaddr = self.httpd.fqaddr
5745 if ':' in fqaddr:
5751 if ':' in fqaddr:
5746 fqaddr = '[%s]' % fqaddr
5752 fqaddr = '[%s]' % fqaddr
5747 if self.opts['port']:
5753 if self.opts['port']:
5748 write = self.ui.status
5754 write = self.ui.status
5749 else:
5755 else:
5750 write = self.ui.write
5756 write = self.ui.write
5751 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5757 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5752 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5758 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5753 self.ui.flush() # avoid buffering of status message
5759 self.ui.flush() # avoid buffering of status message
5754
5760
5755 def run(self):
5761 def run(self):
5756 self.httpd.serve_forever()
5762 self.httpd.serve_forever()
5757
5763
5758
5764
5759 @command('^status|st',
5765 @command('^status|st',
5760 [('A', 'all', None, _('show status of all files')),
5766 [('A', 'all', None, _('show status of all files')),
5761 ('m', 'modified', None, _('show only modified files')),
5767 ('m', 'modified', None, _('show only modified files')),
5762 ('a', 'added', None, _('show only added files')),
5768 ('a', 'added', None, _('show only added files')),
5763 ('r', 'removed', None, _('show only removed files')),
5769 ('r', 'removed', None, _('show only removed files')),
5764 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5770 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5765 ('c', 'clean', None, _('show only files without changes')),
5771 ('c', 'clean', None, _('show only files without changes')),
5766 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5772 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5767 ('i', 'ignored', None, _('show only ignored files')),
5773 ('i', 'ignored', None, _('show only ignored files')),
5768 ('n', 'no-status', None, _('hide status prefix')),
5774 ('n', 'no-status', None, _('hide status prefix')),
5769 ('C', 'copies', None, _('show source of copied files')),
5775 ('C', 'copies', None, _('show source of copied files')),
5770 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5776 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5771 ('', 'rev', [], _('show difference from revision'), _('REV')),
5777 ('', 'rev', [], _('show difference from revision'), _('REV')),
5772 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5778 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5773 ] + walkopts + subrepoopts + formatteropts,
5779 ] + walkopts + subrepoopts + formatteropts,
5774 _('[OPTION]... [FILE]...'),
5780 _('[OPTION]... [FILE]...'),
5775 inferrepo=True)
5781 inferrepo=True)
5776 def status(ui, repo, *pats, **opts):
5782 def status(ui, repo, *pats, **opts):
5777 """show changed files in the working directory
5783 """show changed files in the working directory
5778
5784
5779 Show status of files in the repository. If names are given, only
5785 Show status of files in the repository. If names are given, only
5780 files that match are shown. Files that are clean or ignored or
5786 files that match are shown. Files that are clean or ignored or
5781 the source of a copy/move operation, are not listed unless
5787 the source of a copy/move operation, are not listed unless
5782 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5788 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5783 Unless options described with "show only ..." are given, the
5789 Unless options described with "show only ..." are given, the
5784 options -mardu are used.
5790 options -mardu are used.
5785
5791
5786 Option -q/--quiet hides untracked (unknown and ignored) files
5792 Option -q/--quiet hides untracked (unknown and ignored) files
5787 unless explicitly requested with -u/--unknown or -i/--ignored.
5793 unless explicitly requested with -u/--unknown or -i/--ignored.
5788
5794
5789 .. note::
5795 .. note::
5790
5796
5791 status may appear to disagree with diff if permissions have
5797 status may appear to disagree with diff if permissions have
5792 changed or a merge has occurred. The standard diff format does
5798 changed or a merge has occurred. The standard diff format does
5793 not report permission changes and diff only reports changes
5799 not report permission changes and diff only reports changes
5794 relative to one merge parent.
5800 relative to one merge parent.
5795
5801
5796 If one revision is given, it is used as the base revision.
5802 If one revision is given, it is used as the base revision.
5797 If two revisions are given, the differences between them are
5803 If two revisions are given, the differences between them are
5798 shown. The --change option can also be used as a shortcut to list
5804 shown. The --change option can also be used as a shortcut to list
5799 the changed files of a revision from its first parent.
5805 the changed files of a revision from its first parent.
5800
5806
5801 The codes used to show the status of files are::
5807 The codes used to show the status of files are::
5802
5808
5803 M = modified
5809 M = modified
5804 A = added
5810 A = added
5805 R = removed
5811 R = removed
5806 C = clean
5812 C = clean
5807 ! = missing (deleted by non-hg command, but still tracked)
5813 ! = missing (deleted by non-hg command, but still tracked)
5808 ? = not tracked
5814 ? = not tracked
5809 I = ignored
5815 I = ignored
5810 = origin of the previous file (with --copies)
5816 = origin of the previous file (with --copies)
5811
5817
5812 .. container:: verbose
5818 .. container:: verbose
5813
5819
5814 Examples:
5820 Examples:
5815
5821
5816 - show changes in the working directory relative to a
5822 - show changes in the working directory relative to a
5817 changeset::
5823 changeset::
5818
5824
5819 hg status --rev 9353
5825 hg status --rev 9353
5820
5826
5821 - show changes in the working directory relative to the
5827 - show changes in the working directory relative to the
5822 current directory (see :hg:`help patterns` for more information)::
5828 current directory (see :hg:`help patterns` for more information)::
5823
5829
5824 hg status re:
5830 hg status re:
5825
5831
5826 - show all changes including copies in an existing changeset::
5832 - show all changes including copies in an existing changeset::
5827
5833
5828 hg status --copies --change 9353
5834 hg status --copies --change 9353
5829
5835
5830 - get a NUL separated list of added files, suitable for xargs::
5836 - get a NUL separated list of added files, suitable for xargs::
5831
5837
5832 hg status -an0
5838 hg status -an0
5833
5839
5834 Returns 0 on success.
5840 Returns 0 on success.
5835 """
5841 """
5836
5842
5837 revs = opts.get('rev')
5843 revs = opts.get('rev')
5838 change = opts.get('change')
5844 change = opts.get('change')
5839
5845
5840 if revs and change:
5846 if revs and change:
5841 msg = _('cannot specify --rev and --change at the same time')
5847 msg = _('cannot specify --rev and --change at the same time')
5842 raise util.Abort(msg)
5848 raise util.Abort(msg)
5843 elif change:
5849 elif change:
5844 node2 = scmutil.revsingle(repo, change, None).node()
5850 node2 = scmutil.revsingle(repo, change, None).node()
5845 node1 = repo[node2].p1().node()
5851 node1 = repo[node2].p1().node()
5846 else:
5852 else:
5847 node1, node2 = scmutil.revpair(repo, revs)
5853 node1, node2 = scmutil.revpair(repo, revs)
5848
5854
5849 if pats:
5855 if pats:
5850 cwd = repo.getcwd()
5856 cwd = repo.getcwd()
5851 else:
5857 else:
5852 cwd = ''
5858 cwd = ''
5853
5859
5854 if opts.get('print0'):
5860 if opts.get('print0'):
5855 end = '\0'
5861 end = '\0'
5856 else:
5862 else:
5857 end = '\n'
5863 end = '\n'
5858 copy = {}
5864 copy = {}
5859 states = 'modified added removed deleted unknown ignored clean'.split()
5865 states = 'modified added removed deleted unknown ignored clean'.split()
5860 show = [k for k in states if opts.get(k)]
5866 show = [k for k in states if opts.get(k)]
5861 if opts.get('all'):
5867 if opts.get('all'):
5862 show += ui.quiet and (states[:4] + ['clean']) or states
5868 show += ui.quiet and (states[:4] + ['clean']) or states
5863 if not show:
5869 if not show:
5864 if ui.quiet:
5870 if ui.quiet:
5865 show = states[:4]
5871 show = states[:4]
5866 else:
5872 else:
5867 show = states[:5]
5873 show = states[:5]
5868
5874
5869 m = scmutil.match(repo[node2], pats, opts)
5875 m = scmutil.match(repo[node2], pats, opts)
5870 stat = repo.status(node1, node2, m,
5876 stat = repo.status(node1, node2, m,
5871 'ignored' in show, 'clean' in show, 'unknown' in show,
5877 'ignored' in show, 'clean' in show, 'unknown' in show,
5872 opts.get('subrepos'))
5878 opts.get('subrepos'))
5873 changestates = zip(states, 'MAR!?IC', stat)
5879 changestates = zip(states, 'MAR!?IC', stat)
5874
5880
5875 if (opts.get('all') or opts.get('copies')
5881 if (opts.get('all') or opts.get('copies')
5876 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5882 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
5877 copy = copies.pathcopies(repo[node1], repo[node2], m)
5883 copy = copies.pathcopies(repo[node1], repo[node2], m)
5878
5884
5879 fm = ui.formatter('status', opts)
5885 fm = ui.formatter('status', opts)
5880 fmt = '%s' + end
5886 fmt = '%s' + end
5881 showchar = not opts.get('no_status')
5887 showchar = not opts.get('no_status')
5882
5888
5883 for state, char, files in changestates:
5889 for state, char, files in changestates:
5884 if state in show:
5890 if state in show:
5885 label = 'status.' + state
5891 label = 'status.' + state
5886 for f in files:
5892 for f in files:
5887 fm.startitem()
5893 fm.startitem()
5888 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5894 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5889 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5895 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5890 if f in copy:
5896 if f in copy:
5891 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5897 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5892 label='status.copied')
5898 label='status.copied')
5893 fm.end()
5899 fm.end()
5894
5900
5895 @command('^summary|sum',
5901 @command('^summary|sum',
5896 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5902 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5897 def summary(ui, repo, **opts):
5903 def summary(ui, repo, **opts):
5898 """summarize working directory state
5904 """summarize working directory state
5899
5905
5900 This generates a brief summary of the working directory state,
5906 This generates a brief summary of the working directory state,
5901 including parents, branch, commit status, phase and available updates.
5907 including parents, branch, commit status, phase and available updates.
5902
5908
5903 With the --remote option, this will check the default paths for
5909 With the --remote option, this will check the default paths for
5904 incoming and outgoing changes. This can be time-consuming.
5910 incoming and outgoing changes. This can be time-consuming.
5905
5911
5906 Returns 0 on success.
5912 Returns 0 on success.
5907 """
5913 """
5908
5914
5909 ctx = repo[None]
5915 ctx = repo[None]
5910 parents = ctx.parents()
5916 parents = ctx.parents()
5911 pnode = parents[0].node()
5917 pnode = parents[0].node()
5912 marks = []
5918 marks = []
5913
5919
5914 for p in parents:
5920 for p in parents:
5915 # label with log.changeset (instead of log.parent) since this
5921 # label with log.changeset (instead of log.parent) since this
5916 # shows a working directory parent *changeset*:
5922 # shows a working directory parent *changeset*:
5917 # i18n: column positioning for "hg summary"
5923 # i18n: column positioning for "hg summary"
5918 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5924 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5919 label='log.changeset changeset.%s' % p.phasestr())
5925 label='log.changeset changeset.%s' % p.phasestr())
5920 ui.write(' '.join(p.tags()), label='log.tag')
5926 ui.write(' '.join(p.tags()), label='log.tag')
5921 if p.bookmarks():
5927 if p.bookmarks():
5922 marks.extend(p.bookmarks())
5928 marks.extend(p.bookmarks())
5923 if p.rev() == -1:
5929 if p.rev() == -1:
5924 if not len(repo):
5930 if not len(repo):
5925 ui.write(_(' (empty repository)'))
5931 ui.write(_(' (empty repository)'))
5926 else:
5932 else:
5927 ui.write(_(' (no revision checked out)'))
5933 ui.write(_(' (no revision checked out)'))
5928 ui.write('\n')
5934 ui.write('\n')
5929 if p.description():
5935 if p.description():
5930 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5936 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5931 label='log.summary')
5937 label='log.summary')
5932
5938
5933 branch = ctx.branch()
5939 branch = ctx.branch()
5934 bheads = repo.branchheads(branch)
5940 bheads = repo.branchheads(branch)
5935 # i18n: column positioning for "hg summary"
5941 # i18n: column positioning for "hg summary"
5936 m = _('branch: %s\n') % branch
5942 m = _('branch: %s\n') % branch
5937 if branch != 'default':
5943 if branch != 'default':
5938 ui.write(m, label='log.branch')
5944 ui.write(m, label='log.branch')
5939 else:
5945 else:
5940 ui.status(m, label='log.branch')
5946 ui.status(m, label='log.branch')
5941
5947
5942 if marks:
5948 if marks:
5943 active = repo._activebookmark
5949 active = repo._activebookmark
5944 # i18n: column positioning for "hg summary"
5950 # i18n: column positioning for "hg summary"
5945 ui.write(_('bookmarks:'), label='log.bookmark')
5951 ui.write(_('bookmarks:'), label='log.bookmark')
5946 if active is not None:
5952 if active is not None:
5947 if active in marks:
5953 if active in marks:
5948 ui.write(' *' + active, label=activebookmarklabel)
5954 ui.write(' *' + active, label=activebookmarklabel)
5949 marks.remove(active)
5955 marks.remove(active)
5950 else:
5956 else:
5951 ui.write(' [%s]' % active, label=activebookmarklabel)
5957 ui.write(' [%s]' % active, label=activebookmarklabel)
5952 for m in marks:
5958 for m in marks:
5953 ui.write(' ' + m, label='log.bookmark')
5959 ui.write(' ' + m, label='log.bookmark')
5954 ui.write('\n', label='log.bookmark')
5960 ui.write('\n', label='log.bookmark')
5955
5961
5956 status = repo.status(unknown=True)
5962 status = repo.status(unknown=True)
5957
5963
5958 c = repo.dirstate.copies()
5964 c = repo.dirstate.copies()
5959 copied, renamed = [], []
5965 copied, renamed = [], []
5960 for d, s in c.iteritems():
5966 for d, s in c.iteritems():
5961 if s in status.removed:
5967 if s in status.removed:
5962 status.removed.remove(s)
5968 status.removed.remove(s)
5963 renamed.append(d)
5969 renamed.append(d)
5964 else:
5970 else:
5965 copied.append(d)
5971 copied.append(d)
5966 if d in status.added:
5972 if d in status.added:
5967 status.added.remove(d)
5973 status.added.remove(d)
5968
5974
5969 ms = mergemod.mergestate(repo)
5975 ms = mergemod.mergestate(repo)
5970 unresolved = [f for f in ms if ms[f] == 'u']
5976 unresolved = [f for f in ms if ms[f] == 'u']
5971
5977
5972 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5978 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5973
5979
5974 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5980 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5975 (ui.label(_('%d added'), 'status.added'), status.added),
5981 (ui.label(_('%d added'), 'status.added'), status.added),
5976 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5982 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5977 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5983 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5978 (ui.label(_('%d copied'), 'status.copied'), copied),
5984 (ui.label(_('%d copied'), 'status.copied'), copied),
5979 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5985 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5980 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5986 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5981 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5987 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5982 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5988 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5983 t = []
5989 t = []
5984 for l, s in labels:
5990 for l, s in labels:
5985 if s:
5991 if s:
5986 t.append(l % len(s))
5992 t.append(l % len(s))
5987
5993
5988 t = ', '.join(t)
5994 t = ', '.join(t)
5989 cleanworkdir = False
5995 cleanworkdir = False
5990
5996
5991 if repo.vfs.exists('updatestate'):
5997 if repo.vfs.exists('updatestate'):
5992 t += _(' (interrupted update)')
5998 t += _(' (interrupted update)')
5993 elif len(parents) > 1:
5999 elif len(parents) > 1:
5994 t += _(' (merge)')
6000 t += _(' (merge)')
5995 elif branch != parents[0].branch():
6001 elif branch != parents[0].branch():
5996 t += _(' (new branch)')
6002 t += _(' (new branch)')
5997 elif (parents[0].closesbranch() and
6003 elif (parents[0].closesbranch() and
5998 pnode in repo.branchheads(branch, closed=True)):
6004 pnode in repo.branchheads(branch, closed=True)):
5999 t += _(' (head closed)')
6005 t += _(' (head closed)')
6000 elif not (status.modified or status.added or status.removed or renamed or
6006 elif not (status.modified or status.added or status.removed or renamed or
6001 copied or subs):
6007 copied or subs):
6002 t += _(' (clean)')
6008 t += _(' (clean)')
6003 cleanworkdir = True
6009 cleanworkdir = True
6004 elif pnode not in bheads:
6010 elif pnode not in bheads:
6005 t += _(' (new branch head)')
6011 t += _(' (new branch head)')
6006
6012
6007 if parents:
6013 if parents:
6008 pendingphase = max(p.phase() for p in parents)
6014 pendingphase = max(p.phase() for p in parents)
6009 else:
6015 else:
6010 pendingphase = phases.public
6016 pendingphase = phases.public
6011
6017
6012 if pendingphase > phases.newcommitphase(ui):
6018 if pendingphase > phases.newcommitphase(ui):
6013 t += ' (%s)' % phases.phasenames[pendingphase]
6019 t += ' (%s)' % phases.phasenames[pendingphase]
6014
6020
6015 if cleanworkdir:
6021 if cleanworkdir:
6016 # i18n: column positioning for "hg summary"
6022 # i18n: column positioning for "hg summary"
6017 ui.status(_('commit: %s\n') % t.strip())
6023 ui.status(_('commit: %s\n') % t.strip())
6018 else:
6024 else:
6019 # i18n: column positioning for "hg summary"
6025 # i18n: column positioning for "hg summary"
6020 ui.write(_('commit: %s\n') % t.strip())
6026 ui.write(_('commit: %s\n') % t.strip())
6021
6027
6022 # all ancestors of branch heads - all ancestors of parent = new csets
6028 # all ancestors of branch heads - all ancestors of parent = new csets
6023 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6029 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6024 bheads))
6030 bheads))
6025
6031
6026 if new == 0:
6032 if new == 0:
6027 # i18n: column positioning for "hg summary"
6033 # i18n: column positioning for "hg summary"
6028 ui.status(_('update: (current)\n'))
6034 ui.status(_('update: (current)\n'))
6029 elif pnode not in bheads:
6035 elif pnode not in bheads:
6030 # i18n: column positioning for "hg summary"
6036 # i18n: column positioning for "hg summary"
6031 ui.write(_('update: %d new changesets (update)\n') % new)
6037 ui.write(_('update: %d new changesets (update)\n') % new)
6032 else:
6038 else:
6033 # i18n: column positioning for "hg summary"
6039 # i18n: column positioning for "hg summary"
6034 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6040 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6035 (new, len(bheads)))
6041 (new, len(bheads)))
6036
6042
6037 t = []
6043 t = []
6038 draft = len(repo.revs('draft()'))
6044 draft = len(repo.revs('draft()'))
6039 if draft:
6045 if draft:
6040 t.append(_('%d draft') % draft)
6046 t.append(_('%d draft') % draft)
6041 secret = len(repo.revs('secret()'))
6047 secret = len(repo.revs('secret()'))
6042 if secret:
6048 if secret:
6043 t.append(_('%d secret') % secret)
6049 t.append(_('%d secret') % secret)
6044
6050
6045 if draft or secret:
6051 if draft or secret:
6046 ui.status(_('phases: %s\n') % ', '.join(t))
6052 ui.status(_('phases: %s\n') % ', '.join(t))
6047
6053
6048 cmdutil.summaryhooks(ui, repo)
6054 cmdutil.summaryhooks(ui, repo)
6049
6055
6050 if opts.get('remote'):
6056 if opts.get('remote'):
6051 needsincoming, needsoutgoing = True, True
6057 needsincoming, needsoutgoing = True, True
6052 else:
6058 else:
6053 needsincoming, needsoutgoing = False, False
6059 needsincoming, needsoutgoing = False, False
6054 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6060 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6055 if i:
6061 if i:
6056 needsincoming = True
6062 needsincoming = True
6057 if o:
6063 if o:
6058 needsoutgoing = True
6064 needsoutgoing = True
6059 if not needsincoming and not needsoutgoing:
6065 if not needsincoming and not needsoutgoing:
6060 return
6066 return
6061
6067
6062 def getincoming():
6068 def getincoming():
6063 source, branches = hg.parseurl(ui.expandpath('default'))
6069 source, branches = hg.parseurl(ui.expandpath('default'))
6064 sbranch = branches[0]
6070 sbranch = branches[0]
6065 try:
6071 try:
6066 other = hg.peer(repo, {}, source)
6072 other = hg.peer(repo, {}, source)
6067 except error.RepoError:
6073 except error.RepoError:
6068 if opts.get('remote'):
6074 if opts.get('remote'):
6069 raise
6075 raise
6070 return source, sbranch, None, None, None
6076 return source, sbranch, None, None, None
6071 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6077 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6072 if revs:
6078 if revs:
6073 revs = [other.lookup(rev) for rev in revs]
6079 revs = [other.lookup(rev) for rev in revs]
6074 ui.debug('comparing with %s\n' % util.hidepassword(source))
6080 ui.debug('comparing with %s\n' % util.hidepassword(source))
6075 repo.ui.pushbuffer()
6081 repo.ui.pushbuffer()
6076 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6082 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6077 repo.ui.popbuffer()
6083 repo.ui.popbuffer()
6078 return source, sbranch, other, commoninc, commoninc[1]
6084 return source, sbranch, other, commoninc, commoninc[1]
6079
6085
6080 if needsincoming:
6086 if needsincoming:
6081 source, sbranch, sother, commoninc, incoming = getincoming()
6087 source, sbranch, sother, commoninc, incoming = getincoming()
6082 else:
6088 else:
6083 source = sbranch = sother = commoninc = incoming = None
6089 source = sbranch = sother = commoninc = incoming = None
6084
6090
6085 def getoutgoing():
6091 def getoutgoing():
6086 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6092 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6087 dbranch = branches[0]
6093 dbranch = branches[0]
6088 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6094 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6089 if source != dest:
6095 if source != dest:
6090 try:
6096 try:
6091 dother = hg.peer(repo, {}, dest)
6097 dother = hg.peer(repo, {}, dest)
6092 except error.RepoError:
6098 except error.RepoError:
6093 if opts.get('remote'):
6099 if opts.get('remote'):
6094 raise
6100 raise
6095 return dest, dbranch, None, None
6101 return dest, dbranch, None, None
6096 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6102 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6097 elif sother is None:
6103 elif sother is None:
6098 # there is no explicit destination peer, but source one is invalid
6104 # there is no explicit destination peer, but source one is invalid
6099 return dest, dbranch, None, None
6105 return dest, dbranch, None, None
6100 else:
6106 else:
6101 dother = sother
6107 dother = sother
6102 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6108 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6103 common = None
6109 common = None
6104 else:
6110 else:
6105 common = commoninc
6111 common = commoninc
6106 if revs:
6112 if revs:
6107 revs = [repo.lookup(rev) for rev in revs]
6113 revs = [repo.lookup(rev) for rev in revs]
6108 repo.ui.pushbuffer()
6114 repo.ui.pushbuffer()
6109 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6115 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6110 commoninc=common)
6116 commoninc=common)
6111 repo.ui.popbuffer()
6117 repo.ui.popbuffer()
6112 return dest, dbranch, dother, outgoing
6118 return dest, dbranch, dother, outgoing
6113
6119
6114 if needsoutgoing:
6120 if needsoutgoing:
6115 dest, dbranch, dother, outgoing = getoutgoing()
6121 dest, dbranch, dother, outgoing = getoutgoing()
6116 else:
6122 else:
6117 dest = dbranch = dother = outgoing = None
6123 dest = dbranch = dother = outgoing = None
6118
6124
6119 if opts.get('remote'):
6125 if opts.get('remote'):
6120 t = []
6126 t = []
6121 if incoming:
6127 if incoming:
6122 t.append(_('1 or more incoming'))
6128 t.append(_('1 or more incoming'))
6123 o = outgoing.missing
6129 o = outgoing.missing
6124 if o:
6130 if o:
6125 t.append(_('%d outgoing') % len(o))
6131 t.append(_('%d outgoing') % len(o))
6126 other = dother or sother
6132 other = dother or sother
6127 if 'bookmarks' in other.listkeys('namespaces'):
6133 if 'bookmarks' in other.listkeys('namespaces'):
6128 counts = bookmarks.summary(repo, other)
6134 counts = bookmarks.summary(repo, other)
6129 if counts[0] > 0:
6135 if counts[0] > 0:
6130 t.append(_('%d incoming bookmarks') % counts[0])
6136 t.append(_('%d incoming bookmarks') % counts[0])
6131 if counts[1] > 0:
6137 if counts[1] > 0:
6132 t.append(_('%d outgoing bookmarks') % counts[1])
6138 t.append(_('%d outgoing bookmarks') % counts[1])
6133
6139
6134 if t:
6140 if t:
6135 # i18n: column positioning for "hg summary"
6141 # i18n: column positioning for "hg summary"
6136 ui.write(_('remote: %s\n') % (', '.join(t)))
6142 ui.write(_('remote: %s\n') % (', '.join(t)))
6137 else:
6143 else:
6138 # i18n: column positioning for "hg summary"
6144 # i18n: column positioning for "hg summary"
6139 ui.status(_('remote: (synced)\n'))
6145 ui.status(_('remote: (synced)\n'))
6140
6146
6141 cmdutil.summaryremotehooks(ui, repo, opts,
6147 cmdutil.summaryremotehooks(ui, repo, opts,
6142 ((source, sbranch, sother, commoninc),
6148 ((source, sbranch, sother, commoninc),
6143 (dest, dbranch, dother, outgoing)))
6149 (dest, dbranch, dother, outgoing)))
6144
6150
6145 @command('tag',
6151 @command('tag',
6146 [('f', 'force', None, _('force tag')),
6152 [('f', 'force', None, _('force tag')),
6147 ('l', 'local', None, _('make the tag local')),
6153 ('l', 'local', None, _('make the tag local')),
6148 ('r', 'rev', '', _('revision to tag'), _('REV')),
6154 ('r', 'rev', '', _('revision to tag'), _('REV')),
6149 ('', 'remove', None, _('remove a tag')),
6155 ('', 'remove', None, _('remove a tag')),
6150 # -l/--local is already there, commitopts cannot be used
6156 # -l/--local is already there, commitopts cannot be used
6151 ('e', 'edit', None, _('invoke editor on commit messages')),
6157 ('e', 'edit', None, _('invoke editor on commit messages')),
6152 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6158 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6153 ] + commitopts2,
6159 ] + commitopts2,
6154 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6160 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6155 def tag(ui, repo, name1, *names, **opts):
6161 def tag(ui, repo, name1, *names, **opts):
6156 """add one or more tags for the current or given revision
6162 """add one or more tags for the current or given revision
6157
6163
6158 Name a particular revision using <name>.
6164 Name a particular revision using <name>.
6159
6165
6160 Tags are used to name particular revisions of the repository and are
6166 Tags are used to name particular revisions of the repository and are
6161 very useful to compare different revisions, to go back to significant
6167 very useful to compare different revisions, to go back to significant
6162 earlier versions or to mark branch points as releases, etc. Changing
6168 earlier versions or to mark branch points as releases, etc. Changing
6163 an existing tag is normally disallowed; use -f/--force to override.
6169 an existing tag is normally disallowed; use -f/--force to override.
6164
6170
6165 If no revision is given, the parent of the working directory is
6171 If no revision is given, the parent of the working directory is
6166 used.
6172 used.
6167
6173
6168 To facilitate version control, distribution, and merging of tags,
6174 To facilitate version control, distribution, and merging of tags,
6169 they are stored as a file named ".hgtags" which is managed similarly
6175 they are stored as a file named ".hgtags" which is managed similarly
6170 to other project files and can be hand-edited if necessary. This
6176 to other project files and can be hand-edited if necessary. This
6171 also means that tagging creates a new commit. The file
6177 also means that tagging creates a new commit. The file
6172 ".hg/localtags" is used for local tags (not shared among
6178 ".hg/localtags" is used for local tags (not shared among
6173 repositories).
6179 repositories).
6174
6180
6175 Tag commits are usually made at the head of a branch. If the parent
6181 Tag commits are usually made at the head of a branch. If the parent
6176 of the working directory is not a branch head, :hg:`tag` aborts; use
6182 of the working directory is not a branch head, :hg:`tag` aborts; use
6177 -f/--force to force the tag commit to be based on a non-head
6183 -f/--force to force the tag commit to be based on a non-head
6178 changeset.
6184 changeset.
6179
6185
6180 See :hg:`help dates` for a list of formats valid for -d/--date.
6186 See :hg:`help dates` for a list of formats valid for -d/--date.
6181
6187
6182 Since tag names have priority over branch names during revision
6188 Since tag names have priority over branch names during revision
6183 lookup, using an existing branch name as a tag name is discouraged.
6189 lookup, using an existing branch name as a tag name is discouraged.
6184
6190
6185 Returns 0 on success.
6191 Returns 0 on success.
6186 """
6192 """
6187 wlock = lock = None
6193 wlock = lock = None
6188 try:
6194 try:
6189 wlock = repo.wlock()
6195 wlock = repo.wlock()
6190 lock = repo.lock()
6196 lock = repo.lock()
6191 rev_ = "."
6197 rev_ = "."
6192 names = [t.strip() for t in (name1,) + names]
6198 names = [t.strip() for t in (name1,) + names]
6193 if len(names) != len(set(names)):
6199 if len(names) != len(set(names)):
6194 raise util.Abort(_('tag names must be unique'))
6200 raise util.Abort(_('tag names must be unique'))
6195 for n in names:
6201 for n in names:
6196 scmutil.checknewlabel(repo, n, 'tag')
6202 scmutil.checknewlabel(repo, n, 'tag')
6197 if not n:
6203 if not n:
6198 raise util.Abort(_('tag names cannot consist entirely of '
6204 raise util.Abort(_('tag names cannot consist entirely of '
6199 'whitespace'))
6205 'whitespace'))
6200 if opts.get('rev') and opts.get('remove'):
6206 if opts.get('rev') and opts.get('remove'):
6201 raise util.Abort(_("--rev and --remove are incompatible"))
6207 raise util.Abort(_("--rev and --remove are incompatible"))
6202 if opts.get('rev'):
6208 if opts.get('rev'):
6203 rev_ = opts['rev']
6209 rev_ = opts['rev']
6204 message = opts.get('message')
6210 message = opts.get('message')
6205 if opts.get('remove'):
6211 if opts.get('remove'):
6206 if opts.get('local'):
6212 if opts.get('local'):
6207 expectedtype = 'local'
6213 expectedtype = 'local'
6208 else:
6214 else:
6209 expectedtype = 'global'
6215 expectedtype = 'global'
6210
6216
6211 for n in names:
6217 for n in names:
6212 if not repo.tagtype(n):
6218 if not repo.tagtype(n):
6213 raise util.Abort(_("tag '%s' does not exist") % n)
6219 raise util.Abort(_("tag '%s' does not exist") % n)
6214 if repo.tagtype(n) != expectedtype:
6220 if repo.tagtype(n) != expectedtype:
6215 if expectedtype == 'global':
6221 if expectedtype == 'global':
6216 raise util.Abort(_("tag '%s' is not a global tag") % n)
6222 raise util.Abort(_("tag '%s' is not a global tag") % n)
6217 else:
6223 else:
6218 raise util.Abort(_("tag '%s' is not a local tag") % n)
6224 raise util.Abort(_("tag '%s' is not a local tag") % n)
6219 rev_ = nullid
6225 rev_ = nullid
6220 if not message:
6226 if not message:
6221 # we don't translate commit messages
6227 # we don't translate commit messages
6222 message = 'Removed tag %s' % ', '.join(names)
6228 message = 'Removed tag %s' % ', '.join(names)
6223 elif not opts.get('force'):
6229 elif not opts.get('force'):
6224 for n in names:
6230 for n in names:
6225 if n in repo.tags():
6231 if n in repo.tags():
6226 raise util.Abort(_("tag '%s' already exists "
6232 raise util.Abort(_("tag '%s' already exists "
6227 "(use -f to force)") % n)
6233 "(use -f to force)") % n)
6228 if not opts.get('local'):
6234 if not opts.get('local'):
6229 p1, p2 = repo.dirstate.parents()
6235 p1, p2 = repo.dirstate.parents()
6230 if p2 != nullid:
6236 if p2 != nullid:
6231 raise util.Abort(_('uncommitted merge'))
6237 raise util.Abort(_('uncommitted merge'))
6232 bheads = repo.branchheads()
6238 bheads = repo.branchheads()
6233 if not opts.get('force') and bheads and p1 not in bheads:
6239 if not opts.get('force') and bheads and p1 not in bheads:
6234 raise util.Abort(_('not at a branch head (use -f to force)'))
6240 raise util.Abort(_('not at a branch head (use -f to force)'))
6235 r = scmutil.revsingle(repo, rev_).node()
6241 r = scmutil.revsingle(repo, rev_).node()
6236
6242
6237 if not message:
6243 if not message:
6238 # we don't translate commit messages
6244 # we don't translate commit messages
6239 message = ('Added tag %s for changeset %s' %
6245 message = ('Added tag %s for changeset %s' %
6240 (', '.join(names), short(r)))
6246 (', '.join(names), short(r)))
6241
6247
6242 date = opts.get('date')
6248 date = opts.get('date')
6243 if date:
6249 if date:
6244 date = util.parsedate(date)
6250 date = util.parsedate(date)
6245
6251
6246 if opts.get('remove'):
6252 if opts.get('remove'):
6247 editform = 'tag.remove'
6253 editform = 'tag.remove'
6248 else:
6254 else:
6249 editform = 'tag.add'
6255 editform = 'tag.add'
6250 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6256 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6251
6257
6252 # don't allow tagging the null rev
6258 # don't allow tagging the null rev
6253 if (not opts.get('remove') and
6259 if (not opts.get('remove') and
6254 scmutil.revsingle(repo, rev_).rev() == nullrev):
6260 scmutil.revsingle(repo, rev_).rev() == nullrev):
6255 raise util.Abort(_("cannot tag null revision"))
6261 raise util.Abort(_("cannot tag null revision"))
6256
6262
6257 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6263 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6258 editor=editor)
6264 editor=editor)
6259 finally:
6265 finally:
6260 release(lock, wlock)
6266 release(lock, wlock)
6261
6267
6262 @command('tags', formatteropts, '')
6268 @command('tags', formatteropts, '')
6263 def tags(ui, repo, **opts):
6269 def tags(ui, repo, **opts):
6264 """list repository tags
6270 """list repository tags
6265
6271
6266 This lists both regular and local tags. When the -v/--verbose
6272 This lists both regular and local tags. When the -v/--verbose
6267 switch is used, a third column "local" is printed for local tags.
6273 switch is used, a third column "local" is printed for local tags.
6268
6274
6269 Returns 0 on success.
6275 Returns 0 on success.
6270 """
6276 """
6271
6277
6272 fm = ui.formatter('tags', opts)
6278 fm = ui.formatter('tags', opts)
6273 hexfunc = fm.hexfunc
6279 hexfunc = fm.hexfunc
6274 tagtype = ""
6280 tagtype = ""
6275
6281
6276 for t, n in reversed(repo.tagslist()):
6282 for t, n in reversed(repo.tagslist()):
6277 hn = hexfunc(n)
6283 hn = hexfunc(n)
6278 label = 'tags.normal'
6284 label = 'tags.normal'
6279 tagtype = ''
6285 tagtype = ''
6280 if repo.tagtype(t) == 'local':
6286 if repo.tagtype(t) == 'local':
6281 label = 'tags.local'
6287 label = 'tags.local'
6282 tagtype = 'local'
6288 tagtype = 'local'
6283
6289
6284 fm.startitem()
6290 fm.startitem()
6285 fm.write('tag', '%s', t, label=label)
6291 fm.write('tag', '%s', t, label=label)
6286 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6292 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6287 fm.condwrite(not ui.quiet, 'rev node', fmt,
6293 fm.condwrite(not ui.quiet, 'rev node', fmt,
6288 repo.changelog.rev(n), hn, label=label)
6294 repo.changelog.rev(n), hn, label=label)
6289 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6295 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6290 tagtype, label=label)
6296 tagtype, label=label)
6291 fm.plain('\n')
6297 fm.plain('\n')
6292 fm.end()
6298 fm.end()
6293
6299
6294 @command('tip',
6300 @command('tip',
6295 [('p', 'patch', None, _('show patch')),
6301 [('p', 'patch', None, _('show patch')),
6296 ('g', 'git', None, _('use git extended diff format')),
6302 ('g', 'git', None, _('use git extended diff format')),
6297 ] + templateopts,
6303 ] + templateopts,
6298 _('[-p] [-g]'))
6304 _('[-p] [-g]'))
6299 def tip(ui, repo, **opts):
6305 def tip(ui, repo, **opts):
6300 """show the tip revision (DEPRECATED)
6306 """show the tip revision (DEPRECATED)
6301
6307
6302 The tip revision (usually just called the tip) is the changeset
6308 The tip revision (usually just called the tip) is the changeset
6303 most recently added to the repository (and therefore the most
6309 most recently added to the repository (and therefore the most
6304 recently changed head).
6310 recently changed head).
6305
6311
6306 If you have just made a commit, that commit will be the tip. If
6312 If you have just made a commit, that commit will be the tip. If
6307 you have just pulled changes from another repository, the tip of
6313 you have just pulled changes from another repository, the tip of
6308 that repository becomes the current tip. The "tip" tag is special
6314 that repository becomes the current tip. The "tip" tag is special
6309 and cannot be renamed or assigned to a different changeset.
6315 and cannot be renamed or assigned to a different changeset.
6310
6316
6311 This command is deprecated, please use :hg:`heads` instead.
6317 This command is deprecated, please use :hg:`heads` instead.
6312
6318
6313 Returns 0 on success.
6319 Returns 0 on success.
6314 """
6320 """
6315 displayer = cmdutil.show_changeset(ui, repo, opts)
6321 displayer = cmdutil.show_changeset(ui, repo, opts)
6316 displayer.show(repo['tip'])
6322 displayer.show(repo['tip'])
6317 displayer.close()
6323 displayer.close()
6318
6324
6319 @command('unbundle',
6325 @command('unbundle',
6320 [('u', 'update', None,
6326 [('u', 'update', None,
6321 _('update to new branch head if changesets were unbundled'))],
6327 _('update to new branch head if changesets were unbundled'))],
6322 _('[-u] FILE...'))
6328 _('[-u] FILE...'))
6323 def unbundle(ui, repo, fname1, *fnames, **opts):
6329 def unbundle(ui, repo, fname1, *fnames, **opts):
6324 """apply one or more changegroup files
6330 """apply one or more changegroup files
6325
6331
6326 Apply one or more compressed changegroup files generated by the
6332 Apply one or more compressed changegroup files generated by the
6327 bundle command.
6333 bundle command.
6328
6334
6329 Returns 0 on success, 1 if an update has unresolved files.
6335 Returns 0 on success, 1 if an update has unresolved files.
6330 """
6336 """
6331 fnames = (fname1,) + fnames
6337 fnames = (fname1,) + fnames
6332
6338
6333 lock = repo.lock()
6339 lock = repo.lock()
6334 try:
6340 try:
6335 for fname in fnames:
6341 for fname in fnames:
6336 f = hg.openpath(ui, fname)
6342 f = hg.openpath(ui, fname)
6337 gen = exchange.readbundle(ui, f, fname)
6343 gen = exchange.readbundle(ui, f, fname)
6338 if isinstance(gen, bundle2.unbundle20):
6344 if isinstance(gen, bundle2.unbundle20):
6339 tr = repo.transaction('unbundle')
6345 tr = repo.transaction('unbundle')
6340 try:
6346 try:
6341 op = bundle2.processbundle(repo, gen, lambda: tr)
6347 op = bundle2.processbundle(repo, gen, lambda: tr)
6342 tr.close()
6348 tr.close()
6343 finally:
6349 finally:
6344 if tr:
6350 if tr:
6345 tr.release()
6351 tr.release()
6346 changes = [r.get('result', 0)
6352 changes = [r.get('result', 0)
6347 for r in op.records['changegroup']]
6353 for r in op.records['changegroup']]
6348 modheads = changegroup.combineresults(changes)
6354 modheads = changegroup.combineresults(changes)
6349 else:
6355 else:
6350 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6356 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6351 'bundle:' + fname)
6357 'bundle:' + fname)
6352 finally:
6358 finally:
6353 lock.release()
6359 lock.release()
6354
6360
6355 return postincoming(ui, repo, modheads, opts.get('update'), None)
6361 return postincoming(ui, repo, modheads, opts.get('update'), None)
6356
6362
6357 @command('^update|up|checkout|co',
6363 @command('^update|up|checkout|co',
6358 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6364 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6359 ('c', 'check', None,
6365 ('c', 'check', None,
6360 _('update across branches if no uncommitted changes')),
6366 _('update across branches if no uncommitted changes')),
6361 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6367 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6362 ('r', 'rev', '', _('revision'), _('REV'))
6368 ('r', 'rev', '', _('revision'), _('REV'))
6363 ] + mergetoolopts,
6369 ] + mergetoolopts,
6364 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6370 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6365 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6371 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6366 tool=None):
6372 tool=None):
6367 """update working directory (or switch revisions)
6373 """update working directory (or switch revisions)
6368
6374
6369 Update the repository's working directory to the specified
6375 Update the repository's working directory to the specified
6370 changeset. If no changeset is specified, update to the tip of the
6376 changeset. If no changeset is specified, update to the tip of the
6371 current named branch and move the active bookmark (see :hg:`help
6377 current named branch and move the active bookmark (see :hg:`help
6372 bookmarks`).
6378 bookmarks`).
6373
6379
6374 Update sets the working directory's parent revision to the specified
6380 Update sets the working directory's parent revision to the specified
6375 changeset (see :hg:`help parents`).
6381 changeset (see :hg:`help parents`).
6376
6382
6377 If the changeset is not a descendant or ancestor of the working
6383 If the changeset is not a descendant or ancestor of the working
6378 directory's parent, the update is aborted. With the -c/--check
6384 directory's parent, the update is aborted. With the -c/--check
6379 option, the working directory is checked for uncommitted changes; if
6385 option, the working directory is checked for uncommitted changes; if
6380 none are found, the working directory is updated to the specified
6386 none are found, the working directory is updated to the specified
6381 changeset.
6387 changeset.
6382
6388
6383 .. container:: verbose
6389 .. container:: verbose
6384
6390
6385 The following rules apply when the working directory contains
6391 The following rules apply when the working directory contains
6386 uncommitted changes:
6392 uncommitted changes:
6387
6393
6388 1. If neither -c/--check nor -C/--clean is specified, and if
6394 1. If neither -c/--check nor -C/--clean is specified, and if
6389 the requested changeset is an ancestor or descendant of
6395 the requested changeset is an ancestor or descendant of
6390 the working directory's parent, the uncommitted changes
6396 the working directory's parent, the uncommitted changes
6391 are merged into the requested changeset and the merged
6397 are merged into the requested changeset and the merged
6392 result is left uncommitted. If the requested changeset is
6398 result is left uncommitted. If the requested changeset is
6393 not an ancestor or descendant (that is, it is on another
6399 not an ancestor or descendant (that is, it is on another
6394 branch), the update is aborted and the uncommitted changes
6400 branch), the update is aborted and the uncommitted changes
6395 are preserved.
6401 are preserved.
6396
6402
6397 2. With the -c/--check option, the update is aborted and the
6403 2. With the -c/--check option, the update is aborted and the
6398 uncommitted changes are preserved.
6404 uncommitted changes are preserved.
6399
6405
6400 3. With the -C/--clean option, uncommitted changes are discarded and
6406 3. With the -C/--clean option, uncommitted changes are discarded and
6401 the working directory is updated to the requested changeset.
6407 the working directory is updated to the requested changeset.
6402
6408
6403 To cancel an uncommitted merge (and lose your changes), use
6409 To cancel an uncommitted merge (and lose your changes), use
6404 :hg:`update --clean .`.
6410 :hg:`update --clean .`.
6405
6411
6406 Use null as the changeset to remove the working directory (like
6412 Use null as the changeset to remove the working directory (like
6407 :hg:`clone -U`).
6413 :hg:`clone -U`).
6408
6414
6409 If you want to revert just one file to an older revision, use
6415 If you want to revert just one file to an older revision, use
6410 :hg:`revert [-r REV] NAME`.
6416 :hg:`revert [-r REV] NAME`.
6411
6417
6412 See :hg:`help dates` for a list of formats valid for -d/--date.
6418 See :hg:`help dates` for a list of formats valid for -d/--date.
6413
6419
6414 Returns 0 on success, 1 if there are unresolved files.
6420 Returns 0 on success, 1 if there are unresolved files.
6415 """
6421 """
6416 if rev and node:
6422 if rev and node:
6417 raise util.Abort(_("please specify just one revision"))
6423 raise util.Abort(_("please specify just one revision"))
6418
6424
6419 if rev is None or rev == '':
6425 if rev is None or rev == '':
6420 rev = node
6426 rev = node
6421
6427
6422 cmdutil.clearunfinished(repo)
6428 cmdutil.clearunfinished(repo)
6423
6429
6424 # with no argument, we also move the active bookmark, if any
6430 # with no argument, we also move the active bookmark, if any
6425 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6431 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6426
6432
6427 # if we defined a bookmark, we have to remember the original bookmark name
6433 # if we defined a bookmark, we have to remember the original bookmark name
6428 brev = rev
6434 brev = rev
6429 rev = scmutil.revsingle(repo, rev, rev).rev()
6435 rev = scmutil.revsingle(repo, rev, rev).rev()
6430
6436
6431 if check and clean:
6437 if check and clean:
6432 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6438 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6433
6439
6434 if date:
6440 if date:
6435 if rev is not None:
6441 if rev is not None:
6436 raise util.Abort(_("you can't specify a revision and a date"))
6442 raise util.Abort(_("you can't specify a revision and a date"))
6437 rev = cmdutil.finddate(ui, repo, date)
6443 rev = cmdutil.finddate(ui, repo, date)
6438
6444
6439 if check:
6445 if check:
6440 cmdutil.bailifchanged(repo, merge=False)
6446 cmdutil.bailifchanged(repo, merge=False)
6441 if rev is None:
6447 if rev is None:
6442 rev = repo[repo[None].branch()].rev()
6448 rev = repo[repo[None].branch()].rev()
6443
6449
6444 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6450 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6445
6451
6446 if clean:
6452 if clean:
6447 ret = hg.clean(repo, rev)
6453 ret = hg.clean(repo, rev)
6448 else:
6454 else:
6449 ret = hg.update(repo, rev)
6455 ret = hg.update(repo, rev)
6450
6456
6451 if not ret and movemarkfrom:
6457 if not ret and movemarkfrom:
6452 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6458 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6453 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6459 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6454 elif brev in repo._bookmarks:
6460 elif brev in repo._bookmarks:
6455 bookmarks.activate(repo, brev)
6461 bookmarks.activate(repo, brev)
6456 ui.status(_("(activating bookmark %s)\n") % brev)
6462 ui.status(_("(activating bookmark %s)\n") % brev)
6457 elif brev:
6463 elif brev:
6458 if repo._activebookmark:
6464 if repo._activebookmark:
6459 ui.status(_("(leaving bookmark %s)\n") %
6465 ui.status(_("(leaving bookmark %s)\n") %
6460 repo._activebookmark)
6466 repo._activebookmark)
6461 bookmarks.deactivate(repo)
6467 bookmarks.deactivate(repo)
6462
6468
6463 return ret
6469 return ret
6464
6470
6465 @command('verify', [])
6471 @command('verify', [])
6466 def verify(ui, repo):
6472 def verify(ui, repo):
6467 """verify the integrity of the repository
6473 """verify the integrity of the repository
6468
6474
6469 Verify the integrity of the current repository.
6475 Verify the integrity of the current repository.
6470
6476
6471 This will perform an extensive check of the repository's
6477 This will perform an extensive check of the repository's
6472 integrity, validating the hashes and checksums of each entry in
6478 integrity, validating the hashes and checksums of each entry in
6473 the changelog, manifest, and tracked files, as well as the
6479 the changelog, manifest, and tracked files, as well as the
6474 integrity of their crosslinks and indices.
6480 integrity of their crosslinks and indices.
6475
6481
6476 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6482 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6477 for more information about recovery from corruption of the
6483 for more information about recovery from corruption of the
6478 repository.
6484 repository.
6479
6485
6480 Returns 0 on success, 1 if errors are encountered.
6486 Returns 0 on success, 1 if errors are encountered.
6481 """
6487 """
6482 return hg.verify(repo)
6488 return hg.verify(repo)
6483
6489
6484 @command('version', [], norepo=True)
6490 @command('version', [], norepo=True)
6485 def version_(ui):
6491 def version_(ui):
6486 """output version and copyright information"""
6492 """output version and copyright information"""
6487 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6493 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6488 % util.version())
6494 % util.version())
6489 ui.status(_(
6495 ui.status(_(
6490 "(see http://mercurial.selenic.com for more information)\n"
6496 "(see http://mercurial.selenic.com for more information)\n"
6491 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6497 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6492 "This is free software; see the source for copying conditions. "
6498 "This is free software; see the source for copying conditions. "
6493 "There is NO\nwarranty; "
6499 "There is NO\nwarranty; "
6494 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6500 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6495 ))
6501 ))
6496
6502
6497 ui.note(_("\nEnabled extensions:\n\n"))
6503 ui.note(_("\nEnabled extensions:\n\n"))
6498 if ui.verbose:
6504 if ui.verbose:
6499 # format names and versions into columns
6505 # format names and versions into columns
6500 names = []
6506 names = []
6501 vers = []
6507 vers = []
6502 for name, module in extensions.extensions():
6508 for name, module in extensions.extensions():
6503 names.append(name)
6509 names.append(name)
6504 vers.append(extensions.moduleversion(module))
6510 vers.append(extensions.moduleversion(module))
6505 if names:
6511 if names:
6506 maxnamelen = max(len(n) for n in names)
6512 maxnamelen = max(len(n) for n in names)
6507 for i, name in enumerate(names):
6513 for i, name in enumerate(names):
6508 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6514 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,463 +1,469
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.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 import os, re, time
9 import os, re, time
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial import ui, hg, scmutil, util, templater
11 from mercurial import ui, hg, scmutil, util, templater
12 from mercurial import error, encoding
12 from mercurial import error, encoding
13 from common import ErrorResponse, get_mtime, staticfile, paritygen, ismember, \
13 from common import ErrorResponse, get_mtime, staticfile, paritygen, ismember, \
14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
15 from hgweb_mod import hgweb, makebreadcrumb
15 from hgweb_mod import hgweb, makebreadcrumb
16 from request import wsgirequest
16 from request import wsgirequest
17 import webutil
17 import webutil
18
18
19 def cleannames(items):
19 def cleannames(items):
20 return [(util.pconvert(name).strip('/'), path) for name, path in items]
20 return [(util.pconvert(name).strip('/'), path) for name, path in items]
21
21
22 def findrepos(paths):
22 def findrepos(paths):
23 repos = []
23 repos = []
24 for prefix, root in cleannames(paths):
24 for prefix, root in cleannames(paths):
25 roothead, roottail = os.path.split(root)
25 roothead, roottail = os.path.split(root)
26 # "foo = /bar/*" or "foo = /bar/**" lets every repo /bar/N in or below
26 # "foo = /bar/*" or "foo = /bar/**" lets every repo /bar/N in or below
27 # /bar/ be served as as foo/N .
27 # /bar/ be served as as foo/N .
28 # '*' will not search inside dirs with .hg (except .hg/patches),
28 # '*' will not search inside dirs with .hg (except .hg/patches),
29 # '**' will search inside dirs with .hg (and thus also find subrepos).
29 # '**' will search inside dirs with .hg (and thus also find subrepos).
30 try:
30 try:
31 recurse = {'*': False, '**': True}[roottail]
31 recurse = {'*': False, '**': True}[roottail]
32 except KeyError:
32 except KeyError:
33 repos.append((prefix, root))
33 repos.append((prefix, root))
34 continue
34 continue
35 roothead = os.path.normpath(os.path.abspath(roothead))
35 roothead = os.path.normpath(os.path.abspath(roothead))
36 paths = scmutil.walkrepos(roothead, followsym=True, recurse=recurse)
36 paths = scmutil.walkrepos(roothead, followsym=True, recurse=recurse)
37 repos.extend(urlrepos(prefix, roothead, paths))
37 repos.extend(urlrepos(prefix, roothead, paths))
38 return repos
38 return repos
39
39
40 def urlrepos(prefix, roothead, paths):
40 def urlrepos(prefix, roothead, paths):
41 """yield url paths and filesystem paths from a list of repo paths
41 """yield url paths and filesystem paths from a list of repo paths
42
42
43 >>> conv = lambda seq: [(v, util.pconvert(p)) for v,p in seq]
43 >>> conv = lambda seq: [(v, util.pconvert(p)) for v,p in seq]
44 >>> conv(urlrepos('hg', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
44 >>> conv(urlrepos('hg', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
45 [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg', '/opt')]
45 [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg', '/opt')]
46 >>> conv(urlrepos('', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
46 >>> conv(urlrepos('', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
47 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
47 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
48 """
48 """
49 for path in paths:
49 for path in paths:
50 path = os.path.normpath(path)
50 path = os.path.normpath(path)
51 yield (prefix + '/' +
51 yield (prefix + '/' +
52 util.pconvert(path[len(roothead):]).lstrip('/')).strip('/'), path
52 util.pconvert(path[len(roothead):]).lstrip('/')).strip('/'), path
53
53
54 def geturlcgivars(baseurl, port):
54 def geturlcgivars(baseurl, port):
55 """
55 """
56 Extract CGI variables from baseurl
56 Extract CGI variables from baseurl
57
57
58 >>> geturlcgivars("http://host.org/base", "80")
58 >>> geturlcgivars("http://host.org/base", "80")
59 ('host.org', '80', '/base')
59 ('host.org', '80', '/base')
60 >>> geturlcgivars("http://host.org:8000/base", "80")
60 >>> geturlcgivars("http://host.org:8000/base", "80")
61 ('host.org', '8000', '/base')
61 ('host.org', '8000', '/base')
62 >>> geturlcgivars('/base', 8000)
62 >>> geturlcgivars('/base', 8000)
63 ('', '8000', '/base')
63 ('', '8000', '/base')
64 >>> geturlcgivars("base", '8000')
64 >>> geturlcgivars("base", '8000')
65 ('', '8000', '/base')
65 ('', '8000', '/base')
66 >>> geturlcgivars("http://host", '8000')
66 >>> geturlcgivars("http://host", '8000')
67 ('host', '8000', '/')
67 ('host', '8000', '/')
68 >>> geturlcgivars("http://host/", '8000')
68 >>> geturlcgivars("http://host/", '8000')
69 ('host', '8000', '/')
69 ('host', '8000', '/')
70 """
70 """
71 u = util.url(baseurl)
71 u = util.url(baseurl)
72 name = u.host or ''
72 name = u.host or ''
73 if u.port:
73 if u.port:
74 port = u.port
74 port = u.port
75 path = u.path or ""
75 path = u.path or ""
76 if not path.startswith('/'):
76 if not path.startswith('/'):
77 path = '/' + path
77 path = '/' + path
78
78
79 return name, str(port), path
79 return name, str(port), path
80
80
81 class hgwebdir(object):
81 class hgwebdir(object):
82 refreshinterval = 20
82 refreshinterval = 20
83
83
84 def __init__(self, conf, baseui=None):
84 def __init__(self, conf, baseui=None):
85 self.conf = conf
85 self.conf = conf
86 self.baseui = baseui
86 self.baseui = baseui
87 self.lastrefresh = 0
87 self.lastrefresh = 0
88 self.motd = None
88 self.motd = None
89 self.refresh()
89 self.refresh()
90
90
91 def refresh(self):
91 def refresh(self):
92 if self.lastrefresh + self.refreshinterval > time.time():
92 if self.lastrefresh + self.refreshinterval > time.time():
93 return
93 return
94
94
95 if self.baseui:
95 if self.baseui:
96 u = self.baseui.copy()
96 u = self.baseui.copy()
97 else:
97 else:
98 u = ui.ui()
98 u = ui.ui()
99 u.setconfig('ui', 'report_untrusted', 'off', 'hgwebdir')
99 u.setconfig('ui', 'report_untrusted', 'off', 'hgwebdir')
100 u.setconfig('ui', 'nontty', 'true', 'hgwebdir')
100 u.setconfig('ui', 'nontty', 'true', 'hgwebdir')
101
101
102 if not isinstance(self.conf, (dict, list, tuple)):
102 if not isinstance(self.conf, (dict, list, tuple)):
103 map = {'paths': 'hgweb-paths'}
103 map = {'paths': 'hgweb-paths'}
104 if not os.path.exists(self.conf):
104 if not os.path.exists(self.conf):
105 raise util.Abort(_('config file %s not found!') % self.conf)
105 raise util.Abort(_('config file %s not found!') % self.conf)
106 u.readconfig(self.conf, remap=map, trust=True)
106 u.readconfig(self.conf, remap=map, trust=True)
107 paths = []
107 paths = []
108 for name, ignored in u.configitems('hgweb-paths'):
108 for name, ignored in u.configitems('hgweb-paths'):
109 for path in u.configlist('hgweb-paths', name):
109 for path in u.configlist('hgweb-paths', name):
110 paths.append((name, path))
110 paths.append((name, path))
111 elif isinstance(self.conf, (list, tuple)):
111 elif isinstance(self.conf, (list, tuple)):
112 paths = self.conf
112 paths = self.conf
113 elif isinstance(self.conf, dict):
113 elif isinstance(self.conf, dict):
114 paths = self.conf.items()
114 paths = self.conf.items()
115
115
116 repos = findrepos(paths)
116 repos = findrepos(paths)
117 for prefix, root in u.configitems('collections'):
117 for prefix, root in u.configitems('collections'):
118 prefix = util.pconvert(prefix)
118 prefix = util.pconvert(prefix)
119 for path in scmutil.walkrepos(root, followsym=True):
119 for path in scmutil.walkrepos(root, followsym=True):
120 repo = os.path.normpath(path)
120 repo = os.path.normpath(path)
121 name = util.pconvert(repo)
121 name = util.pconvert(repo)
122 if name.startswith(prefix):
122 if name.startswith(prefix):
123 name = name[len(prefix):]
123 name = name[len(prefix):]
124 repos.append((name.lstrip('/'), repo))
124 repos.append((name.lstrip('/'), repo))
125
125
126 self.repos = repos
126 self.repos = repos
127 self.ui = u
127 self.ui = u
128 encoding.encoding = self.ui.config('web', 'encoding',
128 encoding.encoding = self.ui.config('web', 'encoding',
129 encoding.encoding)
129 encoding.encoding)
130 self.style = self.ui.config('web', 'style', 'paper')
130 self.style = self.ui.config('web', 'style', 'paper')
131 self.templatepath = self.ui.config('web', 'templates', None)
131 self.templatepath = self.ui.config('web', 'templates', None)
132 self.stripecount = self.ui.config('web', 'stripes', 1)
132 self.stripecount = self.ui.config('web', 'stripes', 1)
133 if self.stripecount:
133 if self.stripecount:
134 self.stripecount = int(self.stripecount)
134 self.stripecount = int(self.stripecount)
135 self._baseurl = self.ui.config('web', 'baseurl')
135 self._baseurl = self.ui.config('web', 'baseurl')
136 prefix = self.ui.config('web', 'prefix', '')
136 prefix = self.ui.config('web', 'prefix', '')
137 if prefix.startswith('/'):
137 if prefix.startswith('/'):
138 prefix = prefix[1:]
138 prefix = prefix[1:]
139 if prefix.endswith('/'):
139 if prefix.endswith('/'):
140 prefix = prefix[:-1]
140 prefix = prefix[:-1]
141 self.prefix = prefix
141 self.prefix = prefix
142 self.lastrefresh = time.time()
142 self.lastrefresh = time.time()
143
143
144 def run(self):
144 def run(self):
145 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
145 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
146 raise RuntimeError("This function is only intended to be "
146 raise RuntimeError("This function is only intended to be "
147 "called while running as a CGI script.")
147 "called while running as a CGI script.")
148 import mercurial.hgweb.wsgicgi as wsgicgi
148 import mercurial.hgweb.wsgicgi as wsgicgi
149 wsgicgi.launch(self)
149 wsgicgi.launch(self)
150
150
151 def __call__(self, env, respond):
151 def __call__(self, env, respond):
152 req = wsgirequest(env, respond)
152 req = wsgirequest(env, respond)
153 return self.run_wsgi(req)
153 return self.run_wsgi(req)
154
154
155 def read_allowed(self, ui, req):
155 def read_allowed(self, ui, req):
156 """Check allow_read and deny_read config options of a repo's ui object
156 """Check allow_read and deny_read config options of a repo's ui object
157 to determine user permissions. By default, with neither option set (or
157 to determine user permissions. By default, with neither option set (or
158 both empty), allow all users to read the repo. There are two ways a
158 both empty), allow all users to read the repo. There are two ways a
159 user can be denied read access: (1) deny_read is not empty, and the
159 user can be denied read access: (1) deny_read is not empty, and the
160 user is unauthenticated or deny_read contains user (or *), and (2)
160 user is unauthenticated or deny_read contains user (or *), and (2)
161 allow_read is not empty and the user is not in allow_read. Return True
161 allow_read is not empty and the user is not in allow_read. Return True
162 if user is allowed to read the repo, else return False."""
162 if user is allowed to read the repo, else return False."""
163
163
164 user = req.env.get('REMOTE_USER')
164 user = req.env.get('REMOTE_USER')
165
165
166 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
166 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
167 if deny_read and (not user or ismember(ui, user, deny_read)):
167 if deny_read and (not user or ismember(ui, user, deny_read)):
168 return False
168 return False
169
169
170 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
170 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
171 # by default, allow reading if no allow_read option has been set
171 # by default, allow reading if no allow_read option has been set
172 if (not allow_read) or ismember(ui, user, allow_read):
172 if (not allow_read) or ismember(ui, user, allow_read):
173 return True
173 return True
174
174
175 return False
175 return False
176
176
177 def run_wsgi(self, req):
177 def run_wsgi(self, req):
178 try:
178 try:
179 self.refresh()
179 self.refresh()
180
180
181 virtual = req.env.get("PATH_INFO", "").strip('/')
181 virtual = req.env.get("PATH_INFO", "").strip('/')
182 tmpl = self.templater(req)
182 tmpl = self.templater(req)
183 ctype = tmpl('mimetype', encoding=encoding.encoding)
183 ctype = tmpl('mimetype', encoding=encoding.encoding)
184 ctype = templater.stringify(ctype)
184 ctype = templater.stringify(ctype)
185
185
186 # a static file
186 # a static file
187 if virtual.startswith('static/') or 'static' in req.form:
187 if virtual.startswith('static/') or 'static' in req.form:
188 if virtual.startswith('static/'):
188 if virtual.startswith('static/'):
189 fname = virtual[7:]
189 fname = virtual[7:]
190 else:
190 else:
191 fname = req.form['static'][0]
191 fname = req.form['static'][0]
192 static = self.ui.config("web", "static", None,
192 static = self.ui.config("web", "static", None,
193 untrusted=False)
193 untrusted=False)
194 if not static:
194 if not static:
195 tp = self.templatepath or templater.templatepaths()
195 tp = self.templatepath or templater.templatepaths()
196 if isinstance(tp, str):
196 if isinstance(tp, str):
197 tp = [tp]
197 tp = [tp]
198 static = [os.path.join(p, 'static') for p in tp]
198 static = [os.path.join(p, 'static') for p in tp]
199 staticfile(static, fname, req)
199 staticfile(static, fname, req)
200 return []
200 return []
201
201
202 # top-level index
202 # top-level index
203 elif not virtual:
203 elif not virtual:
204 req.respond(HTTP_OK, ctype)
204 req.respond(HTTP_OK, ctype)
205 return self.makeindex(req, tmpl)
205 return self.makeindex(req, tmpl)
206
206
207 # nested indexes and hgwebs
207 # nested indexes and hgwebs
208
208
209 repos = dict(self.repos)
209 repos = dict(self.repos)
210 virtualrepo = virtual
210 virtualrepo = virtual
211 while virtualrepo:
211 while virtualrepo:
212 real = repos.get(virtualrepo)
212 real = repos.get(virtualrepo)
213 if real:
213 if real:
214 req.env['REPO_NAME'] = virtualrepo
214 req.env['REPO_NAME'] = virtualrepo
215 try:
215 try:
216 # ensure caller gets private copy of ui
216 # ensure caller gets private copy of ui
217 repo = hg.repository(self.ui.copy(), real)
217 repo = hg.repository(self.ui.copy(), real)
218 return hgweb(repo).run_wsgi(req)
218 return hgweb(repo).run_wsgi(req)
219 except IOError, inst:
219 except IOError, inst:
220 msg = inst.strerror
220 msg = inst.strerror
221 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
221 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
222 except error.RepoError, inst:
222 except error.RepoError, inst:
223 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
223 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
224
224
225 up = virtualrepo.rfind('/')
225 up = virtualrepo.rfind('/')
226 if up < 0:
226 if up < 0:
227 break
227 break
228 virtualrepo = virtualrepo[:up]
228 virtualrepo = virtualrepo[:up]
229
229
230 # browse subdirectories
230 # browse subdirectories
231 subdir = virtual + '/'
231 subdir = virtual + '/'
232 if [r for r in repos if r.startswith(subdir)]:
232 if [r for r in repos if r.startswith(subdir)]:
233 req.respond(HTTP_OK, ctype)
233 req.respond(HTTP_OK, ctype)
234 return self.makeindex(req, tmpl, subdir)
234 return self.makeindex(req, tmpl, subdir)
235
235
236 # prefixes not found
236 # prefixes not found
237 req.respond(HTTP_NOT_FOUND, ctype)
237 req.respond(HTTP_NOT_FOUND, ctype)
238 return tmpl("notfound", repo=virtual)
238 return tmpl("notfound", repo=virtual)
239
239
240 except ErrorResponse, err:
240 except ErrorResponse, err:
241 req.respond(err, ctype)
241 req.respond(err, ctype)
242 return tmpl('error', error=err.message or '')
242 return tmpl('error', error=err.message or '')
243 finally:
243 finally:
244 tmpl = None
244 tmpl = None
245
245
246 def makeindex(self, req, tmpl, subdir=""):
246 def makeindex(self, req, tmpl, subdir=""):
247
247
248 def archivelist(ui, nodeid, url):
248 def archivelist(ui, nodeid, url):
249 allowed = ui.configlist("web", "allow_archive", untrusted=True)
249 allowed = ui.configlist("web", "allow_archive", untrusted=True)
250 archives = []
250 archives = []
251 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
251 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
252 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
252 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
253 untrusted=True):
253 untrusted=True):
254 archives.append({"type" : i[0], "extension": i[1],
254 archives.append({"type" : i[0], "extension": i[1],
255 "node": nodeid, "url": url})
255 "node": nodeid, "url": url})
256 return archives
256 return archives
257
257
258 def rawentries(subdir="", **map):
258 def rawentries(subdir="", **map):
259
259
260 descend = self.ui.configbool('web', 'descend', True)
260 descend = self.ui.configbool('web', 'descend', True)
261 collapse = self.ui.configbool('web', 'collapse', False)
261 collapse = self.ui.configbool('web', 'collapse', False)
262 seenrepos = set()
262 seenrepos = set()
263 seendirs = set()
263 seendirs = set()
264 for name, path in self.repos:
264 for name, path in self.repos:
265
265
266 if not name.startswith(subdir):
266 if not name.startswith(subdir):
267 continue
267 continue
268 name = name[len(subdir):]
268 name = name[len(subdir):]
269 directory = False
269 directory = False
270
270
271 if '/' in name:
271 if '/' in name:
272 if not descend:
272 if not descend:
273 continue
273 continue
274
274
275 nameparts = name.split('/')
275 nameparts = name.split('/')
276 rootname = nameparts[0]
276 rootname = nameparts[0]
277
277
278 if not collapse:
278 if not collapse:
279 pass
279 pass
280 elif rootname in seendirs:
280 elif rootname in seendirs:
281 continue
281 continue
282 elif rootname in seenrepos:
282 elif rootname in seenrepos:
283 pass
283 pass
284 else:
284 else:
285 directory = True
285 directory = True
286 name = rootname
286 name = rootname
287
287
288 # redefine the path to refer to the directory
288 # redefine the path to refer to the directory
289 discarded = '/'.join(nameparts[1:])
289 discarded = '/'.join(nameparts[1:])
290
290
291 # remove name parts plus accompanying slash
291 # remove name parts plus accompanying slash
292 path = path[:-len(discarded) - 1]
292 path = path[:-len(discarded) - 1]
293
293
294 try:
295 r = hg.repository(self.ui, path)
296 directory = False
297 except (IOError, error.RepoError):
298 pass
299
294 parts = [name]
300 parts = [name]
295 if 'PATH_INFO' in req.env:
301 if 'PATH_INFO' in req.env:
296 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
302 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
297 if req.env['SCRIPT_NAME']:
303 if req.env['SCRIPT_NAME']:
298 parts.insert(0, req.env['SCRIPT_NAME'])
304 parts.insert(0, req.env['SCRIPT_NAME'])
299 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
305 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
300
306
301 # show either a directory entry or a repository
307 # show either a directory entry or a repository
302 if directory:
308 if directory:
303 # get the directory's time information
309 # get the directory's time information
304 try:
310 try:
305 d = (get_mtime(path), util.makedate()[1])
311 d = (get_mtime(path), util.makedate()[1])
306 except OSError:
312 except OSError:
307 continue
313 continue
308
314
309 # add '/' to the name to make it obvious that
315 # add '/' to the name to make it obvious that
310 # the entry is a directory, not a regular repository
316 # the entry is a directory, not a regular repository
311 row = {'contact': "",
317 row = {'contact': "",
312 'contact_sort': "",
318 'contact_sort': "",
313 'name': name + '/',
319 'name': name + '/',
314 'name_sort': name,
320 'name_sort': name,
315 'url': url,
321 'url': url,
316 'description': "",
322 'description': "",
317 'description_sort': "",
323 'description_sort': "",
318 'lastchange': d,
324 'lastchange': d,
319 'lastchange_sort': d[1]-d[0],
325 'lastchange_sort': d[1]-d[0],
320 'archives': [],
326 'archives': [],
321 'isdirectory': True}
327 'isdirectory': True}
322
328
323 seendirs.add(name)
329 seendirs.add(name)
324 yield row
330 yield row
325 continue
331 continue
326
332
327 u = self.ui.copy()
333 u = self.ui.copy()
328 try:
334 try:
329 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
335 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
330 except Exception, e:
336 except Exception, e:
331 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
337 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
332 continue
338 continue
333 def get(section, name, default=None):
339 def get(section, name, default=None):
334 return u.config(section, name, default, untrusted=True)
340 return u.config(section, name, default, untrusted=True)
335
341
336 if u.configbool("web", "hidden", untrusted=True):
342 if u.configbool("web", "hidden", untrusted=True):
337 continue
343 continue
338
344
339 if not self.read_allowed(u, req):
345 if not self.read_allowed(u, req):
340 continue
346 continue
341
347
342 # update time with local timezone
348 # update time with local timezone
343 try:
349 try:
344 r = hg.repository(self.ui, path)
350 r = hg.repository(self.ui, path)
345 except IOError:
351 except IOError:
346 u.warn(_('error accessing repository at %s\n') % path)
352 u.warn(_('error accessing repository at %s\n') % path)
347 continue
353 continue
348 except error.RepoError:
354 except error.RepoError:
349 u.warn(_('error accessing repository at %s\n') % path)
355 u.warn(_('error accessing repository at %s\n') % path)
350 continue
356 continue
351 try:
357 try:
352 d = (get_mtime(r.spath), util.makedate()[1])
358 d = (get_mtime(r.spath), util.makedate()[1])
353 except OSError:
359 except OSError:
354 continue
360 continue
355
361
356 contact = get_contact(get)
362 contact = get_contact(get)
357 description = get("web", "description", "")
363 description = get("web", "description", "")
358 seenrepos.add(name)
364 seenrepos.add(name)
359 name = get("web", "name", name)
365 name = get("web", "name", name)
360 row = {'contact': contact or "unknown",
366 row = {'contact': contact or "unknown",
361 'contact_sort': contact.upper() or "unknown",
367 'contact_sort': contact.upper() or "unknown",
362 'name': name,
368 'name': name,
363 'name_sort': name,
369 'name_sort': name,
364 'url': url,
370 'url': url,
365 'description': description or "unknown",
371 'description': description or "unknown",
366 'description_sort': description.upper() or "unknown",
372 'description_sort': description.upper() or "unknown",
367 'lastchange': d,
373 'lastchange': d,
368 'lastchange_sort': d[1]-d[0],
374 'lastchange_sort': d[1]-d[0],
369 'archives': archivelist(u, "tip", url),
375 'archives': archivelist(u, "tip", url),
370 'isdirectory': None,
376 'isdirectory': None,
371 }
377 }
372
378
373 yield row
379 yield row
374
380
375 sortdefault = None, False
381 sortdefault = None, False
376 def entries(sortcolumn="", descending=False, subdir="", **map):
382 def entries(sortcolumn="", descending=False, subdir="", **map):
377 rows = rawentries(subdir=subdir, **map)
383 rows = rawentries(subdir=subdir, **map)
378
384
379 if sortcolumn and sortdefault != (sortcolumn, descending):
385 if sortcolumn and sortdefault != (sortcolumn, descending):
380 sortkey = '%s_sort' % sortcolumn
386 sortkey = '%s_sort' % sortcolumn
381 rows = sorted(rows, key=lambda x: x[sortkey],
387 rows = sorted(rows, key=lambda x: x[sortkey],
382 reverse=descending)
388 reverse=descending)
383 for row, parity in zip(rows, paritygen(self.stripecount)):
389 for row, parity in zip(rows, paritygen(self.stripecount)):
384 row['parity'] = parity
390 row['parity'] = parity
385 yield row
391 yield row
386
392
387 self.refresh()
393 self.refresh()
388 sortable = ["name", "description", "contact", "lastchange"]
394 sortable = ["name", "description", "contact", "lastchange"]
389 sortcolumn, descending = sortdefault
395 sortcolumn, descending = sortdefault
390 if 'sort' in req.form:
396 if 'sort' in req.form:
391 sortcolumn = req.form['sort'][0]
397 sortcolumn = req.form['sort'][0]
392 descending = sortcolumn.startswith('-')
398 descending = sortcolumn.startswith('-')
393 if descending:
399 if descending:
394 sortcolumn = sortcolumn[1:]
400 sortcolumn = sortcolumn[1:]
395 if sortcolumn not in sortable:
401 if sortcolumn not in sortable:
396 sortcolumn = ""
402 sortcolumn = ""
397
403
398 sort = [("sort_%s" % column,
404 sort = [("sort_%s" % column,
399 "%s%s" % ((not descending and column == sortcolumn)
405 "%s%s" % ((not descending and column == sortcolumn)
400 and "-" or "", column))
406 and "-" or "", column))
401 for column in sortable]
407 for column in sortable]
402
408
403 self.refresh()
409 self.refresh()
404 self.updatereqenv(req.env)
410 self.updatereqenv(req.env)
405
411
406 return tmpl("index", entries=entries, subdir=subdir,
412 return tmpl("index", entries=entries, subdir=subdir,
407 pathdef=makebreadcrumb('/' + subdir, self.prefix),
413 pathdef=makebreadcrumb('/' + subdir, self.prefix),
408 sortcolumn=sortcolumn, descending=descending,
414 sortcolumn=sortcolumn, descending=descending,
409 **dict(sort))
415 **dict(sort))
410
416
411 def templater(self, req):
417 def templater(self, req):
412
418
413 def motd(**map):
419 def motd(**map):
414 if self.motd is not None:
420 if self.motd is not None:
415 yield self.motd
421 yield self.motd
416 else:
422 else:
417 yield config('web', 'motd', '')
423 yield config('web', 'motd', '')
418
424
419 def config(section, name, default=None, untrusted=True):
425 def config(section, name, default=None, untrusted=True):
420 return self.ui.config(section, name, default, untrusted)
426 return self.ui.config(section, name, default, untrusted)
421
427
422 self.updatereqenv(req.env)
428 self.updatereqenv(req.env)
423
429
424 url = req.env.get('SCRIPT_NAME', '')
430 url = req.env.get('SCRIPT_NAME', '')
425 if not url.endswith('/'):
431 if not url.endswith('/'):
426 url += '/'
432 url += '/'
427
433
428 vars = {}
434 vars = {}
429 styles = (
435 styles = (
430 req.form.get('style', [None])[0],
436 req.form.get('style', [None])[0],
431 config('web', 'style'),
437 config('web', 'style'),
432 'paper'
438 'paper'
433 )
439 )
434 style, mapfile = templater.stylemap(styles, self.templatepath)
440 style, mapfile = templater.stylemap(styles, self.templatepath)
435 if style == styles[0]:
441 if style == styles[0]:
436 vars['style'] = style
442 vars['style'] = style
437
443
438 start = url[-1] == '?' and '&' or '?'
444 start = url[-1] == '?' and '&' or '?'
439 sessionvars = webutil.sessionvars(vars, start)
445 sessionvars = webutil.sessionvars(vars, start)
440 logourl = config('web', 'logourl', 'http://mercurial.selenic.com/')
446 logourl = config('web', 'logourl', 'http://mercurial.selenic.com/')
441 logoimg = config('web', 'logoimg', 'hglogo.png')
447 logoimg = config('web', 'logoimg', 'hglogo.png')
442 staticurl = config('web', 'staticurl') or url + 'static/'
448 staticurl = config('web', 'staticurl') or url + 'static/'
443 if not staticurl.endswith('/'):
449 if not staticurl.endswith('/'):
444 staticurl += '/'
450 staticurl += '/'
445
451
446 tmpl = templater.templater(mapfile,
452 tmpl = templater.templater(mapfile,
447 defaults={"encoding": encoding.encoding,
453 defaults={"encoding": encoding.encoding,
448 "motd": motd,
454 "motd": motd,
449 "url": url,
455 "url": url,
450 "logourl": logourl,
456 "logourl": logourl,
451 "logoimg": logoimg,
457 "logoimg": logoimg,
452 "staticurl": staticurl,
458 "staticurl": staticurl,
453 "sessionvars": sessionvars,
459 "sessionvars": sessionvars,
454 "style": style,
460 "style": style,
455 })
461 })
456 return tmpl
462 return tmpl
457
463
458 def updatereqenv(self, env):
464 def updatereqenv(self, env):
459 if self._baseurl is not None:
465 if self._baseurl is not None:
460 name, port, path = geturlcgivars(self._baseurl, env['SERVER_PORT'])
466 name, port, path = geturlcgivars(self._baseurl, env['SERVER_PORT'])
461 env['SERVER_NAME'] = name
467 env['SERVER_NAME'] = name
462 env['SERVER_PORT'] = port
468 env['SERVER_PORT'] = port
463 env['SCRIPT_NAME'] = path
469 env['SCRIPT_NAME'] = path
@@ -1,1267 +1,1286
1 #require serve
1 #require serve
2
2
3 hide outer repo and work in dir without '.hg'
3 hide outer repo and work in dir without '.hg'
4 $ hg init
4 $ hg init
5 $ mkdir dir
5 $ mkdir dir
6 $ cd dir
6 $ cd dir
7
7
8 Tests some basic hgwebdir functionality. Tests setting up paths and
8 Tests some basic hgwebdir functionality. Tests setting up paths and
9 collection, different forms of 404s and the subdirectory support.
9 collection, different forms of 404s and the subdirectory support.
10
10
11 $ mkdir webdir
11 $ mkdir webdir
12 $ cd webdir
12 $ cd webdir
13 $ hg init a
13 $ hg init a
14 $ echo a > a/a
14 $ echo a > a/a
15 $ hg --cwd a ci -Ama -d'1 0'
15 $ hg --cwd a ci -Ama -d'1 0'
16 adding a
16 adding a
17
17
18 create a mercurial queue repository
18 create a mercurial queue repository
19
19
20 $ hg --cwd a qinit --config extensions.hgext.mq= -c
20 $ hg --cwd a qinit --config extensions.hgext.mq= -c
21 $ hg init b
21 $ hg init b
22 $ echo b > b/b
22 $ echo b > b/b
23 $ hg --cwd b ci -Amb -d'2 0'
23 $ hg --cwd b ci -Amb -d'2 0'
24 adding b
24 adding b
25
25
26 create a nested repository
26 create a nested repository
27
27
28 $ cd b
28 $ cd b
29 $ hg init d
29 $ hg init d
30 $ echo d > d/d
30 $ echo d > d/d
31 $ hg --cwd d ci -Amd -d'3 0'
31 $ hg --cwd d ci -Amd -d'3 0'
32 adding d
32 adding d
33 $ cd ..
33 $ cd ..
34 $ hg init c
34 $ hg init c
35 $ echo c > c/c
35 $ echo c > c/c
36 $ hg --cwd c ci -Amc -d'3 0'
36 $ hg --cwd c ci -Amc -d'3 0'
37 adding c
37 adding c
38
38
39 create a subdirectory containing repositories and subrepositories
39 create a subdirectory containing repositories and subrepositories
40
40
41 $ mkdir notrepo
41 $ mkdir notrepo
42 $ cd notrepo
42 $ cd notrepo
43 $ hg init e
43 $ hg init e
44 $ echo e > e/e
44 $ echo e > e/e
45 $ hg --cwd e ci -Ame -d'4 0'
45 $ hg --cwd e ci -Ame -d'4 0'
46 adding e
46 adding e
47 $ hg init e/e2
47 $ hg init e/e2
48 $ echo e2 > e/e2/e2
48 $ echo e2 > e/e2/e2
49 $ hg --cwd e/e2 ci -Ame2 -d '4 0'
49 $ hg --cwd e/e2 ci -Ame2 -d '4 0'
50 adding e2
50 adding e2
51 $ hg init f
51 $ hg init f
52 $ echo f > f/f
52 $ echo f > f/f
53 $ hg --cwd f ci -Amf -d'4 0'
53 $ hg --cwd f ci -Amf -d'4 0'
54 adding f
54 adding f
55 $ hg init f/f2
55 $ hg init f/f2
56 $ echo f2 > f/f2/f2
56 $ echo f2 > f/f2/f2
57 $ hg --cwd f/f2 ci -Amf2 -d '4 0'
57 $ hg --cwd f/f2 ci -Amf2 -d '4 0'
58 adding f2
58 adding f2
59 $ echo 'f2 = f2' > f/.hgsub
59 $ echo 'f2 = f2' > f/.hgsub
60 $ hg -R f ci -Am 'add subrepo' -d'4 0'
60 $ hg -R f ci -Am 'add subrepo' -d'4 0'
61 adding .hgsub
61 adding .hgsub
62 $ cat >> f/.hg/hgrc << EOF
62 $ cat >> f/.hg/hgrc << EOF
63 > [web]
63 > [web]
64 > name = fancy name for repo f
64 > name = fancy name for repo f
65 > EOF
65 > EOF
66 $ cd ..
66 $ cd ..
67
67
68 create repository without .hg/store
68 create repository without .hg/store
69
69
70 $ hg init nostore
70 $ hg init nostore
71 $ rm -R nostore/.hg/store
71 $ rm -R nostore/.hg/store
72 $ root=`pwd`
72 $ root=`pwd`
73 $ cd ..
73 $ cd ..
74
74
75 serve
75 serve
76 $ cat > paths.conf <<EOF
76 $ cat > paths.conf <<EOF
77 > [paths]
77 > [paths]
78 > a=$root/a
78 > a=$root/a
79 > b=$root/b
79 > b=$root/b
80 > EOF
80 > EOF
81 $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
81 $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
82 > -A access-paths.log -E error-paths-1.log
82 > -A access-paths.log -E error-paths-1.log
83 $ cat hg.pid >> $DAEMON_PIDS
83 $ cat hg.pid >> $DAEMON_PIDS
84
84
85 should give a 404 - file does not exist
85 should give a 404 - file does not exist
86
86
87 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/bork?style=raw'
87 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/bork?style=raw'
88 404 Not Found
88 404 Not Found
89
89
90
90
91 error: bork@8580ff50825a: not found in manifest
91 error: bork@8580ff50825a: not found in manifest
92 [1]
92 [1]
93
93
94 should succeed
94 should succeed
95
95
96 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
96 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
97 200 Script output follows
97 200 Script output follows
98
98
99
99
100 /a/
100 /a/
101 /b/
101 /b/
102
102
103 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/a?style=raw'
103 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/a?style=raw'
104 200 Script output follows
104 200 Script output follows
105
105
106 a
106 a
107 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
107 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
108 200 Script output follows
108 200 Script output follows
109
109
110 b
110 b
111
111
112 should give a 404 - repo is not published
112 should give a 404 - repo is not published
113
113
114 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
114 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
115 404 Not Found
115 404 Not Found
116
116
117
117
118 error: repository c/file/tip/c not found
118 error: repository c/file/tip/c not found
119 [1]
119 [1]
120
120
121 atom-log without basedir
121 atom-log without basedir
122
122
123 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/atom-log' | grep '<link'
123 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/atom-log' | grep '<link'
124 <link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
124 <link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
125 <link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
125 <link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
126 <link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
126 <link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
127
127
128 rss-log without basedir
128 rss-log without basedir
129
129
130 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/rss-log' | grep '<guid'
130 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/rss-log' | grep '<guid'
131 <guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
131 <guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
132 $ cat > paths.conf <<EOF
132 $ cat > paths.conf <<EOF
133 > [paths]
133 > [paths]
134 > t/a/=$root/a
134 > t/a/=$root/a
135 > b=$root/b
135 > b=$root/b
136 > coll=$root/*
136 > coll=$root/*
137 > rcoll=$root/**
137 > rcoll=$root/**
138 > star=*
138 > star=*
139 > starstar=**
139 > starstar=**
140 > astar=webdir/a/*
140 > astar=webdir/a/*
141 > EOF
141 > EOF
142 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
142 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
143 > -A access-paths.log -E error-paths-2.log
143 > -A access-paths.log -E error-paths-2.log
144 $ cat hg.pid >> $DAEMON_PIDS
144 $ cat hg.pid >> $DAEMON_PIDS
145
145
146 should succeed, slashy names
146 should succeed, slashy names
147
147
148 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
148 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
149 200 Script output follows
149 200 Script output follows
150
150
151
151
152 /t/a/
152 /t/a/
153 /b/
153 /b/
154 /coll/a/
154 /coll/a/
155 /coll/a/.hg/patches/
155 /coll/a/.hg/patches/
156 /coll/b/
156 /coll/b/
157 /coll/c/
157 /coll/c/
158 /coll/notrepo/e/
158 /coll/notrepo/e/
159 /coll/notrepo/f/
159 /coll/notrepo/f/
160 /rcoll/a/
160 /rcoll/a/
161 /rcoll/a/.hg/patches/
161 /rcoll/a/.hg/patches/
162 /rcoll/b/
162 /rcoll/b/
163 /rcoll/b/d/
163 /rcoll/b/d/
164 /rcoll/c/
164 /rcoll/c/
165 /rcoll/notrepo/e/
165 /rcoll/notrepo/e/
166 /rcoll/notrepo/e/e2/
166 /rcoll/notrepo/e/e2/
167 /rcoll/notrepo/f/
167 /rcoll/notrepo/f/
168 /rcoll/notrepo/f/f2/
168 /rcoll/notrepo/f/f2/
169 /star/webdir/a/
169 /star/webdir/a/
170 /star/webdir/a/.hg/patches/
170 /star/webdir/a/.hg/patches/
171 /star/webdir/b/
171 /star/webdir/b/
172 /star/webdir/c/
172 /star/webdir/c/
173 /star/webdir/notrepo/e/
173 /star/webdir/notrepo/e/
174 /star/webdir/notrepo/f/
174 /star/webdir/notrepo/f/
175 /starstar/webdir/a/
175 /starstar/webdir/a/
176 /starstar/webdir/a/.hg/patches/
176 /starstar/webdir/a/.hg/patches/
177 /starstar/webdir/b/
177 /starstar/webdir/b/
178 /starstar/webdir/b/d/
178 /starstar/webdir/b/d/
179 /starstar/webdir/c/
179 /starstar/webdir/c/
180 /starstar/webdir/notrepo/e/
180 /starstar/webdir/notrepo/e/
181 /starstar/webdir/notrepo/e/e2/
181 /starstar/webdir/notrepo/e/e2/
182 /starstar/webdir/notrepo/f/
182 /starstar/webdir/notrepo/f/
183 /starstar/webdir/notrepo/f/f2/
183 /starstar/webdir/notrepo/f/f2/
184 /astar/
184 /astar/
185 /astar/.hg/patches/
185 /astar/.hg/patches/
186
186
187 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=paper'
187 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=paper'
188 200 Script output follows
188 200 Script output follows
189
189
190 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
190 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
191 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
191 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
192 <head>
192 <head>
193 <link rel="icon" href="/static/hgicon.png" type="image/png" />
193 <link rel="icon" href="/static/hgicon.png" type="image/png" />
194 <meta name="robots" content="index, nofollow" />
194 <meta name="robots" content="index, nofollow" />
195 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
195 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
196 <script type="text/javascript" src="/static/mercurial.js"></script>
196 <script type="text/javascript" src="/static/mercurial.js"></script>
197
197
198 <title>Mercurial repositories index</title>
198 <title>Mercurial repositories index</title>
199 </head>
199 </head>
200 <body>
200 <body>
201
201
202 <div class="container">
202 <div class="container">
203 <div class="menu">
203 <div class="menu">
204 <a href="http://mercurial.selenic.com/">
204 <a href="http://mercurial.selenic.com/">
205 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
205 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
206 </div>
206 </div>
207 <div class="main">
207 <div class="main">
208 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
208 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
209
209
210 <table class="bigtable">
210 <table class="bigtable">
211 <thead>
211 <thead>
212 <tr>
212 <tr>
213 <th><a href="?sort=name">Name</a></th>
213 <th><a href="?sort=name">Name</a></th>
214 <th><a href="?sort=description">Description</a></th>
214 <th><a href="?sort=description">Description</a></th>
215 <th><a href="?sort=contact">Contact</a></th>
215 <th><a href="?sort=contact">Contact</a></th>
216 <th><a href="?sort=lastchange">Last modified</a></th>
216 <th><a href="?sort=lastchange">Last modified</a></th>
217 <th>&nbsp;</th>
217 <th>&nbsp;</th>
218 <th>&nbsp;</th>
218 <th>&nbsp;</th>
219 </tr>
219 </tr>
220 </thead>
220 </thead>
221 <tbody class="stripes2">
221 <tbody class="stripes2">
222
222
223 <tr>
223 <tr>
224 <td><a href="/t/a/?style=paper">t/a</a></td>
224 <td><a href="/t/a/?style=paper">t/a</a></td>
225 <td>unknown</td>
225 <td>unknown</td>
226 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
226 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
227 <td class="age">*</td> (glob)
227 <td class="age">*</td> (glob)
228 <td class="indexlinks"></td>
228 <td class="indexlinks"></td>
229 <td>
229 <td>
230 <a href="/t/a/atom-log" title="subscribe to repository atom feed">
230 <a href="/t/a/atom-log" title="subscribe to repository atom feed">
231 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
231 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
232 </a>
232 </a>
233 </td>
233 </td>
234 </tr>
234 </tr>
235
235
236 <tr>
236 <tr>
237 <td><a href="/b/?style=paper">b</a></td>
237 <td><a href="/b/?style=paper">b</a></td>
238 <td>unknown</td>
238 <td>unknown</td>
239 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
239 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
240 <td class="age">*</td> (glob)
240 <td class="age">*</td> (glob)
241 <td class="indexlinks"></td>
241 <td class="indexlinks"></td>
242 <td>
242 <td>
243 <a href="/b/atom-log" title="subscribe to repository atom feed">
243 <a href="/b/atom-log" title="subscribe to repository atom feed">
244 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
244 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
245 </a>
245 </a>
246 </td>
246 </td>
247 </tr>
247 </tr>
248
248
249 <tr>
249 <tr>
250 <td><a href="/coll/a/?style=paper">coll/a</a></td>
250 <td><a href="/coll/a/?style=paper">coll/a</a></td>
251 <td>unknown</td>
251 <td>unknown</td>
252 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
252 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
253 <td class="age">*</td> (glob)
253 <td class="age">*</td> (glob)
254 <td class="indexlinks"></td>
254 <td class="indexlinks"></td>
255 <td>
255 <td>
256 <a href="/coll/a/atom-log" title="subscribe to repository atom feed">
256 <a href="/coll/a/atom-log" title="subscribe to repository atom feed">
257 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
257 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
258 </a>
258 </a>
259 </td>
259 </td>
260 </tr>
260 </tr>
261
261
262 <tr>
262 <tr>
263 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
263 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
264 <td>unknown</td>
264 <td>unknown</td>
265 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
265 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
266 <td class="age">*</td> (glob)
266 <td class="age">*</td> (glob)
267 <td class="indexlinks"></td>
267 <td class="indexlinks"></td>
268 <td>
268 <td>
269 <a href="/coll/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
269 <a href="/coll/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
270 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
270 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
271 </a>
271 </a>
272 </td>
272 </td>
273 </tr>
273 </tr>
274
274
275 <tr>
275 <tr>
276 <td><a href="/coll/b/?style=paper">coll/b</a></td>
276 <td><a href="/coll/b/?style=paper">coll/b</a></td>
277 <td>unknown</td>
277 <td>unknown</td>
278 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
278 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
279 <td class="age">*</td> (glob)
279 <td class="age">*</td> (glob)
280 <td class="indexlinks"></td>
280 <td class="indexlinks"></td>
281 <td>
281 <td>
282 <a href="/coll/b/atom-log" title="subscribe to repository atom feed">
282 <a href="/coll/b/atom-log" title="subscribe to repository atom feed">
283 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
283 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
284 </a>
284 </a>
285 </td>
285 </td>
286 </tr>
286 </tr>
287
287
288 <tr>
288 <tr>
289 <td><a href="/coll/c/?style=paper">coll/c</a></td>
289 <td><a href="/coll/c/?style=paper">coll/c</a></td>
290 <td>unknown</td>
290 <td>unknown</td>
291 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
291 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
292 <td class="age">*</td> (glob)
292 <td class="age">*</td> (glob)
293 <td class="indexlinks"></td>
293 <td class="indexlinks"></td>
294 <td>
294 <td>
295 <a href="/coll/c/atom-log" title="subscribe to repository atom feed">
295 <a href="/coll/c/atom-log" title="subscribe to repository atom feed">
296 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
296 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
297 </a>
297 </a>
298 </td>
298 </td>
299 </tr>
299 </tr>
300
300
301 <tr>
301 <tr>
302 <td><a href="/coll/notrepo/e/?style=paper">coll/notrepo/e</a></td>
302 <td><a href="/coll/notrepo/e/?style=paper">coll/notrepo/e</a></td>
303 <td>unknown</td>
303 <td>unknown</td>
304 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
304 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
305 <td class="age">*</td> (glob)
305 <td class="age">*</td> (glob)
306 <td class="indexlinks"></td>
306 <td class="indexlinks"></td>
307 <td>
307 <td>
308 <a href="/coll/notrepo/e/atom-log" title="subscribe to repository atom feed">
308 <a href="/coll/notrepo/e/atom-log" title="subscribe to repository atom feed">
309 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
309 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
310 </a>
310 </a>
311 </td>
311 </td>
312 </tr>
312 </tr>
313
313
314 <tr>
314 <tr>
315 <td><a href="/coll/notrepo/f/?style=paper">fancy name for repo f</a></td>
315 <td><a href="/coll/notrepo/f/?style=paper">fancy name for repo f</a></td>
316 <td>unknown</td>
316 <td>unknown</td>
317 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
317 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
318 <td class="age">*</td> (glob)
318 <td class="age">*</td> (glob)
319 <td class="indexlinks"></td>
319 <td class="indexlinks"></td>
320 <td>
320 <td>
321 <a href="/coll/notrepo/f/atom-log" title="subscribe to repository atom feed">
321 <a href="/coll/notrepo/f/atom-log" title="subscribe to repository atom feed">
322 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
322 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
323 </a>
323 </a>
324 </td>
324 </td>
325 </tr>
325 </tr>
326
326
327 <tr>
327 <tr>
328 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
328 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
329 <td>unknown</td>
329 <td>unknown</td>
330 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
330 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
331 <td class="age">*</td> (glob)
331 <td class="age">*</td> (glob)
332 <td class="indexlinks"></td>
332 <td class="indexlinks"></td>
333 <td>
333 <td>
334 <a href="/rcoll/a/atom-log" title="subscribe to repository atom feed">
334 <a href="/rcoll/a/atom-log" title="subscribe to repository atom feed">
335 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
335 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
336 </a>
336 </a>
337 </td>
337 </td>
338 </tr>
338 </tr>
339
339
340 <tr>
340 <tr>
341 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
341 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
342 <td>unknown</td>
342 <td>unknown</td>
343 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
343 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
344 <td class="age">*</td> (glob)
344 <td class="age">*</td> (glob)
345 <td class="indexlinks"></td>
345 <td class="indexlinks"></td>
346 <td>
346 <td>
347 <a href="/rcoll/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
347 <a href="/rcoll/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
348 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
348 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
349 </a>
349 </a>
350 </td>
350 </td>
351 </tr>
351 </tr>
352
352
353 <tr>
353 <tr>
354 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
354 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
355 <td>unknown</td>
355 <td>unknown</td>
356 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
356 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
357 <td class="age">*</td> (glob)
357 <td class="age">*</td> (glob)
358 <td class="indexlinks"></td>
358 <td class="indexlinks"></td>
359 <td>
359 <td>
360 <a href="/rcoll/b/atom-log" title="subscribe to repository atom feed">
360 <a href="/rcoll/b/atom-log" title="subscribe to repository atom feed">
361 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
361 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
362 </a>
362 </a>
363 </td>
363 </td>
364 </tr>
364 </tr>
365
365
366 <tr>
366 <tr>
367 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
367 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
368 <td>unknown</td>
368 <td>unknown</td>
369 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
369 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
370 <td class="age">*</td> (glob)
370 <td class="age">*</td> (glob)
371 <td class="indexlinks"></td>
371 <td class="indexlinks"></td>
372 <td>
372 <td>
373 <a href="/rcoll/b/d/atom-log" title="subscribe to repository atom feed">
373 <a href="/rcoll/b/d/atom-log" title="subscribe to repository atom feed">
374 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
374 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
375 </a>
375 </a>
376 </td>
376 </td>
377 </tr>
377 </tr>
378
378
379 <tr>
379 <tr>
380 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
380 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
381 <td>unknown</td>
381 <td>unknown</td>
382 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
382 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
383 <td class="age">*</td> (glob)
383 <td class="age">*</td> (glob)
384 <td class="indexlinks"></td>
384 <td class="indexlinks"></td>
385 <td>
385 <td>
386 <a href="/rcoll/c/atom-log" title="subscribe to repository atom feed">
386 <a href="/rcoll/c/atom-log" title="subscribe to repository atom feed">
387 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
387 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
388 </a>
388 </a>
389 </td>
389 </td>
390 </tr>
390 </tr>
391
391
392 <tr>
392 <tr>
393 <td><a href="/rcoll/notrepo/e/?style=paper">rcoll/notrepo/e</a></td>
393 <td><a href="/rcoll/notrepo/e/?style=paper">rcoll/notrepo/e</a></td>
394 <td>unknown</td>
394 <td>unknown</td>
395 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
395 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
396 <td class="age">*</td> (glob)
396 <td class="age">*</td> (glob)
397 <td class="indexlinks"></td>
397 <td class="indexlinks"></td>
398 <td>
398 <td>
399 <a href="/rcoll/notrepo/e/atom-log" title="subscribe to repository atom feed">
399 <a href="/rcoll/notrepo/e/atom-log" title="subscribe to repository atom feed">
400 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
400 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
401 </a>
401 </a>
402 </td>
402 </td>
403 </tr>
403 </tr>
404
404
405 <tr>
405 <tr>
406 <td><a href="/rcoll/notrepo/e/e2/?style=paper">rcoll/notrepo/e/e2</a></td>
406 <td><a href="/rcoll/notrepo/e/e2/?style=paper">rcoll/notrepo/e/e2</a></td>
407 <td>unknown</td>
407 <td>unknown</td>
408 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
408 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
409 <td class="age">*</td> (glob)
409 <td class="age">*</td> (glob)
410 <td class="indexlinks"></td>
410 <td class="indexlinks"></td>
411 <td>
411 <td>
412 <a href="/rcoll/notrepo/e/e2/atom-log" title="subscribe to repository atom feed">
412 <a href="/rcoll/notrepo/e/e2/atom-log" title="subscribe to repository atom feed">
413 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
413 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
414 </a>
414 </a>
415 </td>
415 </td>
416 </tr>
416 </tr>
417
417
418 <tr>
418 <tr>
419 <td><a href="/rcoll/notrepo/f/?style=paper">fancy name for repo f</a></td>
419 <td><a href="/rcoll/notrepo/f/?style=paper">fancy name for repo f</a></td>
420 <td>unknown</td>
420 <td>unknown</td>
421 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
421 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
422 <td class="age">*</td> (glob)
422 <td class="age">*</td> (glob)
423 <td class="indexlinks"></td>
423 <td class="indexlinks"></td>
424 <td>
424 <td>
425 <a href="/rcoll/notrepo/f/atom-log" title="subscribe to repository atom feed">
425 <a href="/rcoll/notrepo/f/atom-log" title="subscribe to repository atom feed">
426 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
426 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
427 </a>
427 </a>
428 </td>
428 </td>
429 </tr>
429 </tr>
430
430
431 <tr>
431 <tr>
432 <td><a href="/rcoll/notrepo/f/f2/?style=paper">rcoll/notrepo/f/f2</a></td>
432 <td><a href="/rcoll/notrepo/f/f2/?style=paper">rcoll/notrepo/f/f2</a></td>
433 <td>unknown</td>
433 <td>unknown</td>
434 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
434 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
435 <td class="age">*</td> (glob)
435 <td class="age">*</td> (glob)
436 <td class="indexlinks"></td>
436 <td class="indexlinks"></td>
437 <td>
437 <td>
438 <a href="/rcoll/notrepo/f/f2/atom-log" title="subscribe to repository atom feed">
438 <a href="/rcoll/notrepo/f/f2/atom-log" title="subscribe to repository atom feed">
439 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
439 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
440 </a>
440 </a>
441 </td>
441 </td>
442 </tr>
442 </tr>
443
443
444 <tr>
444 <tr>
445 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
445 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
446 <td>unknown</td>
446 <td>unknown</td>
447 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
447 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
448 <td class="age">*</td> (glob)
448 <td class="age">*</td> (glob)
449 <td class="indexlinks"></td>
449 <td class="indexlinks"></td>
450 <td>
450 <td>
451 <a href="/star/webdir/a/atom-log" title="subscribe to repository atom feed">
451 <a href="/star/webdir/a/atom-log" title="subscribe to repository atom feed">
452 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
452 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
453 </a>
453 </a>
454 </td>
454 </td>
455 </tr>
455 </tr>
456
456
457 <tr>
457 <tr>
458 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
458 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
459 <td>unknown</td>
459 <td>unknown</td>
460 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
460 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
461 <td class="age">*</td> (glob)
461 <td class="age">*</td> (glob)
462 <td class="indexlinks"></td>
462 <td class="indexlinks"></td>
463 <td>
463 <td>
464 <a href="/star/webdir/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
464 <a href="/star/webdir/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
465 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
465 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
466 </a>
466 </a>
467 </td>
467 </td>
468 </tr>
468 </tr>
469
469
470 <tr>
470 <tr>
471 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
471 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
472 <td>unknown</td>
472 <td>unknown</td>
473 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
473 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
474 <td class="age">*</td> (glob)
474 <td class="age">*</td> (glob)
475 <td class="indexlinks"></td>
475 <td class="indexlinks"></td>
476 <td>
476 <td>
477 <a href="/star/webdir/b/atom-log" title="subscribe to repository atom feed">
477 <a href="/star/webdir/b/atom-log" title="subscribe to repository atom feed">
478 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
478 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
479 </a>
479 </a>
480 </td>
480 </td>
481 </tr>
481 </tr>
482
482
483 <tr>
483 <tr>
484 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
484 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
485 <td>unknown</td>
485 <td>unknown</td>
486 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
486 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
487 <td class="age">*</td> (glob)
487 <td class="age">*</td> (glob)
488 <td class="indexlinks"></td>
488 <td class="indexlinks"></td>
489 <td>
489 <td>
490 <a href="/star/webdir/c/atom-log" title="subscribe to repository atom feed">
490 <a href="/star/webdir/c/atom-log" title="subscribe to repository atom feed">
491 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
491 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
492 </a>
492 </a>
493 </td>
493 </td>
494 </tr>
494 </tr>
495
495
496 <tr>
496 <tr>
497 <td><a href="/star/webdir/notrepo/e/?style=paper">star/webdir/notrepo/e</a></td>
497 <td><a href="/star/webdir/notrepo/e/?style=paper">star/webdir/notrepo/e</a></td>
498 <td>unknown</td>
498 <td>unknown</td>
499 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
499 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
500 <td class="age">*</td> (glob)
500 <td class="age">*</td> (glob)
501 <td class="indexlinks"></td>
501 <td class="indexlinks"></td>
502 <td>
502 <td>
503 <a href="/star/webdir/notrepo/e/atom-log" title="subscribe to repository atom feed">
503 <a href="/star/webdir/notrepo/e/atom-log" title="subscribe to repository atom feed">
504 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
504 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
505 </a>
505 </a>
506 </td>
506 </td>
507 </tr>
507 </tr>
508
508
509 <tr>
509 <tr>
510 <td><a href="/star/webdir/notrepo/f/?style=paper">fancy name for repo f</a></td>
510 <td><a href="/star/webdir/notrepo/f/?style=paper">fancy name for repo f</a></td>
511 <td>unknown</td>
511 <td>unknown</td>
512 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
512 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
513 <td class="age">*</td> (glob)
513 <td class="age">*</td> (glob)
514 <td class="indexlinks"></td>
514 <td class="indexlinks"></td>
515 <td>
515 <td>
516 <a href="/star/webdir/notrepo/f/atom-log" title="subscribe to repository atom feed">
516 <a href="/star/webdir/notrepo/f/atom-log" title="subscribe to repository atom feed">
517 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
517 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
518 </a>
518 </a>
519 </td>
519 </td>
520 </tr>
520 </tr>
521
521
522 <tr>
522 <tr>
523 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
523 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
524 <td>unknown</td>
524 <td>unknown</td>
525 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
525 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
526 <td class="age">*</td> (glob)
526 <td class="age">*</td> (glob)
527 <td class="indexlinks"></td>
527 <td class="indexlinks"></td>
528 <td>
528 <td>
529 <a href="/starstar/webdir/a/atom-log" title="subscribe to repository atom feed">
529 <a href="/starstar/webdir/a/atom-log" title="subscribe to repository atom feed">
530 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
530 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
531 </a>
531 </a>
532 </td>
532 </td>
533 </tr>
533 </tr>
534
534
535 <tr>
535 <tr>
536 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
536 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
537 <td>unknown</td>
537 <td>unknown</td>
538 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
538 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
539 <td class="age">*</td> (glob)
539 <td class="age">*</td> (glob)
540 <td class="indexlinks"></td>
540 <td class="indexlinks"></td>
541 <td>
541 <td>
542 <a href="/starstar/webdir/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
542 <a href="/starstar/webdir/a/.hg/patches/atom-log" title="subscribe to repository atom feed">
543 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
543 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
544 </a>
544 </a>
545 </td>
545 </td>
546 </tr>
546 </tr>
547
547
548 <tr>
548 <tr>
549 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
549 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
550 <td>unknown</td>
550 <td>unknown</td>
551 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
551 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
552 <td class="age">*</td> (glob)
552 <td class="age">*</td> (glob)
553 <td class="indexlinks"></td>
553 <td class="indexlinks"></td>
554 <td>
554 <td>
555 <a href="/starstar/webdir/b/atom-log" title="subscribe to repository atom feed">
555 <a href="/starstar/webdir/b/atom-log" title="subscribe to repository atom feed">
556 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
556 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
557 </a>
557 </a>
558 </td>
558 </td>
559 </tr>
559 </tr>
560
560
561 <tr>
561 <tr>
562 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
562 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
563 <td>unknown</td>
563 <td>unknown</td>
564 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
564 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
565 <td class="age">*</td> (glob)
565 <td class="age">*</td> (glob)
566 <td class="indexlinks"></td>
566 <td class="indexlinks"></td>
567 <td>
567 <td>
568 <a href="/starstar/webdir/b/d/atom-log" title="subscribe to repository atom feed">
568 <a href="/starstar/webdir/b/d/atom-log" title="subscribe to repository atom feed">
569 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
569 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
570 </a>
570 </a>
571 </td>
571 </td>
572 </tr>
572 </tr>
573
573
574 <tr>
574 <tr>
575 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
575 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
576 <td>unknown</td>
576 <td>unknown</td>
577 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
577 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
578 <td class="age">*</td> (glob)
578 <td class="age">*</td> (glob)
579 <td class="indexlinks"></td>
579 <td class="indexlinks"></td>
580 <td>
580 <td>
581 <a href="/starstar/webdir/c/atom-log" title="subscribe to repository atom feed">
581 <a href="/starstar/webdir/c/atom-log" title="subscribe to repository atom feed">
582 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
582 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
583 </a>
583 </a>
584 </td>
584 </td>
585 </tr>
585 </tr>
586
586
587 <tr>
587 <tr>
588 <td><a href="/starstar/webdir/notrepo/e/?style=paper">starstar/webdir/notrepo/e</a></td>
588 <td><a href="/starstar/webdir/notrepo/e/?style=paper">starstar/webdir/notrepo/e</a></td>
589 <td>unknown</td>
589 <td>unknown</td>
590 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
590 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
591 <td class="age">*</td> (glob)
591 <td class="age">*</td> (glob)
592 <td class="indexlinks"></td>
592 <td class="indexlinks"></td>
593 <td>
593 <td>
594 <a href="/starstar/webdir/notrepo/e/atom-log" title="subscribe to repository atom feed">
594 <a href="/starstar/webdir/notrepo/e/atom-log" title="subscribe to repository atom feed">
595 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
595 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
596 </a>
596 </a>
597 </td>
597 </td>
598 </tr>
598 </tr>
599
599
600 <tr>
600 <tr>
601 <td><a href="/starstar/webdir/notrepo/e/e2/?style=paper">starstar/webdir/notrepo/e/e2</a></td>
601 <td><a href="/starstar/webdir/notrepo/e/e2/?style=paper">starstar/webdir/notrepo/e/e2</a></td>
602 <td>unknown</td>
602 <td>unknown</td>
603 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
603 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
604 <td class="age">*</td> (glob)
604 <td class="age">*</td> (glob)
605 <td class="indexlinks"></td>
605 <td class="indexlinks"></td>
606 <td>
606 <td>
607 <a href="/starstar/webdir/notrepo/e/e2/atom-log" title="subscribe to repository atom feed">
607 <a href="/starstar/webdir/notrepo/e/e2/atom-log" title="subscribe to repository atom feed">
608 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
608 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
609 </a>
609 </a>
610 </td>
610 </td>
611 </tr>
611 </tr>
612
612
613 <tr>
613 <tr>
614 <td><a href="/starstar/webdir/notrepo/f/?style=paper">fancy name for repo f</a></td>
614 <td><a href="/starstar/webdir/notrepo/f/?style=paper">fancy name for repo f</a></td>
615 <td>unknown</td>
615 <td>unknown</td>
616 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
616 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
617 <td class="age">*</td> (glob)
617 <td class="age">*</td> (glob)
618 <td class="indexlinks"></td>
618 <td class="indexlinks"></td>
619 <td>
619 <td>
620 <a href="/starstar/webdir/notrepo/f/atom-log" title="subscribe to repository atom feed">
620 <a href="/starstar/webdir/notrepo/f/atom-log" title="subscribe to repository atom feed">
621 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
621 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
622 </a>
622 </a>
623 </td>
623 </td>
624 </tr>
624 </tr>
625
625
626 <tr>
626 <tr>
627 <td><a href="/starstar/webdir/notrepo/f/f2/?style=paper">starstar/webdir/notrepo/f/f2</a></td>
627 <td><a href="/starstar/webdir/notrepo/f/f2/?style=paper">starstar/webdir/notrepo/f/f2</a></td>
628 <td>unknown</td>
628 <td>unknown</td>
629 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
629 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
630 <td class="age">*</td> (glob)
630 <td class="age">*</td> (glob)
631 <td class="indexlinks"></td>
631 <td class="indexlinks"></td>
632 <td>
632 <td>
633 <a href="/starstar/webdir/notrepo/f/f2/atom-log" title="subscribe to repository atom feed">
633 <a href="/starstar/webdir/notrepo/f/f2/atom-log" title="subscribe to repository atom feed">
634 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
634 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
635 </a>
635 </a>
636 </td>
636 </td>
637 </tr>
637 </tr>
638
638
639 <tr>
639 <tr>
640 <td><a href="/astar/?style=paper">astar</a></td>
640 <td><a href="/astar/?style=paper">astar</a></td>
641 <td>unknown</td>
641 <td>unknown</td>
642 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
642 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
643 <td class="age">*</td> (glob)
643 <td class="age">*</td> (glob)
644 <td class="indexlinks"></td>
644 <td class="indexlinks"></td>
645 <td>
645 <td>
646 <a href="/astar/atom-log" title="subscribe to repository atom feed">
646 <a href="/astar/atom-log" title="subscribe to repository atom feed">
647 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
647 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
648 </a>
648 </a>
649 </td>
649 </td>
650 </tr>
650 </tr>
651
651
652 <tr>
652 <tr>
653 <td><a href="/astar/.hg/patches/?style=paper">astar/.hg/patches</a></td>
653 <td><a href="/astar/.hg/patches/?style=paper">astar/.hg/patches</a></td>
654 <td>unknown</td>
654 <td>unknown</td>
655 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
655 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
656 <td class="age">*</td> (glob)
656 <td class="age">*</td> (glob)
657 <td class="indexlinks"></td>
657 <td class="indexlinks"></td>
658 <td>
658 <td>
659 <a href="/astar/.hg/patches/atom-log" title="subscribe to repository atom feed">
659 <a href="/astar/.hg/patches/atom-log" title="subscribe to repository atom feed">
660 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
660 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
661 </a>
661 </a>
662 </td>
662 </td>
663 </tr>
663 </tr>
664
664
665 </tbody>
665 </tbody>
666 </table>
666 </table>
667 </div>
667 </div>
668 </div>
668 </div>
669 <script type="text/javascript">process_dates()</script>
669 <script type="text/javascript">process_dates()</script>
670
670
671
671
672 </body>
672 </body>
673 </html>
673 </html>
674
674
675 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't?style=raw'
675 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't?style=raw'
676 200 Script output follows
676 200 Script output follows
677
677
678
678
679 /t/a/
679 /t/a/
680
680
681 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
681 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
682 200 Script output follows
682 200 Script output follows
683
683
684
684
685 /t/a/
685 /t/a/
686
686
687 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=paper'
687 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=paper'
688 200 Script output follows
688 200 Script output follows
689
689
690 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
690 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
691 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
691 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
692 <head>
692 <head>
693 <link rel="icon" href="/static/hgicon.png" type="image/png" />
693 <link rel="icon" href="/static/hgicon.png" type="image/png" />
694 <meta name="robots" content="index, nofollow" />
694 <meta name="robots" content="index, nofollow" />
695 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
695 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
696 <script type="text/javascript" src="/static/mercurial.js"></script>
696 <script type="text/javascript" src="/static/mercurial.js"></script>
697
697
698 <title>Mercurial repositories index</title>
698 <title>Mercurial repositories index</title>
699 </head>
699 </head>
700 <body>
700 <body>
701
701
702 <div class="container">
702 <div class="container">
703 <div class="menu">
703 <div class="menu">
704 <a href="http://mercurial.selenic.com/">
704 <a href="http://mercurial.selenic.com/">
705 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
705 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
706 </div>
706 </div>
707 <div class="main">
707 <div class="main">
708 <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/t">t</a> </h2>
708 <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/t">t</a> </h2>
709
709
710 <table class="bigtable">
710 <table class="bigtable">
711 <thead>
711 <thead>
712 <tr>
712 <tr>
713 <th><a href="?sort=name">Name</a></th>
713 <th><a href="?sort=name">Name</a></th>
714 <th><a href="?sort=description">Description</a></th>
714 <th><a href="?sort=description">Description</a></th>
715 <th><a href="?sort=contact">Contact</a></th>
715 <th><a href="?sort=contact">Contact</a></th>
716 <th><a href="?sort=lastchange">Last modified</a></th>
716 <th><a href="?sort=lastchange">Last modified</a></th>
717 <th>&nbsp;</th>
717 <th>&nbsp;</th>
718 <th>&nbsp;</th>
718 <th>&nbsp;</th>
719 </tr>
719 </tr>
720 </thead>
720 </thead>
721 <tbody class="stripes2">
721 <tbody class="stripes2">
722
722
723 <tr>
723 <tr>
724 <td><a href="/t/a/?style=paper">a</a></td>
724 <td><a href="/t/a/?style=paper">a</a></td>
725 <td>unknown</td>
725 <td>unknown</td>
726 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
726 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
727 <td class="age">*</td> (glob)
727 <td class="age">*</td> (glob)
728 <td class="indexlinks"></td>
728 <td class="indexlinks"></td>
729 <td>
729 <td>
730 <a href="/t/a/atom-log" title="subscribe to repository atom feed">
730 <a href="/t/a/atom-log" title="subscribe to repository atom feed">
731 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
731 <img class="atom-logo" src="/static/feed-icon-14x14.png" alt="subscribe to repository atom feed">
732 </a>
732 </a>
733 </td>
733 </td>
734 </tr>
734 </tr>
735
735
736 </tbody>
736 </tbody>
737 </table>
737 </table>
738 </div>
738 </div>
739 </div>
739 </div>
740 <script type="text/javascript">process_dates()</script>
740 <script type="text/javascript">process_dates()</script>
741
741
742
742
743 </body>
743 </body>
744 </html>
744 </html>
745
745
746 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a?style=atom'
746 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a?style=atom'
747 200 Script output follows
747 200 Script output follows
748
748
749 <?xml version="1.0" encoding="ascii"?>
749 <?xml version="1.0" encoding="ascii"?>
750 <feed xmlns="http://www.w3.org/2005/Atom">
750 <feed xmlns="http://www.w3.org/2005/Atom">
751 <!-- Changelog -->
751 <!-- Changelog -->
752 <id>http://*:$HGPORT1/t/a/</id> (glob)
752 <id>http://*:$HGPORT1/t/a/</id> (glob)
753 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
753 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
754 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
754 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
755 <title>t/a Changelog</title>
755 <title>t/a Changelog</title>
756 <updated>1970-01-01T00:00:01+00:00</updated>
756 <updated>1970-01-01T00:00:01+00:00</updated>
757
757
758 <entry>
758 <entry>
759 <title>[default] a</title>
759 <title>[default] a</title>
760 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
760 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
761 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
761 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
762 <author>
762 <author>
763 <name>test</name>
763 <name>test</name>
764 <email>&#116;&#101;&#115;&#116;</email>
764 <email>&#116;&#101;&#115;&#116;</email>
765 </author>
765 </author>
766 <updated>1970-01-01T00:00:01+00:00</updated>
766 <updated>1970-01-01T00:00:01+00:00</updated>
767 <published>1970-01-01T00:00:01+00:00</published>
767 <published>1970-01-01T00:00:01+00:00</published>
768 <content type="xhtml">
768 <content type="xhtml">
769 <table xmlns="http://www.w3.org/1999/xhtml">
769 <table xmlns="http://www.w3.org/1999/xhtml">
770 <tr>
770 <tr>
771 <th style="text-align:left;">changeset</th>
771 <th style="text-align:left;">changeset</th>
772 <td>8580ff50825a</td>
772 <td>8580ff50825a</td>
773 </tr>
773 </tr>
774 <tr>
774 <tr>
775 <th style="text-align:left;">branch</th>
775 <th style="text-align:left;">branch</th>
776 <td>default</td>
776 <td>default</td>
777 </tr>
777 </tr>
778 <tr>
778 <tr>
779 <th style="text-align:left;">bookmark</th>
779 <th style="text-align:left;">bookmark</th>
780 <td></td>
780 <td></td>
781 </tr>
781 </tr>
782 <tr>
782 <tr>
783 <th style="text-align:left;">tag</th>
783 <th style="text-align:left;">tag</th>
784 <td>tip</td>
784 <td>tip</td>
785 </tr>
785 </tr>
786 <tr>
786 <tr>
787 <th style="text-align:left;">user</th>
787 <th style="text-align:left;">user</th>
788 <td>&#116;&#101;&#115;&#116;</td>
788 <td>&#116;&#101;&#115;&#116;</td>
789 </tr>
789 </tr>
790 <tr>
790 <tr>
791 <th style="text-align:left;vertical-align:top;">description</th>
791 <th style="text-align:left;vertical-align:top;">description</th>
792 <td>a</td>
792 <td>a</td>
793 </tr>
793 </tr>
794 <tr>
794 <tr>
795 <th style="text-align:left;vertical-align:top;">files</th>
795 <th style="text-align:left;vertical-align:top;">files</th>
796 <td>a<br /></td>
796 <td>a<br /></td>
797 </tr>
797 </tr>
798 </table>
798 </table>
799 </content>
799 </content>
800 </entry>
800 </entry>
801
801
802 </feed>
802 </feed>
803 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/?style=atom'
803 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/?style=atom'
804 200 Script output follows
804 200 Script output follows
805
805
806 <?xml version="1.0" encoding="ascii"?>
806 <?xml version="1.0" encoding="ascii"?>
807 <feed xmlns="http://www.w3.org/2005/Atom">
807 <feed xmlns="http://www.w3.org/2005/Atom">
808 <!-- Changelog -->
808 <!-- Changelog -->
809 <id>http://*:$HGPORT1/t/a/</id> (glob)
809 <id>http://*:$HGPORT1/t/a/</id> (glob)
810 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
810 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
811 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
811 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
812 <title>t/a Changelog</title>
812 <title>t/a Changelog</title>
813 <updated>1970-01-01T00:00:01+00:00</updated>
813 <updated>1970-01-01T00:00:01+00:00</updated>
814
814
815 <entry>
815 <entry>
816 <title>[default] a</title>
816 <title>[default] a</title>
817 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
817 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
818 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
818 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
819 <author>
819 <author>
820 <name>test</name>
820 <name>test</name>
821 <email>&#116;&#101;&#115;&#116;</email>
821 <email>&#116;&#101;&#115;&#116;</email>
822 </author>
822 </author>
823 <updated>1970-01-01T00:00:01+00:00</updated>
823 <updated>1970-01-01T00:00:01+00:00</updated>
824 <published>1970-01-01T00:00:01+00:00</published>
824 <published>1970-01-01T00:00:01+00:00</published>
825 <content type="xhtml">
825 <content type="xhtml">
826 <table xmlns="http://www.w3.org/1999/xhtml">
826 <table xmlns="http://www.w3.org/1999/xhtml">
827 <tr>
827 <tr>
828 <th style="text-align:left;">changeset</th>
828 <th style="text-align:left;">changeset</th>
829 <td>8580ff50825a</td>
829 <td>8580ff50825a</td>
830 </tr>
830 </tr>
831 <tr>
831 <tr>
832 <th style="text-align:left;">branch</th>
832 <th style="text-align:left;">branch</th>
833 <td>default</td>
833 <td>default</td>
834 </tr>
834 </tr>
835 <tr>
835 <tr>
836 <th style="text-align:left;">bookmark</th>
836 <th style="text-align:left;">bookmark</th>
837 <td></td>
837 <td></td>
838 </tr>
838 </tr>
839 <tr>
839 <tr>
840 <th style="text-align:left;">tag</th>
840 <th style="text-align:left;">tag</th>
841 <td>tip</td>
841 <td>tip</td>
842 </tr>
842 </tr>
843 <tr>
843 <tr>
844 <th style="text-align:left;">user</th>
844 <th style="text-align:left;">user</th>
845 <td>&#116;&#101;&#115;&#116;</td>
845 <td>&#116;&#101;&#115;&#116;</td>
846 </tr>
846 </tr>
847 <tr>
847 <tr>
848 <th style="text-align:left;vertical-align:top;">description</th>
848 <th style="text-align:left;vertical-align:top;">description</th>
849 <td>a</td>
849 <td>a</td>
850 </tr>
850 </tr>
851 <tr>
851 <tr>
852 <th style="text-align:left;vertical-align:top;">files</th>
852 <th style="text-align:left;vertical-align:top;">files</th>
853 <td>a<br /></td>
853 <td>a<br /></td>
854 </tr>
854 </tr>
855 </table>
855 </table>
856 </content>
856 </content>
857 </entry>
857 </entry>
858
858
859 </feed>
859 </feed>
860 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/file/tip/a?style=raw'
860 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/file/tip/a?style=raw'
861 200 Script output follows
861 200 Script output follows
862
862
863 a
863 a
864
864
865 Test [paths] '*' extension
865 Test [paths] '*' extension
866
866
867 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
867 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
868 200 Script output follows
868 200 Script output follows
869
869
870
870
871 /coll/a/
871 /coll/a/
872 /coll/a/.hg/patches/
872 /coll/a/.hg/patches/
873 /coll/b/
873 /coll/b/
874 /coll/c/
874 /coll/c/
875 /coll/notrepo/e/
875 /coll/notrepo/e/
876 /coll/notrepo/f/
876 /coll/notrepo/f/
877
877
878 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
878 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
879 200 Script output follows
879 200 Script output follows
880
880
881 a
881 a
882
882
883 Test [paths] '**' extension
883 Test [paths] '**' extension
884
884
885 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
885 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
886 200 Script output follows
886 200 Script output follows
887
887
888
888
889 /rcoll/a/
889 /rcoll/a/
890 /rcoll/a/.hg/patches/
890 /rcoll/a/.hg/patches/
891 /rcoll/b/
891 /rcoll/b/
892 /rcoll/b/d/
892 /rcoll/b/d/
893 /rcoll/c/
893 /rcoll/c/
894 /rcoll/notrepo/e/
894 /rcoll/notrepo/e/
895 /rcoll/notrepo/e/e2/
895 /rcoll/notrepo/e/e2/
896 /rcoll/notrepo/f/
896 /rcoll/notrepo/f/
897 /rcoll/notrepo/f/f2/
897 /rcoll/notrepo/f/f2/
898
898
899 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
899 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
900 200 Script output follows
900 200 Script output follows
901
901
902 d
902 d
903
903
904 Test collapse = True
904 Test collapse = True
905
905
906 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
906 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
907 $ cat >> paths.conf <<EOF
907 $ cat >> paths.conf <<EOF
908 > [web]
908 > [web]
909 > collapse=true
909 > collapse=true
910 > descend = true
910 > descend = true
911 > EOF
911 > EOF
912 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
912 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
913 > -A access-paths.log -E error-paths-3.log
913 > -A access-paths.log -E error-paths-3.log
914 $ cat hg.pid >> $DAEMON_PIDS
914 $ cat hg.pid >> $DAEMON_PIDS
915 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
915 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
916 200 Script output follows
916 200 Script output follows
917
917
918
918
919 /coll/a/
919 /coll/a/
920 /coll/a/.hg/patches/
920 /coll/a/.hg/patches/
921 /coll/b/
921 /coll/b/
922 /coll/c/
922 /coll/c/
923 /coll/notrepo/
923 /coll/notrepo/
924
924
925 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
925 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
926 200 Script output follows
926 200 Script output follows
927
927
928 a
928 a
929 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
929 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
930 200 Script output follows
930 200 Script output follows
931
931
932
932
933 /rcoll/a/
933 /rcoll/a/
934 /rcoll/a/.hg/patches/
934 /rcoll/a/.hg/patches/
935 /rcoll/b/
935 /rcoll/b/
936 /rcoll/b/d/
936 /rcoll/b/d/
937 /rcoll/c/
937 /rcoll/c/
938 /rcoll/notrepo/
938 /rcoll/notrepo/
939
939
940 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
940 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
941 200 Script output follows
941 200 Script output follows
942
942
943 d
943 d
944
944
945 Test intermediate directories
945 Test intermediate directories
946
946
947 Hide the subrepo parent
948
949 $ cp $root/notrepo/f/.hg/hgrc $root/notrepo/f/.hg/hgrc.bak
950 $ cat >> $root/notrepo/f/.hg/hgrc << EOF
951 > [web]
952 > hidden = True
953 > EOF
954
955 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
956 200 Script output follows
957
958
959 /rcoll/notrepo/e/
960 /rcoll/notrepo/e/e2/
961
962
963 Subrepo parent not hidden
964 $ mv $root/notrepo/f/.hg/hgrc.bak $root/notrepo/f/.hg/hgrc
965
947 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
966 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
948 200 Script output follows
967 200 Script output follows
949
968
950
969
951 /rcoll/notrepo/e/
970 /rcoll/notrepo/e/
952 /rcoll/notrepo/e/e2/
971 /rcoll/notrepo/e/e2/
953 /rcoll/notrepo/f/
972 /rcoll/notrepo/f/
954 /rcoll/notrepo/f/f2/
973 /rcoll/notrepo/f/f2/
955
974
956
975
957 Test repositories inside intermediate directories
976 Test repositories inside intermediate directories
958
977
959 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
978 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
960 200 Script output follows
979 200 Script output follows
961
980
962 e
981 e
963
982
964 Test subrepositories inside intermediate directories
983 Test subrepositories inside intermediate directories
965
984
966 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
985 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
967 200 Script output follows
986 200 Script output follows
968
987
969 f2
988 f2
970
989
971 Test descend = False
990 Test descend = False
972
991
973 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
992 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
974 $ cat >> paths.conf <<EOF
993 $ cat >> paths.conf <<EOF
975 > descend=false
994 > descend=false
976 > EOF
995 > EOF
977 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
996 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
978 > -A access-paths.log -E error-paths-4.log
997 > -A access-paths.log -E error-paths-4.log
979 $ cat hg.pid >> $DAEMON_PIDS
998 $ cat hg.pid >> $DAEMON_PIDS
980 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
999 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
981 200 Script output follows
1000 200 Script output follows
982
1001
983
1002
984 /coll/a/
1003 /coll/a/
985 /coll/b/
1004 /coll/b/
986 /coll/c/
1005 /coll/c/
987
1006
988 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
1007 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
989 200 Script output follows
1008 200 Script output follows
990
1009
991 a
1010 a
992 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
1011 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
993 200 Script output follows
1012 200 Script output follows
994
1013
995
1014
996 /rcoll/a/
1015 /rcoll/a/
997 /rcoll/b/
1016 /rcoll/b/
998 /rcoll/c/
1017 /rcoll/c/
999
1018
1000 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
1019 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
1001 200 Script output follows
1020 200 Script output follows
1002
1021
1003 d
1022 d
1004
1023
1005 Test intermediate directories
1024 Test intermediate directories
1006
1025
1007 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
1026 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
1008 200 Script output follows
1027 200 Script output follows
1009
1028
1010
1029
1011 /rcoll/notrepo/e/
1030 /rcoll/notrepo/e/
1012 /rcoll/notrepo/f/
1031 /rcoll/notrepo/f/
1013
1032
1014
1033
1015 Test repositories inside intermediate directories
1034 Test repositories inside intermediate directories
1016
1035
1017 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
1036 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
1018 200 Script output follows
1037 200 Script output follows
1019
1038
1020 e
1039 e
1021
1040
1022 Test subrepositories inside intermediate directories
1041 Test subrepositories inside intermediate directories
1023
1042
1024 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
1043 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
1025 200 Script output follows
1044 200 Script output follows
1026
1045
1027 f2
1046 f2
1028
1047
1029 Test [paths] '*' in a repo root
1048 Test [paths] '*' in a repo root
1030
1049
1031 $ hg id http://localhost:$HGPORT1/astar
1050 $ hg id http://localhost:$HGPORT1/astar
1032 8580ff50825a
1051 8580ff50825a
1033
1052
1034 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1053 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1035 $ cat > paths.conf <<EOF
1054 $ cat > paths.conf <<EOF
1036 > [paths]
1055 > [paths]
1037 > t/a = $root/a
1056 > t/a = $root/a
1038 > t/b = $root/b
1057 > t/b = $root/b
1039 > c = $root/c
1058 > c = $root/c
1040 > EOF
1059 > EOF
1041 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1060 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1042 > -A access-paths.log -E error-paths-5.log
1061 > -A access-paths.log -E error-paths-5.log
1043 $ cat hg.pid >> $DAEMON_PIDS
1062 $ cat hg.pid >> $DAEMON_PIDS
1044 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1063 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1045 200 Script output follows
1064 200 Script output follows
1046
1065
1047
1066
1048 /t/a/
1067 /t/a/
1049 /t/b/
1068 /t/b/
1050 /c/
1069 /c/
1051
1070
1052 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1071 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1053 200 Script output follows
1072 200 Script output follows
1054
1073
1055
1074
1056 /t/a/
1075 /t/a/
1057 /t/b/
1076 /t/b/
1058
1077
1059
1078
1060 Test collapse = True
1079 Test collapse = True
1061
1080
1062 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1081 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1063 $ cat >> paths.conf <<EOF
1082 $ cat >> paths.conf <<EOF
1064 > [web]
1083 > [web]
1065 > collapse=true
1084 > collapse=true
1066 > EOF
1085 > EOF
1067 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1086 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1068 > -A access-paths.log -E error-paths-6.log
1087 > -A access-paths.log -E error-paths-6.log
1069 $ cat hg.pid >> $DAEMON_PIDS
1088 $ cat hg.pid >> $DAEMON_PIDS
1070 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1089 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1071 200 Script output follows
1090 200 Script output follows
1072
1091
1073
1092
1074 /t/
1093 /t/
1075 /c/
1094 /c/
1076
1095
1077 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1096 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1078 200 Script output follows
1097 200 Script output follows
1079
1098
1080
1099
1081 /t/a/
1100 /t/a/
1082 /t/b/
1101 /t/b/
1083
1102
1084
1103
1085 test descend = False
1104 test descend = False
1086
1105
1087 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1106 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1088 $ cat >> paths.conf <<EOF
1107 $ cat >> paths.conf <<EOF
1089 > descend=false
1108 > descend=false
1090 > EOF
1109 > EOF
1091 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1110 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1092 > -A access-paths.log -E error-paths-7.log
1111 > -A access-paths.log -E error-paths-7.log
1093 $ cat hg.pid >> $DAEMON_PIDS
1112 $ cat hg.pid >> $DAEMON_PIDS
1094 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1113 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
1095 200 Script output follows
1114 200 Script output follows
1096
1115
1097
1116
1098 /c/
1117 /c/
1099
1118
1100 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1119 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
1101 200 Script output follows
1120 200 Script output follows
1102
1121
1103
1122
1104 /t/a/
1123 /t/a/
1105 /t/b/
1124 /t/b/
1106
1125
1107 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1126 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1108 $ cat > paths.conf <<EOF
1127 $ cat > paths.conf <<EOF
1109 > [paths]
1128 > [paths]
1110 > nostore = $root/nostore
1129 > nostore = $root/nostore
1111 > inexistent = $root/inexistent
1130 > inexistent = $root/inexistent
1112 > EOF
1131 > EOF
1113 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1132 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
1114 > -A access-paths.log -E error-paths-8.log
1133 > -A access-paths.log -E error-paths-8.log
1115 $ cat hg.pid >> $DAEMON_PIDS
1134 $ cat hg.pid >> $DAEMON_PIDS
1116
1135
1117 test inexistent and inaccessible repo should be ignored silently
1136 test inexistent and inaccessible repo should be ignored silently
1118
1137
1119 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 ''
1138 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 ''
1120 200 Script output follows
1139 200 Script output follows
1121
1140
1122 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1141 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
1123 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1142 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1124 <head>
1143 <head>
1125 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1144 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1126 <meta name="robots" content="index, nofollow" />
1145 <meta name="robots" content="index, nofollow" />
1127 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1146 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1128 <script type="text/javascript" src="/static/mercurial.js"></script>
1147 <script type="text/javascript" src="/static/mercurial.js"></script>
1129
1148
1130 <title>Mercurial repositories index</title>
1149 <title>Mercurial repositories index</title>
1131 </head>
1150 </head>
1132 <body>
1151 <body>
1133
1152
1134 <div class="container">
1153 <div class="container">
1135 <div class="menu">
1154 <div class="menu">
1136 <a href="http://mercurial.selenic.com/">
1155 <a href="http://mercurial.selenic.com/">
1137 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
1156 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
1138 </div>
1157 </div>
1139 <div class="main">
1158 <div class="main">
1140 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1159 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1141
1160
1142 <table class="bigtable">
1161 <table class="bigtable">
1143 <thead>
1162 <thead>
1144 <tr>
1163 <tr>
1145 <th><a href="?sort=name">Name</a></th>
1164 <th><a href="?sort=name">Name</a></th>
1146 <th><a href="?sort=description">Description</a></th>
1165 <th><a href="?sort=description">Description</a></th>
1147 <th><a href="?sort=contact">Contact</a></th>
1166 <th><a href="?sort=contact">Contact</a></th>
1148 <th><a href="?sort=lastchange">Last modified</a></th>
1167 <th><a href="?sort=lastchange">Last modified</a></th>
1149 <th>&nbsp;</th>
1168 <th>&nbsp;</th>
1150 <th>&nbsp;</th>
1169 <th>&nbsp;</th>
1151 </tr>
1170 </tr>
1152 </thead>
1171 </thead>
1153 <tbody class="stripes2">
1172 <tbody class="stripes2">
1154
1173
1155 </tbody>
1174 </tbody>
1156 </table>
1175 </table>
1157 </div>
1176 </div>
1158 </div>
1177 </div>
1159 <script type="text/javascript">process_dates()</script>
1178 <script type="text/javascript">process_dates()</script>
1160
1179
1161
1180
1162 </body>
1181 </body>
1163 </html>
1182 </html>
1164
1183
1165 $ cat > collections.conf <<EOF
1184 $ cat > collections.conf <<EOF
1166 > [collections]
1185 > [collections]
1167 > $root=$root
1186 > $root=$root
1168 > EOF
1187 > EOF
1169 $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
1188 $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
1170 > --pid-file=hg.pid --webdir-conf collections.conf \
1189 > --pid-file=hg.pid --webdir-conf collections.conf \
1171 > -A access-collections.log -E error-collections.log
1190 > -A access-collections.log -E error-collections.log
1172 $ cat hg.pid >> $DAEMON_PIDS
1191 $ cat hg.pid >> $DAEMON_PIDS
1173
1192
1174 collections: should succeed
1193 collections: should succeed
1175
1194
1176 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
1195 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
1177 200 Script output follows
1196 200 Script output follows
1178
1197
1179
1198
1180 /a/
1199 /a/
1181 /a/.hg/patches/
1200 /a/.hg/patches/
1182 /b/
1201 /b/
1183 /c/
1202 /c/
1184 /notrepo/e/
1203 /notrepo/e/
1185 /notrepo/f/
1204 /notrepo/f/
1186
1205
1187 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/file/tip/a?style=raw'
1206 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/file/tip/a?style=raw'
1188 200 Script output follows
1207 200 Script output follows
1189
1208
1190 a
1209 a
1191 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'b/file/tip/b?style=raw'
1210 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'b/file/tip/b?style=raw'
1192 200 Script output follows
1211 200 Script output follows
1193
1212
1194 b
1213 b
1195 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'c/file/tip/c?style=raw'
1214 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'c/file/tip/c?style=raw'
1196 200 Script output follows
1215 200 Script output follows
1197
1216
1198 c
1217 c
1199
1218
1200 atom-log with basedir /
1219 atom-log with basedir /
1201
1220
1202 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
1221 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
1203 <link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
1222 <link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
1204 <link rel="alternate" href="http://hg.example.com:8080/a/"/>
1223 <link rel="alternate" href="http://hg.example.com:8080/a/"/>
1205 <link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
1224 <link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
1206
1225
1207 rss-log with basedir /
1226 rss-log with basedir /
1208
1227
1209 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
1228 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
1210 <guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
1229 <guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
1211 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1230 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
1212 $ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
1231 $ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
1213 > --pid-file=hg.pid --webdir-conf collections.conf \
1232 > --pid-file=hg.pid --webdir-conf collections.conf \
1214 > -A access-collections-2.log -E error-collections-2.log
1233 > -A access-collections-2.log -E error-collections-2.log
1215 $ cat hg.pid >> $DAEMON_PIDS
1234 $ cat hg.pid >> $DAEMON_PIDS
1216
1235
1217 atom-log with basedir /foo/
1236 atom-log with basedir /foo/
1218
1237
1219 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
1238 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
1220 <link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
1239 <link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
1221 <link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
1240 <link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
1222 <link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
1241 <link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
1223
1242
1224 rss-log with basedir /foo/
1243 rss-log with basedir /foo/
1225
1244
1226 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
1245 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
1227 <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
1246 <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
1228
1247
1229 paths errors 1
1248 paths errors 1
1230
1249
1231 $ cat error-paths-1.log
1250 $ cat error-paths-1.log
1232
1251
1233 paths errors 2
1252 paths errors 2
1234
1253
1235 $ cat error-paths-2.log
1254 $ cat error-paths-2.log
1236
1255
1237 paths errors 3
1256 paths errors 3
1238
1257
1239 $ cat error-paths-3.log
1258 $ cat error-paths-3.log
1240
1259
1241 paths errors 4
1260 paths errors 4
1242
1261
1243 $ cat error-paths-4.log
1262 $ cat error-paths-4.log
1244
1263
1245 paths errors 5
1264 paths errors 5
1246
1265
1247 $ cat error-paths-5.log
1266 $ cat error-paths-5.log
1248
1267
1249 paths errors 6
1268 paths errors 6
1250
1269
1251 $ cat error-paths-6.log
1270 $ cat error-paths-6.log
1252
1271
1253 paths errors 7
1272 paths errors 7
1254
1273
1255 $ cat error-paths-7.log
1274 $ cat error-paths-7.log
1256
1275
1257 paths errors 8
1276 paths errors 8
1258
1277
1259 $ cat error-paths-8.log
1278 $ cat error-paths-8.log
1260
1279
1261 collections errors
1280 collections errors
1262
1281
1263 $ cat error-collections.log
1282 $ cat error-collections.log
1264
1283
1265 collections errors 2
1284 collections errors 2
1266
1285
1267 $ cat error-collections-2.log
1286 $ cat error-collections-2.log
@@ -1,104 +1,144
1 $ hg init repo
1 $ hg init repo
2 $ cd repo
2 $ cd repo
3 $ echo foo > foo
3 $ echo foo > foo
4 $ hg ci -qAm 'add foo'
4 $ hg ci -qAm 'add foo'
5 $ echo >> foo
5 $ echo >> foo
6 $ hg ci -m 'change foo'
6 $ hg ci -m 'change foo'
7 $ hg up -qC 0
7 $ hg up -qC 0
8 $ echo bar > bar
8 $ echo bar > bar
9 $ hg ci -qAm 'add bar'
9 $ hg ci -qAm 'add bar'
10
10
11 $ hg log
11 $ hg log
12 changeset: 2:effea6de0384
12 changeset: 2:effea6de0384
13 tag: tip
13 tag: tip
14 parent: 0:bbd179dfa0a7
14 parent: 0:bbd179dfa0a7
15 user: test
15 user: test
16 date: Thu Jan 01 00:00:00 1970 +0000
16 date: Thu Jan 01 00:00:00 1970 +0000
17 summary: add bar
17 summary: add bar
18
18
19 changeset: 1:ed1b79f46b9a
19 changeset: 1:ed1b79f46b9a
20 user: test
20 user: test
21 date: Thu Jan 01 00:00:00 1970 +0000
21 date: Thu Jan 01 00:00:00 1970 +0000
22 summary: change foo
22 summary: change foo
23
23
24 changeset: 0:bbd179dfa0a7
24 changeset: 0:bbd179dfa0a7
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
27 summary: add foo
27 summary: add foo
28
28
29 $ cd ..
29 $ cd ..
30
30
31 don't show "(+1 heads)" message when pulling closed head
31 don't show "(+1 heads)" message when pulling closed head
32
32
33 $ hg clone -q repo repo2
33 $ hg clone -q repo repo2
34 $ hg clone -q repo2 repo3
34 $ hg clone -q repo2 repo3
35 $ cd repo2
35 $ cd repo2
36 $ hg up -q 0
36 $ hg up -q 0
37 $ echo hello >> foo
37 $ echo hello >> foo
38 $ hg ci -mx1
38 $ hg ci -mx1
39 created new head
39 created new head
40 $ hg ci -mx2 --close-branch
40 $ hg ci -mx2 --close-branch
41 $ cd ../repo3
41 $ cd ../repo3
42 $ hg heads -q --closed
42 $ hg heads -q --closed
43 2:effea6de0384
43 2:effea6de0384
44 1:ed1b79f46b9a
44 1:ed1b79f46b9a
45 $ hg pull
45 $ hg pull
46 pulling from $TESTTMP/repo2 (glob)
46 pulling from $TESTTMP/repo2 (glob)
47 searching for changes
47 searching for changes
48 adding changesets
48 adding changesets
49 adding manifests
49 adding manifests
50 adding file changes
50 adding file changes
51 added 2 changesets with 1 changes to 1 files
51 added 2 changesets with 1 changes to 1 files
52 (run 'hg update' to get a working copy)
52 (run 'hg update' to get a working copy)
53 $ hg heads -q --closed
53 $ hg heads -q --closed
54 4:00cfe9073916
54 4:00cfe9073916
55 2:effea6de0384
55 2:effea6de0384
56 1:ed1b79f46b9a
56 1:ed1b79f46b9a
57
57
58 $ cd ..
58 $ cd ..
59
59
60 $ hg init copy
60 $ hg init copy
61 $ cd copy
61 $ cd copy
62
62
63 Pull a missing revision:
63 Pull a missing revision:
64
64
65 $ hg pull -qr missing ../repo
65 $ hg pull -qr missing ../repo
66 abort: unknown revision 'missing'!
66 abort: unknown revision 'missing'!
67 [255]
67 [255]
68
68
69 Pull multiple revisions with update:
69 Pull multiple revisions with update:
70
70
71 $ hg pull -qu -r 0 -r 1 ../repo
71 $ hg pull -qu -r 0 -r 1 ../repo
72 $ hg -q parents
72 $ hg -q parents
73 0:bbd179dfa0a7
73 0:bbd179dfa0a7
74 $ hg rollback
74 $ hg rollback
75 repository tip rolled back to revision -1 (undo pull)
75 repository tip rolled back to revision -1 (undo pull)
76 working directory now based on revision -1
76 working directory now based on revision -1
77
77
78 $ hg pull -qr 0 ../repo
78 $ hg pull -qr 0 ../repo
79 $ hg log
79 $ hg log
80 changeset: 0:bbd179dfa0a7
80 changeset: 0:bbd179dfa0a7
81 tag: tip
81 tag: tip
82 user: test
82 user: test
83 date: Thu Jan 01 00:00:00 1970 +0000
83 date: Thu Jan 01 00:00:00 1970 +0000
84 summary: add foo
84 summary: add foo
85
85
86 $ hg pull -qr 1 ../repo
86 $ hg pull -qr 1 ../repo
87 $ hg log
87 $ hg log
88 changeset: 1:ed1b79f46b9a
88 changeset: 1:ed1b79f46b9a
89 tag: tip
89 tag: tip
90 user: test
90 user: test
91 date: Thu Jan 01 00:00:00 1970 +0000
91 date: Thu Jan 01 00:00:00 1970 +0000
92 summary: change foo
92 summary: change foo
93
93
94 changeset: 0:bbd179dfa0a7
94 changeset: 0:bbd179dfa0a7
95 user: test
95 user: test
96 date: Thu Jan 01 00:00:00 1970 +0000
96 date: Thu Jan 01 00:00:00 1970 +0000
97 summary: add foo
97 summary: add foo
98
98
99
99
100 This used to abort: received changelog group is empty:
100 This used to abort: received changelog group is empty:
101
101
102 $ hg pull -qr 1 ../repo
102 $ hg pull -qr 1 ../repo
103
103
104 Test race condition with -r and -U (issue4707)
105
106 We pull '-U -r <name>' and the name change right after/during the changegroup emission.
107 We use http because http is better is our racy-est option.
108
109
110 $ echo babar > ../repo/jungle
111 $ cat <<EOF > ../repo/.hg/hgrc
112 > [hooks]
113 > outgoing.makecommit = hg ci -Am 'racy commit'; echo committed in pull-race
114 > EOF
115 $ hg -R ../repo serve -p $HGPORT2 -d --pid-file=../repo.pid
116 $ cat ../repo.pid >> $DAEMON_PIDS
117 $ hg pull --rev default --update http://localhost:$HGPORT2/
118 pulling from http://localhost:$HGPORT2/
119 searching for changes
120 adding changesets
121 adding manifests
122 adding file changes
123 added 1 changesets with 1 changes to 1 files (+1 heads)
124 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 $ hg log -G
126 @ changeset: 2:effea6de0384
127 | tag: tip
128 | parent: 0:bbd179dfa0a7
129 | user: test
130 | date: Thu Jan 01 00:00:00 1970 +0000
131 | summary: add bar
132 |
133 | o changeset: 1:ed1b79f46b9a
134 |/ user: test
135 | date: Thu Jan 01 00:00:00 1970 +0000
136 | summary: change foo
137 |
138 o changeset: 0:bbd179dfa0a7
139 user: test
140 date: Thu Jan 01 00:00:00 1970 +0000
141 summary: add foo
142
143
104 $ cd ..
144 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now