##// END OF EJS Templates
version: verbose list internal and external extension source (issue4731)
liscju -
r27990:96bfd287 default
parent child Browse files
Show More
@@ -1,7039 +1,7045 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullhex, nullid, nullrev, short
8 from node import hex, bin, nullhex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb
16 import sshserver, hgweb
17 import extensions
17 import extensions
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod, copies
20 import dagparser, context, simplemerge, graphmod, copies
21 import random, operator
21 import random, operator
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import ui as uimod
24 import ui as uimod
25 import streamclone
25 import streamclone
26 import commandserver
26 import commandserver
27
27
28 table = {}
28 table = {}
29
29
30 command = cmdutil.command(table)
30 command = cmdutil.command(table)
31
31
32 # Space delimited list of commands that don't require local repositories.
32 # Space delimited list of commands that don't require local repositories.
33 # This should be populated by passing norepo=True into the @command decorator.
33 # This should be populated by passing norepo=True into the @command decorator.
34 norepo = ''
34 norepo = ''
35 # Space delimited list of commands that optionally require local repositories.
35 # Space delimited list of commands that optionally require local repositories.
36 # This should be populated by passing optionalrepo=True into the @command
36 # This should be populated by passing optionalrepo=True into the @command
37 # decorator.
37 # decorator.
38 optionalrepo = ''
38 optionalrepo = ''
39 # Space delimited list of commands that will examine arguments looking for
39 # Space delimited list of commands that will examine arguments looking for
40 # a repository. This should be populated by passing inferrepo=True into the
40 # a repository. This should be populated by passing inferrepo=True into the
41 # @command decorator.
41 # @command decorator.
42 inferrepo = ''
42 inferrepo = ''
43
43
44 # label constants
44 # label constants
45 # until 3.5, bookmarks.current was the advertised name, not
45 # until 3.5, bookmarks.current was the advertised name, not
46 # bookmarks.active, so we must use both to avoid breaking old
46 # bookmarks.active, so we must use both to avoid breaking old
47 # custom styles
47 # custom styles
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
49
49
50 # common command options
50 # common command options
51
51
52 globalopts = [
52 globalopts = [
53 ('R', 'repository', '',
53 ('R', 'repository', '',
54 _('repository root directory or name of overlay bundle file'),
54 _('repository root directory or name of overlay bundle file'),
55 _('REPO')),
55 _('REPO')),
56 ('', 'cwd', '',
56 ('', 'cwd', '',
57 _('change working directory'), _('DIR')),
57 _('change working directory'), _('DIR')),
58 ('y', 'noninteractive', None,
58 ('y', 'noninteractive', None,
59 _('do not prompt, automatically pick the first choice for all prompts')),
59 _('do not prompt, automatically pick the first choice for all prompts')),
60 ('q', 'quiet', None, _('suppress output')),
60 ('q', 'quiet', None, _('suppress output')),
61 ('v', 'verbose', None, _('enable additional output')),
61 ('v', 'verbose', None, _('enable additional output')),
62 ('', 'config', [],
62 ('', 'config', [],
63 _('set/override config option (use \'section.name=value\')'),
63 _('set/override config option (use \'section.name=value\')'),
64 _('CONFIG')),
64 _('CONFIG')),
65 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debug', None, _('enable debugging output')),
66 ('', 'debugger', None, _('start debugger')),
66 ('', 'debugger', None, _('start debugger')),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
68 _('ENCODE')),
68 _('ENCODE')),
69 ('', 'encodingmode', encoding.encodingmode,
69 ('', 'encodingmode', encoding.encodingmode,
70 _('set the charset encoding mode'), _('MODE')),
70 _('set the charset encoding mode'), _('MODE')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
72 ('', 'time', None, _('time how long the command takes')),
72 ('', 'time', None, _('time how long the command takes')),
73 ('', 'profile', None, _('print command execution profile')),
73 ('', 'profile', None, _('print command execution profile')),
74 ('', 'version', None, _('output version information and exit')),
74 ('', 'version', None, _('output version information and exit')),
75 ('h', 'help', None, _('display help and exit')),
75 ('h', 'help', None, _('display help and exit')),
76 ('', 'hidden', False, _('consider hidden changesets')),
76 ('', 'hidden', False, _('consider hidden changesets')),
77 ]
77 ]
78
78
79 dryrunopts = [('n', 'dry-run', None,
79 dryrunopts = [('n', 'dry-run', None,
80 _('do not perform actions, just print output'))]
80 _('do not perform actions, just print output'))]
81
81
82 remoteopts = [
82 remoteopts = [
83 ('e', 'ssh', '',
83 ('e', 'ssh', '',
84 _('specify ssh command to use'), _('CMD')),
84 _('specify ssh command to use'), _('CMD')),
85 ('', 'remotecmd', '',
85 ('', 'remotecmd', '',
86 _('specify hg command to run on the remote side'), _('CMD')),
86 _('specify hg command to run on the remote side'), _('CMD')),
87 ('', 'insecure', None,
87 ('', 'insecure', None,
88 _('do not verify server certificate (ignoring web.cacerts config)')),
88 _('do not verify server certificate (ignoring web.cacerts config)')),
89 ]
89 ]
90
90
91 walkopts = [
91 walkopts = [
92 ('I', 'include', [],
92 ('I', 'include', [],
93 _('include names matching the given patterns'), _('PATTERN')),
93 _('include names matching the given patterns'), _('PATTERN')),
94 ('X', 'exclude', [],
94 ('X', 'exclude', [],
95 _('exclude names matching the given patterns'), _('PATTERN')),
95 _('exclude names matching the given patterns'), _('PATTERN')),
96 ]
96 ]
97
97
98 commitopts = [
98 commitopts = [
99 ('m', 'message', '',
99 ('m', 'message', '',
100 _('use text as commit message'), _('TEXT')),
100 _('use text as commit message'), _('TEXT')),
101 ('l', 'logfile', '',
101 ('l', 'logfile', '',
102 _('read commit message from file'), _('FILE')),
102 _('read commit message from file'), _('FILE')),
103 ]
103 ]
104
104
105 commitopts2 = [
105 commitopts2 = [
106 ('d', 'date', '',
106 ('d', 'date', '',
107 _('record the specified date as commit date'), _('DATE')),
107 _('record the specified date as commit date'), _('DATE')),
108 ('u', 'user', '',
108 ('u', 'user', '',
109 _('record the specified user as committer'), _('USER')),
109 _('record the specified user as committer'), _('USER')),
110 ]
110 ]
111
111
112 # hidden for now
112 # hidden for now
113 formatteropts = [
113 formatteropts = [
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 templateopts = [
118 templateopts = [
119 ('', 'style', '',
119 ('', 'style', '',
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
121 ('T', 'template', '',
121 ('T', 'template', '',
122 _('display with template'), _('TEMPLATE')),
122 _('display with template'), _('TEMPLATE')),
123 ]
123 ]
124
124
125 logopts = [
125 logopts = [
126 ('p', 'patch', None, _('show patch')),
126 ('p', 'patch', None, _('show patch')),
127 ('g', 'git', None, _('use git extended diff format')),
127 ('g', 'git', None, _('use git extended diff format')),
128 ('l', 'limit', '',
128 ('l', 'limit', '',
129 _('limit number of changes displayed'), _('NUM')),
129 _('limit number of changes displayed'), _('NUM')),
130 ('M', 'no-merges', None, _('do not show merges')),
130 ('M', 'no-merges', None, _('do not show merges')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
132 ('G', 'graph', None, _("show the revision DAG")),
132 ('G', 'graph', None, _("show the revision DAG")),
133 ] + templateopts
133 ] + templateopts
134
134
135 diffopts = [
135 diffopts = [
136 ('a', 'text', None, _('treat all files as text')),
136 ('a', 'text', None, _('treat all files as text')),
137 ('g', 'git', None, _('use git extended diff format')),
137 ('g', 'git', None, _('use git extended diff format')),
138 ('', 'nodates', None, _('omit dates from diff headers'))
138 ('', 'nodates', None, _('omit dates from diff headers'))
139 ]
139 ]
140
140
141 diffwsopts = [
141 diffwsopts = [
142 ('w', 'ignore-all-space', None,
142 ('w', 'ignore-all-space', None,
143 _('ignore white space when comparing lines')),
143 _('ignore white space when comparing lines')),
144 ('b', 'ignore-space-change', None,
144 ('b', 'ignore-space-change', None,
145 _('ignore changes in the amount of white space')),
145 _('ignore changes in the amount of white space')),
146 ('B', 'ignore-blank-lines', None,
146 ('B', 'ignore-blank-lines', None,
147 _('ignore changes whose lines are all blank')),
147 _('ignore changes whose lines are all blank')),
148 ]
148 ]
149
149
150 diffopts2 = [
150 diffopts2 = [
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
152 ('p', 'show-function', None, _('show which function each change is in')),
152 ('p', 'show-function', None, _('show which function each change is in')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
154 ] + diffwsopts + [
154 ] + diffwsopts + [
155 ('U', 'unified', '',
155 ('U', 'unified', '',
156 _('number of lines of context to show'), _('NUM')),
156 _('number of lines of context to show'), _('NUM')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
159 ]
159 ]
160
160
161 mergetoolopts = [
161 mergetoolopts = [
162 ('t', 'tool', '', _('specify merge tool')),
162 ('t', 'tool', '', _('specify merge tool')),
163 ]
163 ]
164
164
165 similarityopts = [
165 similarityopts = [
166 ('s', 'similarity', '',
166 ('s', 'similarity', '',
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
168 ]
168 ]
169
169
170 subrepoopts = [
170 subrepoopts = [
171 ('S', 'subrepos', None,
171 ('S', 'subrepos', None,
172 _('recurse into subrepositories'))
172 _('recurse into subrepositories'))
173 ]
173 ]
174
174
175 debugrevlogopts = [
175 debugrevlogopts = [
176 ('c', 'changelog', False, _('open changelog')),
176 ('c', 'changelog', False, _('open changelog')),
177 ('m', 'manifest', False, _('open manifest')),
177 ('m', 'manifest', False, _('open manifest')),
178 ('', 'dir', False, _('open directory manifest')),
178 ('', 'dir', False, _('open directory manifest')),
179 ]
179 ]
180
180
181 # Commands start here, listed alphabetically
181 # Commands start here, listed alphabetically
182
182
183 @command('^add',
183 @command('^add',
184 walkopts + subrepoopts + dryrunopts,
184 walkopts + subrepoopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
185 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
186 inferrepo=True)
187 def add(ui, repo, *pats, **opts):
187 def add(ui, repo, *pats, **opts):
188 """add the specified files on the next commit
188 """add the specified files on the next commit
189
189
190 Schedule files to be version controlled and added to the
190 Schedule files to be version controlled and added to the
191 repository.
191 repository.
192
192
193 The files will be added to the repository at the next commit. To
193 The files will be added to the repository at the next commit. To
194 undo an add before that, see :hg:`forget`.
194 undo an add before that, see :hg:`forget`.
195
195
196 If no names are given, add all files to the repository (except
196 If no names are given, add all files to the repository (except
197 files matching ``.hgignore``).
197 files matching ``.hgignore``).
198
198
199 .. container:: verbose
199 .. container:: verbose
200
200
201 Examples:
201 Examples:
202
202
203 - New (unknown) files are added
203 - New (unknown) files are added
204 automatically by :hg:`add`::
204 automatically by :hg:`add`::
205
205
206 $ ls
206 $ ls
207 foo.c
207 foo.c
208 $ hg status
208 $ hg status
209 ? foo.c
209 ? foo.c
210 $ hg add
210 $ hg add
211 adding foo.c
211 adding foo.c
212 $ hg status
212 $ hg status
213 A foo.c
213 A foo.c
214
214
215 - Specific files to be added can be specified::
215 - Specific files to be added can be specified::
216
216
217 $ ls
217 $ ls
218 bar.c foo.c
218 bar.c foo.c
219 $ hg status
219 $ hg status
220 ? bar.c
220 ? bar.c
221 ? foo.c
221 ? foo.c
222 $ hg add bar.c
222 $ hg add bar.c
223 $ hg status
223 $ hg status
224 A bar.c
224 A bar.c
225 ? foo.c
225 ? foo.c
226
226
227 Returns 0 if all files are successfully added.
227 Returns 0 if all files are successfully added.
228 """
228 """
229
229
230 m = scmutil.match(repo[None], pats, opts)
230 m = scmutil.match(repo[None], pats, opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
232 return rejected and 1 or 0
232 return rejected and 1 or 0
233
233
234 @command('addremove',
234 @command('addremove',
235 similarityopts + subrepoopts + walkopts + dryrunopts,
235 similarityopts + subrepoopts + walkopts + dryrunopts,
236 _('[OPTION]... [FILE]...'),
236 _('[OPTION]... [FILE]...'),
237 inferrepo=True)
237 inferrepo=True)
238 def addremove(ui, repo, *pats, **opts):
238 def addremove(ui, repo, *pats, **opts):
239 """add all new files, delete all missing files
239 """add all new files, delete all missing files
240
240
241 Add all new files and remove all missing files from the
241 Add all new files and remove all missing files from the
242 repository.
242 repository.
243
243
244 Unless names are given, new files are ignored if they match any of
244 Unless names are given, new files are ignored if they match any of
245 the patterns in ``.hgignore``. As with add, these changes take
245 the patterns in ``.hgignore``. As with add, these changes take
246 effect at the next commit.
246 effect at the next commit.
247
247
248 Use the -s/--similarity option to detect renamed files. This
248 Use the -s/--similarity option to detect renamed files. This
249 option takes a percentage between 0 (disabled) and 100 (files must
249 option takes a percentage between 0 (disabled) and 100 (files must
250 be identical) as its parameter. With a parameter greater than 0,
250 be identical) as its parameter. With a parameter greater than 0,
251 this compares every removed file with every added file and records
251 this compares every removed file with every added file and records
252 those similar enough as renames. Detecting renamed files this way
252 those similar enough as renames. Detecting renamed files this way
253 can be expensive. After using this option, :hg:`status -C` can be
253 can be expensive. After using this option, :hg:`status -C` can be
254 used to check which files were identified as moved or renamed. If
254 used to check which files were identified as moved or renamed. If
255 not specified, -s/--similarity defaults to 100 and only renames of
255 not specified, -s/--similarity defaults to 100 and only renames of
256 identical files are detected.
256 identical files are detected.
257
257
258 .. container:: verbose
258 .. container:: verbose
259
259
260 Examples:
260 Examples:
261
261
262 - A number of files (bar.c and foo.c) are new,
262 - A number of files (bar.c and foo.c) are new,
263 while foobar.c has been removed (without using :hg:`remove`)
263 while foobar.c has been removed (without using :hg:`remove`)
264 from the repository::
264 from the repository::
265
265
266 $ ls
266 $ ls
267 bar.c foo.c
267 bar.c foo.c
268 $ hg status
268 $ hg status
269 ! foobar.c
269 ! foobar.c
270 ? bar.c
270 ? bar.c
271 ? foo.c
271 ? foo.c
272 $ hg addremove
272 $ hg addremove
273 adding bar.c
273 adding bar.c
274 adding foo.c
274 adding foo.c
275 removing foobar.c
275 removing foobar.c
276 $ hg status
276 $ hg status
277 A bar.c
277 A bar.c
278 A foo.c
278 A foo.c
279 R foobar.c
279 R foobar.c
280
280
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
282 Afterwards, it was edited slightly::
282 Afterwards, it was edited slightly::
283
283
284 $ ls
284 $ ls
285 foo.c
285 foo.c
286 $ hg status
286 $ hg status
287 ! foobar.c
287 ! foobar.c
288 ? foo.c
288 ? foo.c
289 $ hg addremove --similarity 90
289 $ hg addremove --similarity 90
290 removing foobar.c
290 removing foobar.c
291 adding foo.c
291 adding foo.c
292 recording removal of foobar.c as rename to foo.c (94% similar)
292 recording removal of foobar.c as rename to foo.c (94% similar)
293 $ hg status -C
293 $ hg status -C
294 A foo.c
294 A foo.c
295 foobar.c
295 foobar.c
296 R foobar.c
296 R foobar.c
297
297
298 Returns 0 if all files are successfully added.
298 Returns 0 if all files are successfully added.
299 """
299 """
300 try:
300 try:
301 sim = float(opts.get('similarity') or 100)
301 sim = float(opts.get('similarity') or 100)
302 except ValueError:
302 except ValueError:
303 raise error.Abort(_('similarity must be a number'))
303 raise error.Abort(_('similarity must be a number'))
304 if sim < 0 or sim > 100:
304 if sim < 0 or sim > 100:
305 raise error.Abort(_('similarity must be between 0 and 100'))
305 raise error.Abort(_('similarity must be between 0 and 100'))
306 matcher = scmutil.match(repo[None], pats, opts)
306 matcher = scmutil.match(repo[None], pats, opts)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
308
308
309 @command('^annotate|blame',
309 @command('^annotate|blame',
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
311 ('', 'follow', None,
311 ('', 'follow', None,
312 _('follow copies/renames and list the filename (DEPRECATED)')),
312 _('follow copies/renames and list the filename (DEPRECATED)')),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
314 ('a', 'text', None, _('treat all files as text')),
314 ('a', 'text', None, _('treat all files as text')),
315 ('u', 'user', None, _('list the author (long with -v)')),
315 ('u', 'user', None, _('list the author (long with -v)')),
316 ('f', 'file', None, _('list the filename')),
316 ('f', 'file', None, _('list the filename')),
317 ('d', 'date', None, _('list the date (short with -q)')),
317 ('d', 'date', None, _('list the date (short with -q)')),
318 ('n', 'number', None, _('list the revision number (default)')),
318 ('n', 'number', None, _('list the revision number (default)')),
319 ('c', 'changeset', None, _('list the changeset')),
319 ('c', 'changeset', None, _('list the changeset')),
320 ('l', 'line-number', None, _('show line number at the first appearance'))
320 ('l', 'line-number', None, _('show line number at the first appearance'))
321 ] + diffwsopts + walkopts + formatteropts,
321 ] + diffwsopts + walkopts + formatteropts,
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
323 inferrepo=True)
323 inferrepo=True)
324 def annotate(ui, repo, *pats, **opts):
324 def annotate(ui, repo, *pats, **opts):
325 """show changeset information by line for each file
325 """show changeset information by line for each file
326
326
327 List changes in files, showing the revision id responsible for
327 List changes in files, showing the revision id responsible for
328 each line.
328 each line.
329
329
330 This command is useful for discovering when a change was made and
330 This command is useful for discovering when a change was made and
331 by whom.
331 by whom.
332
332
333 If you include --file, --user, or --date, the revision number is
333 If you include --file, --user, or --date, the revision number is
334 suppressed unless you also include --number.
334 suppressed unless you also include --number.
335
335
336 Without the -a/--text option, annotate will avoid processing files
336 Without the -a/--text option, annotate will avoid processing files
337 it detects as binary. With -a, annotate will annotate the file
337 it detects as binary. With -a, annotate will annotate the file
338 anyway, although the results will probably be neither useful
338 anyway, although the results will probably be neither useful
339 nor desirable.
339 nor desirable.
340
340
341 Returns 0 on success.
341 Returns 0 on success.
342 """
342 """
343 if not pats:
343 if not pats:
344 raise error.Abort(_('at least one filename or pattern is required'))
344 raise error.Abort(_('at least one filename or pattern is required'))
345
345
346 if opts.get('follow'):
346 if opts.get('follow'):
347 # --follow is deprecated and now just an alias for -f/--file
347 # --follow is deprecated and now just an alias for -f/--file
348 # to mimic the behavior of Mercurial before version 1.5
348 # to mimic the behavior of Mercurial before version 1.5
349 opts['file'] = True
349 opts['file'] = True
350
350
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
352
352
353 fm = ui.formatter('annotate', opts)
353 fm = ui.formatter('annotate', opts)
354 if ui.quiet:
354 if ui.quiet:
355 datefunc = util.shortdate
355 datefunc = util.shortdate
356 else:
356 else:
357 datefunc = util.datestr
357 datefunc = util.datestr
358 if ctx.rev() is None:
358 if ctx.rev() is None:
359 def hexfn(node):
359 def hexfn(node):
360 if node is None:
360 if node is None:
361 return None
361 return None
362 else:
362 else:
363 return fm.hexfunc(node)
363 return fm.hexfunc(node)
364 if opts.get('changeset'):
364 if opts.get('changeset'):
365 # omit "+" suffix which is appended to node hex
365 # omit "+" suffix which is appended to node hex
366 def formatrev(rev):
366 def formatrev(rev):
367 if rev is None:
367 if rev is None:
368 return '%d' % ctx.p1().rev()
368 return '%d' % ctx.p1().rev()
369 else:
369 else:
370 return '%d' % rev
370 return '%d' % rev
371 else:
371 else:
372 def formatrev(rev):
372 def formatrev(rev):
373 if rev is None:
373 if rev is None:
374 return '%d+' % ctx.p1().rev()
374 return '%d+' % ctx.p1().rev()
375 else:
375 else:
376 return '%d ' % rev
376 return '%d ' % rev
377 def formathex(hex):
377 def formathex(hex):
378 if hex is None:
378 if hex is None:
379 return '%s+' % fm.hexfunc(ctx.p1().node())
379 return '%s+' % fm.hexfunc(ctx.p1().node())
380 else:
380 else:
381 return '%s ' % hex
381 return '%s ' % hex
382 else:
382 else:
383 hexfn = fm.hexfunc
383 hexfn = fm.hexfunc
384 formatrev = formathex = str
384 formatrev = formathex = str
385
385
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
390 ('file', ' ', lambda x: x[0].path(), str),
390 ('file', ' ', lambda x: x[0].path(), str),
391 ('line_number', ':', lambda x: x[1], str),
391 ('line_number', ':', lambda x: x[1], str),
392 ]
392 ]
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
394
394
395 if (not opts.get('user') and not opts.get('changeset')
395 if (not opts.get('user') and not opts.get('changeset')
396 and not opts.get('date') and not opts.get('file')):
396 and not opts.get('date') and not opts.get('file')):
397 opts['number'] = True
397 opts['number'] = True
398
398
399 linenumber = opts.get('line_number') is not None
399 linenumber = opts.get('line_number') is not None
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
402
402
403 if fm:
403 if fm:
404 def makefunc(get, fmt):
404 def makefunc(get, fmt):
405 return get
405 return get
406 else:
406 else:
407 def makefunc(get, fmt):
407 def makefunc(get, fmt):
408 return lambda x: fmt(get(x))
408 return lambda x: fmt(get(x))
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
410 if opts.get(op)]
410 if opts.get(op)]
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
413 if opts.get(op))
413 if opts.get(op))
414
414
415 def bad(x, y):
415 def bad(x, y):
416 raise error.Abort("%s: %s" % (x, y))
416 raise error.Abort("%s: %s" % (x, y))
417
417
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
419
419
420 follow = not opts.get('no_follow')
420 follow = not opts.get('no_follow')
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
422 whitespace=True)
422 whitespace=True)
423 for abs in ctx.walk(m):
423 for abs in ctx.walk(m):
424 fctx = ctx[abs]
424 fctx = ctx[abs]
425 if not opts.get('text') and util.binary(fctx.data()):
425 if not opts.get('text') and util.binary(fctx.data()):
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
427 continue
427 continue
428
428
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
430 diffopts=diffopts)
430 diffopts=diffopts)
431 formats = []
431 formats = []
432 pieces = []
432 pieces = []
433
433
434 for f, sep in funcmap:
434 for f, sep in funcmap:
435 l = [f(n) for n, dummy in lines]
435 l = [f(n) for n, dummy in lines]
436 if l:
436 if l:
437 if fm:
437 if fm:
438 formats.append(['%s' for x in l])
438 formats.append(['%s' for x in l])
439 else:
439 else:
440 sizes = [encoding.colwidth(x) for x in l]
440 sizes = [encoding.colwidth(x) for x in l]
441 ml = max(sizes)
441 ml = max(sizes)
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
443 pieces.append(l)
443 pieces.append(l)
444
444
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
446 fm.startitem()
446 fm.startitem()
447 fm.write(fields, "".join(f), *p)
447 fm.write(fields, "".join(f), *p)
448 fm.write('line', ": %s", l[1])
448 fm.write('line', ": %s", l[1])
449
449
450 if lines and not lines[-1][1].endswith('\n'):
450 if lines and not lines[-1][1].endswith('\n'):
451 fm.plain('\n')
451 fm.plain('\n')
452
452
453 fm.end()
453 fm.end()
454
454
455 @command('archive',
455 @command('archive',
456 [('', 'no-decode', None, _('do not pass files through decoders')),
456 [('', 'no-decode', None, _('do not pass files through decoders')),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
458 _('PREFIX')),
458 _('PREFIX')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
461 ] + subrepoopts + walkopts,
461 ] + subrepoopts + walkopts,
462 _('[OPTION]... DEST'))
462 _('[OPTION]... DEST'))
463 def archive(ui, repo, dest, **opts):
463 def archive(ui, repo, dest, **opts):
464 '''create an unversioned archive of a repository revision
464 '''create an unversioned archive of a repository revision
465
465
466 By default, the revision used is the parent of the working
466 By default, the revision used is the parent of the working
467 directory; use -r/--rev to specify a different revision.
467 directory; use -r/--rev to specify a different revision.
468
468
469 The archive type is automatically detected based on file
469 The archive type is automatically detected based on file
470 extension (to override, use -t/--type).
470 extension (to override, use -t/--type).
471
471
472 .. container:: verbose
472 .. container:: verbose
473
473
474 Examples:
474 Examples:
475
475
476 - create a zip file containing the 1.0 release::
476 - create a zip file containing the 1.0 release::
477
477
478 hg archive -r 1.0 project-1.0.zip
478 hg archive -r 1.0 project-1.0.zip
479
479
480 - create a tarball excluding .hg files::
480 - create a tarball excluding .hg files::
481
481
482 hg archive project.tar.gz -X ".hg*"
482 hg archive project.tar.gz -X ".hg*"
483
483
484 Valid types are:
484 Valid types are:
485
485
486 :``files``: a directory full of files (default)
486 :``files``: a directory full of files (default)
487 :``tar``: tar archive, uncompressed
487 :``tar``: tar archive, uncompressed
488 :``tbz2``: tar archive, compressed using bzip2
488 :``tbz2``: tar archive, compressed using bzip2
489 :``tgz``: tar archive, compressed using gzip
489 :``tgz``: tar archive, compressed using gzip
490 :``uzip``: zip archive, uncompressed
490 :``uzip``: zip archive, uncompressed
491 :``zip``: zip archive, compressed using deflate
491 :``zip``: zip archive, compressed using deflate
492
492
493 The exact name of the destination archive or directory is given
493 The exact name of the destination archive or directory is given
494 using a format string; see :hg:`help export` for details.
494 using a format string; see :hg:`help export` for details.
495
495
496 Each member added to an archive file has a directory prefix
496 Each member added to an archive file has a directory prefix
497 prepended. Use -p/--prefix to specify a format string for the
497 prepended. Use -p/--prefix to specify a format string for the
498 prefix. The default is the basename of the archive, with suffixes
498 prefix. The default is the basename of the archive, with suffixes
499 removed.
499 removed.
500
500
501 Returns 0 on success.
501 Returns 0 on success.
502 '''
502 '''
503
503
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
505 if not ctx:
505 if not ctx:
506 raise error.Abort(_('no working directory: please specify a revision'))
506 raise error.Abort(_('no working directory: please specify a revision'))
507 node = ctx.node()
507 node = ctx.node()
508 dest = cmdutil.makefilename(repo, dest, node)
508 dest = cmdutil.makefilename(repo, dest, node)
509 if os.path.realpath(dest) == repo.root:
509 if os.path.realpath(dest) == repo.root:
510 raise error.Abort(_('repository root cannot be destination'))
510 raise error.Abort(_('repository root cannot be destination'))
511
511
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
513 prefix = opts.get('prefix')
513 prefix = opts.get('prefix')
514
514
515 if dest == '-':
515 if dest == '-':
516 if kind == 'files':
516 if kind == 'files':
517 raise error.Abort(_('cannot archive plain files to stdout'))
517 raise error.Abort(_('cannot archive plain files to stdout'))
518 dest = cmdutil.makefileobj(repo, dest)
518 dest = cmdutil.makefileobj(repo, dest)
519 if not prefix:
519 if not prefix:
520 prefix = os.path.basename(repo.root) + '-%h'
520 prefix = os.path.basename(repo.root) + '-%h'
521
521
522 prefix = cmdutil.makefilename(repo, prefix, node)
522 prefix = cmdutil.makefilename(repo, prefix, node)
523 matchfn = scmutil.match(ctx, [], opts)
523 matchfn = scmutil.match(ctx, [], opts)
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
525 matchfn, prefix, subrepos=opts.get('subrepos'))
525 matchfn, prefix, subrepos=opts.get('subrepos'))
526
526
527 @command('backout',
527 @command('backout',
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
529 ('', 'commit', None,
529 ('', 'commit', None,
530 _('commit if no conflicts were encountered (DEPRECATED)')),
530 _('commit if no conflicts were encountered (DEPRECATED)')),
531 ('', 'no-commit', None, _('do not commit')),
531 ('', 'no-commit', None, _('do not commit')),
532 ('', 'parent', '',
532 ('', 'parent', '',
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
533 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
534 ('r', 'rev', '', _('revision to backout'), _('REV')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
535 ('e', 'edit', False, _('invoke editor on commit messages')),
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
536 ] + mergetoolopts + walkopts + commitopts + commitopts2,
537 _('[OPTION]... [-r] REV'))
537 _('[OPTION]... [-r] REV'))
538 def backout(ui, repo, node=None, rev=None, **opts):
538 def backout(ui, repo, node=None, rev=None, **opts):
539 '''reverse effect of earlier changeset
539 '''reverse effect of earlier changeset
540
540
541 Prepare a new changeset with the effect of REV undone in the
541 Prepare a new changeset with the effect of REV undone in the
542 current working directory. If no conflicts were encountered,
542 current working directory. If no conflicts were encountered,
543 it will be committed immediately.
543 it will be committed immediately.
544
544
545 If REV is the parent of the working directory, then this new changeset
545 If REV is the parent of the working directory, then this new changeset
546 is committed automatically (unless --no-commit is specified).
546 is committed automatically (unless --no-commit is specified).
547
547
548 .. note::
548 .. note::
549
549
550 :hg:`backout` cannot be used to fix either an unwanted or
550 :hg:`backout` cannot be used to fix either an unwanted or
551 incorrect merge.
551 incorrect merge.
552
552
553 .. container:: verbose
553 .. container:: verbose
554
554
555 Examples:
555 Examples:
556
556
557 - Reverse the effect of the parent of the working directory.
557 - Reverse the effect of the parent of the working directory.
558 This backout will be committed immediately::
558 This backout will be committed immediately::
559
559
560 hg backout -r .
560 hg backout -r .
561
561
562 - Reverse the effect of previous bad revision 23::
562 - Reverse the effect of previous bad revision 23::
563
563
564 hg backout -r 23
564 hg backout -r 23
565
565
566 - Reverse the effect of previous bad revision 23 and
566 - Reverse the effect of previous bad revision 23 and
567 leave changes uncommitted::
567 leave changes uncommitted::
568
568
569 hg backout -r 23 --no-commit
569 hg backout -r 23 --no-commit
570 hg commit -m "Backout revision 23"
570 hg commit -m "Backout revision 23"
571
571
572 By default, the pending changeset will have one parent,
572 By default, the pending changeset will have one parent,
573 maintaining a linear history. With --merge, the pending
573 maintaining a linear history. With --merge, the pending
574 changeset will instead have two parents: the old parent of the
574 changeset will instead have two parents: the old parent of the
575 working directory and a new child of REV that simply undoes REV.
575 working directory and a new child of REV that simply undoes REV.
576
576
577 Before version 1.7, the behavior without --merge was equivalent
577 Before version 1.7, the behavior without --merge was equivalent
578 to specifying --merge followed by :hg:`update --clean .` to
578 to specifying --merge followed by :hg:`update --clean .` to
579 cancel the merge and leave the child of REV as a head to be
579 cancel the merge and leave the child of REV as a head to be
580 merged separately.
580 merged separately.
581
581
582 See :hg:`help dates` for a list of formats valid for -d/--date.
582 See :hg:`help dates` for a list of formats valid for -d/--date.
583
583
584 See :hg:`help revert` for a way to restore files to the state
584 See :hg:`help revert` for a way to restore files to the state
585 of another revision.
585 of another revision.
586
586
587 Returns 0 on success, 1 if nothing to backout or there are unresolved
587 Returns 0 on success, 1 if nothing to backout or there are unresolved
588 files.
588 files.
589 '''
589 '''
590 wlock = lock = None
590 wlock = lock = None
591 try:
591 try:
592 wlock = repo.wlock()
592 wlock = repo.wlock()
593 lock = repo.lock()
593 lock = repo.lock()
594 return _dobackout(ui, repo, node, rev, **opts)
594 return _dobackout(ui, repo, node, rev, **opts)
595 finally:
595 finally:
596 release(lock, wlock)
596 release(lock, wlock)
597
597
598 def _dobackout(ui, repo, node=None, rev=None, **opts):
598 def _dobackout(ui, repo, node=None, rev=None, **opts):
599 if opts.get('commit') and opts.get('no_commit'):
599 if opts.get('commit') and opts.get('no_commit'):
600 raise error.Abort(_("cannot use --commit with --no-commit"))
600 raise error.Abort(_("cannot use --commit with --no-commit"))
601 if opts.get('merge') and opts.get('no_commit'):
601 if opts.get('merge') and opts.get('no_commit'):
602 raise error.Abort(_("cannot use --merge with --no-commit"))
602 raise error.Abort(_("cannot use --merge with --no-commit"))
603
603
604 if rev and node:
604 if rev and node:
605 raise error.Abort(_("please specify just one revision"))
605 raise error.Abort(_("please specify just one revision"))
606
606
607 if not rev:
607 if not rev:
608 rev = node
608 rev = node
609
609
610 if not rev:
610 if not rev:
611 raise error.Abort(_("please specify a revision to backout"))
611 raise error.Abort(_("please specify a revision to backout"))
612
612
613 date = opts.get('date')
613 date = opts.get('date')
614 if date:
614 if date:
615 opts['date'] = util.parsedate(date)
615 opts['date'] = util.parsedate(date)
616
616
617 cmdutil.checkunfinished(repo)
617 cmdutil.checkunfinished(repo)
618 cmdutil.bailifchanged(repo)
618 cmdutil.bailifchanged(repo)
619 node = scmutil.revsingle(repo, rev).node()
619 node = scmutil.revsingle(repo, rev).node()
620
620
621 op1, op2 = repo.dirstate.parents()
621 op1, op2 = repo.dirstate.parents()
622 if not repo.changelog.isancestor(node, op1):
622 if not repo.changelog.isancestor(node, op1):
623 raise error.Abort(_('cannot backout change that is not an ancestor'))
623 raise error.Abort(_('cannot backout change that is not an ancestor'))
624
624
625 p1, p2 = repo.changelog.parents(node)
625 p1, p2 = repo.changelog.parents(node)
626 if p1 == nullid:
626 if p1 == nullid:
627 raise error.Abort(_('cannot backout a change with no parents'))
627 raise error.Abort(_('cannot backout a change with no parents'))
628 if p2 != nullid:
628 if p2 != nullid:
629 if not opts.get('parent'):
629 if not opts.get('parent'):
630 raise error.Abort(_('cannot backout a merge changeset'))
630 raise error.Abort(_('cannot backout a merge changeset'))
631 p = repo.lookup(opts['parent'])
631 p = repo.lookup(opts['parent'])
632 if p not in (p1, p2):
632 if p not in (p1, p2):
633 raise error.Abort(_('%s is not a parent of %s') %
633 raise error.Abort(_('%s is not a parent of %s') %
634 (short(p), short(node)))
634 (short(p), short(node)))
635 parent = p
635 parent = p
636 else:
636 else:
637 if opts.get('parent'):
637 if opts.get('parent'):
638 raise error.Abort(_('cannot use --parent on non-merge changeset'))
638 raise error.Abort(_('cannot use --parent on non-merge changeset'))
639 parent = p1
639 parent = p1
640
640
641 # the backout should appear on the same branch
641 # the backout should appear on the same branch
642 branch = repo.dirstate.branch()
642 branch = repo.dirstate.branch()
643 bheads = repo.branchheads(branch)
643 bheads = repo.branchheads(branch)
644 rctx = scmutil.revsingle(repo, hex(parent))
644 rctx = scmutil.revsingle(repo, hex(parent))
645 if not opts.get('merge') and op1 != node:
645 if not opts.get('merge') and op1 != node:
646 dsguard = cmdutil.dirstateguard(repo, 'backout')
646 dsguard = cmdutil.dirstateguard(repo, 'backout')
647 try:
647 try:
648 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
648 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
649 'backout')
649 'backout')
650 stats = mergemod.update(repo, parent, True, True, node, False)
650 stats = mergemod.update(repo, parent, True, True, node, False)
651 repo.setparents(op1, op2)
651 repo.setparents(op1, op2)
652 dsguard.close()
652 dsguard.close()
653 hg._showstats(repo, stats)
653 hg._showstats(repo, stats)
654 if stats[3]:
654 if stats[3]:
655 repo.ui.status(_("use 'hg resolve' to retry unresolved "
655 repo.ui.status(_("use 'hg resolve' to retry unresolved "
656 "file merges\n"))
656 "file merges\n"))
657 return 1
657 return 1
658 finally:
658 finally:
659 ui.setconfig('ui', 'forcemerge', '', '')
659 ui.setconfig('ui', 'forcemerge', '', '')
660 lockmod.release(dsguard)
660 lockmod.release(dsguard)
661 else:
661 else:
662 hg.clean(repo, node, show_stats=False)
662 hg.clean(repo, node, show_stats=False)
663 repo.dirstate.setbranch(branch)
663 repo.dirstate.setbranch(branch)
664 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
664 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
665
665
666 if opts.get('no_commit'):
666 if opts.get('no_commit'):
667 msg = _("changeset %s backed out, "
667 msg = _("changeset %s backed out, "
668 "don't forget to commit.\n")
668 "don't forget to commit.\n")
669 ui.status(msg % short(node))
669 ui.status(msg % short(node))
670 return 0
670 return 0
671
671
672 def commitfunc(ui, repo, message, match, opts):
672 def commitfunc(ui, repo, message, match, opts):
673 editform = 'backout'
673 editform = 'backout'
674 e = cmdutil.getcommiteditor(editform=editform, **opts)
674 e = cmdutil.getcommiteditor(editform=editform, **opts)
675 if not message:
675 if not message:
676 # we don't translate commit messages
676 # we don't translate commit messages
677 message = "Backed out changeset %s" % short(node)
677 message = "Backed out changeset %s" % short(node)
678 e = cmdutil.getcommiteditor(edit=True, editform=editform)
678 e = cmdutil.getcommiteditor(edit=True, editform=editform)
679 return repo.commit(message, opts.get('user'), opts.get('date'),
679 return repo.commit(message, opts.get('user'), opts.get('date'),
680 match, editor=e)
680 match, editor=e)
681 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
681 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
682 if not newnode:
682 if not newnode:
683 ui.status(_("nothing changed\n"))
683 ui.status(_("nothing changed\n"))
684 return 1
684 return 1
685 cmdutil.commitstatus(repo, newnode, branch, bheads)
685 cmdutil.commitstatus(repo, newnode, branch, bheads)
686
686
687 def nice(node):
687 def nice(node):
688 return '%d:%s' % (repo.changelog.rev(node), short(node))
688 return '%d:%s' % (repo.changelog.rev(node), short(node))
689 ui.status(_('changeset %s backs out changeset %s\n') %
689 ui.status(_('changeset %s backs out changeset %s\n') %
690 (nice(repo.changelog.tip()), nice(node)))
690 (nice(repo.changelog.tip()), nice(node)))
691 if opts.get('merge') and op1 != node:
691 if opts.get('merge') and op1 != node:
692 hg.clean(repo, op1, show_stats=False)
692 hg.clean(repo, op1, show_stats=False)
693 ui.status(_('merging with changeset %s\n')
693 ui.status(_('merging with changeset %s\n')
694 % nice(repo.changelog.tip()))
694 % nice(repo.changelog.tip()))
695 try:
695 try:
696 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
696 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
697 'backout')
697 'backout')
698 return hg.merge(repo, hex(repo.changelog.tip()))
698 return hg.merge(repo, hex(repo.changelog.tip()))
699 finally:
699 finally:
700 ui.setconfig('ui', 'forcemerge', '', '')
700 ui.setconfig('ui', 'forcemerge', '', '')
701 return 0
701 return 0
702
702
703 @command('bisect',
703 @command('bisect',
704 [('r', 'reset', False, _('reset bisect state')),
704 [('r', 'reset', False, _('reset bisect state')),
705 ('g', 'good', False, _('mark changeset good')),
705 ('g', 'good', False, _('mark changeset good')),
706 ('b', 'bad', False, _('mark changeset bad')),
706 ('b', 'bad', False, _('mark changeset bad')),
707 ('s', 'skip', False, _('skip testing changeset')),
707 ('s', 'skip', False, _('skip testing changeset')),
708 ('e', 'extend', False, _('extend the bisect range')),
708 ('e', 'extend', False, _('extend the bisect range')),
709 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
709 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
710 ('U', 'noupdate', False, _('do not update to target'))],
710 ('U', 'noupdate', False, _('do not update to target'))],
711 _("[-gbsr] [-U] [-c CMD] [REV]"))
711 _("[-gbsr] [-U] [-c CMD] [REV]"))
712 def bisect(ui, repo, rev=None, extra=None, command=None,
712 def bisect(ui, repo, rev=None, extra=None, command=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
713 reset=None, good=None, bad=None, skip=None, extend=None,
714 noupdate=None):
714 noupdate=None):
715 """subdivision search of changesets
715 """subdivision search of changesets
716
716
717 This command helps to find changesets which introduce problems. To
717 This command helps to find changesets which introduce problems. To
718 use, mark the earliest changeset you know exhibits the problem as
718 use, mark the earliest changeset you know exhibits the problem as
719 bad, then mark the latest changeset which is free from the problem
719 bad, then mark the latest changeset which is free from the problem
720 as good. Bisect will update your working directory to a revision
720 as good. Bisect will update your working directory to a revision
721 for testing (unless the -U/--noupdate option is specified). Once
721 for testing (unless the -U/--noupdate option is specified). Once
722 you have performed tests, mark the working directory as good or
722 you have performed tests, mark the working directory as good or
723 bad, and bisect will either update to another candidate changeset
723 bad, and bisect will either update to another candidate changeset
724 or announce that it has found the bad revision.
724 or announce that it has found the bad revision.
725
725
726 As a shortcut, you can also use the revision argument to mark a
726 As a shortcut, you can also use the revision argument to mark a
727 revision as good or bad without checking it out first.
727 revision as good or bad without checking it out first.
728
728
729 If you supply a command, it will be used for automatic bisection.
729 If you supply a command, it will be used for automatic bisection.
730 The environment variable HG_NODE will contain the ID of the
730 The environment variable HG_NODE will contain the ID of the
731 changeset being tested. The exit status of the command will be
731 changeset being tested. The exit status of the command will be
732 used to mark revisions as good or bad: status 0 means good, 125
732 used to mark revisions as good or bad: status 0 means good, 125
733 means to skip the revision, 127 (command not found) will abort the
733 means to skip the revision, 127 (command not found) will abort the
734 bisection, and any other non-zero exit status means the revision
734 bisection, and any other non-zero exit status means the revision
735 is bad.
735 is bad.
736
736
737 .. container:: verbose
737 .. container:: verbose
738
738
739 Some examples:
739 Some examples:
740
740
741 - start a bisection with known bad revision 34, and good revision 12::
741 - start a bisection with known bad revision 34, and good revision 12::
742
742
743 hg bisect --bad 34
743 hg bisect --bad 34
744 hg bisect --good 12
744 hg bisect --good 12
745
745
746 - advance the current bisection by marking current revision as good or
746 - advance the current bisection by marking current revision as good or
747 bad::
747 bad::
748
748
749 hg bisect --good
749 hg bisect --good
750 hg bisect --bad
750 hg bisect --bad
751
751
752 - mark the current revision, or a known revision, to be skipped (e.g. if
752 - mark the current revision, or a known revision, to be skipped (e.g. if
753 that revision is not usable because of another issue)::
753 that revision is not usable because of another issue)::
754
754
755 hg bisect --skip
755 hg bisect --skip
756 hg bisect --skip 23
756 hg bisect --skip 23
757
757
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
758 - skip all revisions that do not touch directories ``foo`` or ``bar``::
759
759
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
760 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
761
761
762 - forget the current bisection::
762 - forget the current bisection::
763
763
764 hg bisect --reset
764 hg bisect --reset
765
765
766 - use 'make && make tests' to automatically find the first broken
766 - use 'make && make tests' to automatically find the first broken
767 revision::
767 revision::
768
768
769 hg bisect --reset
769 hg bisect --reset
770 hg bisect --bad 34
770 hg bisect --bad 34
771 hg bisect --good 12
771 hg bisect --good 12
772 hg bisect --command "make && make tests"
772 hg bisect --command "make && make tests"
773
773
774 - see all changesets whose states are already known in the current
774 - see all changesets whose states are already known in the current
775 bisection::
775 bisection::
776
776
777 hg log -r "bisect(pruned)"
777 hg log -r "bisect(pruned)"
778
778
779 - see the changeset currently being bisected (especially useful
779 - see the changeset currently being bisected (especially useful
780 if running with -U/--noupdate)::
780 if running with -U/--noupdate)::
781
781
782 hg log -r "bisect(current)"
782 hg log -r "bisect(current)"
783
783
784 - see all changesets that took part in the current bisection::
784 - see all changesets that took part in the current bisection::
785
785
786 hg log -r "bisect(range)"
786 hg log -r "bisect(range)"
787
787
788 - you can even get a nice graph::
788 - you can even get a nice graph::
789
789
790 hg log --graph -r "bisect(range)"
790 hg log --graph -r "bisect(range)"
791
791
792 See :hg:`help revsets` for more about the `bisect()` keyword.
792 See :hg:`help revsets` for more about the `bisect()` keyword.
793
793
794 Returns 0 on success.
794 Returns 0 on success.
795 """
795 """
796 def extendbisectrange(nodes, good):
796 def extendbisectrange(nodes, good):
797 # bisect is incomplete when it ends on a merge node and
797 # bisect is incomplete when it ends on a merge node and
798 # one of the parent was not checked.
798 # one of the parent was not checked.
799 parents = repo[nodes[0]].parents()
799 parents = repo[nodes[0]].parents()
800 if len(parents) > 1:
800 if len(parents) > 1:
801 if good:
801 if good:
802 side = state['bad']
802 side = state['bad']
803 else:
803 else:
804 side = state['good']
804 side = state['good']
805 num = len(set(i.node() for i in parents) & set(side))
805 num = len(set(i.node() for i in parents) & set(side))
806 if num == 1:
806 if num == 1:
807 return parents[0].ancestor(parents[1])
807 return parents[0].ancestor(parents[1])
808 return None
808 return None
809
809
810 def print_result(nodes, good):
810 def print_result(nodes, good):
811 displayer = cmdutil.show_changeset(ui, repo, {})
811 displayer = cmdutil.show_changeset(ui, repo, {})
812 if len(nodes) == 1:
812 if len(nodes) == 1:
813 # narrowed it down to a single revision
813 # narrowed it down to a single revision
814 if good:
814 if good:
815 ui.write(_("The first good revision is:\n"))
815 ui.write(_("The first good revision is:\n"))
816 else:
816 else:
817 ui.write(_("The first bad revision is:\n"))
817 ui.write(_("The first bad revision is:\n"))
818 displayer.show(repo[nodes[0]])
818 displayer.show(repo[nodes[0]])
819 extendnode = extendbisectrange(nodes, good)
819 extendnode = extendbisectrange(nodes, good)
820 if extendnode is not None:
820 if extendnode is not None:
821 ui.write(_('Not all ancestors of this changeset have been'
821 ui.write(_('Not all ancestors of this changeset have been'
822 ' checked.\nUse bisect --extend to continue the '
822 ' checked.\nUse bisect --extend to continue the '
823 'bisection from\nthe common ancestor, %s.\n')
823 'bisection from\nthe common ancestor, %s.\n')
824 % extendnode)
824 % extendnode)
825 else:
825 else:
826 # multiple possible revisions
826 # multiple possible revisions
827 if good:
827 if good:
828 ui.write(_("Due to skipped revisions, the first "
828 ui.write(_("Due to skipped revisions, the first "
829 "good revision could be any of:\n"))
829 "good revision could be any of:\n"))
830 else:
830 else:
831 ui.write(_("Due to skipped revisions, the first "
831 ui.write(_("Due to skipped revisions, the first "
832 "bad revision could be any of:\n"))
832 "bad revision could be any of:\n"))
833 for n in nodes:
833 for n in nodes:
834 displayer.show(repo[n])
834 displayer.show(repo[n])
835 displayer.close()
835 displayer.close()
836
836
837 def check_state(state, interactive=True):
837 def check_state(state, interactive=True):
838 if not state['good'] or not state['bad']:
838 if not state['good'] or not state['bad']:
839 if (good or bad or skip or reset) and interactive:
839 if (good or bad or skip or reset) and interactive:
840 return
840 return
841 if not state['good']:
841 if not state['good']:
842 raise error.Abort(_('cannot bisect (no known good revisions)'))
842 raise error.Abort(_('cannot bisect (no known good revisions)'))
843 else:
843 else:
844 raise error.Abort(_('cannot bisect (no known bad revisions)'))
844 raise error.Abort(_('cannot bisect (no known bad revisions)'))
845 return True
845 return True
846
846
847 # backward compatibility
847 # backward compatibility
848 if rev in "good bad reset init".split():
848 if rev in "good bad reset init".split():
849 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
849 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
850 cmd, rev, extra = rev, extra, None
850 cmd, rev, extra = rev, extra, None
851 if cmd == "good":
851 if cmd == "good":
852 good = True
852 good = True
853 elif cmd == "bad":
853 elif cmd == "bad":
854 bad = True
854 bad = True
855 else:
855 else:
856 reset = True
856 reset = True
857 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
857 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
858 raise error.Abort(_('incompatible arguments'))
858 raise error.Abort(_('incompatible arguments'))
859
859
860 cmdutil.checkunfinished(repo)
860 cmdutil.checkunfinished(repo)
861
861
862 if reset:
862 if reset:
863 p = repo.join("bisect.state")
863 p = repo.join("bisect.state")
864 if os.path.exists(p):
864 if os.path.exists(p):
865 os.unlink(p)
865 os.unlink(p)
866 return
866 return
867
867
868 state = hbisect.load_state(repo)
868 state = hbisect.load_state(repo)
869
869
870 if command:
870 if command:
871 changesets = 1
871 changesets = 1
872 if noupdate:
872 if noupdate:
873 try:
873 try:
874 node = state['current'][0]
874 node = state['current'][0]
875 except LookupError:
875 except LookupError:
876 raise error.Abort(_('current bisect revision is unknown - '
876 raise error.Abort(_('current bisect revision is unknown - '
877 'start a new bisect to fix'))
877 'start a new bisect to fix'))
878 else:
878 else:
879 node, p2 = repo.dirstate.parents()
879 node, p2 = repo.dirstate.parents()
880 if p2 != nullid:
880 if p2 != nullid:
881 raise error.Abort(_('current bisect revision is a merge'))
881 raise error.Abort(_('current bisect revision is a merge'))
882 try:
882 try:
883 while changesets:
883 while changesets:
884 # update state
884 # update state
885 state['current'] = [node]
885 state['current'] = [node]
886 hbisect.save_state(repo, state)
886 hbisect.save_state(repo, state)
887 status = ui.system(command, environ={'HG_NODE': hex(node)})
887 status = ui.system(command, environ={'HG_NODE': hex(node)})
888 if status == 125:
888 if status == 125:
889 transition = "skip"
889 transition = "skip"
890 elif status == 0:
890 elif status == 0:
891 transition = "good"
891 transition = "good"
892 # status < 0 means process was killed
892 # status < 0 means process was killed
893 elif status == 127:
893 elif status == 127:
894 raise error.Abort(_("failed to execute %s") % command)
894 raise error.Abort(_("failed to execute %s") % command)
895 elif status < 0:
895 elif status < 0:
896 raise error.Abort(_("%s killed") % command)
896 raise error.Abort(_("%s killed") % command)
897 else:
897 else:
898 transition = "bad"
898 transition = "bad"
899 ctx = scmutil.revsingle(repo, rev, node)
899 ctx = scmutil.revsingle(repo, rev, node)
900 rev = None # clear for future iterations
900 rev = None # clear for future iterations
901 state[transition].append(ctx.node())
901 state[transition].append(ctx.node())
902 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
902 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
903 check_state(state, interactive=False)
903 check_state(state, interactive=False)
904 # bisect
904 # bisect
905 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
905 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
906 # update to next check
906 # update to next check
907 node = nodes[0]
907 node = nodes[0]
908 if not noupdate:
908 if not noupdate:
909 cmdutil.bailifchanged(repo)
909 cmdutil.bailifchanged(repo)
910 hg.clean(repo, node, show_stats=False)
910 hg.clean(repo, node, show_stats=False)
911 finally:
911 finally:
912 state['current'] = [node]
912 state['current'] = [node]
913 hbisect.save_state(repo, state)
913 hbisect.save_state(repo, state)
914 print_result(nodes, bgood)
914 print_result(nodes, bgood)
915 return
915 return
916
916
917 # update state
917 # update state
918
918
919 if rev:
919 if rev:
920 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
920 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
921 else:
921 else:
922 nodes = [repo.lookup('.')]
922 nodes = [repo.lookup('.')]
923
923
924 if good or bad or skip:
924 if good or bad or skip:
925 if good:
925 if good:
926 state['good'] += nodes
926 state['good'] += nodes
927 elif bad:
927 elif bad:
928 state['bad'] += nodes
928 state['bad'] += nodes
929 elif skip:
929 elif skip:
930 state['skip'] += nodes
930 state['skip'] += nodes
931 hbisect.save_state(repo, state)
931 hbisect.save_state(repo, state)
932
932
933 if not check_state(state):
933 if not check_state(state):
934 return
934 return
935
935
936 # actually bisect
936 # actually bisect
937 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
937 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
938 if extend:
938 if extend:
939 if not changesets:
939 if not changesets:
940 extendnode = extendbisectrange(nodes, good)
940 extendnode = extendbisectrange(nodes, good)
941 if extendnode is not None:
941 if extendnode is not None:
942 ui.write(_("Extending search to changeset %d:%s\n")
942 ui.write(_("Extending search to changeset %d:%s\n")
943 % (extendnode.rev(), extendnode))
943 % (extendnode.rev(), extendnode))
944 state['current'] = [extendnode.node()]
944 state['current'] = [extendnode.node()]
945 hbisect.save_state(repo, state)
945 hbisect.save_state(repo, state)
946 if noupdate:
946 if noupdate:
947 return
947 return
948 cmdutil.bailifchanged(repo)
948 cmdutil.bailifchanged(repo)
949 return hg.clean(repo, extendnode.node())
949 return hg.clean(repo, extendnode.node())
950 raise error.Abort(_("nothing to extend"))
950 raise error.Abort(_("nothing to extend"))
951
951
952 if changesets == 0:
952 if changesets == 0:
953 print_result(nodes, good)
953 print_result(nodes, good)
954 else:
954 else:
955 assert len(nodes) == 1 # only a single node can be tested next
955 assert len(nodes) == 1 # only a single node can be tested next
956 node = nodes[0]
956 node = nodes[0]
957 # compute the approximate number of remaining tests
957 # compute the approximate number of remaining tests
958 tests, size = 0, 2
958 tests, size = 0, 2
959 while size <= changesets:
959 while size <= changesets:
960 tests, size = tests + 1, size * 2
960 tests, size = tests + 1, size * 2
961 rev = repo.changelog.rev(node)
961 rev = repo.changelog.rev(node)
962 ui.write(_("Testing changeset %d:%s "
962 ui.write(_("Testing changeset %d:%s "
963 "(%d changesets remaining, ~%d tests)\n")
963 "(%d changesets remaining, ~%d tests)\n")
964 % (rev, short(node), changesets, tests))
964 % (rev, short(node), changesets, tests))
965 state['current'] = [node]
965 state['current'] = [node]
966 hbisect.save_state(repo, state)
966 hbisect.save_state(repo, state)
967 if not noupdate:
967 if not noupdate:
968 cmdutil.bailifchanged(repo)
968 cmdutil.bailifchanged(repo)
969 return hg.clean(repo, node)
969 return hg.clean(repo, node)
970
970
971 @command('bookmarks|bookmark',
971 @command('bookmarks|bookmark',
972 [('f', 'force', False, _('force')),
972 [('f', 'force', False, _('force')),
973 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
973 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
974 ('d', 'delete', False, _('delete a given bookmark')),
974 ('d', 'delete', False, _('delete a given bookmark')),
975 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
975 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
976 ('i', 'inactive', False, _('mark a bookmark inactive')),
976 ('i', 'inactive', False, _('mark a bookmark inactive')),
977 ] + formatteropts,
977 ] + formatteropts,
978 _('hg bookmarks [OPTIONS]... [NAME]...'))
978 _('hg bookmarks [OPTIONS]... [NAME]...'))
979 def bookmark(ui, repo, *names, **opts):
979 def bookmark(ui, repo, *names, **opts):
980 '''create a new bookmark or list existing bookmarks
980 '''create a new bookmark or list existing bookmarks
981
981
982 Bookmarks are labels on changesets to help track lines of development.
982 Bookmarks are labels on changesets to help track lines of development.
983 Bookmarks are unversioned and can be moved, renamed and deleted.
983 Bookmarks are unversioned and can be moved, renamed and deleted.
984 Deleting or moving a bookmark has no effect on the associated changesets.
984 Deleting or moving a bookmark has no effect on the associated changesets.
985
985
986 Creating or updating to a bookmark causes it to be marked as 'active'.
986 Creating or updating to a bookmark causes it to be marked as 'active'.
987 The active bookmark is indicated with a '*'.
987 The active bookmark is indicated with a '*'.
988 When a commit is made, the active bookmark will advance to the new commit.
988 When a commit is made, the active bookmark will advance to the new commit.
989 A plain :hg:`update` will also advance an active bookmark, if possible.
989 A plain :hg:`update` will also advance an active bookmark, if possible.
990 Updating away from a bookmark will cause it to be deactivated.
990 Updating away from a bookmark will cause it to be deactivated.
991
991
992 Bookmarks can be pushed and pulled between repositories (see
992 Bookmarks can be pushed and pulled between repositories (see
993 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
993 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
994 diverged, a new 'divergent bookmark' of the form 'name@path' will
994 diverged, a new 'divergent bookmark' of the form 'name@path' will
995 be created. Using :hg:`merge` will resolve the divergence.
995 be created. Using :hg:`merge` will resolve the divergence.
996
996
997 A bookmark named '@' has the special property that :hg:`clone` will
997 A bookmark named '@' has the special property that :hg:`clone` will
998 check it out by default if it exists.
998 check it out by default if it exists.
999
999
1000 .. container:: verbose
1000 .. container:: verbose
1001
1001
1002 Examples:
1002 Examples:
1003
1003
1004 - create an active bookmark for a new line of development::
1004 - create an active bookmark for a new line of development::
1005
1005
1006 hg book new-feature
1006 hg book new-feature
1007
1007
1008 - create an inactive bookmark as a place marker::
1008 - create an inactive bookmark as a place marker::
1009
1009
1010 hg book -i reviewed
1010 hg book -i reviewed
1011
1011
1012 - create an inactive bookmark on another changeset::
1012 - create an inactive bookmark on another changeset::
1013
1013
1014 hg book -r .^ tested
1014 hg book -r .^ tested
1015
1015
1016 - rename bookmark turkey to dinner::
1016 - rename bookmark turkey to dinner::
1017
1017
1018 hg book -m turkey dinner
1018 hg book -m turkey dinner
1019
1019
1020 - move the '@' bookmark from another branch::
1020 - move the '@' bookmark from another branch::
1021
1021
1022 hg book -f @
1022 hg book -f @
1023 '''
1023 '''
1024 force = opts.get('force')
1024 force = opts.get('force')
1025 rev = opts.get('rev')
1025 rev = opts.get('rev')
1026 delete = opts.get('delete')
1026 delete = opts.get('delete')
1027 rename = opts.get('rename')
1027 rename = opts.get('rename')
1028 inactive = opts.get('inactive')
1028 inactive = opts.get('inactive')
1029
1029
1030 def checkformat(mark):
1030 def checkformat(mark):
1031 mark = mark.strip()
1031 mark = mark.strip()
1032 if not mark:
1032 if not mark:
1033 raise error.Abort(_("bookmark names cannot consist entirely of "
1033 raise error.Abort(_("bookmark names cannot consist entirely of "
1034 "whitespace"))
1034 "whitespace"))
1035 scmutil.checknewlabel(repo, mark, 'bookmark')
1035 scmutil.checknewlabel(repo, mark, 'bookmark')
1036 return mark
1036 return mark
1037
1037
1038 def checkconflict(repo, mark, cur, force=False, target=None):
1038 def checkconflict(repo, mark, cur, force=False, target=None):
1039 if mark in marks and not force:
1039 if mark in marks and not force:
1040 if target:
1040 if target:
1041 if marks[mark] == target and target == cur:
1041 if marks[mark] == target and target == cur:
1042 # re-activating a bookmark
1042 # re-activating a bookmark
1043 return
1043 return
1044 anc = repo.changelog.ancestors([repo[target].rev()])
1044 anc = repo.changelog.ancestors([repo[target].rev()])
1045 bmctx = repo[marks[mark]]
1045 bmctx = repo[marks[mark]]
1046 divs = [repo[b].node() for b in marks
1046 divs = [repo[b].node() for b in marks
1047 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1047 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1048
1048
1049 # allow resolving a single divergent bookmark even if moving
1049 # allow resolving a single divergent bookmark even if moving
1050 # the bookmark across branches when a revision is specified
1050 # the bookmark across branches when a revision is specified
1051 # that contains a divergent bookmark
1051 # that contains a divergent bookmark
1052 if bmctx.rev() not in anc and target in divs:
1052 if bmctx.rev() not in anc and target in divs:
1053 bookmarks.deletedivergent(repo, [target], mark)
1053 bookmarks.deletedivergent(repo, [target], mark)
1054 return
1054 return
1055
1055
1056 deletefrom = [b for b in divs
1056 deletefrom = [b for b in divs
1057 if repo[b].rev() in anc or b == target]
1057 if repo[b].rev() in anc or b == target]
1058 bookmarks.deletedivergent(repo, deletefrom, mark)
1058 bookmarks.deletedivergent(repo, deletefrom, mark)
1059 if bookmarks.validdest(repo, bmctx, repo[target]):
1059 if bookmarks.validdest(repo, bmctx, repo[target]):
1060 ui.status(_("moving bookmark '%s' forward from %s\n") %
1060 ui.status(_("moving bookmark '%s' forward from %s\n") %
1061 (mark, short(bmctx.node())))
1061 (mark, short(bmctx.node())))
1062 return
1062 return
1063 raise error.Abort(_("bookmark '%s' already exists "
1063 raise error.Abort(_("bookmark '%s' already exists "
1064 "(use -f to force)") % mark)
1064 "(use -f to force)") % mark)
1065 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1065 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1066 and not force):
1066 and not force):
1067 raise error.Abort(
1067 raise error.Abort(
1068 _("a bookmark cannot have the name of an existing branch"))
1068 _("a bookmark cannot have the name of an existing branch"))
1069
1069
1070 if delete and rename:
1070 if delete and rename:
1071 raise error.Abort(_("--delete and --rename are incompatible"))
1071 raise error.Abort(_("--delete and --rename are incompatible"))
1072 if delete and rev:
1072 if delete and rev:
1073 raise error.Abort(_("--rev is incompatible with --delete"))
1073 raise error.Abort(_("--rev is incompatible with --delete"))
1074 if rename and rev:
1074 if rename and rev:
1075 raise error.Abort(_("--rev is incompatible with --rename"))
1075 raise error.Abort(_("--rev is incompatible with --rename"))
1076 if not names and (delete or rev):
1076 if not names and (delete or rev):
1077 raise error.Abort(_("bookmark name required"))
1077 raise error.Abort(_("bookmark name required"))
1078
1078
1079 if delete or rename or names or inactive:
1079 if delete or rename or names or inactive:
1080 wlock = lock = tr = None
1080 wlock = lock = tr = None
1081 try:
1081 try:
1082 wlock = repo.wlock()
1082 wlock = repo.wlock()
1083 lock = repo.lock()
1083 lock = repo.lock()
1084 cur = repo.changectx('.').node()
1084 cur = repo.changectx('.').node()
1085 marks = repo._bookmarks
1085 marks = repo._bookmarks
1086 if delete:
1086 if delete:
1087 tr = repo.transaction('bookmark')
1087 tr = repo.transaction('bookmark')
1088 for mark in names:
1088 for mark in names:
1089 if mark not in marks:
1089 if mark not in marks:
1090 raise error.Abort(_("bookmark '%s' does not exist") %
1090 raise error.Abort(_("bookmark '%s' does not exist") %
1091 mark)
1091 mark)
1092 if mark == repo._activebookmark:
1092 if mark == repo._activebookmark:
1093 bookmarks.deactivate(repo)
1093 bookmarks.deactivate(repo)
1094 del marks[mark]
1094 del marks[mark]
1095
1095
1096 elif rename:
1096 elif rename:
1097 tr = repo.transaction('bookmark')
1097 tr = repo.transaction('bookmark')
1098 if not names:
1098 if not names:
1099 raise error.Abort(_("new bookmark name required"))
1099 raise error.Abort(_("new bookmark name required"))
1100 elif len(names) > 1:
1100 elif len(names) > 1:
1101 raise error.Abort(_("only one new bookmark name allowed"))
1101 raise error.Abort(_("only one new bookmark name allowed"))
1102 mark = checkformat(names[0])
1102 mark = checkformat(names[0])
1103 if rename not in marks:
1103 if rename not in marks:
1104 raise error.Abort(_("bookmark '%s' does not exist")
1104 raise error.Abort(_("bookmark '%s' does not exist")
1105 % rename)
1105 % rename)
1106 checkconflict(repo, mark, cur, force)
1106 checkconflict(repo, mark, cur, force)
1107 marks[mark] = marks[rename]
1107 marks[mark] = marks[rename]
1108 if repo._activebookmark == rename and not inactive:
1108 if repo._activebookmark == rename and not inactive:
1109 bookmarks.activate(repo, mark)
1109 bookmarks.activate(repo, mark)
1110 del marks[rename]
1110 del marks[rename]
1111 elif names:
1111 elif names:
1112 tr = repo.transaction('bookmark')
1112 tr = repo.transaction('bookmark')
1113 newact = None
1113 newact = None
1114 for mark in names:
1114 for mark in names:
1115 mark = checkformat(mark)
1115 mark = checkformat(mark)
1116 if newact is None:
1116 if newact is None:
1117 newact = mark
1117 newact = mark
1118 if inactive and mark == repo._activebookmark:
1118 if inactive and mark == repo._activebookmark:
1119 bookmarks.deactivate(repo)
1119 bookmarks.deactivate(repo)
1120 return
1120 return
1121 tgt = cur
1121 tgt = cur
1122 if rev:
1122 if rev:
1123 tgt = scmutil.revsingle(repo, rev).node()
1123 tgt = scmutil.revsingle(repo, rev).node()
1124 checkconflict(repo, mark, cur, force, tgt)
1124 checkconflict(repo, mark, cur, force, tgt)
1125 marks[mark] = tgt
1125 marks[mark] = tgt
1126 if not inactive and cur == marks[newact] and not rev:
1126 if not inactive and cur == marks[newact] and not rev:
1127 bookmarks.activate(repo, newact)
1127 bookmarks.activate(repo, newact)
1128 elif cur != tgt and newact == repo._activebookmark:
1128 elif cur != tgt and newact == repo._activebookmark:
1129 bookmarks.deactivate(repo)
1129 bookmarks.deactivate(repo)
1130 elif inactive:
1130 elif inactive:
1131 if len(marks) == 0:
1131 if len(marks) == 0:
1132 ui.status(_("no bookmarks set\n"))
1132 ui.status(_("no bookmarks set\n"))
1133 elif not repo._activebookmark:
1133 elif not repo._activebookmark:
1134 ui.status(_("no active bookmark\n"))
1134 ui.status(_("no active bookmark\n"))
1135 else:
1135 else:
1136 bookmarks.deactivate(repo)
1136 bookmarks.deactivate(repo)
1137 if tr is not None:
1137 if tr is not None:
1138 marks.recordchange(tr)
1138 marks.recordchange(tr)
1139 tr.close()
1139 tr.close()
1140 finally:
1140 finally:
1141 lockmod.release(tr, lock, wlock)
1141 lockmod.release(tr, lock, wlock)
1142 else: # show bookmarks
1142 else: # show bookmarks
1143 fm = ui.formatter('bookmarks', opts)
1143 fm = ui.formatter('bookmarks', opts)
1144 hexfn = fm.hexfunc
1144 hexfn = fm.hexfunc
1145 marks = repo._bookmarks
1145 marks = repo._bookmarks
1146 if len(marks) == 0 and not fm:
1146 if len(marks) == 0 and not fm:
1147 ui.status(_("no bookmarks set\n"))
1147 ui.status(_("no bookmarks set\n"))
1148 for bmark, n in sorted(marks.iteritems()):
1148 for bmark, n in sorted(marks.iteritems()):
1149 active = repo._activebookmark
1149 active = repo._activebookmark
1150 if bmark == active:
1150 if bmark == active:
1151 prefix, label = '*', activebookmarklabel
1151 prefix, label = '*', activebookmarklabel
1152 else:
1152 else:
1153 prefix, label = ' ', ''
1153 prefix, label = ' ', ''
1154
1154
1155 fm.startitem()
1155 fm.startitem()
1156 if not ui.quiet:
1156 if not ui.quiet:
1157 fm.plain(' %s ' % prefix, label=label)
1157 fm.plain(' %s ' % prefix, label=label)
1158 fm.write('bookmark', '%s', bmark, label=label)
1158 fm.write('bookmark', '%s', bmark, label=label)
1159 pad = " " * (25 - encoding.colwidth(bmark))
1159 pad = " " * (25 - encoding.colwidth(bmark))
1160 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1160 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1161 repo.changelog.rev(n), hexfn(n), label=label)
1161 repo.changelog.rev(n), hexfn(n), label=label)
1162 fm.data(active=(bmark == active))
1162 fm.data(active=(bmark == active))
1163 fm.plain('\n')
1163 fm.plain('\n')
1164 fm.end()
1164 fm.end()
1165
1165
1166 @command('branch',
1166 @command('branch',
1167 [('f', 'force', None,
1167 [('f', 'force', None,
1168 _('set branch name even if it shadows an existing branch')),
1168 _('set branch name even if it shadows an existing branch')),
1169 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1169 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1170 _('[-fC] [NAME]'))
1170 _('[-fC] [NAME]'))
1171 def branch(ui, repo, label=None, **opts):
1171 def branch(ui, repo, label=None, **opts):
1172 """set or show the current branch name
1172 """set or show the current branch name
1173
1173
1174 .. note::
1174 .. note::
1175
1175
1176 Branch names are permanent and global. Use :hg:`bookmark` to create a
1176 Branch names are permanent and global. Use :hg:`bookmark` to create a
1177 light-weight bookmark instead. See :hg:`help glossary` for more
1177 light-weight bookmark instead. See :hg:`help glossary` for more
1178 information about named branches and bookmarks.
1178 information about named branches and bookmarks.
1179
1179
1180 With no argument, show the current branch name. With one argument,
1180 With no argument, show the current branch name. With one argument,
1181 set the working directory branch name (the branch will not exist
1181 set the working directory branch name (the branch will not exist
1182 in the repository until the next commit). Standard practice
1182 in the repository until the next commit). Standard practice
1183 recommends that primary development take place on the 'default'
1183 recommends that primary development take place on the 'default'
1184 branch.
1184 branch.
1185
1185
1186 Unless -f/--force is specified, branch will not let you set a
1186 Unless -f/--force is specified, branch will not let you set a
1187 branch name that already exists.
1187 branch name that already exists.
1188
1188
1189 Use -C/--clean to reset the working directory branch to that of
1189 Use -C/--clean to reset the working directory branch to that of
1190 the parent of the working directory, negating a previous branch
1190 the parent of the working directory, negating a previous branch
1191 change.
1191 change.
1192
1192
1193 Use the command :hg:`update` to switch to an existing branch. Use
1193 Use the command :hg:`update` to switch to an existing branch. Use
1194 :hg:`commit --close-branch` to mark this branch head as closed.
1194 :hg:`commit --close-branch` to mark this branch head as closed.
1195 When all heads of a branch are closed, the branch will be
1195 When all heads of a branch are closed, the branch will be
1196 considered closed.
1196 considered closed.
1197
1197
1198 Returns 0 on success.
1198 Returns 0 on success.
1199 """
1199 """
1200 if label:
1200 if label:
1201 label = label.strip()
1201 label = label.strip()
1202
1202
1203 if not opts.get('clean') and not label:
1203 if not opts.get('clean') and not label:
1204 ui.write("%s\n" % repo.dirstate.branch())
1204 ui.write("%s\n" % repo.dirstate.branch())
1205 return
1205 return
1206
1206
1207 with repo.wlock():
1207 with repo.wlock():
1208 if opts.get('clean'):
1208 if opts.get('clean'):
1209 label = repo[None].p1().branch()
1209 label = repo[None].p1().branch()
1210 repo.dirstate.setbranch(label)
1210 repo.dirstate.setbranch(label)
1211 ui.status(_('reset working directory to branch %s\n') % label)
1211 ui.status(_('reset working directory to branch %s\n') % label)
1212 elif label:
1212 elif label:
1213 if not opts.get('force') and label in repo.branchmap():
1213 if not opts.get('force') and label in repo.branchmap():
1214 if label not in [p.branch() for p in repo[None].parents()]:
1214 if label not in [p.branch() for p in repo[None].parents()]:
1215 raise error.Abort(_('a branch of the same name already'
1215 raise error.Abort(_('a branch of the same name already'
1216 ' exists'),
1216 ' exists'),
1217 # i18n: "it" refers to an existing branch
1217 # i18n: "it" refers to an existing branch
1218 hint=_("use 'hg update' to switch to it"))
1218 hint=_("use 'hg update' to switch to it"))
1219 scmutil.checknewlabel(repo, label, 'branch')
1219 scmutil.checknewlabel(repo, label, 'branch')
1220 repo.dirstate.setbranch(label)
1220 repo.dirstate.setbranch(label)
1221 ui.status(_('marked working directory as branch %s\n') % label)
1221 ui.status(_('marked working directory as branch %s\n') % label)
1222
1222
1223 # find any open named branches aside from default
1223 # find any open named branches aside from default
1224 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1224 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1225 if n != "default" and not c]
1225 if n != "default" and not c]
1226 if not others:
1226 if not others:
1227 ui.status(_('(branches are permanent and global, '
1227 ui.status(_('(branches are permanent and global, '
1228 'did you want a bookmark?)\n'))
1228 'did you want a bookmark?)\n'))
1229
1229
1230 @command('branches',
1230 @command('branches',
1231 [('a', 'active', False,
1231 [('a', 'active', False,
1232 _('show only branches that have unmerged heads (DEPRECATED)')),
1232 _('show only branches that have unmerged heads (DEPRECATED)')),
1233 ('c', 'closed', False, _('show normal and closed branches')),
1233 ('c', 'closed', False, _('show normal and closed branches')),
1234 ] + formatteropts,
1234 ] + formatteropts,
1235 _('[-ac]'))
1235 _('[-ac]'))
1236 def branches(ui, repo, active=False, closed=False, **opts):
1236 def branches(ui, repo, active=False, closed=False, **opts):
1237 """list repository named branches
1237 """list repository named branches
1238
1238
1239 List the repository's named branches, indicating which ones are
1239 List the repository's named branches, indicating which ones are
1240 inactive. If -c/--closed is specified, also list branches which have
1240 inactive. If -c/--closed is specified, also list branches which have
1241 been marked closed (see :hg:`commit --close-branch`).
1241 been marked closed (see :hg:`commit --close-branch`).
1242
1242
1243 Use the command :hg:`update` to switch to an existing branch.
1243 Use the command :hg:`update` to switch to an existing branch.
1244
1244
1245 Returns 0.
1245 Returns 0.
1246 """
1246 """
1247
1247
1248 fm = ui.formatter('branches', opts)
1248 fm = ui.formatter('branches', opts)
1249 hexfunc = fm.hexfunc
1249 hexfunc = fm.hexfunc
1250
1250
1251 allheads = set(repo.heads())
1251 allheads = set(repo.heads())
1252 branches = []
1252 branches = []
1253 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1253 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1254 isactive = not isclosed and bool(set(heads) & allheads)
1254 isactive = not isclosed and bool(set(heads) & allheads)
1255 branches.append((tag, repo[tip], isactive, not isclosed))
1255 branches.append((tag, repo[tip], isactive, not isclosed))
1256 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1256 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1257 reverse=True)
1257 reverse=True)
1258
1258
1259 for tag, ctx, isactive, isopen in branches:
1259 for tag, ctx, isactive, isopen in branches:
1260 if active and not isactive:
1260 if active and not isactive:
1261 continue
1261 continue
1262 if isactive:
1262 if isactive:
1263 label = 'branches.active'
1263 label = 'branches.active'
1264 notice = ''
1264 notice = ''
1265 elif not isopen:
1265 elif not isopen:
1266 if not closed:
1266 if not closed:
1267 continue
1267 continue
1268 label = 'branches.closed'
1268 label = 'branches.closed'
1269 notice = _(' (closed)')
1269 notice = _(' (closed)')
1270 else:
1270 else:
1271 label = 'branches.inactive'
1271 label = 'branches.inactive'
1272 notice = _(' (inactive)')
1272 notice = _(' (inactive)')
1273 current = (tag == repo.dirstate.branch())
1273 current = (tag == repo.dirstate.branch())
1274 if current:
1274 if current:
1275 label = 'branches.current'
1275 label = 'branches.current'
1276
1276
1277 fm.startitem()
1277 fm.startitem()
1278 fm.write('branch', '%s', tag, label=label)
1278 fm.write('branch', '%s', tag, label=label)
1279 rev = ctx.rev()
1279 rev = ctx.rev()
1280 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1280 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1281 fmt = ' ' * padsize + ' %d:%s'
1281 fmt = ' ' * padsize + ' %d:%s'
1282 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1282 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1283 label='log.changeset changeset.%s' % ctx.phasestr())
1283 label='log.changeset changeset.%s' % ctx.phasestr())
1284 fm.data(active=isactive, closed=not isopen, current=current)
1284 fm.data(active=isactive, closed=not isopen, current=current)
1285 if not ui.quiet:
1285 if not ui.quiet:
1286 fm.plain(notice)
1286 fm.plain(notice)
1287 fm.plain('\n')
1287 fm.plain('\n')
1288 fm.end()
1288 fm.end()
1289
1289
1290 @command('bundle',
1290 @command('bundle',
1291 [('f', 'force', None, _('run even when the destination is unrelated')),
1291 [('f', 'force', None, _('run even when the destination is unrelated')),
1292 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1292 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1293 _('REV')),
1293 _('REV')),
1294 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1294 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1295 _('BRANCH')),
1295 _('BRANCH')),
1296 ('', 'base', [],
1296 ('', 'base', [],
1297 _('a base changeset assumed to be available at the destination'),
1297 _('a base changeset assumed to be available at the destination'),
1298 _('REV')),
1298 _('REV')),
1299 ('a', 'all', None, _('bundle all changesets in the repository')),
1299 ('a', 'all', None, _('bundle all changesets in the repository')),
1300 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1300 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1301 ] + remoteopts,
1301 ] + remoteopts,
1302 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1302 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1303 def bundle(ui, repo, fname, dest=None, **opts):
1303 def bundle(ui, repo, fname, dest=None, **opts):
1304 """create a changegroup file
1304 """create a changegroup file
1305
1305
1306 Generate a changegroup file collecting changesets to be added
1306 Generate a changegroup file collecting changesets to be added
1307 to a repository.
1307 to a repository.
1308
1308
1309 To create a bundle containing all changesets, use -a/--all
1309 To create a bundle containing all changesets, use -a/--all
1310 (or --base null). Otherwise, hg assumes the destination will have
1310 (or --base null). Otherwise, hg assumes the destination will have
1311 all the nodes you specify with --base parameters. Otherwise, hg
1311 all the nodes you specify with --base parameters. Otherwise, hg
1312 will assume the repository has all the nodes in destination, or
1312 will assume the repository has all the nodes in destination, or
1313 default-push/default if no destination is specified.
1313 default-push/default if no destination is specified.
1314
1314
1315 You can change bundle format with the -t/--type option. You can
1315 You can change bundle format with the -t/--type option. You can
1316 specify a compression, a bundle version or both using a dash
1316 specify a compression, a bundle version or both using a dash
1317 (comp-version). The available compression methods are: none, bzip2,
1317 (comp-version). The available compression methods are: none, bzip2,
1318 and gzip (by default, bundles are compressed using bzip2). The
1318 and gzip (by default, bundles are compressed using bzip2). The
1319 available formats are: v1, v2 (default to most suitable).
1319 available formats are: v1, v2 (default to most suitable).
1320
1320
1321 The bundle file can then be transferred using conventional means
1321 The bundle file can then be transferred using conventional means
1322 and applied to another repository with the unbundle or pull
1322 and applied to another repository with the unbundle or pull
1323 command. This is useful when direct push and pull are not
1323 command. This is useful when direct push and pull are not
1324 available or when exporting an entire repository is undesirable.
1324 available or when exporting an entire repository is undesirable.
1325
1325
1326 Applying bundles preserves all changeset contents including
1326 Applying bundles preserves all changeset contents including
1327 permissions, copy/rename information, and revision history.
1327 permissions, copy/rename information, and revision history.
1328
1328
1329 Returns 0 on success, 1 if no changes found.
1329 Returns 0 on success, 1 if no changes found.
1330 """
1330 """
1331 revs = None
1331 revs = None
1332 if 'rev' in opts:
1332 if 'rev' in opts:
1333 revstrings = opts['rev']
1333 revstrings = opts['rev']
1334 revs = scmutil.revrange(repo, revstrings)
1334 revs = scmutil.revrange(repo, revstrings)
1335 if revstrings and not revs:
1335 if revstrings and not revs:
1336 raise error.Abort(_('no commits to bundle'))
1336 raise error.Abort(_('no commits to bundle'))
1337
1337
1338 bundletype = opts.get('type', 'bzip2').lower()
1338 bundletype = opts.get('type', 'bzip2').lower()
1339 try:
1339 try:
1340 bcompression, cgversion, params = exchange.parsebundlespec(
1340 bcompression, cgversion, params = exchange.parsebundlespec(
1341 repo, bundletype, strict=False)
1341 repo, bundletype, strict=False)
1342 except error.UnsupportedBundleSpecification as e:
1342 except error.UnsupportedBundleSpecification as e:
1343 raise error.Abort(str(e),
1343 raise error.Abort(str(e),
1344 hint=_('see "hg help bundle" for supported '
1344 hint=_('see "hg help bundle" for supported '
1345 'values for --type'))
1345 'values for --type'))
1346
1346
1347 # Packed bundles are a pseudo bundle format for now.
1347 # Packed bundles are a pseudo bundle format for now.
1348 if cgversion == 's1':
1348 if cgversion == 's1':
1349 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1349 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1350 hint=_('use "hg debugcreatestreamclonebundle"'))
1350 hint=_('use "hg debugcreatestreamclonebundle"'))
1351
1351
1352 if opts.get('all'):
1352 if opts.get('all'):
1353 if dest:
1353 if dest:
1354 raise error.Abort(_("--all is incompatible with specifying "
1354 raise error.Abort(_("--all is incompatible with specifying "
1355 "a destination"))
1355 "a destination"))
1356 if opts.get('base'):
1356 if opts.get('base'):
1357 ui.warn(_("ignoring --base because --all was specified\n"))
1357 ui.warn(_("ignoring --base because --all was specified\n"))
1358 base = ['null']
1358 base = ['null']
1359 else:
1359 else:
1360 base = scmutil.revrange(repo, opts.get('base'))
1360 base = scmutil.revrange(repo, opts.get('base'))
1361 # TODO: get desired bundlecaps from command line.
1361 # TODO: get desired bundlecaps from command line.
1362 bundlecaps = None
1362 bundlecaps = None
1363 if base:
1363 if base:
1364 if dest:
1364 if dest:
1365 raise error.Abort(_("--base is incompatible with specifying "
1365 raise error.Abort(_("--base is incompatible with specifying "
1366 "a destination"))
1366 "a destination"))
1367 common = [repo.lookup(rev) for rev in base]
1367 common = [repo.lookup(rev) for rev in base]
1368 heads = revs and map(repo.lookup, revs) or revs
1368 heads = revs and map(repo.lookup, revs) or revs
1369 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1369 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1370 common=common, bundlecaps=bundlecaps,
1370 common=common, bundlecaps=bundlecaps,
1371 version=cgversion)
1371 version=cgversion)
1372 outgoing = None
1372 outgoing = None
1373 else:
1373 else:
1374 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1374 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1375 dest, branches = hg.parseurl(dest, opts.get('branch'))
1375 dest, branches = hg.parseurl(dest, opts.get('branch'))
1376 other = hg.peer(repo, opts, dest)
1376 other = hg.peer(repo, opts, dest)
1377 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1377 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1378 heads = revs and map(repo.lookup, revs) or revs
1378 heads = revs and map(repo.lookup, revs) or revs
1379 outgoing = discovery.findcommonoutgoing(repo, other,
1379 outgoing = discovery.findcommonoutgoing(repo, other,
1380 onlyheads=heads,
1380 onlyheads=heads,
1381 force=opts.get('force'),
1381 force=opts.get('force'),
1382 portable=True)
1382 portable=True)
1383 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1383 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1384 bundlecaps, version=cgversion)
1384 bundlecaps, version=cgversion)
1385 if not cg:
1385 if not cg:
1386 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1386 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1387 return 1
1387 return 1
1388
1388
1389 if cgversion == '01': #bundle1
1389 if cgversion == '01': #bundle1
1390 if bcompression is None:
1390 if bcompression is None:
1391 bcompression = 'UN'
1391 bcompression = 'UN'
1392 bversion = 'HG10' + bcompression
1392 bversion = 'HG10' + bcompression
1393 bcompression = None
1393 bcompression = None
1394 else:
1394 else:
1395 assert cgversion == '02'
1395 assert cgversion == '02'
1396 bversion = 'HG20'
1396 bversion = 'HG20'
1397
1397
1398
1398
1399 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1399 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1400
1400
1401 @command('cat',
1401 @command('cat',
1402 [('o', 'output', '',
1402 [('o', 'output', '',
1403 _('print output to file with formatted name'), _('FORMAT')),
1403 _('print output to file with formatted name'), _('FORMAT')),
1404 ('r', 'rev', '', _('print the given revision'), _('REV')),
1404 ('r', 'rev', '', _('print the given revision'), _('REV')),
1405 ('', 'decode', None, _('apply any matching decode filter')),
1405 ('', 'decode', None, _('apply any matching decode filter')),
1406 ] + walkopts,
1406 ] + walkopts,
1407 _('[OPTION]... FILE...'),
1407 _('[OPTION]... FILE...'),
1408 inferrepo=True)
1408 inferrepo=True)
1409 def cat(ui, repo, file1, *pats, **opts):
1409 def cat(ui, repo, file1, *pats, **opts):
1410 """output the current or given revision of files
1410 """output the current or given revision of files
1411
1411
1412 Print the specified files as they were at the given revision. If
1412 Print the specified files as they were at the given revision. If
1413 no revision is given, the parent of the working directory is used.
1413 no revision is given, the parent of the working directory is used.
1414
1414
1415 Output may be to a file, in which case the name of the file is
1415 Output may be to a file, in which case the name of the file is
1416 given using a format string. The formatting rules as follows:
1416 given using a format string. The formatting rules as follows:
1417
1417
1418 :``%%``: literal "%" character
1418 :``%%``: literal "%" character
1419 :``%s``: basename of file being printed
1419 :``%s``: basename of file being printed
1420 :``%d``: dirname of file being printed, or '.' if in repository root
1420 :``%d``: dirname of file being printed, or '.' if in repository root
1421 :``%p``: root-relative path name of file being printed
1421 :``%p``: root-relative path name of file being printed
1422 :``%H``: changeset hash (40 hexadecimal digits)
1422 :``%H``: changeset hash (40 hexadecimal digits)
1423 :``%R``: changeset revision number
1423 :``%R``: changeset revision number
1424 :``%h``: short-form changeset hash (12 hexadecimal digits)
1424 :``%h``: short-form changeset hash (12 hexadecimal digits)
1425 :``%r``: zero-padded changeset revision number
1425 :``%r``: zero-padded changeset revision number
1426 :``%b``: basename of the exporting repository
1426 :``%b``: basename of the exporting repository
1427
1427
1428 Returns 0 on success.
1428 Returns 0 on success.
1429 """
1429 """
1430 ctx = scmutil.revsingle(repo, opts.get('rev'))
1430 ctx = scmutil.revsingle(repo, opts.get('rev'))
1431 m = scmutil.match(ctx, (file1,) + pats, opts)
1431 m = scmutil.match(ctx, (file1,) + pats, opts)
1432
1432
1433 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1433 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1434
1434
1435 @command('^clone',
1435 @command('^clone',
1436 [('U', 'noupdate', None, _('the clone will include an empty working '
1436 [('U', 'noupdate', None, _('the clone will include an empty working '
1437 'directory (only a repository)')),
1437 'directory (only a repository)')),
1438 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1438 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1439 _('REV')),
1439 _('REV')),
1440 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1440 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1441 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1441 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1442 ('', 'pull', None, _('use pull protocol to copy metadata')),
1442 ('', 'pull', None, _('use pull protocol to copy metadata')),
1443 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1443 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1444 ] + remoteopts,
1444 ] + remoteopts,
1445 _('[OPTION]... SOURCE [DEST]'),
1445 _('[OPTION]... SOURCE [DEST]'),
1446 norepo=True)
1446 norepo=True)
1447 def clone(ui, source, dest=None, **opts):
1447 def clone(ui, source, dest=None, **opts):
1448 """make a copy of an existing repository
1448 """make a copy of an existing repository
1449
1449
1450 Create a copy of an existing repository in a new directory.
1450 Create a copy of an existing repository in a new directory.
1451
1451
1452 If no destination directory name is specified, it defaults to the
1452 If no destination directory name is specified, it defaults to the
1453 basename of the source.
1453 basename of the source.
1454
1454
1455 The location of the source is added to the new repository's
1455 The location of the source is added to the new repository's
1456 ``.hg/hgrc`` file, as the default to be used for future pulls.
1456 ``.hg/hgrc`` file, as the default to be used for future pulls.
1457
1457
1458 Only local paths and ``ssh://`` URLs are supported as
1458 Only local paths and ``ssh://`` URLs are supported as
1459 destinations. For ``ssh://`` destinations, no working directory or
1459 destinations. For ``ssh://`` destinations, no working directory or
1460 ``.hg/hgrc`` will be created on the remote side.
1460 ``.hg/hgrc`` will be created on the remote side.
1461
1461
1462 If the source repository has a bookmark called '@' set, that
1462 If the source repository has a bookmark called '@' set, that
1463 revision will be checked out in the new repository by default.
1463 revision will be checked out in the new repository by default.
1464
1464
1465 To check out a particular version, use -u/--update, or
1465 To check out a particular version, use -u/--update, or
1466 -U/--noupdate to create a clone with no working directory.
1466 -U/--noupdate to create a clone with no working directory.
1467
1467
1468 To pull only a subset of changesets, specify one or more revisions
1468 To pull only a subset of changesets, specify one or more revisions
1469 identifiers with -r/--rev or branches with -b/--branch. The
1469 identifiers with -r/--rev or branches with -b/--branch. The
1470 resulting clone will contain only the specified changesets and
1470 resulting clone will contain only the specified changesets and
1471 their ancestors. These options (or 'clone src#rev dest') imply
1471 their ancestors. These options (or 'clone src#rev dest') imply
1472 --pull, even for local source repositories.
1472 --pull, even for local source repositories.
1473
1473
1474 .. note::
1474 .. note::
1475
1475
1476 Specifying a tag will include the tagged changeset but not the
1476 Specifying a tag will include the tagged changeset but not the
1477 changeset containing the tag.
1477 changeset containing the tag.
1478
1478
1479 .. container:: verbose
1479 .. container:: verbose
1480
1480
1481 For efficiency, hardlinks are used for cloning whenever the
1481 For efficiency, hardlinks are used for cloning whenever the
1482 source and destination are on the same filesystem (note this
1482 source and destination are on the same filesystem (note this
1483 applies only to the repository data, not to the working
1483 applies only to the repository data, not to the working
1484 directory). Some filesystems, such as AFS, implement hardlinking
1484 directory). Some filesystems, such as AFS, implement hardlinking
1485 incorrectly, but do not report errors. In these cases, use the
1485 incorrectly, but do not report errors. In these cases, use the
1486 --pull option to avoid hardlinking.
1486 --pull option to avoid hardlinking.
1487
1487
1488 In some cases, you can clone repositories and the working
1488 In some cases, you can clone repositories and the working
1489 directory using full hardlinks with ::
1489 directory using full hardlinks with ::
1490
1490
1491 $ cp -al REPO REPOCLONE
1491 $ cp -al REPO REPOCLONE
1492
1492
1493 This is the fastest way to clone, but it is not always safe. The
1493 This is the fastest way to clone, but it is not always safe. The
1494 operation is not atomic (making sure REPO is not modified during
1494 operation is not atomic (making sure REPO is not modified during
1495 the operation is up to you) and you have to make sure your
1495 the operation is up to you) and you have to make sure your
1496 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1496 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1497 so). Also, this is not compatible with certain extensions that
1497 so). Also, this is not compatible with certain extensions that
1498 place their metadata under the .hg directory, such as mq.
1498 place their metadata under the .hg directory, such as mq.
1499
1499
1500 Mercurial will update the working directory to the first applicable
1500 Mercurial will update the working directory to the first applicable
1501 revision from this list:
1501 revision from this list:
1502
1502
1503 a) null if -U or the source repository has no changesets
1503 a) null if -U or the source repository has no changesets
1504 b) if -u . and the source repository is local, the first parent of
1504 b) if -u . and the source repository is local, the first parent of
1505 the source repository's working directory
1505 the source repository's working directory
1506 c) the changeset specified with -u (if a branch name, this means the
1506 c) the changeset specified with -u (if a branch name, this means the
1507 latest head of that branch)
1507 latest head of that branch)
1508 d) the changeset specified with -r
1508 d) the changeset specified with -r
1509 e) the tipmost head specified with -b
1509 e) the tipmost head specified with -b
1510 f) the tipmost head specified with the url#branch source syntax
1510 f) the tipmost head specified with the url#branch source syntax
1511 g) the revision marked with the '@' bookmark, if present
1511 g) the revision marked with the '@' bookmark, if present
1512 h) the tipmost head of the default branch
1512 h) the tipmost head of the default branch
1513 i) tip
1513 i) tip
1514
1514
1515 When cloning from servers that support it, Mercurial may fetch
1515 When cloning from servers that support it, Mercurial may fetch
1516 pre-generated data from a server-advertised URL. When this is done,
1516 pre-generated data from a server-advertised URL. When this is done,
1517 hooks operating on incoming changesets and changegroups may fire twice,
1517 hooks operating on incoming changesets and changegroups may fire twice,
1518 once for the bundle fetched from the URL and another for any additional
1518 once for the bundle fetched from the URL and another for any additional
1519 data not fetched from this URL. In addition, if an error occurs, the
1519 data not fetched from this URL. In addition, if an error occurs, the
1520 repository may be rolled back to a partial clone. This behavior may
1520 repository may be rolled back to a partial clone. This behavior may
1521 change in future releases. See :hg:`help -e clonebundles` for more.
1521 change in future releases. See :hg:`help -e clonebundles` for more.
1522
1522
1523 Examples:
1523 Examples:
1524
1524
1525 - clone a remote repository to a new directory named hg/::
1525 - clone a remote repository to a new directory named hg/::
1526
1526
1527 hg clone http://selenic.com/hg
1527 hg clone http://selenic.com/hg
1528
1528
1529 - create a lightweight local clone::
1529 - create a lightweight local clone::
1530
1530
1531 hg clone project/ project-feature/
1531 hg clone project/ project-feature/
1532
1532
1533 - clone from an absolute path on an ssh server (note double-slash)::
1533 - clone from an absolute path on an ssh server (note double-slash)::
1534
1534
1535 hg clone ssh://user@server//home/projects/alpha/
1535 hg clone ssh://user@server//home/projects/alpha/
1536
1536
1537 - do a high-speed clone over a LAN while checking out a
1537 - do a high-speed clone over a LAN while checking out a
1538 specified version::
1538 specified version::
1539
1539
1540 hg clone --uncompressed http://server/repo -u 1.5
1540 hg clone --uncompressed http://server/repo -u 1.5
1541
1541
1542 - create a repository without changesets after a particular revision::
1542 - create a repository without changesets after a particular revision::
1543
1543
1544 hg clone -r 04e544 experimental/ good/
1544 hg clone -r 04e544 experimental/ good/
1545
1545
1546 - clone (and track) a particular named branch::
1546 - clone (and track) a particular named branch::
1547
1547
1548 hg clone http://selenic.com/hg#stable
1548 hg clone http://selenic.com/hg#stable
1549
1549
1550 See :hg:`help urls` for details on specifying URLs.
1550 See :hg:`help urls` for details on specifying URLs.
1551
1551
1552 Returns 0 on success.
1552 Returns 0 on success.
1553 """
1553 """
1554 if opts.get('noupdate') and opts.get('updaterev'):
1554 if opts.get('noupdate') and opts.get('updaterev'):
1555 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1555 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1556
1556
1557 r = hg.clone(ui, opts, source, dest,
1557 r = hg.clone(ui, opts, source, dest,
1558 pull=opts.get('pull'),
1558 pull=opts.get('pull'),
1559 stream=opts.get('uncompressed'),
1559 stream=opts.get('uncompressed'),
1560 rev=opts.get('rev'),
1560 rev=opts.get('rev'),
1561 update=opts.get('updaterev') or not opts.get('noupdate'),
1561 update=opts.get('updaterev') or not opts.get('noupdate'),
1562 branch=opts.get('branch'),
1562 branch=opts.get('branch'),
1563 shareopts=opts.get('shareopts'))
1563 shareopts=opts.get('shareopts'))
1564
1564
1565 return r is None
1565 return r is None
1566
1566
1567 @command('^commit|ci',
1567 @command('^commit|ci',
1568 [('A', 'addremove', None,
1568 [('A', 'addremove', None,
1569 _('mark new/missing files as added/removed before committing')),
1569 _('mark new/missing files as added/removed before committing')),
1570 ('', 'close-branch', None,
1570 ('', 'close-branch', None,
1571 _('mark a branch head as closed')),
1571 _('mark a branch head as closed')),
1572 ('', 'amend', None, _('amend the parent of the working directory')),
1572 ('', 'amend', None, _('amend the parent of the working directory')),
1573 ('s', 'secret', None, _('use the secret phase for committing')),
1573 ('s', 'secret', None, _('use the secret phase for committing')),
1574 ('e', 'edit', None, _('invoke editor on commit messages')),
1574 ('e', 'edit', None, _('invoke editor on commit messages')),
1575 ('i', 'interactive', None, _('use interactive mode')),
1575 ('i', 'interactive', None, _('use interactive mode')),
1576 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1576 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1577 _('[OPTION]... [FILE]...'),
1577 _('[OPTION]... [FILE]...'),
1578 inferrepo=True)
1578 inferrepo=True)
1579 def commit(ui, repo, *pats, **opts):
1579 def commit(ui, repo, *pats, **opts):
1580 """commit the specified files or all outstanding changes
1580 """commit the specified files or all outstanding changes
1581
1581
1582 Commit changes to the given files into the repository. Unlike a
1582 Commit changes to the given files into the repository. Unlike a
1583 centralized SCM, this operation is a local operation. See
1583 centralized SCM, this operation is a local operation. See
1584 :hg:`push` for a way to actively distribute your changes.
1584 :hg:`push` for a way to actively distribute your changes.
1585
1585
1586 If a list of files is omitted, all changes reported by :hg:`status`
1586 If a list of files is omitted, all changes reported by :hg:`status`
1587 will be committed.
1587 will be committed.
1588
1588
1589 If you are committing the result of a merge, do not provide any
1589 If you are committing the result of a merge, do not provide any
1590 filenames or -I/-X filters.
1590 filenames or -I/-X filters.
1591
1591
1592 If no commit message is specified, Mercurial starts your
1592 If no commit message is specified, Mercurial starts your
1593 configured editor where you can enter a message. In case your
1593 configured editor where you can enter a message. In case your
1594 commit fails, you will find a backup of your message in
1594 commit fails, you will find a backup of your message in
1595 ``.hg/last-message.txt``.
1595 ``.hg/last-message.txt``.
1596
1596
1597 The --close-branch flag can be used to mark the current branch
1597 The --close-branch flag can be used to mark the current branch
1598 head closed. When all heads of a branch are closed, the branch
1598 head closed. When all heads of a branch are closed, the branch
1599 will be considered closed and no longer listed.
1599 will be considered closed and no longer listed.
1600
1600
1601 The --amend flag can be used to amend the parent of the
1601 The --amend flag can be used to amend the parent of the
1602 working directory with a new commit that contains the changes
1602 working directory with a new commit that contains the changes
1603 in the parent in addition to those currently reported by :hg:`status`,
1603 in the parent in addition to those currently reported by :hg:`status`,
1604 if there are any. The old commit is stored in a backup bundle in
1604 if there are any. The old commit is stored in a backup bundle in
1605 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1605 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1606 on how to restore it).
1606 on how to restore it).
1607
1607
1608 Message, user and date are taken from the amended commit unless
1608 Message, user and date are taken from the amended commit unless
1609 specified. When a message isn't specified on the command line,
1609 specified. When a message isn't specified on the command line,
1610 the editor will open with the message of the amended commit.
1610 the editor will open with the message of the amended commit.
1611
1611
1612 It is not possible to amend public changesets (see :hg:`help phases`)
1612 It is not possible to amend public changesets (see :hg:`help phases`)
1613 or changesets that have children.
1613 or changesets that have children.
1614
1614
1615 See :hg:`help dates` for a list of formats valid for -d/--date.
1615 See :hg:`help dates` for a list of formats valid for -d/--date.
1616
1616
1617 Returns 0 on success, 1 if nothing changed.
1617 Returns 0 on success, 1 if nothing changed.
1618
1618
1619 .. container:: verbose
1619 .. container:: verbose
1620
1620
1621 Examples:
1621 Examples:
1622
1622
1623 - commit all files ending in .py::
1623 - commit all files ending in .py::
1624
1624
1625 hg commit --include "set:**.py"
1625 hg commit --include "set:**.py"
1626
1626
1627 - commit all non-binary files::
1627 - commit all non-binary files::
1628
1628
1629 hg commit --exclude "set:binary()"
1629 hg commit --exclude "set:binary()"
1630
1630
1631 - amend the current commit and set the date to now::
1631 - amend the current commit and set the date to now::
1632
1632
1633 hg commit --amend --date now
1633 hg commit --amend --date now
1634 """
1634 """
1635 wlock = lock = None
1635 wlock = lock = None
1636 try:
1636 try:
1637 wlock = repo.wlock()
1637 wlock = repo.wlock()
1638 lock = repo.lock()
1638 lock = repo.lock()
1639 return _docommit(ui, repo, *pats, **opts)
1639 return _docommit(ui, repo, *pats, **opts)
1640 finally:
1640 finally:
1641 release(lock, wlock)
1641 release(lock, wlock)
1642
1642
1643 def _docommit(ui, repo, *pats, **opts):
1643 def _docommit(ui, repo, *pats, **opts):
1644 if opts.get('interactive'):
1644 if opts.get('interactive'):
1645 opts.pop('interactive')
1645 opts.pop('interactive')
1646 cmdutil.dorecord(ui, repo, commit, None, False,
1646 cmdutil.dorecord(ui, repo, commit, None, False,
1647 cmdutil.recordfilter, *pats, **opts)
1647 cmdutil.recordfilter, *pats, **opts)
1648 return
1648 return
1649
1649
1650 if opts.get('subrepos'):
1650 if opts.get('subrepos'):
1651 if opts.get('amend'):
1651 if opts.get('amend'):
1652 raise error.Abort(_('cannot amend with --subrepos'))
1652 raise error.Abort(_('cannot amend with --subrepos'))
1653 # Let --subrepos on the command line override config setting.
1653 # Let --subrepos on the command line override config setting.
1654 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1654 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1655
1655
1656 cmdutil.checkunfinished(repo, commit=True)
1656 cmdutil.checkunfinished(repo, commit=True)
1657
1657
1658 branch = repo[None].branch()
1658 branch = repo[None].branch()
1659 bheads = repo.branchheads(branch)
1659 bheads = repo.branchheads(branch)
1660
1660
1661 extra = {}
1661 extra = {}
1662 if opts.get('close_branch'):
1662 if opts.get('close_branch'):
1663 extra['close'] = 1
1663 extra['close'] = 1
1664
1664
1665 if not bheads:
1665 if not bheads:
1666 raise error.Abort(_('can only close branch heads'))
1666 raise error.Abort(_('can only close branch heads'))
1667 elif opts.get('amend'):
1667 elif opts.get('amend'):
1668 if repo[None].parents()[0].p1().branch() != branch and \
1668 if repo[None].parents()[0].p1().branch() != branch and \
1669 repo[None].parents()[0].p2().branch() != branch:
1669 repo[None].parents()[0].p2().branch() != branch:
1670 raise error.Abort(_('can only close branch heads'))
1670 raise error.Abort(_('can only close branch heads'))
1671
1671
1672 if opts.get('amend'):
1672 if opts.get('amend'):
1673 if ui.configbool('ui', 'commitsubrepos'):
1673 if ui.configbool('ui', 'commitsubrepos'):
1674 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1674 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1675
1675
1676 old = repo['.']
1676 old = repo['.']
1677 if not old.mutable():
1677 if not old.mutable():
1678 raise error.Abort(_('cannot amend public changesets'))
1678 raise error.Abort(_('cannot amend public changesets'))
1679 if len(repo[None].parents()) > 1:
1679 if len(repo[None].parents()) > 1:
1680 raise error.Abort(_('cannot amend while merging'))
1680 raise error.Abort(_('cannot amend while merging'))
1681 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1681 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1682 if not allowunstable and old.children():
1682 if not allowunstable and old.children():
1683 raise error.Abort(_('cannot amend changeset with children'))
1683 raise error.Abort(_('cannot amend changeset with children'))
1684
1684
1685 # commitfunc is used only for temporary amend commit by cmdutil.amend
1685 # commitfunc is used only for temporary amend commit by cmdutil.amend
1686 def commitfunc(ui, repo, message, match, opts):
1686 def commitfunc(ui, repo, message, match, opts):
1687 return repo.commit(message,
1687 return repo.commit(message,
1688 opts.get('user') or old.user(),
1688 opts.get('user') or old.user(),
1689 opts.get('date') or old.date(),
1689 opts.get('date') or old.date(),
1690 match,
1690 match,
1691 extra=extra)
1691 extra=extra)
1692
1692
1693 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1693 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1694 if node == old.node():
1694 if node == old.node():
1695 ui.status(_("nothing changed\n"))
1695 ui.status(_("nothing changed\n"))
1696 return 1
1696 return 1
1697 else:
1697 else:
1698 def commitfunc(ui, repo, message, match, opts):
1698 def commitfunc(ui, repo, message, match, opts):
1699 backup = ui.backupconfig('phases', 'new-commit')
1699 backup = ui.backupconfig('phases', 'new-commit')
1700 baseui = repo.baseui
1700 baseui = repo.baseui
1701 basebackup = baseui.backupconfig('phases', 'new-commit')
1701 basebackup = baseui.backupconfig('phases', 'new-commit')
1702 try:
1702 try:
1703 if opts.get('secret'):
1703 if opts.get('secret'):
1704 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1704 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1705 # Propagate to subrepos
1705 # Propagate to subrepos
1706 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1706 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1707
1707
1708 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1708 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1709 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1709 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1710 return repo.commit(message, opts.get('user'), opts.get('date'),
1710 return repo.commit(message, opts.get('user'), opts.get('date'),
1711 match,
1711 match,
1712 editor=editor,
1712 editor=editor,
1713 extra=extra)
1713 extra=extra)
1714 finally:
1714 finally:
1715 ui.restoreconfig(backup)
1715 ui.restoreconfig(backup)
1716 repo.baseui.restoreconfig(basebackup)
1716 repo.baseui.restoreconfig(basebackup)
1717
1717
1718
1718
1719 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1719 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1720
1720
1721 if not node:
1721 if not node:
1722 stat = cmdutil.postcommitstatus(repo, pats, opts)
1722 stat = cmdutil.postcommitstatus(repo, pats, opts)
1723 if stat[3]:
1723 if stat[3]:
1724 ui.status(_("nothing changed (%d missing files, see "
1724 ui.status(_("nothing changed (%d missing files, see "
1725 "'hg status')\n") % len(stat[3]))
1725 "'hg status')\n") % len(stat[3]))
1726 else:
1726 else:
1727 ui.status(_("nothing changed\n"))
1727 ui.status(_("nothing changed\n"))
1728 return 1
1728 return 1
1729
1729
1730 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1730 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1731
1731
1732 @command('config|showconfig|debugconfig',
1732 @command('config|showconfig|debugconfig',
1733 [('u', 'untrusted', None, _('show untrusted configuration options')),
1733 [('u', 'untrusted', None, _('show untrusted configuration options')),
1734 ('e', 'edit', None, _('edit user config')),
1734 ('e', 'edit', None, _('edit user config')),
1735 ('l', 'local', None, _('edit repository config')),
1735 ('l', 'local', None, _('edit repository config')),
1736 ('g', 'global', None, _('edit global config'))],
1736 ('g', 'global', None, _('edit global config'))],
1737 _('[-u] [NAME]...'),
1737 _('[-u] [NAME]...'),
1738 optionalrepo=True)
1738 optionalrepo=True)
1739 def config(ui, repo, *values, **opts):
1739 def config(ui, repo, *values, **opts):
1740 """show combined config settings from all hgrc files
1740 """show combined config settings from all hgrc files
1741
1741
1742 With no arguments, print names and values of all config items.
1742 With no arguments, print names and values of all config items.
1743
1743
1744 With one argument of the form section.name, print just the value
1744 With one argument of the form section.name, print just the value
1745 of that config item.
1745 of that config item.
1746
1746
1747 With multiple arguments, print names and values of all config
1747 With multiple arguments, print names and values of all config
1748 items with matching section names.
1748 items with matching section names.
1749
1749
1750 With --edit, start an editor on the user-level config file. With
1750 With --edit, start an editor on the user-level config file. With
1751 --global, edit the system-wide config file. With --local, edit the
1751 --global, edit the system-wide config file. With --local, edit the
1752 repository-level config file.
1752 repository-level config file.
1753
1753
1754 With --debug, the source (filename and line number) is printed
1754 With --debug, the source (filename and line number) is printed
1755 for each config item.
1755 for each config item.
1756
1756
1757 See :hg:`help config` for more information about config files.
1757 See :hg:`help config` for more information about config files.
1758
1758
1759 Returns 0 on success, 1 if NAME does not exist.
1759 Returns 0 on success, 1 if NAME does not exist.
1760
1760
1761 """
1761 """
1762
1762
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1763 if opts.get('edit') or opts.get('local') or opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1764 if opts.get('local') and opts.get('global'):
1765 raise error.Abort(_("can't use --local and --global together"))
1765 raise error.Abort(_("can't use --local and --global together"))
1766
1766
1767 if opts.get('local'):
1767 if opts.get('local'):
1768 if not repo:
1768 if not repo:
1769 raise error.Abort(_("can't use --local outside a repository"))
1769 raise error.Abort(_("can't use --local outside a repository"))
1770 paths = [repo.join('hgrc')]
1770 paths = [repo.join('hgrc')]
1771 elif opts.get('global'):
1771 elif opts.get('global'):
1772 paths = scmutil.systemrcpath()
1772 paths = scmutil.systemrcpath()
1773 else:
1773 else:
1774 paths = scmutil.userrcpath()
1774 paths = scmutil.userrcpath()
1775
1775
1776 for f in paths:
1776 for f in paths:
1777 if os.path.exists(f):
1777 if os.path.exists(f):
1778 break
1778 break
1779 else:
1779 else:
1780 if opts.get('global'):
1780 if opts.get('global'):
1781 samplehgrc = uimod.samplehgrcs['global']
1781 samplehgrc = uimod.samplehgrcs['global']
1782 elif opts.get('local'):
1782 elif opts.get('local'):
1783 samplehgrc = uimod.samplehgrcs['local']
1783 samplehgrc = uimod.samplehgrcs['local']
1784 else:
1784 else:
1785 samplehgrc = uimod.samplehgrcs['user']
1785 samplehgrc = uimod.samplehgrcs['user']
1786
1786
1787 f = paths[0]
1787 f = paths[0]
1788 fp = open(f, "w")
1788 fp = open(f, "w")
1789 fp.write(samplehgrc)
1789 fp.write(samplehgrc)
1790 fp.close()
1790 fp.close()
1791
1791
1792 editor = ui.geteditor()
1792 editor = ui.geteditor()
1793 ui.system("%s \"%s\"" % (editor, f),
1793 ui.system("%s \"%s\"" % (editor, f),
1794 onerr=error.Abort, errprefix=_("edit failed"))
1794 onerr=error.Abort, errprefix=_("edit failed"))
1795 return
1795 return
1796
1796
1797 for f in scmutil.rcpath():
1797 for f in scmutil.rcpath():
1798 ui.debug('read config from: %s\n' % f)
1798 ui.debug('read config from: %s\n' % f)
1799 untrusted = bool(opts.get('untrusted'))
1799 untrusted = bool(opts.get('untrusted'))
1800 if values:
1800 if values:
1801 sections = [v for v in values if '.' not in v]
1801 sections = [v for v in values if '.' not in v]
1802 items = [v for v in values if '.' in v]
1802 items = [v for v in values if '.' in v]
1803 if len(items) > 1 or items and sections:
1803 if len(items) > 1 or items and sections:
1804 raise error.Abort(_('only one config item permitted'))
1804 raise error.Abort(_('only one config item permitted'))
1805 matched = False
1805 matched = False
1806 for section, name, value in ui.walkconfig(untrusted=untrusted):
1806 for section, name, value in ui.walkconfig(untrusted=untrusted):
1807 value = str(value).replace('\n', '\\n')
1807 value = str(value).replace('\n', '\\n')
1808 sectname = section + '.' + name
1808 sectname = section + '.' + name
1809 if values:
1809 if values:
1810 for v in values:
1810 for v in values:
1811 if v == section:
1811 if v == section:
1812 ui.debug('%s: ' %
1812 ui.debug('%s: ' %
1813 ui.configsource(section, name, untrusted))
1813 ui.configsource(section, name, untrusted))
1814 ui.write('%s=%s\n' % (sectname, value))
1814 ui.write('%s=%s\n' % (sectname, value))
1815 matched = True
1815 matched = True
1816 elif v == sectname:
1816 elif v == sectname:
1817 ui.debug('%s: ' %
1817 ui.debug('%s: ' %
1818 ui.configsource(section, name, untrusted))
1818 ui.configsource(section, name, untrusted))
1819 ui.write(value, '\n')
1819 ui.write(value, '\n')
1820 matched = True
1820 matched = True
1821 else:
1821 else:
1822 ui.debug('%s: ' %
1822 ui.debug('%s: ' %
1823 ui.configsource(section, name, untrusted))
1823 ui.configsource(section, name, untrusted))
1824 ui.write('%s=%s\n' % (sectname, value))
1824 ui.write('%s=%s\n' % (sectname, value))
1825 matched = True
1825 matched = True
1826 if matched:
1826 if matched:
1827 return 0
1827 return 0
1828 return 1
1828 return 1
1829
1829
1830 @command('copy|cp',
1830 @command('copy|cp',
1831 [('A', 'after', None, _('record a copy that has already occurred')),
1831 [('A', 'after', None, _('record a copy that has already occurred')),
1832 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1832 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1833 ] + walkopts + dryrunopts,
1833 ] + walkopts + dryrunopts,
1834 _('[OPTION]... [SOURCE]... DEST'))
1834 _('[OPTION]... [SOURCE]... DEST'))
1835 def copy(ui, repo, *pats, **opts):
1835 def copy(ui, repo, *pats, **opts):
1836 """mark files as copied for the next commit
1836 """mark files as copied for the next commit
1837
1837
1838 Mark dest as having copies of source files. If dest is a
1838 Mark dest as having copies of source files. If dest is a
1839 directory, copies are put in that directory. If dest is a file,
1839 directory, copies are put in that directory. If dest is a file,
1840 the source must be a single file.
1840 the source must be a single file.
1841
1841
1842 By default, this command copies the contents of files as they
1842 By default, this command copies the contents of files as they
1843 exist in the working directory. If invoked with -A/--after, the
1843 exist in the working directory. If invoked with -A/--after, the
1844 operation is recorded, but no copying is performed.
1844 operation is recorded, but no copying is performed.
1845
1845
1846 This command takes effect with the next commit. To undo a copy
1846 This command takes effect with the next commit. To undo a copy
1847 before that, see :hg:`revert`.
1847 before that, see :hg:`revert`.
1848
1848
1849 Returns 0 on success, 1 if errors are encountered.
1849 Returns 0 on success, 1 if errors are encountered.
1850 """
1850 """
1851 with repo.wlock(False):
1851 with repo.wlock(False):
1852 return cmdutil.copy(ui, repo, pats, opts)
1852 return cmdutil.copy(ui, repo, pats, opts)
1853
1853
1854 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1854 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1855 def debugancestor(ui, repo, *args):
1855 def debugancestor(ui, repo, *args):
1856 """find the ancestor revision of two revisions in a given index"""
1856 """find the ancestor revision of two revisions in a given index"""
1857 if len(args) == 3:
1857 if len(args) == 3:
1858 index, rev1, rev2 = args
1858 index, rev1, rev2 = args
1859 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1859 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1860 lookup = r.lookup
1860 lookup = r.lookup
1861 elif len(args) == 2:
1861 elif len(args) == 2:
1862 if not repo:
1862 if not repo:
1863 raise error.Abort(_("there is no Mercurial repository here "
1863 raise error.Abort(_("there is no Mercurial repository here "
1864 "(.hg not found)"))
1864 "(.hg not found)"))
1865 rev1, rev2 = args
1865 rev1, rev2 = args
1866 r = repo.changelog
1866 r = repo.changelog
1867 lookup = repo.lookup
1867 lookup = repo.lookup
1868 else:
1868 else:
1869 raise error.Abort(_('either two or three arguments required'))
1869 raise error.Abort(_('either two or three arguments required'))
1870 a = r.ancestor(lookup(rev1), lookup(rev2))
1870 a = r.ancestor(lookup(rev1), lookup(rev2))
1871 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1871 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1872
1872
1873 @command('debugbuilddag',
1873 @command('debugbuilddag',
1874 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1874 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1875 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1875 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1876 ('n', 'new-file', None, _('add new file at each rev'))],
1876 ('n', 'new-file', None, _('add new file at each rev'))],
1877 _('[OPTION]... [TEXT]'))
1877 _('[OPTION]... [TEXT]'))
1878 def debugbuilddag(ui, repo, text=None,
1878 def debugbuilddag(ui, repo, text=None,
1879 mergeable_file=False,
1879 mergeable_file=False,
1880 overwritten_file=False,
1880 overwritten_file=False,
1881 new_file=False):
1881 new_file=False):
1882 """builds a repo with a given DAG from scratch in the current empty repo
1882 """builds a repo with a given DAG from scratch in the current empty repo
1883
1883
1884 The description of the DAG is read from stdin if not given on the
1884 The description of the DAG is read from stdin if not given on the
1885 command line.
1885 command line.
1886
1886
1887 Elements:
1887 Elements:
1888
1888
1889 - "+n" is a linear run of n nodes based on the current default parent
1889 - "+n" is a linear run of n nodes based on the current default parent
1890 - "." is a single node based on the current default parent
1890 - "." is a single node based on the current default parent
1891 - "$" resets the default parent to null (implied at the start);
1891 - "$" resets the default parent to null (implied at the start);
1892 otherwise the default parent is always the last node created
1892 otherwise the default parent is always the last node created
1893 - "<p" sets the default parent to the backref p
1893 - "<p" sets the default parent to the backref p
1894 - "*p" is a fork at parent p, which is a backref
1894 - "*p" is a fork at parent p, which is a backref
1895 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1895 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1896 - "/p2" is a merge of the preceding node and p2
1896 - "/p2" is a merge of the preceding node and p2
1897 - ":tag" defines a local tag for the preceding node
1897 - ":tag" defines a local tag for the preceding node
1898 - "@branch" sets the named branch for subsequent nodes
1898 - "@branch" sets the named branch for subsequent nodes
1899 - "#...\\n" is a comment up to the end of the line
1899 - "#...\\n" is a comment up to the end of the line
1900
1900
1901 Whitespace between the above elements is ignored.
1901 Whitespace between the above elements is ignored.
1902
1902
1903 A backref is either
1903 A backref is either
1904
1904
1905 - a number n, which references the node curr-n, where curr is the current
1905 - a number n, which references the node curr-n, where curr is the current
1906 node, or
1906 node, or
1907 - the name of a local tag you placed earlier using ":tag", or
1907 - the name of a local tag you placed earlier using ":tag", or
1908 - empty to denote the default parent.
1908 - empty to denote the default parent.
1909
1909
1910 All string valued-elements are either strictly alphanumeric, or must
1910 All string valued-elements are either strictly alphanumeric, or must
1911 be enclosed in double quotes ("..."), with "\\" as escape character.
1911 be enclosed in double quotes ("..."), with "\\" as escape character.
1912 """
1912 """
1913
1913
1914 if text is None:
1914 if text is None:
1915 ui.status(_("reading DAG from stdin\n"))
1915 ui.status(_("reading DAG from stdin\n"))
1916 text = ui.fin.read()
1916 text = ui.fin.read()
1917
1917
1918 cl = repo.changelog
1918 cl = repo.changelog
1919 if len(cl) > 0:
1919 if len(cl) > 0:
1920 raise error.Abort(_('repository is not empty'))
1920 raise error.Abort(_('repository is not empty'))
1921
1921
1922 # determine number of revs in DAG
1922 # determine number of revs in DAG
1923 total = 0
1923 total = 0
1924 for type, data in dagparser.parsedag(text):
1924 for type, data in dagparser.parsedag(text):
1925 if type == 'n':
1925 if type == 'n':
1926 total += 1
1926 total += 1
1927
1927
1928 if mergeable_file:
1928 if mergeable_file:
1929 linesperrev = 2
1929 linesperrev = 2
1930 # make a file with k lines per rev
1930 # make a file with k lines per rev
1931 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1931 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1932 initialmergedlines.append("")
1932 initialmergedlines.append("")
1933
1933
1934 tags = []
1934 tags = []
1935
1935
1936 lock = tr = None
1936 lock = tr = None
1937 try:
1937 try:
1938 lock = repo.lock()
1938 lock = repo.lock()
1939 tr = repo.transaction("builddag")
1939 tr = repo.transaction("builddag")
1940
1940
1941 at = -1
1941 at = -1
1942 atbranch = 'default'
1942 atbranch = 'default'
1943 nodeids = []
1943 nodeids = []
1944 id = 0
1944 id = 0
1945 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1945 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1946 for type, data in dagparser.parsedag(text):
1946 for type, data in dagparser.parsedag(text):
1947 if type == 'n':
1947 if type == 'n':
1948 ui.note(('node %s\n' % str(data)))
1948 ui.note(('node %s\n' % str(data)))
1949 id, ps = data
1949 id, ps = data
1950
1950
1951 files = []
1951 files = []
1952 fctxs = {}
1952 fctxs = {}
1953
1953
1954 p2 = None
1954 p2 = None
1955 if mergeable_file:
1955 if mergeable_file:
1956 fn = "mf"
1956 fn = "mf"
1957 p1 = repo[ps[0]]
1957 p1 = repo[ps[0]]
1958 if len(ps) > 1:
1958 if len(ps) > 1:
1959 p2 = repo[ps[1]]
1959 p2 = repo[ps[1]]
1960 pa = p1.ancestor(p2)
1960 pa = p1.ancestor(p2)
1961 base, local, other = [x[fn].data() for x in (pa, p1,
1961 base, local, other = [x[fn].data() for x in (pa, p1,
1962 p2)]
1962 p2)]
1963 m3 = simplemerge.Merge3Text(base, local, other)
1963 m3 = simplemerge.Merge3Text(base, local, other)
1964 ml = [l.strip() for l in m3.merge_lines()]
1964 ml = [l.strip() for l in m3.merge_lines()]
1965 ml.append("")
1965 ml.append("")
1966 elif at > 0:
1966 elif at > 0:
1967 ml = p1[fn].data().split("\n")
1967 ml = p1[fn].data().split("\n")
1968 else:
1968 else:
1969 ml = initialmergedlines
1969 ml = initialmergedlines
1970 ml[id * linesperrev] += " r%i" % id
1970 ml[id * linesperrev] += " r%i" % id
1971 mergedtext = "\n".join(ml)
1971 mergedtext = "\n".join(ml)
1972 files.append(fn)
1972 files.append(fn)
1973 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1973 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1974
1974
1975 if overwritten_file:
1975 if overwritten_file:
1976 fn = "of"
1976 fn = "of"
1977 files.append(fn)
1977 files.append(fn)
1978 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1978 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1979
1979
1980 if new_file:
1980 if new_file:
1981 fn = "nf%i" % id
1981 fn = "nf%i" % id
1982 files.append(fn)
1982 files.append(fn)
1983 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1983 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1984 if len(ps) > 1:
1984 if len(ps) > 1:
1985 if not p2:
1985 if not p2:
1986 p2 = repo[ps[1]]
1986 p2 = repo[ps[1]]
1987 for fn in p2:
1987 for fn in p2:
1988 if fn.startswith("nf"):
1988 if fn.startswith("nf"):
1989 files.append(fn)
1989 files.append(fn)
1990 fctxs[fn] = p2[fn]
1990 fctxs[fn] = p2[fn]
1991
1991
1992 def fctxfn(repo, cx, path):
1992 def fctxfn(repo, cx, path):
1993 return fctxs.get(path)
1993 return fctxs.get(path)
1994
1994
1995 if len(ps) == 0 or ps[0] < 0:
1995 if len(ps) == 0 or ps[0] < 0:
1996 pars = [None, None]
1996 pars = [None, None]
1997 elif len(ps) == 1:
1997 elif len(ps) == 1:
1998 pars = [nodeids[ps[0]], None]
1998 pars = [nodeids[ps[0]], None]
1999 else:
1999 else:
2000 pars = [nodeids[p] for p in ps]
2000 pars = [nodeids[p] for p in ps]
2001 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2001 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2002 date=(id, 0),
2002 date=(id, 0),
2003 user="debugbuilddag",
2003 user="debugbuilddag",
2004 extra={'branch': atbranch})
2004 extra={'branch': atbranch})
2005 nodeid = repo.commitctx(cx)
2005 nodeid = repo.commitctx(cx)
2006 nodeids.append(nodeid)
2006 nodeids.append(nodeid)
2007 at = id
2007 at = id
2008 elif type == 'l':
2008 elif type == 'l':
2009 id, name = data
2009 id, name = data
2010 ui.note(('tag %s\n' % name))
2010 ui.note(('tag %s\n' % name))
2011 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2011 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2012 elif type == 'a':
2012 elif type == 'a':
2013 ui.note(('branch %s\n' % data))
2013 ui.note(('branch %s\n' % data))
2014 atbranch = data
2014 atbranch = data
2015 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2015 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2016 tr.close()
2016 tr.close()
2017
2017
2018 if tags:
2018 if tags:
2019 repo.vfs.write("localtags", "".join(tags))
2019 repo.vfs.write("localtags", "".join(tags))
2020 finally:
2020 finally:
2021 ui.progress(_('building'), None)
2021 ui.progress(_('building'), None)
2022 release(tr, lock)
2022 release(tr, lock)
2023
2023
2024 @command('debugbundle',
2024 @command('debugbundle',
2025 [('a', 'all', None, _('show all details')),
2025 [('a', 'all', None, _('show all details')),
2026 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2026 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2027 _('FILE'),
2027 _('FILE'),
2028 norepo=True)
2028 norepo=True)
2029 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2029 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2030 """lists the contents of a bundle"""
2030 """lists the contents of a bundle"""
2031 with hg.openpath(ui, bundlepath) as f:
2031 with hg.openpath(ui, bundlepath) as f:
2032 if spec:
2032 if spec:
2033 spec = exchange.getbundlespec(ui, f)
2033 spec = exchange.getbundlespec(ui, f)
2034 ui.write('%s\n' % spec)
2034 ui.write('%s\n' % spec)
2035 return
2035 return
2036
2036
2037 gen = exchange.readbundle(ui, f, bundlepath)
2037 gen = exchange.readbundle(ui, f, bundlepath)
2038 if isinstance(gen, bundle2.unbundle20):
2038 if isinstance(gen, bundle2.unbundle20):
2039 return _debugbundle2(ui, gen, all=all, **opts)
2039 return _debugbundle2(ui, gen, all=all, **opts)
2040 if all:
2040 if all:
2041 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2041 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2042
2042
2043 def showchunks(named):
2043 def showchunks(named):
2044 ui.write("\n%s\n" % named)
2044 ui.write("\n%s\n" % named)
2045 chain = None
2045 chain = None
2046 while True:
2046 while True:
2047 chunkdata = gen.deltachunk(chain)
2047 chunkdata = gen.deltachunk(chain)
2048 if not chunkdata:
2048 if not chunkdata:
2049 break
2049 break
2050 node = chunkdata['node']
2050 node = chunkdata['node']
2051 p1 = chunkdata['p1']
2051 p1 = chunkdata['p1']
2052 p2 = chunkdata['p2']
2052 p2 = chunkdata['p2']
2053 cs = chunkdata['cs']
2053 cs = chunkdata['cs']
2054 deltabase = chunkdata['deltabase']
2054 deltabase = chunkdata['deltabase']
2055 delta = chunkdata['delta']
2055 delta = chunkdata['delta']
2056 ui.write("%s %s %s %s %s %s\n" %
2056 ui.write("%s %s %s %s %s %s\n" %
2057 (hex(node), hex(p1), hex(p2),
2057 (hex(node), hex(p1), hex(p2),
2058 hex(cs), hex(deltabase), len(delta)))
2058 hex(cs), hex(deltabase), len(delta)))
2059 chain = node
2059 chain = node
2060
2060
2061 chunkdata = gen.changelogheader()
2061 chunkdata = gen.changelogheader()
2062 showchunks("changelog")
2062 showchunks("changelog")
2063 chunkdata = gen.manifestheader()
2063 chunkdata = gen.manifestheader()
2064 showchunks("manifest")
2064 showchunks("manifest")
2065 while True:
2065 while True:
2066 chunkdata = gen.filelogheader()
2066 chunkdata = gen.filelogheader()
2067 if not chunkdata:
2067 if not chunkdata:
2068 break
2068 break
2069 fname = chunkdata['filename']
2069 fname = chunkdata['filename']
2070 showchunks(fname)
2070 showchunks(fname)
2071 else:
2071 else:
2072 if isinstance(gen, bundle2.unbundle20):
2072 if isinstance(gen, bundle2.unbundle20):
2073 raise error.Abort(_('use debugbundle2 for this file'))
2073 raise error.Abort(_('use debugbundle2 for this file'))
2074 chunkdata = gen.changelogheader()
2074 chunkdata = gen.changelogheader()
2075 chain = None
2075 chain = None
2076 while True:
2076 while True:
2077 chunkdata = gen.deltachunk(chain)
2077 chunkdata = gen.deltachunk(chain)
2078 if not chunkdata:
2078 if not chunkdata:
2079 break
2079 break
2080 node = chunkdata['node']
2080 node = chunkdata['node']
2081 ui.write("%s\n" % hex(node))
2081 ui.write("%s\n" % hex(node))
2082 chain = node
2082 chain = node
2083
2083
2084 def _debugbundle2(ui, gen, **opts):
2084 def _debugbundle2(ui, gen, **opts):
2085 """lists the contents of a bundle2"""
2085 """lists the contents of a bundle2"""
2086 if not isinstance(gen, bundle2.unbundle20):
2086 if not isinstance(gen, bundle2.unbundle20):
2087 raise error.Abort(_('not a bundle2 file'))
2087 raise error.Abort(_('not a bundle2 file'))
2088 ui.write(('Stream params: %s\n' % repr(gen.params)))
2088 ui.write(('Stream params: %s\n' % repr(gen.params)))
2089 for part in gen.iterparts():
2089 for part in gen.iterparts():
2090 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2090 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2091 if part.type == 'changegroup':
2091 if part.type == 'changegroup':
2092 version = part.params.get('version', '01')
2092 version = part.params.get('version', '01')
2093 cg = changegroup.getunbundler(version, part, 'UN')
2093 cg = changegroup.getunbundler(version, part, 'UN')
2094 chunkdata = cg.changelogheader()
2094 chunkdata = cg.changelogheader()
2095 chain = None
2095 chain = None
2096 while True:
2096 while True:
2097 chunkdata = cg.deltachunk(chain)
2097 chunkdata = cg.deltachunk(chain)
2098 if not chunkdata:
2098 if not chunkdata:
2099 break
2099 break
2100 node = chunkdata['node']
2100 node = chunkdata['node']
2101 ui.write(" %s\n" % hex(node))
2101 ui.write(" %s\n" % hex(node))
2102 chain = node
2102 chain = node
2103
2103
2104 @command('debugcreatestreamclonebundle', [], 'FILE')
2104 @command('debugcreatestreamclonebundle', [], 'FILE')
2105 def debugcreatestreamclonebundle(ui, repo, fname):
2105 def debugcreatestreamclonebundle(ui, repo, fname):
2106 """create a stream clone bundle file
2106 """create a stream clone bundle file
2107
2107
2108 Stream bundles are special bundles that are essentially archives of
2108 Stream bundles are special bundles that are essentially archives of
2109 revlog files. They are commonly used for cloning very quickly.
2109 revlog files. They are commonly used for cloning very quickly.
2110 """
2110 """
2111 requirements, gen = streamclone.generatebundlev1(repo)
2111 requirements, gen = streamclone.generatebundlev1(repo)
2112 changegroup.writechunks(ui, gen, fname)
2112 changegroup.writechunks(ui, gen, fname)
2113
2113
2114 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2114 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2115
2115
2116 @command('debugapplystreamclonebundle', [], 'FILE')
2116 @command('debugapplystreamclonebundle', [], 'FILE')
2117 def debugapplystreamclonebundle(ui, repo, fname):
2117 def debugapplystreamclonebundle(ui, repo, fname):
2118 """apply a stream clone bundle file"""
2118 """apply a stream clone bundle file"""
2119 f = hg.openpath(ui, fname)
2119 f = hg.openpath(ui, fname)
2120 gen = exchange.readbundle(ui, f, fname)
2120 gen = exchange.readbundle(ui, f, fname)
2121 gen.apply(repo)
2121 gen.apply(repo)
2122
2122
2123 @command('debugcheckstate', [], '')
2123 @command('debugcheckstate', [], '')
2124 def debugcheckstate(ui, repo):
2124 def debugcheckstate(ui, repo):
2125 """validate the correctness of the current dirstate"""
2125 """validate the correctness of the current dirstate"""
2126 parent1, parent2 = repo.dirstate.parents()
2126 parent1, parent2 = repo.dirstate.parents()
2127 m1 = repo[parent1].manifest()
2127 m1 = repo[parent1].manifest()
2128 m2 = repo[parent2].manifest()
2128 m2 = repo[parent2].manifest()
2129 errors = 0
2129 errors = 0
2130 for f in repo.dirstate:
2130 for f in repo.dirstate:
2131 state = repo.dirstate[f]
2131 state = repo.dirstate[f]
2132 if state in "nr" and f not in m1:
2132 if state in "nr" and f not in m1:
2133 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2133 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2134 errors += 1
2134 errors += 1
2135 if state in "a" and f in m1:
2135 if state in "a" and f in m1:
2136 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2136 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2137 errors += 1
2137 errors += 1
2138 if state in "m" and f not in m1 and f not in m2:
2138 if state in "m" and f not in m1 and f not in m2:
2139 ui.warn(_("%s in state %s, but not in either manifest\n") %
2139 ui.warn(_("%s in state %s, but not in either manifest\n") %
2140 (f, state))
2140 (f, state))
2141 errors += 1
2141 errors += 1
2142 for f in m1:
2142 for f in m1:
2143 state = repo.dirstate[f]
2143 state = repo.dirstate[f]
2144 if state not in "nrm":
2144 if state not in "nrm":
2145 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2145 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2146 errors += 1
2146 errors += 1
2147 if errors:
2147 if errors:
2148 error = _(".hg/dirstate inconsistent with current parent's manifest")
2148 error = _(".hg/dirstate inconsistent with current parent's manifest")
2149 raise error.Abort(error)
2149 raise error.Abort(error)
2150
2150
2151 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2151 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2152 def debugcommands(ui, cmd='', *args):
2152 def debugcommands(ui, cmd='', *args):
2153 """list all available commands and options"""
2153 """list all available commands and options"""
2154 for cmd, vals in sorted(table.iteritems()):
2154 for cmd, vals in sorted(table.iteritems()):
2155 cmd = cmd.split('|')[0].strip('^')
2155 cmd = cmd.split('|')[0].strip('^')
2156 opts = ', '.join([i[1] for i in vals[1]])
2156 opts = ', '.join([i[1] for i in vals[1]])
2157 ui.write('%s: %s\n' % (cmd, opts))
2157 ui.write('%s: %s\n' % (cmd, opts))
2158
2158
2159 @command('debugcomplete',
2159 @command('debugcomplete',
2160 [('o', 'options', None, _('show the command options'))],
2160 [('o', 'options', None, _('show the command options'))],
2161 _('[-o] CMD'),
2161 _('[-o] CMD'),
2162 norepo=True)
2162 norepo=True)
2163 def debugcomplete(ui, cmd='', **opts):
2163 def debugcomplete(ui, cmd='', **opts):
2164 """returns the completion list associated with the given command"""
2164 """returns the completion list associated with the given command"""
2165
2165
2166 if opts.get('options'):
2166 if opts.get('options'):
2167 options = []
2167 options = []
2168 otables = [globalopts]
2168 otables = [globalopts]
2169 if cmd:
2169 if cmd:
2170 aliases, entry = cmdutil.findcmd(cmd, table, False)
2170 aliases, entry = cmdutil.findcmd(cmd, table, False)
2171 otables.append(entry[1])
2171 otables.append(entry[1])
2172 for t in otables:
2172 for t in otables:
2173 for o in t:
2173 for o in t:
2174 if "(DEPRECATED)" in o[3]:
2174 if "(DEPRECATED)" in o[3]:
2175 continue
2175 continue
2176 if o[0]:
2176 if o[0]:
2177 options.append('-%s' % o[0])
2177 options.append('-%s' % o[0])
2178 options.append('--%s' % o[1])
2178 options.append('--%s' % o[1])
2179 ui.write("%s\n" % "\n".join(options))
2179 ui.write("%s\n" % "\n".join(options))
2180 return
2180 return
2181
2181
2182 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2182 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2183 if ui.verbose:
2183 if ui.verbose:
2184 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2184 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2185 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2185 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2186
2186
2187 @command('debugdag',
2187 @command('debugdag',
2188 [('t', 'tags', None, _('use tags as labels')),
2188 [('t', 'tags', None, _('use tags as labels')),
2189 ('b', 'branches', None, _('annotate with branch names')),
2189 ('b', 'branches', None, _('annotate with branch names')),
2190 ('', 'dots', None, _('use dots for runs')),
2190 ('', 'dots', None, _('use dots for runs')),
2191 ('s', 'spaces', None, _('separate elements by spaces'))],
2191 ('s', 'spaces', None, _('separate elements by spaces'))],
2192 _('[OPTION]... [FILE [REV]...]'),
2192 _('[OPTION]... [FILE [REV]...]'),
2193 optionalrepo=True)
2193 optionalrepo=True)
2194 def debugdag(ui, repo, file_=None, *revs, **opts):
2194 def debugdag(ui, repo, file_=None, *revs, **opts):
2195 """format the changelog or an index DAG as a concise textual description
2195 """format the changelog or an index DAG as a concise textual description
2196
2196
2197 If you pass a revlog index, the revlog's DAG is emitted. If you list
2197 If you pass a revlog index, the revlog's DAG is emitted. If you list
2198 revision numbers, they get labeled in the output as rN.
2198 revision numbers, they get labeled in the output as rN.
2199
2199
2200 Otherwise, the changelog DAG of the current repo is emitted.
2200 Otherwise, the changelog DAG of the current repo is emitted.
2201 """
2201 """
2202 spaces = opts.get('spaces')
2202 spaces = opts.get('spaces')
2203 dots = opts.get('dots')
2203 dots = opts.get('dots')
2204 if file_:
2204 if file_:
2205 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2205 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2206 revs = set((int(r) for r in revs))
2206 revs = set((int(r) for r in revs))
2207 def events():
2207 def events():
2208 for r in rlog:
2208 for r in rlog:
2209 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2209 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2210 if p != -1))
2210 if p != -1))
2211 if r in revs:
2211 if r in revs:
2212 yield 'l', (r, "r%i" % r)
2212 yield 'l', (r, "r%i" % r)
2213 elif repo:
2213 elif repo:
2214 cl = repo.changelog
2214 cl = repo.changelog
2215 tags = opts.get('tags')
2215 tags = opts.get('tags')
2216 branches = opts.get('branches')
2216 branches = opts.get('branches')
2217 if tags:
2217 if tags:
2218 labels = {}
2218 labels = {}
2219 for l, n in repo.tags().items():
2219 for l, n in repo.tags().items():
2220 labels.setdefault(cl.rev(n), []).append(l)
2220 labels.setdefault(cl.rev(n), []).append(l)
2221 def events():
2221 def events():
2222 b = "default"
2222 b = "default"
2223 for r in cl:
2223 for r in cl:
2224 if branches:
2224 if branches:
2225 newb = cl.read(cl.node(r))[5]['branch']
2225 newb = cl.read(cl.node(r))[5]['branch']
2226 if newb != b:
2226 if newb != b:
2227 yield 'a', newb
2227 yield 'a', newb
2228 b = newb
2228 b = newb
2229 yield 'n', (r, list(p for p in cl.parentrevs(r)
2229 yield 'n', (r, list(p for p in cl.parentrevs(r)
2230 if p != -1))
2230 if p != -1))
2231 if tags:
2231 if tags:
2232 ls = labels.get(r)
2232 ls = labels.get(r)
2233 if ls:
2233 if ls:
2234 for l in ls:
2234 for l in ls:
2235 yield 'l', (r, l)
2235 yield 'l', (r, l)
2236 else:
2236 else:
2237 raise error.Abort(_('need repo for changelog dag'))
2237 raise error.Abort(_('need repo for changelog dag'))
2238
2238
2239 for line in dagparser.dagtextlines(events(),
2239 for line in dagparser.dagtextlines(events(),
2240 addspaces=spaces,
2240 addspaces=spaces,
2241 wraplabels=True,
2241 wraplabels=True,
2242 wrapannotations=True,
2242 wrapannotations=True,
2243 wrapnonlinear=dots,
2243 wrapnonlinear=dots,
2244 usedots=dots,
2244 usedots=dots,
2245 maxlinewidth=70):
2245 maxlinewidth=70):
2246 ui.write(line)
2246 ui.write(line)
2247 ui.write("\n")
2247 ui.write("\n")
2248
2248
2249 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2249 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2250 def debugdata(ui, repo, file_, rev=None, **opts):
2250 def debugdata(ui, repo, file_, rev=None, **opts):
2251 """dump the contents of a data file revision"""
2251 """dump the contents of a data file revision"""
2252 if opts.get('changelog') or opts.get('manifest'):
2252 if opts.get('changelog') or opts.get('manifest'):
2253 file_, rev = None, file_
2253 file_, rev = None, file_
2254 elif rev is None:
2254 elif rev is None:
2255 raise error.CommandError('debugdata', _('invalid arguments'))
2255 raise error.CommandError('debugdata', _('invalid arguments'))
2256 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2256 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2257 try:
2257 try:
2258 ui.write(r.revision(r.lookup(rev)))
2258 ui.write(r.revision(r.lookup(rev)))
2259 except KeyError:
2259 except KeyError:
2260 raise error.Abort(_('invalid revision identifier %s') % rev)
2260 raise error.Abort(_('invalid revision identifier %s') % rev)
2261
2261
2262 @command('debugdate',
2262 @command('debugdate',
2263 [('e', 'extended', None, _('try extended date formats'))],
2263 [('e', 'extended', None, _('try extended date formats'))],
2264 _('[-e] DATE [RANGE]'),
2264 _('[-e] DATE [RANGE]'),
2265 norepo=True, optionalrepo=True)
2265 norepo=True, optionalrepo=True)
2266 def debugdate(ui, date, range=None, **opts):
2266 def debugdate(ui, date, range=None, **opts):
2267 """parse and display a date"""
2267 """parse and display a date"""
2268 if opts["extended"]:
2268 if opts["extended"]:
2269 d = util.parsedate(date, util.extendeddateformats)
2269 d = util.parsedate(date, util.extendeddateformats)
2270 else:
2270 else:
2271 d = util.parsedate(date)
2271 d = util.parsedate(date)
2272 ui.write(("internal: %s %s\n") % d)
2272 ui.write(("internal: %s %s\n") % d)
2273 ui.write(("standard: %s\n") % util.datestr(d))
2273 ui.write(("standard: %s\n") % util.datestr(d))
2274 if range:
2274 if range:
2275 m = util.matchdate(range)
2275 m = util.matchdate(range)
2276 ui.write(("match: %s\n") % m(d[0]))
2276 ui.write(("match: %s\n") % m(d[0]))
2277
2277
2278 @command('debugdiscovery',
2278 @command('debugdiscovery',
2279 [('', 'old', None, _('use old-style discovery')),
2279 [('', 'old', None, _('use old-style discovery')),
2280 ('', 'nonheads', None,
2280 ('', 'nonheads', None,
2281 _('use old-style discovery with non-heads included')),
2281 _('use old-style discovery with non-heads included')),
2282 ] + remoteopts,
2282 ] + remoteopts,
2283 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2283 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2284 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2284 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2285 """runs the changeset discovery protocol in isolation"""
2285 """runs the changeset discovery protocol in isolation"""
2286 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2286 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2287 opts.get('branch'))
2287 opts.get('branch'))
2288 remote = hg.peer(repo, opts, remoteurl)
2288 remote = hg.peer(repo, opts, remoteurl)
2289 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2289 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2290
2290
2291 # make sure tests are repeatable
2291 # make sure tests are repeatable
2292 random.seed(12323)
2292 random.seed(12323)
2293
2293
2294 def doit(localheads, remoteheads, remote=remote):
2294 def doit(localheads, remoteheads, remote=remote):
2295 if opts.get('old'):
2295 if opts.get('old'):
2296 if localheads:
2296 if localheads:
2297 raise error.Abort('cannot use localheads with old style '
2297 raise error.Abort('cannot use localheads with old style '
2298 'discovery')
2298 'discovery')
2299 if not util.safehasattr(remote, 'branches'):
2299 if not util.safehasattr(remote, 'branches'):
2300 # enable in-client legacy support
2300 # enable in-client legacy support
2301 remote = localrepo.locallegacypeer(remote.local())
2301 remote = localrepo.locallegacypeer(remote.local())
2302 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2302 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2303 force=True)
2303 force=True)
2304 common = set(common)
2304 common = set(common)
2305 if not opts.get('nonheads'):
2305 if not opts.get('nonheads'):
2306 ui.write(("unpruned common: %s\n") %
2306 ui.write(("unpruned common: %s\n") %
2307 " ".join(sorted(short(n) for n in common)))
2307 " ".join(sorted(short(n) for n in common)))
2308 dag = dagutil.revlogdag(repo.changelog)
2308 dag = dagutil.revlogdag(repo.changelog)
2309 all = dag.ancestorset(dag.internalizeall(common))
2309 all = dag.ancestorset(dag.internalizeall(common))
2310 common = dag.externalizeall(dag.headsetofconnecteds(all))
2310 common = dag.externalizeall(dag.headsetofconnecteds(all))
2311 else:
2311 else:
2312 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2312 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2313 common = set(common)
2313 common = set(common)
2314 rheads = set(hds)
2314 rheads = set(hds)
2315 lheads = set(repo.heads())
2315 lheads = set(repo.heads())
2316 ui.write(("common heads: %s\n") %
2316 ui.write(("common heads: %s\n") %
2317 " ".join(sorted(short(n) for n in common)))
2317 " ".join(sorted(short(n) for n in common)))
2318 if lheads <= common:
2318 if lheads <= common:
2319 ui.write(("local is subset\n"))
2319 ui.write(("local is subset\n"))
2320 elif rheads <= common:
2320 elif rheads <= common:
2321 ui.write(("remote is subset\n"))
2321 ui.write(("remote is subset\n"))
2322
2322
2323 serverlogs = opts.get('serverlog')
2323 serverlogs = opts.get('serverlog')
2324 if serverlogs:
2324 if serverlogs:
2325 for filename in serverlogs:
2325 for filename in serverlogs:
2326 with open(filename, 'r') as logfile:
2326 with open(filename, 'r') as logfile:
2327 line = logfile.readline()
2327 line = logfile.readline()
2328 while line:
2328 while line:
2329 parts = line.strip().split(';')
2329 parts = line.strip().split(';')
2330 op = parts[1]
2330 op = parts[1]
2331 if op == 'cg':
2331 if op == 'cg':
2332 pass
2332 pass
2333 elif op == 'cgss':
2333 elif op == 'cgss':
2334 doit(parts[2].split(' '), parts[3].split(' '))
2334 doit(parts[2].split(' '), parts[3].split(' '))
2335 elif op == 'unb':
2335 elif op == 'unb':
2336 doit(parts[3].split(' '), parts[2].split(' '))
2336 doit(parts[3].split(' '), parts[2].split(' '))
2337 line = logfile.readline()
2337 line = logfile.readline()
2338 else:
2338 else:
2339 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2339 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2340 opts.get('remote_head'))
2340 opts.get('remote_head'))
2341 localrevs = opts.get('local_head')
2341 localrevs = opts.get('local_head')
2342 doit(localrevs, remoterevs)
2342 doit(localrevs, remoterevs)
2343
2343
2344 @command('debugextensions', formatteropts, [], norepo=True)
2344 @command('debugextensions', formatteropts, [], norepo=True)
2345 def debugextensions(ui, **opts):
2345 def debugextensions(ui, **opts):
2346 '''show information about active extensions'''
2346 '''show information about active extensions'''
2347 exts = extensions.extensions(ui)
2347 exts = extensions.extensions(ui)
2348 fm = ui.formatter('debugextensions', opts)
2348 fm = ui.formatter('debugextensions', opts)
2349 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2349 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2350 extsource = extmod.__file__
2350 extsource = extmod.__file__
2351 exttestedwith = getattr(extmod, 'testedwith', None)
2351 exttestedwith = getattr(extmod, 'testedwith', None)
2352 if exttestedwith is not None:
2352 if exttestedwith is not None:
2353 exttestedwith = exttestedwith.split()
2353 exttestedwith = exttestedwith.split()
2354 extbuglink = getattr(extmod, 'buglink', None)
2354 extbuglink = getattr(extmod, 'buglink', None)
2355
2355
2356 fm.startitem()
2356 fm.startitem()
2357
2357
2358 if ui.quiet or ui.verbose:
2358 if ui.quiet or ui.verbose:
2359 fm.write('name', '%s\n', extname)
2359 fm.write('name', '%s\n', extname)
2360 else:
2360 else:
2361 fm.write('name', '%s', extname)
2361 fm.write('name', '%s', extname)
2362 if not exttestedwith:
2362 if not exttestedwith:
2363 fm.plain(_(' (untested!)\n'))
2363 fm.plain(_(' (untested!)\n'))
2364 else:
2364 else:
2365 if exttestedwith == ['internal'] or \
2365 if exttestedwith == ['internal'] or \
2366 util.version() in exttestedwith:
2366 util.version() in exttestedwith:
2367 fm.plain('\n')
2367 fm.plain('\n')
2368 else:
2368 else:
2369 lasttestedversion = exttestedwith[-1]
2369 lasttestedversion = exttestedwith[-1]
2370 fm.plain(' (%s!)\n' % lasttestedversion)
2370 fm.plain(' (%s!)\n' % lasttestedversion)
2371
2371
2372 fm.condwrite(ui.verbose and extsource, 'source',
2372 fm.condwrite(ui.verbose and extsource, 'source',
2373 _(' location: %s\n'), extsource or "")
2373 _(' location: %s\n'), extsource or "")
2374
2374
2375 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2375 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2376 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2376 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2377
2377
2378 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2378 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2379 _(' bug reporting: %s\n'), extbuglink or "")
2379 _(' bug reporting: %s\n'), extbuglink or "")
2380
2380
2381 fm.end()
2381 fm.end()
2382
2382
2383 @command('debugfileset',
2383 @command('debugfileset',
2384 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2384 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2385 _('[-r REV] FILESPEC'))
2385 _('[-r REV] FILESPEC'))
2386 def debugfileset(ui, repo, expr, **opts):
2386 def debugfileset(ui, repo, expr, **opts):
2387 '''parse and apply a fileset specification'''
2387 '''parse and apply a fileset specification'''
2388 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2388 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2389 if ui.verbose:
2389 if ui.verbose:
2390 tree = fileset.parse(expr)
2390 tree = fileset.parse(expr)
2391 ui.note(fileset.prettyformat(tree), "\n")
2391 ui.note(fileset.prettyformat(tree), "\n")
2392
2392
2393 for f in ctx.getfileset(expr):
2393 for f in ctx.getfileset(expr):
2394 ui.write("%s\n" % f)
2394 ui.write("%s\n" % f)
2395
2395
2396 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2396 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2397 def debugfsinfo(ui, path="."):
2397 def debugfsinfo(ui, path="."):
2398 """show information detected about current filesystem"""
2398 """show information detected about current filesystem"""
2399 util.writefile('.debugfsinfo', '')
2399 util.writefile('.debugfsinfo', '')
2400 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2400 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2401 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2401 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2402 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2402 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2403 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2403 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2404 and 'yes' or 'no'))
2404 and 'yes' or 'no'))
2405 os.unlink('.debugfsinfo')
2405 os.unlink('.debugfsinfo')
2406
2406
2407 @command('debuggetbundle',
2407 @command('debuggetbundle',
2408 [('H', 'head', [], _('id of head node'), _('ID')),
2408 [('H', 'head', [], _('id of head node'), _('ID')),
2409 ('C', 'common', [], _('id of common node'), _('ID')),
2409 ('C', 'common', [], _('id of common node'), _('ID')),
2410 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2410 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2411 _('REPO FILE [-H|-C ID]...'),
2411 _('REPO FILE [-H|-C ID]...'),
2412 norepo=True)
2412 norepo=True)
2413 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2413 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2414 """retrieves a bundle from a repo
2414 """retrieves a bundle from a repo
2415
2415
2416 Every ID must be a full-length hex node id string. Saves the bundle to the
2416 Every ID must be a full-length hex node id string. Saves the bundle to the
2417 given file.
2417 given file.
2418 """
2418 """
2419 repo = hg.peer(ui, opts, repopath)
2419 repo = hg.peer(ui, opts, repopath)
2420 if not repo.capable('getbundle'):
2420 if not repo.capable('getbundle'):
2421 raise error.Abort("getbundle() not supported by target repository")
2421 raise error.Abort("getbundle() not supported by target repository")
2422 args = {}
2422 args = {}
2423 if common:
2423 if common:
2424 args['common'] = [bin(s) for s in common]
2424 args['common'] = [bin(s) for s in common]
2425 if head:
2425 if head:
2426 args['heads'] = [bin(s) for s in head]
2426 args['heads'] = [bin(s) for s in head]
2427 # TODO: get desired bundlecaps from command line.
2427 # TODO: get desired bundlecaps from command line.
2428 args['bundlecaps'] = None
2428 args['bundlecaps'] = None
2429 bundle = repo.getbundle('debug', **args)
2429 bundle = repo.getbundle('debug', **args)
2430
2430
2431 bundletype = opts.get('type', 'bzip2').lower()
2431 bundletype = opts.get('type', 'bzip2').lower()
2432 btypes = {'none': 'HG10UN',
2432 btypes = {'none': 'HG10UN',
2433 'bzip2': 'HG10BZ',
2433 'bzip2': 'HG10BZ',
2434 'gzip': 'HG10GZ',
2434 'gzip': 'HG10GZ',
2435 'bundle2': 'HG20'}
2435 'bundle2': 'HG20'}
2436 bundletype = btypes.get(bundletype)
2436 bundletype = btypes.get(bundletype)
2437 if bundletype not in changegroup.bundletypes:
2437 if bundletype not in changegroup.bundletypes:
2438 raise error.Abort(_('unknown bundle type specified with --type'))
2438 raise error.Abort(_('unknown bundle type specified with --type'))
2439 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2439 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2440
2440
2441 @command('debugignore', [], '[FILE]')
2441 @command('debugignore', [], '[FILE]')
2442 def debugignore(ui, repo, *files, **opts):
2442 def debugignore(ui, repo, *files, **opts):
2443 """display the combined ignore pattern and information about ignored files
2443 """display the combined ignore pattern and information about ignored files
2444
2444
2445 With no argument display the combined ignore pattern.
2445 With no argument display the combined ignore pattern.
2446
2446
2447 Given space separated file names, shows if the given file is ignored and
2447 Given space separated file names, shows if the given file is ignored and
2448 if so, show the ignore rule (file and line number) that matched it.
2448 if so, show the ignore rule (file and line number) that matched it.
2449 """
2449 """
2450 ignore = repo.dirstate._ignore
2450 ignore = repo.dirstate._ignore
2451 if not files:
2451 if not files:
2452 # Show all the patterns
2452 # Show all the patterns
2453 includepat = getattr(ignore, 'includepat', None)
2453 includepat = getattr(ignore, 'includepat', None)
2454 if includepat is not None:
2454 if includepat is not None:
2455 ui.write("%s\n" % includepat)
2455 ui.write("%s\n" % includepat)
2456 else:
2456 else:
2457 raise error.Abort(_("no ignore patterns found"))
2457 raise error.Abort(_("no ignore patterns found"))
2458 else:
2458 else:
2459 for f in files:
2459 for f in files:
2460 ignored = None
2460 ignored = None
2461 ignoredata = None
2461 ignoredata = None
2462 if f != '.':
2462 if f != '.':
2463 if ignore(f):
2463 if ignore(f):
2464 ignored = f
2464 ignored = f
2465 ignoredata = repo.dirstate._ignorefileandline(f)
2465 ignoredata = repo.dirstate._ignorefileandline(f)
2466 else:
2466 else:
2467 for p in util.finddirs(f):
2467 for p in util.finddirs(f):
2468 if ignore(p):
2468 if ignore(p):
2469 ignored = p
2469 ignored = p
2470 ignoredata = repo.dirstate._ignorefileandline(p)
2470 ignoredata = repo.dirstate._ignorefileandline(p)
2471 break
2471 break
2472 if ignored:
2472 if ignored:
2473 if ignored == f:
2473 if ignored == f:
2474 ui.write("%s is ignored\n" % f)
2474 ui.write("%s is ignored\n" % f)
2475 else:
2475 else:
2476 ui.write("%s is ignored because of containing folder %s\n"
2476 ui.write("%s is ignored because of containing folder %s\n"
2477 % (f, ignored))
2477 % (f, ignored))
2478 ignorefile, lineno, line = ignoredata
2478 ignorefile, lineno, line = ignoredata
2479 ui.write("(ignore rule in %s, line %d: '%s')\n"
2479 ui.write("(ignore rule in %s, line %d: '%s')\n"
2480 % (ignorefile, lineno, line))
2480 % (ignorefile, lineno, line))
2481 else:
2481 else:
2482 ui.write("%s is not ignored\n" % f)
2482 ui.write("%s is not ignored\n" % f)
2483
2483
2484 @command('debugindex', debugrevlogopts +
2484 @command('debugindex', debugrevlogopts +
2485 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2485 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2486 _('[-f FORMAT] -c|-m|FILE'),
2486 _('[-f FORMAT] -c|-m|FILE'),
2487 optionalrepo=True)
2487 optionalrepo=True)
2488 def debugindex(ui, repo, file_=None, **opts):
2488 def debugindex(ui, repo, file_=None, **opts):
2489 """dump the contents of an index file"""
2489 """dump the contents of an index file"""
2490 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2490 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2491 format = opts.get('format', 0)
2491 format = opts.get('format', 0)
2492 if format not in (0, 1):
2492 if format not in (0, 1):
2493 raise error.Abort(_("unknown format %d") % format)
2493 raise error.Abort(_("unknown format %d") % format)
2494
2494
2495 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2495 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2496 if generaldelta:
2496 if generaldelta:
2497 basehdr = ' delta'
2497 basehdr = ' delta'
2498 else:
2498 else:
2499 basehdr = ' base'
2499 basehdr = ' base'
2500
2500
2501 if ui.debugflag:
2501 if ui.debugflag:
2502 shortfn = hex
2502 shortfn = hex
2503 else:
2503 else:
2504 shortfn = short
2504 shortfn = short
2505
2505
2506 # There might not be anything in r, so have a sane default
2506 # There might not be anything in r, so have a sane default
2507 idlen = 12
2507 idlen = 12
2508 for i in r:
2508 for i in r:
2509 idlen = len(shortfn(r.node(i)))
2509 idlen = len(shortfn(r.node(i)))
2510 break
2510 break
2511
2511
2512 if format == 0:
2512 if format == 0:
2513 ui.write(" rev offset length " + basehdr + " linkrev"
2513 ui.write(" rev offset length " + basehdr + " linkrev"
2514 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2514 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2515 elif format == 1:
2515 elif format == 1:
2516 ui.write(" rev flag offset length"
2516 ui.write(" rev flag offset length"
2517 " size " + basehdr + " link p1 p2"
2517 " size " + basehdr + " link p1 p2"
2518 " %s\n" % "nodeid".rjust(idlen))
2518 " %s\n" % "nodeid".rjust(idlen))
2519
2519
2520 for i in r:
2520 for i in r:
2521 node = r.node(i)
2521 node = r.node(i)
2522 if generaldelta:
2522 if generaldelta:
2523 base = r.deltaparent(i)
2523 base = r.deltaparent(i)
2524 else:
2524 else:
2525 base = r.chainbase(i)
2525 base = r.chainbase(i)
2526 if format == 0:
2526 if format == 0:
2527 try:
2527 try:
2528 pp = r.parents(node)
2528 pp = r.parents(node)
2529 except Exception:
2529 except Exception:
2530 pp = [nullid, nullid]
2530 pp = [nullid, nullid]
2531 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2531 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2532 i, r.start(i), r.length(i), base, r.linkrev(i),
2532 i, r.start(i), r.length(i), base, r.linkrev(i),
2533 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2533 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2534 elif format == 1:
2534 elif format == 1:
2535 pr = r.parentrevs(i)
2535 pr = r.parentrevs(i)
2536 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2536 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2537 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2537 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2538 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2538 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2539
2539
2540 @command('debugindexdot', debugrevlogopts,
2540 @command('debugindexdot', debugrevlogopts,
2541 _('-c|-m|FILE'), optionalrepo=True)
2541 _('-c|-m|FILE'), optionalrepo=True)
2542 def debugindexdot(ui, repo, file_=None, **opts):
2542 def debugindexdot(ui, repo, file_=None, **opts):
2543 """dump an index DAG as a graphviz dot file"""
2543 """dump an index DAG as a graphviz dot file"""
2544 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2544 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2545 ui.write(("digraph G {\n"))
2545 ui.write(("digraph G {\n"))
2546 for i in r:
2546 for i in r:
2547 node = r.node(i)
2547 node = r.node(i)
2548 pp = r.parents(node)
2548 pp = r.parents(node)
2549 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2549 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2550 if pp[1] != nullid:
2550 if pp[1] != nullid:
2551 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2551 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2552 ui.write("}\n")
2552 ui.write("}\n")
2553
2553
2554 @command('debugdeltachain',
2554 @command('debugdeltachain',
2555 debugrevlogopts + formatteropts,
2555 debugrevlogopts + formatteropts,
2556 _('-c|-m|FILE'),
2556 _('-c|-m|FILE'),
2557 optionalrepo=True)
2557 optionalrepo=True)
2558 def debugdeltachain(ui, repo, file_=None, **opts):
2558 def debugdeltachain(ui, repo, file_=None, **opts):
2559 """dump information about delta chains in a revlog
2559 """dump information about delta chains in a revlog
2560
2560
2561 Output can be templatized. Available template keywords are:
2561 Output can be templatized. Available template keywords are:
2562
2562
2563 rev revision number
2563 rev revision number
2564 chainid delta chain identifier (numbered by unique base)
2564 chainid delta chain identifier (numbered by unique base)
2565 chainlen delta chain length to this revision
2565 chainlen delta chain length to this revision
2566 prevrev previous revision in delta chain
2566 prevrev previous revision in delta chain
2567 deltatype role of delta / how it was computed
2567 deltatype role of delta / how it was computed
2568 compsize compressed size of revision
2568 compsize compressed size of revision
2569 uncompsize uncompressed size of revision
2569 uncompsize uncompressed size of revision
2570 chainsize total size of compressed revisions in chain
2570 chainsize total size of compressed revisions in chain
2571 chainratio total chain size divided by uncompressed revision size
2571 chainratio total chain size divided by uncompressed revision size
2572 (new delta chains typically start at ratio 2.00)
2572 (new delta chains typically start at ratio 2.00)
2573 lindist linear distance from base revision in delta chain to end
2573 lindist linear distance from base revision in delta chain to end
2574 of this revision
2574 of this revision
2575 extradist total size of revisions not part of this delta chain from
2575 extradist total size of revisions not part of this delta chain from
2576 base of delta chain to end of this revision; a measurement
2576 base of delta chain to end of this revision; a measurement
2577 of how much extra data we need to read/seek across to read
2577 of how much extra data we need to read/seek across to read
2578 the delta chain for this revision
2578 the delta chain for this revision
2579 extraratio extradist divided by chainsize; another representation of
2579 extraratio extradist divided by chainsize; another representation of
2580 how much unrelated data is needed to load this delta chain
2580 how much unrelated data is needed to load this delta chain
2581 """
2581 """
2582 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2582 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2583 index = r.index
2583 index = r.index
2584 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2584 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2585
2585
2586 def revinfo(rev):
2586 def revinfo(rev):
2587 e = index[rev]
2587 e = index[rev]
2588 compsize = e[1]
2588 compsize = e[1]
2589 uncompsize = e[2]
2589 uncompsize = e[2]
2590 chainsize = 0
2590 chainsize = 0
2591
2591
2592 if generaldelta:
2592 if generaldelta:
2593 if e[3] == e[5]:
2593 if e[3] == e[5]:
2594 deltatype = 'p1'
2594 deltatype = 'p1'
2595 elif e[3] == e[6]:
2595 elif e[3] == e[6]:
2596 deltatype = 'p2'
2596 deltatype = 'p2'
2597 elif e[3] == rev - 1:
2597 elif e[3] == rev - 1:
2598 deltatype = 'prev'
2598 deltatype = 'prev'
2599 elif e[3] == rev:
2599 elif e[3] == rev:
2600 deltatype = 'base'
2600 deltatype = 'base'
2601 else:
2601 else:
2602 deltatype = 'other'
2602 deltatype = 'other'
2603 else:
2603 else:
2604 if e[3] == rev:
2604 if e[3] == rev:
2605 deltatype = 'base'
2605 deltatype = 'base'
2606 else:
2606 else:
2607 deltatype = 'prev'
2607 deltatype = 'prev'
2608
2608
2609 chain = r._deltachain(rev)[0]
2609 chain = r._deltachain(rev)[0]
2610 for iterrev in chain:
2610 for iterrev in chain:
2611 e = index[iterrev]
2611 e = index[iterrev]
2612 chainsize += e[1]
2612 chainsize += e[1]
2613
2613
2614 return compsize, uncompsize, deltatype, chain, chainsize
2614 return compsize, uncompsize, deltatype, chain, chainsize
2615
2615
2616 fm = ui.formatter('debugdeltachain', opts)
2616 fm = ui.formatter('debugdeltachain', opts)
2617
2617
2618 fm.plain(' rev chain# chainlen prev delta '
2618 fm.plain(' rev chain# chainlen prev delta '
2619 'size rawsize chainsize ratio lindist extradist '
2619 'size rawsize chainsize ratio lindist extradist '
2620 'extraratio\n')
2620 'extraratio\n')
2621
2621
2622 chainbases = {}
2622 chainbases = {}
2623 for rev in r:
2623 for rev in r:
2624 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2624 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2625 chainbase = chain[0]
2625 chainbase = chain[0]
2626 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2626 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2627 basestart = r.start(chainbase)
2627 basestart = r.start(chainbase)
2628 revstart = r.start(rev)
2628 revstart = r.start(rev)
2629 lineardist = revstart + comp - basestart
2629 lineardist = revstart + comp - basestart
2630 extradist = lineardist - chainsize
2630 extradist = lineardist - chainsize
2631 try:
2631 try:
2632 prevrev = chain[-2]
2632 prevrev = chain[-2]
2633 except IndexError:
2633 except IndexError:
2634 prevrev = -1
2634 prevrev = -1
2635
2635
2636 chainratio = float(chainsize) / float(uncomp)
2636 chainratio = float(chainsize) / float(uncomp)
2637 extraratio = float(extradist) / float(chainsize)
2637 extraratio = float(extradist) / float(chainsize)
2638
2638
2639 fm.startitem()
2639 fm.startitem()
2640 fm.write('rev chainid chainlen prevrev deltatype compsize '
2640 fm.write('rev chainid chainlen prevrev deltatype compsize '
2641 'uncompsize chainsize chainratio lindist extradist '
2641 'uncompsize chainsize chainratio lindist extradist '
2642 'extraratio',
2642 'extraratio',
2643 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2643 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2644 rev, chainid, len(chain), prevrev, deltatype, comp,
2644 rev, chainid, len(chain), prevrev, deltatype, comp,
2645 uncomp, chainsize, chainratio, lineardist, extradist,
2645 uncomp, chainsize, chainratio, lineardist, extradist,
2646 extraratio,
2646 extraratio,
2647 rev=rev, chainid=chainid, chainlen=len(chain),
2647 rev=rev, chainid=chainid, chainlen=len(chain),
2648 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2648 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2649 uncompsize=uncomp, chainsize=chainsize,
2649 uncompsize=uncomp, chainsize=chainsize,
2650 chainratio=chainratio, lindist=lineardist,
2650 chainratio=chainratio, lindist=lineardist,
2651 extradist=extradist, extraratio=extraratio)
2651 extradist=extradist, extraratio=extraratio)
2652
2652
2653 fm.end()
2653 fm.end()
2654
2654
2655 @command('debuginstall', [], '', norepo=True)
2655 @command('debuginstall', [], '', norepo=True)
2656 def debuginstall(ui):
2656 def debuginstall(ui):
2657 '''test Mercurial installation
2657 '''test Mercurial installation
2658
2658
2659 Returns 0 on success.
2659 Returns 0 on success.
2660 '''
2660 '''
2661
2661
2662 def writetemp(contents):
2662 def writetemp(contents):
2663 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2663 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2664 f = os.fdopen(fd, "wb")
2664 f = os.fdopen(fd, "wb")
2665 f.write(contents)
2665 f.write(contents)
2666 f.close()
2666 f.close()
2667 return name
2667 return name
2668
2668
2669 problems = 0
2669 problems = 0
2670
2670
2671 # encoding
2671 # encoding
2672 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2672 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2673 try:
2673 try:
2674 encoding.fromlocal("test")
2674 encoding.fromlocal("test")
2675 except error.Abort as inst:
2675 except error.Abort as inst:
2676 ui.write(" %s\n" % inst)
2676 ui.write(" %s\n" % inst)
2677 ui.write(_(" (check that your locale is properly set)\n"))
2677 ui.write(_(" (check that your locale is properly set)\n"))
2678 problems += 1
2678 problems += 1
2679
2679
2680 # Python
2680 # Python
2681 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2681 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2682 ui.status(_("checking Python version (%s)\n")
2682 ui.status(_("checking Python version (%s)\n")
2683 % ("%s.%s.%s" % sys.version_info[:3]))
2683 % ("%s.%s.%s" % sys.version_info[:3]))
2684 ui.status(_("checking Python lib (%s)...\n")
2684 ui.status(_("checking Python lib (%s)...\n")
2685 % os.path.dirname(os.__file__))
2685 % os.path.dirname(os.__file__))
2686
2686
2687 # compiled modules
2687 # compiled modules
2688 ui.status(_("checking installed modules (%s)...\n")
2688 ui.status(_("checking installed modules (%s)...\n")
2689 % os.path.dirname(__file__))
2689 % os.path.dirname(__file__))
2690 try:
2690 try:
2691 import bdiff, mpatch, base85, osutil
2691 import bdiff, mpatch, base85, osutil
2692 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2692 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2693 except Exception as inst:
2693 except Exception as inst:
2694 ui.write(" %s\n" % inst)
2694 ui.write(" %s\n" % inst)
2695 ui.write(_(" One or more extensions could not be found"))
2695 ui.write(_(" One or more extensions could not be found"))
2696 ui.write(_(" (check that you compiled the extensions)\n"))
2696 ui.write(_(" (check that you compiled the extensions)\n"))
2697 problems += 1
2697 problems += 1
2698
2698
2699 # templates
2699 # templates
2700 import templater
2700 import templater
2701 p = templater.templatepaths()
2701 p = templater.templatepaths()
2702 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2702 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2703 if p:
2703 if p:
2704 m = templater.templatepath("map-cmdline.default")
2704 m = templater.templatepath("map-cmdline.default")
2705 if m:
2705 if m:
2706 # template found, check if it is working
2706 # template found, check if it is working
2707 try:
2707 try:
2708 templater.templater(m)
2708 templater.templater(m)
2709 except Exception as inst:
2709 except Exception as inst:
2710 ui.write(" %s\n" % inst)
2710 ui.write(" %s\n" % inst)
2711 p = None
2711 p = None
2712 else:
2712 else:
2713 ui.write(_(" template 'default' not found\n"))
2713 ui.write(_(" template 'default' not found\n"))
2714 p = None
2714 p = None
2715 else:
2715 else:
2716 ui.write(_(" no template directories found\n"))
2716 ui.write(_(" no template directories found\n"))
2717 if not p:
2717 if not p:
2718 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2718 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2719 problems += 1
2719 problems += 1
2720
2720
2721 # editor
2721 # editor
2722 ui.status(_("checking commit editor...\n"))
2722 ui.status(_("checking commit editor...\n"))
2723 editor = ui.geteditor()
2723 editor = ui.geteditor()
2724 editor = util.expandpath(editor)
2724 editor = util.expandpath(editor)
2725 cmdpath = util.findexe(shlex.split(editor)[0])
2725 cmdpath = util.findexe(shlex.split(editor)[0])
2726 if not cmdpath:
2726 if not cmdpath:
2727 if editor == 'vi':
2727 if editor == 'vi':
2728 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2728 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2729 ui.write(_(" (specify a commit editor in your configuration"
2729 ui.write(_(" (specify a commit editor in your configuration"
2730 " file)\n"))
2730 " file)\n"))
2731 else:
2731 else:
2732 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2732 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2733 ui.write(_(" (specify a commit editor in your configuration"
2733 ui.write(_(" (specify a commit editor in your configuration"
2734 " file)\n"))
2734 " file)\n"))
2735 problems += 1
2735 problems += 1
2736
2736
2737 # check username
2737 # check username
2738 ui.status(_("checking username...\n"))
2738 ui.status(_("checking username...\n"))
2739 try:
2739 try:
2740 ui.username()
2740 ui.username()
2741 except error.Abort as e:
2741 except error.Abort as e:
2742 ui.write(" %s\n" % e)
2742 ui.write(" %s\n" % e)
2743 ui.write(_(" (specify a username in your configuration file)\n"))
2743 ui.write(_(" (specify a username in your configuration file)\n"))
2744 problems += 1
2744 problems += 1
2745
2745
2746 if not problems:
2746 if not problems:
2747 ui.status(_("no problems detected\n"))
2747 ui.status(_("no problems detected\n"))
2748 else:
2748 else:
2749 ui.write(_("%s problems detected,"
2749 ui.write(_("%s problems detected,"
2750 " please check your install!\n") % problems)
2750 " please check your install!\n") % problems)
2751
2751
2752 return problems
2752 return problems
2753
2753
2754 @command('debugknown', [], _('REPO ID...'), norepo=True)
2754 @command('debugknown', [], _('REPO ID...'), norepo=True)
2755 def debugknown(ui, repopath, *ids, **opts):
2755 def debugknown(ui, repopath, *ids, **opts):
2756 """test whether node ids are known to a repo
2756 """test whether node ids are known to a repo
2757
2757
2758 Every ID must be a full-length hex node id string. Returns a list of 0s
2758 Every ID must be a full-length hex node id string. Returns a list of 0s
2759 and 1s indicating unknown/known.
2759 and 1s indicating unknown/known.
2760 """
2760 """
2761 repo = hg.peer(ui, opts, repopath)
2761 repo = hg.peer(ui, opts, repopath)
2762 if not repo.capable('known'):
2762 if not repo.capable('known'):
2763 raise error.Abort("known() not supported by target repository")
2763 raise error.Abort("known() not supported by target repository")
2764 flags = repo.known([bin(s) for s in ids])
2764 flags = repo.known([bin(s) for s in ids])
2765 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2765 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2766
2766
2767 @command('debuglabelcomplete', [], _('LABEL...'))
2767 @command('debuglabelcomplete', [], _('LABEL...'))
2768 def debuglabelcomplete(ui, repo, *args):
2768 def debuglabelcomplete(ui, repo, *args):
2769 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2769 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2770 debugnamecomplete(ui, repo, *args)
2770 debugnamecomplete(ui, repo, *args)
2771
2771
2772 @command('debugmergestate', [], '')
2772 @command('debugmergestate', [], '')
2773 def debugmergestate(ui, repo, *args):
2773 def debugmergestate(ui, repo, *args):
2774 """print merge state
2774 """print merge state
2775
2775
2776 Use --verbose to print out information about whether v1 or v2 merge state
2776 Use --verbose to print out information about whether v1 or v2 merge state
2777 was chosen."""
2777 was chosen."""
2778 def _hashornull(h):
2778 def _hashornull(h):
2779 if h == nullhex:
2779 if h == nullhex:
2780 return 'null'
2780 return 'null'
2781 else:
2781 else:
2782 return h
2782 return h
2783
2783
2784 def printrecords(version):
2784 def printrecords(version):
2785 ui.write(('* version %s records\n') % version)
2785 ui.write(('* version %s records\n') % version)
2786 if version == 1:
2786 if version == 1:
2787 records = v1records
2787 records = v1records
2788 else:
2788 else:
2789 records = v2records
2789 records = v2records
2790
2790
2791 for rtype, record in records:
2791 for rtype, record in records:
2792 # pretty print some record types
2792 # pretty print some record types
2793 if rtype == 'L':
2793 if rtype == 'L':
2794 ui.write(('local: %s\n') % record)
2794 ui.write(('local: %s\n') % record)
2795 elif rtype == 'O':
2795 elif rtype == 'O':
2796 ui.write(('other: %s\n') % record)
2796 ui.write(('other: %s\n') % record)
2797 elif rtype == 'm':
2797 elif rtype == 'm':
2798 driver, mdstate = record.split('\0', 1)
2798 driver, mdstate = record.split('\0', 1)
2799 ui.write(('merge driver: %s (state "%s")\n')
2799 ui.write(('merge driver: %s (state "%s")\n')
2800 % (driver, mdstate))
2800 % (driver, mdstate))
2801 elif rtype in 'FDC':
2801 elif rtype in 'FDC':
2802 r = record.split('\0')
2802 r = record.split('\0')
2803 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2803 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2804 if version == 1:
2804 if version == 1:
2805 onode = 'not stored in v1 format'
2805 onode = 'not stored in v1 format'
2806 flags = r[7]
2806 flags = r[7]
2807 else:
2807 else:
2808 onode, flags = r[7:9]
2808 onode, flags = r[7:9]
2809 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2809 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2810 % (f, rtype, state, _hashornull(hash)))
2810 % (f, rtype, state, _hashornull(hash)))
2811 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2811 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2812 ui.write((' ancestor path: %s (node %s)\n')
2812 ui.write((' ancestor path: %s (node %s)\n')
2813 % (afile, _hashornull(anode)))
2813 % (afile, _hashornull(anode)))
2814 ui.write((' other path: %s (node %s)\n')
2814 ui.write((' other path: %s (node %s)\n')
2815 % (ofile, _hashornull(onode)))
2815 % (ofile, _hashornull(onode)))
2816 else:
2816 else:
2817 ui.write(('unrecognized entry: %s\t%s\n')
2817 ui.write(('unrecognized entry: %s\t%s\n')
2818 % (rtype, record.replace('\0', '\t')))
2818 % (rtype, record.replace('\0', '\t')))
2819
2819
2820 # Avoid mergestate.read() since it may raise an exception for unsupported
2820 # Avoid mergestate.read() since it may raise an exception for unsupported
2821 # merge state records. We shouldn't be doing this, but this is OK since this
2821 # merge state records. We shouldn't be doing this, but this is OK since this
2822 # command is pretty low-level.
2822 # command is pretty low-level.
2823 ms = mergemod.mergestate(repo)
2823 ms = mergemod.mergestate(repo)
2824
2824
2825 # sort so that reasonable information is on top
2825 # sort so that reasonable information is on top
2826 v1records = ms._readrecordsv1()
2826 v1records = ms._readrecordsv1()
2827 v2records = ms._readrecordsv2()
2827 v2records = ms._readrecordsv2()
2828 order = 'LOm'
2828 order = 'LOm'
2829 def key(r):
2829 def key(r):
2830 idx = order.find(r[0])
2830 idx = order.find(r[0])
2831 if idx == -1:
2831 if idx == -1:
2832 return (1, r[1])
2832 return (1, r[1])
2833 else:
2833 else:
2834 return (0, idx)
2834 return (0, idx)
2835 v1records.sort(key=key)
2835 v1records.sort(key=key)
2836 v2records.sort(key=key)
2836 v2records.sort(key=key)
2837
2837
2838 if not v1records and not v2records:
2838 if not v1records and not v2records:
2839 ui.write(('no merge state found\n'))
2839 ui.write(('no merge state found\n'))
2840 elif not v2records:
2840 elif not v2records:
2841 ui.note(('no version 2 merge state\n'))
2841 ui.note(('no version 2 merge state\n'))
2842 printrecords(1)
2842 printrecords(1)
2843 elif ms._v1v2match(v1records, v2records):
2843 elif ms._v1v2match(v1records, v2records):
2844 ui.note(('v1 and v2 states match: using v2\n'))
2844 ui.note(('v1 and v2 states match: using v2\n'))
2845 printrecords(2)
2845 printrecords(2)
2846 else:
2846 else:
2847 ui.note(('v1 and v2 states mismatch: using v1\n'))
2847 ui.note(('v1 and v2 states mismatch: using v1\n'))
2848 printrecords(1)
2848 printrecords(1)
2849 if ui.verbose:
2849 if ui.verbose:
2850 printrecords(2)
2850 printrecords(2)
2851
2851
2852 @command('debugnamecomplete', [], _('NAME...'))
2852 @command('debugnamecomplete', [], _('NAME...'))
2853 def debugnamecomplete(ui, repo, *args):
2853 def debugnamecomplete(ui, repo, *args):
2854 '''complete "names" - tags, open branch names, bookmark names'''
2854 '''complete "names" - tags, open branch names, bookmark names'''
2855
2855
2856 names = set()
2856 names = set()
2857 # since we previously only listed open branches, we will handle that
2857 # since we previously only listed open branches, we will handle that
2858 # specially (after this for loop)
2858 # specially (after this for loop)
2859 for name, ns in repo.names.iteritems():
2859 for name, ns in repo.names.iteritems():
2860 if name != 'branches':
2860 if name != 'branches':
2861 names.update(ns.listnames(repo))
2861 names.update(ns.listnames(repo))
2862 names.update(tag for (tag, heads, tip, closed)
2862 names.update(tag for (tag, heads, tip, closed)
2863 in repo.branchmap().iterbranches() if not closed)
2863 in repo.branchmap().iterbranches() if not closed)
2864 completions = set()
2864 completions = set()
2865 if not args:
2865 if not args:
2866 args = ['']
2866 args = ['']
2867 for a in args:
2867 for a in args:
2868 completions.update(n for n in names if n.startswith(a))
2868 completions.update(n for n in names if n.startswith(a))
2869 ui.write('\n'.join(sorted(completions)))
2869 ui.write('\n'.join(sorted(completions)))
2870 ui.write('\n')
2870 ui.write('\n')
2871
2871
2872 @command('debuglocks',
2872 @command('debuglocks',
2873 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2873 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2874 ('W', 'force-wlock', None,
2874 ('W', 'force-wlock', None,
2875 _('free the working state lock (DANGEROUS)'))],
2875 _('free the working state lock (DANGEROUS)'))],
2876 _('[OPTION]...'))
2876 _('[OPTION]...'))
2877 def debuglocks(ui, repo, **opts):
2877 def debuglocks(ui, repo, **opts):
2878 """show or modify state of locks
2878 """show or modify state of locks
2879
2879
2880 By default, this command will show which locks are held. This
2880 By default, this command will show which locks are held. This
2881 includes the user and process holding the lock, the amount of time
2881 includes the user and process holding the lock, the amount of time
2882 the lock has been held, and the machine name where the process is
2882 the lock has been held, and the machine name where the process is
2883 running if it's not local.
2883 running if it's not local.
2884
2884
2885 Locks protect the integrity of Mercurial's data, so should be
2885 Locks protect the integrity of Mercurial's data, so should be
2886 treated with care. System crashes or other interruptions may cause
2886 treated with care. System crashes or other interruptions may cause
2887 locks to not be properly released, though Mercurial will usually
2887 locks to not be properly released, though Mercurial will usually
2888 detect and remove such stale locks automatically.
2888 detect and remove such stale locks automatically.
2889
2889
2890 However, detecting stale locks may not always be possible (for
2890 However, detecting stale locks may not always be possible (for
2891 instance, on a shared filesystem). Removing locks may also be
2891 instance, on a shared filesystem). Removing locks may also be
2892 blocked by filesystem permissions.
2892 blocked by filesystem permissions.
2893
2893
2894 Returns 0 if no locks are held.
2894 Returns 0 if no locks are held.
2895
2895
2896 """
2896 """
2897
2897
2898 if opts.get('force_lock'):
2898 if opts.get('force_lock'):
2899 repo.svfs.unlink('lock')
2899 repo.svfs.unlink('lock')
2900 if opts.get('force_wlock'):
2900 if opts.get('force_wlock'):
2901 repo.vfs.unlink('wlock')
2901 repo.vfs.unlink('wlock')
2902 if opts.get('force_lock') or opts.get('force_lock'):
2902 if opts.get('force_lock') or opts.get('force_lock'):
2903 return 0
2903 return 0
2904
2904
2905 now = time.time()
2905 now = time.time()
2906 held = 0
2906 held = 0
2907
2907
2908 def report(vfs, name, method):
2908 def report(vfs, name, method):
2909 # this causes stale locks to get reaped for more accurate reporting
2909 # this causes stale locks to get reaped for more accurate reporting
2910 try:
2910 try:
2911 l = method(False)
2911 l = method(False)
2912 except error.LockHeld:
2912 except error.LockHeld:
2913 l = None
2913 l = None
2914
2914
2915 if l:
2915 if l:
2916 l.release()
2916 l.release()
2917 else:
2917 else:
2918 try:
2918 try:
2919 stat = vfs.lstat(name)
2919 stat = vfs.lstat(name)
2920 age = now - stat.st_mtime
2920 age = now - stat.st_mtime
2921 user = util.username(stat.st_uid)
2921 user = util.username(stat.st_uid)
2922 locker = vfs.readlock(name)
2922 locker = vfs.readlock(name)
2923 if ":" in locker:
2923 if ":" in locker:
2924 host, pid = locker.split(':')
2924 host, pid = locker.split(':')
2925 if host == socket.gethostname():
2925 if host == socket.gethostname():
2926 locker = 'user %s, process %s' % (user, pid)
2926 locker = 'user %s, process %s' % (user, pid)
2927 else:
2927 else:
2928 locker = 'user %s, process %s, host %s' \
2928 locker = 'user %s, process %s, host %s' \
2929 % (user, pid, host)
2929 % (user, pid, host)
2930 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2930 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2931 return 1
2931 return 1
2932 except OSError as e:
2932 except OSError as e:
2933 if e.errno != errno.ENOENT:
2933 if e.errno != errno.ENOENT:
2934 raise
2934 raise
2935
2935
2936 ui.write("%-6s free\n" % (name + ":"))
2936 ui.write("%-6s free\n" % (name + ":"))
2937 return 0
2937 return 0
2938
2938
2939 held += report(repo.svfs, "lock", repo.lock)
2939 held += report(repo.svfs, "lock", repo.lock)
2940 held += report(repo.vfs, "wlock", repo.wlock)
2940 held += report(repo.vfs, "wlock", repo.wlock)
2941
2941
2942 return held
2942 return held
2943
2943
2944 @command('debugobsolete',
2944 @command('debugobsolete',
2945 [('', 'flags', 0, _('markers flag')),
2945 [('', 'flags', 0, _('markers flag')),
2946 ('', 'record-parents', False,
2946 ('', 'record-parents', False,
2947 _('record parent information for the precursor')),
2947 _('record parent information for the precursor')),
2948 ('r', 'rev', [], _('display markers relevant to REV')),
2948 ('r', 'rev', [], _('display markers relevant to REV')),
2949 ] + commitopts2,
2949 ] + commitopts2,
2950 _('[OBSOLETED [REPLACEMENT ...]]'))
2950 _('[OBSOLETED [REPLACEMENT ...]]'))
2951 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2951 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2952 """create arbitrary obsolete marker
2952 """create arbitrary obsolete marker
2953
2953
2954 With no arguments, displays the list of obsolescence markers."""
2954 With no arguments, displays the list of obsolescence markers."""
2955
2955
2956 def parsenodeid(s):
2956 def parsenodeid(s):
2957 try:
2957 try:
2958 # We do not use revsingle/revrange functions here to accept
2958 # We do not use revsingle/revrange functions here to accept
2959 # arbitrary node identifiers, possibly not present in the
2959 # arbitrary node identifiers, possibly not present in the
2960 # local repository.
2960 # local repository.
2961 n = bin(s)
2961 n = bin(s)
2962 if len(n) != len(nullid):
2962 if len(n) != len(nullid):
2963 raise TypeError()
2963 raise TypeError()
2964 return n
2964 return n
2965 except TypeError:
2965 except TypeError:
2966 raise error.Abort('changeset references must be full hexadecimal '
2966 raise error.Abort('changeset references must be full hexadecimal '
2967 'node identifiers')
2967 'node identifiers')
2968
2968
2969 if precursor is not None:
2969 if precursor is not None:
2970 if opts['rev']:
2970 if opts['rev']:
2971 raise error.Abort('cannot select revision when creating marker')
2971 raise error.Abort('cannot select revision when creating marker')
2972 metadata = {}
2972 metadata = {}
2973 metadata['user'] = opts['user'] or ui.username()
2973 metadata['user'] = opts['user'] or ui.username()
2974 succs = tuple(parsenodeid(succ) for succ in successors)
2974 succs = tuple(parsenodeid(succ) for succ in successors)
2975 l = repo.lock()
2975 l = repo.lock()
2976 try:
2976 try:
2977 tr = repo.transaction('debugobsolete')
2977 tr = repo.transaction('debugobsolete')
2978 try:
2978 try:
2979 date = opts.get('date')
2979 date = opts.get('date')
2980 if date:
2980 if date:
2981 date = util.parsedate(date)
2981 date = util.parsedate(date)
2982 else:
2982 else:
2983 date = None
2983 date = None
2984 prec = parsenodeid(precursor)
2984 prec = parsenodeid(precursor)
2985 parents = None
2985 parents = None
2986 if opts['record_parents']:
2986 if opts['record_parents']:
2987 if prec not in repo.unfiltered():
2987 if prec not in repo.unfiltered():
2988 raise error.Abort('cannot used --record-parents on '
2988 raise error.Abort('cannot used --record-parents on '
2989 'unknown changesets')
2989 'unknown changesets')
2990 parents = repo.unfiltered()[prec].parents()
2990 parents = repo.unfiltered()[prec].parents()
2991 parents = tuple(p.node() for p in parents)
2991 parents = tuple(p.node() for p in parents)
2992 repo.obsstore.create(tr, prec, succs, opts['flags'],
2992 repo.obsstore.create(tr, prec, succs, opts['flags'],
2993 parents=parents, date=date,
2993 parents=parents, date=date,
2994 metadata=metadata)
2994 metadata=metadata)
2995 tr.close()
2995 tr.close()
2996 except ValueError as exc:
2996 except ValueError as exc:
2997 raise error.Abort(_('bad obsmarker input: %s') % exc)
2997 raise error.Abort(_('bad obsmarker input: %s') % exc)
2998 finally:
2998 finally:
2999 tr.release()
2999 tr.release()
3000 finally:
3000 finally:
3001 l.release()
3001 l.release()
3002 else:
3002 else:
3003 if opts['rev']:
3003 if opts['rev']:
3004 revs = scmutil.revrange(repo, opts['rev'])
3004 revs = scmutil.revrange(repo, opts['rev'])
3005 nodes = [repo[r].node() for r in revs]
3005 nodes = [repo[r].node() for r in revs]
3006 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3006 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3007 markers.sort(key=lambda x: x._data)
3007 markers.sort(key=lambda x: x._data)
3008 else:
3008 else:
3009 markers = obsolete.getmarkers(repo)
3009 markers = obsolete.getmarkers(repo)
3010
3010
3011 for m in markers:
3011 for m in markers:
3012 cmdutil.showmarker(ui, m)
3012 cmdutil.showmarker(ui, m)
3013
3013
3014 @command('debugpathcomplete',
3014 @command('debugpathcomplete',
3015 [('f', 'full', None, _('complete an entire path')),
3015 [('f', 'full', None, _('complete an entire path')),
3016 ('n', 'normal', None, _('show only normal files')),
3016 ('n', 'normal', None, _('show only normal files')),
3017 ('a', 'added', None, _('show only added files')),
3017 ('a', 'added', None, _('show only added files')),
3018 ('r', 'removed', None, _('show only removed files'))],
3018 ('r', 'removed', None, _('show only removed files'))],
3019 _('FILESPEC...'))
3019 _('FILESPEC...'))
3020 def debugpathcomplete(ui, repo, *specs, **opts):
3020 def debugpathcomplete(ui, repo, *specs, **opts):
3021 '''complete part or all of a tracked path
3021 '''complete part or all of a tracked path
3022
3022
3023 This command supports shells that offer path name completion. It
3023 This command supports shells that offer path name completion. It
3024 currently completes only files already known to the dirstate.
3024 currently completes only files already known to the dirstate.
3025
3025
3026 Completion extends only to the next path segment unless
3026 Completion extends only to the next path segment unless
3027 --full is specified, in which case entire paths are used.'''
3027 --full is specified, in which case entire paths are used.'''
3028
3028
3029 def complete(path, acceptable):
3029 def complete(path, acceptable):
3030 dirstate = repo.dirstate
3030 dirstate = repo.dirstate
3031 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3031 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3032 rootdir = repo.root + os.sep
3032 rootdir = repo.root + os.sep
3033 if spec != repo.root and not spec.startswith(rootdir):
3033 if spec != repo.root and not spec.startswith(rootdir):
3034 return [], []
3034 return [], []
3035 if os.path.isdir(spec):
3035 if os.path.isdir(spec):
3036 spec += '/'
3036 spec += '/'
3037 spec = spec[len(rootdir):]
3037 spec = spec[len(rootdir):]
3038 fixpaths = os.sep != '/'
3038 fixpaths = os.sep != '/'
3039 if fixpaths:
3039 if fixpaths:
3040 spec = spec.replace(os.sep, '/')
3040 spec = spec.replace(os.sep, '/')
3041 speclen = len(spec)
3041 speclen = len(spec)
3042 fullpaths = opts['full']
3042 fullpaths = opts['full']
3043 files, dirs = set(), set()
3043 files, dirs = set(), set()
3044 adddir, addfile = dirs.add, files.add
3044 adddir, addfile = dirs.add, files.add
3045 for f, st in dirstate.iteritems():
3045 for f, st in dirstate.iteritems():
3046 if f.startswith(spec) and st[0] in acceptable:
3046 if f.startswith(spec) and st[0] in acceptable:
3047 if fixpaths:
3047 if fixpaths:
3048 f = f.replace('/', os.sep)
3048 f = f.replace('/', os.sep)
3049 if fullpaths:
3049 if fullpaths:
3050 addfile(f)
3050 addfile(f)
3051 continue
3051 continue
3052 s = f.find(os.sep, speclen)
3052 s = f.find(os.sep, speclen)
3053 if s >= 0:
3053 if s >= 0:
3054 adddir(f[:s])
3054 adddir(f[:s])
3055 else:
3055 else:
3056 addfile(f)
3056 addfile(f)
3057 return files, dirs
3057 return files, dirs
3058
3058
3059 acceptable = ''
3059 acceptable = ''
3060 if opts['normal']:
3060 if opts['normal']:
3061 acceptable += 'nm'
3061 acceptable += 'nm'
3062 if opts['added']:
3062 if opts['added']:
3063 acceptable += 'a'
3063 acceptable += 'a'
3064 if opts['removed']:
3064 if opts['removed']:
3065 acceptable += 'r'
3065 acceptable += 'r'
3066 cwd = repo.getcwd()
3066 cwd = repo.getcwd()
3067 if not specs:
3067 if not specs:
3068 specs = ['.']
3068 specs = ['.']
3069
3069
3070 files, dirs = set(), set()
3070 files, dirs = set(), set()
3071 for spec in specs:
3071 for spec in specs:
3072 f, d = complete(spec, acceptable or 'nmar')
3072 f, d = complete(spec, acceptable or 'nmar')
3073 files.update(f)
3073 files.update(f)
3074 dirs.update(d)
3074 dirs.update(d)
3075 files.update(dirs)
3075 files.update(dirs)
3076 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3076 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3077 ui.write('\n')
3077 ui.write('\n')
3078
3078
3079 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3079 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3080 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3080 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3081 '''access the pushkey key/value protocol
3081 '''access the pushkey key/value protocol
3082
3082
3083 With two args, list the keys in the given namespace.
3083 With two args, list the keys in the given namespace.
3084
3084
3085 With five args, set a key to new if it currently is set to old.
3085 With five args, set a key to new if it currently is set to old.
3086 Reports success or failure.
3086 Reports success or failure.
3087 '''
3087 '''
3088
3088
3089 target = hg.peer(ui, {}, repopath)
3089 target = hg.peer(ui, {}, repopath)
3090 if keyinfo:
3090 if keyinfo:
3091 key, old, new = keyinfo
3091 key, old, new = keyinfo
3092 r = target.pushkey(namespace, key, old, new)
3092 r = target.pushkey(namespace, key, old, new)
3093 ui.status(str(r) + '\n')
3093 ui.status(str(r) + '\n')
3094 return not r
3094 return not r
3095 else:
3095 else:
3096 for k, v in sorted(target.listkeys(namespace).iteritems()):
3096 for k, v in sorted(target.listkeys(namespace).iteritems()):
3097 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3097 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3098 v.encode('string-escape')))
3098 v.encode('string-escape')))
3099
3099
3100 @command('debugpvec', [], _('A B'))
3100 @command('debugpvec', [], _('A B'))
3101 def debugpvec(ui, repo, a, b=None):
3101 def debugpvec(ui, repo, a, b=None):
3102 ca = scmutil.revsingle(repo, a)
3102 ca = scmutil.revsingle(repo, a)
3103 cb = scmutil.revsingle(repo, b)
3103 cb = scmutil.revsingle(repo, b)
3104 pa = pvec.ctxpvec(ca)
3104 pa = pvec.ctxpvec(ca)
3105 pb = pvec.ctxpvec(cb)
3105 pb = pvec.ctxpvec(cb)
3106 if pa == pb:
3106 if pa == pb:
3107 rel = "="
3107 rel = "="
3108 elif pa > pb:
3108 elif pa > pb:
3109 rel = ">"
3109 rel = ">"
3110 elif pa < pb:
3110 elif pa < pb:
3111 rel = "<"
3111 rel = "<"
3112 elif pa | pb:
3112 elif pa | pb:
3113 rel = "|"
3113 rel = "|"
3114 ui.write(_("a: %s\n") % pa)
3114 ui.write(_("a: %s\n") % pa)
3115 ui.write(_("b: %s\n") % pb)
3115 ui.write(_("b: %s\n") % pb)
3116 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3116 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3117 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3117 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3118 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3118 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3119 pa.distance(pb), rel))
3119 pa.distance(pb), rel))
3120
3120
3121 @command('debugrebuilddirstate|debugrebuildstate',
3121 @command('debugrebuilddirstate|debugrebuildstate',
3122 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3122 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3123 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3123 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3124 'the working copy parent')),
3124 'the working copy parent')),
3125 ],
3125 ],
3126 _('[-r REV]'))
3126 _('[-r REV]'))
3127 def debugrebuilddirstate(ui, repo, rev, **opts):
3127 def debugrebuilddirstate(ui, repo, rev, **opts):
3128 """rebuild the dirstate as it would look like for the given revision
3128 """rebuild the dirstate as it would look like for the given revision
3129
3129
3130 If no revision is specified the first current parent will be used.
3130 If no revision is specified the first current parent will be used.
3131
3131
3132 The dirstate will be set to the files of the given revision.
3132 The dirstate will be set to the files of the given revision.
3133 The actual working directory content or existing dirstate
3133 The actual working directory content or existing dirstate
3134 information such as adds or removes is not considered.
3134 information such as adds or removes is not considered.
3135
3135
3136 ``minimal`` will only rebuild the dirstate status for files that claim to be
3136 ``minimal`` will only rebuild the dirstate status for files that claim to be
3137 tracked but are not in the parent manifest, or that exist in the parent
3137 tracked but are not in the parent manifest, or that exist in the parent
3138 manifest but are not in the dirstate. It will not change adds, removes, or
3138 manifest but are not in the dirstate. It will not change adds, removes, or
3139 modified files that are in the working copy parent.
3139 modified files that are in the working copy parent.
3140
3140
3141 One use of this command is to make the next :hg:`status` invocation
3141 One use of this command is to make the next :hg:`status` invocation
3142 check the actual file content.
3142 check the actual file content.
3143 """
3143 """
3144 ctx = scmutil.revsingle(repo, rev)
3144 ctx = scmutil.revsingle(repo, rev)
3145 with repo.wlock():
3145 with repo.wlock():
3146 dirstate = repo.dirstate
3146 dirstate = repo.dirstate
3147 changedfiles = None
3147 changedfiles = None
3148 # See command doc for what minimal does.
3148 # See command doc for what minimal does.
3149 if opts.get('minimal'):
3149 if opts.get('minimal'):
3150 manifestfiles = set(ctx.manifest().keys())
3150 manifestfiles = set(ctx.manifest().keys())
3151 dirstatefiles = set(dirstate)
3151 dirstatefiles = set(dirstate)
3152 manifestonly = manifestfiles - dirstatefiles
3152 manifestonly = manifestfiles - dirstatefiles
3153 dsonly = dirstatefiles - manifestfiles
3153 dsonly = dirstatefiles - manifestfiles
3154 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3154 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3155 changedfiles = manifestonly | dsnotadded
3155 changedfiles = manifestonly | dsnotadded
3156
3156
3157 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3157 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3158
3158
3159 @command('debugrebuildfncache', [], '')
3159 @command('debugrebuildfncache', [], '')
3160 def debugrebuildfncache(ui, repo):
3160 def debugrebuildfncache(ui, repo):
3161 """rebuild the fncache file"""
3161 """rebuild the fncache file"""
3162 repair.rebuildfncache(ui, repo)
3162 repair.rebuildfncache(ui, repo)
3163
3163
3164 @command('debugrename',
3164 @command('debugrename',
3165 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3165 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3166 _('[-r REV] FILE'))
3166 _('[-r REV] FILE'))
3167 def debugrename(ui, repo, file1, *pats, **opts):
3167 def debugrename(ui, repo, file1, *pats, **opts):
3168 """dump rename information"""
3168 """dump rename information"""
3169
3169
3170 ctx = scmutil.revsingle(repo, opts.get('rev'))
3170 ctx = scmutil.revsingle(repo, opts.get('rev'))
3171 m = scmutil.match(ctx, (file1,) + pats, opts)
3171 m = scmutil.match(ctx, (file1,) + pats, opts)
3172 for abs in ctx.walk(m):
3172 for abs in ctx.walk(m):
3173 fctx = ctx[abs]
3173 fctx = ctx[abs]
3174 o = fctx.filelog().renamed(fctx.filenode())
3174 o = fctx.filelog().renamed(fctx.filenode())
3175 rel = m.rel(abs)
3175 rel = m.rel(abs)
3176 if o:
3176 if o:
3177 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3177 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3178 else:
3178 else:
3179 ui.write(_("%s not renamed\n") % rel)
3179 ui.write(_("%s not renamed\n") % rel)
3180
3180
3181 @command('debugrevlog', debugrevlogopts +
3181 @command('debugrevlog', debugrevlogopts +
3182 [('d', 'dump', False, _('dump index data'))],
3182 [('d', 'dump', False, _('dump index data'))],
3183 _('-c|-m|FILE'),
3183 _('-c|-m|FILE'),
3184 optionalrepo=True)
3184 optionalrepo=True)
3185 def debugrevlog(ui, repo, file_=None, **opts):
3185 def debugrevlog(ui, repo, file_=None, **opts):
3186 """show data and statistics about a revlog"""
3186 """show data and statistics about a revlog"""
3187 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3187 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3188
3188
3189 if opts.get("dump"):
3189 if opts.get("dump"):
3190 numrevs = len(r)
3190 numrevs = len(r)
3191 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3191 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3192 " rawsize totalsize compression heads chainlen\n")
3192 " rawsize totalsize compression heads chainlen\n")
3193 ts = 0
3193 ts = 0
3194 heads = set()
3194 heads = set()
3195
3195
3196 for rev in xrange(numrevs):
3196 for rev in xrange(numrevs):
3197 dbase = r.deltaparent(rev)
3197 dbase = r.deltaparent(rev)
3198 if dbase == -1:
3198 if dbase == -1:
3199 dbase = rev
3199 dbase = rev
3200 cbase = r.chainbase(rev)
3200 cbase = r.chainbase(rev)
3201 clen = r.chainlen(rev)
3201 clen = r.chainlen(rev)
3202 p1, p2 = r.parentrevs(rev)
3202 p1, p2 = r.parentrevs(rev)
3203 rs = r.rawsize(rev)
3203 rs = r.rawsize(rev)
3204 ts = ts + rs
3204 ts = ts + rs
3205 heads -= set(r.parentrevs(rev))
3205 heads -= set(r.parentrevs(rev))
3206 heads.add(rev)
3206 heads.add(rev)
3207 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3207 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3208 "%11d %5d %8d\n" %
3208 "%11d %5d %8d\n" %
3209 (rev, p1, p2, r.start(rev), r.end(rev),
3209 (rev, p1, p2, r.start(rev), r.end(rev),
3210 r.start(dbase), r.start(cbase),
3210 r.start(dbase), r.start(cbase),
3211 r.start(p1), r.start(p2),
3211 r.start(p1), r.start(p2),
3212 rs, ts, ts / r.end(rev), len(heads), clen))
3212 rs, ts, ts / r.end(rev), len(heads), clen))
3213 return 0
3213 return 0
3214
3214
3215 v = r.version
3215 v = r.version
3216 format = v & 0xFFFF
3216 format = v & 0xFFFF
3217 flags = []
3217 flags = []
3218 gdelta = False
3218 gdelta = False
3219 if v & revlog.REVLOGNGINLINEDATA:
3219 if v & revlog.REVLOGNGINLINEDATA:
3220 flags.append('inline')
3220 flags.append('inline')
3221 if v & revlog.REVLOGGENERALDELTA:
3221 if v & revlog.REVLOGGENERALDELTA:
3222 gdelta = True
3222 gdelta = True
3223 flags.append('generaldelta')
3223 flags.append('generaldelta')
3224 if not flags:
3224 if not flags:
3225 flags = ['(none)']
3225 flags = ['(none)']
3226
3226
3227 nummerges = 0
3227 nummerges = 0
3228 numfull = 0
3228 numfull = 0
3229 numprev = 0
3229 numprev = 0
3230 nump1 = 0
3230 nump1 = 0
3231 nump2 = 0
3231 nump2 = 0
3232 numother = 0
3232 numother = 0
3233 nump1prev = 0
3233 nump1prev = 0
3234 nump2prev = 0
3234 nump2prev = 0
3235 chainlengths = []
3235 chainlengths = []
3236
3236
3237 datasize = [None, 0, 0L]
3237 datasize = [None, 0, 0L]
3238 fullsize = [None, 0, 0L]
3238 fullsize = [None, 0, 0L]
3239 deltasize = [None, 0, 0L]
3239 deltasize = [None, 0, 0L]
3240
3240
3241 def addsize(size, l):
3241 def addsize(size, l):
3242 if l[0] is None or size < l[0]:
3242 if l[0] is None or size < l[0]:
3243 l[0] = size
3243 l[0] = size
3244 if size > l[1]:
3244 if size > l[1]:
3245 l[1] = size
3245 l[1] = size
3246 l[2] += size
3246 l[2] += size
3247
3247
3248 numrevs = len(r)
3248 numrevs = len(r)
3249 for rev in xrange(numrevs):
3249 for rev in xrange(numrevs):
3250 p1, p2 = r.parentrevs(rev)
3250 p1, p2 = r.parentrevs(rev)
3251 delta = r.deltaparent(rev)
3251 delta = r.deltaparent(rev)
3252 if format > 0:
3252 if format > 0:
3253 addsize(r.rawsize(rev), datasize)
3253 addsize(r.rawsize(rev), datasize)
3254 if p2 != nullrev:
3254 if p2 != nullrev:
3255 nummerges += 1
3255 nummerges += 1
3256 size = r.length(rev)
3256 size = r.length(rev)
3257 if delta == nullrev:
3257 if delta == nullrev:
3258 chainlengths.append(0)
3258 chainlengths.append(0)
3259 numfull += 1
3259 numfull += 1
3260 addsize(size, fullsize)
3260 addsize(size, fullsize)
3261 else:
3261 else:
3262 chainlengths.append(chainlengths[delta] + 1)
3262 chainlengths.append(chainlengths[delta] + 1)
3263 addsize(size, deltasize)
3263 addsize(size, deltasize)
3264 if delta == rev - 1:
3264 if delta == rev - 1:
3265 numprev += 1
3265 numprev += 1
3266 if delta == p1:
3266 if delta == p1:
3267 nump1prev += 1
3267 nump1prev += 1
3268 elif delta == p2:
3268 elif delta == p2:
3269 nump2prev += 1
3269 nump2prev += 1
3270 elif delta == p1:
3270 elif delta == p1:
3271 nump1 += 1
3271 nump1 += 1
3272 elif delta == p2:
3272 elif delta == p2:
3273 nump2 += 1
3273 nump2 += 1
3274 elif delta != nullrev:
3274 elif delta != nullrev:
3275 numother += 1
3275 numother += 1
3276
3276
3277 # Adjust size min value for empty cases
3277 # Adjust size min value for empty cases
3278 for size in (datasize, fullsize, deltasize):
3278 for size in (datasize, fullsize, deltasize):
3279 if size[0] is None:
3279 if size[0] is None:
3280 size[0] = 0
3280 size[0] = 0
3281
3281
3282 numdeltas = numrevs - numfull
3282 numdeltas = numrevs - numfull
3283 numoprev = numprev - nump1prev - nump2prev
3283 numoprev = numprev - nump1prev - nump2prev
3284 totalrawsize = datasize[2]
3284 totalrawsize = datasize[2]
3285 datasize[2] /= numrevs
3285 datasize[2] /= numrevs
3286 fulltotal = fullsize[2]
3286 fulltotal = fullsize[2]
3287 fullsize[2] /= numfull
3287 fullsize[2] /= numfull
3288 deltatotal = deltasize[2]
3288 deltatotal = deltasize[2]
3289 if numrevs - numfull > 0:
3289 if numrevs - numfull > 0:
3290 deltasize[2] /= numrevs - numfull
3290 deltasize[2] /= numrevs - numfull
3291 totalsize = fulltotal + deltatotal
3291 totalsize = fulltotal + deltatotal
3292 avgchainlen = sum(chainlengths) / numrevs
3292 avgchainlen = sum(chainlengths) / numrevs
3293 maxchainlen = max(chainlengths)
3293 maxchainlen = max(chainlengths)
3294 compratio = 1
3294 compratio = 1
3295 if totalsize:
3295 if totalsize:
3296 compratio = totalrawsize / totalsize
3296 compratio = totalrawsize / totalsize
3297
3297
3298 basedfmtstr = '%%%dd\n'
3298 basedfmtstr = '%%%dd\n'
3299 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3299 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3300
3300
3301 def dfmtstr(max):
3301 def dfmtstr(max):
3302 return basedfmtstr % len(str(max))
3302 return basedfmtstr % len(str(max))
3303 def pcfmtstr(max, padding=0):
3303 def pcfmtstr(max, padding=0):
3304 return basepcfmtstr % (len(str(max)), ' ' * padding)
3304 return basepcfmtstr % (len(str(max)), ' ' * padding)
3305
3305
3306 def pcfmt(value, total):
3306 def pcfmt(value, total):
3307 if total:
3307 if total:
3308 return (value, 100 * float(value) / total)
3308 return (value, 100 * float(value) / total)
3309 else:
3309 else:
3310 return value, 100.0
3310 return value, 100.0
3311
3311
3312 ui.write(('format : %d\n') % format)
3312 ui.write(('format : %d\n') % format)
3313 ui.write(('flags : %s\n') % ', '.join(flags))
3313 ui.write(('flags : %s\n') % ', '.join(flags))
3314
3314
3315 ui.write('\n')
3315 ui.write('\n')
3316 fmt = pcfmtstr(totalsize)
3316 fmt = pcfmtstr(totalsize)
3317 fmt2 = dfmtstr(totalsize)
3317 fmt2 = dfmtstr(totalsize)
3318 ui.write(('revisions : ') + fmt2 % numrevs)
3318 ui.write(('revisions : ') + fmt2 % numrevs)
3319 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3319 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3320 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3320 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3321 ui.write(('revisions : ') + fmt2 % numrevs)
3321 ui.write(('revisions : ') + fmt2 % numrevs)
3322 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3322 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3323 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3323 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3324 ui.write(('revision size : ') + fmt2 % totalsize)
3324 ui.write(('revision size : ') + fmt2 % totalsize)
3325 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3325 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3326 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3326 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3327
3327
3328 ui.write('\n')
3328 ui.write('\n')
3329 fmt = dfmtstr(max(avgchainlen, compratio))
3329 fmt = dfmtstr(max(avgchainlen, compratio))
3330 ui.write(('avg chain length : ') + fmt % avgchainlen)
3330 ui.write(('avg chain length : ') + fmt % avgchainlen)
3331 ui.write(('max chain length : ') + fmt % maxchainlen)
3331 ui.write(('max chain length : ') + fmt % maxchainlen)
3332 ui.write(('compression ratio : ') + fmt % compratio)
3332 ui.write(('compression ratio : ') + fmt % compratio)
3333
3333
3334 if format > 0:
3334 if format > 0:
3335 ui.write('\n')
3335 ui.write('\n')
3336 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3336 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3337 % tuple(datasize))
3337 % tuple(datasize))
3338 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3338 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3339 % tuple(fullsize))
3339 % tuple(fullsize))
3340 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3340 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3341 % tuple(deltasize))
3341 % tuple(deltasize))
3342
3342
3343 if numdeltas > 0:
3343 if numdeltas > 0:
3344 ui.write('\n')
3344 ui.write('\n')
3345 fmt = pcfmtstr(numdeltas)
3345 fmt = pcfmtstr(numdeltas)
3346 fmt2 = pcfmtstr(numdeltas, 4)
3346 fmt2 = pcfmtstr(numdeltas, 4)
3347 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3347 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3348 if numprev > 0:
3348 if numprev > 0:
3349 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3349 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3350 numprev))
3350 numprev))
3351 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3351 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3352 numprev))
3352 numprev))
3353 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3353 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3354 numprev))
3354 numprev))
3355 if gdelta:
3355 if gdelta:
3356 ui.write(('deltas against p1 : ')
3356 ui.write(('deltas against p1 : ')
3357 + fmt % pcfmt(nump1, numdeltas))
3357 + fmt % pcfmt(nump1, numdeltas))
3358 ui.write(('deltas against p2 : ')
3358 ui.write(('deltas against p2 : ')
3359 + fmt % pcfmt(nump2, numdeltas))
3359 + fmt % pcfmt(nump2, numdeltas))
3360 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3360 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3361 numdeltas))
3361 numdeltas))
3362
3362
3363 @command('debugrevspec',
3363 @command('debugrevspec',
3364 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3364 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3365 ('REVSPEC'))
3365 ('REVSPEC'))
3366 def debugrevspec(ui, repo, expr, **opts):
3366 def debugrevspec(ui, repo, expr, **opts):
3367 """parse and apply a revision specification
3367 """parse and apply a revision specification
3368
3368
3369 Use --verbose to print the parsed tree before and after aliases
3369 Use --verbose to print the parsed tree before and after aliases
3370 expansion.
3370 expansion.
3371 """
3371 """
3372 if ui.verbose:
3372 if ui.verbose:
3373 tree = revset.parse(expr, lookup=repo.__contains__)
3373 tree = revset.parse(expr, lookup=repo.__contains__)
3374 ui.note(revset.prettyformat(tree), "\n")
3374 ui.note(revset.prettyformat(tree), "\n")
3375 newtree = revset.findaliases(ui, tree)
3375 newtree = revset.findaliases(ui, tree)
3376 if newtree != tree:
3376 if newtree != tree:
3377 ui.note(revset.prettyformat(newtree), "\n")
3377 ui.note(revset.prettyformat(newtree), "\n")
3378 tree = newtree
3378 tree = newtree
3379 newtree = revset.foldconcat(tree)
3379 newtree = revset.foldconcat(tree)
3380 if newtree != tree:
3380 if newtree != tree:
3381 ui.note(revset.prettyformat(newtree), "\n")
3381 ui.note(revset.prettyformat(newtree), "\n")
3382 if opts["optimize"]:
3382 if opts["optimize"]:
3383 weight, optimizedtree = revset.optimize(newtree, True)
3383 weight, optimizedtree = revset.optimize(newtree, True)
3384 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3384 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3385 func = revset.match(ui, expr, repo)
3385 func = revset.match(ui, expr, repo)
3386 revs = func(repo)
3386 revs = func(repo)
3387 if ui.verbose:
3387 if ui.verbose:
3388 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3388 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3389 for c in revs:
3389 for c in revs:
3390 ui.write("%s\n" % c)
3390 ui.write("%s\n" % c)
3391
3391
3392 @command('debugsetparents', [], _('REV1 [REV2]'))
3392 @command('debugsetparents', [], _('REV1 [REV2]'))
3393 def debugsetparents(ui, repo, rev1, rev2=None):
3393 def debugsetparents(ui, repo, rev1, rev2=None):
3394 """manually set the parents of the current working directory
3394 """manually set the parents of the current working directory
3395
3395
3396 This is useful for writing repository conversion tools, but should
3396 This is useful for writing repository conversion tools, but should
3397 be used with care. For example, neither the working directory nor the
3397 be used with care. For example, neither the working directory nor the
3398 dirstate is updated, so file status may be incorrect after running this
3398 dirstate is updated, so file status may be incorrect after running this
3399 command.
3399 command.
3400
3400
3401 Returns 0 on success.
3401 Returns 0 on success.
3402 """
3402 """
3403
3403
3404 r1 = scmutil.revsingle(repo, rev1).node()
3404 r1 = scmutil.revsingle(repo, rev1).node()
3405 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3405 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3406
3406
3407 with repo.wlock():
3407 with repo.wlock():
3408 repo.dirstate.beginparentchange()
3408 repo.dirstate.beginparentchange()
3409 repo.setparents(r1, r2)
3409 repo.setparents(r1, r2)
3410 repo.dirstate.endparentchange()
3410 repo.dirstate.endparentchange()
3411
3411
3412 @command('debugdirstate|debugstate',
3412 @command('debugdirstate|debugstate',
3413 [('', 'nodates', None, _('do not display the saved mtime')),
3413 [('', 'nodates', None, _('do not display the saved mtime')),
3414 ('', 'datesort', None, _('sort by saved mtime'))],
3414 ('', 'datesort', None, _('sort by saved mtime'))],
3415 _('[OPTION]...'))
3415 _('[OPTION]...'))
3416 def debugstate(ui, repo, **opts):
3416 def debugstate(ui, repo, **opts):
3417 """show the contents of the current dirstate"""
3417 """show the contents of the current dirstate"""
3418
3418
3419 nodates = opts.get('nodates')
3419 nodates = opts.get('nodates')
3420 datesort = opts.get('datesort')
3420 datesort = opts.get('datesort')
3421
3421
3422 timestr = ""
3422 timestr = ""
3423 if datesort:
3423 if datesort:
3424 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3424 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3425 else:
3425 else:
3426 keyfunc = None # sort by filename
3426 keyfunc = None # sort by filename
3427 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3427 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3428 if ent[3] == -1:
3428 if ent[3] == -1:
3429 timestr = 'unset '
3429 timestr = 'unset '
3430 elif nodates:
3430 elif nodates:
3431 timestr = 'set '
3431 timestr = 'set '
3432 else:
3432 else:
3433 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3433 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3434 time.localtime(ent[3]))
3434 time.localtime(ent[3]))
3435 if ent[1] & 0o20000:
3435 if ent[1] & 0o20000:
3436 mode = 'lnk'
3436 mode = 'lnk'
3437 else:
3437 else:
3438 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3438 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3439 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3439 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3440 for f in repo.dirstate.copies():
3440 for f in repo.dirstate.copies():
3441 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3441 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3442
3442
3443 @command('debugsub',
3443 @command('debugsub',
3444 [('r', 'rev', '',
3444 [('r', 'rev', '',
3445 _('revision to check'), _('REV'))],
3445 _('revision to check'), _('REV'))],
3446 _('[-r REV] [REV]'))
3446 _('[-r REV] [REV]'))
3447 def debugsub(ui, repo, rev=None):
3447 def debugsub(ui, repo, rev=None):
3448 ctx = scmutil.revsingle(repo, rev, None)
3448 ctx = scmutil.revsingle(repo, rev, None)
3449 for k, v in sorted(ctx.substate.items()):
3449 for k, v in sorted(ctx.substate.items()):
3450 ui.write(('path %s\n') % k)
3450 ui.write(('path %s\n') % k)
3451 ui.write((' source %s\n') % v[0])
3451 ui.write((' source %s\n') % v[0])
3452 ui.write((' revision %s\n') % v[1])
3452 ui.write((' revision %s\n') % v[1])
3453
3453
3454 @command('debugsuccessorssets',
3454 @command('debugsuccessorssets',
3455 [],
3455 [],
3456 _('[REV]'))
3456 _('[REV]'))
3457 def debugsuccessorssets(ui, repo, *revs):
3457 def debugsuccessorssets(ui, repo, *revs):
3458 """show set of successors for revision
3458 """show set of successors for revision
3459
3459
3460 A successors set of changeset A is a consistent group of revisions that
3460 A successors set of changeset A is a consistent group of revisions that
3461 succeed A. It contains non-obsolete changesets only.
3461 succeed A. It contains non-obsolete changesets only.
3462
3462
3463 In most cases a changeset A has a single successors set containing a single
3463 In most cases a changeset A has a single successors set containing a single
3464 successor (changeset A replaced by A').
3464 successor (changeset A replaced by A').
3465
3465
3466 A changeset that is made obsolete with no successors are called "pruned".
3466 A changeset that is made obsolete with no successors are called "pruned".
3467 Such changesets have no successors sets at all.
3467 Such changesets have no successors sets at all.
3468
3468
3469 A changeset that has been "split" will have a successors set containing
3469 A changeset that has been "split" will have a successors set containing
3470 more than one successor.
3470 more than one successor.
3471
3471
3472 A changeset that has been rewritten in multiple different ways is called
3472 A changeset that has been rewritten in multiple different ways is called
3473 "divergent". Such changesets have multiple successor sets (each of which
3473 "divergent". Such changesets have multiple successor sets (each of which
3474 may also be split, i.e. have multiple successors).
3474 may also be split, i.e. have multiple successors).
3475
3475
3476 Results are displayed as follows::
3476 Results are displayed as follows::
3477
3477
3478 <rev1>
3478 <rev1>
3479 <successors-1A>
3479 <successors-1A>
3480 <rev2>
3480 <rev2>
3481 <successors-2A>
3481 <successors-2A>
3482 <successors-2B1> <successors-2B2> <successors-2B3>
3482 <successors-2B1> <successors-2B2> <successors-2B3>
3483
3483
3484 Here rev2 has two possible (i.e. divergent) successors sets. The first
3484 Here rev2 has two possible (i.e. divergent) successors sets. The first
3485 holds one element, whereas the second holds three (i.e. the changeset has
3485 holds one element, whereas the second holds three (i.e. the changeset has
3486 been split).
3486 been split).
3487 """
3487 """
3488 # passed to successorssets caching computation from one call to another
3488 # passed to successorssets caching computation from one call to another
3489 cache = {}
3489 cache = {}
3490 ctx2str = str
3490 ctx2str = str
3491 node2str = short
3491 node2str = short
3492 if ui.debug():
3492 if ui.debug():
3493 def ctx2str(ctx):
3493 def ctx2str(ctx):
3494 return ctx.hex()
3494 return ctx.hex()
3495 node2str = hex
3495 node2str = hex
3496 for rev in scmutil.revrange(repo, revs):
3496 for rev in scmutil.revrange(repo, revs):
3497 ctx = repo[rev]
3497 ctx = repo[rev]
3498 ui.write('%s\n'% ctx2str(ctx))
3498 ui.write('%s\n'% ctx2str(ctx))
3499 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3499 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3500 if succsset:
3500 if succsset:
3501 ui.write(' ')
3501 ui.write(' ')
3502 ui.write(node2str(succsset[0]))
3502 ui.write(node2str(succsset[0]))
3503 for node in succsset[1:]:
3503 for node in succsset[1:]:
3504 ui.write(' ')
3504 ui.write(' ')
3505 ui.write(node2str(node))
3505 ui.write(node2str(node))
3506 ui.write('\n')
3506 ui.write('\n')
3507
3507
3508 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3508 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3509 def debugwalk(ui, repo, *pats, **opts):
3509 def debugwalk(ui, repo, *pats, **opts):
3510 """show how files match on given patterns"""
3510 """show how files match on given patterns"""
3511 m = scmutil.match(repo[None], pats, opts)
3511 m = scmutil.match(repo[None], pats, opts)
3512 items = list(repo.walk(m))
3512 items = list(repo.walk(m))
3513 if not items:
3513 if not items:
3514 return
3514 return
3515 f = lambda fn: fn
3515 f = lambda fn: fn
3516 if ui.configbool('ui', 'slash') and os.sep != '/':
3516 if ui.configbool('ui', 'slash') and os.sep != '/':
3517 f = lambda fn: util.normpath(fn)
3517 f = lambda fn: util.normpath(fn)
3518 fmt = 'f %%-%ds %%-%ds %%s' % (
3518 fmt = 'f %%-%ds %%-%ds %%s' % (
3519 max([len(abs) for abs in items]),
3519 max([len(abs) for abs in items]),
3520 max([len(m.rel(abs)) for abs in items]))
3520 max([len(m.rel(abs)) for abs in items]))
3521 for abs in items:
3521 for abs in items:
3522 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3522 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3523 ui.write("%s\n" % line.rstrip())
3523 ui.write("%s\n" % line.rstrip())
3524
3524
3525 @command('debugwireargs',
3525 @command('debugwireargs',
3526 [('', 'three', '', 'three'),
3526 [('', 'three', '', 'three'),
3527 ('', 'four', '', 'four'),
3527 ('', 'four', '', 'four'),
3528 ('', 'five', '', 'five'),
3528 ('', 'five', '', 'five'),
3529 ] + remoteopts,
3529 ] + remoteopts,
3530 _('REPO [OPTIONS]... [ONE [TWO]]'),
3530 _('REPO [OPTIONS]... [ONE [TWO]]'),
3531 norepo=True)
3531 norepo=True)
3532 def debugwireargs(ui, repopath, *vals, **opts):
3532 def debugwireargs(ui, repopath, *vals, **opts):
3533 repo = hg.peer(ui, opts, repopath)
3533 repo = hg.peer(ui, opts, repopath)
3534 for opt in remoteopts:
3534 for opt in remoteopts:
3535 del opts[opt[1]]
3535 del opts[opt[1]]
3536 args = {}
3536 args = {}
3537 for k, v in opts.iteritems():
3537 for k, v in opts.iteritems():
3538 if v:
3538 if v:
3539 args[k] = v
3539 args[k] = v
3540 # run twice to check that we don't mess up the stream for the next command
3540 # run twice to check that we don't mess up the stream for the next command
3541 res1 = repo.debugwireargs(*vals, **args)
3541 res1 = repo.debugwireargs(*vals, **args)
3542 res2 = repo.debugwireargs(*vals, **args)
3542 res2 = repo.debugwireargs(*vals, **args)
3543 ui.write("%s\n" % res1)
3543 ui.write("%s\n" % res1)
3544 if res1 != res2:
3544 if res1 != res2:
3545 ui.warn("%s\n" % res2)
3545 ui.warn("%s\n" % res2)
3546
3546
3547 @command('^diff',
3547 @command('^diff',
3548 [('r', 'rev', [], _('revision'), _('REV')),
3548 [('r', 'rev', [], _('revision'), _('REV')),
3549 ('c', 'change', '', _('change made by revision'), _('REV'))
3549 ('c', 'change', '', _('change made by revision'), _('REV'))
3550 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3550 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3551 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3551 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3552 inferrepo=True)
3552 inferrepo=True)
3553 def diff(ui, repo, *pats, **opts):
3553 def diff(ui, repo, *pats, **opts):
3554 """diff repository (or selected files)
3554 """diff repository (or selected files)
3555
3555
3556 Show differences between revisions for the specified files.
3556 Show differences between revisions for the specified files.
3557
3557
3558 Differences between files are shown using the unified diff format.
3558 Differences between files are shown using the unified diff format.
3559
3559
3560 .. note::
3560 .. note::
3561
3561
3562 :hg:`diff` may generate unexpected results for merges, as it will
3562 :hg:`diff` may generate unexpected results for merges, as it will
3563 default to comparing against the working directory's first
3563 default to comparing against the working directory's first
3564 parent changeset if no revisions are specified.
3564 parent changeset if no revisions are specified.
3565
3565
3566 When two revision arguments are given, then changes are shown
3566 When two revision arguments are given, then changes are shown
3567 between those revisions. If only one revision is specified then
3567 between those revisions. If only one revision is specified then
3568 that revision is compared to the working directory, and, when no
3568 that revision is compared to the working directory, and, when no
3569 revisions are specified, the working directory files are compared
3569 revisions are specified, the working directory files are compared
3570 to its first parent.
3570 to its first parent.
3571
3571
3572 Alternatively you can specify -c/--change with a revision to see
3572 Alternatively you can specify -c/--change with a revision to see
3573 the changes in that changeset relative to its first parent.
3573 the changes in that changeset relative to its first parent.
3574
3574
3575 Without the -a/--text option, diff will avoid generating diffs of
3575 Without the -a/--text option, diff will avoid generating diffs of
3576 files it detects as binary. With -a, diff will generate a diff
3576 files it detects as binary. With -a, diff will generate a diff
3577 anyway, probably with undesirable results.
3577 anyway, probably with undesirable results.
3578
3578
3579 Use the -g/--git option to generate diffs in the git extended diff
3579 Use the -g/--git option to generate diffs in the git extended diff
3580 format. For more information, read :hg:`help diffs`.
3580 format. For more information, read :hg:`help diffs`.
3581
3581
3582 .. container:: verbose
3582 .. container:: verbose
3583
3583
3584 Examples:
3584 Examples:
3585
3585
3586 - compare a file in the current working directory to its parent::
3586 - compare a file in the current working directory to its parent::
3587
3587
3588 hg diff foo.c
3588 hg diff foo.c
3589
3589
3590 - compare two historical versions of a directory, with rename info::
3590 - compare two historical versions of a directory, with rename info::
3591
3591
3592 hg diff --git -r 1.0:1.2 lib/
3592 hg diff --git -r 1.0:1.2 lib/
3593
3593
3594 - get change stats relative to the last change on some date::
3594 - get change stats relative to the last change on some date::
3595
3595
3596 hg diff --stat -r "date('may 2')"
3596 hg diff --stat -r "date('may 2')"
3597
3597
3598 - diff all newly-added files that contain a keyword::
3598 - diff all newly-added files that contain a keyword::
3599
3599
3600 hg diff "set:added() and grep(GNU)"
3600 hg diff "set:added() and grep(GNU)"
3601
3601
3602 - compare a revision and its parents::
3602 - compare a revision and its parents::
3603
3603
3604 hg diff -c 9353 # compare against first parent
3604 hg diff -c 9353 # compare against first parent
3605 hg diff -r 9353^:9353 # same using revset syntax
3605 hg diff -r 9353^:9353 # same using revset syntax
3606 hg diff -r 9353^2:9353 # compare against the second parent
3606 hg diff -r 9353^2:9353 # compare against the second parent
3607
3607
3608 Returns 0 on success.
3608 Returns 0 on success.
3609 """
3609 """
3610
3610
3611 revs = opts.get('rev')
3611 revs = opts.get('rev')
3612 change = opts.get('change')
3612 change = opts.get('change')
3613 stat = opts.get('stat')
3613 stat = opts.get('stat')
3614 reverse = opts.get('reverse')
3614 reverse = opts.get('reverse')
3615
3615
3616 if revs and change:
3616 if revs and change:
3617 msg = _('cannot specify --rev and --change at the same time')
3617 msg = _('cannot specify --rev and --change at the same time')
3618 raise error.Abort(msg)
3618 raise error.Abort(msg)
3619 elif change:
3619 elif change:
3620 node2 = scmutil.revsingle(repo, change, None).node()
3620 node2 = scmutil.revsingle(repo, change, None).node()
3621 node1 = repo[node2].p1().node()
3621 node1 = repo[node2].p1().node()
3622 else:
3622 else:
3623 node1, node2 = scmutil.revpair(repo, revs)
3623 node1, node2 = scmutil.revpair(repo, revs)
3624
3624
3625 if reverse:
3625 if reverse:
3626 node1, node2 = node2, node1
3626 node1, node2 = node2, node1
3627
3627
3628 diffopts = patch.diffallopts(ui, opts)
3628 diffopts = patch.diffallopts(ui, opts)
3629 m = scmutil.match(repo[node2], pats, opts)
3629 m = scmutil.match(repo[node2], pats, opts)
3630 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3630 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3631 listsubrepos=opts.get('subrepos'),
3631 listsubrepos=opts.get('subrepos'),
3632 root=opts.get('root'))
3632 root=opts.get('root'))
3633
3633
3634 @command('^export',
3634 @command('^export',
3635 [('o', 'output', '',
3635 [('o', 'output', '',
3636 _('print output to file with formatted name'), _('FORMAT')),
3636 _('print output to file with formatted name'), _('FORMAT')),
3637 ('', 'switch-parent', None, _('diff against the second parent')),
3637 ('', 'switch-parent', None, _('diff against the second parent')),
3638 ('r', 'rev', [], _('revisions to export'), _('REV')),
3638 ('r', 'rev', [], _('revisions to export'), _('REV')),
3639 ] + diffopts,
3639 ] + diffopts,
3640 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3640 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3641 def export(ui, repo, *changesets, **opts):
3641 def export(ui, repo, *changesets, **opts):
3642 """dump the header and diffs for one or more changesets
3642 """dump the header and diffs for one or more changesets
3643
3643
3644 Print the changeset header and diffs for one or more revisions.
3644 Print the changeset header and diffs for one or more revisions.
3645 If no revision is given, the parent of the working directory is used.
3645 If no revision is given, the parent of the working directory is used.
3646
3646
3647 The information shown in the changeset header is: author, date,
3647 The information shown in the changeset header is: author, date,
3648 branch name (if non-default), changeset hash, parent(s) and commit
3648 branch name (if non-default), changeset hash, parent(s) and commit
3649 comment.
3649 comment.
3650
3650
3651 .. note::
3651 .. note::
3652
3652
3653 :hg:`export` may generate unexpected diff output for merge
3653 :hg:`export` may generate unexpected diff output for merge
3654 changesets, as it will compare the merge changeset against its
3654 changesets, as it will compare the merge changeset against its
3655 first parent only.
3655 first parent only.
3656
3656
3657 Output may be to a file, in which case the name of the file is
3657 Output may be to a file, in which case the name of the file is
3658 given using a format string. The formatting rules are as follows:
3658 given using a format string. The formatting rules are as follows:
3659
3659
3660 :``%%``: literal "%" character
3660 :``%%``: literal "%" character
3661 :``%H``: changeset hash (40 hexadecimal digits)
3661 :``%H``: changeset hash (40 hexadecimal digits)
3662 :``%N``: number of patches being generated
3662 :``%N``: number of patches being generated
3663 :``%R``: changeset revision number
3663 :``%R``: changeset revision number
3664 :``%b``: basename of the exporting repository
3664 :``%b``: basename of the exporting repository
3665 :``%h``: short-form changeset hash (12 hexadecimal digits)
3665 :``%h``: short-form changeset hash (12 hexadecimal digits)
3666 :``%m``: first line of the commit message (only alphanumeric characters)
3666 :``%m``: first line of the commit message (only alphanumeric characters)
3667 :``%n``: zero-padded sequence number, starting at 1
3667 :``%n``: zero-padded sequence number, starting at 1
3668 :``%r``: zero-padded changeset revision number
3668 :``%r``: zero-padded changeset revision number
3669
3669
3670 Without the -a/--text option, export will avoid generating diffs
3670 Without the -a/--text option, export will avoid generating diffs
3671 of files it detects as binary. With -a, export will generate a
3671 of files it detects as binary. With -a, export will generate a
3672 diff anyway, probably with undesirable results.
3672 diff anyway, probably with undesirable results.
3673
3673
3674 Use the -g/--git option to generate diffs in the git extended diff
3674 Use the -g/--git option to generate diffs in the git extended diff
3675 format. See :hg:`help diffs` for more information.
3675 format. See :hg:`help diffs` for more information.
3676
3676
3677 With the --switch-parent option, the diff will be against the
3677 With the --switch-parent option, the diff will be against the
3678 second parent. It can be useful to review a merge.
3678 second parent. It can be useful to review a merge.
3679
3679
3680 .. container:: verbose
3680 .. container:: verbose
3681
3681
3682 Examples:
3682 Examples:
3683
3683
3684 - use export and import to transplant a bugfix to the current
3684 - use export and import to transplant a bugfix to the current
3685 branch::
3685 branch::
3686
3686
3687 hg export -r 9353 | hg import -
3687 hg export -r 9353 | hg import -
3688
3688
3689 - export all the changesets between two revisions to a file with
3689 - export all the changesets between two revisions to a file with
3690 rename information::
3690 rename information::
3691
3691
3692 hg export --git -r 123:150 > changes.txt
3692 hg export --git -r 123:150 > changes.txt
3693
3693
3694 - split outgoing changes into a series of patches with
3694 - split outgoing changes into a series of patches with
3695 descriptive names::
3695 descriptive names::
3696
3696
3697 hg export -r "outgoing()" -o "%n-%m.patch"
3697 hg export -r "outgoing()" -o "%n-%m.patch"
3698
3698
3699 Returns 0 on success.
3699 Returns 0 on success.
3700 """
3700 """
3701 changesets += tuple(opts.get('rev', []))
3701 changesets += tuple(opts.get('rev', []))
3702 if not changesets:
3702 if not changesets:
3703 changesets = ['.']
3703 changesets = ['.']
3704 revs = scmutil.revrange(repo, changesets)
3704 revs = scmutil.revrange(repo, changesets)
3705 if not revs:
3705 if not revs:
3706 raise error.Abort(_("export requires at least one changeset"))
3706 raise error.Abort(_("export requires at least one changeset"))
3707 if len(revs) > 1:
3707 if len(revs) > 1:
3708 ui.note(_('exporting patches:\n'))
3708 ui.note(_('exporting patches:\n'))
3709 else:
3709 else:
3710 ui.note(_('exporting patch:\n'))
3710 ui.note(_('exporting patch:\n'))
3711 cmdutil.export(repo, revs, template=opts.get('output'),
3711 cmdutil.export(repo, revs, template=opts.get('output'),
3712 switch_parent=opts.get('switch_parent'),
3712 switch_parent=opts.get('switch_parent'),
3713 opts=patch.diffallopts(ui, opts))
3713 opts=patch.diffallopts(ui, opts))
3714
3714
3715 @command('files',
3715 @command('files',
3716 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3716 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3717 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3717 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3718 ] + walkopts + formatteropts + subrepoopts,
3718 ] + walkopts + formatteropts + subrepoopts,
3719 _('[OPTION]... [PATTERN]...'))
3719 _('[OPTION]... [PATTERN]...'))
3720 def files(ui, repo, *pats, **opts):
3720 def files(ui, repo, *pats, **opts):
3721 """list tracked files
3721 """list tracked files
3722
3722
3723 Print files under Mercurial control in the working directory or
3723 Print files under Mercurial control in the working directory or
3724 specified revision whose names match the given patterns (excluding
3724 specified revision whose names match the given patterns (excluding
3725 removed files).
3725 removed files).
3726
3726
3727 If no patterns are given to match, this command prints the names
3727 If no patterns are given to match, this command prints the names
3728 of all files under Mercurial control in the working directory.
3728 of all files under Mercurial control in the working directory.
3729
3729
3730 .. container:: verbose
3730 .. container:: verbose
3731
3731
3732 Examples:
3732 Examples:
3733
3733
3734 - list all files under the current directory::
3734 - list all files under the current directory::
3735
3735
3736 hg files .
3736 hg files .
3737
3737
3738 - shows sizes and flags for current revision::
3738 - shows sizes and flags for current revision::
3739
3739
3740 hg files -vr .
3740 hg files -vr .
3741
3741
3742 - list all files named README::
3742 - list all files named README::
3743
3743
3744 hg files -I "**/README"
3744 hg files -I "**/README"
3745
3745
3746 - list all binary files::
3746 - list all binary files::
3747
3747
3748 hg files "set:binary()"
3748 hg files "set:binary()"
3749
3749
3750 - find files containing a regular expression::
3750 - find files containing a regular expression::
3751
3751
3752 hg files "set:grep('bob')"
3752 hg files "set:grep('bob')"
3753
3753
3754 - search tracked file contents with xargs and grep::
3754 - search tracked file contents with xargs and grep::
3755
3755
3756 hg files -0 | xargs -0 grep foo
3756 hg files -0 | xargs -0 grep foo
3757
3757
3758 See :hg:`help patterns` and :hg:`help filesets` for more information
3758 See :hg:`help patterns` and :hg:`help filesets` for more information
3759 on specifying file patterns.
3759 on specifying file patterns.
3760
3760
3761 Returns 0 if a match is found, 1 otherwise.
3761 Returns 0 if a match is found, 1 otherwise.
3762
3762
3763 """
3763 """
3764 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3764 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3765
3765
3766 end = '\n'
3766 end = '\n'
3767 if opts.get('print0'):
3767 if opts.get('print0'):
3768 end = '\0'
3768 end = '\0'
3769 fm = ui.formatter('files', opts)
3769 fm = ui.formatter('files', opts)
3770 fmt = '%s' + end
3770 fmt = '%s' + end
3771
3771
3772 m = scmutil.match(ctx, pats, opts)
3772 m = scmutil.match(ctx, pats, opts)
3773 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3773 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3774
3774
3775 fm.end()
3775 fm.end()
3776
3776
3777 return ret
3777 return ret
3778
3778
3779 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3779 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3780 def forget(ui, repo, *pats, **opts):
3780 def forget(ui, repo, *pats, **opts):
3781 """forget the specified files on the next commit
3781 """forget the specified files on the next commit
3782
3782
3783 Mark the specified files so they will no longer be tracked
3783 Mark the specified files so they will no longer be tracked
3784 after the next commit.
3784 after the next commit.
3785
3785
3786 This only removes files from the current branch, not from the
3786 This only removes files from the current branch, not from the
3787 entire project history, and it does not delete them from the
3787 entire project history, and it does not delete them from the
3788 working directory.
3788 working directory.
3789
3789
3790 To delete the file from the working directory, see :hg:`remove`.
3790 To delete the file from the working directory, see :hg:`remove`.
3791
3791
3792 To undo a forget before the next commit, see :hg:`add`.
3792 To undo a forget before the next commit, see :hg:`add`.
3793
3793
3794 .. container:: verbose
3794 .. container:: verbose
3795
3795
3796 Examples:
3796 Examples:
3797
3797
3798 - forget newly-added binary files::
3798 - forget newly-added binary files::
3799
3799
3800 hg forget "set:added() and binary()"
3800 hg forget "set:added() and binary()"
3801
3801
3802 - forget files that would be excluded by .hgignore::
3802 - forget files that would be excluded by .hgignore::
3803
3803
3804 hg forget "set:hgignore()"
3804 hg forget "set:hgignore()"
3805
3805
3806 Returns 0 on success.
3806 Returns 0 on success.
3807 """
3807 """
3808
3808
3809 if not pats:
3809 if not pats:
3810 raise error.Abort(_('no files specified'))
3810 raise error.Abort(_('no files specified'))
3811
3811
3812 m = scmutil.match(repo[None], pats, opts)
3812 m = scmutil.match(repo[None], pats, opts)
3813 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3813 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3814 return rejected and 1 or 0
3814 return rejected and 1 or 0
3815
3815
3816 @command(
3816 @command(
3817 'graft',
3817 'graft',
3818 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3818 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3819 ('c', 'continue', False, _('resume interrupted graft')),
3819 ('c', 'continue', False, _('resume interrupted graft')),
3820 ('e', 'edit', False, _('invoke editor on commit messages')),
3820 ('e', 'edit', False, _('invoke editor on commit messages')),
3821 ('', 'log', None, _('append graft info to log message')),
3821 ('', 'log', None, _('append graft info to log message')),
3822 ('f', 'force', False, _('force graft')),
3822 ('f', 'force', False, _('force graft')),
3823 ('D', 'currentdate', False,
3823 ('D', 'currentdate', False,
3824 _('record the current date as commit date')),
3824 _('record the current date as commit date')),
3825 ('U', 'currentuser', False,
3825 ('U', 'currentuser', False,
3826 _('record the current user as committer'), _('DATE'))]
3826 _('record the current user as committer'), _('DATE'))]
3827 + commitopts2 + mergetoolopts + dryrunopts,
3827 + commitopts2 + mergetoolopts + dryrunopts,
3828 _('[OPTION]... [-r REV]... REV...'))
3828 _('[OPTION]... [-r REV]... REV...'))
3829 def graft(ui, repo, *revs, **opts):
3829 def graft(ui, repo, *revs, **opts):
3830 '''copy changes from other branches onto the current branch
3830 '''copy changes from other branches onto the current branch
3831
3831
3832 This command uses Mercurial's merge logic to copy individual
3832 This command uses Mercurial's merge logic to copy individual
3833 changes from other branches without merging branches in the
3833 changes from other branches without merging branches in the
3834 history graph. This is sometimes known as 'backporting' or
3834 history graph. This is sometimes known as 'backporting' or
3835 'cherry-picking'. By default, graft will copy user, date, and
3835 'cherry-picking'. By default, graft will copy user, date, and
3836 description from the source changesets.
3836 description from the source changesets.
3837
3837
3838 Changesets that are ancestors of the current revision, that have
3838 Changesets that are ancestors of the current revision, that have
3839 already been grafted, or that are merges will be skipped.
3839 already been grafted, or that are merges will be skipped.
3840
3840
3841 If --log is specified, log messages will have a comment appended
3841 If --log is specified, log messages will have a comment appended
3842 of the form::
3842 of the form::
3843
3843
3844 (grafted from CHANGESETHASH)
3844 (grafted from CHANGESETHASH)
3845
3845
3846 If --force is specified, revisions will be grafted even if they
3846 If --force is specified, revisions will be grafted even if they
3847 are already ancestors of or have been grafted to the destination.
3847 are already ancestors of or have been grafted to the destination.
3848 This is useful when the revisions have since been backed out.
3848 This is useful when the revisions have since been backed out.
3849
3849
3850 If a graft merge results in conflicts, the graft process is
3850 If a graft merge results in conflicts, the graft process is
3851 interrupted so that the current merge can be manually resolved.
3851 interrupted so that the current merge can be manually resolved.
3852 Once all conflicts are addressed, the graft process can be
3852 Once all conflicts are addressed, the graft process can be
3853 continued with the -c/--continue option.
3853 continued with the -c/--continue option.
3854
3854
3855 .. note::
3855 .. note::
3856
3856
3857 The -c/--continue option does not reapply earlier options, except
3857 The -c/--continue option does not reapply earlier options, except
3858 for --force.
3858 for --force.
3859
3859
3860 .. container:: verbose
3860 .. container:: verbose
3861
3861
3862 Examples:
3862 Examples:
3863
3863
3864 - copy a single change to the stable branch and edit its description::
3864 - copy a single change to the stable branch and edit its description::
3865
3865
3866 hg update stable
3866 hg update stable
3867 hg graft --edit 9393
3867 hg graft --edit 9393
3868
3868
3869 - graft a range of changesets with one exception, updating dates::
3869 - graft a range of changesets with one exception, updating dates::
3870
3870
3871 hg graft -D "2085::2093 and not 2091"
3871 hg graft -D "2085::2093 and not 2091"
3872
3872
3873 - continue a graft after resolving conflicts::
3873 - continue a graft after resolving conflicts::
3874
3874
3875 hg graft -c
3875 hg graft -c
3876
3876
3877 - show the source of a grafted changeset::
3877 - show the source of a grafted changeset::
3878
3878
3879 hg log --debug -r .
3879 hg log --debug -r .
3880
3880
3881 - show revisions sorted by date::
3881 - show revisions sorted by date::
3882
3882
3883 hg log -r 'sort(all(), date)'
3883 hg log -r 'sort(all(), date)'
3884
3884
3885 See :hg:`help revisions` and :hg:`help revsets` for more about
3885 See :hg:`help revisions` and :hg:`help revsets` for more about
3886 specifying revisions.
3886 specifying revisions.
3887
3887
3888 Returns 0 on successful completion.
3888 Returns 0 on successful completion.
3889 '''
3889 '''
3890 with repo.wlock():
3890 with repo.wlock():
3891 return _dograft(ui, repo, *revs, **opts)
3891 return _dograft(ui, repo, *revs, **opts)
3892
3892
3893 def _dograft(ui, repo, *revs, **opts):
3893 def _dograft(ui, repo, *revs, **opts):
3894 if revs and opts['rev']:
3894 if revs and opts['rev']:
3895 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3895 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
3896 'revision ordering!\n'))
3896 'revision ordering!\n'))
3897
3897
3898 revs = list(revs)
3898 revs = list(revs)
3899 revs.extend(opts['rev'])
3899 revs.extend(opts['rev'])
3900
3900
3901 if not opts.get('user') and opts.get('currentuser'):
3901 if not opts.get('user') and opts.get('currentuser'):
3902 opts['user'] = ui.username()
3902 opts['user'] = ui.username()
3903 if not opts.get('date') and opts.get('currentdate'):
3903 if not opts.get('date') and opts.get('currentdate'):
3904 opts['date'] = "%d %d" % util.makedate()
3904 opts['date'] = "%d %d" % util.makedate()
3905
3905
3906 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3906 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3907
3907
3908 cont = False
3908 cont = False
3909 if opts['continue']:
3909 if opts['continue']:
3910 cont = True
3910 cont = True
3911 if revs:
3911 if revs:
3912 raise error.Abort(_("can't specify --continue and revisions"))
3912 raise error.Abort(_("can't specify --continue and revisions"))
3913 # read in unfinished revisions
3913 # read in unfinished revisions
3914 try:
3914 try:
3915 nodes = repo.vfs.read('graftstate').splitlines()
3915 nodes = repo.vfs.read('graftstate').splitlines()
3916 revs = [repo[node].rev() for node in nodes]
3916 revs = [repo[node].rev() for node in nodes]
3917 except IOError as inst:
3917 except IOError as inst:
3918 if inst.errno != errno.ENOENT:
3918 if inst.errno != errno.ENOENT:
3919 raise
3919 raise
3920 raise error.Abort(_("no graft state found, can't continue"))
3920 raise error.Abort(_("no graft state found, can't continue"))
3921 else:
3921 else:
3922 cmdutil.checkunfinished(repo)
3922 cmdutil.checkunfinished(repo)
3923 cmdutil.bailifchanged(repo)
3923 cmdutil.bailifchanged(repo)
3924 if not revs:
3924 if not revs:
3925 raise error.Abort(_('no revisions specified'))
3925 raise error.Abort(_('no revisions specified'))
3926 revs = scmutil.revrange(repo, revs)
3926 revs = scmutil.revrange(repo, revs)
3927
3927
3928 skipped = set()
3928 skipped = set()
3929 # check for merges
3929 # check for merges
3930 for rev in repo.revs('%ld and merge()', revs):
3930 for rev in repo.revs('%ld and merge()', revs):
3931 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3931 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3932 skipped.add(rev)
3932 skipped.add(rev)
3933 revs = [r for r in revs if r not in skipped]
3933 revs = [r for r in revs if r not in skipped]
3934 if not revs:
3934 if not revs:
3935 return -1
3935 return -1
3936
3936
3937 # Don't check in the --continue case, in effect retaining --force across
3937 # Don't check in the --continue case, in effect retaining --force across
3938 # --continues. That's because without --force, any revisions we decided to
3938 # --continues. That's because without --force, any revisions we decided to
3939 # skip would have been filtered out here, so they wouldn't have made their
3939 # skip would have been filtered out here, so they wouldn't have made their
3940 # way to the graftstate. With --force, any revisions we would have otherwise
3940 # way to the graftstate. With --force, any revisions we would have otherwise
3941 # skipped would not have been filtered out, and if they hadn't been applied
3941 # skipped would not have been filtered out, and if they hadn't been applied
3942 # already, they'd have been in the graftstate.
3942 # already, they'd have been in the graftstate.
3943 if not (cont or opts.get('force')):
3943 if not (cont or opts.get('force')):
3944 # check for ancestors of dest branch
3944 # check for ancestors of dest branch
3945 crev = repo['.'].rev()
3945 crev = repo['.'].rev()
3946 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3946 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3947 # Cannot use x.remove(y) on smart set, this has to be a list.
3947 # Cannot use x.remove(y) on smart set, this has to be a list.
3948 # XXX make this lazy in the future
3948 # XXX make this lazy in the future
3949 revs = list(revs)
3949 revs = list(revs)
3950 # don't mutate while iterating, create a copy
3950 # don't mutate while iterating, create a copy
3951 for rev in list(revs):
3951 for rev in list(revs):
3952 if rev in ancestors:
3952 if rev in ancestors:
3953 ui.warn(_('skipping ancestor revision %d:%s\n') %
3953 ui.warn(_('skipping ancestor revision %d:%s\n') %
3954 (rev, repo[rev]))
3954 (rev, repo[rev]))
3955 # XXX remove on list is slow
3955 # XXX remove on list is slow
3956 revs.remove(rev)
3956 revs.remove(rev)
3957 if not revs:
3957 if not revs:
3958 return -1
3958 return -1
3959
3959
3960 # analyze revs for earlier grafts
3960 # analyze revs for earlier grafts
3961 ids = {}
3961 ids = {}
3962 for ctx in repo.set("%ld", revs):
3962 for ctx in repo.set("%ld", revs):
3963 ids[ctx.hex()] = ctx.rev()
3963 ids[ctx.hex()] = ctx.rev()
3964 n = ctx.extra().get('source')
3964 n = ctx.extra().get('source')
3965 if n:
3965 if n:
3966 ids[n] = ctx.rev()
3966 ids[n] = ctx.rev()
3967
3967
3968 # check ancestors for earlier grafts
3968 # check ancestors for earlier grafts
3969 ui.debug('scanning for duplicate grafts\n')
3969 ui.debug('scanning for duplicate grafts\n')
3970
3970
3971 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3971 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3972 ctx = repo[rev]
3972 ctx = repo[rev]
3973 n = ctx.extra().get('source')
3973 n = ctx.extra().get('source')
3974 if n in ids:
3974 if n in ids:
3975 try:
3975 try:
3976 r = repo[n].rev()
3976 r = repo[n].rev()
3977 except error.RepoLookupError:
3977 except error.RepoLookupError:
3978 r = None
3978 r = None
3979 if r in revs:
3979 if r in revs:
3980 ui.warn(_('skipping revision %d:%s '
3980 ui.warn(_('skipping revision %d:%s '
3981 '(already grafted to %d:%s)\n')
3981 '(already grafted to %d:%s)\n')
3982 % (r, repo[r], rev, ctx))
3982 % (r, repo[r], rev, ctx))
3983 revs.remove(r)
3983 revs.remove(r)
3984 elif ids[n] in revs:
3984 elif ids[n] in revs:
3985 if r is None:
3985 if r is None:
3986 ui.warn(_('skipping already grafted revision %d:%s '
3986 ui.warn(_('skipping already grafted revision %d:%s '
3987 '(%d:%s also has unknown origin %s)\n')
3987 '(%d:%s also has unknown origin %s)\n')
3988 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3988 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3989 else:
3989 else:
3990 ui.warn(_('skipping already grafted revision %d:%s '
3990 ui.warn(_('skipping already grafted revision %d:%s '
3991 '(%d:%s also has origin %d:%s)\n')
3991 '(%d:%s also has origin %d:%s)\n')
3992 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3992 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3993 revs.remove(ids[n])
3993 revs.remove(ids[n])
3994 elif ctx.hex() in ids:
3994 elif ctx.hex() in ids:
3995 r = ids[ctx.hex()]
3995 r = ids[ctx.hex()]
3996 ui.warn(_('skipping already grafted revision %d:%s '
3996 ui.warn(_('skipping already grafted revision %d:%s '
3997 '(was grafted from %d:%s)\n') %
3997 '(was grafted from %d:%s)\n') %
3998 (r, repo[r], rev, ctx))
3998 (r, repo[r], rev, ctx))
3999 revs.remove(r)
3999 revs.remove(r)
4000 if not revs:
4000 if not revs:
4001 return -1
4001 return -1
4002
4002
4003 for pos, ctx in enumerate(repo.set("%ld", revs)):
4003 for pos, ctx in enumerate(repo.set("%ld", revs)):
4004 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4004 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4005 ctx.description().split('\n', 1)[0])
4005 ctx.description().split('\n', 1)[0])
4006 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4006 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4007 if names:
4007 if names:
4008 desc += ' (%s)' % ' '.join(names)
4008 desc += ' (%s)' % ' '.join(names)
4009 ui.status(_('grafting %s\n') % desc)
4009 ui.status(_('grafting %s\n') % desc)
4010 if opts.get('dry_run'):
4010 if opts.get('dry_run'):
4011 continue
4011 continue
4012
4012
4013 source = ctx.extra().get('source')
4013 source = ctx.extra().get('source')
4014 extra = {}
4014 extra = {}
4015 if source:
4015 if source:
4016 extra['source'] = source
4016 extra['source'] = source
4017 extra['intermediate-source'] = ctx.hex()
4017 extra['intermediate-source'] = ctx.hex()
4018 else:
4018 else:
4019 extra['source'] = ctx.hex()
4019 extra['source'] = ctx.hex()
4020 user = ctx.user()
4020 user = ctx.user()
4021 if opts.get('user'):
4021 if opts.get('user'):
4022 user = opts['user']
4022 user = opts['user']
4023 date = ctx.date()
4023 date = ctx.date()
4024 if opts.get('date'):
4024 if opts.get('date'):
4025 date = opts['date']
4025 date = opts['date']
4026 message = ctx.description()
4026 message = ctx.description()
4027 if opts.get('log'):
4027 if opts.get('log'):
4028 message += '\n(grafted from %s)' % ctx.hex()
4028 message += '\n(grafted from %s)' % ctx.hex()
4029
4029
4030 # we don't merge the first commit when continuing
4030 # we don't merge the first commit when continuing
4031 if not cont:
4031 if not cont:
4032 # perform the graft merge with p1(rev) as 'ancestor'
4032 # perform the graft merge with p1(rev) as 'ancestor'
4033 try:
4033 try:
4034 # ui.forcemerge is an internal variable, do not document
4034 # ui.forcemerge is an internal variable, do not document
4035 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4035 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4036 'graft')
4036 'graft')
4037 stats = mergemod.graft(repo, ctx, ctx.p1(),
4037 stats = mergemod.graft(repo, ctx, ctx.p1(),
4038 ['local', 'graft'])
4038 ['local', 'graft'])
4039 finally:
4039 finally:
4040 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4040 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4041 # report any conflicts
4041 # report any conflicts
4042 if stats and stats[3] > 0:
4042 if stats and stats[3] > 0:
4043 # write out state for --continue
4043 # write out state for --continue
4044 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4044 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4045 repo.vfs.write('graftstate', ''.join(nodelines))
4045 repo.vfs.write('graftstate', ''.join(nodelines))
4046 extra = ''
4046 extra = ''
4047 if opts.get('user'):
4047 if opts.get('user'):
4048 extra += ' --user %s' % opts['user']
4048 extra += ' --user %s' % opts['user']
4049 if opts.get('date'):
4049 if opts.get('date'):
4050 extra += ' --date %s' % opts['date']
4050 extra += ' --date %s' % opts['date']
4051 if opts.get('log'):
4051 if opts.get('log'):
4052 extra += ' --log'
4052 extra += ' --log'
4053 hint=_('use hg resolve and hg graft --continue%s') % extra
4053 hint=_('use hg resolve and hg graft --continue%s') % extra
4054 raise error.Abort(
4054 raise error.Abort(
4055 _("unresolved conflicts, can't continue"),
4055 _("unresolved conflicts, can't continue"),
4056 hint=hint)
4056 hint=hint)
4057 else:
4057 else:
4058 cont = False
4058 cont = False
4059
4059
4060 # commit
4060 # commit
4061 node = repo.commit(text=message, user=user,
4061 node = repo.commit(text=message, user=user,
4062 date=date, extra=extra, editor=editor)
4062 date=date, extra=extra, editor=editor)
4063 if node is None:
4063 if node is None:
4064 ui.warn(
4064 ui.warn(
4065 _('note: graft of %d:%s created no changes to commit\n') %
4065 _('note: graft of %d:%s created no changes to commit\n') %
4066 (ctx.rev(), ctx))
4066 (ctx.rev(), ctx))
4067
4067
4068 # remove state when we complete successfully
4068 # remove state when we complete successfully
4069 if not opts.get('dry_run'):
4069 if not opts.get('dry_run'):
4070 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4070 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4071
4071
4072 return 0
4072 return 0
4073
4073
4074 @command('grep',
4074 @command('grep',
4075 [('0', 'print0', None, _('end fields with NUL')),
4075 [('0', 'print0', None, _('end fields with NUL')),
4076 ('', 'all', None, _('print all revisions that match')),
4076 ('', 'all', None, _('print all revisions that match')),
4077 ('a', 'text', None, _('treat all files as text')),
4077 ('a', 'text', None, _('treat all files as text')),
4078 ('f', 'follow', None,
4078 ('f', 'follow', None,
4079 _('follow changeset history,'
4079 _('follow changeset history,'
4080 ' or file history across copies and renames')),
4080 ' or file history across copies and renames')),
4081 ('i', 'ignore-case', None, _('ignore case when matching')),
4081 ('i', 'ignore-case', None, _('ignore case when matching')),
4082 ('l', 'files-with-matches', None,
4082 ('l', 'files-with-matches', None,
4083 _('print only filenames and revisions that match')),
4083 _('print only filenames and revisions that match')),
4084 ('n', 'line-number', None, _('print matching line numbers')),
4084 ('n', 'line-number', None, _('print matching line numbers')),
4085 ('r', 'rev', [],
4085 ('r', 'rev', [],
4086 _('only search files changed within revision range'), _('REV')),
4086 _('only search files changed within revision range'), _('REV')),
4087 ('u', 'user', None, _('list the author (long with -v)')),
4087 ('u', 'user', None, _('list the author (long with -v)')),
4088 ('d', 'date', None, _('list the date (short with -q)')),
4088 ('d', 'date', None, _('list the date (short with -q)')),
4089 ] + walkopts,
4089 ] + walkopts,
4090 _('[OPTION]... PATTERN [FILE]...'),
4090 _('[OPTION]... PATTERN [FILE]...'),
4091 inferrepo=True)
4091 inferrepo=True)
4092 def grep(ui, repo, pattern, *pats, **opts):
4092 def grep(ui, repo, pattern, *pats, **opts):
4093 """search for a pattern in specified files and revisions
4093 """search for a pattern in specified files and revisions
4094
4094
4095 Search revisions of files for a regular expression.
4095 Search revisions of files for a regular expression.
4096
4096
4097 This command behaves differently than Unix grep. It only accepts
4097 This command behaves differently than Unix grep. It only accepts
4098 Python/Perl regexps. It searches repository history, not the
4098 Python/Perl regexps. It searches repository history, not the
4099 working directory. It always prints the revision number in which a
4099 working directory. It always prints the revision number in which a
4100 match appears.
4100 match appears.
4101
4101
4102 By default, grep only prints output for the first revision of a
4102 By default, grep only prints output for the first revision of a
4103 file in which it finds a match. To get it to print every revision
4103 file in which it finds a match. To get it to print every revision
4104 that contains a change in match status ("-" for a match that
4104 that contains a change in match status ("-" for a match that
4105 becomes a non-match, or "+" for a non-match that becomes a match),
4105 becomes a non-match, or "+" for a non-match that becomes a match),
4106 use the --all flag.
4106 use the --all flag.
4107
4107
4108 Returns 0 if a match is found, 1 otherwise.
4108 Returns 0 if a match is found, 1 otherwise.
4109 """
4109 """
4110 reflags = re.M
4110 reflags = re.M
4111 if opts.get('ignore_case'):
4111 if opts.get('ignore_case'):
4112 reflags |= re.I
4112 reflags |= re.I
4113 try:
4113 try:
4114 regexp = util.re.compile(pattern, reflags)
4114 regexp = util.re.compile(pattern, reflags)
4115 except re.error as inst:
4115 except re.error as inst:
4116 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4116 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4117 return 1
4117 return 1
4118 sep, eol = ':', '\n'
4118 sep, eol = ':', '\n'
4119 if opts.get('print0'):
4119 if opts.get('print0'):
4120 sep = eol = '\0'
4120 sep = eol = '\0'
4121
4121
4122 getfile = util.lrucachefunc(repo.file)
4122 getfile = util.lrucachefunc(repo.file)
4123
4123
4124 def matchlines(body):
4124 def matchlines(body):
4125 begin = 0
4125 begin = 0
4126 linenum = 0
4126 linenum = 0
4127 while begin < len(body):
4127 while begin < len(body):
4128 match = regexp.search(body, begin)
4128 match = regexp.search(body, begin)
4129 if not match:
4129 if not match:
4130 break
4130 break
4131 mstart, mend = match.span()
4131 mstart, mend = match.span()
4132 linenum += body.count('\n', begin, mstart) + 1
4132 linenum += body.count('\n', begin, mstart) + 1
4133 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4133 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4134 begin = body.find('\n', mend) + 1 or len(body) + 1
4134 begin = body.find('\n', mend) + 1 or len(body) + 1
4135 lend = begin - 1
4135 lend = begin - 1
4136 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4136 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4137
4137
4138 class linestate(object):
4138 class linestate(object):
4139 def __init__(self, line, linenum, colstart, colend):
4139 def __init__(self, line, linenum, colstart, colend):
4140 self.line = line
4140 self.line = line
4141 self.linenum = linenum
4141 self.linenum = linenum
4142 self.colstart = colstart
4142 self.colstart = colstart
4143 self.colend = colend
4143 self.colend = colend
4144
4144
4145 def __hash__(self):
4145 def __hash__(self):
4146 return hash((self.linenum, self.line))
4146 return hash((self.linenum, self.line))
4147
4147
4148 def __eq__(self, other):
4148 def __eq__(self, other):
4149 return self.line == other.line
4149 return self.line == other.line
4150
4150
4151 def __iter__(self):
4151 def __iter__(self):
4152 yield (self.line[:self.colstart], '')
4152 yield (self.line[:self.colstart], '')
4153 yield (self.line[self.colstart:self.colend], 'grep.match')
4153 yield (self.line[self.colstart:self.colend], 'grep.match')
4154 rest = self.line[self.colend:]
4154 rest = self.line[self.colend:]
4155 while rest != '':
4155 while rest != '':
4156 match = regexp.search(rest)
4156 match = regexp.search(rest)
4157 if not match:
4157 if not match:
4158 yield (rest, '')
4158 yield (rest, '')
4159 break
4159 break
4160 mstart, mend = match.span()
4160 mstart, mend = match.span()
4161 yield (rest[:mstart], '')
4161 yield (rest[:mstart], '')
4162 yield (rest[mstart:mend], 'grep.match')
4162 yield (rest[mstart:mend], 'grep.match')
4163 rest = rest[mend:]
4163 rest = rest[mend:]
4164
4164
4165 matches = {}
4165 matches = {}
4166 copies = {}
4166 copies = {}
4167 def grepbody(fn, rev, body):
4167 def grepbody(fn, rev, body):
4168 matches[rev].setdefault(fn, [])
4168 matches[rev].setdefault(fn, [])
4169 m = matches[rev][fn]
4169 m = matches[rev][fn]
4170 for lnum, cstart, cend, line in matchlines(body):
4170 for lnum, cstart, cend, line in matchlines(body):
4171 s = linestate(line, lnum, cstart, cend)
4171 s = linestate(line, lnum, cstart, cend)
4172 m.append(s)
4172 m.append(s)
4173
4173
4174 def difflinestates(a, b):
4174 def difflinestates(a, b):
4175 sm = difflib.SequenceMatcher(None, a, b)
4175 sm = difflib.SequenceMatcher(None, a, b)
4176 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4176 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4177 if tag == 'insert':
4177 if tag == 'insert':
4178 for i in xrange(blo, bhi):
4178 for i in xrange(blo, bhi):
4179 yield ('+', b[i])
4179 yield ('+', b[i])
4180 elif tag == 'delete':
4180 elif tag == 'delete':
4181 for i in xrange(alo, ahi):
4181 for i in xrange(alo, ahi):
4182 yield ('-', a[i])
4182 yield ('-', a[i])
4183 elif tag == 'replace':
4183 elif tag == 'replace':
4184 for i in xrange(alo, ahi):
4184 for i in xrange(alo, ahi):
4185 yield ('-', a[i])
4185 yield ('-', a[i])
4186 for i in xrange(blo, bhi):
4186 for i in xrange(blo, bhi):
4187 yield ('+', b[i])
4187 yield ('+', b[i])
4188
4188
4189 def display(fn, ctx, pstates, states):
4189 def display(fn, ctx, pstates, states):
4190 rev = ctx.rev()
4190 rev = ctx.rev()
4191 if ui.quiet:
4191 if ui.quiet:
4192 datefunc = util.shortdate
4192 datefunc = util.shortdate
4193 else:
4193 else:
4194 datefunc = util.datestr
4194 datefunc = util.datestr
4195 found = False
4195 found = False
4196 @util.cachefunc
4196 @util.cachefunc
4197 def binary():
4197 def binary():
4198 flog = getfile(fn)
4198 flog = getfile(fn)
4199 return util.binary(flog.read(ctx.filenode(fn)))
4199 return util.binary(flog.read(ctx.filenode(fn)))
4200
4200
4201 if opts.get('all'):
4201 if opts.get('all'):
4202 iter = difflinestates(pstates, states)
4202 iter = difflinestates(pstates, states)
4203 else:
4203 else:
4204 iter = [('', l) for l in states]
4204 iter = [('', l) for l in states]
4205 for change, l in iter:
4205 for change, l in iter:
4206 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4206 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4207
4207
4208 if opts.get('line_number'):
4208 if opts.get('line_number'):
4209 cols.append((str(l.linenum), 'grep.linenumber'))
4209 cols.append((str(l.linenum), 'grep.linenumber'))
4210 if opts.get('all'):
4210 if opts.get('all'):
4211 cols.append((change, 'grep.change'))
4211 cols.append((change, 'grep.change'))
4212 if opts.get('user'):
4212 if opts.get('user'):
4213 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4213 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4214 if opts.get('date'):
4214 if opts.get('date'):
4215 cols.append((datefunc(ctx.date()), 'grep.date'))
4215 cols.append((datefunc(ctx.date()), 'grep.date'))
4216 for col, label in cols[:-1]:
4216 for col, label in cols[:-1]:
4217 ui.write(col, label=label)
4217 ui.write(col, label=label)
4218 ui.write(sep, label='grep.sep')
4218 ui.write(sep, label='grep.sep')
4219 ui.write(cols[-1][0], label=cols[-1][1])
4219 ui.write(cols[-1][0], label=cols[-1][1])
4220 if not opts.get('files_with_matches'):
4220 if not opts.get('files_with_matches'):
4221 ui.write(sep, label='grep.sep')
4221 ui.write(sep, label='grep.sep')
4222 if not opts.get('text') and binary():
4222 if not opts.get('text') and binary():
4223 ui.write(" Binary file matches")
4223 ui.write(" Binary file matches")
4224 else:
4224 else:
4225 for s, label in l:
4225 for s, label in l:
4226 ui.write(s, label=label)
4226 ui.write(s, label=label)
4227 ui.write(eol)
4227 ui.write(eol)
4228 found = True
4228 found = True
4229 if opts.get('files_with_matches'):
4229 if opts.get('files_with_matches'):
4230 break
4230 break
4231 return found
4231 return found
4232
4232
4233 skip = {}
4233 skip = {}
4234 revfiles = {}
4234 revfiles = {}
4235 matchfn = scmutil.match(repo[None], pats, opts)
4235 matchfn = scmutil.match(repo[None], pats, opts)
4236 found = False
4236 found = False
4237 follow = opts.get('follow')
4237 follow = opts.get('follow')
4238
4238
4239 def prep(ctx, fns):
4239 def prep(ctx, fns):
4240 rev = ctx.rev()
4240 rev = ctx.rev()
4241 pctx = ctx.p1()
4241 pctx = ctx.p1()
4242 parent = pctx.rev()
4242 parent = pctx.rev()
4243 matches.setdefault(rev, {})
4243 matches.setdefault(rev, {})
4244 matches.setdefault(parent, {})
4244 matches.setdefault(parent, {})
4245 files = revfiles.setdefault(rev, [])
4245 files = revfiles.setdefault(rev, [])
4246 for fn in fns:
4246 for fn in fns:
4247 flog = getfile(fn)
4247 flog = getfile(fn)
4248 try:
4248 try:
4249 fnode = ctx.filenode(fn)
4249 fnode = ctx.filenode(fn)
4250 except error.LookupError:
4250 except error.LookupError:
4251 continue
4251 continue
4252
4252
4253 copied = flog.renamed(fnode)
4253 copied = flog.renamed(fnode)
4254 copy = follow and copied and copied[0]
4254 copy = follow and copied and copied[0]
4255 if copy:
4255 if copy:
4256 copies.setdefault(rev, {})[fn] = copy
4256 copies.setdefault(rev, {})[fn] = copy
4257 if fn in skip:
4257 if fn in skip:
4258 if copy:
4258 if copy:
4259 skip[copy] = True
4259 skip[copy] = True
4260 continue
4260 continue
4261 files.append(fn)
4261 files.append(fn)
4262
4262
4263 if fn not in matches[rev]:
4263 if fn not in matches[rev]:
4264 grepbody(fn, rev, flog.read(fnode))
4264 grepbody(fn, rev, flog.read(fnode))
4265
4265
4266 pfn = copy or fn
4266 pfn = copy or fn
4267 if pfn not in matches[parent]:
4267 if pfn not in matches[parent]:
4268 try:
4268 try:
4269 fnode = pctx.filenode(pfn)
4269 fnode = pctx.filenode(pfn)
4270 grepbody(pfn, parent, flog.read(fnode))
4270 grepbody(pfn, parent, flog.read(fnode))
4271 except error.LookupError:
4271 except error.LookupError:
4272 pass
4272 pass
4273
4273
4274 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4274 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4275 rev = ctx.rev()
4275 rev = ctx.rev()
4276 parent = ctx.p1().rev()
4276 parent = ctx.p1().rev()
4277 for fn in sorted(revfiles.get(rev, [])):
4277 for fn in sorted(revfiles.get(rev, [])):
4278 states = matches[rev][fn]
4278 states = matches[rev][fn]
4279 copy = copies.get(rev, {}).get(fn)
4279 copy = copies.get(rev, {}).get(fn)
4280 if fn in skip:
4280 if fn in skip:
4281 if copy:
4281 if copy:
4282 skip[copy] = True
4282 skip[copy] = True
4283 continue
4283 continue
4284 pstates = matches.get(parent, {}).get(copy or fn, [])
4284 pstates = matches.get(parent, {}).get(copy or fn, [])
4285 if pstates or states:
4285 if pstates or states:
4286 r = display(fn, ctx, pstates, states)
4286 r = display(fn, ctx, pstates, states)
4287 found = found or r
4287 found = found or r
4288 if r and not opts.get('all'):
4288 if r and not opts.get('all'):
4289 skip[fn] = True
4289 skip[fn] = True
4290 if copy:
4290 if copy:
4291 skip[copy] = True
4291 skip[copy] = True
4292 del matches[rev]
4292 del matches[rev]
4293 del revfiles[rev]
4293 del revfiles[rev]
4294
4294
4295 return not found
4295 return not found
4296
4296
4297 @command('heads',
4297 @command('heads',
4298 [('r', 'rev', '',
4298 [('r', 'rev', '',
4299 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4299 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4300 ('t', 'topo', False, _('show topological heads only')),
4300 ('t', 'topo', False, _('show topological heads only')),
4301 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4301 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4302 ('c', 'closed', False, _('show normal and closed branch heads')),
4302 ('c', 'closed', False, _('show normal and closed branch heads')),
4303 ] + templateopts,
4303 ] + templateopts,
4304 _('[-ct] [-r STARTREV] [REV]...'))
4304 _('[-ct] [-r STARTREV] [REV]...'))
4305 def heads(ui, repo, *branchrevs, **opts):
4305 def heads(ui, repo, *branchrevs, **opts):
4306 """show branch heads
4306 """show branch heads
4307
4307
4308 With no arguments, show all open branch heads in the repository.
4308 With no arguments, show all open branch heads in the repository.
4309 Branch heads are changesets that have no descendants on the
4309 Branch heads are changesets that have no descendants on the
4310 same branch. They are where development generally takes place and
4310 same branch. They are where development generally takes place and
4311 are the usual targets for update and merge operations.
4311 are the usual targets for update and merge operations.
4312
4312
4313 If one or more REVs are given, only open branch heads on the
4313 If one or more REVs are given, only open branch heads on the
4314 branches associated with the specified changesets are shown. This
4314 branches associated with the specified changesets are shown. This
4315 means that you can use :hg:`heads .` to see the heads on the
4315 means that you can use :hg:`heads .` to see the heads on the
4316 currently checked-out branch.
4316 currently checked-out branch.
4317
4317
4318 If -c/--closed is specified, also show branch heads marked closed
4318 If -c/--closed is specified, also show branch heads marked closed
4319 (see :hg:`commit --close-branch`).
4319 (see :hg:`commit --close-branch`).
4320
4320
4321 If STARTREV is specified, only those heads that are descendants of
4321 If STARTREV is specified, only those heads that are descendants of
4322 STARTREV will be displayed.
4322 STARTREV will be displayed.
4323
4323
4324 If -t/--topo is specified, named branch mechanics will be ignored and only
4324 If -t/--topo is specified, named branch mechanics will be ignored and only
4325 topological heads (changesets with no children) will be shown.
4325 topological heads (changesets with no children) will be shown.
4326
4326
4327 Returns 0 if matching heads are found, 1 if not.
4327 Returns 0 if matching heads are found, 1 if not.
4328 """
4328 """
4329
4329
4330 start = None
4330 start = None
4331 if 'rev' in opts:
4331 if 'rev' in opts:
4332 start = scmutil.revsingle(repo, opts['rev'], None).node()
4332 start = scmutil.revsingle(repo, opts['rev'], None).node()
4333
4333
4334 if opts.get('topo'):
4334 if opts.get('topo'):
4335 heads = [repo[h] for h in repo.heads(start)]
4335 heads = [repo[h] for h in repo.heads(start)]
4336 else:
4336 else:
4337 heads = []
4337 heads = []
4338 for branch in repo.branchmap():
4338 for branch in repo.branchmap():
4339 heads += repo.branchheads(branch, start, opts.get('closed'))
4339 heads += repo.branchheads(branch, start, opts.get('closed'))
4340 heads = [repo[h] for h in heads]
4340 heads = [repo[h] for h in heads]
4341
4341
4342 if branchrevs:
4342 if branchrevs:
4343 branches = set(repo[br].branch() for br in branchrevs)
4343 branches = set(repo[br].branch() for br in branchrevs)
4344 heads = [h for h in heads if h.branch() in branches]
4344 heads = [h for h in heads if h.branch() in branches]
4345
4345
4346 if opts.get('active') and branchrevs:
4346 if opts.get('active') and branchrevs:
4347 dagheads = repo.heads(start)
4347 dagheads = repo.heads(start)
4348 heads = [h for h in heads if h.node() in dagheads]
4348 heads = [h for h in heads if h.node() in dagheads]
4349
4349
4350 if branchrevs:
4350 if branchrevs:
4351 haveheads = set(h.branch() for h in heads)
4351 haveheads = set(h.branch() for h in heads)
4352 if branches - haveheads:
4352 if branches - haveheads:
4353 headless = ', '.join(b for b in branches - haveheads)
4353 headless = ', '.join(b for b in branches - haveheads)
4354 msg = _('no open branch heads found on branches %s')
4354 msg = _('no open branch heads found on branches %s')
4355 if opts.get('rev'):
4355 if opts.get('rev'):
4356 msg += _(' (started at %s)') % opts['rev']
4356 msg += _(' (started at %s)') % opts['rev']
4357 ui.warn((msg + '\n') % headless)
4357 ui.warn((msg + '\n') % headless)
4358
4358
4359 if not heads:
4359 if not heads:
4360 return 1
4360 return 1
4361
4361
4362 heads = sorted(heads, key=lambda x: -x.rev())
4362 heads = sorted(heads, key=lambda x: -x.rev())
4363 displayer = cmdutil.show_changeset(ui, repo, opts)
4363 displayer = cmdutil.show_changeset(ui, repo, opts)
4364 for ctx in heads:
4364 for ctx in heads:
4365 displayer.show(ctx)
4365 displayer.show(ctx)
4366 displayer.close()
4366 displayer.close()
4367
4367
4368 @command('help',
4368 @command('help',
4369 [('e', 'extension', None, _('show only help for extensions')),
4369 [('e', 'extension', None, _('show only help for extensions')),
4370 ('c', 'command', None, _('show only help for commands')),
4370 ('c', 'command', None, _('show only help for commands')),
4371 ('k', 'keyword', None, _('show topics matching keyword')),
4371 ('k', 'keyword', None, _('show topics matching keyword')),
4372 ('s', 'system', [], _('show help for specific platform(s)')),
4372 ('s', 'system', [], _('show help for specific platform(s)')),
4373 ],
4373 ],
4374 _('[-ecks] [TOPIC]'),
4374 _('[-ecks] [TOPIC]'),
4375 norepo=True)
4375 norepo=True)
4376 def help_(ui, name=None, **opts):
4376 def help_(ui, name=None, **opts):
4377 """show help for a given topic or a help overview
4377 """show help for a given topic or a help overview
4378
4378
4379 With no arguments, print a list of commands with short help messages.
4379 With no arguments, print a list of commands with short help messages.
4380
4380
4381 Given a topic, extension, or command name, print help for that
4381 Given a topic, extension, or command name, print help for that
4382 topic.
4382 topic.
4383
4383
4384 Returns 0 if successful.
4384 Returns 0 if successful.
4385 """
4385 """
4386
4386
4387 textwidth = min(ui.termwidth(), 80) - 2
4387 textwidth = min(ui.termwidth(), 80) - 2
4388
4388
4389 keep = opts.get('system') or []
4389 keep = opts.get('system') or []
4390 if len(keep) == 0:
4390 if len(keep) == 0:
4391 if sys.platform.startswith('win'):
4391 if sys.platform.startswith('win'):
4392 keep.append('windows')
4392 keep.append('windows')
4393 elif sys.platform == 'OpenVMS':
4393 elif sys.platform == 'OpenVMS':
4394 keep.append('vms')
4394 keep.append('vms')
4395 elif sys.platform == 'plan9':
4395 elif sys.platform == 'plan9':
4396 keep.append('plan9')
4396 keep.append('plan9')
4397 else:
4397 else:
4398 keep.append('unix')
4398 keep.append('unix')
4399 keep.append(sys.platform.lower())
4399 keep.append(sys.platform.lower())
4400 if ui.verbose:
4400 if ui.verbose:
4401 keep.append('verbose')
4401 keep.append('verbose')
4402
4402
4403 section = None
4403 section = None
4404 subtopic = None
4404 subtopic = None
4405 if name and '.' in name:
4405 if name and '.' in name:
4406 name, section = name.split('.', 1)
4406 name, section = name.split('.', 1)
4407 section = section.lower()
4407 section = section.lower()
4408 if '.' in section:
4408 if '.' in section:
4409 subtopic, section = section.split('.', 1)
4409 subtopic, section = section.split('.', 1)
4410 else:
4410 else:
4411 subtopic = section
4411 subtopic = section
4412
4412
4413 text = help.help_(ui, name, subtopic=subtopic, **opts)
4413 text = help.help_(ui, name, subtopic=subtopic, **opts)
4414
4414
4415 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4415 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4416 section=section)
4416 section=section)
4417
4417
4418 # We could have been given a weird ".foo" section without a name
4418 # We could have been given a weird ".foo" section without a name
4419 # to look for, or we could have simply failed to found "foo.bar"
4419 # to look for, or we could have simply failed to found "foo.bar"
4420 # because bar isn't a section of foo
4420 # because bar isn't a section of foo
4421 if section and not (formatted and name):
4421 if section and not (formatted and name):
4422 raise error.Abort(_("help section not found"))
4422 raise error.Abort(_("help section not found"))
4423
4423
4424 if 'verbose' in pruned:
4424 if 'verbose' in pruned:
4425 keep.append('omitted')
4425 keep.append('omitted')
4426 else:
4426 else:
4427 keep.append('notomitted')
4427 keep.append('notomitted')
4428 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4428 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4429 section=section)
4429 section=section)
4430 ui.write(formatted)
4430 ui.write(formatted)
4431
4431
4432
4432
4433 @command('identify|id',
4433 @command('identify|id',
4434 [('r', 'rev', '',
4434 [('r', 'rev', '',
4435 _('identify the specified revision'), _('REV')),
4435 _('identify the specified revision'), _('REV')),
4436 ('n', 'num', None, _('show local revision number')),
4436 ('n', 'num', None, _('show local revision number')),
4437 ('i', 'id', None, _('show global revision id')),
4437 ('i', 'id', None, _('show global revision id')),
4438 ('b', 'branch', None, _('show branch')),
4438 ('b', 'branch', None, _('show branch')),
4439 ('t', 'tags', None, _('show tags')),
4439 ('t', 'tags', None, _('show tags')),
4440 ('B', 'bookmarks', None, _('show bookmarks')),
4440 ('B', 'bookmarks', None, _('show bookmarks')),
4441 ] + remoteopts,
4441 ] + remoteopts,
4442 _('[-nibtB] [-r REV] [SOURCE]'),
4442 _('[-nibtB] [-r REV] [SOURCE]'),
4443 optionalrepo=True)
4443 optionalrepo=True)
4444 def identify(ui, repo, source=None, rev=None,
4444 def identify(ui, repo, source=None, rev=None,
4445 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4445 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4446 """identify the working directory or specified revision
4446 """identify the working directory or specified revision
4447
4447
4448 Print a summary identifying the repository state at REV using one or
4448 Print a summary identifying the repository state at REV using one or
4449 two parent hash identifiers, followed by a "+" if the working
4449 two parent hash identifiers, followed by a "+" if the working
4450 directory has uncommitted changes, the branch name (if not default),
4450 directory has uncommitted changes, the branch name (if not default),
4451 a list of tags, and a list of bookmarks.
4451 a list of tags, and a list of bookmarks.
4452
4452
4453 When REV is not given, print a summary of the current state of the
4453 When REV is not given, print a summary of the current state of the
4454 repository.
4454 repository.
4455
4455
4456 Specifying a path to a repository root or Mercurial bundle will
4456 Specifying a path to a repository root or Mercurial bundle will
4457 cause lookup to operate on that repository/bundle.
4457 cause lookup to operate on that repository/bundle.
4458
4458
4459 .. container:: verbose
4459 .. container:: verbose
4460
4460
4461 Examples:
4461 Examples:
4462
4462
4463 - generate a build identifier for the working directory::
4463 - generate a build identifier for the working directory::
4464
4464
4465 hg id --id > build-id.dat
4465 hg id --id > build-id.dat
4466
4466
4467 - find the revision corresponding to a tag::
4467 - find the revision corresponding to a tag::
4468
4468
4469 hg id -n -r 1.3
4469 hg id -n -r 1.3
4470
4470
4471 - check the most recent revision of a remote repository::
4471 - check the most recent revision of a remote repository::
4472
4472
4473 hg id -r tip http://selenic.com/hg/
4473 hg id -r tip http://selenic.com/hg/
4474
4474
4475 See :hg:`log` for generating more information about specific revisions,
4475 See :hg:`log` for generating more information about specific revisions,
4476 including full hash identifiers.
4476 including full hash identifiers.
4477
4477
4478 Returns 0 if successful.
4478 Returns 0 if successful.
4479 """
4479 """
4480
4480
4481 if not repo and not source:
4481 if not repo and not source:
4482 raise error.Abort(_("there is no Mercurial repository here "
4482 raise error.Abort(_("there is no Mercurial repository here "
4483 "(.hg not found)"))
4483 "(.hg not found)"))
4484
4484
4485 if ui.debugflag:
4485 if ui.debugflag:
4486 hexfunc = hex
4486 hexfunc = hex
4487 else:
4487 else:
4488 hexfunc = short
4488 hexfunc = short
4489 default = not (num or id or branch or tags or bookmarks)
4489 default = not (num or id or branch or tags or bookmarks)
4490 output = []
4490 output = []
4491 revs = []
4491 revs = []
4492
4492
4493 if source:
4493 if source:
4494 source, branches = hg.parseurl(ui.expandpath(source))
4494 source, branches = hg.parseurl(ui.expandpath(source))
4495 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4495 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4496 repo = peer.local()
4496 repo = peer.local()
4497 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4497 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4498
4498
4499 if not repo:
4499 if not repo:
4500 if num or branch or tags:
4500 if num or branch or tags:
4501 raise error.Abort(
4501 raise error.Abort(
4502 _("can't query remote revision number, branch, or tags"))
4502 _("can't query remote revision number, branch, or tags"))
4503 if not rev and revs:
4503 if not rev and revs:
4504 rev = revs[0]
4504 rev = revs[0]
4505 if not rev:
4505 if not rev:
4506 rev = "tip"
4506 rev = "tip"
4507
4507
4508 remoterev = peer.lookup(rev)
4508 remoterev = peer.lookup(rev)
4509 if default or id:
4509 if default or id:
4510 output = [hexfunc(remoterev)]
4510 output = [hexfunc(remoterev)]
4511
4511
4512 def getbms():
4512 def getbms():
4513 bms = []
4513 bms = []
4514
4514
4515 if 'bookmarks' in peer.listkeys('namespaces'):
4515 if 'bookmarks' in peer.listkeys('namespaces'):
4516 hexremoterev = hex(remoterev)
4516 hexremoterev = hex(remoterev)
4517 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4517 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4518 if bmr == hexremoterev]
4518 if bmr == hexremoterev]
4519
4519
4520 return sorted(bms)
4520 return sorted(bms)
4521
4521
4522 if bookmarks:
4522 if bookmarks:
4523 output.extend(getbms())
4523 output.extend(getbms())
4524 elif default and not ui.quiet:
4524 elif default and not ui.quiet:
4525 # multiple bookmarks for a single parent separated by '/'
4525 # multiple bookmarks for a single parent separated by '/'
4526 bm = '/'.join(getbms())
4526 bm = '/'.join(getbms())
4527 if bm:
4527 if bm:
4528 output.append(bm)
4528 output.append(bm)
4529 else:
4529 else:
4530 ctx = scmutil.revsingle(repo, rev, None)
4530 ctx = scmutil.revsingle(repo, rev, None)
4531
4531
4532 if ctx.rev() is None:
4532 if ctx.rev() is None:
4533 ctx = repo[None]
4533 ctx = repo[None]
4534 parents = ctx.parents()
4534 parents = ctx.parents()
4535 taglist = []
4535 taglist = []
4536 for p in parents:
4536 for p in parents:
4537 taglist.extend(p.tags())
4537 taglist.extend(p.tags())
4538
4538
4539 changed = ""
4539 changed = ""
4540 if default or id or num:
4540 if default or id or num:
4541 if (any(repo.status())
4541 if (any(repo.status())
4542 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4542 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4543 changed = '+'
4543 changed = '+'
4544 if default or id:
4544 if default or id:
4545 output = ["%s%s" %
4545 output = ["%s%s" %
4546 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4546 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4547 if num:
4547 if num:
4548 output.append("%s%s" %
4548 output.append("%s%s" %
4549 ('+'.join([str(p.rev()) for p in parents]), changed))
4549 ('+'.join([str(p.rev()) for p in parents]), changed))
4550 else:
4550 else:
4551 if default or id:
4551 if default or id:
4552 output = [hexfunc(ctx.node())]
4552 output = [hexfunc(ctx.node())]
4553 if num:
4553 if num:
4554 output.append(str(ctx.rev()))
4554 output.append(str(ctx.rev()))
4555 taglist = ctx.tags()
4555 taglist = ctx.tags()
4556
4556
4557 if default and not ui.quiet:
4557 if default and not ui.quiet:
4558 b = ctx.branch()
4558 b = ctx.branch()
4559 if b != 'default':
4559 if b != 'default':
4560 output.append("(%s)" % b)
4560 output.append("(%s)" % b)
4561
4561
4562 # multiple tags for a single parent separated by '/'
4562 # multiple tags for a single parent separated by '/'
4563 t = '/'.join(taglist)
4563 t = '/'.join(taglist)
4564 if t:
4564 if t:
4565 output.append(t)
4565 output.append(t)
4566
4566
4567 # multiple bookmarks for a single parent separated by '/'
4567 # multiple bookmarks for a single parent separated by '/'
4568 bm = '/'.join(ctx.bookmarks())
4568 bm = '/'.join(ctx.bookmarks())
4569 if bm:
4569 if bm:
4570 output.append(bm)
4570 output.append(bm)
4571 else:
4571 else:
4572 if branch:
4572 if branch:
4573 output.append(ctx.branch())
4573 output.append(ctx.branch())
4574
4574
4575 if tags:
4575 if tags:
4576 output.extend(taglist)
4576 output.extend(taglist)
4577
4577
4578 if bookmarks:
4578 if bookmarks:
4579 output.extend(ctx.bookmarks())
4579 output.extend(ctx.bookmarks())
4580
4580
4581 ui.write("%s\n" % ' '.join(output))
4581 ui.write("%s\n" % ' '.join(output))
4582
4582
4583 @command('import|patch',
4583 @command('import|patch',
4584 [('p', 'strip', 1,
4584 [('p', 'strip', 1,
4585 _('directory strip option for patch. This has the same '
4585 _('directory strip option for patch. This has the same '
4586 'meaning as the corresponding patch option'), _('NUM')),
4586 'meaning as the corresponding patch option'), _('NUM')),
4587 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4587 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4588 ('e', 'edit', False, _('invoke editor on commit messages')),
4588 ('e', 'edit', False, _('invoke editor on commit messages')),
4589 ('f', 'force', None,
4589 ('f', 'force', None,
4590 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4590 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4591 ('', 'no-commit', None,
4591 ('', 'no-commit', None,
4592 _("don't commit, just update the working directory")),
4592 _("don't commit, just update the working directory")),
4593 ('', 'bypass', None,
4593 ('', 'bypass', None,
4594 _("apply patch without touching the working directory")),
4594 _("apply patch without touching the working directory")),
4595 ('', 'partial', None,
4595 ('', 'partial', None,
4596 _('commit even if some hunks fail')),
4596 _('commit even if some hunks fail')),
4597 ('', 'exact', None,
4597 ('', 'exact', None,
4598 _('apply patch to the nodes from which it was generated')),
4598 _('apply patch to the nodes from which it was generated')),
4599 ('', 'prefix', '',
4599 ('', 'prefix', '',
4600 _('apply patch to subdirectory'), _('DIR')),
4600 _('apply patch to subdirectory'), _('DIR')),
4601 ('', 'import-branch', None,
4601 ('', 'import-branch', None,
4602 _('use any branch information in patch (implied by --exact)'))] +
4602 _('use any branch information in patch (implied by --exact)'))] +
4603 commitopts + commitopts2 + similarityopts,
4603 commitopts + commitopts2 + similarityopts,
4604 _('[OPTION]... PATCH...'))
4604 _('[OPTION]... PATCH...'))
4605 def import_(ui, repo, patch1=None, *patches, **opts):
4605 def import_(ui, repo, patch1=None, *patches, **opts):
4606 """import an ordered set of patches
4606 """import an ordered set of patches
4607
4607
4608 Import a list of patches and commit them individually (unless
4608 Import a list of patches and commit them individually (unless
4609 --no-commit is specified).
4609 --no-commit is specified).
4610
4610
4611 To read a patch from standard input, use "-" as the patch name. If
4611 To read a patch from standard input, use "-" as the patch name. If
4612 a URL is specified, the patch will be downloaded from there.
4612 a URL is specified, the patch will be downloaded from there.
4613
4613
4614 Import first applies changes to the working directory (unless
4614 Import first applies changes to the working directory (unless
4615 --bypass is specified), import will abort if there are outstanding
4615 --bypass is specified), import will abort if there are outstanding
4616 changes.
4616 changes.
4617
4617
4618 Use --bypass to apply and commit patches directly to the
4618 Use --bypass to apply and commit patches directly to the
4619 repository, without affecting the working directory. Without
4619 repository, without affecting the working directory. Without
4620 --exact, patches will be applied on top of the working directory
4620 --exact, patches will be applied on top of the working directory
4621 parent revision.
4621 parent revision.
4622
4622
4623 You can import a patch straight from a mail message. Even patches
4623 You can import a patch straight from a mail message. Even patches
4624 as attachments work (to use the body part, it must have type
4624 as attachments work (to use the body part, it must have type
4625 text/plain or text/x-patch). From and Subject headers of email
4625 text/plain or text/x-patch). From and Subject headers of email
4626 message are used as default committer and commit message. All
4626 message are used as default committer and commit message. All
4627 text/plain body parts before first diff are added to the commit
4627 text/plain body parts before first diff are added to the commit
4628 message.
4628 message.
4629
4629
4630 If the imported patch was generated by :hg:`export`, user and
4630 If the imported patch was generated by :hg:`export`, user and
4631 description from patch override values from message headers and
4631 description from patch override values from message headers and
4632 body. Values given on command line with -m/--message and -u/--user
4632 body. Values given on command line with -m/--message and -u/--user
4633 override these.
4633 override these.
4634
4634
4635 If --exact is specified, import will set the working directory to
4635 If --exact is specified, import will set the working directory to
4636 the parent of each patch before applying it, and will abort if the
4636 the parent of each patch before applying it, and will abort if the
4637 resulting changeset has a different ID than the one recorded in
4637 resulting changeset has a different ID than the one recorded in
4638 the patch. This may happen due to character set problems or other
4638 the patch. This may happen due to character set problems or other
4639 deficiencies in the text patch format.
4639 deficiencies in the text patch format.
4640
4640
4641 Use --partial to ensure a changeset will be created from the patch
4641 Use --partial to ensure a changeset will be created from the patch
4642 even if some hunks fail to apply. Hunks that fail to apply will be
4642 even if some hunks fail to apply. Hunks that fail to apply will be
4643 written to a <target-file>.rej file. Conflicts can then be resolved
4643 written to a <target-file>.rej file. Conflicts can then be resolved
4644 by hand before :hg:`commit --amend` is run to update the created
4644 by hand before :hg:`commit --amend` is run to update the created
4645 changeset. This flag exists to let people import patches that
4645 changeset. This flag exists to let people import patches that
4646 partially apply without losing the associated metadata (author,
4646 partially apply without losing the associated metadata (author,
4647 date, description, ...).
4647 date, description, ...).
4648
4648
4649 .. note::
4649 .. note::
4650
4650
4651 When no hunks apply cleanly, :hg:`import --partial` will create
4651 When no hunks apply cleanly, :hg:`import --partial` will create
4652 an empty changeset, importing only the patch metadata.
4652 an empty changeset, importing only the patch metadata.
4653
4653
4654 With -s/--similarity, hg will attempt to discover renames and
4654 With -s/--similarity, hg will attempt to discover renames and
4655 copies in the patch in the same way as :hg:`addremove`.
4655 copies in the patch in the same way as :hg:`addremove`.
4656
4656
4657 It is possible to use external patch programs to perform the patch
4657 It is possible to use external patch programs to perform the patch
4658 by setting the ``ui.patch`` configuration option. For the default
4658 by setting the ``ui.patch`` configuration option. For the default
4659 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4659 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4660 See :hg:`help config` for more information about configuration
4660 See :hg:`help config` for more information about configuration
4661 files and how to use these options.
4661 files and how to use these options.
4662
4662
4663 See :hg:`help dates` for a list of formats valid for -d/--date.
4663 See :hg:`help dates` for a list of formats valid for -d/--date.
4664
4664
4665 .. container:: verbose
4665 .. container:: verbose
4666
4666
4667 Examples:
4667 Examples:
4668
4668
4669 - import a traditional patch from a website and detect renames::
4669 - import a traditional patch from a website and detect renames::
4670
4670
4671 hg import -s 80 http://example.com/bugfix.patch
4671 hg import -s 80 http://example.com/bugfix.patch
4672
4672
4673 - import a changeset from an hgweb server::
4673 - import a changeset from an hgweb server::
4674
4674
4675 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4675 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4676
4676
4677 - import all the patches in an Unix-style mbox::
4677 - import all the patches in an Unix-style mbox::
4678
4678
4679 hg import incoming-patches.mbox
4679 hg import incoming-patches.mbox
4680
4680
4681 - attempt to exactly restore an exported changeset (not always
4681 - attempt to exactly restore an exported changeset (not always
4682 possible)::
4682 possible)::
4683
4683
4684 hg import --exact proposed-fix.patch
4684 hg import --exact proposed-fix.patch
4685
4685
4686 - use an external tool to apply a patch which is too fuzzy for
4686 - use an external tool to apply a patch which is too fuzzy for
4687 the default internal tool.
4687 the default internal tool.
4688
4688
4689 hg import --config ui.patch="patch --merge" fuzzy.patch
4689 hg import --config ui.patch="patch --merge" fuzzy.patch
4690
4690
4691 - change the default fuzzing from 2 to a less strict 7
4691 - change the default fuzzing from 2 to a less strict 7
4692
4692
4693 hg import --config ui.fuzz=7 fuzz.patch
4693 hg import --config ui.fuzz=7 fuzz.patch
4694
4694
4695 Returns 0 on success, 1 on partial success (see --partial).
4695 Returns 0 on success, 1 on partial success (see --partial).
4696 """
4696 """
4697
4697
4698 if not patch1:
4698 if not patch1:
4699 raise error.Abort(_('need at least one patch to import'))
4699 raise error.Abort(_('need at least one patch to import'))
4700
4700
4701 patches = (patch1,) + patches
4701 patches = (patch1,) + patches
4702
4702
4703 date = opts.get('date')
4703 date = opts.get('date')
4704 if date:
4704 if date:
4705 opts['date'] = util.parsedate(date)
4705 opts['date'] = util.parsedate(date)
4706
4706
4707 exact = opts.get('exact')
4707 exact = opts.get('exact')
4708 update = not opts.get('bypass')
4708 update = not opts.get('bypass')
4709 if not update and opts.get('no_commit'):
4709 if not update and opts.get('no_commit'):
4710 raise error.Abort(_('cannot use --no-commit with --bypass'))
4710 raise error.Abort(_('cannot use --no-commit with --bypass'))
4711 try:
4711 try:
4712 sim = float(opts.get('similarity') or 0)
4712 sim = float(opts.get('similarity') or 0)
4713 except ValueError:
4713 except ValueError:
4714 raise error.Abort(_('similarity must be a number'))
4714 raise error.Abort(_('similarity must be a number'))
4715 if sim < 0 or sim > 100:
4715 if sim < 0 or sim > 100:
4716 raise error.Abort(_('similarity must be between 0 and 100'))
4716 raise error.Abort(_('similarity must be between 0 and 100'))
4717 if sim and not update:
4717 if sim and not update:
4718 raise error.Abort(_('cannot use --similarity with --bypass'))
4718 raise error.Abort(_('cannot use --similarity with --bypass'))
4719 if exact:
4719 if exact:
4720 if opts.get('edit'):
4720 if opts.get('edit'):
4721 raise error.Abort(_('cannot use --exact with --edit'))
4721 raise error.Abort(_('cannot use --exact with --edit'))
4722 if opts.get('prefix'):
4722 if opts.get('prefix'):
4723 raise error.Abort(_('cannot use --exact with --prefix'))
4723 raise error.Abort(_('cannot use --exact with --prefix'))
4724
4724
4725 base = opts["base"]
4725 base = opts["base"]
4726 wlock = dsguard = lock = tr = None
4726 wlock = dsguard = lock = tr = None
4727 msgs = []
4727 msgs = []
4728 ret = 0
4728 ret = 0
4729
4729
4730
4730
4731 try:
4731 try:
4732 wlock = repo.wlock()
4732 wlock = repo.wlock()
4733
4733
4734 if update:
4734 if update:
4735 cmdutil.checkunfinished(repo)
4735 cmdutil.checkunfinished(repo)
4736 if (exact or not opts.get('force')):
4736 if (exact or not opts.get('force')):
4737 cmdutil.bailifchanged(repo)
4737 cmdutil.bailifchanged(repo)
4738
4738
4739 if not opts.get('no_commit'):
4739 if not opts.get('no_commit'):
4740 lock = repo.lock()
4740 lock = repo.lock()
4741 tr = repo.transaction('import')
4741 tr = repo.transaction('import')
4742 else:
4742 else:
4743 dsguard = cmdutil.dirstateguard(repo, 'import')
4743 dsguard = cmdutil.dirstateguard(repo, 'import')
4744 parents = repo[None].parents()
4744 parents = repo[None].parents()
4745 for patchurl in patches:
4745 for patchurl in patches:
4746 if patchurl == '-':
4746 if patchurl == '-':
4747 ui.status(_('applying patch from stdin\n'))
4747 ui.status(_('applying patch from stdin\n'))
4748 patchfile = ui.fin
4748 patchfile = ui.fin
4749 patchurl = 'stdin' # for error message
4749 patchurl = 'stdin' # for error message
4750 else:
4750 else:
4751 patchurl = os.path.join(base, patchurl)
4751 patchurl = os.path.join(base, patchurl)
4752 ui.status(_('applying %s\n') % patchurl)
4752 ui.status(_('applying %s\n') % patchurl)
4753 patchfile = hg.openpath(ui, patchurl)
4753 patchfile = hg.openpath(ui, patchurl)
4754
4754
4755 haspatch = False
4755 haspatch = False
4756 for hunk in patch.split(patchfile):
4756 for hunk in patch.split(patchfile):
4757 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4757 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4758 parents, opts,
4758 parents, opts,
4759 msgs, hg.clean)
4759 msgs, hg.clean)
4760 if msg:
4760 if msg:
4761 haspatch = True
4761 haspatch = True
4762 ui.note(msg + '\n')
4762 ui.note(msg + '\n')
4763 if update or exact:
4763 if update or exact:
4764 parents = repo[None].parents()
4764 parents = repo[None].parents()
4765 else:
4765 else:
4766 parents = [repo[node]]
4766 parents = [repo[node]]
4767 if rej:
4767 if rej:
4768 ui.write_err(_("patch applied partially\n"))
4768 ui.write_err(_("patch applied partially\n"))
4769 ui.write_err(_("(fix the .rej files and run "
4769 ui.write_err(_("(fix the .rej files and run "
4770 "`hg commit --amend`)\n"))
4770 "`hg commit --amend`)\n"))
4771 ret = 1
4771 ret = 1
4772 break
4772 break
4773
4773
4774 if not haspatch:
4774 if not haspatch:
4775 raise error.Abort(_('%s: no diffs found') % patchurl)
4775 raise error.Abort(_('%s: no diffs found') % patchurl)
4776
4776
4777 if tr:
4777 if tr:
4778 tr.close()
4778 tr.close()
4779 if msgs:
4779 if msgs:
4780 repo.savecommitmessage('\n* * *\n'.join(msgs))
4780 repo.savecommitmessage('\n* * *\n'.join(msgs))
4781 if dsguard:
4781 if dsguard:
4782 dsguard.close()
4782 dsguard.close()
4783 return ret
4783 return ret
4784 finally:
4784 finally:
4785 if tr:
4785 if tr:
4786 tr.release()
4786 tr.release()
4787 release(lock, dsguard, wlock)
4787 release(lock, dsguard, wlock)
4788
4788
4789 @command('incoming|in',
4789 @command('incoming|in',
4790 [('f', 'force', None,
4790 [('f', 'force', None,
4791 _('run even if remote repository is unrelated')),
4791 _('run even if remote repository is unrelated')),
4792 ('n', 'newest-first', None, _('show newest record first')),
4792 ('n', 'newest-first', None, _('show newest record first')),
4793 ('', 'bundle', '',
4793 ('', 'bundle', '',
4794 _('file to store the bundles into'), _('FILE')),
4794 _('file to store the bundles into'), _('FILE')),
4795 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4795 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4796 ('B', 'bookmarks', False, _("compare bookmarks")),
4796 ('B', 'bookmarks', False, _("compare bookmarks")),
4797 ('b', 'branch', [],
4797 ('b', 'branch', [],
4798 _('a specific branch you would like to pull'), _('BRANCH')),
4798 _('a specific branch you would like to pull'), _('BRANCH')),
4799 ] + logopts + remoteopts + subrepoopts,
4799 ] + logopts + remoteopts + subrepoopts,
4800 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4800 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4801 def incoming(ui, repo, source="default", **opts):
4801 def incoming(ui, repo, source="default", **opts):
4802 """show new changesets found in source
4802 """show new changesets found in source
4803
4803
4804 Show new changesets found in the specified path/URL or the default
4804 Show new changesets found in the specified path/URL or the default
4805 pull location. These are the changesets that would have been pulled
4805 pull location. These are the changesets that would have been pulled
4806 if a pull at the time you issued this command.
4806 if a pull at the time you issued this command.
4807
4807
4808 See pull for valid source format details.
4808 See pull for valid source format details.
4809
4809
4810 .. container:: verbose
4810 .. container:: verbose
4811
4811
4812 With -B/--bookmarks, the result of bookmark comparison between
4812 With -B/--bookmarks, the result of bookmark comparison between
4813 local and remote repositories is displayed. With -v/--verbose,
4813 local and remote repositories is displayed. With -v/--verbose,
4814 status is also displayed for each bookmark like below::
4814 status is also displayed for each bookmark like below::
4815
4815
4816 BM1 01234567890a added
4816 BM1 01234567890a added
4817 BM2 1234567890ab advanced
4817 BM2 1234567890ab advanced
4818 BM3 234567890abc diverged
4818 BM3 234567890abc diverged
4819 BM4 34567890abcd changed
4819 BM4 34567890abcd changed
4820
4820
4821 The action taken locally when pulling depends on the
4821 The action taken locally when pulling depends on the
4822 status of each bookmark:
4822 status of each bookmark:
4823
4823
4824 :``added``: pull will create it
4824 :``added``: pull will create it
4825 :``advanced``: pull will update it
4825 :``advanced``: pull will update it
4826 :``diverged``: pull will create a divergent bookmark
4826 :``diverged``: pull will create a divergent bookmark
4827 :``changed``: result depends on remote changesets
4827 :``changed``: result depends on remote changesets
4828
4828
4829 From the point of view of pulling behavior, bookmark
4829 From the point of view of pulling behavior, bookmark
4830 existing only in the remote repository are treated as ``added``,
4830 existing only in the remote repository are treated as ``added``,
4831 even if it is in fact locally deleted.
4831 even if it is in fact locally deleted.
4832
4832
4833 .. container:: verbose
4833 .. container:: verbose
4834
4834
4835 For remote repository, using --bundle avoids downloading the
4835 For remote repository, using --bundle avoids downloading the
4836 changesets twice if the incoming is followed by a pull.
4836 changesets twice if the incoming is followed by a pull.
4837
4837
4838 Examples:
4838 Examples:
4839
4839
4840 - show incoming changes with patches and full description::
4840 - show incoming changes with patches and full description::
4841
4841
4842 hg incoming -vp
4842 hg incoming -vp
4843
4843
4844 - show incoming changes excluding merges, store a bundle::
4844 - show incoming changes excluding merges, store a bundle::
4845
4845
4846 hg in -vpM --bundle incoming.hg
4846 hg in -vpM --bundle incoming.hg
4847 hg pull incoming.hg
4847 hg pull incoming.hg
4848
4848
4849 - briefly list changes inside a bundle::
4849 - briefly list changes inside a bundle::
4850
4850
4851 hg in changes.hg -T "{desc|firstline}\\n"
4851 hg in changes.hg -T "{desc|firstline}\\n"
4852
4852
4853 Returns 0 if there are incoming changes, 1 otherwise.
4853 Returns 0 if there are incoming changes, 1 otherwise.
4854 """
4854 """
4855 if opts.get('graph'):
4855 if opts.get('graph'):
4856 cmdutil.checkunsupportedgraphflags([], opts)
4856 cmdutil.checkunsupportedgraphflags([], opts)
4857 def display(other, chlist, displayer):
4857 def display(other, chlist, displayer):
4858 revdag = cmdutil.graphrevs(other, chlist, opts)
4858 revdag = cmdutil.graphrevs(other, chlist, opts)
4859 cmdutil.displaygraph(ui, repo, revdag, displayer,
4859 cmdutil.displaygraph(ui, repo, revdag, displayer,
4860 graphmod.asciiedges)
4860 graphmod.asciiedges)
4861
4861
4862 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4862 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4863 return 0
4863 return 0
4864
4864
4865 if opts.get('bundle') and opts.get('subrepos'):
4865 if opts.get('bundle') and opts.get('subrepos'):
4866 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4866 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4867
4867
4868 if opts.get('bookmarks'):
4868 if opts.get('bookmarks'):
4869 source, branches = hg.parseurl(ui.expandpath(source),
4869 source, branches = hg.parseurl(ui.expandpath(source),
4870 opts.get('branch'))
4870 opts.get('branch'))
4871 other = hg.peer(repo, opts, source)
4871 other = hg.peer(repo, opts, source)
4872 if 'bookmarks' not in other.listkeys('namespaces'):
4872 if 'bookmarks' not in other.listkeys('namespaces'):
4873 ui.warn(_("remote doesn't support bookmarks\n"))
4873 ui.warn(_("remote doesn't support bookmarks\n"))
4874 return 0
4874 return 0
4875 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4875 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4876 return bookmarks.incoming(ui, repo, other)
4876 return bookmarks.incoming(ui, repo, other)
4877
4877
4878 repo._subtoppath = ui.expandpath(source)
4878 repo._subtoppath = ui.expandpath(source)
4879 try:
4879 try:
4880 return hg.incoming(ui, repo, source, opts)
4880 return hg.incoming(ui, repo, source, opts)
4881 finally:
4881 finally:
4882 del repo._subtoppath
4882 del repo._subtoppath
4883
4883
4884
4884
4885 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4885 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4886 norepo=True)
4886 norepo=True)
4887 def init(ui, dest=".", **opts):
4887 def init(ui, dest=".", **opts):
4888 """create a new repository in the given directory
4888 """create a new repository in the given directory
4889
4889
4890 Initialize a new repository in the given directory. If the given
4890 Initialize a new repository in the given directory. If the given
4891 directory does not exist, it will be created.
4891 directory does not exist, it will be created.
4892
4892
4893 If no directory is given, the current directory is used.
4893 If no directory is given, the current directory is used.
4894
4894
4895 It is possible to specify an ``ssh://`` URL as the destination.
4895 It is possible to specify an ``ssh://`` URL as the destination.
4896 See :hg:`help urls` for more information.
4896 See :hg:`help urls` for more information.
4897
4897
4898 Returns 0 on success.
4898 Returns 0 on success.
4899 """
4899 """
4900 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4900 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4901
4901
4902 @command('locate',
4902 @command('locate',
4903 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4903 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4904 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4904 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4905 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4905 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4906 ] + walkopts,
4906 ] + walkopts,
4907 _('[OPTION]... [PATTERN]...'))
4907 _('[OPTION]... [PATTERN]...'))
4908 def locate(ui, repo, *pats, **opts):
4908 def locate(ui, repo, *pats, **opts):
4909 """locate files matching specific patterns (DEPRECATED)
4909 """locate files matching specific patterns (DEPRECATED)
4910
4910
4911 Print files under Mercurial control in the working directory whose
4911 Print files under Mercurial control in the working directory whose
4912 names match the given patterns.
4912 names match the given patterns.
4913
4913
4914 By default, this command searches all directories in the working
4914 By default, this command searches all directories in the working
4915 directory. To search just the current directory and its
4915 directory. To search just the current directory and its
4916 subdirectories, use "--include .".
4916 subdirectories, use "--include .".
4917
4917
4918 If no patterns are given to match, this command prints the names
4918 If no patterns are given to match, this command prints the names
4919 of all files under Mercurial control in the working directory.
4919 of all files under Mercurial control in the working directory.
4920
4920
4921 If you want to feed the output of this command into the "xargs"
4921 If you want to feed the output of this command into the "xargs"
4922 command, use the -0 option to both this command and "xargs". This
4922 command, use the -0 option to both this command and "xargs". This
4923 will avoid the problem of "xargs" treating single filenames that
4923 will avoid the problem of "xargs" treating single filenames that
4924 contain whitespace as multiple filenames.
4924 contain whitespace as multiple filenames.
4925
4925
4926 See :hg:`help files` for a more versatile command.
4926 See :hg:`help files` for a more versatile command.
4927
4927
4928 Returns 0 if a match is found, 1 otherwise.
4928 Returns 0 if a match is found, 1 otherwise.
4929 """
4929 """
4930 if opts.get('print0'):
4930 if opts.get('print0'):
4931 end = '\0'
4931 end = '\0'
4932 else:
4932 else:
4933 end = '\n'
4933 end = '\n'
4934 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4934 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4935
4935
4936 ret = 1
4936 ret = 1
4937 ctx = repo[rev]
4937 ctx = repo[rev]
4938 m = scmutil.match(ctx, pats, opts, default='relglob',
4938 m = scmutil.match(ctx, pats, opts, default='relglob',
4939 badfn=lambda x, y: False)
4939 badfn=lambda x, y: False)
4940
4940
4941 for abs in ctx.matches(m):
4941 for abs in ctx.matches(m):
4942 if opts.get('fullpath'):
4942 if opts.get('fullpath'):
4943 ui.write(repo.wjoin(abs), end)
4943 ui.write(repo.wjoin(abs), end)
4944 else:
4944 else:
4945 ui.write(((pats and m.rel(abs)) or abs), end)
4945 ui.write(((pats and m.rel(abs)) or abs), end)
4946 ret = 0
4946 ret = 0
4947
4947
4948 return ret
4948 return ret
4949
4949
4950 @command('^log|history',
4950 @command('^log|history',
4951 [('f', 'follow', None,
4951 [('f', 'follow', None,
4952 _('follow changeset history, or file history across copies and renames')),
4952 _('follow changeset history, or file history across copies and renames')),
4953 ('', 'follow-first', None,
4953 ('', 'follow-first', None,
4954 _('only follow the first parent of merge changesets (DEPRECATED)')),
4954 _('only follow the first parent of merge changesets (DEPRECATED)')),
4955 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4955 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4956 ('C', 'copies', None, _('show copied files')),
4956 ('C', 'copies', None, _('show copied files')),
4957 ('k', 'keyword', [],
4957 ('k', 'keyword', [],
4958 _('do case-insensitive search for a given text'), _('TEXT')),
4958 _('do case-insensitive search for a given text'), _('TEXT')),
4959 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4959 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4960 ('', 'removed', None, _('include revisions where files were removed')),
4960 ('', 'removed', None, _('include revisions where files were removed')),
4961 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4961 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4962 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4962 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4963 ('', 'only-branch', [],
4963 ('', 'only-branch', [],
4964 _('show only changesets within the given named branch (DEPRECATED)'),
4964 _('show only changesets within the given named branch (DEPRECATED)'),
4965 _('BRANCH')),
4965 _('BRANCH')),
4966 ('b', 'branch', [],
4966 ('b', 'branch', [],
4967 _('show changesets within the given named branch'), _('BRANCH')),
4967 _('show changesets within the given named branch'), _('BRANCH')),
4968 ('P', 'prune', [],
4968 ('P', 'prune', [],
4969 _('do not display revision or any of its ancestors'), _('REV')),
4969 _('do not display revision or any of its ancestors'), _('REV')),
4970 ] + logopts + walkopts,
4970 ] + logopts + walkopts,
4971 _('[OPTION]... [FILE]'),
4971 _('[OPTION]... [FILE]'),
4972 inferrepo=True)
4972 inferrepo=True)
4973 def log(ui, repo, *pats, **opts):
4973 def log(ui, repo, *pats, **opts):
4974 """show revision history of entire repository or files
4974 """show revision history of entire repository or files
4975
4975
4976 Print the revision history of the specified files or the entire
4976 Print the revision history of the specified files or the entire
4977 project.
4977 project.
4978
4978
4979 If no revision range is specified, the default is ``tip:0`` unless
4979 If no revision range is specified, the default is ``tip:0`` unless
4980 --follow is set, in which case the working directory parent is
4980 --follow is set, in which case the working directory parent is
4981 used as the starting revision.
4981 used as the starting revision.
4982
4982
4983 File history is shown without following rename or copy history of
4983 File history is shown without following rename or copy history of
4984 files. Use -f/--follow with a filename to follow history across
4984 files. Use -f/--follow with a filename to follow history across
4985 renames and copies. --follow without a filename will only show
4985 renames and copies. --follow without a filename will only show
4986 ancestors or descendants of the starting revision.
4986 ancestors or descendants of the starting revision.
4987
4987
4988 By default this command prints revision number and changeset id,
4988 By default this command prints revision number and changeset id,
4989 tags, non-trivial parents, user, date and time, and a summary for
4989 tags, non-trivial parents, user, date and time, and a summary for
4990 each commit. When the -v/--verbose switch is used, the list of
4990 each commit. When the -v/--verbose switch is used, the list of
4991 changed files and full commit message are shown.
4991 changed files and full commit message are shown.
4992
4992
4993 With --graph the revisions are shown as an ASCII art DAG with the most
4993 With --graph the revisions are shown as an ASCII art DAG with the most
4994 recent changeset at the top.
4994 recent changeset at the top.
4995 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4995 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4996 and '+' represents a fork where the changeset from the lines below is a
4996 and '+' represents a fork where the changeset from the lines below is a
4997 parent of the 'o' merge on the same line.
4997 parent of the 'o' merge on the same line.
4998
4998
4999 .. note::
4999 .. note::
5000
5000
5001 :hg:`log --patch` may generate unexpected diff output for merge
5001 :hg:`log --patch` may generate unexpected diff output for merge
5002 changesets, as it will only compare the merge changeset against
5002 changesets, as it will only compare the merge changeset against
5003 its first parent. Also, only files different from BOTH parents
5003 its first parent. Also, only files different from BOTH parents
5004 will appear in files:.
5004 will appear in files:.
5005
5005
5006 .. note::
5006 .. note::
5007
5007
5008 For performance reasons, :hg:`log FILE` may omit duplicate changes
5008 For performance reasons, :hg:`log FILE` may omit duplicate changes
5009 made on branches and will not show removals or mode changes. To
5009 made on branches and will not show removals or mode changes. To
5010 see all such changes, use the --removed switch.
5010 see all such changes, use the --removed switch.
5011
5011
5012 .. container:: verbose
5012 .. container:: verbose
5013
5013
5014 Some examples:
5014 Some examples:
5015
5015
5016 - changesets with full descriptions and file lists::
5016 - changesets with full descriptions and file lists::
5017
5017
5018 hg log -v
5018 hg log -v
5019
5019
5020 - changesets ancestral to the working directory::
5020 - changesets ancestral to the working directory::
5021
5021
5022 hg log -f
5022 hg log -f
5023
5023
5024 - last 10 commits on the current branch::
5024 - last 10 commits on the current branch::
5025
5025
5026 hg log -l 10 -b .
5026 hg log -l 10 -b .
5027
5027
5028 - changesets showing all modifications of a file, including removals::
5028 - changesets showing all modifications of a file, including removals::
5029
5029
5030 hg log --removed file.c
5030 hg log --removed file.c
5031
5031
5032 - all changesets that touch a directory, with diffs, excluding merges::
5032 - all changesets that touch a directory, with diffs, excluding merges::
5033
5033
5034 hg log -Mp lib/
5034 hg log -Mp lib/
5035
5035
5036 - all revision numbers that match a keyword::
5036 - all revision numbers that match a keyword::
5037
5037
5038 hg log -k bug --template "{rev}\\n"
5038 hg log -k bug --template "{rev}\\n"
5039
5039
5040 - the full hash identifier of the working directory parent::
5040 - the full hash identifier of the working directory parent::
5041
5041
5042 hg log -r . --template "{node}\\n"
5042 hg log -r . --template "{node}\\n"
5043
5043
5044 - list available log templates::
5044 - list available log templates::
5045
5045
5046 hg log -T list
5046 hg log -T list
5047
5047
5048 - check if a given changeset is included in a tagged release::
5048 - check if a given changeset is included in a tagged release::
5049
5049
5050 hg log -r "a21ccf and ancestor(1.9)"
5050 hg log -r "a21ccf and ancestor(1.9)"
5051
5051
5052 - find all changesets by some user in a date range::
5052 - find all changesets by some user in a date range::
5053
5053
5054 hg log -k alice -d "may 2008 to jul 2008"
5054 hg log -k alice -d "may 2008 to jul 2008"
5055
5055
5056 - summary of all changesets after the last tag::
5056 - summary of all changesets after the last tag::
5057
5057
5058 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5058 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5059
5059
5060 See :hg:`help dates` for a list of formats valid for -d/--date.
5060 See :hg:`help dates` for a list of formats valid for -d/--date.
5061
5061
5062 See :hg:`help revisions` and :hg:`help revsets` for more about
5062 See :hg:`help revisions` and :hg:`help revsets` for more about
5063 specifying and ordering revisions.
5063 specifying and ordering revisions.
5064
5064
5065 See :hg:`help templates` for more about pre-packaged styles and
5065 See :hg:`help templates` for more about pre-packaged styles and
5066 specifying custom templates.
5066 specifying custom templates.
5067
5067
5068 Returns 0 on success.
5068 Returns 0 on success.
5069
5069
5070 """
5070 """
5071 if opts.get('follow') and opts.get('rev'):
5071 if opts.get('follow') and opts.get('rev'):
5072 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5072 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5073 del opts['follow']
5073 del opts['follow']
5074
5074
5075 if opts.get('graph'):
5075 if opts.get('graph'):
5076 return cmdutil.graphlog(ui, repo, *pats, **opts)
5076 return cmdutil.graphlog(ui, repo, *pats, **opts)
5077
5077
5078 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5078 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5079 limit = cmdutil.loglimit(opts)
5079 limit = cmdutil.loglimit(opts)
5080 count = 0
5080 count = 0
5081
5081
5082 getrenamed = None
5082 getrenamed = None
5083 if opts.get('copies'):
5083 if opts.get('copies'):
5084 endrev = None
5084 endrev = None
5085 if opts.get('rev'):
5085 if opts.get('rev'):
5086 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5086 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5087 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5087 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5088
5088
5089 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5089 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5090 for rev in revs:
5090 for rev in revs:
5091 if count == limit:
5091 if count == limit:
5092 break
5092 break
5093 ctx = repo[rev]
5093 ctx = repo[rev]
5094 copies = None
5094 copies = None
5095 if getrenamed is not None and rev:
5095 if getrenamed is not None and rev:
5096 copies = []
5096 copies = []
5097 for fn in ctx.files():
5097 for fn in ctx.files():
5098 rename = getrenamed(fn, rev)
5098 rename = getrenamed(fn, rev)
5099 if rename:
5099 if rename:
5100 copies.append((fn, rename[0]))
5100 copies.append((fn, rename[0]))
5101 if filematcher:
5101 if filematcher:
5102 revmatchfn = filematcher(ctx.rev())
5102 revmatchfn = filematcher(ctx.rev())
5103 else:
5103 else:
5104 revmatchfn = None
5104 revmatchfn = None
5105 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5105 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5106 if displayer.flush(ctx):
5106 if displayer.flush(ctx):
5107 count += 1
5107 count += 1
5108
5108
5109 displayer.close()
5109 displayer.close()
5110
5110
5111 @command('manifest',
5111 @command('manifest',
5112 [('r', 'rev', '', _('revision to display'), _('REV')),
5112 [('r', 'rev', '', _('revision to display'), _('REV')),
5113 ('', 'all', False, _("list files from all revisions"))]
5113 ('', 'all', False, _("list files from all revisions"))]
5114 + formatteropts,
5114 + formatteropts,
5115 _('[-r REV]'))
5115 _('[-r REV]'))
5116 def manifest(ui, repo, node=None, rev=None, **opts):
5116 def manifest(ui, repo, node=None, rev=None, **opts):
5117 """output the current or given revision of the project manifest
5117 """output the current or given revision of the project manifest
5118
5118
5119 Print a list of version controlled files for the given revision.
5119 Print a list of version controlled files for the given revision.
5120 If no revision is given, the first parent of the working directory
5120 If no revision is given, the first parent of the working directory
5121 is used, or the null revision if no revision is checked out.
5121 is used, or the null revision if no revision is checked out.
5122
5122
5123 With -v, print file permissions, symlink and executable bits.
5123 With -v, print file permissions, symlink and executable bits.
5124 With --debug, print file revision hashes.
5124 With --debug, print file revision hashes.
5125
5125
5126 If option --all is specified, the list of all files from all revisions
5126 If option --all is specified, the list of all files from all revisions
5127 is printed. This includes deleted and renamed files.
5127 is printed. This includes deleted and renamed files.
5128
5128
5129 Returns 0 on success.
5129 Returns 0 on success.
5130 """
5130 """
5131
5131
5132 fm = ui.formatter('manifest', opts)
5132 fm = ui.formatter('manifest', opts)
5133
5133
5134 if opts.get('all'):
5134 if opts.get('all'):
5135 if rev or node:
5135 if rev or node:
5136 raise error.Abort(_("can't specify a revision with --all"))
5136 raise error.Abort(_("can't specify a revision with --all"))
5137
5137
5138 res = []
5138 res = []
5139 prefix = "data/"
5139 prefix = "data/"
5140 suffix = ".i"
5140 suffix = ".i"
5141 plen = len(prefix)
5141 plen = len(prefix)
5142 slen = len(suffix)
5142 slen = len(suffix)
5143 with repo.lock():
5143 with repo.lock():
5144 for fn, b, size in repo.store.datafiles():
5144 for fn, b, size in repo.store.datafiles():
5145 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5145 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5146 res.append(fn[plen:-slen])
5146 res.append(fn[plen:-slen])
5147 for f in res:
5147 for f in res:
5148 fm.startitem()
5148 fm.startitem()
5149 fm.write("path", '%s\n', f)
5149 fm.write("path", '%s\n', f)
5150 fm.end()
5150 fm.end()
5151 return
5151 return
5152
5152
5153 if rev and node:
5153 if rev and node:
5154 raise error.Abort(_("please specify just one revision"))
5154 raise error.Abort(_("please specify just one revision"))
5155
5155
5156 if not node:
5156 if not node:
5157 node = rev
5157 node = rev
5158
5158
5159 char = {'l': '@', 'x': '*', '': ''}
5159 char = {'l': '@', 'x': '*', '': ''}
5160 mode = {'l': '644', 'x': '755', '': '644'}
5160 mode = {'l': '644', 'x': '755', '': '644'}
5161 ctx = scmutil.revsingle(repo, node)
5161 ctx = scmutil.revsingle(repo, node)
5162 mf = ctx.manifest()
5162 mf = ctx.manifest()
5163 for f in ctx:
5163 for f in ctx:
5164 fm.startitem()
5164 fm.startitem()
5165 fl = ctx[f].flags()
5165 fl = ctx[f].flags()
5166 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5166 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5167 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5167 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5168 fm.write('path', '%s\n', f)
5168 fm.write('path', '%s\n', f)
5169 fm.end()
5169 fm.end()
5170
5170
5171 @command('^merge',
5171 @command('^merge',
5172 [('f', 'force', None,
5172 [('f', 'force', None,
5173 _('force a merge including outstanding changes (DEPRECATED)')),
5173 _('force a merge including outstanding changes (DEPRECATED)')),
5174 ('r', 'rev', '', _('revision to merge'), _('REV')),
5174 ('r', 'rev', '', _('revision to merge'), _('REV')),
5175 ('P', 'preview', None,
5175 ('P', 'preview', None,
5176 _('review revisions to merge (no merge is performed)'))
5176 _('review revisions to merge (no merge is performed)'))
5177 ] + mergetoolopts,
5177 ] + mergetoolopts,
5178 _('[-P] [-f] [[-r] REV]'))
5178 _('[-P] [-f] [[-r] REV]'))
5179 def merge(ui, repo, node=None, **opts):
5179 def merge(ui, repo, node=None, **opts):
5180 """merge another revision into working directory
5180 """merge another revision into working directory
5181
5181
5182 The current working directory is updated with all changes made in
5182 The current working directory is updated with all changes made in
5183 the requested revision since the last common predecessor revision.
5183 the requested revision since the last common predecessor revision.
5184
5184
5185 Files that changed between either parent are marked as changed for
5185 Files that changed between either parent are marked as changed for
5186 the next commit and a commit must be performed before any further
5186 the next commit and a commit must be performed before any further
5187 updates to the repository are allowed. The next commit will have
5187 updates to the repository are allowed. The next commit will have
5188 two parents.
5188 two parents.
5189
5189
5190 ``--tool`` can be used to specify the merge tool used for file
5190 ``--tool`` can be used to specify the merge tool used for file
5191 merges. It overrides the HGMERGE environment variable and your
5191 merges. It overrides the HGMERGE environment variable and your
5192 configuration files. See :hg:`help merge-tools` for options.
5192 configuration files. See :hg:`help merge-tools` for options.
5193
5193
5194 If no revision is specified, the working directory's parent is a
5194 If no revision is specified, the working directory's parent is a
5195 head revision, and the current branch contains exactly one other
5195 head revision, and the current branch contains exactly one other
5196 head, the other head is merged with by default. Otherwise, an
5196 head, the other head is merged with by default. Otherwise, an
5197 explicit revision with which to merge with must be provided.
5197 explicit revision with which to merge with must be provided.
5198
5198
5199 See :hg:`help resolve` for information on handling file conflicts.
5199 See :hg:`help resolve` for information on handling file conflicts.
5200
5200
5201 To undo an uncommitted merge, use :hg:`update --clean .` which
5201 To undo an uncommitted merge, use :hg:`update --clean .` which
5202 will check out a clean copy of the original merge parent, losing
5202 will check out a clean copy of the original merge parent, losing
5203 all changes.
5203 all changes.
5204
5204
5205 Returns 0 on success, 1 if there are unresolved files.
5205 Returns 0 on success, 1 if there are unresolved files.
5206 """
5206 """
5207
5207
5208 if opts.get('rev') and node:
5208 if opts.get('rev') and node:
5209 raise error.Abort(_("please specify just one revision"))
5209 raise error.Abort(_("please specify just one revision"))
5210 if not node:
5210 if not node:
5211 node = opts.get('rev')
5211 node = opts.get('rev')
5212
5212
5213 if node:
5213 if node:
5214 node = scmutil.revsingle(repo, node).node()
5214 node = scmutil.revsingle(repo, node).node()
5215
5215
5216 if not node:
5216 if not node:
5217 node = repo[destutil.destmerge(repo)].node()
5217 node = repo[destutil.destmerge(repo)].node()
5218
5218
5219 if opts.get('preview'):
5219 if opts.get('preview'):
5220 # find nodes that are ancestors of p2 but not of p1
5220 # find nodes that are ancestors of p2 but not of p1
5221 p1 = repo.lookup('.')
5221 p1 = repo.lookup('.')
5222 p2 = repo.lookup(node)
5222 p2 = repo.lookup(node)
5223 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5223 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5224
5224
5225 displayer = cmdutil.show_changeset(ui, repo, opts)
5225 displayer = cmdutil.show_changeset(ui, repo, opts)
5226 for node in nodes:
5226 for node in nodes:
5227 displayer.show(repo[node])
5227 displayer.show(repo[node])
5228 displayer.close()
5228 displayer.close()
5229 return 0
5229 return 0
5230
5230
5231 try:
5231 try:
5232 # ui.forcemerge is an internal variable, do not document
5232 # ui.forcemerge is an internal variable, do not document
5233 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5233 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5234 return hg.merge(repo, node, force=opts.get('force'))
5234 return hg.merge(repo, node, force=opts.get('force'))
5235 finally:
5235 finally:
5236 ui.setconfig('ui', 'forcemerge', '', 'merge')
5236 ui.setconfig('ui', 'forcemerge', '', 'merge')
5237
5237
5238 @command('outgoing|out',
5238 @command('outgoing|out',
5239 [('f', 'force', None, _('run even when the destination is unrelated')),
5239 [('f', 'force', None, _('run even when the destination is unrelated')),
5240 ('r', 'rev', [],
5240 ('r', 'rev', [],
5241 _('a changeset intended to be included in the destination'), _('REV')),
5241 _('a changeset intended to be included in the destination'), _('REV')),
5242 ('n', 'newest-first', None, _('show newest record first')),
5242 ('n', 'newest-first', None, _('show newest record first')),
5243 ('B', 'bookmarks', False, _('compare bookmarks')),
5243 ('B', 'bookmarks', False, _('compare bookmarks')),
5244 ('b', 'branch', [], _('a specific branch you would like to push'),
5244 ('b', 'branch', [], _('a specific branch you would like to push'),
5245 _('BRANCH')),
5245 _('BRANCH')),
5246 ] + logopts + remoteopts + subrepoopts,
5246 ] + logopts + remoteopts + subrepoopts,
5247 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5247 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5248 def outgoing(ui, repo, dest=None, **opts):
5248 def outgoing(ui, repo, dest=None, **opts):
5249 """show changesets not found in the destination
5249 """show changesets not found in the destination
5250
5250
5251 Show changesets not found in the specified destination repository
5251 Show changesets not found in the specified destination repository
5252 or the default push location. These are the changesets that would
5252 or the default push location. These are the changesets that would
5253 be pushed if a push was requested.
5253 be pushed if a push was requested.
5254
5254
5255 See pull for details of valid destination formats.
5255 See pull for details of valid destination formats.
5256
5256
5257 .. container:: verbose
5257 .. container:: verbose
5258
5258
5259 With -B/--bookmarks, the result of bookmark comparison between
5259 With -B/--bookmarks, the result of bookmark comparison between
5260 local and remote repositories is displayed. With -v/--verbose,
5260 local and remote repositories is displayed. With -v/--verbose,
5261 status is also displayed for each bookmark like below::
5261 status is also displayed for each bookmark like below::
5262
5262
5263 BM1 01234567890a added
5263 BM1 01234567890a added
5264 BM2 deleted
5264 BM2 deleted
5265 BM3 234567890abc advanced
5265 BM3 234567890abc advanced
5266 BM4 34567890abcd diverged
5266 BM4 34567890abcd diverged
5267 BM5 4567890abcde changed
5267 BM5 4567890abcde changed
5268
5268
5269 The action taken when pushing depends on the
5269 The action taken when pushing depends on the
5270 status of each bookmark:
5270 status of each bookmark:
5271
5271
5272 :``added``: push with ``-B`` will create it
5272 :``added``: push with ``-B`` will create it
5273 :``deleted``: push with ``-B`` will delete it
5273 :``deleted``: push with ``-B`` will delete it
5274 :``advanced``: push will update it
5274 :``advanced``: push will update it
5275 :``diverged``: push with ``-B`` will update it
5275 :``diverged``: push with ``-B`` will update it
5276 :``changed``: push with ``-B`` will update it
5276 :``changed``: push with ``-B`` will update it
5277
5277
5278 From the point of view of pushing behavior, bookmarks
5278 From the point of view of pushing behavior, bookmarks
5279 existing only in the remote repository are treated as
5279 existing only in the remote repository are treated as
5280 ``deleted``, even if it is in fact added remotely.
5280 ``deleted``, even if it is in fact added remotely.
5281
5281
5282 Returns 0 if there are outgoing changes, 1 otherwise.
5282 Returns 0 if there are outgoing changes, 1 otherwise.
5283 """
5283 """
5284 if opts.get('graph'):
5284 if opts.get('graph'):
5285 cmdutil.checkunsupportedgraphflags([], opts)
5285 cmdutil.checkunsupportedgraphflags([], opts)
5286 o, other = hg._outgoing(ui, repo, dest, opts)
5286 o, other = hg._outgoing(ui, repo, dest, opts)
5287 if not o:
5287 if not o:
5288 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5288 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5289 return
5289 return
5290
5290
5291 revdag = cmdutil.graphrevs(repo, o, opts)
5291 revdag = cmdutil.graphrevs(repo, o, opts)
5292 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5292 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5293 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5293 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5294 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5294 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5295 return 0
5295 return 0
5296
5296
5297 if opts.get('bookmarks'):
5297 if opts.get('bookmarks'):
5298 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5298 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5299 dest, branches = hg.parseurl(dest, opts.get('branch'))
5299 dest, branches = hg.parseurl(dest, opts.get('branch'))
5300 other = hg.peer(repo, opts, dest)
5300 other = hg.peer(repo, opts, dest)
5301 if 'bookmarks' not in other.listkeys('namespaces'):
5301 if 'bookmarks' not in other.listkeys('namespaces'):
5302 ui.warn(_("remote doesn't support bookmarks\n"))
5302 ui.warn(_("remote doesn't support bookmarks\n"))
5303 return 0
5303 return 0
5304 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5304 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5305 return bookmarks.outgoing(ui, repo, other)
5305 return bookmarks.outgoing(ui, repo, other)
5306
5306
5307 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5307 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5308 try:
5308 try:
5309 return hg.outgoing(ui, repo, dest, opts)
5309 return hg.outgoing(ui, repo, dest, opts)
5310 finally:
5310 finally:
5311 del repo._subtoppath
5311 del repo._subtoppath
5312
5312
5313 @command('parents',
5313 @command('parents',
5314 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5314 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5315 ] + templateopts,
5315 ] + templateopts,
5316 _('[-r REV] [FILE]'),
5316 _('[-r REV] [FILE]'),
5317 inferrepo=True)
5317 inferrepo=True)
5318 def parents(ui, repo, file_=None, **opts):
5318 def parents(ui, repo, file_=None, **opts):
5319 """show the parents of the working directory or revision (DEPRECATED)
5319 """show the parents of the working directory or revision (DEPRECATED)
5320
5320
5321 Print the working directory's parent revisions. If a revision is
5321 Print the working directory's parent revisions. If a revision is
5322 given via -r/--rev, the parent of that revision will be printed.
5322 given via -r/--rev, the parent of that revision will be printed.
5323 If a file argument is given, the revision in which the file was
5323 If a file argument is given, the revision in which the file was
5324 last changed (before the working directory revision or the
5324 last changed (before the working directory revision or the
5325 argument to --rev if given) is printed.
5325 argument to --rev if given) is printed.
5326
5326
5327 This command is equivalent to::
5327 This command is equivalent to::
5328
5328
5329 hg log -r "p1()+p2()" or
5329 hg log -r "p1()+p2()" or
5330 hg log -r "p1(REV)+p2(REV)" or
5330 hg log -r "p1(REV)+p2(REV)" or
5331 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5331 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5332 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5332 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5333
5333
5334 See :hg:`summary` and :hg:`help revsets` for related information.
5334 See :hg:`summary` and :hg:`help revsets` for related information.
5335
5335
5336 Returns 0 on success.
5336 Returns 0 on success.
5337 """
5337 """
5338
5338
5339 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5339 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5340
5340
5341 if file_:
5341 if file_:
5342 m = scmutil.match(ctx, (file_,), opts)
5342 m = scmutil.match(ctx, (file_,), opts)
5343 if m.anypats() or len(m.files()) != 1:
5343 if m.anypats() or len(m.files()) != 1:
5344 raise error.Abort(_('can only specify an explicit filename'))
5344 raise error.Abort(_('can only specify an explicit filename'))
5345 file_ = m.files()[0]
5345 file_ = m.files()[0]
5346 filenodes = []
5346 filenodes = []
5347 for cp in ctx.parents():
5347 for cp in ctx.parents():
5348 if not cp:
5348 if not cp:
5349 continue
5349 continue
5350 try:
5350 try:
5351 filenodes.append(cp.filenode(file_))
5351 filenodes.append(cp.filenode(file_))
5352 except error.LookupError:
5352 except error.LookupError:
5353 pass
5353 pass
5354 if not filenodes:
5354 if not filenodes:
5355 raise error.Abort(_("'%s' not found in manifest!") % file_)
5355 raise error.Abort(_("'%s' not found in manifest!") % file_)
5356 p = []
5356 p = []
5357 for fn in filenodes:
5357 for fn in filenodes:
5358 fctx = repo.filectx(file_, fileid=fn)
5358 fctx = repo.filectx(file_, fileid=fn)
5359 p.append(fctx.node())
5359 p.append(fctx.node())
5360 else:
5360 else:
5361 p = [cp.node() for cp in ctx.parents()]
5361 p = [cp.node() for cp in ctx.parents()]
5362
5362
5363 displayer = cmdutil.show_changeset(ui, repo, opts)
5363 displayer = cmdutil.show_changeset(ui, repo, opts)
5364 for n in p:
5364 for n in p:
5365 if n != nullid:
5365 if n != nullid:
5366 displayer.show(repo[n])
5366 displayer.show(repo[n])
5367 displayer.close()
5367 displayer.close()
5368
5368
5369 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5369 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5370 def paths(ui, repo, search=None, **opts):
5370 def paths(ui, repo, search=None, **opts):
5371 """show aliases for remote repositories
5371 """show aliases for remote repositories
5372
5372
5373 Show definition of symbolic path name NAME. If no name is given,
5373 Show definition of symbolic path name NAME. If no name is given,
5374 show definition of all available names.
5374 show definition of all available names.
5375
5375
5376 Option -q/--quiet suppresses all output when searching for NAME
5376 Option -q/--quiet suppresses all output when searching for NAME
5377 and shows only the path names when listing all definitions.
5377 and shows only the path names when listing all definitions.
5378
5378
5379 Path names are defined in the [paths] section of your
5379 Path names are defined in the [paths] section of your
5380 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5380 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5381 repository, ``.hg/hgrc`` is used, too.
5381 repository, ``.hg/hgrc`` is used, too.
5382
5382
5383 The path names ``default`` and ``default-push`` have a special
5383 The path names ``default`` and ``default-push`` have a special
5384 meaning. When performing a push or pull operation, they are used
5384 meaning. When performing a push or pull operation, they are used
5385 as fallbacks if no location is specified on the command-line.
5385 as fallbacks if no location is specified on the command-line.
5386 When ``default-push`` is set, it will be used for push and
5386 When ``default-push`` is set, it will be used for push and
5387 ``default`` will be used for pull; otherwise ``default`` is used
5387 ``default`` will be used for pull; otherwise ``default`` is used
5388 as the fallback for both. When cloning a repository, the clone
5388 as the fallback for both. When cloning a repository, the clone
5389 source is written as ``default`` in ``.hg/hgrc``.
5389 source is written as ``default`` in ``.hg/hgrc``.
5390
5390
5391 .. note::
5391 .. note::
5392
5392
5393 ``default`` and ``default-push`` apply to all inbound (e.g.
5393 ``default`` and ``default-push`` apply to all inbound (e.g.
5394 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5394 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5395 and :hg:`bundle`) operations.
5395 and :hg:`bundle`) operations.
5396
5396
5397 See :hg:`help urls` for more information.
5397 See :hg:`help urls` for more information.
5398
5398
5399 Returns 0 on success.
5399 Returns 0 on success.
5400 """
5400 """
5401 if search:
5401 if search:
5402 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5402 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5403 if name == search]
5403 if name == search]
5404 else:
5404 else:
5405 pathitems = sorted(ui.paths.iteritems())
5405 pathitems = sorted(ui.paths.iteritems())
5406
5406
5407 fm = ui.formatter('paths', opts)
5407 fm = ui.formatter('paths', opts)
5408 if fm:
5408 if fm:
5409 hidepassword = str
5409 hidepassword = str
5410 else:
5410 else:
5411 hidepassword = util.hidepassword
5411 hidepassword = util.hidepassword
5412 if ui.quiet:
5412 if ui.quiet:
5413 namefmt = '%s\n'
5413 namefmt = '%s\n'
5414 else:
5414 else:
5415 namefmt = '%s = '
5415 namefmt = '%s = '
5416 showsubopts = not search and not ui.quiet
5416 showsubopts = not search and not ui.quiet
5417
5417
5418 for name, path in pathitems:
5418 for name, path in pathitems:
5419 fm.startitem()
5419 fm.startitem()
5420 fm.condwrite(not search, 'name', namefmt, name)
5420 fm.condwrite(not search, 'name', namefmt, name)
5421 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5421 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5422 for subopt, value in sorted(path.suboptions.items()):
5422 for subopt, value in sorted(path.suboptions.items()):
5423 assert subopt not in ('name', 'url')
5423 assert subopt not in ('name', 'url')
5424 if showsubopts:
5424 if showsubopts:
5425 fm.plain('%s:%s = ' % (name, subopt))
5425 fm.plain('%s:%s = ' % (name, subopt))
5426 fm.condwrite(showsubopts, subopt, '%s\n', value)
5426 fm.condwrite(showsubopts, subopt, '%s\n', value)
5427
5427
5428 fm.end()
5428 fm.end()
5429
5429
5430 if search and not pathitems:
5430 if search and not pathitems:
5431 if not ui.quiet:
5431 if not ui.quiet:
5432 ui.warn(_("not found!\n"))
5432 ui.warn(_("not found!\n"))
5433 return 1
5433 return 1
5434 else:
5434 else:
5435 return 0
5435 return 0
5436
5436
5437 @command('phase',
5437 @command('phase',
5438 [('p', 'public', False, _('set changeset phase to public')),
5438 [('p', 'public', False, _('set changeset phase to public')),
5439 ('d', 'draft', False, _('set changeset phase to draft')),
5439 ('d', 'draft', False, _('set changeset phase to draft')),
5440 ('s', 'secret', False, _('set changeset phase to secret')),
5440 ('s', 'secret', False, _('set changeset phase to secret')),
5441 ('f', 'force', False, _('allow to move boundary backward')),
5441 ('f', 'force', False, _('allow to move boundary backward')),
5442 ('r', 'rev', [], _('target revision'), _('REV')),
5442 ('r', 'rev', [], _('target revision'), _('REV')),
5443 ],
5443 ],
5444 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5444 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5445 def phase(ui, repo, *revs, **opts):
5445 def phase(ui, repo, *revs, **opts):
5446 """set or show the current phase name
5446 """set or show the current phase name
5447
5447
5448 With no argument, show the phase name of the current revision(s).
5448 With no argument, show the phase name of the current revision(s).
5449
5449
5450 With one of -p/--public, -d/--draft or -s/--secret, change the
5450 With one of -p/--public, -d/--draft or -s/--secret, change the
5451 phase value of the specified revisions.
5451 phase value of the specified revisions.
5452
5452
5453 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5453 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5454 lower phase to an higher phase. Phases are ordered as follows::
5454 lower phase to an higher phase. Phases are ordered as follows::
5455
5455
5456 public < draft < secret
5456 public < draft < secret
5457
5457
5458 Returns 0 on success, 1 if some phases could not be changed.
5458 Returns 0 on success, 1 if some phases could not be changed.
5459
5459
5460 (For more information about the phases concept, see :hg:`help phases`.)
5460 (For more information about the phases concept, see :hg:`help phases`.)
5461 """
5461 """
5462 # search for a unique phase argument
5462 # search for a unique phase argument
5463 targetphase = None
5463 targetphase = None
5464 for idx, name in enumerate(phases.phasenames):
5464 for idx, name in enumerate(phases.phasenames):
5465 if opts[name]:
5465 if opts[name]:
5466 if targetphase is not None:
5466 if targetphase is not None:
5467 raise error.Abort(_('only one phase can be specified'))
5467 raise error.Abort(_('only one phase can be specified'))
5468 targetphase = idx
5468 targetphase = idx
5469
5469
5470 # look for specified revision
5470 # look for specified revision
5471 revs = list(revs)
5471 revs = list(revs)
5472 revs.extend(opts['rev'])
5472 revs.extend(opts['rev'])
5473 if not revs:
5473 if not revs:
5474 # display both parents as the second parent phase can influence
5474 # display both parents as the second parent phase can influence
5475 # the phase of a merge commit
5475 # the phase of a merge commit
5476 revs = [c.rev() for c in repo[None].parents()]
5476 revs = [c.rev() for c in repo[None].parents()]
5477
5477
5478 revs = scmutil.revrange(repo, revs)
5478 revs = scmutil.revrange(repo, revs)
5479
5479
5480 lock = None
5480 lock = None
5481 ret = 0
5481 ret = 0
5482 if targetphase is None:
5482 if targetphase is None:
5483 # display
5483 # display
5484 for r in revs:
5484 for r in revs:
5485 ctx = repo[r]
5485 ctx = repo[r]
5486 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5486 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5487 else:
5487 else:
5488 tr = None
5488 tr = None
5489 lock = repo.lock()
5489 lock = repo.lock()
5490 try:
5490 try:
5491 tr = repo.transaction("phase")
5491 tr = repo.transaction("phase")
5492 # set phase
5492 # set phase
5493 if not revs:
5493 if not revs:
5494 raise error.Abort(_('empty revision set'))
5494 raise error.Abort(_('empty revision set'))
5495 nodes = [repo[r].node() for r in revs]
5495 nodes = [repo[r].node() for r in revs]
5496 # moving revision from public to draft may hide them
5496 # moving revision from public to draft may hide them
5497 # We have to check result on an unfiltered repository
5497 # We have to check result on an unfiltered repository
5498 unfi = repo.unfiltered()
5498 unfi = repo.unfiltered()
5499 getphase = unfi._phasecache.phase
5499 getphase = unfi._phasecache.phase
5500 olddata = [getphase(unfi, r) for r in unfi]
5500 olddata = [getphase(unfi, r) for r in unfi]
5501 phases.advanceboundary(repo, tr, targetphase, nodes)
5501 phases.advanceboundary(repo, tr, targetphase, nodes)
5502 if opts['force']:
5502 if opts['force']:
5503 phases.retractboundary(repo, tr, targetphase, nodes)
5503 phases.retractboundary(repo, tr, targetphase, nodes)
5504 tr.close()
5504 tr.close()
5505 finally:
5505 finally:
5506 if tr is not None:
5506 if tr is not None:
5507 tr.release()
5507 tr.release()
5508 lock.release()
5508 lock.release()
5509 getphase = unfi._phasecache.phase
5509 getphase = unfi._phasecache.phase
5510 newdata = [getphase(unfi, r) for r in unfi]
5510 newdata = [getphase(unfi, r) for r in unfi]
5511 changes = sum(newdata[r] != olddata[r] for r in unfi)
5511 changes = sum(newdata[r] != olddata[r] for r in unfi)
5512 cl = unfi.changelog
5512 cl = unfi.changelog
5513 rejected = [n for n in nodes
5513 rejected = [n for n in nodes
5514 if newdata[cl.rev(n)] < targetphase]
5514 if newdata[cl.rev(n)] < targetphase]
5515 if rejected:
5515 if rejected:
5516 ui.warn(_('cannot move %i changesets to a higher '
5516 ui.warn(_('cannot move %i changesets to a higher '
5517 'phase, use --force\n') % len(rejected))
5517 'phase, use --force\n') % len(rejected))
5518 ret = 1
5518 ret = 1
5519 if changes:
5519 if changes:
5520 msg = _('phase changed for %i changesets\n') % changes
5520 msg = _('phase changed for %i changesets\n') % changes
5521 if ret:
5521 if ret:
5522 ui.status(msg)
5522 ui.status(msg)
5523 else:
5523 else:
5524 ui.note(msg)
5524 ui.note(msg)
5525 else:
5525 else:
5526 ui.warn(_('no phases changed\n'))
5526 ui.warn(_('no phases changed\n'))
5527 return ret
5527 return ret
5528
5528
5529 def postincoming(ui, repo, modheads, optupdate, checkout):
5529 def postincoming(ui, repo, modheads, optupdate, checkout):
5530 if modheads == 0:
5530 if modheads == 0:
5531 return
5531 return
5532 if optupdate:
5532 if optupdate:
5533 try:
5533 try:
5534 brev = checkout
5534 brev = checkout
5535 movemarkfrom = None
5535 movemarkfrom = None
5536 if not checkout:
5536 if not checkout:
5537 updata = destutil.destupdate(repo)
5537 updata = destutil.destupdate(repo)
5538 checkout, movemarkfrom, brev = updata
5538 checkout, movemarkfrom, brev = updata
5539 ret = hg.update(repo, checkout)
5539 ret = hg.update(repo, checkout)
5540 except error.UpdateAbort as inst:
5540 except error.UpdateAbort as inst:
5541 msg = _("not updating: %s") % str(inst)
5541 msg = _("not updating: %s") % str(inst)
5542 hint = inst.hint
5542 hint = inst.hint
5543 raise error.UpdateAbort(msg, hint=hint)
5543 raise error.UpdateAbort(msg, hint=hint)
5544 if not ret and movemarkfrom:
5544 if not ret and movemarkfrom:
5545 if movemarkfrom == repo['.'].node():
5545 if movemarkfrom == repo['.'].node():
5546 pass # no-op update
5546 pass # no-op update
5547 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5547 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5548 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5548 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5549 return ret
5549 return ret
5550 if modheads > 1:
5550 if modheads > 1:
5551 currentbranchheads = len(repo.branchheads())
5551 currentbranchheads = len(repo.branchheads())
5552 if currentbranchheads == modheads:
5552 if currentbranchheads == modheads:
5553 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5553 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5554 elif currentbranchheads > 1:
5554 elif currentbranchheads > 1:
5555 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5555 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5556 "merge)\n"))
5556 "merge)\n"))
5557 else:
5557 else:
5558 ui.status(_("(run 'hg heads' to see heads)\n"))
5558 ui.status(_("(run 'hg heads' to see heads)\n"))
5559 else:
5559 else:
5560 ui.status(_("(run 'hg update' to get a working copy)\n"))
5560 ui.status(_("(run 'hg update' to get a working copy)\n"))
5561
5561
5562 @command('^pull',
5562 @command('^pull',
5563 [('u', 'update', None,
5563 [('u', 'update', None,
5564 _('update to new branch head if changesets were pulled')),
5564 _('update to new branch head if changesets were pulled')),
5565 ('f', 'force', None, _('run even when remote repository is unrelated')),
5565 ('f', 'force', None, _('run even when remote repository is unrelated')),
5566 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5566 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5567 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5567 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5568 ('b', 'branch', [], _('a specific branch you would like to pull'),
5568 ('b', 'branch', [], _('a specific branch you would like to pull'),
5569 _('BRANCH')),
5569 _('BRANCH')),
5570 ] + remoteopts,
5570 ] + remoteopts,
5571 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5571 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5572 def pull(ui, repo, source="default", **opts):
5572 def pull(ui, repo, source="default", **opts):
5573 """pull changes from the specified source
5573 """pull changes from the specified source
5574
5574
5575 Pull changes from a remote repository to a local one.
5575 Pull changes from a remote repository to a local one.
5576
5576
5577 This finds all changes from the repository at the specified path
5577 This finds all changes from the repository at the specified path
5578 or URL and adds them to a local repository (the current one unless
5578 or URL and adds them to a local repository (the current one unless
5579 -R is specified). By default, this does not update the copy of the
5579 -R is specified). By default, this does not update the copy of the
5580 project in the working directory.
5580 project in the working directory.
5581
5581
5582 Use :hg:`incoming` if you want to see what would have been added
5582 Use :hg:`incoming` if you want to see what would have been added
5583 by a pull at the time you issued this command. If you then decide
5583 by a pull at the time you issued this command. If you then decide
5584 to add those changes to the repository, you should use :hg:`pull
5584 to add those changes to the repository, you should use :hg:`pull
5585 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5585 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5586
5586
5587 If SOURCE is omitted, the 'default' path will be used.
5587 If SOURCE is omitted, the 'default' path will be used.
5588 See :hg:`help urls` for more information.
5588 See :hg:`help urls` for more information.
5589
5589
5590 Returns 0 on success, 1 if an update had unresolved files.
5590 Returns 0 on success, 1 if an update had unresolved files.
5591 """
5591 """
5592 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5592 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5593 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5593 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5594 other = hg.peer(repo, opts, source)
5594 other = hg.peer(repo, opts, source)
5595 try:
5595 try:
5596 revs, checkout = hg.addbranchrevs(repo, other, branches,
5596 revs, checkout = hg.addbranchrevs(repo, other, branches,
5597 opts.get('rev'))
5597 opts.get('rev'))
5598
5598
5599
5599
5600 pullopargs = {}
5600 pullopargs = {}
5601 if opts.get('bookmark'):
5601 if opts.get('bookmark'):
5602 if not revs:
5602 if not revs:
5603 revs = []
5603 revs = []
5604 # The list of bookmark used here is not the one used to actually
5604 # The list of bookmark used here is not the one used to actually
5605 # update the bookmark name. This can result in the revision pulled
5605 # update the bookmark name. This can result in the revision pulled
5606 # not ending up with the name of the bookmark because of a race
5606 # not ending up with the name of the bookmark because of a race
5607 # condition on the server. (See issue 4689 for details)
5607 # condition on the server. (See issue 4689 for details)
5608 remotebookmarks = other.listkeys('bookmarks')
5608 remotebookmarks = other.listkeys('bookmarks')
5609 pullopargs['remotebookmarks'] = remotebookmarks
5609 pullopargs['remotebookmarks'] = remotebookmarks
5610 for b in opts['bookmark']:
5610 for b in opts['bookmark']:
5611 if b not in remotebookmarks:
5611 if b not in remotebookmarks:
5612 raise error.Abort(_('remote bookmark %s not found!') % b)
5612 raise error.Abort(_('remote bookmark %s not found!') % b)
5613 revs.append(remotebookmarks[b])
5613 revs.append(remotebookmarks[b])
5614
5614
5615 if revs:
5615 if revs:
5616 try:
5616 try:
5617 # When 'rev' is a bookmark name, we cannot guarantee that it
5617 # When 'rev' is a bookmark name, we cannot guarantee that it
5618 # will be updated with that name because of a race condition
5618 # will be updated with that name because of a race condition
5619 # server side. (See issue 4689 for details)
5619 # server side. (See issue 4689 for details)
5620 oldrevs = revs
5620 oldrevs = revs
5621 revs = [] # actually, nodes
5621 revs = [] # actually, nodes
5622 for r in oldrevs:
5622 for r in oldrevs:
5623 node = other.lookup(r)
5623 node = other.lookup(r)
5624 revs.append(node)
5624 revs.append(node)
5625 if r == checkout:
5625 if r == checkout:
5626 checkout = node
5626 checkout = node
5627 except error.CapabilityError:
5627 except error.CapabilityError:
5628 err = _("other repository doesn't support revision lookup, "
5628 err = _("other repository doesn't support revision lookup, "
5629 "so a rev cannot be specified.")
5629 "so a rev cannot be specified.")
5630 raise error.Abort(err)
5630 raise error.Abort(err)
5631
5631
5632 pullopargs.update(opts.get('opargs', {}))
5632 pullopargs.update(opts.get('opargs', {}))
5633 modheads = exchange.pull(repo, other, heads=revs,
5633 modheads = exchange.pull(repo, other, heads=revs,
5634 force=opts.get('force'),
5634 force=opts.get('force'),
5635 bookmarks=opts.get('bookmark', ()),
5635 bookmarks=opts.get('bookmark', ()),
5636 opargs=pullopargs).cgresult
5636 opargs=pullopargs).cgresult
5637 if checkout:
5637 if checkout:
5638 checkout = str(repo.changelog.rev(checkout))
5638 checkout = str(repo.changelog.rev(checkout))
5639 repo._subtoppath = source
5639 repo._subtoppath = source
5640 try:
5640 try:
5641 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5641 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5642
5642
5643 finally:
5643 finally:
5644 del repo._subtoppath
5644 del repo._subtoppath
5645
5645
5646 finally:
5646 finally:
5647 other.close()
5647 other.close()
5648 return ret
5648 return ret
5649
5649
5650 @command('^push',
5650 @command('^push',
5651 [('f', 'force', None, _('force push')),
5651 [('f', 'force', None, _('force push')),
5652 ('r', 'rev', [],
5652 ('r', 'rev', [],
5653 _('a changeset intended to be included in the destination'),
5653 _('a changeset intended to be included in the destination'),
5654 _('REV')),
5654 _('REV')),
5655 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5655 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5656 ('b', 'branch', [],
5656 ('b', 'branch', [],
5657 _('a specific branch you would like to push'), _('BRANCH')),
5657 _('a specific branch you would like to push'), _('BRANCH')),
5658 ('', 'new-branch', False, _('allow pushing a new branch')),
5658 ('', 'new-branch', False, _('allow pushing a new branch')),
5659 ] + remoteopts,
5659 ] + remoteopts,
5660 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5660 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5661 def push(ui, repo, dest=None, **opts):
5661 def push(ui, repo, dest=None, **opts):
5662 """push changes to the specified destination
5662 """push changes to the specified destination
5663
5663
5664 Push changesets from the local repository to the specified
5664 Push changesets from the local repository to the specified
5665 destination.
5665 destination.
5666
5666
5667 This operation is symmetrical to pull: it is identical to a pull
5667 This operation is symmetrical to pull: it is identical to a pull
5668 in the destination repository from the current one.
5668 in the destination repository from the current one.
5669
5669
5670 By default, push will not allow creation of new heads at the
5670 By default, push will not allow creation of new heads at the
5671 destination, since multiple heads would make it unclear which head
5671 destination, since multiple heads would make it unclear which head
5672 to use. In this situation, it is recommended to pull and merge
5672 to use. In this situation, it is recommended to pull and merge
5673 before pushing.
5673 before pushing.
5674
5674
5675 Use --new-branch if you want to allow push to create a new named
5675 Use --new-branch if you want to allow push to create a new named
5676 branch that is not present at the destination. This allows you to
5676 branch that is not present at the destination. This allows you to
5677 only create a new branch without forcing other changes.
5677 only create a new branch without forcing other changes.
5678
5678
5679 .. note::
5679 .. note::
5680
5680
5681 Extra care should be taken with the -f/--force option,
5681 Extra care should be taken with the -f/--force option,
5682 which will push all new heads on all branches, an action which will
5682 which will push all new heads on all branches, an action which will
5683 almost always cause confusion for collaborators.
5683 almost always cause confusion for collaborators.
5684
5684
5685 If -r/--rev is used, the specified revision and all its ancestors
5685 If -r/--rev is used, the specified revision and all its ancestors
5686 will be pushed to the remote repository.
5686 will be pushed to the remote repository.
5687
5687
5688 If -B/--bookmark is used, the specified bookmarked revision, its
5688 If -B/--bookmark is used, the specified bookmarked revision, its
5689 ancestors, and the bookmark will be pushed to the remote
5689 ancestors, and the bookmark will be pushed to the remote
5690 repository.
5690 repository.
5691
5691
5692 Please see :hg:`help urls` for important details about ``ssh://``
5692 Please see :hg:`help urls` for important details about ``ssh://``
5693 URLs. If DESTINATION is omitted, a default path will be used.
5693 URLs. If DESTINATION is omitted, a default path will be used.
5694
5694
5695 Returns 0 if push was successful, 1 if nothing to push.
5695 Returns 0 if push was successful, 1 if nothing to push.
5696 """
5696 """
5697
5697
5698 if opts.get('bookmark'):
5698 if opts.get('bookmark'):
5699 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5699 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5700 for b in opts['bookmark']:
5700 for b in opts['bookmark']:
5701 # translate -B options to -r so changesets get pushed
5701 # translate -B options to -r so changesets get pushed
5702 if b in repo._bookmarks:
5702 if b in repo._bookmarks:
5703 opts.setdefault('rev', []).append(b)
5703 opts.setdefault('rev', []).append(b)
5704 else:
5704 else:
5705 # if we try to push a deleted bookmark, translate it to null
5705 # if we try to push a deleted bookmark, translate it to null
5706 # this lets simultaneous -r, -b options continue working
5706 # this lets simultaneous -r, -b options continue working
5707 opts.setdefault('rev', []).append("null")
5707 opts.setdefault('rev', []).append("null")
5708
5708
5709 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5709 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5710 if not path:
5710 if not path:
5711 raise error.Abort(_('default repository not configured!'),
5711 raise error.Abort(_('default repository not configured!'),
5712 hint=_('see the "path" section in "hg help config"'))
5712 hint=_('see the "path" section in "hg help config"'))
5713 dest = path.pushloc or path.loc
5713 dest = path.pushloc or path.loc
5714 branches = (path.branch, opts.get('branch') or [])
5714 branches = (path.branch, opts.get('branch') or [])
5715 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5715 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5716 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5716 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5717 other = hg.peer(repo, opts, dest)
5717 other = hg.peer(repo, opts, dest)
5718
5718
5719 if revs:
5719 if revs:
5720 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5720 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5721 if not revs:
5721 if not revs:
5722 raise error.Abort(_("specified revisions evaluate to an empty set"),
5722 raise error.Abort(_("specified revisions evaluate to an empty set"),
5723 hint=_("use different revision arguments"))
5723 hint=_("use different revision arguments"))
5724
5724
5725 repo._subtoppath = dest
5725 repo._subtoppath = dest
5726 try:
5726 try:
5727 # push subrepos depth-first for coherent ordering
5727 # push subrepos depth-first for coherent ordering
5728 c = repo['']
5728 c = repo['']
5729 subs = c.substate # only repos that are committed
5729 subs = c.substate # only repos that are committed
5730 for s in sorted(subs):
5730 for s in sorted(subs):
5731 result = c.sub(s).push(opts)
5731 result = c.sub(s).push(opts)
5732 if result == 0:
5732 if result == 0:
5733 return not result
5733 return not result
5734 finally:
5734 finally:
5735 del repo._subtoppath
5735 del repo._subtoppath
5736 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5736 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5737 newbranch=opts.get('new_branch'),
5737 newbranch=opts.get('new_branch'),
5738 bookmarks=opts.get('bookmark', ()),
5738 bookmarks=opts.get('bookmark', ()),
5739 opargs=opts.get('opargs'))
5739 opargs=opts.get('opargs'))
5740
5740
5741 result = not pushop.cgresult
5741 result = not pushop.cgresult
5742
5742
5743 if pushop.bkresult is not None:
5743 if pushop.bkresult is not None:
5744 if pushop.bkresult == 2:
5744 if pushop.bkresult == 2:
5745 result = 2
5745 result = 2
5746 elif not result and pushop.bkresult:
5746 elif not result and pushop.bkresult:
5747 result = 2
5747 result = 2
5748
5748
5749 return result
5749 return result
5750
5750
5751 @command('recover', [])
5751 @command('recover', [])
5752 def recover(ui, repo):
5752 def recover(ui, repo):
5753 """roll back an interrupted transaction
5753 """roll back an interrupted transaction
5754
5754
5755 Recover from an interrupted commit or pull.
5755 Recover from an interrupted commit or pull.
5756
5756
5757 This command tries to fix the repository status after an
5757 This command tries to fix the repository status after an
5758 interrupted operation. It should only be necessary when Mercurial
5758 interrupted operation. It should only be necessary when Mercurial
5759 suggests it.
5759 suggests it.
5760
5760
5761 Returns 0 if successful, 1 if nothing to recover or verify fails.
5761 Returns 0 if successful, 1 if nothing to recover or verify fails.
5762 """
5762 """
5763 if repo.recover():
5763 if repo.recover():
5764 return hg.verify(repo)
5764 return hg.verify(repo)
5765 return 1
5765 return 1
5766
5766
5767 @command('^remove|rm',
5767 @command('^remove|rm',
5768 [('A', 'after', None, _('record delete for missing files')),
5768 [('A', 'after', None, _('record delete for missing files')),
5769 ('f', 'force', None,
5769 ('f', 'force', None,
5770 _('remove (and delete) file even if added or modified')),
5770 _('remove (and delete) file even if added or modified')),
5771 ] + subrepoopts + walkopts,
5771 ] + subrepoopts + walkopts,
5772 _('[OPTION]... FILE...'),
5772 _('[OPTION]... FILE...'),
5773 inferrepo=True)
5773 inferrepo=True)
5774 def remove(ui, repo, *pats, **opts):
5774 def remove(ui, repo, *pats, **opts):
5775 """remove the specified files on the next commit
5775 """remove the specified files on the next commit
5776
5776
5777 Schedule the indicated files for removal from the current branch.
5777 Schedule the indicated files for removal from the current branch.
5778
5778
5779 This command schedules the files to be removed at the next commit.
5779 This command schedules the files to be removed at the next commit.
5780 To undo a remove before that, see :hg:`revert`. To undo added
5780 To undo a remove before that, see :hg:`revert`. To undo added
5781 files, see :hg:`forget`.
5781 files, see :hg:`forget`.
5782
5782
5783 .. container:: verbose
5783 .. container:: verbose
5784
5784
5785 -A/--after can be used to remove only files that have already
5785 -A/--after can be used to remove only files that have already
5786 been deleted, -f/--force can be used to force deletion, and -Af
5786 been deleted, -f/--force can be used to force deletion, and -Af
5787 can be used to remove files from the next revision without
5787 can be used to remove files from the next revision without
5788 deleting them from the working directory.
5788 deleting them from the working directory.
5789
5789
5790 The following table details the behavior of remove for different
5790 The following table details the behavior of remove for different
5791 file states (columns) and option combinations (rows). The file
5791 file states (columns) and option combinations (rows). The file
5792 states are Added [A], Clean [C], Modified [M] and Missing [!]
5792 states are Added [A], Clean [C], Modified [M] and Missing [!]
5793 (as reported by :hg:`status`). The actions are Warn, Remove
5793 (as reported by :hg:`status`). The actions are Warn, Remove
5794 (from branch) and Delete (from disk):
5794 (from branch) and Delete (from disk):
5795
5795
5796 ========= == == == ==
5796 ========= == == == ==
5797 opt/state A C M !
5797 opt/state A C M !
5798 ========= == == == ==
5798 ========= == == == ==
5799 none W RD W R
5799 none W RD W R
5800 -f R RD RD R
5800 -f R RD RD R
5801 -A W W W R
5801 -A W W W R
5802 -Af R R R R
5802 -Af R R R R
5803 ========= == == == ==
5803 ========= == == == ==
5804
5804
5805 .. note::
5805 .. note::
5806
5806
5807 :hg:`remove` never deletes files in Added [A] state from the
5807 :hg:`remove` never deletes files in Added [A] state from the
5808 working directory, not even if ``--force`` is specified.
5808 working directory, not even if ``--force`` is specified.
5809
5809
5810 Returns 0 on success, 1 if any warnings encountered.
5810 Returns 0 on success, 1 if any warnings encountered.
5811 """
5811 """
5812
5812
5813 after, force = opts.get('after'), opts.get('force')
5813 after, force = opts.get('after'), opts.get('force')
5814 if not pats and not after:
5814 if not pats and not after:
5815 raise error.Abort(_('no files specified'))
5815 raise error.Abort(_('no files specified'))
5816
5816
5817 m = scmutil.match(repo[None], pats, opts)
5817 m = scmutil.match(repo[None], pats, opts)
5818 subrepos = opts.get('subrepos')
5818 subrepos = opts.get('subrepos')
5819 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5819 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5820
5820
5821 @command('rename|move|mv',
5821 @command('rename|move|mv',
5822 [('A', 'after', None, _('record a rename that has already occurred')),
5822 [('A', 'after', None, _('record a rename that has already occurred')),
5823 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5823 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5824 ] + walkopts + dryrunopts,
5824 ] + walkopts + dryrunopts,
5825 _('[OPTION]... SOURCE... DEST'))
5825 _('[OPTION]... SOURCE... DEST'))
5826 def rename(ui, repo, *pats, **opts):
5826 def rename(ui, repo, *pats, **opts):
5827 """rename files; equivalent of copy + remove
5827 """rename files; equivalent of copy + remove
5828
5828
5829 Mark dest as copies of sources; mark sources for deletion. If dest
5829 Mark dest as copies of sources; mark sources for deletion. If dest
5830 is a directory, copies are put in that directory. If dest is a
5830 is a directory, copies are put in that directory. If dest is a
5831 file, there can only be one source.
5831 file, there can only be one source.
5832
5832
5833 By default, this command copies the contents of files as they
5833 By default, this command copies the contents of files as they
5834 exist in the working directory. If invoked with -A/--after, the
5834 exist in the working directory. If invoked with -A/--after, the
5835 operation is recorded, but no copying is performed.
5835 operation is recorded, but no copying is performed.
5836
5836
5837 This command takes effect at the next commit. To undo a rename
5837 This command takes effect at the next commit. To undo a rename
5838 before that, see :hg:`revert`.
5838 before that, see :hg:`revert`.
5839
5839
5840 Returns 0 on success, 1 if errors are encountered.
5840 Returns 0 on success, 1 if errors are encountered.
5841 """
5841 """
5842 with repo.wlock(False):
5842 with repo.wlock(False):
5843 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5843 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5844
5844
5845 @command('resolve',
5845 @command('resolve',
5846 [('a', 'all', None, _('select all unresolved files')),
5846 [('a', 'all', None, _('select all unresolved files')),
5847 ('l', 'list', None, _('list state of files needing merge')),
5847 ('l', 'list', None, _('list state of files needing merge')),
5848 ('m', 'mark', None, _('mark files as resolved')),
5848 ('m', 'mark', None, _('mark files as resolved')),
5849 ('u', 'unmark', None, _('mark files as unresolved')),
5849 ('u', 'unmark', None, _('mark files as unresolved')),
5850 ('n', 'no-status', None, _('hide status prefix'))]
5850 ('n', 'no-status', None, _('hide status prefix'))]
5851 + mergetoolopts + walkopts + formatteropts,
5851 + mergetoolopts + walkopts + formatteropts,
5852 _('[OPTION]... [FILE]...'),
5852 _('[OPTION]... [FILE]...'),
5853 inferrepo=True)
5853 inferrepo=True)
5854 def resolve(ui, repo, *pats, **opts):
5854 def resolve(ui, repo, *pats, **opts):
5855 """redo merges or set/view the merge status of files
5855 """redo merges or set/view the merge status of files
5856
5856
5857 Merges with unresolved conflicts are often the result of
5857 Merges with unresolved conflicts are often the result of
5858 non-interactive merging using the ``internal:merge`` configuration
5858 non-interactive merging using the ``internal:merge`` configuration
5859 setting, or a command-line merge tool like ``diff3``. The resolve
5859 setting, or a command-line merge tool like ``diff3``. The resolve
5860 command is used to manage the files involved in a merge, after
5860 command is used to manage the files involved in a merge, after
5861 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5861 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5862 working directory must have two parents). See :hg:`help
5862 working directory must have two parents). See :hg:`help
5863 merge-tools` for information on configuring merge tools.
5863 merge-tools` for information on configuring merge tools.
5864
5864
5865 The resolve command can be used in the following ways:
5865 The resolve command can be used in the following ways:
5866
5866
5867 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5867 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5868 files, discarding any previous merge attempts. Re-merging is not
5868 files, discarding any previous merge attempts. Re-merging is not
5869 performed for files already marked as resolved. Use ``--all/-a``
5869 performed for files already marked as resolved. Use ``--all/-a``
5870 to select all unresolved files. ``--tool`` can be used to specify
5870 to select all unresolved files. ``--tool`` can be used to specify
5871 the merge tool used for the given files. It overrides the HGMERGE
5871 the merge tool used for the given files. It overrides the HGMERGE
5872 environment variable and your configuration files. Previous file
5872 environment variable and your configuration files. Previous file
5873 contents are saved with a ``.orig`` suffix.
5873 contents are saved with a ``.orig`` suffix.
5874
5874
5875 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5875 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5876 (e.g. after having manually fixed-up the files). The default is
5876 (e.g. after having manually fixed-up the files). The default is
5877 to mark all unresolved files.
5877 to mark all unresolved files.
5878
5878
5879 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5879 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5880 default is to mark all resolved files.
5880 default is to mark all resolved files.
5881
5881
5882 - :hg:`resolve -l`: list files which had or still have conflicts.
5882 - :hg:`resolve -l`: list files which had or still have conflicts.
5883 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5883 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5884
5884
5885 .. note::
5885 .. note::
5886
5886
5887 Mercurial will not let you commit files with unresolved merge
5887 Mercurial will not let you commit files with unresolved merge
5888 conflicts. You must use :hg:`resolve -m ...` before you can
5888 conflicts. You must use :hg:`resolve -m ...` before you can
5889 commit after a conflicting merge.
5889 commit after a conflicting merge.
5890
5890
5891 Returns 0 on success, 1 if any files fail a resolve attempt.
5891 Returns 0 on success, 1 if any files fail a resolve attempt.
5892 """
5892 """
5893
5893
5894 all, mark, unmark, show, nostatus = \
5894 all, mark, unmark, show, nostatus = \
5895 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5895 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5896
5896
5897 if (show and (mark or unmark)) or (mark and unmark):
5897 if (show and (mark or unmark)) or (mark and unmark):
5898 raise error.Abort(_("too many options specified"))
5898 raise error.Abort(_("too many options specified"))
5899 if pats and all:
5899 if pats and all:
5900 raise error.Abort(_("can't specify --all and patterns"))
5900 raise error.Abort(_("can't specify --all and patterns"))
5901 if not (all or pats or show or mark or unmark):
5901 if not (all or pats or show or mark or unmark):
5902 raise error.Abort(_('no files or directories specified'),
5902 raise error.Abort(_('no files or directories specified'),
5903 hint=('use --all to re-merge all unresolved files'))
5903 hint=('use --all to re-merge all unresolved files'))
5904
5904
5905 if show:
5905 if show:
5906 fm = ui.formatter('resolve', opts)
5906 fm = ui.formatter('resolve', opts)
5907 ms = mergemod.mergestate.read(repo)
5907 ms = mergemod.mergestate.read(repo)
5908 m = scmutil.match(repo[None], pats, opts)
5908 m = scmutil.match(repo[None], pats, opts)
5909 for f in ms:
5909 for f in ms:
5910 if not m(f):
5910 if not m(f):
5911 continue
5911 continue
5912 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5912 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5913 'd': 'driverresolved'}[ms[f]]
5913 'd': 'driverresolved'}[ms[f]]
5914 fm.startitem()
5914 fm.startitem()
5915 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5915 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5916 fm.write('path', '%s\n', f, label=l)
5916 fm.write('path', '%s\n', f, label=l)
5917 fm.end()
5917 fm.end()
5918 return 0
5918 return 0
5919
5919
5920 with repo.wlock():
5920 with repo.wlock():
5921 ms = mergemod.mergestate.read(repo)
5921 ms = mergemod.mergestate.read(repo)
5922
5922
5923 if not (ms.active() or repo.dirstate.p2() != nullid):
5923 if not (ms.active() or repo.dirstate.p2() != nullid):
5924 raise error.Abort(
5924 raise error.Abort(
5925 _('resolve command not applicable when not merging'))
5925 _('resolve command not applicable when not merging'))
5926
5926
5927 wctx = repo[None]
5927 wctx = repo[None]
5928
5928
5929 if ms.mergedriver and ms.mdstate() == 'u':
5929 if ms.mergedriver and ms.mdstate() == 'u':
5930 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5930 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5931 ms.commit()
5931 ms.commit()
5932 # allow mark and unmark to go through
5932 # allow mark and unmark to go through
5933 if not mark and not unmark and not proceed:
5933 if not mark and not unmark and not proceed:
5934 return 1
5934 return 1
5935
5935
5936 m = scmutil.match(wctx, pats, opts)
5936 m = scmutil.match(wctx, pats, opts)
5937 ret = 0
5937 ret = 0
5938 didwork = False
5938 didwork = False
5939 runconclude = False
5939 runconclude = False
5940
5940
5941 tocomplete = []
5941 tocomplete = []
5942 for f in ms:
5942 for f in ms:
5943 if not m(f):
5943 if not m(f):
5944 continue
5944 continue
5945
5945
5946 didwork = True
5946 didwork = True
5947
5947
5948 # don't let driver-resolved files be marked, and run the conclude
5948 # don't let driver-resolved files be marked, and run the conclude
5949 # step if asked to resolve
5949 # step if asked to resolve
5950 if ms[f] == "d":
5950 if ms[f] == "d":
5951 exact = m.exact(f)
5951 exact = m.exact(f)
5952 if mark:
5952 if mark:
5953 if exact:
5953 if exact:
5954 ui.warn(_('not marking %s as it is driver-resolved\n')
5954 ui.warn(_('not marking %s as it is driver-resolved\n')
5955 % f)
5955 % f)
5956 elif unmark:
5956 elif unmark:
5957 if exact:
5957 if exact:
5958 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5958 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5959 % f)
5959 % f)
5960 else:
5960 else:
5961 runconclude = True
5961 runconclude = True
5962 continue
5962 continue
5963
5963
5964 if mark:
5964 if mark:
5965 ms.mark(f, "r")
5965 ms.mark(f, "r")
5966 elif unmark:
5966 elif unmark:
5967 ms.mark(f, "u")
5967 ms.mark(f, "u")
5968 else:
5968 else:
5969 # backup pre-resolve (merge uses .orig for its own purposes)
5969 # backup pre-resolve (merge uses .orig for its own purposes)
5970 a = repo.wjoin(f)
5970 a = repo.wjoin(f)
5971 try:
5971 try:
5972 util.copyfile(a, a + ".resolve")
5972 util.copyfile(a, a + ".resolve")
5973 except (IOError, OSError) as inst:
5973 except (IOError, OSError) as inst:
5974 if inst.errno != errno.ENOENT:
5974 if inst.errno != errno.ENOENT:
5975 raise
5975 raise
5976
5976
5977 try:
5977 try:
5978 # preresolve file
5978 # preresolve file
5979 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5979 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5980 'resolve')
5980 'resolve')
5981 complete, r = ms.preresolve(f, wctx)
5981 complete, r = ms.preresolve(f, wctx)
5982 if not complete:
5982 if not complete:
5983 tocomplete.append(f)
5983 tocomplete.append(f)
5984 elif r:
5984 elif r:
5985 ret = 1
5985 ret = 1
5986 finally:
5986 finally:
5987 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5987 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5988 ms.commit()
5988 ms.commit()
5989
5989
5990 # replace filemerge's .orig file with our resolve file, but only
5990 # replace filemerge's .orig file with our resolve file, but only
5991 # for merges that are complete
5991 # for merges that are complete
5992 if complete:
5992 if complete:
5993 try:
5993 try:
5994 util.rename(a + ".resolve",
5994 util.rename(a + ".resolve",
5995 scmutil.origpath(ui, repo, a))
5995 scmutil.origpath(ui, repo, a))
5996 except OSError as inst:
5996 except OSError as inst:
5997 if inst.errno != errno.ENOENT:
5997 if inst.errno != errno.ENOENT:
5998 raise
5998 raise
5999
5999
6000 for f in tocomplete:
6000 for f in tocomplete:
6001 try:
6001 try:
6002 # resolve file
6002 # resolve file
6003 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6003 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6004 'resolve')
6004 'resolve')
6005 r = ms.resolve(f, wctx)
6005 r = ms.resolve(f, wctx)
6006 if r:
6006 if r:
6007 ret = 1
6007 ret = 1
6008 finally:
6008 finally:
6009 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6009 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6010 ms.commit()
6010 ms.commit()
6011
6011
6012 # replace filemerge's .orig file with our resolve file
6012 # replace filemerge's .orig file with our resolve file
6013 a = repo.wjoin(f)
6013 a = repo.wjoin(f)
6014 try:
6014 try:
6015 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6015 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6016 except OSError as inst:
6016 except OSError as inst:
6017 if inst.errno != errno.ENOENT:
6017 if inst.errno != errno.ENOENT:
6018 raise
6018 raise
6019
6019
6020 ms.commit()
6020 ms.commit()
6021 ms.recordactions()
6021 ms.recordactions()
6022
6022
6023 if not didwork and pats:
6023 if not didwork and pats:
6024 ui.warn(_("arguments do not match paths that need resolving\n"))
6024 ui.warn(_("arguments do not match paths that need resolving\n"))
6025 elif ms.mergedriver and ms.mdstate() != 's':
6025 elif ms.mergedriver and ms.mdstate() != 's':
6026 # run conclude step when either a driver-resolved file is requested
6026 # run conclude step when either a driver-resolved file is requested
6027 # or there are no driver-resolved files
6027 # or there are no driver-resolved files
6028 # we can't use 'ret' to determine whether any files are unresolved
6028 # we can't use 'ret' to determine whether any files are unresolved
6029 # because we might not have tried to resolve some
6029 # because we might not have tried to resolve some
6030 if ((runconclude or not list(ms.driverresolved()))
6030 if ((runconclude or not list(ms.driverresolved()))
6031 and not list(ms.unresolved())):
6031 and not list(ms.unresolved())):
6032 proceed = mergemod.driverconclude(repo, ms, wctx)
6032 proceed = mergemod.driverconclude(repo, ms, wctx)
6033 ms.commit()
6033 ms.commit()
6034 if not proceed:
6034 if not proceed:
6035 return 1
6035 return 1
6036
6036
6037 # Nudge users into finishing an unfinished operation
6037 # Nudge users into finishing an unfinished operation
6038 unresolvedf = list(ms.unresolved())
6038 unresolvedf = list(ms.unresolved())
6039 driverresolvedf = list(ms.driverresolved())
6039 driverresolvedf = list(ms.driverresolved())
6040 if not unresolvedf and not driverresolvedf:
6040 if not unresolvedf and not driverresolvedf:
6041 ui.status(_('(no more unresolved files)\n'))
6041 ui.status(_('(no more unresolved files)\n'))
6042 cmdutil.checkafterresolved(repo)
6042 cmdutil.checkafterresolved(repo)
6043 elif not unresolvedf:
6043 elif not unresolvedf:
6044 ui.status(_('(no more unresolved files -- '
6044 ui.status(_('(no more unresolved files -- '
6045 'run "hg resolve --all" to conclude)\n'))
6045 'run "hg resolve --all" to conclude)\n'))
6046
6046
6047 return ret
6047 return ret
6048
6048
6049 @command('revert',
6049 @command('revert',
6050 [('a', 'all', None, _('revert all changes when no arguments given')),
6050 [('a', 'all', None, _('revert all changes when no arguments given')),
6051 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6051 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6052 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6052 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6053 ('C', 'no-backup', None, _('do not save backup copies of files')),
6053 ('C', 'no-backup', None, _('do not save backup copies of files')),
6054 ('i', 'interactive', None,
6054 ('i', 'interactive', None,
6055 _('interactively select the changes (EXPERIMENTAL)')),
6055 _('interactively select the changes (EXPERIMENTAL)')),
6056 ] + walkopts + dryrunopts,
6056 ] + walkopts + dryrunopts,
6057 _('[OPTION]... [-r REV] [NAME]...'))
6057 _('[OPTION]... [-r REV] [NAME]...'))
6058 def revert(ui, repo, *pats, **opts):
6058 def revert(ui, repo, *pats, **opts):
6059 """restore files to their checkout state
6059 """restore files to their checkout state
6060
6060
6061 .. note::
6061 .. note::
6062
6062
6063 To check out earlier revisions, you should use :hg:`update REV`.
6063 To check out earlier revisions, you should use :hg:`update REV`.
6064 To cancel an uncommitted merge (and lose your changes),
6064 To cancel an uncommitted merge (and lose your changes),
6065 use :hg:`update --clean .`.
6065 use :hg:`update --clean .`.
6066
6066
6067 With no revision specified, revert the specified files or directories
6067 With no revision specified, revert the specified files or directories
6068 to the contents they had in the parent of the working directory.
6068 to the contents they had in the parent of the working directory.
6069 This restores the contents of files to an unmodified
6069 This restores the contents of files to an unmodified
6070 state and unschedules adds, removes, copies, and renames. If the
6070 state and unschedules adds, removes, copies, and renames. If the
6071 working directory has two parents, you must explicitly specify a
6071 working directory has two parents, you must explicitly specify a
6072 revision.
6072 revision.
6073
6073
6074 Using the -r/--rev or -d/--date options, revert the given files or
6074 Using the -r/--rev or -d/--date options, revert the given files or
6075 directories to their states as of a specific revision. Because
6075 directories to their states as of a specific revision. Because
6076 revert does not change the working directory parents, this will
6076 revert does not change the working directory parents, this will
6077 cause these files to appear modified. This can be helpful to "back
6077 cause these files to appear modified. This can be helpful to "back
6078 out" some or all of an earlier change. See :hg:`backout` for a
6078 out" some or all of an earlier change. See :hg:`backout` for a
6079 related method.
6079 related method.
6080
6080
6081 Modified files are saved with a .orig suffix before reverting.
6081 Modified files are saved with a .orig suffix before reverting.
6082 To disable these backups, use --no-backup.
6082 To disable these backups, use --no-backup.
6083
6083
6084 See :hg:`help dates` for a list of formats valid for -d/--date.
6084 See :hg:`help dates` for a list of formats valid for -d/--date.
6085
6085
6086 See :hg:`help backout` for a way to reverse the effect of an
6086 See :hg:`help backout` for a way to reverse the effect of an
6087 earlier changeset.
6087 earlier changeset.
6088
6088
6089 Returns 0 on success.
6089 Returns 0 on success.
6090 """
6090 """
6091
6091
6092 if opts.get("date"):
6092 if opts.get("date"):
6093 if opts.get("rev"):
6093 if opts.get("rev"):
6094 raise error.Abort(_("you can't specify a revision and a date"))
6094 raise error.Abort(_("you can't specify a revision and a date"))
6095 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6095 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6096
6096
6097 parent, p2 = repo.dirstate.parents()
6097 parent, p2 = repo.dirstate.parents()
6098 if not opts.get('rev') and p2 != nullid:
6098 if not opts.get('rev') and p2 != nullid:
6099 # revert after merge is a trap for new users (issue2915)
6099 # revert after merge is a trap for new users (issue2915)
6100 raise error.Abort(_('uncommitted merge with no revision specified'),
6100 raise error.Abort(_('uncommitted merge with no revision specified'),
6101 hint=_('use "hg update" or see "hg help revert"'))
6101 hint=_('use "hg update" or see "hg help revert"'))
6102
6102
6103 ctx = scmutil.revsingle(repo, opts.get('rev'))
6103 ctx = scmutil.revsingle(repo, opts.get('rev'))
6104
6104
6105 if (not (pats or opts.get('include') or opts.get('exclude') or
6105 if (not (pats or opts.get('include') or opts.get('exclude') or
6106 opts.get('all') or opts.get('interactive'))):
6106 opts.get('all') or opts.get('interactive'))):
6107 msg = _("no files or directories specified")
6107 msg = _("no files or directories specified")
6108 if p2 != nullid:
6108 if p2 != nullid:
6109 hint = _("uncommitted merge, use --all to discard all changes,"
6109 hint = _("uncommitted merge, use --all to discard all changes,"
6110 " or 'hg update -C .' to abort the merge")
6110 " or 'hg update -C .' to abort the merge")
6111 raise error.Abort(msg, hint=hint)
6111 raise error.Abort(msg, hint=hint)
6112 dirty = any(repo.status())
6112 dirty = any(repo.status())
6113 node = ctx.node()
6113 node = ctx.node()
6114 if node != parent:
6114 if node != parent:
6115 if dirty:
6115 if dirty:
6116 hint = _("uncommitted changes, use --all to discard all"
6116 hint = _("uncommitted changes, use --all to discard all"
6117 " changes, or 'hg update %s' to update") % ctx.rev()
6117 " changes, or 'hg update %s' to update") % ctx.rev()
6118 else:
6118 else:
6119 hint = _("use --all to revert all files,"
6119 hint = _("use --all to revert all files,"
6120 " or 'hg update %s' to update") % ctx.rev()
6120 " or 'hg update %s' to update") % ctx.rev()
6121 elif dirty:
6121 elif dirty:
6122 hint = _("uncommitted changes, use --all to discard all changes")
6122 hint = _("uncommitted changes, use --all to discard all changes")
6123 else:
6123 else:
6124 hint = _("use --all to revert all files")
6124 hint = _("use --all to revert all files")
6125 raise error.Abort(msg, hint=hint)
6125 raise error.Abort(msg, hint=hint)
6126
6126
6127 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6127 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6128
6128
6129 @command('rollback', dryrunopts +
6129 @command('rollback', dryrunopts +
6130 [('f', 'force', False, _('ignore safety measures'))])
6130 [('f', 'force', False, _('ignore safety measures'))])
6131 def rollback(ui, repo, **opts):
6131 def rollback(ui, repo, **opts):
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6133
6133
6134 Please use :hg:`commit --amend` instead of rollback to correct
6134 Please use :hg:`commit --amend` instead of rollback to correct
6135 mistakes in the last commit.
6135 mistakes in the last commit.
6136
6136
6137 This command should be used with care. There is only one level of
6137 This command should be used with care. There is only one level of
6138 rollback, and there is no way to undo a rollback. It will also
6138 rollback, and there is no way to undo a rollback. It will also
6139 restore the dirstate at the time of the last transaction, losing
6139 restore the dirstate at the time of the last transaction, losing
6140 any dirstate changes since that time. This command does not alter
6140 any dirstate changes since that time. This command does not alter
6141 the working directory.
6141 the working directory.
6142
6142
6143 Transactions are used to encapsulate the effects of all commands
6143 Transactions are used to encapsulate the effects of all commands
6144 that create new changesets or propagate existing changesets into a
6144 that create new changesets or propagate existing changesets into a
6145 repository.
6145 repository.
6146
6146
6147 .. container:: verbose
6147 .. container:: verbose
6148
6148
6149 For example, the following commands are transactional, and their
6149 For example, the following commands are transactional, and their
6150 effects can be rolled back:
6150 effects can be rolled back:
6151
6151
6152 - commit
6152 - commit
6153 - import
6153 - import
6154 - pull
6154 - pull
6155 - push (with this repository as the destination)
6155 - push (with this repository as the destination)
6156 - unbundle
6156 - unbundle
6157
6157
6158 To avoid permanent data loss, rollback will refuse to rollback a
6158 To avoid permanent data loss, rollback will refuse to rollback a
6159 commit transaction if it isn't checked out. Use --force to
6159 commit transaction if it isn't checked out. Use --force to
6160 override this protection.
6160 override this protection.
6161
6161
6162 This command is not intended for use on public repositories. Once
6162 This command is not intended for use on public repositories. Once
6163 changes are visible for pull by other users, rolling a transaction
6163 changes are visible for pull by other users, rolling a transaction
6164 back locally is ineffective (someone else may already have pulled
6164 back locally is ineffective (someone else may already have pulled
6165 the changes). Furthermore, a race is possible with readers of the
6165 the changes). Furthermore, a race is possible with readers of the
6166 repository; for example an in-progress pull from the repository
6166 repository; for example an in-progress pull from the repository
6167 may fail if a rollback is performed.
6167 may fail if a rollback is performed.
6168
6168
6169 Returns 0 on success, 1 if no rollback data is available.
6169 Returns 0 on success, 1 if no rollback data is available.
6170 """
6170 """
6171 return repo.rollback(dryrun=opts.get('dry_run'),
6171 return repo.rollback(dryrun=opts.get('dry_run'),
6172 force=opts.get('force'))
6172 force=opts.get('force'))
6173
6173
6174 @command('root', [])
6174 @command('root', [])
6175 def root(ui, repo):
6175 def root(ui, repo):
6176 """print the root (top) of the current working directory
6176 """print the root (top) of the current working directory
6177
6177
6178 Print the root directory of the current repository.
6178 Print the root directory of the current repository.
6179
6179
6180 Returns 0 on success.
6180 Returns 0 on success.
6181 """
6181 """
6182 ui.write(repo.root + "\n")
6182 ui.write(repo.root + "\n")
6183
6183
6184 @command('^serve',
6184 @command('^serve',
6185 [('A', 'accesslog', '', _('name of access log file to write to'),
6185 [('A', 'accesslog', '', _('name of access log file to write to'),
6186 _('FILE')),
6186 _('FILE')),
6187 ('d', 'daemon', None, _('run server in background')),
6187 ('d', 'daemon', None, _('run server in background')),
6188 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6188 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6189 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6189 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6190 # use string type, then we can check if something was passed
6190 # use string type, then we can check if something was passed
6191 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6191 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6192 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6192 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6193 _('ADDR')),
6193 _('ADDR')),
6194 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6194 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6195 _('PREFIX')),
6195 _('PREFIX')),
6196 ('n', 'name', '',
6196 ('n', 'name', '',
6197 _('name to show in web pages (default: working directory)'), _('NAME')),
6197 _('name to show in web pages (default: working directory)'), _('NAME')),
6198 ('', 'web-conf', '',
6198 ('', 'web-conf', '',
6199 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6199 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6200 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6200 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6201 _('FILE')),
6201 _('FILE')),
6202 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6202 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6203 ('', 'stdio', None, _('for remote clients')),
6203 ('', 'stdio', None, _('for remote clients')),
6204 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6204 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6205 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6205 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6206 ('', 'style', '', _('template style to use'), _('STYLE')),
6206 ('', 'style', '', _('template style to use'), _('STYLE')),
6207 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6207 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6208 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6208 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6209 _('[OPTION]...'),
6209 _('[OPTION]...'),
6210 optionalrepo=True)
6210 optionalrepo=True)
6211 def serve(ui, repo, **opts):
6211 def serve(ui, repo, **opts):
6212 """start stand-alone webserver
6212 """start stand-alone webserver
6213
6213
6214 Start a local HTTP repository browser and pull server. You can use
6214 Start a local HTTP repository browser and pull server. You can use
6215 this for ad-hoc sharing and browsing of repositories. It is
6215 this for ad-hoc sharing and browsing of repositories. It is
6216 recommended to use a real web server to serve a repository for
6216 recommended to use a real web server to serve a repository for
6217 longer periods of time.
6217 longer periods of time.
6218
6218
6219 Please note that the server does not implement access control.
6219 Please note that the server does not implement access control.
6220 This means that, by default, anybody can read from the server and
6220 This means that, by default, anybody can read from the server and
6221 nobody can write to it by default. Set the ``web.allow_push``
6221 nobody can write to it by default. Set the ``web.allow_push``
6222 option to ``*`` to allow everybody to push to the server. You
6222 option to ``*`` to allow everybody to push to the server. You
6223 should use a real web server if you need to authenticate users.
6223 should use a real web server if you need to authenticate users.
6224
6224
6225 By default, the server logs accesses to stdout and errors to
6225 By default, the server logs accesses to stdout and errors to
6226 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6226 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6227 files.
6227 files.
6228
6228
6229 To have the server choose a free port number to listen on, specify
6229 To have the server choose a free port number to listen on, specify
6230 a port number of 0; in this case, the server will print the port
6230 a port number of 0; in this case, the server will print the port
6231 number it uses.
6231 number it uses.
6232
6232
6233 Returns 0 on success.
6233 Returns 0 on success.
6234 """
6234 """
6235
6235
6236 if opts["stdio"] and opts["cmdserver"]:
6236 if opts["stdio"] and opts["cmdserver"]:
6237 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6237 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6238
6238
6239 if opts["stdio"]:
6239 if opts["stdio"]:
6240 if repo is None:
6240 if repo is None:
6241 raise error.RepoError(_("there is no Mercurial repository here"
6241 raise error.RepoError(_("there is no Mercurial repository here"
6242 " (.hg not found)"))
6242 " (.hg not found)"))
6243 s = sshserver.sshserver(ui, repo)
6243 s = sshserver.sshserver(ui, repo)
6244 s.serve_forever()
6244 s.serve_forever()
6245
6245
6246 if opts["cmdserver"]:
6246 if opts["cmdserver"]:
6247 service = commandserver.createservice(ui, repo, opts)
6247 service = commandserver.createservice(ui, repo, opts)
6248 else:
6248 else:
6249 service = hgweb.createservice(ui, repo, opts)
6249 service = hgweb.createservice(ui, repo, opts)
6250 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6250 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6251
6251
6252 @command('^status|st',
6252 @command('^status|st',
6253 [('A', 'all', None, _('show status of all files')),
6253 [('A', 'all', None, _('show status of all files')),
6254 ('m', 'modified', None, _('show only modified files')),
6254 ('m', 'modified', None, _('show only modified files')),
6255 ('a', 'added', None, _('show only added files')),
6255 ('a', 'added', None, _('show only added files')),
6256 ('r', 'removed', None, _('show only removed files')),
6256 ('r', 'removed', None, _('show only removed files')),
6257 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6257 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6258 ('c', 'clean', None, _('show only files without changes')),
6258 ('c', 'clean', None, _('show only files without changes')),
6259 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6259 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6260 ('i', 'ignored', None, _('show only ignored files')),
6260 ('i', 'ignored', None, _('show only ignored files')),
6261 ('n', 'no-status', None, _('hide status prefix')),
6261 ('n', 'no-status', None, _('hide status prefix')),
6262 ('C', 'copies', None, _('show source of copied files')),
6262 ('C', 'copies', None, _('show source of copied files')),
6263 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6263 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6264 ('', 'rev', [], _('show difference from revision'), _('REV')),
6264 ('', 'rev', [], _('show difference from revision'), _('REV')),
6265 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6265 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6266 ] + walkopts + subrepoopts + formatteropts,
6266 ] + walkopts + subrepoopts + formatteropts,
6267 _('[OPTION]... [FILE]...'),
6267 _('[OPTION]... [FILE]...'),
6268 inferrepo=True)
6268 inferrepo=True)
6269 def status(ui, repo, *pats, **opts):
6269 def status(ui, repo, *pats, **opts):
6270 """show changed files in the working directory
6270 """show changed files in the working directory
6271
6271
6272 Show status of files in the repository. If names are given, only
6272 Show status of files in the repository. If names are given, only
6273 files that match are shown. Files that are clean or ignored or
6273 files that match are shown. Files that are clean or ignored or
6274 the source of a copy/move operation, are not listed unless
6274 the source of a copy/move operation, are not listed unless
6275 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6275 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6276 Unless options described with "show only ..." are given, the
6276 Unless options described with "show only ..." are given, the
6277 options -mardu are used.
6277 options -mardu are used.
6278
6278
6279 Option -q/--quiet hides untracked (unknown and ignored) files
6279 Option -q/--quiet hides untracked (unknown and ignored) files
6280 unless explicitly requested with -u/--unknown or -i/--ignored.
6280 unless explicitly requested with -u/--unknown or -i/--ignored.
6281
6281
6282 .. note::
6282 .. note::
6283
6283
6284 :hg:`status` may appear to disagree with diff if permissions have
6284 :hg:`status` may appear to disagree with diff if permissions have
6285 changed or a merge has occurred. The standard diff format does
6285 changed or a merge has occurred. The standard diff format does
6286 not report permission changes and diff only reports changes
6286 not report permission changes and diff only reports changes
6287 relative to one merge parent.
6287 relative to one merge parent.
6288
6288
6289 If one revision is given, it is used as the base revision.
6289 If one revision is given, it is used as the base revision.
6290 If two revisions are given, the differences between them are
6290 If two revisions are given, the differences between them are
6291 shown. The --change option can also be used as a shortcut to list
6291 shown. The --change option can also be used as a shortcut to list
6292 the changed files of a revision from its first parent.
6292 the changed files of a revision from its first parent.
6293
6293
6294 The codes used to show the status of files are::
6294 The codes used to show the status of files are::
6295
6295
6296 M = modified
6296 M = modified
6297 A = added
6297 A = added
6298 R = removed
6298 R = removed
6299 C = clean
6299 C = clean
6300 ! = missing (deleted by non-hg command, but still tracked)
6300 ! = missing (deleted by non-hg command, but still tracked)
6301 ? = not tracked
6301 ? = not tracked
6302 I = ignored
6302 I = ignored
6303 = origin of the previous file (with --copies)
6303 = origin of the previous file (with --copies)
6304
6304
6305 .. container:: verbose
6305 .. container:: verbose
6306
6306
6307 Examples:
6307 Examples:
6308
6308
6309 - show changes in the working directory relative to a
6309 - show changes in the working directory relative to a
6310 changeset::
6310 changeset::
6311
6311
6312 hg status --rev 9353
6312 hg status --rev 9353
6313
6313
6314 - show changes in the working directory relative to the
6314 - show changes in the working directory relative to the
6315 current directory (see :hg:`help patterns` for more information)::
6315 current directory (see :hg:`help patterns` for more information)::
6316
6316
6317 hg status re:
6317 hg status re:
6318
6318
6319 - show all changes including copies in an existing changeset::
6319 - show all changes including copies in an existing changeset::
6320
6320
6321 hg status --copies --change 9353
6321 hg status --copies --change 9353
6322
6322
6323 - get a NUL separated list of added files, suitable for xargs::
6323 - get a NUL separated list of added files, suitable for xargs::
6324
6324
6325 hg status -an0
6325 hg status -an0
6326
6326
6327 Returns 0 on success.
6327 Returns 0 on success.
6328 """
6328 """
6329
6329
6330 revs = opts.get('rev')
6330 revs = opts.get('rev')
6331 change = opts.get('change')
6331 change = opts.get('change')
6332
6332
6333 if revs and change:
6333 if revs and change:
6334 msg = _('cannot specify --rev and --change at the same time')
6334 msg = _('cannot specify --rev and --change at the same time')
6335 raise error.Abort(msg)
6335 raise error.Abort(msg)
6336 elif change:
6336 elif change:
6337 node2 = scmutil.revsingle(repo, change, None).node()
6337 node2 = scmutil.revsingle(repo, change, None).node()
6338 node1 = repo[node2].p1().node()
6338 node1 = repo[node2].p1().node()
6339 else:
6339 else:
6340 node1, node2 = scmutil.revpair(repo, revs)
6340 node1, node2 = scmutil.revpair(repo, revs)
6341
6341
6342 if pats:
6342 if pats:
6343 cwd = repo.getcwd()
6343 cwd = repo.getcwd()
6344 else:
6344 else:
6345 cwd = ''
6345 cwd = ''
6346
6346
6347 if opts.get('print0'):
6347 if opts.get('print0'):
6348 end = '\0'
6348 end = '\0'
6349 else:
6349 else:
6350 end = '\n'
6350 end = '\n'
6351 copy = {}
6351 copy = {}
6352 states = 'modified added removed deleted unknown ignored clean'.split()
6352 states = 'modified added removed deleted unknown ignored clean'.split()
6353 show = [k for k in states if opts.get(k)]
6353 show = [k for k in states if opts.get(k)]
6354 if opts.get('all'):
6354 if opts.get('all'):
6355 show += ui.quiet and (states[:4] + ['clean']) or states
6355 show += ui.quiet and (states[:4] + ['clean']) or states
6356 if not show:
6356 if not show:
6357 if ui.quiet:
6357 if ui.quiet:
6358 show = states[:4]
6358 show = states[:4]
6359 else:
6359 else:
6360 show = states[:5]
6360 show = states[:5]
6361
6361
6362 m = scmutil.match(repo[node2], pats, opts)
6362 m = scmutil.match(repo[node2], pats, opts)
6363 stat = repo.status(node1, node2, m,
6363 stat = repo.status(node1, node2, m,
6364 'ignored' in show, 'clean' in show, 'unknown' in show,
6364 'ignored' in show, 'clean' in show, 'unknown' in show,
6365 opts.get('subrepos'))
6365 opts.get('subrepos'))
6366 changestates = zip(states, 'MAR!?IC', stat)
6366 changestates = zip(states, 'MAR!?IC', stat)
6367
6367
6368 if (opts.get('all') or opts.get('copies')
6368 if (opts.get('all') or opts.get('copies')
6369 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6369 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6370 copy = copies.pathcopies(repo[node1], repo[node2], m)
6370 copy = copies.pathcopies(repo[node1], repo[node2], m)
6371
6371
6372 fm = ui.formatter('status', opts)
6372 fm = ui.formatter('status', opts)
6373 fmt = '%s' + end
6373 fmt = '%s' + end
6374 showchar = not opts.get('no_status')
6374 showchar = not opts.get('no_status')
6375
6375
6376 for state, char, files in changestates:
6376 for state, char, files in changestates:
6377 if state in show:
6377 if state in show:
6378 label = 'status.' + state
6378 label = 'status.' + state
6379 for f in files:
6379 for f in files:
6380 fm.startitem()
6380 fm.startitem()
6381 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6381 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6382 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6382 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6383 if f in copy:
6383 if f in copy:
6384 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6384 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6385 label='status.copied')
6385 label='status.copied')
6386 fm.end()
6386 fm.end()
6387
6387
6388 @command('^summary|sum',
6388 @command('^summary|sum',
6389 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6389 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6390 def summary(ui, repo, **opts):
6390 def summary(ui, repo, **opts):
6391 """summarize working directory state
6391 """summarize working directory state
6392
6392
6393 This generates a brief summary of the working directory state,
6393 This generates a brief summary of the working directory state,
6394 including parents, branch, commit status, phase and available updates.
6394 including parents, branch, commit status, phase and available updates.
6395
6395
6396 With the --remote option, this will check the default paths for
6396 With the --remote option, this will check the default paths for
6397 incoming and outgoing changes. This can be time-consuming.
6397 incoming and outgoing changes. This can be time-consuming.
6398
6398
6399 Returns 0 on success.
6399 Returns 0 on success.
6400 """
6400 """
6401
6401
6402 ctx = repo[None]
6402 ctx = repo[None]
6403 parents = ctx.parents()
6403 parents = ctx.parents()
6404 pnode = parents[0].node()
6404 pnode = parents[0].node()
6405 marks = []
6405 marks = []
6406
6406
6407 for p in parents:
6407 for p in parents:
6408 # label with log.changeset (instead of log.parent) since this
6408 # label with log.changeset (instead of log.parent) since this
6409 # shows a working directory parent *changeset*:
6409 # shows a working directory parent *changeset*:
6410 # i18n: column positioning for "hg summary"
6410 # i18n: column positioning for "hg summary"
6411 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6411 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6412 label='log.changeset changeset.%s' % p.phasestr())
6412 label='log.changeset changeset.%s' % p.phasestr())
6413 ui.write(' '.join(p.tags()), label='log.tag')
6413 ui.write(' '.join(p.tags()), label='log.tag')
6414 if p.bookmarks():
6414 if p.bookmarks():
6415 marks.extend(p.bookmarks())
6415 marks.extend(p.bookmarks())
6416 if p.rev() == -1:
6416 if p.rev() == -1:
6417 if not len(repo):
6417 if not len(repo):
6418 ui.write(_(' (empty repository)'))
6418 ui.write(_(' (empty repository)'))
6419 else:
6419 else:
6420 ui.write(_(' (no revision checked out)'))
6420 ui.write(_(' (no revision checked out)'))
6421 ui.write('\n')
6421 ui.write('\n')
6422 if p.description():
6422 if p.description():
6423 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6423 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6424 label='log.summary')
6424 label='log.summary')
6425
6425
6426 branch = ctx.branch()
6426 branch = ctx.branch()
6427 bheads = repo.branchheads(branch)
6427 bheads = repo.branchheads(branch)
6428 # i18n: column positioning for "hg summary"
6428 # i18n: column positioning for "hg summary"
6429 m = _('branch: %s\n') % branch
6429 m = _('branch: %s\n') % branch
6430 if branch != 'default':
6430 if branch != 'default':
6431 ui.write(m, label='log.branch')
6431 ui.write(m, label='log.branch')
6432 else:
6432 else:
6433 ui.status(m, label='log.branch')
6433 ui.status(m, label='log.branch')
6434
6434
6435 if marks:
6435 if marks:
6436 active = repo._activebookmark
6436 active = repo._activebookmark
6437 # i18n: column positioning for "hg summary"
6437 # i18n: column positioning for "hg summary"
6438 ui.write(_('bookmarks:'), label='log.bookmark')
6438 ui.write(_('bookmarks:'), label='log.bookmark')
6439 if active is not None:
6439 if active is not None:
6440 if active in marks:
6440 if active in marks:
6441 ui.write(' *' + active, label=activebookmarklabel)
6441 ui.write(' *' + active, label=activebookmarklabel)
6442 marks.remove(active)
6442 marks.remove(active)
6443 else:
6443 else:
6444 ui.write(' [%s]' % active, label=activebookmarklabel)
6444 ui.write(' [%s]' % active, label=activebookmarklabel)
6445 for m in marks:
6445 for m in marks:
6446 ui.write(' ' + m, label='log.bookmark')
6446 ui.write(' ' + m, label='log.bookmark')
6447 ui.write('\n', label='log.bookmark')
6447 ui.write('\n', label='log.bookmark')
6448
6448
6449 status = repo.status(unknown=True)
6449 status = repo.status(unknown=True)
6450
6450
6451 c = repo.dirstate.copies()
6451 c = repo.dirstate.copies()
6452 copied, renamed = [], []
6452 copied, renamed = [], []
6453 for d, s in c.iteritems():
6453 for d, s in c.iteritems():
6454 if s in status.removed:
6454 if s in status.removed:
6455 status.removed.remove(s)
6455 status.removed.remove(s)
6456 renamed.append(d)
6456 renamed.append(d)
6457 else:
6457 else:
6458 copied.append(d)
6458 copied.append(d)
6459 if d in status.added:
6459 if d in status.added:
6460 status.added.remove(d)
6460 status.added.remove(d)
6461
6461
6462 try:
6462 try:
6463 ms = mergemod.mergestate.read(repo)
6463 ms = mergemod.mergestate.read(repo)
6464 except error.UnsupportedMergeRecords as e:
6464 except error.UnsupportedMergeRecords as e:
6465 s = ' '.join(e.recordtypes)
6465 s = ' '.join(e.recordtypes)
6466 ui.warn(
6466 ui.warn(
6467 _('warning: merge state has unsupported record types: %s\n') % s)
6467 _('warning: merge state has unsupported record types: %s\n') % s)
6468 unresolved = 0
6468 unresolved = 0
6469 else:
6469 else:
6470 unresolved = [f for f in ms if ms[f] == 'u']
6470 unresolved = [f for f in ms if ms[f] == 'u']
6471
6471
6472 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6472 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6473
6473
6474 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6474 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6475 (ui.label(_('%d added'), 'status.added'), status.added),
6475 (ui.label(_('%d added'), 'status.added'), status.added),
6476 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6476 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6477 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6477 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6478 (ui.label(_('%d copied'), 'status.copied'), copied),
6478 (ui.label(_('%d copied'), 'status.copied'), copied),
6479 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6479 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6480 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6480 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6481 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6481 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6482 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6482 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6483 t = []
6483 t = []
6484 for l, s in labels:
6484 for l, s in labels:
6485 if s:
6485 if s:
6486 t.append(l % len(s))
6486 t.append(l % len(s))
6487
6487
6488 t = ', '.join(t)
6488 t = ', '.join(t)
6489 cleanworkdir = False
6489 cleanworkdir = False
6490
6490
6491 if repo.vfs.exists('graftstate'):
6491 if repo.vfs.exists('graftstate'):
6492 t += _(' (graft in progress)')
6492 t += _(' (graft in progress)')
6493 if repo.vfs.exists('updatestate'):
6493 if repo.vfs.exists('updatestate'):
6494 t += _(' (interrupted update)')
6494 t += _(' (interrupted update)')
6495 elif len(parents) > 1:
6495 elif len(parents) > 1:
6496 t += _(' (merge)')
6496 t += _(' (merge)')
6497 elif branch != parents[0].branch():
6497 elif branch != parents[0].branch():
6498 t += _(' (new branch)')
6498 t += _(' (new branch)')
6499 elif (parents[0].closesbranch() and
6499 elif (parents[0].closesbranch() and
6500 pnode in repo.branchheads(branch, closed=True)):
6500 pnode in repo.branchheads(branch, closed=True)):
6501 t += _(' (head closed)')
6501 t += _(' (head closed)')
6502 elif not (status.modified or status.added or status.removed or renamed or
6502 elif not (status.modified or status.added or status.removed or renamed or
6503 copied or subs):
6503 copied or subs):
6504 t += _(' (clean)')
6504 t += _(' (clean)')
6505 cleanworkdir = True
6505 cleanworkdir = True
6506 elif pnode not in bheads:
6506 elif pnode not in bheads:
6507 t += _(' (new branch head)')
6507 t += _(' (new branch head)')
6508
6508
6509 if parents:
6509 if parents:
6510 pendingphase = max(p.phase() for p in parents)
6510 pendingphase = max(p.phase() for p in parents)
6511 else:
6511 else:
6512 pendingphase = phases.public
6512 pendingphase = phases.public
6513
6513
6514 if pendingphase > phases.newcommitphase(ui):
6514 if pendingphase > phases.newcommitphase(ui):
6515 t += ' (%s)' % phases.phasenames[pendingphase]
6515 t += ' (%s)' % phases.phasenames[pendingphase]
6516
6516
6517 if cleanworkdir:
6517 if cleanworkdir:
6518 # i18n: column positioning for "hg summary"
6518 # i18n: column positioning for "hg summary"
6519 ui.status(_('commit: %s\n') % t.strip())
6519 ui.status(_('commit: %s\n') % t.strip())
6520 else:
6520 else:
6521 # i18n: column positioning for "hg summary"
6521 # i18n: column positioning for "hg summary"
6522 ui.write(_('commit: %s\n') % t.strip())
6522 ui.write(_('commit: %s\n') % t.strip())
6523
6523
6524 # all ancestors of branch heads - all ancestors of parent = new csets
6524 # all ancestors of branch heads - all ancestors of parent = new csets
6525 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6525 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6526 bheads))
6526 bheads))
6527
6527
6528 if new == 0:
6528 if new == 0:
6529 # i18n: column positioning for "hg summary"
6529 # i18n: column positioning for "hg summary"
6530 ui.status(_('update: (current)\n'))
6530 ui.status(_('update: (current)\n'))
6531 elif pnode not in bheads:
6531 elif pnode not in bheads:
6532 # i18n: column positioning for "hg summary"
6532 # i18n: column positioning for "hg summary"
6533 ui.write(_('update: %d new changesets (update)\n') % new)
6533 ui.write(_('update: %d new changesets (update)\n') % new)
6534 else:
6534 else:
6535 # i18n: column positioning for "hg summary"
6535 # i18n: column positioning for "hg summary"
6536 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6536 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6537 (new, len(bheads)))
6537 (new, len(bheads)))
6538
6538
6539 t = []
6539 t = []
6540 draft = len(repo.revs('draft()'))
6540 draft = len(repo.revs('draft()'))
6541 if draft:
6541 if draft:
6542 t.append(_('%d draft') % draft)
6542 t.append(_('%d draft') % draft)
6543 secret = len(repo.revs('secret()'))
6543 secret = len(repo.revs('secret()'))
6544 if secret:
6544 if secret:
6545 t.append(_('%d secret') % secret)
6545 t.append(_('%d secret') % secret)
6546
6546
6547 if draft or secret:
6547 if draft or secret:
6548 ui.status(_('phases: %s\n') % ', '.join(t))
6548 ui.status(_('phases: %s\n') % ', '.join(t))
6549
6549
6550 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6550 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6551 for trouble in ("unstable", "divergent", "bumped"):
6551 for trouble in ("unstable", "divergent", "bumped"):
6552 numtrouble = len(repo.revs(trouble + "()"))
6552 numtrouble = len(repo.revs(trouble + "()"))
6553 # We write all the possibilities to ease translation
6553 # We write all the possibilities to ease translation
6554 troublemsg = {
6554 troublemsg = {
6555 "unstable": _("unstable: %d changesets"),
6555 "unstable": _("unstable: %d changesets"),
6556 "divergent": _("divergent: %d changesets"),
6556 "divergent": _("divergent: %d changesets"),
6557 "bumped": _("bumped: %d changesets"),
6557 "bumped": _("bumped: %d changesets"),
6558 }
6558 }
6559 if numtrouble > 0:
6559 if numtrouble > 0:
6560 ui.status(troublemsg[trouble] % numtrouble + "\n")
6560 ui.status(troublemsg[trouble] % numtrouble + "\n")
6561
6561
6562 cmdutil.summaryhooks(ui, repo)
6562 cmdutil.summaryhooks(ui, repo)
6563
6563
6564 if opts.get('remote'):
6564 if opts.get('remote'):
6565 needsincoming, needsoutgoing = True, True
6565 needsincoming, needsoutgoing = True, True
6566 else:
6566 else:
6567 needsincoming, needsoutgoing = False, False
6567 needsincoming, needsoutgoing = False, False
6568 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6568 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6569 if i:
6569 if i:
6570 needsincoming = True
6570 needsincoming = True
6571 if o:
6571 if o:
6572 needsoutgoing = True
6572 needsoutgoing = True
6573 if not needsincoming and not needsoutgoing:
6573 if not needsincoming and not needsoutgoing:
6574 return
6574 return
6575
6575
6576 def getincoming():
6576 def getincoming():
6577 source, branches = hg.parseurl(ui.expandpath('default'))
6577 source, branches = hg.parseurl(ui.expandpath('default'))
6578 sbranch = branches[0]
6578 sbranch = branches[0]
6579 try:
6579 try:
6580 other = hg.peer(repo, {}, source)
6580 other = hg.peer(repo, {}, source)
6581 except error.RepoError:
6581 except error.RepoError:
6582 if opts.get('remote'):
6582 if opts.get('remote'):
6583 raise
6583 raise
6584 return source, sbranch, None, None, None
6584 return source, sbranch, None, None, None
6585 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6585 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6586 if revs:
6586 if revs:
6587 revs = [other.lookup(rev) for rev in revs]
6587 revs = [other.lookup(rev) for rev in revs]
6588 ui.debug('comparing with %s\n' % util.hidepassword(source))
6588 ui.debug('comparing with %s\n' % util.hidepassword(source))
6589 repo.ui.pushbuffer()
6589 repo.ui.pushbuffer()
6590 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6590 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6591 repo.ui.popbuffer()
6591 repo.ui.popbuffer()
6592 return source, sbranch, other, commoninc, commoninc[1]
6592 return source, sbranch, other, commoninc, commoninc[1]
6593
6593
6594 if needsincoming:
6594 if needsincoming:
6595 source, sbranch, sother, commoninc, incoming = getincoming()
6595 source, sbranch, sother, commoninc, incoming = getincoming()
6596 else:
6596 else:
6597 source = sbranch = sother = commoninc = incoming = None
6597 source = sbranch = sother = commoninc = incoming = None
6598
6598
6599 def getoutgoing():
6599 def getoutgoing():
6600 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6600 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6601 dbranch = branches[0]
6601 dbranch = branches[0]
6602 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6602 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6603 if source != dest:
6603 if source != dest:
6604 try:
6604 try:
6605 dother = hg.peer(repo, {}, dest)
6605 dother = hg.peer(repo, {}, dest)
6606 except error.RepoError:
6606 except error.RepoError:
6607 if opts.get('remote'):
6607 if opts.get('remote'):
6608 raise
6608 raise
6609 return dest, dbranch, None, None
6609 return dest, dbranch, None, None
6610 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6610 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6611 elif sother is None:
6611 elif sother is None:
6612 # there is no explicit destination peer, but source one is invalid
6612 # there is no explicit destination peer, but source one is invalid
6613 return dest, dbranch, None, None
6613 return dest, dbranch, None, None
6614 else:
6614 else:
6615 dother = sother
6615 dother = sother
6616 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6616 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6617 common = None
6617 common = None
6618 else:
6618 else:
6619 common = commoninc
6619 common = commoninc
6620 if revs:
6620 if revs:
6621 revs = [repo.lookup(rev) for rev in revs]
6621 revs = [repo.lookup(rev) for rev in revs]
6622 repo.ui.pushbuffer()
6622 repo.ui.pushbuffer()
6623 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6623 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6624 commoninc=common)
6624 commoninc=common)
6625 repo.ui.popbuffer()
6625 repo.ui.popbuffer()
6626 return dest, dbranch, dother, outgoing
6626 return dest, dbranch, dother, outgoing
6627
6627
6628 if needsoutgoing:
6628 if needsoutgoing:
6629 dest, dbranch, dother, outgoing = getoutgoing()
6629 dest, dbranch, dother, outgoing = getoutgoing()
6630 else:
6630 else:
6631 dest = dbranch = dother = outgoing = None
6631 dest = dbranch = dother = outgoing = None
6632
6632
6633 if opts.get('remote'):
6633 if opts.get('remote'):
6634 t = []
6634 t = []
6635 if incoming:
6635 if incoming:
6636 t.append(_('1 or more incoming'))
6636 t.append(_('1 or more incoming'))
6637 o = outgoing.missing
6637 o = outgoing.missing
6638 if o:
6638 if o:
6639 t.append(_('%d outgoing') % len(o))
6639 t.append(_('%d outgoing') % len(o))
6640 other = dother or sother
6640 other = dother or sother
6641 if 'bookmarks' in other.listkeys('namespaces'):
6641 if 'bookmarks' in other.listkeys('namespaces'):
6642 counts = bookmarks.summary(repo, other)
6642 counts = bookmarks.summary(repo, other)
6643 if counts[0] > 0:
6643 if counts[0] > 0:
6644 t.append(_('%d incoming bookmarks') % counts[0])
6644 t.append(_('%d incoming bookmarks') % counts[0])
6645 if counts[1] > 0:
6645 if counts[1] > 0:
6646 t.append(_('%d outgoing bookmarks') % counts[1])
6646 t.append(_('%d outgoing bookmarks') % counts[1])
6647
6647
6648 if t:
6648 if t:
6649 # i18n: column positioning for "hg summary"
6649 # i18n: column positioning for "hg summary"
6650 ui.write(_('remote: %s\n') % (', '.join(t)))
6650 ui.write(_('remote: %s\n') % (', '.join(t)))
6651 else:
6651 else:
6652 # i18n: column positioning for "hg summary"
6652 # i18n: column positioning for "hg summary"
6653 ui.status(_('remote: (synced)\n'))
6653 ui.status(_('remote: (synced)\n'))
6654
6654
6655 cmdutil.summaryremotehooks(ui, repo, opts,
6655 cmdutil.summaryremotehooks(ui, repo, opts,
6656 ((source, sbranch, sother, commoninc),
6656 ((source, sbranch, sother, commoninc),
6657 (dest, dbranch, dother, outgoing)))
6657 (dest, dbranch, dother, outgoing)))
6658
6658
6659 @command('tag',
6659 @command('tag',
6660 [('f', 'force', None, _('force tag')),
6660 [('f', 'force', None, _('force tag')),
6661 ('l', 'local', None, _('make the tag local')),
6661 ('l', 'local', None, _('make the tag local')),
6662 ('r', 'rev', '', _('revision to tag'), _('REV')),
6662 ('r', 'rev', '', _('revision to tag'), _('REV')),
6663 ('', 'remove', None, _('remove a tag')),
6663 ('', 'remove', None, _('remove a tag')),
6664 # -l/--local is already there, commitopts cannot be used
6664 # -l/--local is already there, commitopts cannot be used
6665 ('e', 'edit', None, _('invoke editor on commit messages')),
6665 ('e', 'edit', None, _('invoke editor on commit messages')),
6666 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6666 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6667 ] + commitopts2,
6667 ] + commitopts2,
6668 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6668 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6669 def tag(ui, repo, name1, *names, **opts):
6669 def tag(ui, repo, name1, *names, **opts):
6670 """add one or more tags for the current or given revision
6670 """add one or more tags for the current or given revision
6671
6671
6672 Name a particular revision using <name>.
6672 Name a particular revision using <name>.
6673
6673
6674 Tags are used to name particular revisions of the repository and are
6674 Tags are used to name particular revisions of the repository and are
6675 very useful to compare different revisions, to go back to significant
6675 very useful to compare different revisions, to go back to significant
6676 earlier versions or to mark branch points as releases, etc. Changing
6676 earlier versions or to mark branch points as releases, etc. Changing
6677 an existing tag is normally disallowed; use -f/--force to override.
6677 an existing tag is normally disallowed; use -f/--force to override.
6678
6678
6679 If no revision is given, the parent of the working directory is
6679 If no revision is given, the parent of the working directory is
6680 used.
6680 used.
6681
6681
6682 To facilitate version control, distribution, and merging of tags,
6682 To facilitate version control, distribution, and merging of tags,
6683 they are stored as a file named ".hgtags" which is managed similarly
6683 they are stored as a file named ".hgtags" which is managed similarly
6684 to other project files and can be hand-edited if necessary. This
6684 to other project files and can be hand-edited if necessary. This
6685 also means that tagging creates a new commit. The file
6685 also means that tagging creates a new commit. The file
6686 ".hg/localtags" is used for local tags (not shared among
6686 ".hg/localtags" is used for local tags (not shared among
6687 repositories).
6687 repositories).
6688
6688
6689 Tag commits are usually made at the head of a branch. If the parent
6689 Tag commits are usually made at the head of a branch. If the parent
6690 of the working directory is not a branch head, :hg:`tag` aborts; use
6690 of the working directory is not a branch head, :hg:`tag` aborts; use
6691 -f/--force to force the tag commit to be based on a non-head
6691 -f/--force to force the tag commit to be based on a non-head
6692 changeset.
6692 changeset.
6693
6693
6694 See :hg:`help dates` for a list of formats valid for -d/--date.
6694 See :hg:`help dates` for a list of formats valid for -d/--date.
6695
6695
6696 Since tag names have priority over branch names during revision
6696 Since tag names have priority over branch names during revision
6697 lookup, using an existing branch name as a tag name is discouraged.
6697 lookup, using an existing branch name as a tag name is discouraged.
6698
6698
6699 Returns 0 on success.
6699 Returns 0 on success.
6700 """
6700 """
6701 wlock = lock = None
6701 wlock = lock = None
6702 try:
6702 try:
6703 wlock = repo.wlock()
6703 wlock = repo.wlock()
6704 lock = repo.lock()
6704 lock = repo.lock()
6705 rev_ = "."
6705 rev_ = "."
6706 names = [t.strip() for t in (name1,) + names]
6706 names = [t.strip() for t in (name1,) + names]
6707 if len(names) != len(set(names)):
6707 if len(names) != len(set(names)):
6708 raise error.Abort(_('tag names must be unique'))
6708 raise error.Abort(_('tag names must be unique'))
6709 for n in names:
6709 for n in names:
6710 scmutil.checknewlabel(repo, n, 'tag')
6710 scmutil.checknewlabel(repo, n, 'tag')
6711 if not n:
6711 if not n:
6712 raise error.Abort(_('tag names cannot consist entirely of '
6712 raise error.Abort(_('tag names cannot consist entirely of '
6713 'whitespace'))
6713 'whitespace'))
6714 if opts.get('rev') and opts.get('remove'):
6714 if opts.get('rev') and opts.get('remove'):
6715 raise error.Abort(_("--rev and --remove are incompatible"))
6715 raise error.Abort(_("--rev and --remove are incompatible"))
6716 if opts.get('rev'):
6716 if opts.get('rev'):
6717 rev_ = opts['rev']
6717 rev_ = opts['rev']
6718 message = opts.get('message')
6718 message = opts.get('message')
6719 if opts.get('remove'):
6719 if opts.get('remove'):
6720 if opts.get('local'):
6720 if opts.get('local'):
6721 expectedtype = 'local'
6721 expectedtype = 'local'
6722 else:
6722 else:
6723 expectedtype = 'global'
6723 expectedtype = 'global'
6724
6724
6725 for n in names:
6725 for n in names:
6726 if not repo.tagtype(n):
6726 if not repo.tagtype(n):
6727 raise error.Abort(_("tag '%s' does not exist") % n)
6727 raise error.Abort(_("tag '%s' does not exist") % n)
6728 if repo.tagtype(n) != expectedtype:
6728 if repo.tagtype(n) != expectedtype:
6729 if expectedtype == 'global':
6729 if expectedtype == 'global':
6730 raise error.Abort(_("tag '%s' is not a global tag") % n)
6730 raise error.Abort(_("tag '%s' is not a global tag") % n)
6731 else:
6731 else:
6732 raise error.Abort(_("tag '%s' is not a local tag") % n)
6732 raise error.Abort(_("tag '%s' is not a local tag") % n)
6733 rev_ = 'null'
6733 rev_ = 'null'
6734 if not message:
6734 if not message:
6735 # we don't translate commit messages
6735 # we don't translate commit messages
6736 message = 'Removed tag %s' % ', '.join(names)
6736 message = 'Removed tag %s' % ', '.join(names)
6737 elif not opts.get('force'):
6737 elif not opts.get('force'):
6738 for n in names:
6738 for n in names:
6739 if n in repo.tags():
6739 if n in repo.tags():
6740 raise error.Abort(_("tag '%s' already exists "
6740 raise error.Abort(_("tag '%s' already exists "
6741 "(use -f to force)") % n)
6741 "(use -f to force)") % n)
6742 if not opts.get('local'):
6742 if not opts.get('local'):
6743 p1, p2 = repo.dirstate.parents()
6743 p1, p2 = repo.dirstate.parents()
6744 if p2 != nullid:
6744 if p2 != nullid:
6745 raise error.Abort(_('uncommitted merge'))
6745 raise error.Abort(_('uncommitted merge'))
6746 bheads = repo.branchheads()
6746 bheads = repo.branchheads()
6747 if not opts.get('force') and bheads and p1 not in bheads:
6747 if not opts.get('force') and bheads and p1 not in bheads:
6748 raise error.Abort(_('not at a branch head (use -f to force)'))
6748 raise error.Abort(_('not at a branch head (use -f to force)'))
6749 r = scmutil.revsingle(repo, rev_).node()
6749 r = scmutil.revsingle(repo, rev_).node()
6750
6750
6751 if not message:
6751 if not message:
6752 # we don't translate commit messages
6752 # we don't translate commit messages
6753 message = ('Added tag %s for changeset %s' %
6753 message = ('Added tag %s for changeset %s' %
6754 (', '.join(names), short(r)))
6754 (', '.join(names), short(r)))
6755
6755
6756 date = opts.get('date')
6756 date = opts.get('date')
6757 if date:
6757 if date:
6758 date = util.parsedate(date)
6758 date = util.parsedate(date)
6759
6759
6760 if opts.get('remove'):
6760 if opts.get('remove'):
6761 editform = 'tag.remove'
6761 editform = 'tag.remove'
6762 else:
6762 else:
6763 editform = 'tag.add'
6763 editform = 'tag.add'
6764 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6764 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6765
6765
6766 # don't allow tagging the null rev
6766 # don't allow tagging the null rev
6767 if (not opts.get('remove') and
6767 if (not opts.get('remove') and
6768 scmutil.revsingle(repo, rev_).rev() == nullrev):
6768 scmutil.revsingle(repo, rev_).rev() == nullrev):
6769 raise error.Abort(_("cannot tag null revision"))
6769 raise error.Abort(_("cannot tag null revision"))
6770
6770
6771 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6771 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6772 editor=editor)
6772 editor=editor)
6773 finally:
6773 finally:
6774 release(lock, wlock)
6774 release(lock, wlock)
6775
6775
6776 @command('tags', formatteropts, '')
6776 @command('tags', formatteropts, '')
6777 def tags(ui, repo, **opts):
6777 def tags(ui, repo, **opts):
6778 """list repository tags
6778 """list repository tags
6779
6779
6780 This lists both regular and local tags. When the -v/--verbose
6780 This lists both regular and local tags. When the -v/--verbose
6781 switch is used, a third column "local" is printed for local tags.
6781 switch is used, a third column "local" is printed for local tags.
6782 When the -q/--quiet switch is used, only the tag name is printed.
6782 When the -q/--quiet switch is used, only the tag name is printed.
6783
6783
6784 Returns 0 on success.
6784 Returns 0 on success.
6785 """
6785 """
6786
6786
6787 fm = ui.formatter('tags', opts)
6787 fm = ui.formatter('tags', opts)
6788 hexfunc = fm.hexfunc
6788 hexfunc = fm.hexfunc
6789 tagtype = ""
6789 tagtype = ""
6790
6790
6791 for t, n in reversed(repo.tagslist()):
6791 for t, n in reversed(repo.tagslist()):
6792 hn = hexfunc(n)
6792 hn = hexfunc(n)
6793 label = 'tags.normal'
6793 label = 'tags.normal'
6794 tagtype = ''
6794 tagtype = ''
6795 if repo.tagtype(t) == 'local':
6795 if repo.tagtype(t) == 'local':
6796 label = 'tags.local'
6796 label = 'tags.local'
6797 tagtype = 'local'
6797 tagtype = 'local'
6798
6798
6799 fm.startitem()
6799 fm.startitem()
6800 fm.write('tag', '%s', t, label=label)
6800 fm.write('tag', '%s', t, label=label)
6801 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6801 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6802 fm.condwrite(not ui.quiet, 'rev node', fmt,
6802 fm.condwrite(not ui.quiet, 'rev node', fmt,
6803 repo.changelog.rev(n), hn, label=label)
6803 repo.changelog.rev(n), hn, label=label)
6804 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6804 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6805 tagtype, label=label)
6805 tagtype, label=label)
6806 fm.plain('\n')
6806 fm.plain('\n')
6807 fm.end()
6807 fm.end()
6808
6808
6809 @command('tip',
6809 @command('tip',
6810 [('p', 'patch', None, _('show patch')),
6810 [('p', 'patch', None, _('show patch')),
6811 ('g', 'git', None, _('use git extended diff format')),
6811 ('g', 'git', None, _('use git extended diff format')),
6812 ] + templateopts,
6812 ] + templateopts,
6813 _('[-p] [-g]'))
6813 _('[-p] [-g]'))
6814 def tip(ui, repo, **opts):
6814 def tip(ui, repo, **opts):
6815 """show the tip revision (DEPRECATED)
6815 """show the tip revision (DEPRECATED)
6816
6816
6817 The tip revision (usually just called the tip) is the changeset
6817 The tip revision (usually just called the tip) is the changeset
6818 most recently added to the repository (and therefore the most
6818 most recently added to the repository (and therefore the most
6819 recently changed head).
6819 recently changed head).
6820
6820
6821 If you have just made a commit, that commit will be the tip. If
6821 If you have just made a commit, that commit will be the tip. If
6822 you have just pulled changes from another repository, the tip of
6822 you have just pulled changes from another repository, the tip of
6823 that repository becomes the current tip. The "tip" tag is special
6823 that repository becomes the current tip. The "tip" tag is special
6824 and cannot be renamed or assigned to a different changeset.
6824 and cannot be renamed or assigned to a different changeset.
6825
6825
6826 This command is deprecated, please use :hg:`heads` instead.
6826 This command is deprecated, please use :hg:`heads` instead.
6827
6827
6828 Returns 0 on success.
6828 Returns 0 on success.
6829 """
6829 """
6830 displayer = cmdutil.show_changeset(ui, repo, opts)
6830 displayer = cmdutil.show_changeset(ui, repo, opts)
6831 displayer.show(repo['tip'])
6831 displayer.show(repo['tip'])
6832 displayer.close()
6832 displayer.close()
6833
6833
6834 @command('unbundle',
6834 @command('unbundle',
6835 [('u', 'update', None,
6835 [('u', 'update', None,
6836 _('update to new branch head if changesets were unbundled'))],
6836 _('update to new branch head if changesets were unbundled'))],
6837 _('[-u] FILE...'))
6837 _('[-u] FILE...'))
6838 def unbundle(ui, repo, fname1, *fnames, **opts):
6838 def unbundle(ui, repo, fname1, *fnames, **opts):
6839 """apply one or more changegroup files
6839 """apply one or more changegroup files
6840
6840
6841 Apply one or more compressed changegroup files generated by the
6841 Apply one or more compressed changegroup files generated by the
6842 bundle command.
6842 bundle command.
6843
6843
6844 Returns 0 on success, 1 if an update has unresolved files.
6844 Returns 0 on success, 1 if an update has unresolved files.
6845 """
6845 """
6846 fnames = (fname1,) + fnames
6846 fnames = (fname1,) + fnames
6847
6847
6848 with repo.lock():
6848 with repo.lock():
6849 for fname in fnames:
6849 for fname in fnames:
6850 f = hg.openpath(ui, fname)
6850 f = hg.openpath(ui, fname)
6851 gen = exchange.readbundle(ui, f, fname)
6851 gen = exchange.readbundle(ui, f, fname)
6852 if isinstance(gen, bundle2.unbundle20):
6852 if isinstance(gen, bundle2.unbundle20):
6853 tr = repo.transaction('unbundle')
6853 tr = repo.transaction('unbundle')
6854 try:
6854 try:
6855 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6855 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6856 url='bundle:' + fname)
6856 url='bundle:' + fname)
6857 tr.close()
6857 tr.close()
6858 except error.BundleUnknownFeatureError as exc:
6858 except error.BundleUnknownFeatureError as exc:
6859 raise error.Abort(_('%s: unknown bundle feature, %s')
6859 raise error.Abort(_('%s: unknown bundle feature, %s')
6860 % (fname, exc),
6860 % (fname, exc),
6861 hint=_("see https://mercurial-scm.org/"
6861 hint=_("see https://mercurial-scm.org/"
6862 "wiki/BundleFeature for more "
6862 "wiki/BundleFeature for more "
6863 "information"))
6863 "information"))
6864 finally:
6864 finally:
6865 if tr:
6865 if tr:
6866 tr.release()
6866 tr.release()
6867 changes = [r.get('return', 0)
6867 changes = [r.get('return', 0)
6868 for r in op.records['changegroup']]
6868 for r in op.records['changegroup']]
6869 modheads = changegroup.combineresults(changes)
6869 modheads = changegroup.combineresults(changes)
6870 elif isinstance(gen, streamclone.streamcloneapplier):
6870 elif isinstance(gen, streamclone.streamcloneapplier):
6871 raise error.Abort(
6871 raise error.Abort(
6872 _('packed bundles cannot be applied with '
6872 _('packed bundles cannot be applied with '
6873 '"hg unbundle"'),
6873 '"hg unbundle"'),
6874 hint=_('use "hg debugapplystreamclonebundle"'))
6874 hint=_('use "hg debugapplystreamclonebundle"'))
6875 else:
6875 else:
6876 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6876 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6877
6877
6878 return postincoming(ui, repo, modheads, opts.get('update'), None)
6878 return postincoming(ui, repo, modheads, opts.get('update'), None)
6879
6879
6880 @command('^update|up|checkout|co',
6880 @command('^update|up|checkout|co',
6881 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6881 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6882 ('c', 'check', None,
6882 ('c', 'check', None,
6883 _('update across branches if no uncommitted changes')),
6883 _('update across branches if no uncommitted changes')),
6884 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6884 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6885 ('r', 'rev', '', _('revision'), _('REV'))
6885 ('r', 'rev', '', _('revision'), _('REV'))
6886 ] + mergetoolopts,
6886 ] + mergetoolopts,
6887 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6887 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6888 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6888 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6889 tool=None):
6889 tool=None):
6890 """update working directory (or switch revisions)
6890 """update working directory (or switch revisions)
6891
6891
6892 Update the repository's working directory to the specified
6892 Update the repository's working directory to the specified
6893 changeset. If no changeset is specified, update to the tip of the
6893 changeset. If no changeset is specified, update to the tip of the
6894 current named branch and move the active bookmark (see :hg:`help
6894 current named branch and move the active bookmark (see :hg:`help
6895 bookmarks`).
6895 bookmarks`).
6896
6896
6897 Update sets the working directory's parent revision to the specified
6897 Update sets the working directory's parent revision to the specified
6898 changeset (see :hg:`help parents`).
6898 changeset (see :hg:`help parents`).
6899
6899
6900 If the changeset is not a descendant or ancestor of the working
6900 If the changeset is not a descendant or ancestor of the working
6901 directory's parent, the update is aborted. With the -c/--check
6901 directory's parent, the update is aborted. With the -c/--check
6902 option, the working directory is checked for uncommitted changes; if
6902 option, the working directory is checked for uncommitted changes; if
6903 none are found, the working directory is updated to the specified
6903 none are found, the working directory is updated to the specified
6904 changeset.
6904 changeset.
6905
6905
6906 .. container:: verbose
6906 .. container:: verbose
6907
6907
6908 The following rules apply when the working directory contains
6908 The following rules apply when the working directory contains
6909 uncommitted changes:
6909 uncommitted changes:
6910
6910
6911 1. If neither -c/--check nor -C/--clean is specified, and if
6911 1. If neither -c/--check nor -C/--clean is specified, and if
6912 the requested changeset is an ancestor or descendant of
6912 the requested changeset is an ancestor or descendant of
6913 the working directory's parent, the uncommitted changes
6913 the working directory's parent, the uncommitted changes
6914 are merged into the requested changeset and the merged
6914 are merged into the requested changeset and the merged
6915 result is left uncommitted. If the requested changeset is
6915 result is left uncommitted. If the requested changeset is
6916 not an ancestor or descendant (that is, it is on another
6916 not an ancestor or descendant (that is, it is on another
6917 branch), the update is aborted and the uncommitted changes
6917 branch), the update is aborted and the uncommitted changes
6918 are preserved.
6918 are preserved.
6919
6919
6920 2. With the -c/--check option, the update is aborted and the
6920 2. With the -c/--check option, the update is aborted and the
6921 uncommitted changes are preserved.
6921 uncommitted changes are preserved.
6922
6922
6923 3. With the -C/--clean option, uncommitted changes are discarded and
6923 3. With the -C/--clean option, uncommitted changes are discarded and
6924 the working directory is updated to the requested changeset.
6924 the working directory is updated to the requested changeset.
6925
6925
6926 To cancel an uncommitted merge (and lose your changes), use
6926 To cancel an uncommitted merge (and lose your changes), use
6927 :hg:`update --clean .`.
6927 :hg:`update --clean .`.
6928
6928
6929 Use null as the changeset to remove the working directory (like
6929 Use null as the changeset to remove the working directory (like
6930 :hg:`clone -U`).
6930 :hg:`clone -U`).
6931
6931
6932 If you want to revert just one file to an older revision, use
6932 If you want to revert just one file to an older revision, use
6933 :hg:`revert [-r REV] NAME`.
6933 :hg:`revert [-r REV] NAME`.
6934
6934
6935 See :hg:`help dates` for a list of formats valid for -d/--date.
6935 See :hg:`help dates` for a list of formats valid for -d/--date.
6936
6936
6937 Returns 0 on success, 1 if there are unresolved files.
6937 Returns 0 on success, 1 if there are unresolved files.
6938 """
6938 """
6939 movemarkfrom = None
6939 movemarkfrom = None
6940 if rev and node:
6940 if rev and node:
6941 raise error.Abort(_("please specify just one revision"))
6941 raise error.Abort(_("please specify just one revision"))
6942
6942
6943 if rev is None or rev == '':
6943 if rev is None or rev == '':
6944 rev = node
6944 rev = node
6945
6945
6946 with repo.wlock():
6946 with repo.wlock():
6947 cmdutil.clearunfinished(repo)
6947 cmdutil.clearunfinished(repo)
6948
6948
6949 if date:
6949 if date:
6950 if rev is not None:
6950 if rev is not None:
6951 raise error.Abort(_("you can't specify a revision and a date"))
6951 raise error.Abort(_("you can't specify a revision and a date"))
6952 rev = cmdutil.finddate(ui, repo, date)
6952 rev = cmdutil.finddate(ui, repo, date)
6953
6953
6954 # if we defined a bookmark, we have to remember the original name
6954 # if we defined a bookmark, we have to remember the original name
6955 brev = rev
6955 brev = rev
6956 rev = scmutil.revsingle(repo, rev, rev).rev()
6956 rev = scmutil.revsingle(repo, rev, rev).rev()
6957
6957
6958 if check and clean:
6958 if check and clean:
6959 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6959 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6960 )
6960 )
6961
6961
6962 if check:
6962 if check:
6963 cmdutil.bailifchanged(repo, merge=False)
6963 cmdutil.bailifchanged(repo, merge=False)
6964 if rev is None:
6964 if rev is None:
6965 updata = destutil.destupdate(repo, clean=clean, check=check)
6965 updata = destutil.destupdate(repo, clean=clean, check=check)
6966 rev, movemarkfrom, brev = updata
6966 rev, movemarkfrom, brev = updata
6967
6967
6968 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6968 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6969
6969
6970 if clean:
6970 if clean:
6971 ret = hg.clean(repo, rev)
6971 ret = hg.clean(repo, rev)
6972 else:
6972 else:
6973 ret = hg.update(repo, rev)
6973 ret = hg.update(repo, rev)
6974
6974
6975 if not ret and movemarkfrom:
6975 if not ret and movemarkfrom:
6976 if movemarkfrom == repo['.'].node():
6976 if movemarkfrom == repo['.'].node():
6977 pass # no-op update
6977 pass # no-op update
6978 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6978 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6979 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6979 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6980 else:
6980 else:
6981 # this can happen with a non-linear update
6981 # this can happen with a non-linear update
6982 ui.status(_("(leaving bookmark %s)\n") %
6982 ui.status(_("(leaving bookmark %s)\n") %
6983 repo._activebookmark)
6983 repo._activebookmark)
6984 bookmarks.deactivate(repo)
6984 bookmarks.deactivate(repo)
6985 elif brev in repo._bookmarks:
6985 elif brev in repo._bookmarks:
6986 bookmarks.activate(repo, brev)
6986 bookmarks.activate(repo, brev)
6987 ui.status(_("(activating bookmark %s)\n") % brev)
6987 ui.status(_("(activating bookmark %s)\n") % brev)
6988 elif brev:
6988 elif brev:
6989 if repo._activebookmark:
6989 if repo._activebookmark:
6990 ui.status(_("(leaving bookmark %s)\n") %
6990 ui.status(_("(leaving bookmark %s)\n") %
6991 repo._activebookmark)
6991 repo._activebookmark)
6992 bookmarks.deactivate(repo)
6992 bookmarks.deactivate(repo)
6993
6993
6994 return ret
6994 return ret
6995
6995
6996 @command('verify', [])
6996 @command('verify', [])
6997 def verify(ui, repo):
6997 def verify(ui, repo):
6998 """verify the integrity of the repository
6998 """verify the integrity of the repository
6999
6999
7000 Verify the integrity of the current repository.
7000 Verify the integrity of the current repository.
7001
7001
7002 This will perform an extensive check of the repository's
7002 This will perform an extensive check of the repository's
7003 integrity, validating the hashes and checksums of each entry in
7003 integrity, validating the hashes and checksums of each entry in
7004 the changelog, manifest, and tracked files, as well as the
7004 the changelog, manifest, and tracked files, as well as the
7005 integrity of their crosslinks and indices.
7005 integrity of their crosslinks and indices.
7006
7006
7007 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7007 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7008 for more information about recovery from corruption of the
7008 for more information about recovery from corruption of the
7009 repository.
7009 repository.
7010
7010
7011 Returns 0 on success, 1 if errors are encountered.
7011 Returns 0 on success, 1 if errors are encountered.
7012 """
7012 """
7013 return hg.verify(repo)
7013 return hg.verify(repo)
7014
7014
7015 @command('version', [], norepo=True)
7015 @command('version', [], norepo=True)
7016 def version_(ui):
7016 def version_(ui):
7017 """output version and copyright information"""
7017 """output version and copyright information"""
7018 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7018 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7019 % util.version())
7019 % util.version())
7020 ui.status(_(
7020 ui.status(_(
7021 "(see https://mercurial-scm.org for more information)\n"
7021 "(see https://mercurial-scm.org for more information)\n"
7022 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7022 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7023 "This is free software; see the source for copying conditions. "
7023 "This is free software; see the source for copying conditions. "
7024 "There is NO\nwarranty; "
7024 "There is NO\nwarranty; "
7025 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7025 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7026 ))
7026 ))
7027
7027
7028 ui.note(_("\nEnabled extensions:\n\n"))
7028 ui.note(_("\nEnabled extensions:\n\n"))
7029 if ui.verbose:
7029 if ui.verbose:
7030 # format names and versions into columns
7030 # format names and versions into columns
7031 names = []
7031 names = []
7032 vers = []
7032 vers = []
7033 place = []
7033 for name, module in extensions.extensions():
7034 for name, module in extensions.extensions():
7034 names.append(name)
7035 names.append(name)
7035 vers.append(extensions.moduleversion(module))
7036 vers.append(extensions.moduleversion(module))
7037 if extensions.ismoduleinternal(module):
7038 place.append(_("internal"))
7039 else:
7040 place.append(_("external"))
7036 if names:
7041 if names:
7037 maxnamelen = max(len(n) for n in names)
7042 maxnamelen = max(len(n) for n in names)
7038 for i, name in enumerate(names):
7043 for i, name in enumerate(names):
7039 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
7044 ui.write(" %-*s %s %s\n" %
7045 (maxnamelen, name, place[i], vers[i]))
@@ -1,470 +1,474 b''
1 # extensions.py - extension handling for mercurial
1 # extensions.py - extension handling 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import imp
10 import imp
11 import os
11 import os
12
12
13 from .i18n import (
13 from .i18n import (
14 _,
14 _,
15 gettext,
15 gettext,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 cmdutil,
19 cmdutil,
20 error,
20 error,
21 util,
21 util,
22 )
22 )
23
23
24 _extensions = {}
24 _extensions = {}
25 _aftercallbacks = {}
25 _aftercallbacks = {}
26 _order = []
26 _order = []
27 _builtin = set(['hbisect', 'bookmarks', 'parentrevspec', 'progress', 'interhg',
27 _builtin = set(['hbisect', 'bookmarks', 'parentrevspec', 'progress', 'interhg',
28 'inotify'])
28 'inotify'])
29
29
30 def extensions(ui=None):
30 def extensions(ui=None):
31 if ui:
31 if ui:
32 def enabled(name):
32 def enabled(name):
33 for format in ['%s', 'hgext.%s']:
33 for format in ['%s', 'hgext.%s']:
34 conf = ui.config('extensions', format % name)
34 conf = ui.config('extensions', format % name)
35 if conf is not None and not conf.startswith('!'):
35 if conf is not None and not conf.startswith('!'):
36 return True
36 return True
37 else:
37 else:
38 enabled = lambda name: True
38 enabled = lambda name: True
39 for name in _order:
39 for name in _order:
40 module = _extensions[name]
40 module = _extensions[name]
41 if module and enabled(name):
41 if module and enabled(name):
42 yield name, module
42 yield name, module
43
43
44 def find(name):
44 def find(name):
45 '''return module with given extension name'''
45 '''return module with given extension name'''
46 mod = None
46 mod = None
47 try:
47 try:
48 mod = _extensions[name]
48 mod = _extensions[name]
49 except KeyError:
49 except KeyError:
50 for k, v in _extensions.iteritems():
50 for k, v in _extensions.iteritems():
51 if k.endswith('.' + name) or k.endswith('/' + name):
51 if k.endswith('.' + name) or k.endswith('/' + name):
52 mod = v
52 mod = v
53 break
53 break
54 if not mod:
54 if not mod:
55 raise KeyError(name)
55 raise KeyError(name)
56 return mod
56 return mod
57
57
58 def loadpath(path, module_name):
58 def loadpath(path, module_name):
59 module_name = module_name.replace('.', '_')
59 module_name = module_name.replace('.', '_')
60 path = util.normpath(util.expandpath(path))
60 path = util.normpath(util.expandpath(path))
61 if os.path.isdir(path):
61 if os.path.isdir(path):
62 # module/__init__.py style
62 # module/__init__.py style
63 d, f = os.path.split(path)
63 d, f = os.path.split(path)
64 fd, fpath, desc = imp.find_module(f, [d])
64 fd, fpath, desc = imp.find_module(f, [d])
65 return imp.load_module(module_name, fd, fpath, desc)
65 return imp.load_module(module_name, fd, fpath, desc)
66 else:
66 else:
67 try:
67 try:
68 return imp.load_source(module_name, path)
68 return imp.load_source(module_name, path)
69 except IOError as exc:
69 except IOError as exc:
70 if not exc.filename:
70 if not exc.filename:
71 exc.filename = path # python does not fill this
71 exc.filename = path # python does not fill this
72 raise
72 raise
73
73
74 def load(ui, name, path):
74 def load(ui, name, path):
75 if name.startswith('hgext.') or name.startswith('hgext/'):
75 if name.startswith('hgext.') or name.startswith('hgext/'):
76 shortname = name[6:]
76 shortname = name[6:]
77 else:
77 else:
78 shortname = name
78 shortname = name
79 if shortname in _builtin:
79 if shortname in _builtin:
80 return None
80 return None
81 if shortname in _extensions:
81 if shortname in _extensions:
82 return _extensions[shortname]
82 return _extensions[shortname]
83 _extensions[shortname] = None
83 _extensions[shortname] = None
84 if path:
84 if path:
85 # the module will be loaded in sys.modules
85 # the module will be loaded in sys.modules
86 # choose an unique name so that it doesn't
86 # choose an unique name so that it doesn't
87 # conflicts with other modules
87 # conflicts with other modules
88 mod = loadpath(path, 'hgext.%s' % name)
88 mod = loadpath(path, 'hgext.%s' % name)
89 else:
89 else:
90 def importh(name):
90 def importh(name):
91 mod = __import__(name)
91 mod = __import__(name)
92 components = name.split('.')
92 components = name.split('.')
93 for comp in components[1:]:
93 for comp in components[1:]:
94 mod = getattr(mod, comp)
94 mod = getattr(mod, comp)
95 return mod
95 return mod
96 try:
96 try:
97 mod = importh("hgext.%s" % name)
97 mod = importh("hgext.%s" % name)
98 except ImportError as err:
98 except ImportError as err:
99 ui.debug('could not import hgext.%s (%s): trying %s\n'
99 ui.debug('could not import hgext.%s (%s): trying %s\n'
100 % (name, err, name))
100 % (name, err, name))
101 if ui.debugflag:
101 if ui.debugflag:
102 ui.traceback()
102 ui.traceback()
103 mod = importh(name)
103 mod = importh(name)
104
104
105 # Before we do anything with the extension, check against minimum stated
105 # Before we do anything with the extension, check against minimum stated
106 # compatibility. This gives extension authors a mechanism to have their
106 # compatibility. This gives extension authors a mechanism to have their
107 # extensions short circuit when loaded with a known incompatible version
107 # extensions short circuit when loaded with a known incompatible version
108 # of Mercurial.
108 # of Mercurial.
109 minver = getattr(mod, 'minimumhgversion', None)
109 minver = getattr(mod, 'minimumhgversion', None)
110 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
110 if minver and util.versiontuple(minver, 2) > util.versiontuple(n=2):
111 ui.warn(_('(third party extension %s requires version %s or newer '
111 ui.warn(_('(third party extension %s requires version %s or newer '
112 'of Mercurial; disabling)\n') % (shortname, minver))
112 'of Mercurial; disabling)\n') % (shortname, minver))
113 return
113 return
114
114
115 _extensions[shortname] = mod
115 _extensions[shortname] = mod
116 _order.append(shortname)
116 _order.append(shortname)
117 for fn in _aftercallbacks.get(shortname, []):
117 for fn in _aftercallbacks.get(shortname, []):
118 fn(loaded=True)
118 fn(loaded=True)
119 return mod
119 return mod
120
120
121 def loadall(ui):
121 def loadall(ui):
122 result = ui.configitems("extensions")
122 result = ui.configitems("extensions")
123 newindex = len(_order)
123 newindex = len(_order)
124 for (name, path) in result:
124 for (name, path) in result:
125 if path:
125 if path:
126 if path[0] == '!':
126 if path[0] == '!':
127 continue
127 continue
128 try:
128 try:
129 load(ui, name, path)
129 load(ui, name, path)
130 except KeyboardInterrupt:
130 except KeyboardInterrupt:
131 raise
131 raise
132 except Exception as inst:
132 except Exception as inst:
133 if path:
133 if path:
134 ui.warn(_("*** failed to import extension %s from %s: %s\n")
134 ui.warn(_("*** failed to import extension %s from %s: %s\n")
135 % (name, path, inst))
135 % (name, path, inst))
136 else:
136 else:
137 ui.warn(_("*** failed to import extension %s: %s\n")
137 ui.warn(_("*** failed to import extension %s: %s\n")
138 % (name, inst))
138 % (name, inst))
139 ui.traceback()
139 ui.traceback()
140
140
141 for name in _order[newindex:]:
141 for name in _order[newindex:]:
142 uisetup = getattr(_extensions[name], 'uisetup', None)
142 uisetup = getattr(_extensions[name], 'uisetup', None)
143 if uisetup:
143 if uisetup:
144 uisetup(ui)
144 uisetup(ui)
145
145
146 for name in _order[newindex:]:
146 for name in _order[newindex:]:
147 extsetup = getattr(_extensions[name], 'extsetup', None)
147 extsetup = getattr(_extensions[name], 'extsetup', None)
148 if extsetup:
148 if extsetup:
149 try:
149 try:
150 extsetup(ui)
150 extsetup(ui)
151 except TypeError:
151 except TypeError:
152 if extsetup.func_code.co_argcount != 0:
152 if extsetup.func_code.co_argcount != 0:
153 raise
153 raise
154 extsetup() # old extsetup with no ui argument
154 extsetup() # old extsetup with no ui argument
155
155
156 # Call aftercallbacks that were never met.
156 # Call aftercallbacks that were never met.
157 for shortname in _aftercallbacks:
157 for shortname in _aftercallbacks:
158 if shortname in _extensions:
158 if shortname in _extensions:
159 continue
159 continue
160
160
161 for fn in _aftercallbacks[shortname]:
161 for fn in _aftercallbacks[shortname]:
162 fn(loaded=False)
162 fn(loaded=False)
163
163
164 # loadall() is called multiple times and lingering _aftercallbacks
164 # loadall() is called multiple times and lingering _aftercallbacks
165 # entries could result in double execution. See issue4646.
165 # entries could result in double execution. See issue4646.
166 _aftercallbacks.clear()
166 _aftercallbacks.clear()
167
167
168 def afterloaded(extension, callback):
168 def afterloaded(extension, callback):
169 '''Run the specified function after a named extension is loaded.
169 '''Run the specified function after a named extension is loaded.
170
170
171 If the named extension is already loaded, the callback will be called
171 If the named extension is already loaded, the callback will be called
172 immediately.
172 immediately.
173
173
174 If the named extension never loads, the callback will be called after
174 If the named extension never loads, the callback will be called after
175 all extensions have been loaded.
175 all extensions have been loaded.
176
176
177 The callback receives the named argument ``loaded``, which is a boolean
177 The callback receives the named argument ``loaded``, which is a boolean
178 indicating whether the dependent extension actually loaded.
178 indicating whether the dependent extension actually loaded.
179 '''
179 '''
180
180
181 if extension in _extensions:
181 if extension in _extensions:
182 callback(loaded=True)
182 callback(loaded=True)
183 else:
183 else:
184 _aftercallbacks.setdefault(extension, []).append(callback)
184 _aftercallbacks.setdefault(extension, []).append(callback)
185
185
186 def bind(func, *args):
186 def bind(func, *args):
187 '''Partial function application
187 '''Partial function application
188
188
189 Returns a new function that is the partial application of args and kwargs
189 Returns a new function that is the partial application of args and kwargs
190 to func. For example,
190 to func. For example,
191
191
192 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
192 f(1, 2, bar=3) === bind(f, 1)(2, bar=3)'''
193 assert callable(func)
193 assert callable(func)
194 def closure(*a, **kw):
194 def closure(*a, **kw):
195 return func(*(args + a), **kw)
195 return func(*(args + a), **kw)
196 return closure
196 return closure
197
197
198 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
198 def wrapcommand(table, command, wrapper, synopsis=None, docstring=None):
199 '''Wrap the command named `command' in table
199 '''Wrap the command named `command' in table
200
200
201 Replace command in the command table with wrapper. The wrapped command will
201 Replace command in the command table with wrapper. The wrapped command will
202 be inserted into the command table specified by the table argument.
202 be inserted into the command table specified by the table argument.
203
203
204 The wrapper will be called like
204 The wrapper will be called like
205
205
206 wrapper(orig, *args, **kwargs)
206 wrapper(orig, *args, **kwargs)
207
207
208 where orig is the original (wrapped) function, and *args, **kwargs
208 where orig is the original (wrapped) function, and *args, **kwargs
209 are the arguments passed to it.
209 are the arguments passed to it.
210
210
211 Optionally append to the command synopsis and docstring, used for help.
211 Optionally append to the command synopsis and docstring, used for help.
212 For example, if your extension wraps the ``bookmarks`` command to add the
212 For example, if your extension wraps the ``bookmarks`` command to add the
213 flags ``--remote`` and ``--all`` you might call this function like so:
213 flags ``--remote`` and ``--all`` you might call this function like so:
214
214
215 synopsis = ' [-a] [--remote]'
215 synopsis = ' [-a] [--remote]'
216 docstring = """
216 docstring = """
217
217
218 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
218 The ``remotenames`` extension adds the ``--remote`` and ``--all`` (``-a``)
219 flags to the bookmarks command. Either flag will show the remote bookmarks
219 flags to the bookmarks command. Either flag will show the remote bookmarks
220 known to the repository; ``--remote`` will also suppress the output of the
220 known to the repository; ``--remote`` will also suppress the output of the
221 local bookmarks.
221 local bookmarks.
222 """
222 """
223
223
224 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
224 extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
225 synopsis, docstring)
225 synopsis, docstring)
226 '''
226 '''
227 assert callable(wrapper)
227 assert callable(wrapper)
228 aliases, entry = cmdutil.findcmd(command, table)
228 aliases, entry = cmdutil.findcmd(command, table)
229 for alias, e in table.iteritems():
229 for alias, e in table.iteritems():
230 if e is entry:
230 if e is entry:
231 key = alias
231 key = alias
232 break
232 break
233
233
234 origfn = entry[0]
234 origfn = entry[0]
235 wrap = bind(util.checksignature(wrapper), util.checksignature(origfn))
235 wrap = bind(util.checksignature(wrapper), util.checksignature(origfn))
236
236
237 wrap.__module__ = getattr(origfn, '__module__')
237 wrap.__module__ = getattr(origfn, '__module__')
238
238
239 doc = getattr(origfn, '__doc__')
239 doc = getattr(origfn, '__doc__')
240 if docstring is not None:
240 if docstring is not None:
241 doc += docstring
241 doc += docstring
242 wrap.__doc__ = doc
242 wrap.__doc__ = doc
243
243
244 newentry = list(entry)
244 newentry = list(entry)
245 newentry[0] = wrap
245 newentry[0] = wrap
246 if synopsis is not None:
246 if synopsis is not None:
247 newentry[2] += synopsis
247 newentry[2] += synopsis
248 table[key] = tuple(newentry)
248 table[key] = tuple(newentry)
249 return entry
249 return entry
250
250
251 def wrapfunction(container, funcname, wrapper):
251 def wrapfunction(container, funcname, wrapper):
252 '''Wrap the function named funcname in container
252 '''Wrap the function named funcname in container
253
253
254 Replace the funcname member in the given container with the specified
254 Replace the funcname member in the given container with the specified
255 wrapper. The container is typically a module, class, or instance.
255 wrapper. The container is typically a module, class, or instance.
256
256
257 The wrapper will be called like
257 The wrapper will be called like
258
258
259 wrapper(orig, *args, **kwargs)
259 wrapper(orig, *args, **kwargs)
260
260
261 where orig is the original (wrapped) function, and *args, **kwargs
261 where orig is the original (wrapped) function, and *args, **kwargs
262 are the arguments passed to it.
262 are the arguments passed to it.
263
263
264 Wrapping methods of the repository object is not recommended since
264 Wrapping methods of the repository object is not recommended since
265 it conflicts with extensions that extend the repository by
265 it conflicts with extensions that extend the repository by
266 subclassing. All extensions that need to extend methods of
266 subclassing. All extensions that need to extend methods of
267 localrepository should use this subclassing trick: namely,
267 localrepository should use this subclassing trick: namely,
268 reposetup() should look like
268 reposetup() should look like
269
269
270 def reposetup(ui, repo):
270 def reposetup(ui, repo):
271 class myrepo(repo.__class__):
271 class myrepo(repo.__class__):
272 def whatever(self, *args, **kwargs):
272 def whatever(self, *args, **kwargs):
273 [...extension stuff...]
273 [...extension stuff...]
274 super(myrepo, self).whatever(*args, **kwargs)
274 super(myrepo, self).whatever(*args, **kwargs)
275 [...extension stuff...]
275 [...extension stuff...]
276
276
277 repo.__class__ = myrepo
277 repo.__class__ = myrepo
278
278
279 In general, combining wrapfunction() with subclassing does not
279 In general, combining wrapfunction() with subclassing does not
280 work. Since you cannot control what other extensions are loaded by
280 work. Since you cannot control what other extensions are loaded by
281 your end users, you should play nicely with others by using the
281 your end users, you should play nicely with others by using the
282 subclass trick.
282 subclass trick.
283 '''
283 '''
284 assert callable(wrapper)
284 assert callable(wrapper)
285
285
286 origfn = getattr(container, funcname)
286 origfn = getattr(container, funcname)
287 assert callable(origfn)
287 assert callable(origfn)
288 setattr(container, funcname, bind(wrapper, origfn))
288 setattr(container, funcname, bind(wrapper, origfn))
289 return origfn
289 return origfn
290
290
291 def _disabledpaths(strip_init=False):
291 def _disabledpaths(strip_init=False):
292 '''find paths of disabled extensions. returns a dict of {name: path}
292 '''find paths of disabled extensions. returns a dict of {name: path}
293 removes /__init__.py from packages if strip_init is True'''
293 removes /__init__.py from packages if strip_init is True'''
294 import hgext
294 import hgext
295 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
295 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
296 try: # might not be a filesystem path
296 try: # might not be a filesystem path
297 files = os.listdir(extpath)
297 files = os.listdir(extpath)
298 except OSError:
298 except OSError:
299 return {}
299 return {}
300
300
301 exts = {}
301 exts = {}
302 for e in files:
302 for e in files:
303 if e.endswith('.py'):
303 if e.endswith('.py'):
304 name = e.rsplit('.', 1)[0]
304 name = e.rsplit('.', 1)[0]
305 path = os.path.join(extpath, e)
305 path = os.path.join(extpath, e)
306 else:
306 else:
307 name = e
307 name = e
308 path = os.path.join(extpath, e, '__init__.py')
308 path = os.path.join(extpath, e, '__init__.py')
309 if not os.path.exists(path):
309 if not os.path.exists(path):
310 continue
310 continue
311 if strip_init:
311 if strip_init:
312 path = os.path.dirname(path)
312 path = os.path.dirname(path)
313 if name in exts or name in _order or name == '__init__':
313 if name in exts or name in _order or name == '__init__':
314 continue
314 continue
315 exts[name] = path
315 exts[name] = path
316 return exts
316 return exts
317
317
318 def _moduledoc(file):
318 def _moduledoc(file):
319 '''return the top-level python documentation for the given file
319 '''return the top-level python documentation for the given file
320
320
321 Loosely inspired by pydoc.source_synopsis(), but rewritten to
321 Loosely inspired by pydoc.source_synopsis(), but rewritten to
322 handle triple quotes and to return the whole text instead of just
322 handle triple quotes and to return the whole text instead of just
323 the synopsis'''
323 the synopsis'''
324 result = []
324 result = []
325
325
326 line = file.readline()
326 line = file.readline()
327 while line[:1] == '#' or not line.strip():
327 while line[:1] == '#' or not line.strip():
328 line = file.readline()
328 line = file.readline()
329 if not line:
329 if not line:
330 break
330 break
331
331
332 start = line[:3]
332 start = line[:3]
333 if start == '"""' or start == "'''":
333 if start == '"""' or start == "'''":
334 line = line[3:]
334 line = line[3:]
335 while line:
335 while line:
336 if line.rstrip().endswith(start):
336 if line.rstrip().endswith(start):
337 line = line.split(start)[0]
337 line = line.split(start)[0]
338 if line:
338 if line:
339 result.append(line)
339 result.append(line)
340 break
340 break
341 elif not line:
341 elif not line:
342 return None # unmatched delimiter
342 return None # unmatched delimiter
343 result.append(line)
343 result.append(line)
344 line = file.readline()
344 line = file.readline()
345 else:
345 else:
346 return None
346 return None
347
347
348 return ''.join(result)
348 return ''.join(result)
349
349
350 def _disabledhelp(path):
350 def _disabledhelp(path):
351 '''retrieve help synopsis of a disabled extension (without importing)'''
351 '''retrieve help synopsis of a disabled extension (without importing)'''
352 try:
352 try:
353 file = open(path)
353 file = open(path)
354 except IOError:
354 except IOError:
355 return
355 return
356 else:
356 else:
357 doc = _moduledoc(file)
357 doc = _moduledoc(file)
358 file.close()
358 file.close()
359
359
360 if doc: # extracting localized synopsis
360 if doc: # extracting localized synopsis
361 return gettext(doc).splitlines()[0]
361 return gettext(doc).splitlines()[0]
362 else:
362 else:
363 return _('(no help text available)')
363 return _('(no help text available)')
364
364
365 def disabled():
365 def disabled():
366 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
366 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
367 try:
367 try:
368 from hgext import __index__
368 from hgext import __index__
369 return dict((name, gettext(desc))
369 return dict((name, gettext(desc))
370 for name, desc in __index__.docs.iteritems()
370 for name, desc in __index__.docs.iteritems()
371 if name not in _order)
371 if name not in _order)
372 except (ImportError, AttributeError):
372 except (ImportError, AttributeError):
373 pass
373 pass
374
374
375 paths = _disabledpaths()
375 paths = _disabledpaths()
376 if not paths:
376 if not paths:
377 return {}
377 return {}
378
378
379 exts = {}
379 exts = {}
380 for name, path in paths.iteritems():
380 for name, path in paths.iteritems():
381 doc = _disabledhelp(path)
381 doc = _disabledhelp(path)
382 if doc:
382 if doc:
383 exts[name] = doc
383 exts[name] = doc
384
384
385 return exts
385 return exts
386
386
387 def disabledext(name):
387 def disabledext(name):
388 '''find a specific disabled extension from hgext. returns desc'''
388 '''find a specific disabled extension from hgext. returns desc'''
389 try:
389 try:
390 from hgext import __index__
390 from hgext import __index__
391 if name in _order: # enabled
391 if name in _order: # enabled
392 return
392 return
393 else:
393 else:
394 return gettext(__index__.docs.get(name))
394 return gettext(__index__.docs.get(name))
395 except (ImportError, AttributeError):
395 except (ImportError, AttributeError):
396 pass
396 pass
397
397
398 paths = _disabledpaths()
398 paths = _disabledpaths()
399 if name in paths:
399 if name in paths:
400 return _disabledhelp(paths[name])
400 return _disabledhelp(paths[name])
401
401
402 def disabledcmd(ui, cmd, strict=False):
402 def disabledcmd(ui, cmd, strict=False):
403 '''import disabled extensions until cmd is found.
403 '''import disabled extensions until cmd is found.
404 returns (cmdname, extname, module)'''
404 returns (cmdname, extname, module)'''
405
405
406 paths = _disabledpaths(strip_init=True)
406 paths = _disabledpaths(strip_init=True)
407 if not paths:
407 if not paths:
408 raise error.UnknownCommand(cmd)
408 raise error.UnknownCommand(cmd)
409
409
410 def findcmd(cmd, name, path):
410 def findcmd(cmd, name, path):
411 try:
411 try:
412 mod = loadpath(path, 'hgext.%s' % name)
412 mod = loadpath(path, 'hgext.%s' % name)
413 except Exception:
413 except Exception:
414 return
414 return
415 try:
415 try:
416 aliases, entry = cmdutil.findcmd(cmd,
416 aliases, entry = cmdutil.findcmd(cmd,
417 getattr(mod, 'cmdtable', {}), strict)
417 getattr(mod, 'cmdtable', {}), strict)
418 except (error.AmbiguousCommand, error.UnknownCommand):
418 except (error.AmbiguousCommand, error.UnknownCommand):
419 return
419 return
420 except Exception:
420 except Exception:
421 ui.warn(_('warning: error finding commands in %s\n') % path)
421 ui.warn(_('warning: error finding commands in %s\n') % path)
422 ui.traceback()
422 ui.traceback()
423 return
423 return
424 for c in aliases:
424 for c in aliases:
425 if c.startswith(cmd):
425 if c.startswith(cmd):
426 cmd = c
426 cmd = c
427 break
427 break
428 else:
428 else:
429 cmd = aliases[0]
429 cmd = aliases[0]
430 return (cmd, name, mod)
430 return (cmd, name, mod)
431
431
432 ext = None
432 ext = None
433 # first, search for an extension with the same name as the command
433 # first, search for an extension with the same name as the command
434 path = paths.pop(cmd, None)
434 path = paths.pop(cmd, None)
435 if path:
435 if path:
436 ext = findcmd(cmd, cmd, path)
436 ext = findcmd(cmd, cmd, path)
437 if not ext:
437 if not ext:
438 # otherwise, interrogate each extension until there's a match
438 # otherwise, interrogate each extension until there's a match
439 for name, path in paths.iteritems():
439 for name, path in paths.iteritems():
440 ext = findcmd(cmd, name, path)
440 ext = findcmd(cmd, name, path)
441 if ext:
441 if ext:
442 break
442 break
443 if ext and 'DEPRECATED' not in ext.__doc__:
443 if ext and 'DEPRECATED' not in ext.__doc__:
444 return ext
444 return ext
445
445
446 raise error.UnknownCommand(cmd)
446 raise error.UnknownCommand(cmd)
447
447
448 def enabled(shortname=True):
448 def enabled(shortname=True):
449 '''return a dict of {name: desc} of extensions'''
449 '''return a dict of {name: desc} of extensions'''
450 exts = {}
450 exts = {}
451 for ename, ext in extensions():
451 for ename, ext in extensions():
452 doc = (gettext(ext.__doc__) or _('(no help text available)'))
452 doc = (gettext(ext.__doc__) or _('(no help text available)'))
453 if shortname:
453 if shortname:
454 ename = ename.split('.')[-1]
454 ename = ename.split('.')[-1]
455 exts[ename] = doc.splitlines()[0].strip()
455 exts[ename] = doc.splitlines()[0].strip()
456
456
457 return exts
457 return exts
458
458
459 def moduleversion(module):
459 def moduleversion(module):
460 '''return version information from given module as a string'''
460 '''return version information from given module as a string'''
461 if (util.safehasattr(module, 'getversion')
461 if (util.safehasattr(module, 'getversion')
462 and callable(module.getversion)):
462 and callable(module.getversion)):
463 version = module.getversion()
463 version = module.getversion()
464 elif util.safehasattr(module, '__version__'):
464 elif util.safehasattr(module, '__version__'):
465 version = module.__version__
465 version = module.__version__
466 else:
466 else:
467 version = ''
467 version = ''
468 if isinstance(version, (list, tuple)):
468 if isinstance(version, (list, tuple)):
469 version = '.'.join(str(o) for o in version)
469 version = '.'.join(str(o) for o in version)
470 return version
470 return version
471
472 def ismoduleinternal(module):
473 exttestedwith = getattr(module, 'testedwith', None)
474 return exttestedwith == "internal"
@@ -1,1224 +1,1224 b''
1 Test basic extension support
1 Test basic extension support
2
2
3 $ cat > foobar.py <<EOF
3 $ cat > foobar.py <<EOF
4 > import os
4 > import os
5 > from mercurial import cmdutil, commands
5 > from mercurial import cmdutil, commands
6 > cmdtable = {}
6 > cmdtable = {}
7 > command = cmdutil.command(cmdtable)
7 > command = cmdutil.command(cmdtable)
8 > def uisetup(ui):
8 > def uisetup(ui):
9 > ui.write("uisetup called\\n")
9 > ui.write("uisetup called\\n")
10 > def reposetup(ui, repo):
10 > def reposetup(ui, repo):
11 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
11 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
12 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
12 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
13 > @command('foo', [], 'hg foo')
13 > @command('foo', [], 'hg foo')
14 > def foo(ui, *args, **kwargs):
14 > def foo(ui, *args, **kwargs):
15 > ui.write("Foo\\n")
15 > ui.write("Foo\\n")
16 > @command('bar', [], 'hg bar', norepo=True)
16 > @command('bar', [], 'hg bar', norepo=True)
17 > def bar(ui, *args, **kwargs):
17 > def bar(ui, *args, **kwargs):
18 > ui.write("Bar\\n")
18 > ui.write("Bar\\n")
19 > EOF
19 > EOF
20 $ abspath=`pwd`/foobar.py
20 $ abspath=`pwd`/foobar.py
21
21
22 $ mkdir barfoo
22 $ mkdir barfoo
23 $ cp foobar.py barfoo/__init__.py
23 $ cp foobar.py barfoo/__init__.py
24 $ barfoopath=`pwd`/barfoo
24 $ barfoopath=`pwd`/barfoo
25
25
26 $ hg init a
26 $ hg init a
27 $ cd a
27 $ cd a
28 $ echo foo > file
28 $ echo foo > file
29 $ hg add file
29 $ hg add file
30 $ hg commit -m 'add file'
30 $ hg commit -m 'add file'
31
31
32 $ echo '[extensions]' >> $HGRCPATH
32 $ echo '[extensions]' >> $HGRCPATH
33 $ echo "foobar = $abspath" >> $HGRCPATH
33 $ echo "foobar = $abspath" >> $HGRCPATH
34 $ hg foo
34 $ hg foo
35 uisetup called
35 uisetup called
36 reposetup called for a
36 reposetup called for a
37 ui == repo.ui
37 ui == repo.ui
38 Foo
38 Foo
39
39
40 $ cd ..
40 $ cd ..
41 $ hg clone a b
41 $ hg clone a b
42 uisetup called
42 uisetup called
43 reposetup called for a
43 reposetup called for a
44 ui == repo.ui
44 ui == repo.ui
45 reposetup called for b
45 reposetup called for b
46 ui == repo.ui
46 ui == repo.ui
47 updating to branch default
47 updating to branch default
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49
49
50 $ hg bar
50 $ hg bar
51 uisetup called
51 uisetup called
52 Bar
52 Bar
53 $ echo 'foobar = !' >> $HGRCPATH
53 $ echo 'foobar = !' >> $HGRCPATH
54
54
55 module/__init__.py-style
55 module/__init__.py-style
56
56
57 $ echo "barfoo = $barfoopath" >> $HGRCPATH
57 $ echo "barfoo = $barfoopath" >> $HGRCPATH
58 $ cd a
58 $ cd a
59 $ hg foo
59 $ hg foo
60 uisetup called
60 uisetup called
61 reposetup called for a
61 reposetup called for a
62 ui == repo.ui
62 ui == repo.ui
63 Foo
63 Foo
64 $ echo 'barfoo = !' >> $HGRCPATH
64 $ echo 'barfoo = !' >> $HGRCPATH
65
65
66 Check that extensions are loaded in phases:
66 Check that extensions are loaded in phases:
67
67
68 $ cat > foo.py <<EOF
68 $ cat > foo.py <<EOF
69 > import os
69 > import os
70 > name = os.path.basename(__file__).rsplit('.', 1)[0]
70 > name = os.path.basename(__file__).rsplit('.', 1)[0]
71 > print "1) %s imported" % name
71 > print "1) %s imported" % name
72 > def uisetup(ui):
72 > def uisetup(ui):
73 > print "2) %s uisetup" % name
73 > print "2) %s uisetup" % name
74 > def extsetup():
74 > def extsetup():
75 > print "3) %s extsetup" % name
75 > print "3) %s extsetup" % name
76 > def reposetup(ui, repo):
76 > def reposetup(ui, repo):
77 > print "4) %s reposetup" % name
77 > print "4) %s reposetup" % name
78 > EOF
78 > EOF
79
79
80 $ cp foo.py bar.py
80 $ cp foo.py bar.py
81 $ echo 'foo = foo.py' >> $HGRCPATH
81 $ echo 'foo = foo.py' >> $HGRCPATH
82 $ echo 'bar = bar.py' >> $HGRCPATH
82 $ echo 'bar = bar.py' >> $HGRCPATH
83
83
84 Command with no output, we just want to see the extensions loaded:
84 Command with no output, we just want to see the extensions loaded:
85
85
86 $ hg paths
86 $ hg paths
87 1) foo imported
87 1) foo imported
88 1) bar imported
88 1) bar imported
89 2) foo uisetup
89 2) foo uisetup
90 2) bar uisetup
90 2) bar uisetup
91 3) foo extsetup
91 3) foo extsetup
92 3) bar extsetup
92 3) bar extsetup
93 4) foo reposetup
93 4) foo reposetup
94 4) bar reposetup
94 4) bar reposetup
95
95
96 Check hgweb's load order:
96 Check hgweb's load order:
97
97
98 $ cat > hgweb.cgi <<EOF
98 $ cat > hgweb.cgi <<EOF
99 > #!/usr/bin/env python
99 > #!/usr/bin/env python
100 > from mercurial import demandimport; demandimport.enable()
100 > from mercurial import demandimport; demandimport.enable()
101 > from mercurial.hgweb import hgweb
101 > from mercurial.hgweb import hgweb
102 > from mercurial.hgweb import wsgicgi
102 > from mercurial.hgweb import wsgicgi
103 > application = hgweb('.', 'test repo')
103 > application = hgweb('.', 'test repo')
104 > wsgicgi.launch(application)
104 > wsgicgi.launch(application)
105 > EOF
105 > EOF
106
106
107 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
107 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
108 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
108 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
109 > | grep '^[0-9]) ' # ignores HTML output
109 > | grep '^[0-9]) ' # ignores HTML output
110 1) foo imported
110 1) foo imported
111 1) bar imported
111 1) bar imported
112 2) foo uisetup
112 2) foo uisetup
113 2) bar uisetup
113 2) bar uisetup
114 3) foo extsetup
114 3) foo extsetup
115 3) bar extsetup
115 3) bar extsetup
116 4) foo reposetup
116 4) foo reposetup
117 4) bar reposetup
117 4) bar reposetup
118
118
119 $ echo 'foo = !' >> $HGRCPATH
119 $ echo 'foo = !' >> $HGRCPATH
120 $ echo 'bar = !' >> $HGRCPATH
120 $ echo 'bar = !' >> $HGRCPATH
121
121
122 Check "from __future__ import absolute_import" support for external libraries
122 Check "from __future__ import absolute_import" support for external libraries
123
123
124 #if windows
124 #if windows
125 $ PATHSEP=";"
125 $ PATHSEP=";"
126 #else
126 #else
127 $ PATHSEP=":"
127 $ PATHSEP=":"
128 #endif
128 #endif
129 $ export PATHSEP
129 $ export PATHSEP
130
130
131 $ mkdir $TESTTMP/libroot
131 $ mkdir $TESTTMP/libroot
132 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
132 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
133 $ mkdir $TESTTMP/libroot/mod
133 $ mkdir $TESTTMP/libroot/mod
134 $ touch $TESTTMP/libroot/mod/__init__.py
134 $ touch $TESTTMP/libroot/mod/__init__.py
135 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
135 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
136
136
137 #if absimport
137 #if absimport
138 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
138 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
139 > from __future__ import absolute_import
139 > from __future__ import absolute_import
140 > import ambig # should load "libroot/ambig.py"
140 > import ambig # should load "libroot/ambig.py"
141 > s = ambig.s
141 > s = ambig.s
142 > EOF
142 > EOF
143 $ cat > loadabs.py <<EOF
143 $ cat > loadabs.py <<EOF
144 > import mod.ambigabs as ambigabs
144 > import mod.ambigabs as ambigabs
145 > def extsetup():
145 > def extsetup():
146 > print 'ambigabs.s=%s' % ambigabs.s
146 > print 'ambigabs.s=%s' % ambigabs.s
147 > EOF
147 > EOF
148 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
148 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
149 ambigabs.s=libroot/ambig.py
149 ambigabs.s=libroot/ambig.py
150 $TESTTMP/a (glob)
150 $TESTTMP/a (glob)
151 #endif
151 #endif
152
152
153 #if no-py3k
153 #if no-py3k
154 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
154 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
155 > import ambig # should load "libroot/mod/ambig.py"
155 > import ambig # should load "libroot/mod/ambig.py"
156 > s = ambig.s
156 > s = ambig.s
157 > EOF
157 > EOF
158 $ cat > loadrel.py <<EOF
158 $ cat > loadrel.py <<EOF
159 > import mod.ambigrel as ambigrel
159 > import mod.ambigrel as ambigrel
160 > def extsetup():
160 > def extsetup():
161 > print 'ambigrel.s=%s' % ambigrel.s
161 > print 'ambigrel.s=%s' % ambigrel.s
162 > EOF
162 > EOF
163 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
163 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
164 ambigrel.s=libroot/mod/ambig.py
164 ambigrel.s=libroot/mod/ambig.py
165 $TESTTMP/a (glob)
165 $TESTTMP/a (glob)
166 #endif
166 #endif
167
167
168 Check absolute/relative import of extension specific modules
168 Check absolute/relative import of extension specific modules
169
169
170 $ mkdir $TESTTMP/extroot
170 $ mkdir $TESTTMP/extroot
171 $ cat > $TESTTMP/extroot/bar.py <<EOF
171 $ cat > $TESTTMP/extroot/bar.py <<EOF
172 > s = 'this is extroot.bar'
172 > s = 'this is extroot.bar'
173 > EOF
173 > EOF
174 $ mkdir $TESTTMP/extroot/sub1
174 $ mkdir $TESTTMP/extroot/sub1
175 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
175 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
176 > s = 'this is extroot.sub1.__init__'
176 > s = 'this is extroot.sub1.__init__'
177 > EOF
177 > EOF
178 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
178 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
179 > s = 'this is extroot.sub1.baz'
179 > s = 'this is extroot.sub1.baz'
180 > EOF
180 > EOF
181 $ cat > $TESTTMP/extroot/__init__.py <<EOF
181 $ cat > $TESTTMP/extroot/__init__.py <<EOF
182 > s = 'this is extroot.__init__'
182 > s = 'this is extroot.__init__'
183 > import foo
183 > import foo
184 > def extsetup(ui):
184 > def extsetup(ui):
185 > ui.write('(extroot) ', foo.func(), '\n')
185 > ui.write('(extroot) ', foo.func(), '\n')
186 > EOF
186 > EOF
187
187
188 $ cat > $TESTTMP/extroot/foo.py <<EOF
188 $ cat > $TESTTMP/extroot/foo.py <<EOF
189 > # test absolute import
189 > # test absolute import
190 > buf = []
190 > buf = []
191 > def func():
191 > def func():
192 > # "not locals" case
192 > # "not locals" case
193 > import extroot.bar
193 > import extroot.bar
194 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
194 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
195 > return '\n(extroot) '.join(buf)
195 > return '\n(extroot) '.join(buf)
196 > # "fromlist == ('*',)" case
196 > # "fromlist == ('*',)" case
197 > from extroot.bar import *
197 > from extroot.bar import *
198 > buf.append('from extroot.bar import *: %s' % s)
198 > buf.append('from extroot.bar import *: %s' % s)
199 > # "not fromlist" and "if '.' in name" case
199 > # "not fromlist" and "if '.' in name" case
200 > import extroot.sub1.baz
200 > import extroot.sub1.baz
201 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
201 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
202 > # "not fromlist" and NOT "if '.' in name" case
202 > # "not fromlist" and NOT "if '.' in name" case
203 > import extroot
203 > import extroot
204 > buf.append('import extroot: %s' % extroot.s)
204 > buf.append('import extroot: %s' % extroot.s)
205 > # NOT "not fromlist" and NOT "level != -1" case
205 > # NOT "not fromlist" and NOT "level != -1" case
206 > from extroot.bar import s
206 > from extroot.bar import s
207 > buf.append('from extroot.bar import s: %s' % s)
207 > buf.append('from extroot.bar import s: %s' % s)
208 > EOF
208 > EOF
209 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
209 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
210 (extroot) from extroot.bar import *: this is extroot.bar
210 (extroot) from extroot.bar import *: this is extroot.bar
211 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
211 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
212 (extroot) import extroot: this is extroot.__init__
212 (extroot) import extroot: this is extroot.__init__
213 (extroot) from extroot.bar import s: this is extroot.bar
213 (extroot) from extroot.bar import s: this is extroot.bar
214 (extroot) import extroot.bar in func(): this is extroot.bar
214 (extroot) import extroot.bar in func(): this is extroot.bar
215 $TESTTMP/a (glob)
215 $TESTTMP/a (glob)
216
216
217 #if no-py3k
217 #if no-py3k
218 $ rm "$TESTTMP"/extroot/foo.*
218 $ rm "$TESTTMP"/extroot/foo.*
219 $ cat > $TESTTMP/extroot/foo.py <<EOF
219 $ cat > $TESTTMP/extroot/foo.py <<EOF
220 > # test relative import
220 > # test relative import
221 > buf = []
221 > buf = []
222 > def func():
222 > def func():
223 > # "not locals" case
223 > # "not locals" case
224 > import bar
224 > import bar
225 > buf.append('import bar in func(): %s' % bar.s)
225 > buf.append('import bar in func(): %s' % bar.s)
226 > return '\n(extroot) '.join(buf)
226 > return '\n(extroot) '.join(buf)
227 > # "fromlist == ('*',)" case
227 > # "fromlist == ('*',)" case
228 > from bar import *
228 > from bar import *
229 > buf.append('from bar import *: %s' % s)
229 > buf.append('from bar import *: %s' % s)
230 > # "not fromlist" and "if '.' in name" case
230 > # "not fromlist" and "if '.' in name" case
231 > import sub1.baz
231 > import sub1.baz
232 > buf.append('import sub1.baz: %s' % sub1.baz.s)
232 > buf.append('import sub1.baz: %s' % sub1.baz.s)
233 > # "not fromlist" and NOT "if '.' in name" case
233 > # "not fromlist" and NOT "if '.' in name" case
234 > import sub1
234 > import sub1
235 > buf.append('import sub1: %s' % sub1.s)
235 > buf.append('import sub1: %s' % sub1.s)
236 > # NOT "not fromlist" and NOT "level != -1" case
236 > # NOT "not fromlist" and NOT "level != -1" case
237 > from bar import s
237 > from bar import s
238 > buf.append('from bar import s: %s' % s)
238 > buf.append('from bar import s: %s' % s)
239 > EOF
239 > EOF
240 $ hg --config extensions.extroot=$TESTTMP/extroot root
240 $ hg --config extensions.extroot=$TESTTMP/extroot root
241 (extroot) from bar import *: this is extroot.bar
241 (extroot) from bar import *: this is extroot.bar
242 (extroot) import sub1.baz: this is extroot.sub1.baz
242 (extroot) import sub1.baz: this is extroot.sub1.baz
243 (extroot) import sub1: this is extroot.sub1.__init__
243 (extroot) import sub1: this is extroot.sub1.__init__
244 (extroot) from bar import s: this is extroot.bar
244 (extroot) from bar import s: this is extroot.bar
245 (extroot) import bar in func(): this is extroot.bar
245 (extroot) import bar in func(): this is extroot.bar
246 $TESTTMP/a (glob)
246 $TESTTMP/a (glob)
247 #endif
247 #endif
248
248
249 $ cd ..
249 $ cd ..
250
250
251 hide outer repo
251 hide outer repo
252 $ hg init
252 $ hg init
253
253
254 $ cat > empty.py <<EOF
254 $ cat > empty.py <<EOF
255 > '''empty cmdtable
255 > '''empty cmdtable
256 > '''
256 > '''
257 > cmdtable = {}
257 > cmdtable = {}
258 > EOF
258 > EOF
259 $ emptypath=`pwd`/empty.py
259 $ emptypath=`pwd`/empty.py
260 $ echo "empty = $emptypath" >> $HGRCPATH
260 $ echo "empty = $emptypath" >> $HGRCPATH
261 $ hg help empty
261 $ hg help empty
262 empty extension - empty cmdtable
262 empty extension - empty cmdtable
263
263
264 no commands defined
264 no commands defined
265
265
266
266
267 $ echo 'empty = !' >> $HGRCPATH
267 $ echo 'empty = !' >> $HGRCPATH
268
268
269 $ cat > debugextension.py <<EOF
269 $ cat > debugextension.py <<EOF
270 > '''only debugcommands
270 > '''only debugcommands
271 > '''
271 > '''
272 > from mercurial import cmdutil
272 > from mercurial import cmdutil
273 > cmdtable = {}
273 > cmdtable = {}
274 > command = cmdutil.command(cmdtable)
274 > command = cmdutil.command(cmdtable)
275 > @command('debugfoobar', [], 'hg debugfoobar')
275 > @command('debugfoobar', [], 'hg debugfoobar')
276 > def debugfoobar(ui, repo, *args, **opts):
276 > def debugfoobar(ui, repo, *args, **opts):
277 > "yet another debug command"
277 > "yet another debug command"
278 > pass
278 > pass
279 > @command('foo', [], 'hg foo')
279 > @command('foo', [], 'hg foo')
280 > def foo(ui, repo, *args, **opts):
280 > def foo(ui, repo, *args, **opts):
281 > """yet another foo command
281 > """yet another foo command
282 > This command has been DEPRECATED since forever.
282 > This command has been DEPRECATED since forever.
283 > """
283 > """
284 > pass
284 > pass
285 > EOF
285 > EOF
286 $ debugpath=`pwd`/debugextension.py
286 $ debugpath=`pwd`/debugextension.py
287 $ echo "debugextension = $debugpath" >> $HGRCPATH
287 $ echo "debugextension = $debugpath" >> $HGRCPATH
288
288
289 $ hg help debugextension
289 $ hg help debugextension
290 hg debugextensions
290 hg debugextensions
291
291
292 show information about active extensions
292 show information about active extensions
293
293
294 options:
294 options:
295
295
296 (some details hidden, use --verbose to show complete help)
296 (some details hidden, use --verbose to show complete help)
297
297
298
298
299 $ hg --verbose help debugextension
299 $ hg --verbose help debugextension
300 hg debugextensions
300 hg debugextensions
301
301
302 show information about active extensions
302 show information about active extensions
303
303
304 options:
304 options:
305
305
306 -T --template TEMPLATE display with template (EXPERIMENTAL)
306 -T --template TEMPLATE display with template (EXPERIMENTAL)
307
307
308 global options ([+] can be repeated):
308 global options ([+] can be repeated):
309
309
310 -R --repository REPO repository root directory or name of overlay bundle
310 -R --repository REPO repository root directory or name of overlay bundle
311 file
311 file
312 --cwd DIR change working directory
312 --cwd DIR change working directory
313 -y --noninteractive do not prompt, automatically pick the first choice for
313 -y --noninteractive do not prompt, automatically pick the first choice for
314 all prompts
314 all prompts
315 -q --quiet suppress output
315 -q --quiet suppress output
316 -v --verbose enable additional output
316 -v --verbose enable additional output
317 --config CONFIG [+] set/override config option (use 'section.name=value')
317 --config CONFIG [+] set/override config option (use 'section.name=value')
318 --debug enable debugging output
318 --debug enable debugging output
319 --debugger start debugger
319 --debugger start debugger
320 --encoding ENCODE set the charset encoding (default: ascii)
320 --encoding ENCODE set the charset encoding (default: ascii)
321 --encodingmode MODE set the charset encoding mode (default: strict)
321 --encodingmode MODE set the charset encoding mode (default: strict)
322 --traceback always print a traceback on exception
322 --traceback always print a traceback on exception
323 --time time how long the command takes
323 --time time how long the command takes
324 --profile print command execution profile
324 --profile print command execution profile
325 --version output version information and exit
325 --version output version information and exit
326 -h --help display help and exit
326 -h --help display help and exit
327 --hidden consider hidden changesets
327 --hidden consider hidden changesets
328
328
329
329
330
330
331
331
332
332
333
333
334 $ hg --debug help debugextension
334 $ hg --debug help debugextension
335 hg debugextensions
335 hg debugextensions
336
336
337 show information about active extensions
337 show information about active extensions
338
338
339 options:
339 options:
340
340
341 -T --template TEMPLATE display with template (EXPERIMENTAL)
341 -T --template TEMPLATE display with template (EXPERIMENTAL)
342
342
343 global options ([+] can be repeated):
343 global options ([+] can be repeated):
344
344
345 -R --repository REPO repository root directory or name of overlay bundle
345 -R --repository REPO repository root directory or name of overlay bundle
346 file
346 file
347 --cwd DIR change working directory
347 --cwd DIR change working directory
348 -y --noninteractive do not prompt, automatically pick the first choice for
348 -y --noninteractive do not prompt, automatically pick the first choice for
349 all prompts
349 all prompts
350 -q --quiet suppress output
350 -q --quiet suppress output
351 -v --verbose enable additional output
351 -v --verbose enable additional output
352 --config CONFIG [+] set/override config option (use 'section.name=value')
352 --config CONFIG [+] set/override config option (use 'section.name=value')
353 --debug enable debugging output
353 --debug enable debugging output
354 --debugger start debugger
354 --debugger start debugger
355 --encoding ENCODE set the charset encoding (default: ascii)
355 --encoding ENCODE set the charset encoding (default: ascii)
356 --encodingmode MODE set the charset encoding mode (default: strict)
356 --encodingmode MODE set the charset encoding mode (default: strict)
357 --traceback always print a traceback on exception
357 --traceback always print a traceback on exception
358 --time time how long the command takes
358 --time time how long the command takes
359 --profile print command execution profile
359 --profile print command execution profile
360 --version output version information and exit
360 --version output version information and exit
361 -h --help display help and exit
361 -h --help display help and exit
362 --hidden consider hidden changesets
362 --hidden consider hidden changesets
363
363
364
364
365
365
366
366
367
367
368 $ echo 'debugextension = !' >> $HGRCPATH
368 $ echo 'debugextension = !' >> $HGRCPATH
369
369
370 Asking for help about a deprecated extension should do something useful:
370 Asking for help about a deprecated extension should do something useful:
371
371
372 $ hg help glog
372 $ hg help glog
373 'glog' is provided by the following extension:
373 'glog' is provided by the following extension:
374
374
375 graphlog command to view revision graphs from a shell (DEPRECATED)
375 graphlog command to view revision graphs from a shell (DEPRECATED)
376
376
377 (use "hg help extensions" for information on enabling extensions)
377 (use "hg help extensions" for information on enabling extensions)
378
378
379 Extension module help vs command help:
379 Extension module help vs command help:
380
380
381 $ echo 'extdiff =' >> $HGRCPATH
381 $ echo 'extdiff =' >> $HGRCPATH
382 $ hg help extdiff
382 $ hg help extdiff
383 hg extdiff [OPT]... [FILE]...
383 hg extdiff [OPT]... [FILE]...
384
384
385 use external program to diff repository (or selected files)
385 use external program to diff repository (or selected files)
386
386
387 Show differences between revisions for the specified files, using an
387 Show differences between revisions for the specified files, using an
388 external program. The default program used is diff, with default options
388 external program. The default program used is diff, with default options
389 "-Npru".
389 "-Npru".
390
390
391 To select a different program, use the -p/--program option. The program
391 To select a different program, use the -p/--program option. The program
392 will be passed the names of two directories to compare. To pass additional
392 will be passed the names of two directories to compare. To pass additional
393 options to the program, use -o/--option. These will be passed before the
393 options to the program, use -o/--option. These will be passed before the
394 names of the directories to compare.
394 names of the directories to compare.
395
395
396 When two revision arguments are given, then changes are shown between
396 When two revision arguments are given, then changes are shown between
397 those revisions. If only one revision is specified then that revision is
397 those revisions. If only one revision is specified then that revision is
398 compared to the working directory, and, when no revisions are specified,
398 compared to the working directory, and, when no revisions are specified,
399 the working directory files are compared to its parent.
399 the working directory files are compared to its parent.
400
400
401 (use "hg help -e extdiff" to show help for the extdiff extension)
401 (use "hg help -e extdiff" to show help for the extdiff extension)
402
402
403 options ([+] can be repeated):
403 options ([+] can be repeated):
404
404
405 -p --program CMD comparison program to run
405 -p --program CMD comparison program to run
406 -o --option OPT [+] pass option to comparison program
406 -o --option OPT [+] pass option to comparison program
407 -r --rev REV [+] revision
407 -r --rev REV [+] revision
408 -c --change REV change made by revision
408 -c --change REV change made by revision
409 --patch compare patches for two revisions
409 --patch compare patches for two revisions
410 -I --include PATTERN [+] include names matching the given patterns
410 -I --include PATTERN [+] include names matching the given patterns
411 -X --exclude PATTERN [+] exclude names matching the given patterns
411 -X --exclude PATTERN [+] exclude names matching the given patterns
412 -S --subrepos recurse into subrepositories
412 -S --subrepos recurse into subrepositories
413
413
414 (some details hidden, use --verbose to show complete help)
414 (some details hidden, use --verbose to show complete help)
415
415
416
416
417
417
418
418
419
419
420
420
421
421
422
422
423
423
424
424
425 $ hg help --extension extdiff
425 $ hg help --extension extdiff
426 extdiff extension - command to allow external programs to compare revisions
426 extdiff extension - command to allow external programs to compare revisions
427
427
428 The extdiff Mercurial extension allows you to use external programs to compare
428 The extdiff Mercurial extension allows you to use external programs to compare
429 revisions, or revision with working directory. The external diff programs are
429 revisions, or revision with working directory. The external diff programs are
430 called with a configurable set of options and two non-option arguments: paths
430 called with a configurable set of options and two non-option arguments: paths
431 to directories containing snapshots of files to compare.
431 to directories containing snapshots of files to compare.
432
432
433 The extdiff extension also allows you to configure new diff commands, so you
433 The extdiff extension also allows you to configure new diff commands, so you
434 do not need to type 'hg extdiff -p kdiff3' always.
434 do not need to type 'hg extdiff -p kdiff3' always.
435
435
436 [extdiff]
436 [extdiff]
437 # add new command that runs GNU diff(1) in 'context diff' mode
437 # add new command that runs GNU diff(1) in 'context diff' mode
438 cdiff = gdiff -Nprc5
438 cdiff = gdiff -Nprc5
439 ## or the old way:
439 ## or the old way:
440 #cmd.cdiff = gdiff
440 #cmd.cdiff = gdiff
441 #opts.cdiff = -Nprc5
441 #opts.cdiff = -Nprc5
442
442
443 # add new command called meld, runs meld (no need to name twice). If
443 # add new command called meld, runs meld (no need to name twice). If
444 # the meld executable is not available, the meld tool in [merge-tools]
444 # the meld executable is not available, the meld tool in [merge-tools]
445 # will be used, if available
445 # will be used, if available
446 meld =
446 meld =
447
447
448 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
448 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
449 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
449 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
450 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
450 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
451 # your .vimrc
451 # your .vimrc
452 vimdiff = gvim -f "+next" \
452 vimdiff = gvim -f "+next" \
453 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
453 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
454
454
455 Tool arguments can include variables that are expanded at runtime:
455 Tool arguments can include variables that are expanded at runtime:
456
456
457 $parent1, $plabel1 - filename, descriptive label of first parent
457 $parent1, $plabel1 - filename, descriptive label of first parent
458 $child, $clabel - filename, descriptive label of child revision
458 $child, $clabel - filename, descriptive label of child revision
459 $parent2, $plabel2 - filename, descriptive label of second parent
459 $parent2, $plabel2 - filename, descriptive label of second parent
460 $root - repository root
460 $root - repository root
461 $parent is an alias for $parent1.
461 $parent is an alias for $parent1.
462
462
463 The extdiff extension will look in your [diff-tools] and [merge-tools]
463 The extdiff extension will look in your [diff-tools] and [merge-tools]
464 sections for diff tool arguments, when none are specified in [extdiff].
464 sections for diff tool arguments, when none are specified in [extdiff].
465
465
466 [extdiff]
466 [extdiff]
467 kdiff3 =
467 kdiff3 =
468
468
469 [diff-tools]
469 [diff-tools]
470 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
470 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
471
471
472 You can use -I/-X and list of file or directory names like normal 'hg diff'
472 You can use -I/-X and list of file or directory names like normal 'hg diff'
473 command. The extdiff extension makes snapshots of only needed files, so
473 command. The extdiff extension makes snapshots of only needed files, so
474 running the external diff program will actually be pretty fast (at least
474 running the external diff program will actually be pretty fast (at least
475 faster than having to compare the entire tree).
475 faster than having to compare the entire tree).
476
476
477 list of commands:
477 list of commands:
478
478
479 extdiff use external program to diff repository (or selected files)
479 extdiff use external program to diff repository (or selected files)
480
480
481 (use "hg help -v -e extdiff" to show built-in aliases and global options)
481 (use "hg help -v -e extdiff" to show built-in aliases and global options)
482
482
483
483
484
484
485
485
486
486
487
487
488
488
489
489
490
490
491
491
492
492
493
493
494
494
495
495
496
496
497
497
498 $ echo 'extdiff = !' >> $HGRCPATH
498 $ echo 'extdiff = !' >> $HGRCPATH
499
499
500 Test help topic with same name as extension
500 Test help topic with same name as extension
501
501
502 $ cat > multirevs.py <<EOF
502 $ cat > multirevs.py <<EOF
503 > from mercurial import cmdutil, commands
503 > from mercurial import cmdutil, commands
504 > cmdtable = {}
504 > cmdtable = {}
505 > command = cmdutil.command(cmdtable)
505 > command = cmdutil.command(cmdtable)
506 > """multirevs extension
506 > """multirevs extension
507 > Big multi-line module docstring."""
507 > Big multi-line module docstring."""
508 > @command('multirevs', [], 'ARG', norepo=True)
508 > @command('multirevs', [], 'ARG', norepo=True)
509 > def multirevs(ui, repo, arg, *args, **opts):
509 > def multirevs(ui, repo, arg, *args, **opts):
510 > """multirevs command"""
510 > """multirevs command"""
511 > pass
511 > pass
512 > EOF
512 > EOF
513 $ echo "multirevs = multirevs.py" >> $HGRCPATH
513 $ echo "multirevs = multirevs.py" >> $HGRCPATH
514
514
515 $ hg help multirevs
515 $ hg help multirevs
516 Specifying Multiple Revisions
516 Specifying Multiple Revisions
517 """""""""""""""""""""""""""""
517 """""""""""""""""""""""""""""
518
518
519 When Mercurial accepts more than one revision, they may be specified
519 When Mercurial accepts more than one revision, they may be specified
520 individually, or provided as a topologically continuous range, separated
520 individually, or provided as a topologically continuous range, separated
521 by the ":" character.
521 by the ":" character.
522
522
523 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
523 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
524 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
524 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
525 specified, it defaults to revision number 0. If END is not specified, it
525 specified, it defaults to revision number 0. If END is not specified, it
526 defaults to the tip. The range ":" thus means "all revisions".
526 defaults to the tip. The range ":" thus means "all revisions".
527
527
528 If BEGIN is greater than END, revisions are treated in reverse order.
528 If BEGIN is greater than END, revisions are treated in reverse order.
529
529
530 A range acts as a closed interval. This means that a range of 3:5 gives 3,
530 A range acts as a closed interval. This means that a range of 3:5 gives 3,
531 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
531 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
532
532
533 use "hg help -c multirevs" to see help for the multirevs command
533 use "hg help -c multirevs" to see help for the multirevs command
534
534
535
535
536
536
537
537
538
538
539
539
540 $ hg help -c multirevs
540 $ hg help -c multirevs
541 hg multirevs ARG
541 hg multirevs ARG
542
542
543 multirevs command
543 multirevs command
544
544
545 (some details hidden, use --verbose to show complete help)
545 (some details hidden, use --verbose to show complete help)
546
546
547
547
548
548
549 $ hg multirevs
549 $ hg multirevs
550 hg multirevs: invalid arguments
550 hg multirevs: invalid arguments
551 hg multirevs ARG
551 hg multirevs ARG
552
552
553 multirevs command
553 multirevs command
554
554
555 (use "hg multirevs -h" to show more help)
555 (use "hg multirevs -h" to show more help)
556 [255]
556 [255]
557
557
558
558
559
559
560 $ echo "multirevs = !" >> $HGRCPATH
560 $ echo "multirevs = !" >> $HGRCPATH
561
561
562 Issue811: Problem loading extensions twice (by site and by user)
562 Issue811: Problem loading extensions twice (by site and by user)
563
563
564 $ cat <<EOF >> $HGRCPATH
564 $ cat <<EOF >> $HGRCPATH
565 > mq =
565 > mq =
566 > strip =
566 > strip =
567 > hgext.mq =
567 > hgext.mq =
568 > hgext/mq =
568 > hgext/mq =
569 > EOF
569 > EOF
570
570
571 Show extensions:
571 Show extensions:
572 (note that mq force load strip, also checking it's not loaded twice)
572 (note that mq force load strip, also checking it's not loaded twice)
573
573
574 $ hg debugextensions
574 $ hg debugextensions
575 mq
575 mq
576 strip
576 strip
577
577
578 For extensions, which name matches one of its commands, help
578 For extensions, which name matches one of its commands, help
579 message should ask '-v -e' to get list of built-in aliases
579 message should ask '-v -e' to get list of built-in aliases
580 along with extension help itself
580 along with extension help itself
581
581
582 $ mkdir $TESTTMP/d
582 $ mkdir $TESTTMP/d
583 $ cat > $TESTTMP/d/dodo.py <<EOF
583 $ cat > $TESTTMP/d/dodo.py <<EOF
584 > """
584 > """
585 > This is an awesome 'dodo' extension. It does nothing and
585 > This is an awesome 'dodo' extension. It does nothing and
586 > writes 'Foo foo'
586 > writes 'Foo foo'
587 > """
587 > """
588 > from mercurial import cmdutil, commands
588 > from mercurial import cmdutil, commands
589 > cmdtable = {}
589 > cmdtable = {}
590 > command = cmdutil.command(cmdtable)
590 > command = cmdutil.command(cmdtable)
591 > @command('dodo', [], 'hg dodo')
591 > @command('dodo', [], 'hg dodo')
592 > def dodo(ui, *args, **kwargs):
592 > def dodo(ui, *args, **kwargs):
593 > """Does nothing"""
593 > """Does nothing"""
594 > ui.write("I do nothing. Yay\\n")
594 > ui.write("I do nothing. Yay\\n")
595 > @command('foofoo', [], 'hg foofoo')
595 > @command('foofoo', [], 'hg foofoo')
596 > def foofoo(ui, *args, **kwargs):
596 > def foofoo(ui, *args, **kwargs):
597 > """Writes 'Foo foo'"""
597 > """Writes 'Foo foo'"""
598 > ui.write("Foo foo\\n")
598 > ui.write("Foo foo\\n")
599 > EOF
599 > EOF
600 $ dodopath=$TESTTMP/d/dodo.py
600 $ dodopath=$TESTTMP/d/dodo.py
601
601
602 $ echo "dodo = $dodopath" >> $HGRCPATH
602 $ echo "dodo = $dodopath" >> $HGRCPATH
603
603
604 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
604 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
605 $ hg help -e dodo
605 $ hg help -e dodo
606 dodo extension -
606 dodo extension -
607
607
608 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
608 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
609
609
610 list of commands:
610 list of commands:
611
611
612 dodo Does nothing
612 dodo Does nothing
613 foofoo Writes 'Foo foo'
613 foofoo Writes 'Foo foo'
614
614
615 (use "hg help -v -e dodo" to show built-in aliases and global options)
615 (use "hg help -v -e dodo" to show built-in aliases and global options)
616
616
617 Make sure that '-v -e' prints list of built-in aliases along with
617 Make sure that '-v -e' prints list of built-in aliases along with
618 extension help itself
618 extension help itself
619 $ hg help -v -e dodo
619 $ hg help -v -e dodo
620 dodo extension -
620 dodo extension -
621
621
622 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
622 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
623
623
624 list of commands:
624 list of commands:
625
625
626 dodo Does nothing
626 dodo Does nothing
627 foofoo Writes 'Foo foo'
627 foofoo Writes 'Foo foo'
628
628
629 global options ([+] can be repeated):
629 global options ([+] can be repeated):
630
630
631 -R --repository REPO repository root directory or name of overlay bundle
631 -R --repository REPO repository root directory or name of overlay bundle
632 file
632 file
633 --cwd DIR change working directory
633 --cwd DIR change working directory
634 -y --noninteractive do not prompt, automatically pick the first choice for
634 -y --noninteractive do not prompt, automatically pick the first choice for
635 all prompts
635 all prompts
636 -q --quiet suppress output
636 -q --quiet suppress output
637 -v --verbose enable additional output
637 -v --verbose enable additional output
638 --config CONFIG [+] set/override config option (use 'section.name=value')
638 --config CONFIG [+] set/override config option (use 'section.name=value')
639 --debug enable debugging output
639 --debug enable debugging output
640 --debugger start debugger
640 --debugger start debugger
641 --encoding ENCODE set the charset encoding (default: ascii)
641 --encoding ENCODE set the charset encoding (default: ascii)
642 --encodingmode MODE set the charset encoding mode (default: strict)
642 --encodingmode MODE set the charset encoding mode (default: strict)
643 --traceback always print a traceback on exception
643 --traceback always print a traceback on exception
644 --time time how long the command takes
644 --time time how long the command takes
645 --profile print command execution profile
645 --profile print command execution profile
646 --version output version information and exit
646 --version output version information and exit
647 -h --help display help and exit
647 -h --help display help and exit
648 --hidden consider hidden changesets
648 --hidden consider hidden changesets
649
649
650 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
650 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
651 $ hg help -v dodo
651 $ hg help -v dodo
652 hg dodo
652 hg dodo
653
653
654 Does nothing
654 Does nothing
655
655
656 (use "hg help -e dodo" to show help for the dodo extension)
656 (use "hg help -e dodo" to show help for the dodo extension)
657
657
658 options:
658 options:
659
659
660 --mq operate on patch repository
660 --mq operate on patch repository
661
661
662 global options ([+] can be repeated):
662 global options ([+] can be repeated):
663
663
664 -R --repository REPO repository root directory or name of overlay bundle
664 -R --repository REPO repository root directory or name of overlay bundle
665 file
665 file
666 --cwd DIR change working directory
666 --cwd DIR change working directory
667 -y --noninteractive do not prompt, automatically pick the first choice for
667 -y --noninteractive do not prompt, automatically pick the first choice for
668 all prompts
668 all prompts
669 -q --quiet suppress output
669 -q --quiet suppress output
670 -v --verbose enable additional output
670 -v --verbose enable additional output
671 --config CONFIG [+] set/override config option (use 'section.name=value')
671 --config CONFIG [+] set/override config option (use 'section.name=value')
672 --debug enable debugging output
672 --debug enable debugging output
673 --debugger start debugger
673 --debugger start debugger
674 --encoding ENCODE set the charset encoding (default: ascii)
674 --encoding ENCODE set the charset encoding (default: ascii)
675 --encodingmode MODE set the charset encoding mode (default: strict)
675 --encodingmode MODE set the charset encoding mode (default: strict)
676 --traceback always print a traceback on exception
676 --traceback always print a traceback on exception
677 --time time how long the command takes
677 --time time how long the command takes
678 --profile print command execution profile
678 --profile print command execution profile
679 --version output version information and exit
679 --version output version information and exit
680 -h --help display help and exit
680 -h --help display help and exit
681 --hidden consider hidden changesets
681 --hidden consider hidden changesets
682
682
683 In case when extension name doesn't match any of its commands,
683 In case when extension name doesn't match any of its commands,
684 help message should ask for '-v' to get list of built-in aliases
684 help message should ask for '-v' to get list of built-in aliases
685 along with extension help
685 along with extension help
686 $ cat > $TESTTMP/d/dudu.py <<EOF
686 $ cat > $TESTTMP/d/dudu.py <<EOF
687 > """
687 > """
688 > This is an awesome 'dudu' extension. It does something and
688 > This is an awesome 'dudu' extension. It does something and
689 > also writes 'Beep beep'
689 > also writes 'Beep beep'
690 > """
690 > """
691 > from mercurial import cmdutil, commands
691 > from mercurial import cmdutil, commands
692 > cmdtable = {}
692 > cmdtable = {}
693 > command = cmdutil.command(cmdtable)
693 > command = cmdutil.command(cmdtable)
694 > @command('something', [], 'hg something')
694 > @command('something', [], 'hg something')
695 > def something(ui, *args, **kwargs):
695 > def something(ui, *args, **kwargs):
696 > """Does something"""
696 > """Does something"""
697 > ui.write("I do something. Yaaay\\n")
697 > ui.write("I do something. Yaaay\\n")
698 > @command('beep', [], 'hg beep')
698 > @command('beep', [], 'hg beep')
699 > def beep(ui, *args, **kwargs):
699 > def beep(ui, *args, **kwargs):
700 > """Writes 'Beep beep'"""
700 > """Writes 'Beep beep'"""
701 > ui.write("Beep beep\\n")
701 > ui.write("Beep beep\\n")
702 > EOF
702 > EOF
703 $ dudupath=$TESTTMP/d/dudu.py
703 $ dudupath=$TESTTMP/d/dudu.py
704
704
705 $ echo "dudu = $dudupath" >> $HGRCPATH
705 $ echo "dudu = $dudupath" >> $HGRCPATH
706
706
707 $ hg help -e dudu
707 $ hg help -e dudu
708 dudu extension -
708 dudu extension -
709
709
710 This is an awesome 'dudu' extension. It does something and also writes 'Beep
710 This is an awesome 'dudu' extension. It does something and also writes 'Beep
711 beep'
711 beep'
712
712
713 list of commands:
713 list of commands:
714
714
715 beep Writes 'Beep beep'
715 beep Writes 'Beep beep'
716 something Does something
716 something Does something
717
717
718 (use "hg help -v dudu" to show built-in aliases and global options)
718 (use "hg help -v dudu" to show built-in aliases and global options)
719
719
720 In case when extension name doesn't match any of its commands,
720 In case when extension name doesn't match any of its commands,
721 help options '-v' and '-v -e' should be equivalent
721 help options '-v' and '-v -e' should be equivalent
722 $ hg help -v dudu
722 $ hg help -v dudu
723 dudu extension -
723 dudu extension -
724
724
725 This is an awesome 'dudu' extension. It does something and also writes 'Beep
725 This is an awesome 'dudu' extension. It does something and also writes 'Beep
726 beep'
726 beep'
727
727
728 list of commands:
728 list of commands:
729
729
730 beep Writes 'Beep beep'
730 beep Writes 'Beep beep'
731 something Does something
731 something Does something
732
732
733 global options ([+] can be repeated):
733 global options ([+] can be repeated):
734
734
735 -R --repository REPO repository root directory or name of overlay bundle
735 -R --repository REPO repository root directory or name of overlay bundle
736 file
736 file
737 --cwd DIR change working directory
737 --cwd DIR change working directory
738 -y --noninteractive do not prompt, automatically pick the first choice for
738 -y --noninteractive do not prompt, automatically pick the first choice for
739 all prompts
739 all prompts
740 -q --quiet suppress output
740 -q --quiet suppress output
741 -v --verbose enable additional output
741 -v --verbose enable additional output
742 --config CONFIG [+] set/override config option (use 'section.name=value')
742 --config CONFIG [+] set/override config option (use 'section.name=value')
743 --debug enable debugging output
743 --debug enable debugging output
744 --debugger start debugger
744 --debugger start debugger
745 --encoding ENCODE set the charset encoding (default: ascii)
745 --encoding ENCODE set the charset encoding (default: ascii)
746 --encodingmode MODE set the charset encoding mode (default: strict)
746 --encodingmode MODE set the charset encoding mode (default: strict)
747 --traceback always print a traceback on exception
747 --traceback always print a traceback on exception
748 --time time how long the command takes
748 --time time how long the command takes
749 --profile print command execution profile
749 --profile print command execution profile
750 --version output version information and exit
750 --version output version information and exit
751 -h --help display help and exit
751 -h --help display help and exit
752 --hidden consider hidden changesets
752 --hidden consider hidden changesets
753
753
754 $ hg help -v -e dudu
754 $ hg help -v -e dudu
755 dudu extension -
755 dudu extension -
756
756
757 This is an awesome 'dudu' extension. It does something and also writes 'Beep
757 This is an awesome 'dudu' extension. It does something and also writes 'Beep
758 beep'
758 beep'
759
759
760 list of commands:
760 list of commands:
761
761
762 beep Writes 'Beep beep'
762 beep Writes 'Beep beep'
763 something Does something
763 something Does something
764
764
765 global options ([+] can be repeated):
765 global options ([+] can be repeated):
766
766
767 -R --repository REPO repository root directory or name of overlay bundle
767 -R --repository REPO repository root directory or name of overlay bundle
768 file
768 file
769 --cwd DIR change working directory
769 --cwd DIR change working directory
770 -y --noninteractive do not prompt, automatically pick the first choice for
770 -y --noninteractive do not prompt, automatically pick the first choice for
771 all prompts
771 all prompts
772 -q --quiet suppress output
772 -q --quiet suppress output
773 -v --verbose enable additional output
773 -v --verbose enable additional output
774 --config CONFIG [+] set/override config option (use 'section.name=value')
774 --config CONFIG [+] set/override config option (use 'section.name=value')
775 --debug enable debugging output
775 --debug enable debugging output
776 --debugger start debugger
776 --debugger start debugger
777 --encoding ENCODE set the charset encoding (default: ascii)
777 --encoding ENCODE set the charset encoding (default: ascii)
778 --encodingmode MODE set the charset encoding mode (default: strict)
778 --encodingmode MODE set the charset encoding mode (default: strict)
779 --traceback always print a traceback on exception
779 --traceback always print a traceback on exception
780 --time time how long the command takes
780 --time time how long the command takes
781 --profile print command execution profile
781 --profile print command execution profile
782 --version output version information and exit
782 --version output version information and exit
783 -h --help display help and exit
783 -h --help display help and exit
784 --hidden consider hidden changesets
784 --hidden consider hidden changesets
785
785
786 Disabled extension commands:
786 Disabled extension commands:
787
787
788 $ ORGHGRCPATH=$HGRCPATH
788 $ ORGHGRCPATH=$HGRCPATH
789 $ HGRCPATH=
789 $ HGRCPATH=
790 $ export HGRCPATH
790 $ export HGRCPATH
791 $ hg help email
791 $ hg help email
792 'email' is provided by the following extension:
792 'email' is provided by the following extension:
793
793
794 patchbomb command to send changesets as (a series of) patch emails
794 patchbomb command to send changesets as (a series of) patch emails
795
795
796 (use "hg help extensions" for information on enabling extensions)
796 (use "hg help extensions" for information on enabling extensions)
797
797
798
798
799 $ hg qdel
799 $ hg qdel
800 hg: unknown command 'qdel'
800 hg: unknown command 'qdel'
801 'qdelete' is provided by the following extension:
801 'qdelete' is provided by the following extension:
802
802
803 mq manage a stack of patches
803 mq manage a stack of patches
804
804
805 (use "hg help extensions" for information on enabling extensions)
805 (use "hg help extensions" for information on enabling extensions)
806 [255]
806 [255]
807
807
808
808
809 $ hg churn
809 $ hg churn
810 hg: unknown command 'churn'
810 hg: unknown command 'churn'
811 'churn' is provided by the following extension:
811 'churn' is provided by the following extension:
812
812
813 churn command to display statistics about repository history
813 churn command to display statistics about repository history
814
814
815 (use "hg help extensions" for information on enabling extensions)
815 (use "hg help extensions" for information on enabling extensions)
816 [255]
816 [255]
817
817
818
818
819
819
820 Disabled extensions:
820 Disabled extensions:
821
821
822 $ hg help churn
822 $ hg help churn
823 churn extension - command to display statistics about repository history
823 churn extension - command to display statistics about repository history
824
824
825 (use "hg help extensions" for information on enabling extensions)
825 (use "hg help extensions" for information on enabling extensions)
826
826
827 $ hg help patchbomb
827 $ hg help patchbomb
828 patchbomb extension - command to send changesets as (a series of) patch emails
828 patchbomb extension - command to send changesets as (a series of) patch emails
829
829
830 (use "hg help extensions" for information on enabling extensions)
830 (use "hg help extensions" for information on enabling extensions)
831
831
832
832
833 Broken disabled extension and command:
833 Broken disabled extension and command:
834
834
835 $ mkdir hgext
835 $ mkdir hgext
836 $ echo > hgext/__init__.py
836 $ echo > hgext/__init__.py
837 $ cat > hgext/broken.py <<EOF
837 $ cat > hgext/broken.py <<EOF
838 > "broken extension'
838 > "broken extension'
839 > EOF
839 > EOF
840 $ cat > path.py <<EOF
840 $ cat > path.py <<EOF
841 > import os, sys
841 > import os, sys
842 > sys.path.insert(0, os.environ['HGEXTPATH'])
842 > sys.path.insert(0, os.environ['HGEXTPATH'])
843 > EOF
843 > EOF
844 $ HGEXTPATH=`pwd`
844 $ HGEXTPATH=`pwd`
845 $ export HGEXTPATH
845 $ export HGEXTPATH
846
846
847 $ hg --config extensions.path=./path.py help broken
847 $ hg --config extensions.path=./path.py help broken
848 broken extension - (no help text available)
848 broken extension - (no help text available)
849
849
850 (use "hg help extensions" for information on enabling extensions)
850 (use "hg help extensions" for information on enabling extensions)
851
851
852
852
853 $ cat > hgext/forest.py <<EOF
853 $ cat > hgext/forest.py <<EOF
854 > cmdtable = None
854 > cmdtable = None
855 > EOF
855 > EOF
856 $ hg --config extensions.path=./path.py help foo > /dev/null
856 $ hg --config extensions.path=./path.py help foo > /dev/null
857 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
857 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
858 abort: no such help topic: foo
858 abort: no such help topic: foo
859 (try "hg help --keyword foo")
859 (try "hg help --keyword foo")
860 [255]
860 [255]
861
861
862 $ cat > throw.py <<EOF
862 $ cat > throw.py <<EOF
863 > from mercurial import cmdutil, commands, util
863 > from mercurial import cmdutil, commands, util
864 > cmdtable = {}
864 > cmdtable = {}
865 > command = cmdutil.command(cmdtable)
865 > command = cmdutil.command(cmdtable)
866 > class Bogon(Exception): pass
866 > class Bogon(Exception): pass
867 > @command('throw', [], 'hg throw', norepo=True)
867 > @command('throw', [], 'hg throw', norepo=True)
868 > def throw(ui, **opts):
868 > def throw(ui, **opts):
869 > """throws an exception"""
869 > """throws an exception"""
870 > raise Bogon()
870 > raise Bogon()
871 > EOF
871 > EOF
872
872
873 No declared supported version, extension complains:
873 No declared supported version, extension complains:
874 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
874 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
875 ** Unknown exception encountered with possibly-broken third-party extension throw
875 ** Unknown exception encountered with possibly-broken third-party extension throw
876 ** which supports versions unknown of Mercurial.
876 ** which supports versions unknown of Mercurial.
877 ** Please disable throw and try your action again.
877 ** Please disable throw and try your action again.
878 ** If that fixes the bug please report it to the extension author.
878 ** If that fixes the bug please report it to the extension author.
879 ** Python * (glob)
879 ** Python * (glob)
880 ** Mercurial Distributed SCM * (glob)
880 ** Mercurial Distributed SCM * (glob)
881 ** Extensions loaded: throw
881 ** Extensions loaded: throw
882
882
883 empty declaration of supported version, extension complains:
883 empty declaration of supported version, extension complains:
884 $ echo "testedwith = ''" >> throw.py
884 $ echo "testedwith = ''" >> throw.py
885 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
885 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
886 ** Unknown exception encountered with possibly-broken third-party extension throw
886 ** Unknown exception encountered with possibly-broken third-party extension throw
887 ** which supports versions unknown of Mercurial.
887 ** which supports versions unknown of Mercurial.
888 ** Please disable throw and try your action again.
888 ** Please disable throw and try your action again.
889 ** If that fixes the bug please report it to the extension author.
889 ** If that fixes the bug please report it to the extension author.
890 ** Python * (glob)
890 ** Python * (glob)
891 ** Mercurial Distributed SCM (*) (glob)
891 ** Mercurial Distributed SCM (*) (glob)
892 ** Extensions loaded: throw
892 ** Extensions loaded: throw
893
893
894 If the extension specifies a buglink, show that:
894 If the extension specifies a buglink, show that:
895 $ echo 'buglink = "http://example.com/bts"' >> throw.py
895 $ echo 'buglink = "http://example.com/bts"' >> throw.py
896 $ rm -f throw.pyc throw.pyo
896 $ rm -f throw.pyc throw.pyo
897 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
897 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
898 ** Unknown exception encountered with possibly-broken third-party extension throw
898 ** Unknown exception encountered with possibly-broken third-party extension throw
899 ** which supports versions unknown of Mercurial.
899 ** which supports versions unknown of Mercurial.
900 ** Please disable throw and try your action again.
900 ** Please disable throw and try your action again.
901 ** If that fixes the bug please report it to http://example.com/bts
901 ** If that fixes the bug please report it to http://example.com/bts
902 ** Python * (glob)
902 ** Python * (glob)
903 ** Mercurial Distributed SCM (*) (glob)
903 ** Mercurial Distributed SCM (*) (glob)
904 ** Extensions loaded: throw
904 ** Extensions loaded: throw
905
905
906 If the extensions declare outdated versions, accuse the older extension first:
906 If the extensions declare outdated versions, accuse the older extension first:
907 $ echo "from mercurial import util" >> older.py
907 $ echo "from mercurial import util" >> older.py
908 $ echo "util.version = lambda:'2.2'" >> older.py
908 $ echo "util.version = lambda:'2.2'" >> older.py
909 $ echo "testedwith = '1.9.3'" >> older.py
909 $ echo "testedwith = '1.9.3'" >> older.py
910 $ echo "testedwith = '2.1.1'" >> throw.py
910 $ echo "testedwith = '2.1.1'" >> throw.py
911 $ rm -f throw.pyc throw.pyo
911 $ rm -f throw.pyc throw.pyo
912 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
912 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
913 > throw 2>&1 | egrep '^\*\*'
913 > throw 2>&1 | egrep '^\*\*'
914 ** Unknown exception encountered with possibly-broken third-party extension older
914 ** Unknown exception encountered with possibly-broken third-party extension older
915 ** which supports versions 1.9 of Mercurial.
915 ** which supports versions 1.9 of Mercurial.
916 ** Please disable older and try your action again.
916 ** Please disable older and try your action again.
917 ** If that fixes the bug please report it to the extension author.
917 ** If that fixes the bug please report it to the extension author.
918 ** Python * (glob)
918 ** Python * (glob)
919 ** Mercurial Distributed SCM (version 2.2)
919 ** Mercurial Distributed SCM (version 2.2)
920 ** Extensions loaded: throw, older
920 ** Extensions loaded: throw, older
921
921
922 One extension only tested with older, one only with newer versions:
922 One extension only tested with older, one only with newer versions:
923 $ echo "util.version = lambda:'2.1'" >> older.py
923 $ echo "util.version = lambda:'2.1'" >> older.py
924 $ rm -f older.pyc older.pyo
924 $ rm -f older.pyc older.pyo
925 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
925 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
926 > throw 2>&1 | egrep '^\*\*'
926 > throw 2>&1 | egrep '^\*\*'
927 ** Unknown exception encountered with possibly-broken third-party extension older
927 ** Unknown exception encountered with possibly-broken third-party extension older
928 ** which supports versions 1.9 of Mercurial.
928 ** which supports versions 1.9 of Mercurial.
929 ** Please disable older and try your action again.
929 ** Please disable older and try your action again.
930 ** If that fixes the bug please report it to the extension author.
930 ** If that fixes the bug please report it to the extension author.
931 ** Python * (glob)
931 ** Python * (glob)
932 ** Mercurial Distributed SCM (version 2.1)
932 ** Mercurial Distributed SCM (version 2.1)
933 ** Extensions loaded: throw, older
933 ** Extensions loaded: throw, older
934
934
935 Older extension is tested with current version, the other only with newer:
935 Older extension is tested with current version, the other only with newer:
936 $ echo "util.version = lambda:'1.9.3'" >> older.py
936 $ echo "util.version = lambda:'1.9.3'" >> older.py
937 $ rm -f older.pyc older.pyo
937 $ rm -f older.pyc older.pyo
938 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
938 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
939 > throw 2>&1 | egrep '^\*\*'
939 > throw 2>&1 | egrep '^\*\*'
940 ** Unknown exception encountered with possibly-broken third-party extension throw
940 ** Unknown exception encountered with possibly-broken third-party extension throw
941 ** which supports versions 2.1 of Mercurial.
941 ** which supports versions 2.1 of Mercurial.
942 ** Please disable throw and try your action again.
942 ** Please disable throw and try your action again.
943 ** If that fixes the bug please report it to http://example.com/bts
943 ** If that fixes the bug please report it to http://example.com/bts
944 ** Python * (glob)
944 ** Python * (glob)
945 ** Mercurial Distributed SCM (version 1.9.3)
945 ** Mercurial Distributed SCM (version 1.9.3)
946 ** Extensions loaded: throw, older
946 ** Extensions loaded: throw, older
947
947
948 Ability to point to a different point
948 Ability to point to a different point
949 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
949 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
950 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
950 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
951 ** unknown exception encountered, please report by visiting
951 ** unknown exception encountered, please report by visiting
952 ** Your Local Goat Lenders
952 ** Your Local Goat Lenders
953 ** Python * (glob)
953 ** Python * (glob)
954 ** Mercurial Distributed SCM (*) (glob)
954 ** Mercurial Distributed SCM (*) (glob)
955 ** Extensions loaded: throw, older
955 ** Extensions loaded: throw, older
956
956
957 Declare the version as supporting this hg version, show regular bts link:
957 Declare the version as supporting this hg version, show regular bts link:
958 $ hgver=`$PYTHON -c 'from mercurial import util; print util.version().split("+")[0]'`
958 $ hgver=`$PYTHON -c 'from mercurial import util; print util.version().split("+")[0]'`
959 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
959 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
960 $ if [ -z "$hgver" ]; then
960 $ if [ -z "$hgver" ]; then
961 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
961 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
962 > fi
962 > fi
963 $ rm -f throw.pyc throw.pyo
963 $ rm -f throw.pyc throw.pyo
964 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
964 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
965 ** unknown exception encountered, please report by visiting
965 ** unknown exception encountered, please report by visiting
966 ** https://mercurial-scm.org/wiki/BugTracker
966 ** https://mercurial-scm.org/wiki/BugTracker
967 ** Python * (glob)
967 ** Python * (glob)
968 ** Mercurial Distributed SCM (*) (glob)
968 ** Mercurial Distributed SCM (*) (glob)
969 ** Extensions loaded: throw
969 ** Extensions loaded: throw
970
970
971 Patch version is ignored during compatibility check
971 Patch version is ignored during compatibility check
972 $ echo "testedwith = '3.2'" >> throw.py
972 $ echo "testedwith = '3.2'" >> throw.py
973 $ echo "util.version = lambda:'3.2.2'" >> throw.py
973 $ echo "util.version = lambda:'3.2.2'" >> throw.py
974 $ rm -f throw.pyc throw.pyo
974 $ rm -f throw.pyc throw.pyo
975 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
975 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
976 ** unknown exception encountered, please report by visiting
976 ** unknown exception encountered, please report by visiting
977 ** https://mercurial-scm.org/wiki/BugTracker
977 ** https://mercurial-scm.org/wiki/BugTracker
978 ** Python * (glob)
978 ** Python * (glob)
979 ** Mercurial Distributed SCM (*) (glob)
979 ** Mercurial Distributed SCM (*) (glob)
980 ** Extensions loaded: throw
980 ** Extensions loaded: throw
981
981
982 Test version number support in 'hg version':
982 Test version number support in 'hg version':
983 $ echo '__version__ = (1, 2, 3)' >> throw.py
983 $ echo '__version__ = (1, 2, 3)' >> throw.py
984 $ rm -f throw.pyc throw.pyo
984 $ rm -f throw.pyc throw.pyo
985 $ hg version -v
985 $ hg version -v
986 Mercurial Distributed SCM (version *) (glob)
986 Mercurial Distributed SCM (version *) (glob)
987 (see https://mercurial-scm.org for more information)
987 (see https://mercurial-scm.org for more information)
988
988
989 Copyright (C) 2005-* Matt Mackall and others (glob)
989 Copyright (C) 2005-* Matt Mackall and others (glob)
990 This is free software; see the source for copying conditions. There is NO
990 This is free software; see the source for copying conditions. There is NO
991 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
991 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
992
992
993 Enabled extensions:
993 Enabled extensions:
994
994
995
995
996 $ hg version -v --config extensions.throw=throw.py
996 $ hg version -v --config extensions.throw=throw.py
997 Mercurial Distributed SCM (version *) (glob)
997 Mercurial Distributed SCM (version *) (glob)
998 (see https://mercurial-scm.org for more information)
998 (see https://mercurial-scm.org for more information)
999
999
1000 Copyright (C) 2005-* Matt Mackall and others (glob)
1000 Copyright (C) 2005-* Matt Mackall and others (glob)
1001 This is free software; see the source for copying conditions. There is NO
1001 This is free software; see the source for copying conditions. There is NO
1002 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1002 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1003
1003
1004 Enabled extensions:
1004 Enabled extensions:
1005
1005
1006 throw 1.2.3
1006 throw external 1.2.3
1007 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1007 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1008 $ rm -f throw.pyc throw.pyo
1008 $ rm -f throw.pyc throw.pyo
1009 $ hg version -v --config extensions.throw=throw.py
1009 $ hg version -v --config extensions.throw=throw.py
1010 Mercurial Distributed SCM (version *) (glob)
1010 Mercurial Distributed SCM (version *) (glob)
1011 (see https://mercurial-scm.org for more information)
1011 (see https://mercurial-scm.org for more information)
1012
1012
1013 Copyright (C) 2005-* Matt Mackall and others (glob)
1013 Copyright (C) 2005-* Matt Mackall and others (glob)
1014 This is free software; see the source for copying conditions. There is NO
1014 This is free software; see the source for copying conditions. There is NO
1015 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1015 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1016
1016
1017 Enabled extensions:
1017 Enabled extensions:
1018
1018
1019 throw 1.twentythree
1019 throw external 1.twentythree
1020
1020
1021 Refuse to load extensions with minimum version requirements
1021 Refuse to load extensions with minimum version requirements
1022
1022
1023 $ cat > minversion1.py << EOF
1023 $ cat > minversion1.py << EOF
1024 > from mercurial import util
1024 > from mercurial import util
1025 > util.version = lambda: '3.5.2'
1025 > util.version = lambda: '3.5.2'
1026 > minimumhgversion = '3.6'
1026 > minimumhgversion = '3.6'
1027 > EOF
1027 > EOF
1028 $ hg --config extensions.minversion=minversion1.py version
1028 $ hg --config extensions.minversion=minversion1.py version
1029 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1029 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1030 Mercurial Distributed SCM (version 3.5.2)
1030 Mercurial Distributed SCM (version 3.5.2)
1031 (see https://mercurial-scm.org for more information)
1031 (see https://mercurial-scm.org for more information)
1032
1032
1033 Copyright (C) 2005-* Matt Mackall and others (glob)
1033 Copyright (C) 2005-* Matt Mackall and others (glob)
1034 This is free software; see the source for copying conditions. There is NO
1034 This is free software; see the source for copying conditions. There is NO
1035 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1035 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1036
1036
1037 $ cat > minversion2.py << EOF
1037 $ cat > minversion2.py << EOF
1038 > from mercurial import util
1038 > from mercurial import util
1039 > util.version = lambda: '3.6'
1039 > util.version = lambda: '3.6'
1040 > minimumhgversion = '3.7'
1040 > minimumhgversion = '3.7'
1041 > EOF
1041 > EOF
1042 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1042 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1043 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1043 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1044
1044
1045 Can load version that is only off by point release
1045 Can load version that is only off by point release
1046
1046
1047 $ cat > minversion2.py << EOF
1047 $ cat > minversion2.py << EOF
1048 > from mercurial import util
1048 > from mercurial import util
1049 > util.version = lambda: '3.6.1'
1049 > util.version = lambda: '3.6.1'
1050 > minimumhgversion = '3.6'
1050 > minimumhgversion = '3.6'
1051 > EOF
1051 > EOF
1052 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1052 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1053 [1]
1053 [1]
1054
1054
1055 Can load minimum version identical to current
1055 Can load minimum version identical to current
1056
1056
1057 $ cat > minversion3.py << EOF
1057 $ cat > minversion3.py << EOF
1058 > from mercurial import util
1058 > from mercurial import util
1059 > util.version = lambda: '3.5'
1059 > util.version = lambda: '3.5'
1060 > minimumhgversion = '3.5'
1060 > minimumhgversion = '3.5'
1061 > EOF
1061 > EOF
1062 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1062 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1063 [1]
1063 [1]
1064
1064
1065 Restore HGRCPATH
1065 Restore HGRCPATH
1066
1066
1067 $ HGRCPATH=$ORGHGRCPATH
1067 $ HGRCPATH=$ORGHGRCPATH
1068 $ export HGRCPATH
1068 $ export HGRCPATH
1069
1069
1070 Commands handling multiple repositories at a time should invoke only
1070 Commands handling multiple repositories at a time should invoke only
1071 "reposetup()" of extensions enabling in the target repository.
1071 "reposetup()" of extensions enabling in the target repository.
1072
1072
1073 $ mkdir reposetup-test
1073 $ mkdir reposetup-test
1074 $ cd reposetup-test
1074 $ cd reposetup-test
1075
1075
1076 $ cat > $TESTTMP/reposetuptest.py <<EOF
1076 $ cat > $TESTTMP/reposetuptest.py <<EOF
1077 > from mercurial import extensions
1077 > from mercurial import extensions
1078 > def reposetup(ui, repo):
1078 > def reposetup(ui, repo):
1079 > ui.write('reposetup() for %s\n' % (repo.root))
1079 > ui.write('reposetup() for %s\n' % (repo.root))
1080 > EOF
1080 > EOF
1081 $ hg init src
1081 $ hg init src
1082 $ echo a > src/a
1082 $ echo a > src/a
1083 $ hg -R src commit -Am '#0 at src/a'
1083 $ hg -R src commit -Am '#0 at src/a'
1084 adding a
1084 adding a
1085 $ echo '[extensions]' >> src/.hg/hgrc
1085 $ echo '[extensions]' >> src/.hg/hgrc
1086 $ echo '# enable extension locally' >> src/.hg/hgrc
1086 $ echo '# enable extension locally' >> src/.hg/hgrc
1087 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1087 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1088 $ hg -R src status
1088 $ hg -R src status
1089 reposetup() for $TESTTMP/reposetup-test/src (glob)
1089 reposetup() for $TESTTMP/reposetup-test/src (glob)
1090
1090
1091 $ hg clone -U src clone-dst1
1091 $ hg clone -U src clone-dst1
1092 reposetup() for $TESTTMP/reposetup-test/src (glob)
1092 reposetup() for $TESTTMP/reposetup-test/src (glob)
1093 $ hg init push-dst1
1093 $ hg init push-dst1
1094 $ hg -q -R src push push-dst1
1094 $ hg -q -R src push push-dst1
1095 reposetup() for $TESTTMP/reposetup-test/src (glob)
1095 reposetup() for $TESTTMP/reposetup-test/src (glob)
1096 $ hg init pull-src1
1096 $ hg init pull-src1
1097 $ hg -q -R pull-src1 pull src
1097 $ hg -q -R pull-src1 pull src
1098 reposetup() for $TESTTMP/reposetup-test/src (glob)
1098 reposetup() for $TESTTMP/reposetup-test/src (glob)
1099
1099
1100 $ cat <<EOF >> $HGRCPATH
1100 $ cat <<EOF >> $HGRCPATH
1101 > [extensions]
1101 > [extensions]
1102 > # disable extension globally and explicitly
1102 > # disable extension globally and explicitly
1103 > reposetuptest = !
1103 > reposetuptest = !
1104 > EOF
1104 > EOF
1105 $ hg clone -U src clone-dst2
1105 $ hg clone -U src clone-dst2
1106 reposetup() for $TESTTMP/reposetup-test/src (glob)
1106 reposetup() for $TESTTMP/reposetup-test/src (glob)
1107 $ hg init push-dst2
1107 $ hg init push-dst2
1108 $ hg -q -R src push push-dst2
1108 $ hg -q -R src push push-dst2
1109 reposetup() for $TESTTMP/reposetup-test/src (glob)
1109 reposetup() for $TESTTMP/reposetup-test/src (glob)
1110 $ hg init pull-src2
1110 $ hg init pull-src2
1111 $ hg -q -R pull-src2 pull src
1111 $ hg -q -R pull-src2 pull src
1112 reposetup() for $TESTTMP/reposetup-test/src (glob)
1112 reposetup() for $TESTTMP/reposetup-test/src (glob)
1113
1113
1114 $ cat <<EOF >> $HGRCPATH
1114 $ cat <<EOF >> $HGRCPATH
1115 > [extensions]
1115 > [extensions]
1116 > # enable extension globally
1116 > # enable extension globally
1117 > reposetuptest = $TESTTMP/reposetuptest.py
1117 > reposetuptest = $TESTTMP/reposetuptest.py
1118 > EOF
1118 > EOF
1119 $ hg clone -U src clone-dst3
1119 $ hg clone -U src clone-dst3
1120 reposetup() for $TESTTMP/reposetup-test/src (glob)
1120 reposetup() for $TESTTMP/reposetup-test/src (glob)
1121 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1121 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1122 $ hg init push-dst3
1122 $ hg init push-dst3
1123 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1123 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1124 $ hg -q -R src push push-dst3
1124 $ hg -q -R src push push-dst3
1125 reposetup() for $TESTTMP/reposetup-test/src (glob)
1125 reposetup() for $TESTTMP/reposetup-test/src (glob)
1126 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1126 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1127 $ hg init pull-src3
1127 $ hg init pull-src3
1128 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1128 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1129 $ hg -q -R pull-src3 pull src
1129 $ hg -q -R pull-src3 pull src
1130 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1130 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1131 reposetup() for $TESTTMP/reposetup-test/src (glob)
1131 reposetup() for $TESTTMP/reposetup-test/src (glob)
1132
1132
1133 $ echo '[extensions]' >> src/.hg/hgrc
1133 $ echo '[extensions]' >> src/.hg/hgrc
1134 $ echo '# disable extension locally' >> src/.hg/hgrc
1134 $ echo '# disable extension locally' >> src/.hg/hgrc
1135 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1135 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1136 $ hg clone -U src clone-dst4
1136 $ hg clone -U src clone-dst4
1137 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1137 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1138 $ hg init push-dst4
1138 $ hg init push-dst4
1139 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1139 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1140 $ hg -q -R src push push-dst4
1140 $ hg -q -R src push push-dst4
1141 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1141 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1142 $ hg init pull-src4
1142 $ hg init pull-src4
1143 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1143 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1144 $ hg -q -R pull-src4 pull src
1144 $ hg -q -R pull-src4 pull src
1145 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1145 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1146
1146
1147 disabling in command line overlays with all configuration
1147 disabling in command line overlays with all configuration
1148 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1148 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1149 $ hg --config extensions.reposetuptest=! init push-dst5
1149 $ hg --config extensions.reposetuptest=! init push-dst5
1150 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1150 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1151 $ hg --config extensions.reposetuptest=! init pull-src5
1151 $ hg --config extensions.reposetuptest=! init pull-src5
1152 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1152 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1153
1153
1154 $ cat <<EOF >> $HGRCPATH
1154 $ cat <<EOF >> $HGRCPATH
1155 > [extensions]
1155 > [extensions]
1156 > # disable extension globally and explicitly
1156 > # disable extension globally and explicitly
1157 > reposetuptest = !
1157 > reposetuptest = !
1158 > EOF
1158 > EOF
1159 $ hg init parent
1159 $ hg init parent
1160 $ hg init parent/sub1
1160 $ hg init parent/sub1
1161 $ echo 1 > parent/sub1/1
1161 $ echo 1 > parent/sub1/1
1162 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1162 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1163 adding 1
1163 adding 1
1164 $ hg init parent/sub2
1164 $ hg init parent/sub2
1165 $ hg init parent/sub2/sub21
1165 $ hg init parent/sub2/sub21
1166 $ echo 21 > parent/sub2/sub21/21
1166 $ echo 21 > parent/sub2/sub21/21
1167 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1167 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1168 adding 21
1168 adding 21
1169 $ cat > parent/sub2/.hgsub <<EOF
1169 $ cat > parent/sub2/.hgsub <<EOF
1170 > sub21 = sub21
1170 > sub21 = sub21
1171 > EOF
1171 > EOF
1172 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1172 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1173 adding .hgsub
1173 adding .hgsub
1174 $ hg init parent/sub3
1174 $ hg init parent/sub3
1175 $ echo 3 > parent/sub3/3
1175 $ echo 3 > parent/sub3/3
1176 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1176 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1177 adding 3
1177 adding 3
1178 $ cat > parent/.hgsub <<EOF
1178 $ cat > parent/.hgsub <<EOF
1179 > sub1 = sub1
1179 > sub1 = sub1
1180 > sub2 = sub2
1180 > sub2 = sub2
1181 > sub3 = sub3
1181 > sub3 = sub3
1182 > EOF
1182 > EOF
1183 $ hg -R parent commit -Am '#0 at parent'
1183 $ hg -R parent commit -Am '#0 at parent'
1184 adding .hgsub
1184 adding .hgsub
1185 $ echo '[extensions]' >> parent/.hg/hgrc
1185 $ echo '[extensions]' >> parent/.hg/hgrc
1186 $ echo '# enable extension locally' >> parent/.hg/hgrc
1186 $ echo '# enable extension locally' >> parent/.hg/hgrc
1187 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1187 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1188 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1188 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1189 $ hg -R parent status -S -A
1189 $ hg -R parent status -S -A
1190 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1190 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1191 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1191 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1192 C .hgsub
1192 C .hgsub
1193 C .hgsubstate
1193 C .hgsubstate
1194 C sub1/1
1194 C sub1/1
1195 C sub2/.hgsub
1195 C sub2/.hgsub
1196 C sub2/.hgsubstate
1196 C sub2/.hgsubstate
1197 C sub2/sub21/21
1197 C sub2/sub21/21
1198 C sub3/3
1198 C sub3/3
1199
1199
1200 $ cd ..
1200 $ cd ..
1201
1201
1202 Test synopsis and docstring extending
1202 Test synopsis and docstring extending
1203
1203
1204 $ hg init exthelp
1204 $ hg init exthelp
1205 $ cat > exthelp.py <<EOF
1205 $ cat > exthelp.py <<EOF
1206 > from mercurial import commands, extensions
1206 > from mercurial import commands, extensions
1207 > def exbookmarks(orig, *args, **opts):
1207 > def exbookmarks(orig, *args, **opts):
1208 > return orig(*args, **opts)
1208 > return orig(*args, **opts)
1209 > def uisetup(ui):
1209 > def uisetup(ui):
1210 > synopsis = ' GREPME [--foo] [-x]'
1210 > synopsis = ' GREPME [--foo] [-x]'
1211 > docstring = '''
1211 > docstring = '''
1212 > GREPME make sure that this is in the help!
1212 > GREPME make sure that this is in the help!
1213 > '''
1213 > '''
1214 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1214 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1215 > synopsis, docstring)
1215 > synopsis, docstring)
1216 > EOF
1216 > EOF
1217 $ abspath=`pwd`/exthelp.py
1217 $ abspath=`pwd`/exthelp.py
1218 $ echo '[extensions]' >> $HGRCPATH
1218 $ echo '[extensions]' >> $HGRCPATH
1219 $ echo "exthelp = $abspath" >> $HGRCPATH
1219 $ echo "exthelp = $abspath" >> $HGRCPATH
1220 $ cd exthelp
1220 $ cd exthelp
1221 $ hg help bookmarks | grep GREPME
1221 $ hg help bookmarks | grep GREPME
1222 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1222 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1223 GREPME make sure that this is in the help!
1223 GREPME make sure that this is in the help!
1224
1224
General Comments 0
You need to be logged in to leave comments. Login now