##// END OF EJS Templates
log: mention ordering...
timeless -
r27663:cddb5cd3 default
parent child Browse files
Show More
@@ -1,7009 +1,7009 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, _('commit if no conflicts were encountered')),
529 ('', 'commit', None, _('commit if no conflicts were encountered')),
530 ('', 'parent', '',
530 ('', 'parent', '',
531 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
531 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
532 ('r', 'rev', '', _('revision to backout'), _('REV')),
532 ('r', 'rev', '', _('revision to backout'), _('REV')),
533 ('e', 'edit', False, _('invoke editor on commit messages')),
533 ('e', 'edit', False, _('invoke editor on commit messages')),
534 ] + mergetoolopts + walkopts + commitopts + commitopts2,
534 ] + mergetoolopts + walkopts + commitopts + commitopts2,
535 _('[OPTION]... [-r] REV'))
535 _('[OPTION]... [-r] REV'))
536 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
536 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
537 '''reverse effect of earlier changeset
537 '''reverse effect of earlier changeset
538
538
539 Prepare a new changeset with the effect of REV undone in the
539 Prepare a new changeset with the effect of REV undone in the
540 current working directory.
540 current working directory.
541
541
542 If REV is the parent of the working directory, then this new changeset
542 If REV is the parent of the working directory, then this new changeset
543 is committed automatically. Otherwise, hg needs to merge the
543 is committed automatically. Otherwise, hg needs to merge the
544 changes and the merged result is left uncommitted.
544 changes and the merged result is left uncommitted.
545
545
546 .. note::
546 .. note::
547
547
548 :hg:`backout` cannot be used to fix either an unwanted or
548 :hg:`backout` cannot be used to fix either an unwanted or
549 incorrect merge.
549 incorrect merge.
550
550
551 .. container:: verbose
551 .. container:: verbose
552
552
553 Examples:
553 Examples:
554
554
555 - Reverse the effect of the parent of the working directory.
555 - Reverse the effect of the parent of the working directory.
556 This backout will be committed immediately::
556 This backout will be committed immediately::
557
557
558 hg backout -r .
558 hg backout -r .
559
559
560 - Reverse the effect of previous bad revision 23::
560 - Reverse the effect of previous bad revision 23::
561
561
562 hg backout -r 23
562 hg backout -r 23
563 hg commit -m "Backout revision 23"
563 hg commit -m "Backout revision 23"
564
564
565 - Reverse the effect of previous bad revision 23 and
565 - Reverse the effect of previous bad revision 23 and
566 commit the backout immediately::
566 commit the backout immediately::
567
567
568 hg backout -r 23 --commit
568 hg backout -r 23 --commit
569
569
570 By default, the pending changeset will have one parent,
570 By default, the pending changeset will have one parent,
571 maintaining a linear history. With --merge, the pending
571 maintaining a linear history. With --merge, the pending
572 changeset will instead have two parents: the old parent of the
572 changeset will instead have two parents: the old parent of the
573 working directory and a new child of REV that simply undoes REV.
573 working directory and a new child of REV that simply undoes REV.
574
574
575 Before version 1.7, the behavior without --merge was equivalent
575 Before version 1.7, the behavior without --merge was equivalent
576 to specifying --merge followed by :hg:`update --clean .` to
576 to specifying --merge followed by :hg:`update --clean .` to
577 cancel the merge and leave the child of REV as a head to be
577 cancel the merge and leave the child of REV as a head to be
578 merged separately.
578 merged separately.
579
579
580 See :hg:`help dates` for a list of formats valid for -d/--date.
580 See :hg:`help dates` for a list of formats valid for -d/--date.
581
581
582 See :hg:`help revert` for a way to restore files to the state
582 See :hg:`help revert` for a way to restore files to the state
583 of another revision.
583 of another revision.
584
584
585 Returns 0 on success, 1 if nothing to backout or there are unresolved
585 Returns 0 on success, 1 if nothing to backout or there are unresolved
586 files.
586 files.
587 '''
587 '''
588 wlock = lock = None
588 wlock = lock = None
589 try:
589 try:
590 wlock = repo.wlock()
590 wlock = repo.wlock()
591 lock = repo.lock()
591 lock = repo.lock()
592 return _dobackout(ui, repo, node, rev, commit, **opts)
592 return _dobackout(ui, repo, node, rev, commit, **opts)
593 finally:
593 finally:
594 release(lock, wlock)
594 release(lock, wlock)
595
595
596 def _dobackout(ui, repo, node=None, rev=None, commit=False, **opts):
596 def _dobackout(ui, repo, node=None, rev=None, commit=False, **opts):
597 if rev and node:
597 if rev and node:
598 raise error.Abort(_("please specify just one revision"))
598 raise error.Abort(_("please specify just one revision"))
599
599
600 if not rev:
600 if not rev:
601 rev = node
601 rev = node
602
602
603 if not rev:
603 if not rev:
604 raise error.Abort(_("please specify a revision to backout"))
604 raise error.Abort(_("please specify a revision to backout"))
605
605
606 date = opts.get('date')
606 date = opts.get('date')
607 if date:
607 if date:
608 opts['date'] = util.parsedate(date)
608 opts['date'] = util.parsedate(date)
609
609
610 cmdutil.checkunfinished(repo)
610 cmdutil.checkunfinished(repo)
611 cmdutil.bailifchanged(repo)
611 cmdutil.bailifchanged(repo)
612 node = scmutil.revsingle(repo, rev).node()
612 node = scmutil.revsingle(repo, rev).node()
613
613
614 op1, op2 = repo.dirstate.parents()
614 op1, op2 = repo.dirstate.parents()
615 if not repo.changelog.isancestor(node, op1):
615 if not repo.changelog.isancestor(node, op1):
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
617
617
618 p1, p2 = repo.changelog.parents(node)
618 p1, p2 = repo.changelog.parents(node)
619 if p1 == nullid:
619 if p1 == nullid:
620 raise error.Abort(_('cannot backout a change with no parents'))
620 raise error.Abort(_('cannot backout a change with no parents'))
621 if p2 != nullid:
621 if p2 != nullid:
622 if not opts.get('parent'):
622 if not opts.get('parent'):
623 raise error.Abort(_('cannot backout a merge changeset'))
623 raise error.Abort(_('cannot backout a merge changeset'))
624 p = repo.lookup(opts['parent'])
624 p = repo.lookup(opts['parent'])
625 if p not in (p1, p2):
625 if p not in (p1, p2):
626 raise error.Abort(_('%s is not a parent of %s') %
626 raise error.Abort(_('%s is not a parent of %s') %
627 (short(p), short(node)))
627 (short(p), short(node)))
628 parent = p
628 parent = p
629 else:
629 else:
630 if opts.get('parent'):
630 if opts.get('parent'):
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
632 parent = p1
632 parent = p1
633
633
634 # the backout should appear on the same branch
634 # the backout should appear on the same branch
635 try:
635 try:
636 branch = repo.dirstate.branch()
636 branch = repo.dirstate.branch()
637 bheads = repo.branchheads(branch)
637 bheads = repo.branchheads(branch)
638 rctx = scmutil.revsingle(repo, hex(parent))
638 rctx = scmutil.revsingle(repo, hex(parent))
639 if not opts.get('merge') and op1 != node:
639 if not opts.get('merge') and op1 != node:
640 dsguard = cmdutil.dirstateguard(repo, 'backout')
640 dsguard = cmdutil.dirstateguard(repo, 'backout')
641 try:
641 try:
642 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
642 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
643 'backout')
643 'backout')
644 stats = mergemod.update(repo, parent, True, True, node, False)
644 stats = mergemod.update(repo, parent, True, True, node, False)
645 repo.setparents(op1, op2)
645 repo.setparents(op1, op2)
646 dsguard.close()
646 dsguard.close()
647 hg._showstats(repo, stats)
647 hg._showstats(repo, stats)
648 if stats[3]:
648 if stats[3]:
649 repo.ui.status(_("use 'hg resolve' to retry unresolved "
649 repo.ui.status(_("use 'hg resolve' to retry unresolved "
650 "file merges\n"))
650 "file merges\n"))
651 return 1
651 return 1
652 elif not commit:
652 elif not commit:
653 msg = _("changeset %s backed out, "
653 msg = _("changeset %s backed out, "
654 "don't forget to commit.\n")
654 "don't forget to commit.\n")
655 ui.status(msg % short(node))
655 ui.status(msg % short(node))
656 return 0
656 return 0
657 finally:
657 finally:
658 ui.setconfig('ui', 'forcemerge', '', '')
658 ui.setconfig('ui', 'forcemerge', '', '')
659 lockmod.release(dsguard)
659 lockmod.release(dsguard)
660 else:
660 else:
661 hg.clean(repo, node, show_stats=False)
661 hg.clean(repo, node, show_stats=False)
662 repo.dirstate.setbranch(branch)
662 repo.dirstate.setbranch(branch)
663 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
663 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
664
664
665
665
666 def commitfunc(ui, repo, message, match, opts):
666 def commitfunc(ui, repo, message, match, opts):
667 editform = 'backout'
667 editform = 'backout'
668 e = cmdutil.getcommiteditor(editform=editform, **opts)
668 e = cmdutil.getcommiteditor(editform=editform, **opts)
669 if not message:
669 if not message:
670 # we don't translate commit messages
670 # we don't translate commit messages
671 message = "Backed out changeset %s" % short(node)
671 message = "Backed out changeset %s" % short(node)
672 e = cmdutil.getcommiteditor(edit=True, editform=editform)
672 e = cmdutil.getcommiteditor(edit=True, editform=editform)
673 return repo.commit(message, opts.get('user'), opts.get('date'),
673 return repo.commit(message, opts.get('user'), opts.get('date'),
674 match, editor=e)
674 match, editor=e)
675 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
675 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
676 if not newnode:
676 if not newnode:
677 ui.status(_("nothing changed\n"))
677 ui.status(_("nothing changed\n"))
678 return 1
678 return 1
679 cmdutil.commitstatus(repo, newnode, branch, bheads)
679 cmdutil.commitstatus(repo, newnode, branch, bheads)
680
680
681 def nice(node):
681 def nice(node):
682 return '%d:%s' % (repo.changelog.rev(node), short(node))
682 return '%d:%s' % (repo.changelog.rev(node), short(node))
683 ui.status(_('changeset %s backs out changeset %s\n') %
683 ui.status(_('changeset %s backs out changeset %s\n') %
684 (nice(repo.changelog.tip()), nice(node)))
684 (nice(repo.changelog.tip()), nice(node)))
685 if opts.get('merge') and op1 != node:
685 if opts.get('merge') and op1 != node:
686 hg.clean(repo, op1, show_stats=False)
686 hg.clean(repo, op1, show_stats=False)
687 ui.status(_('merging with changeset %s\n')
687 ui.status(_('merging with changeset %s\n')
688 % nice(repo.changelog.tip()))
688 % nice(repo.changelog.tip()))
689 try:
689 try:
690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
690 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
691 'backout')
691 'backout')
692 return hg.merge(repo, hex(repo.changelog.tip()))
692 return hg.merge(repo, hex(repo.changelog.tip()))
693 finally:
693 finally:
694 ui.setconfig('ui', 'forcemerge', '', '')
694 ui.setconfig('ui', 'forcemerge', '', '')
695 finally:
695 finally:
696 # TODO: get rid of this meaningless try/finally enclosing.
696 # TODO: get rid of this meaningless try/finally enclosing.
697 # this is kept only to reduce changes in a patch.
697 # this is kept only to reduce changes in a patch.
698 pass
698 pass
699 return 0
699 return 0
700
700
701 @command('bisect',
701 @command('bisect',
702 [('r', 'reset', False, _('reset bisect state')),
702 [('r', 'reset', False, _('reset bisect state')),
703 ('g', 'good', False, _('mark changeset good')),
703 ('g', 'good', False, _('mark changeset good')),
704 ('b', 'bad', False, _('mark changeset bad')),
704 ('b', 'bad', False, _('mark changeset bad')),
705 ('s', 'skip', False, _('skip testing changeset')),
705 ('s', 'skip', False, _('skip testing changeset')),
706 ('e', 'extend', False, _('extend the bisect range')),
706 ('e', 'extend', False, _('extend the bisect range')),
707 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
707 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
708 ('U', 'noupdate', False, _('do not update to target'))],
708 ('U', 'noupdate', False, _('do not update to target'))],
709 _("[-gbsr] [-U] [-c CMD] [REV]"))
709 _("[-gbsr] [-U] [-c CMD] [REV]"))
710 def bisect(ui, repo, rev=None, extra=None, command=None,
710 def bisect(ui, repo, rev=None, extra=None, command=None,
711 reset=None, good=None, bad=None, skip=None, extend=None,
711 reset=None, good=None, bad=None, skip=None, extend=None,
712 noupdate=None):
712 noupdate=None):
713 """subdivision search of changesets
713 """subdivision search of changesets
714
714
715 This command helps to find changesets which introduce problems. To
715 This command helps to find changesets which introduce problems. To
716 use, mark the earliest changeset you know exhibits the problem as
716 use, mark the earliest changeset you know exhibits the problem as
717 bad, then mark the latest changeset which is free from the problem
717 bad, then mark the latest changeset which is free from the problem
718 as good. Bisect will update your working directory to a revision
718 as good. Bisect will update your working directory to a revision
719 for testing (unless the -U/--noupdate option is specified). Once
719 for testing (unless the -U/--noupdate option is specified). Once
720 you have performed tests, mark the working directory as good or
720 you have performed tests, mark the working directory as good or
721 bad, and bisect will either update to another candidate changeset
721 bad, and bisect will either update to another candidate changeset
722 or announce that it has found the bad revision.
722 or announce that it has found the bad revision.
723
723
724 As a shortcut, you can also use the revision argument to mark a
724 As a shortcut, you can also use the revision argument to mark a
725 revision as good or bad without checking it out first.
725 revision as good or bad without checking it out first.
726
726
727 If you supply a command, it will be used for automatic bisection.
727 If you supply a command, it will be used for automatic bisection.
728 The environment variable HG_NODE will contain the ID of the
728 The environment variable HG_NODE will contain the ID of the
729 changeset being tested. The exit status of the command will be
729 changeset being tested. The exit status of the command will be
730 used to mark revisions as good or bad: status 0 means good, 125
730 used to mark revisions as good or bad: status 0 means good, 125
731 means to skip the revision, 127 (command not found) will abort the
731 means to skip the revision, 127 (command not found) will abort the
732 bisection, and any other non-zero exit status means the revision
732 bisection, and any other non-zero exit status means the revision
733 is bad.
733 is bad.
734
734
735 .. container:: verbose
735 .. container:: verbose
736
736
737 Some examples:
737 Some examples:
738
738
739 - start a bisection with known bad revision 34, and good revision 12::
739 - start a bisection with known bad revision 34, and good revision 12::
740
740
741 hg bisect --bad 34
741 hg bisect --bad 34
742 hg bisect --good 12
742 hg bisect --good 12
743
743
744 - advance the current bisection by marking current revision as good or
744 - advance the current bisection by marking current revision as good or
745 bad::
745 bad::
746
746
747 hg bisect --good
747 hg bisect --good
748 hg bisect --bad
748 hg bisect --bad
749
749
750 - mark the current revision, or a known revision, to be skipped (e.g. if
750 - mark the current revision, or a known revision, to be skipped (e.g. if
751 that revision is not usable because of another issue)::
751 that revision is not usable because of another issue)::
752
752
753 hg bisect --skip
753 hg bisect --skip
754 hg bisect --skip 23
754 hg bisect --skip 23
755
755
756 - skip all revisions that do not touch directories ``foo`` or ``bar``::
756 - skip all revisions that do not touch directories ``foo`` or ``bar``::
757
757
758 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
758 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
759
759
760 - forget the current bisection::
760 - forget the current bisection::
761
761
762 hg bisect --reset
762 hg bisect --reset
763
763
764 - use 'make && make tests' to automatically find the first broken
764 - use 'make && make tests' to automatically find the first broken
765 revision::
765 revision::
766
766
767 hg bisect --reset
767 hg bisect --reset
768 hg bisect --bad 34
768 hg bisect --bad 34
769 hg bisect --good 12
769 hg bisect --good 12
770 hg bisect --command "make && make tests"
770 hg bisect --command "make && make tests"
771
771
772 - see all changesets whose states are already known in the current
772 - see all changesets whose states are already known in the current
773 bisection::
773 bisection::
774
774
775 hg log -r "bisect(pruned)"
775 hg log -r "bisect(pruned)"
776
776
777 - see the changeset currently being bisected (especially useful
777 - see the changeset currently being bisected (especially useful
778 if running with -U/--noupdate)::
778 if running with -U/--noupdate)::
779
779
780 hg log -r "bisect(current)"
780 hg log -r "bisect(current)"
781
781
782 - see all changesets that took part in the current bisection::
782 - see all changesets that took part in the current bisection::
783
783
784 hg log -r "bisect(range)"
784 hg log -r "bisect(range)"
785
785
786 - you can even get a nice graph::
786 - you can even get a nice graph::
787
787
788 hg log --graph -r "bisect(range)"
788 hg log --graph -r "bisect(range)"
789
789
790 See :hg:`help revsets` for more about the `bisect()` keyword.
790 See :hg:`help revsets` for more about the `bisect()` keyword.
791
791
792 Returns 0 on success.
792 Returns 0 on success.
793 """
793 """
794 def extendbisectrange(nodes, good):
794 def extendbisectrange(nodes, good):
795 # bisect is incomplete when it ends on a merge node and
795 # bisect is incomplete when it ends on a merge node and
796 # one of the parent was not checked.
796 # one of the parent was not checked.
797 parents = repo[nodes[0]].parents()
797 parents = repo[nodes[0]].parents()
798 if len(parents) > 1:
798 if len(parents) > 1:
799 if good:
799 if good:
800 side = state['bad']
800 side = state['bad']
801 else:
801 else:
802 side = state['good']
802 side = state['good']
803 num = len(set(i.node() for i in parents) & set(side))
803 num = len(set(i.node() for i in parents) & set(side))
804 if num == 1:
804 if num == 1:
805 return parents[0].ancestor(parents[1])
805 return parents[0].ancestor(parents[1])
806 return None
806 return None
807
807
808 def print_result(nodes, good):
808 def print_result(nodes, good):
809 displayer = cmdutil.show_changeset(ui, repo, {})
809 displayer = cmdutil.show_changeset(ui, repo, {})
810 if len(nodes) == 1:
810 if len(nodes) == 1:
811 # narrowed it down to a single revision
811 # narrowed it down to a single revision
812 if good:
812 if good:
813 ui.write(_("The first good revision is:\n"))
813 ui.write(_("The first good revision is:\n"))
814 else:
814 else:
815 ui.write(_("The first bad revision is:\n"))
815 ui.write(_("The first bad revision is:\n"))
816 displayer.show(repo[nodes[0]])
816 displayer.show(repo[nodes[0]])
817 extendnode = extendbisectrange(nodes, good)
817 extendnode = extendbisectrange(nodes, good)
818 if extendnode is not None:
818 if extendnode is not None:
819 ui.write(_('Not all ancestors of this changeset have been'
819 ui.write(_('Not all ancestors of this changeset have been'
820 ' checked.\nUse bisect --extend to continue the '
820 ' checked.\nUse bisect --extend to continue the '
821 'bisection from\nthe common ancestor, %s.\n')
821 'bisection from\nthe common ancestor, %s.\n')
822 % extendnode)
822 % extendnode)
823 else:
823 else:
824 # multiple possible revisions
824 # multiple possible revisions
825 if good:
825 if good:
826 ui.write(_("Due to skipped revisions, the first "
826 ui.write(_("Due to skipped revisions, the first "
827 "good revision could be any of:\n"))
827 "good revision could be any of:\n"))
828 else:
828 else:
829 ui.write(_("Due to skipped revisions, the first "
829 ui.write(_("Due to skipped revisions, the first "
830 "bad revision could be any of:\n"))
830 "bad revision could be any of:\n"))
831 for n in nodes:
831 for n in nodes:
832 displayer.show(repo[n])
832 displayer.show(repo[n])
833 displayer.close()
833 displayer.close()
834
834
835 def check_state(state, interactive=True):
835 def check_state(state, interactive=True):
836 if not state['good'] or not state['bad']:
836 if not state['good'] or not state['bad']:
837 if (good or bad or skip or reset) and interactive:
837 if (good or bad or skip or reset) and interactive:
838 return
838 return
839 if not state['good']:
839 if not state['good']:
840 raise error.Abort(_('cannot bisect (no known good revisions)'))
840 raise error.Abort(_('cannot bisect (no known good revisions)'))
841 else:
841 else:
842 raise error.Abort(_('cannot bisect (no known bad revisions)'))
842 raise error.Abort(_('cannot bisect (no known bad revisions)'))
843 return True
843 return True
844
844
845 # backward compatibility
845 # backward compatibility
846 if rev in "good bad reset init".split():
846 if rev in "good bad reset init".split():
847 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
847 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
848 cmd, rev, extra = rev, extra, None
848 cmd, rev, extra = rev, extra, None
849 if cmd == "good":
849 if cmd == "good":
850 good = True
850 good = True
851 elif cmd == "bad":
851 elif cmd == "bad":
852 bad = True
852 bad = True
853 else:
853 else:
854 reset = True
854 reset = True
855 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
855 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
856 raise error.Abort(_('incompatible arguments'))
856 raise error.Abort(_('incompatible arguments'))
857
857
858 cmdutil.checkunfinished(repo)
858 cmdutil.checkunfinished(repo)
859
859
860 if reset:
860 if reset:
861 p = repo.join("bisect.state")
861 p = repo.join("bisect.state")
862 if os.path.exists(p):
862 if os.path.exists(p):
863 os.unlink(p)
863 os.unlink(p)
864 return
864 return
865
865
866 state = hbisect.load_state(repo)
866 state = hbisect.load_state(repo)
867
867
868 if command:
868 if command:
869 changesets = 1
869 changesets = 1
870 if noupdate:
870 if noupdate:
871 try:
871 try:
872 node = state['current'][0]
872 node = state['current'][0]
873 except LookupError:
873 except LookupError:
874 raise error.Abort(_('current bisect revision is unknown - '
874 raise error.Abort(_('current bisect revision is unknown - '
875 'start a new bisect to fix'))
875 'start a new bisect to fix'))
876 else:
876 else:
877 node, p2 = repo.dirstate.parents()
877 node, p2 = repo.dirstate.parents()
878 if p2 != nullid:
878 if p2 != nullid:
879 raise error.Abort(_('current bisect revision is a merge'))
879 raise error.Abort(_('current bisect revision is a merge'))
880 try:
880 try:
881 while changesets:
881 while changesets:
882 # update state
882 # update state
883 state['current'] = [node]
883 state['current'] = [node]
884 hbisect.save_state(repo, state)
884 hbisect.save_state(repo, state)
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
886 if status == 125:
886 if status == 125:
887 transition = "skip"
887 transition = "skip"
888 elif status == 0:
888 elif status == 0:
889 transition = "good"
889 transition = "good"
890 # status < 0 means process was killed
890 # status < 0 means process was killed
891 elif status == 127:
891 elif status == 127:
892 raise error.Abort(_("failed to execute %s") % command)
892 raise error.Abort(_("failed to execute %s") % command)
893 elif status < 0:
893 elif status < 0:
894 raise error.Abort(_("%s killed") % command)
894 raise error.Abort(_("%s killed") % command)
895 else:
895 else:
896 transition = "bad"
896 transition = "bad"
897 ctx = scmutil.revsingle(repo, rev, node)
897 ctx = scmutil.revsingle(repo, rev, node)
898 rev = None # clear for future iterations
898 rev = None # clear for future iterations
899 state[transition].append(ctx.node())
899 state[transition].append(ctx.node())
900 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
900 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
901 check_state(state, interactive=False)
901 check_state(state, interactive=False)
902 # bisect
902 # bisect
903 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
903 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
904 # update to next check
904 # update to next check
905 node = nodes[0]
905 node = nodes[0]
906 if not noupdate:
906 if not noupdate:
907 cmdutil.bailifchanged(repo)
907 cmdutil.bailifchanged(repo)
908 hg.clean(repo, node, show_stats=False)
908 hg.clean(repo, node, show_stats=False)
909 finally:
909 finally:
910 state['current'] = [node]
910 state['current'] = [node]
911 hbisect.save_state(repo, state)
911 hbisect.save_state(repo, state)
912 print_result(nodes, bgood)
912 print_result(nodes, bgood)
913 return
913 return
914
914
915 # update state
915 # update state
916
916
917 if rev:
917 if rev:
918 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
918 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
919 else:
919 else:
920 nodes = [repo.lookup('.')]
920 nodes = [repo.lookup('.')]
921
921
922 if good or bad or skip:
922 if good or bad or skip:
923 if good:
923 if good:
924 state['good'] += nodes
924 state['good'] += nodes
925 elif bad:
925 elif bad:
926 state['bad'] += nodes
926 state['bad'] += nodes
927 elif skip:
927 elif skip:
928 state['skip'] += nodes
928 state['skip'] += nodes
929 hbisect.save_state(repo, state)
929 hbisect.save_state(repo, state)
930
930
931 if not check_state(state):
931 if not check_state(state):
932 return
932 return
933
933
934 # actually bisect
934 # actually bisect
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
935 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
936 if extend:
936 if extend:
937 if not changesets:
937 if not changesets:
938 extendnode = extendbisectrange(nodes, good)
938 extendnode = extendbisectrange(nodes, good)
939 if extendnode is not None:
939 if extendnode is not None:
940 ui.write(_("Extending search to changeset %d:%s\n")
940 ui.write(_("Extending search to changeset %d:%s\n")
941 % (extendnode.rev(), extendnode))
941 % (extendnode.rev(), extendnode))
942 state['current'] = [extendnode.node()]
942 state['current'] = [extendnode.node()]
943 hbisect.save_state(repo, state)
943 hbisect.save_state(repo, state)
944 if noupdate:
944 if noupdate:
945 return
945 return
946 cmdutil.bailifchanged(repo)
946 cmdutil.bailifchanged(repo)
947 return hg.clean(repo, extendnode.node())
947 return hg.clean(repo, extendnode.node())
948 raise error.Abort(_("nothing to extend"))
948 raise error.Abort(_("nothing to extend"))
949
949
950 if changesets == 0:
950 if changesets == 0:
951 print_result(nodes, good)
951 print_result(nodes, good)
952 else:
952 else:
953 assert len(nodes) == 1 # only a single node can be tested next
953 assert len(nodes) == 1 # only a single node can be tested next
954 node = nodes[0]
954 node = nodes[0]
955 # compute the approximate number of remaining tests
955 # compute the approximate number of remaining tests
956 tests, size = 0, 2
956 tests, size = 0, 2
957 while size <= changesets:
957 while size <= changesets:
958 tests, size = tests + 1, size * 2
958 tests, size = tests + 1, size * 2
959 rev = repo.changelog.rev(node)
959 rev = repo.changelog.rev(node)
960 ui.write(_("Testing changeset %d:%s "
960 ui.write(_("Testing changeset %d:%s "
961 "(%d changesets remaining, ~%d tests)\n")
961 "(%d changesets remaining, ~%d tests)\n")
962 % (rev, short(node), changesets, tests))
962 % (rev, short(node), changesets, tests))
963 state['current'] = [node]
963 state['current'] = [node]
964 hbisect.save_state(repo, state)
964 hbisect.save_state(repo, state)
965 if not noupdate:
965 if not noupdate:
966 cmdutil.bailifchanged(repo)
966 cmdutil.bailifchanged(repo)
967 return hg.clean(repo, node)
967 return hg.clean(repo, node)
968
968
969 @command('bookmarks|bookmark',
969 @command('bookmarks|bookmark',
970 [('f', 'force', False, _('force')),
970 [('f', 'force', False, _('force')),
971 ('r', 'rev', '', _('revision'), _('REV')),
971 ('r', 'rev', '', _('revision'), _('REV')),
972 ('d', 'delete', False, _('delete a given bookmark')),
972 ('d', 'delete', False, _('delete a given bookmark')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
973 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
974 ('i', 'inactive', False, _('mark a bookmark inactive')),
975 ] + formatteropts,
975 ] + formatteropts,
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
976 _('hg bookmarks [OPTIONS]... [NAME]...'))
977 def bookmark(ui, repo, *names, **opts):
977 def bookmark(ui, repo, *names, **opts):
978 '''create a new bookmark or list existing bookmarks
978 '''create a new bookmark or list existing bookmarks
979
979
980 Bookmarks are labels on changesets to help track lines of development.
980 Bookmarks are labels on changesets to help track lines of development.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
981 Bookmarks are unversioned and can be moved, renamed and deleted.
982 Deleting or moving a bookmark has no effect on the associated changesets.
982 Deleting or moving a bookmark has no effect on the associated changesets.
983
983
984 Creating or updating to a bookmark causes it to be marked as 'active'.
984 Creating or updating to a bookmark causes it to be marked as 'active'.
985 The active bookmark is indicated with a '*'.
985 The active bookmark is indicated with a '*'.
986 When a commit is made, the active bookmark will advance to the new commit.
986 When a commit is made, the active bookmark will advance to the new commit.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
987 A plain :hg:`update` will also advance an active bookmark, if possible.
988 Updating away from a bookmark will cause it to be deactivated.
988 Updating away from a bookmark will cause it to be deactivated.
989
989
990 Bookmarks can be pushed and pulled between repositories (see
990 Bookmarks can be pushed and pulled between repositories (see
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
991 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
992 diverged, a new 'divergent bookmark' of the form 'name@path' will
993 be created. Using :hg:`merge` will resolve the divergence.
993 be created. Using :hg:`merge` will resolve the divergence.
994
994
995 A bookmark named '@' has the special property that :hg:`clone` will
995 A bookmark named '@' has the special property that :hg:`clone` will
996 check it out by default if it exists.
996 check it out by default if it exists.
997
997
998 .. container:: verbose
998 .. container:: verbose
999
999
1000 Examples:
1000 Examples:
1001
1001
1002 - create an active bookmark for a new line of development::
1002 - create an active bookmark for a new line of development::
1003
1003
1004 hg book new-feature
1004 hg book new-feature
1005
1005
1006 - create an inactive bookmark as a place marker::
1006 - create an inactive bookmark as a place marker::
1007
1007
1008 hg book -i reviewed
1008 hg book -i reviewed
1009
1009
1010 - create an inactive bookmark on another changeset::
1010 - create an inactive bookmark on another changeset::
1011
1011
1012 hg book -r .^ tested
1012 hg book -r .^ tested
1013
1013
1014 - rename bookmark turkey to dinner::
1014 - rename bookmark turkey to dinner::
1015
1015
1016 hg book -m turkey dinner
1016 hg book -m turkey dinner
1017
1017
1018 - move the '@' bookmark from another branch::
1018 - move the '@' bookmark from another branch::
1019
1019
1020 hg book -f @
1020 hg book -f @
1021 '''
1021 '''
1022 force = opts.get('force')
1022 force = opts.get('force')
1023 rev = opts.get('rev')
1023 rev = opts.get('rev')
1024 delete = opts.get('delete')
1024 delete = opts.get('delete')
1025 rename = opts.get('rename')
1025 rename = opts.get('rename')
1026 inactive = opts.get('inactive')
1026 inactive = opts.get('inactive')
1027
1027
1028 def checkformat(mark):
1028 def checkformat(mark):
1029 mark = mark.strip()
1029 mark = mark.strip()
1030 if not mark:
1030 if not mark:
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1031 raise error.Abort(_("bookmark names cannot consist entirely of "
1032 "whitespace"))
1032 "whitespace"))
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1033 scmutil.checknewlabel(repo, mark, 'bookmark')
1034 return mark
1034 return mark
1035
1035
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1036 def checkconflict(repo, mark, cur, force=False, target=None):
1037 if mark in marks and not force:
1037 if mark in marks and not force:
1038 if target:
1038 if target:
1039 if marks[mark] == target and target == cur:
1039 if marks[mark] == target and target == cur:
1040 # re-activating a bookmark
1040 # re-activating a bookmark
1041 return
1041 return
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1042 anc = repo.changelog.ancestors([repo[target].rev()])
1043 bmctx = repo[marks[mark]]
1043 bmctx = repo[marks[mark]]
1044 divs = [repo[b].node() for b in marks
1044 divs = [repo[b].node() for b in marks
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1045 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1046
1046
1047 # allow resolving a single divergent bookmark even if moving
1047 # allow resolving a single divergent bookmark even if moving
1048 # the bookmark across branches when a revision is specified
1048 # the bookmark across branches when a revision is specified
1049 # that contains a divergent bookmark
1049 # that contains a divergent bookmark
1050 if bmctx.rev() not in anc and target in divs:
1050 if bmctx.rev() not in anc and target in divs:
1051 bookmarks.deletedivergent(repo, [target], mark)
1051 bookmarks.deletedivergent(repo, [target], mark)
1052 return
1052 return
1053
1053
1054 deletefrom = [b for b in divs
1054 deletefrom = [b for b in divs
1055 if repo[b].rev() in anc or b == target]
1055 if repo[b].rev() in anc or b == target]
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1056 bookmarks.deletedivergent(repo, deletefrom, mark)
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1057 if bookmarks.validdest(repo, bmctx, repo[target]):
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1058 ui.status(_("moving bookmark '%s' forward from %s\n") %
1059 (mark, short(bmctx.node())))
1059 (mark, short(bmctx.node())))
1060 return
1060 return
1061 raise error.Abort(_("bookmark '%s' already exists "
1061 raise error.Abort(_("bookmark '%s' already exists "
1062 "(use -f to force)") % mark)
1062 "(use -f to force)") % mark)
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1063 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1064 and not force):
1064 and not force):
1065 raise error.Abort(
1065 raise error.Abort(
1066 _("a bookmark cannot have the name of an existing branch"))
1066 _("a bookmark cannot have the name of an existing branch"))
1067
1067
1068 if delete and rename:
1068 if delete and rename:
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1069 raise error.Abort(_("--delete and --rename are incompatible"))
1070 if delete and rev:
1070 if delete and rev:
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1071 raise error.Abort(_("--rev is incompatible with --delete"))
1072 if rename and rev:
1072 if rename and rev:
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1073 raise error.Abort(_("--rev is incompatible with --rename"))
1074 if not names and (delete or rev):
1074 if not names and (delete or rev):
1075 raise error.Abort(_("bookmark name required"))
1075 raise error.Abort(_("bookmark name required"))
1076
1076
1077 if delete or rename or names or inactive:
1077 if delete or rename or names or inactive:
1078 wlock = lock = tr = None
1078 wlock = lock = tr = None
1079 try:
1079 try:
1080 wlock = repo.wlock()
1080 wlock = repo.wlock()
1081 lock = repo.lock()
1081 lock = repo.lock()
1082 cur = repo.changectx('.').node()
1082 cur = repo.changectx('.').node()
1083 marks = repo._bookmarks
1083 marks = repo._bookmarks
1084 if delete:
1084 if delete:
1085 tr = repo.transaction('bookmark')
1085 tr = repo.transaction('bookmark')
1086 for mark in names:
1086 for mark in names:
1087 if mark not in marks:
1087 if mark not in marks:
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1088 raise error.Abort(_("bookmark '%s' does not exist") %
1089 mark)
1089 mark)
1090 if mark == repo._activebookmark:
1090 if mark == repo._activebookmark:
1091 bookmarks.deactivate(repo)
1091 bookmarks.deactivate(repo)
1092 del marks[mark]
1092 del marks[mark]
1093
1093
1094 elif rename:
1094 elif rename:
1095 tr = repo.transaction('bookmark')
1095 tr = repo.transaction('bookmark')
1096 if not names:
1096 if not names:
1097 raise error.Abort(_("new bookmark name required"))
1097 raise error.Abort(_("new bookmark name required"))
1098 elif len(names) > 1:
1098 elif len(names) > 1:
1099 raise error.Abort(_("only one new bookmark name allowed"))
1099 raise error.Abort(_("only one new bookmark name allowed"))
1100 mark = checkformat(names[0])
1100 mark = checkformat(names[0])
1101 if rename not in marks:
1101 if rename not in marks:
1102 raise error.Abort(_("bookmark '%s' does not exist")
1102 raise error.Abort(_("bookmark '%s' does not exist")
1103 % rename)
1103 % rename)
1104 checkconflict(repo, mark, cur, force)
1104 checkconflict(repo, mark, cur, force)
1105 marks[mark] = marks[rename]
1105 marks[mark] = marks[rename]
1106 if repo._activebookmark == rename and not inactive:
1106 if repo._activebookmark == rename and not inactive:
1107 bookmarks.activate(repo, mark)
1107 bookmarks.activate(repo, mark)
1108 del marks[rename]
1108 del marks[rename]
1109 elif names:
1109 elif names:
1110 tr = repo.transaction('bookmark')
1110 tr = repo.transaction('bookmark')
1111 newact = None
1111 newact = None
1112 for mark in names:
1112 for mark in names:
1113 mark = checkformat(mark)
1113 mark = checkformat(mark)
1114 if newact is None:
1114 if newact is None:
1115 newact = mark
1115 newact = mark
1116 if inactive and mark == repo._activebookmark:
1116 if inactive and mark == repo._activebookmark:
1117 bookmarks.deactivate(repo)
1117 bookmarks.deactivate(repo)
1118 return
1118 return
1119 tgt = cur
1119 tgt = cur
1120 if rev:
1120 if rev:
1121 tgt = scmutil.revsingle(repo, rev).node()
1121 tgt = scmutil.revsingle(repo, rev).node()
1122 checkconflict(repo, mark, cur, force, tgt)
1122 checkconflict(repo, mark, cur, force, tgt)
1123 marks[mark] = tgt
1123 marks[mark] = tgt
1124 if not inactive and cur == marks[newact] and not rev:
1124 if not inactive and cur == marks[newact] and not rev:
1125 bookmarks.activate(repo, newact)
1125 bookmarks.activate(repo, newact)
1126 elif cur != tgt and newact == repo._activebookmark:
1126 elif cur != tgt and newact == repo._activebookmark:
1127 bookmarks.deactivate(repo)
1127 bookmarks.deactivate(repo)
1128 elif inactive:
1128 elif inactive:
1129 if len(marks) == 0:
1129 if len(marks) == 0:
1130 ui.status(_("no bookmarks set\n"))
1130 ui.status(_("no bookmarks set\n"))
1131 elif not repo._activebookmark:
1131 elif not repo._activebookmark:
1132 ui.status(_("no active bookmark\n"))
1132 ui.status(_("no active bookmark\n"))
1133 else:
1133 else:
1134 bookmarks.deactivate(repo)
1134 bookmarks.deactivate(repo)
1135 if tr is not None:
1135 if tr is not None:
1136 marks.recordchange(tr)
1136 marks.recordchange(tr)
1137 tr.close()
1137 tr.close()
1138 finally:
1138 finally:
1139 lockmod.release(tr, lock, wlock)
1139 lockmod.release(tr, lock, wlock)
1140 else: # show bookmarks
1140 else: # show bookmarks
1141 fm = ui.formatter('bookmarks', opts)
1141 fm = ui.formatter('bookmarks', opts)
1142 hexfn = fm.hexfunc
1142 hexfn = fm.hexfunc
1143 marks = repo._bookmarks
1143 marks = repo._bookmarks
1144 if len(marks) == 0 and not fm:
1144 if len(marks) == 0 and not fm:
1145 ui.status(_("no bookmarks set\n"))
1145 ui.status(_("no bookmarks set\n"))
1146 for bmark, n in sorted(marks.iteritems()):
1146 for bmark, n in sorted(marks.iteritems()):
1147 active = repo._activebookmark
1147 active = repo._activebookmark
1148 if bmark == active:
1148 if bmark == active:
1149 prefix, label = '*', activebookmarklabel
1149 prefix, label = '*', activebookmarklabel
1150 else:
1150 else:
1151 prefix, label = ' ', ''
1151 prefix, label = ' ', ''
1152
1152
1153 fm.startitem()
1153 fm.startitem()
1154 if not ui.quiet:
1154 if not ui.quiet:
1155 fm.plain(' %s ' % prefix, label=label)
1155 fm.plain(' %s ' % prefix, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1156 fm.write('bookmark', '%s', bmark, label=label)
1157 pad = " " * (25 - encoding.colwidth(bmark))
1157 pad = " " * (25 - encoding.colwidth(bmark))
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1158 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1159 repo.changelog.rev(n), hexfn(n), label=label)
1159 repo.changelog.rev(n), hexfn(n), label=label)
1160 fm.data(active=(bmark == active))
1160 fm.data(active=(bmark == active))
1161 fm.plain('\n')
1161 fm.plain('\n')
1162 fm.end()
1162 fm.end()
1163
1163
1164 @command('branch',
1164 @command('branch',
1165 [('f', 'force', None,
1165 [('f', 'force', None,
1166 _('set branch name even if it shadows an existing branch')),
1166 _('set branch name even if it shadows an existing branch')),
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1167 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1168 _('[-fC] [NAME]'))
1168 _('[-fC] [NAME]'))
1169 def branch(ui, repo, label=None, **opts):
1169 def branch(ui, repo, label=None, **opts):
1170 """set or show the current branch name
1170 """set or show the current branch name
1171
1171
1172 .. note::
1172 .. note::
1173
1173
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1174 Branch names are permanent and global. Use :hg:`bookmark` to create a
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1175 light-weight bookmark instead. See :hg:`help glossary` for more
1176 information about named branches and bookmarks.
1176 information about named branches and bookmarks.
1177
1177
1178 With no argument, show the current branch name. With one argument,
1178 With no argument, show the current branch name. With one argument,
1179 set the working directory branch name (the branch will not exist
1179 set the working directory branch name (the branch will not exist
1180 in the repository until the next commit). Standard practice
1180 in the repository until the next commit). Standard practice
1181 recommends that primary development take place on the 'default'
1181 recommends that primary development take place on the 'default'
1182 branch.
1182 branch.
1183
1183
1184 Unless -f/--force is specified, branch will not let you set a
1184 Unless -f/--force is specified, branch will not let you set a
1185 branch name that already exists.
1185 branch name that already exists.
1186
1186
1187 Use -C/--clean to reset the working directory branch to that of
1187 Use -C/--clean to reset the working directory branch to that of
1188 the parent of the working directory, negating a previous branch
1188 the parent of the working directory, negating a previous branch
1189 change.
1189 change.
1190
1190
1191 Use the command :hg:`update` to switch to an existing branch. Use
1191 Use the command :hg:`update` to switch to an existing branch. Use
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1192 :hg:`commit --close-branch` to mark this branch head as closed.
1193 When all heads of a branch are closed, the branch will be
1193 When all heads of a branch are closed, the branch will be
1194 considered closed.
1194 considered closed.
1195
1195
1196 Returns 0 on success.
1196 Returns 0 on success.
1197 """
1197 """
1198 if label:
1198 if label:
1199 label = label.strip()
1199 label = label.strip()
1200
1200
1201 if not opts.get('clean') and not label:
1201 if not opts.get('clean') and not label:
1202 ui.write("%s\n" % repo.dirstate.branch())
1202 ui.write("%s\n" % repo.dirstate.branch())
1203 return
1203 return
1204
1204
1205 wlock = repo.wlock()
1205 wlock = repo.wlock()
1206 try:
1206 try:
1207 if opts.get('clean'):
1207 if opts.get('clean'):
1208 label = repo[None].p1().branch()
1208 label = repo[None].p1().branch()
1209 repo.dirstate.setbranch(label)
1209 repo.dirstate.setbranch(label)
1210 ui.status(_('reset working directory to branch %s\n') % label)
1210 ui.status(_('reset working directory to branch %s\n') % label)
1211 elif label:
1211 elif label:
1212 if not opts.get('force') and label in repo.branchmap():
1212 if not opts.get('force') and label in repo.branchmap():
1213 if label not in [p.branch() for p in repo[None].parents()]:
1213 if label not in [p.branch() for p in repo[None].parents()]:
1214 raise error.Abort(_('a branch of the same name already'
1214 raise error.Abort(_('a branch of the same name already'
1215 ' exists'),
1215 ' exists'),
1216 # i18n: "it" refers to an existing branch
1216 # i18n: "it" refers to an existing branch
1217 hint=_("use 'hg update' to switch to it"))
1217 hint=_("use 'hg update' to switch to it"))
1218 scmutil.checknewlabel(repo, label, 'branch')
1218 scmutil.checknewlabel(repo, label, 'branch')
1219 repo.dirstate.setbranch(label)
1219 repo.dirstate.setbranch(label)
1220 ui.status(_('marked working directory as branch %s\n') % label)
1220 ui.status(_('marked working directory as branch %s\n') % label)
1221
1221
1222 # find any open named branches aside from default
1222 # find any open named branches aside from default
1223 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1223 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1224 if n != "default" and not c]
1224 if n != "default" and not c]
1225 if not others:
1225 if not others:
1226 ui.status(_('(branches are permanent and global, '
1226 ui.status(_('(branches are permanent and global, '
1227 'did you want a bookmark?)\n'))
1227 'did you want a bookmark?)\n'))
1228 finally:
1228 finally:
1229 wlock.release()
1229 wlock.release()
1230
1230
1231 @command('branches',
1231 @command('branches',
1232 [('a', 'active', False,
1232 [('a', 'active', False,
1233 _('show only branches that have unmerged heads (DEPRECATED)')),
1233 _('show only branches that have unmerged heads (DEPRECATED)')),
1234 ('c', 'closed', False, _('show normal and closed branches')),
1234 ('c', 'closed', False, _('show normal and closed branches')),
1235 ] + formatteropts,
1235 ] + formatteropts,
1236 _('[-ac]'))
1236 _('[-ac]'))
1237 def branches(ui, repo, active=False, closed=False, **opts):
1237 def branches(ui, repo, active=False, closed=False, **opts):
1238 """list repository named branches
1238 """list repository named branches
1239
1239
1240 List the repository's named branches, indicating which ones are
1240 List the repository's named branches, indicating which ones are
1241 inactive. If -c/--closed is specified, also list branches which have
1241 inactive. If -c/--closed is specified, also list branches which have
1242 been marked closed (see :hg:`commit --close-branch`).
1242 been marked closed (see :hg:`commit --close-branch`).
1243
1243
1244 Use the command :hg:`update` to switch to an existing branch.
1244 Use the command :hg:`update` to switch to an existing branch.
1245
1245
1246 Returns 0.
1246 Returns 0.
1247 """
1247 """
1248
1248
1249 fm = ui.formatter('branches', opts)
1249 fm = ui.formatter('branches', opts)
1250 hexfunc = fm.hexfunc
1250 hexfunc = fm.hexfunc
1251
1251
1252 allheads = set(repo.heads())
1252 allheads = set(repo.heads())
1253 branches = []
1253 branches = []
1254 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1254 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1255 isactive = not isclosed and bool(set(heads) & allheads)
1255 isactive = not isclosed and bool(set(heads) & allheads)
1256 branches.append((tag, repo[tip], isactive, not isclosed))
1256 branches.append((tag, repo[tip], isactive, not isclosed))
1257 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1257 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1258 reverse=True)
1258 reverse=True)
1259
1259
1260 for tag, ctx, isactive, isopen in branches:
1260 for tag, ctx, isactive, isopen in branches:
1261 if active and not isactive:
1261 if active and not isactive:
1262 continue
1262 continue
1263 if isactive:
1263 if isactive:
1264 label = 'branches.active'
1264 label = 'branches.active'
1265 notice = ''
1265 notice = ''
1266 elif not isopen:
1266 elif not isopen:
1267 if not closed:
1267 if not closed:
1268 continue
1268 continue
1269 label = 'branches.closed'
1269 label = 'branches.closed'
1270 notice = _(' (closed)')
1270 notice = _(' (closed)')
1271 else:
1271 else:
1272 label = 'branches.inactive'
1272 label = 'branches.inactive'
1273 notice = _(' (inactive)')
1273 notice = _(' (inactive)')
1274 current = (tag == repo.dirstate.branch())
1274 current = (tag == repo.dirstate.branch())
1275 if current:
1275 if current:
1276 label = 'branches.current'
1276 label = 'branches.current'
1277
1277
1278 fm.startitem()
1278 fm.startitem()
1279 fm.write('branch', '%s', tag, label=label)
1279 fm.write('branch', '%s', tag, label=label)
1280 rev = ctx.rev()
1280 rev = ctx.rev()
1281 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1281 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1282 fmt = ' ' * padsize + ' %d:%s'
1282 fmt = ' ' * padsize + ' %d:%s'
1283 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1283 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1284 label='log.changeset changeset.%s' % ctx.phasestr())
1284 label='log.changeset changeset.%s' % ctx.phasestr())
1285 fm.data(active=isactive, closed=not isopen, current=current)
1285 fm.data(active=isactive, closed=not isopen, current=current)
1286 if not ui.quiet:
1286 if not ui.quiet:
1287 fm.plain(notice)
1287 fm.plain(notice)
1288 fm.plain('\n')
1288 fm.plain('\n')
1289 fm.end()
1289 fm.end()
1290
1290
1291 @command('bundle',
1291 @command('bundle',
1292 [('f', 'force', None, _('run even when the destination is unrelated')),
1292 [('f', 'force', None, _('run even when the destination is unrelated')),
1293 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1293 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1294 _('REV')),
1294 _('REV')),
1295 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1295 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1296 _('BRANCH')),
1296 _('BRANCH')),
1297 ('', 'base', [],
1297 ('', 'base', [],
1298 _('a base changeset assumed to be available at the destination'),
1298 _('a base changeset assumed to be available at the destination'),
1299 _('REV')),
1299 _('REV')),
1300 ('a', 'all', None, _('bundle all changesets in the repository')),
1300 ('a', 'all', None, _('bundle all changesets in the repository')),
1301 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1301 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1302 ] + remoteopts,
1302 ] + remoteopts,
1303 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1303 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1304 def bundle(ui, repo, fname, dest=None, **opts):
1304 def bundle(ui, repo, fname, dest=None, **opts):
1305 """create a changegroup file
1305 """create a changegroup file
1306
1306
1307 Generate a changegroup file collecting changesets to be added
1307 Generate a changegroup file collecting changesets to be added
1308 to a repository.
1308 to a repository.
1309
1309
1310 To create a bundle containing all changesets, use -a/--all
1310 To create a bundle containing all changesets, use -a/--all
1311 (or --base null). Otherwise, hg assumes the destination will have
1311 (or --base null). Otherwise, hg assumes the destination will have
1312 all the nodes you specify with --base parameters. Otherwise, hg
1312 all the nodes you specify with --base parameters. Otherwise, hg
1313 will assume the repository has all the nodes in destination, or
1313 will assume the repository has all the nodes in destination, or
1314 default-push/default if no destination is specified.
1314 default-push/default if no destination is specified.
1315
1315
1316 You can change bundle format with the -t/--type option. You can
1316 You can change bundle format with the -t/--type option. You can
1317 specify a compression, a bundle version or both using a dash
1317 specify a compression, a bundle version or both using a dash
1318 (comp-version). The available compression methods are: none, bzip2,
1318 (comp-version). The available compression methods are: none, bzip2,
1319 and gzip (by default, bundles are compressed using bzip2). The
1319 and gzip (by default, bundles are compressed using bzip2). The
1320 available formats are: v1, v2 (default to most suitable).
1320 available formats are: v1, v2 (default to most suitable).
1321
1321
1322 The bundle file can then be transferred using conventional means
1322 The bundle file can then be transferred using conventional means
1323 and applied to another repository with the unbundle or pull
1323 and applied to another repository with the unbundle or pull
1324 command. This is useful when direct push and pull are not
1324 command. This is useful when direct push and pull are not
1325 available or when exporting an entire repository is undesirable.
1325 available or when exporting an entire repository is undesirable.
1326
1326
1327 Applying bundles preserves all changeset contents including
1327 Applying bundles preserves all changeset contents including
1328 permissions, copy/rename information, and revision history.
1328 permissions, copy/rename information, and revision history.
1329
1329
1330 Returns 0 on success, 1 if no changes found.
1330 Returns 0 on success, 1 if no changes found.
1331 """
1331 """
1332 revs = None
1332 revs = None
1333 if 'rev' in opts:
1333 if 'rev' in opts:
1334 revs = scmutil.revrange(repo, opts['rev'])
1334 revs = scmutil.revrange(repo, opts['rev'])
1335
1335
1336 bundletype = opts.get('type', 'bzip2').lower()
1336 bundletype = opts.get('type', 'bzip2').lower()
1337 try:
1337 try:
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1338 bcompression, cgversion, params = exchange.parsebundlespec(
1339 repo, bundletype, strict=False)
1339 repo, bundletype, strict=False)
1340 except error.UnsupportedBundleSpecification as e:
1340 except error.UnsupportedBundleSpecification as e:
1341 raise error.Abort(str(e),
1341 raise error.Abort(str(e),
1342 hint=_('see "hg help bundle" for supported '
1342 hint=_('see "hg help bundle" for supported '
1343 'values for --type'))
1343 'values for --type'))
1344
1344
1345 # Packed bundles are a pseudo bundle format for now.
1345 # Packed bundles are a pseudo bundle format for now.
1346 if cgversion == 's1':
1346 if cgversion == 's1':
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1347 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1348 hint=_('use "hg debugcreatestreamclonebundle"'))
1348 hint=_('use "hg debugcreatestreamclonebundle"'))
1349
1349
1350 if opts.get('all'):
1350 if opts.get('all'):
1351 if dest:
1351 if dest:
1352 raise error.Abort(_("--all is incompatible with specifying "
1352 raise error.Abort(_("--all is incompatible with specifying "
1353 "a destination"))
1353 "a destination"))
1354 if opts.get('base'):
1354 if opts.get('base'):
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1355 ui.warn(_("ignoring --base because --all was specified\n"))
1356 base = ['null']
1356 base = ['null']
1357 else:
1357 else:
1358 base = scmutil.revrange(repo, opts.get('base'))
1358 base = scmutil.revrange(repo, opts.get('base'))
1359 # TODO: get desired bundlecaps from command line.
1359 # TODO: get desired bundlecaps from command line.
1360 bundlecaps = None
1360 bundlecaps = None
1361 if base:
1361 if base:
1362 if dest:
1362 if dest:
1363 raise error.Abort(_("--base is incompatible with specifying "
1363 raise error.Abort(_("--base is incompatible with specifying "
1364 "a destination"))
1364 "a destination"))
1365 common = [repo.lookup(rev) for rev in base]
1365 common = [repo.lookup(rev) for rev in base]
1366 heads = revs and map(repo.lookup, revs) or revs
1366 heads = revs and map(repo.lookup, revs) or revs
1367 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1367 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1368 common=common, bundlecaps=bundlecaps,
1368 common=common, bundlecaps=bundlecaps,
1369 version=cgversion)
1369 version=cgversion)
1370 outgoing = None
1370 outgoing = None
1371 else:
1371 else:
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1373 dest, branches = hg.parseurl(dest, opts.get('branch'))
1374 other = hg.peer(repo, opts, dest)
1374 other = hg.peer(repo, opts, dest)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1375 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1376 heads = revs and map(repo.lookup, revs) or revs
1376 heads = revs and map(repo.lookup, revs) or revs
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1377 outgoing = discovery.findcommonoutgoing(repo, other,
1378 onlyheads=heads,
1378 onlyheads=heads,
1379 force=opts.get('force'),
1379 force=opts.get('force'),
1380 portable=True)
1380 portable=True)
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1381 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1382 bundlecaps, version=cgversion)
1382 bundlecaps, version=cgversion)
1383 if not cg:
1383 if not cg:
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1384 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1385 return 1
1385 return 1
1386
1386
1387 if cgversion == '01': #bundle1
1387 if cgversion == '01': #bundle1
1388 if bcompression is None:
1388 if bcompression is None:
1389 bcompression = 'UN'
1389 bcompression = 'UN'
1390 bversion = 'HG10' + bcompression
1390 bversion = 'HG10' + bcompression
1391 bcompression = None
1391 bcompression = None
1392 else:
1392 else:
1393 assert cgversion == '02'
1393 assert cgversion == '02'
1394 bversion = 'HG20'
1394 bversion = 'HG20'
1395
1395
1396
1396
1397 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1397 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1398
1398
1399 @command('cat',
1399 @command('cat',
1400 [('o', 'output', '',
1400 [('o', 'output', '',
1401 _('print output to file with formatted name'), _('FORMAT')),
1401 _('print output to file with formatted name'), _('FORMAT')),
1402 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('r', 'rev', '', _('print the given revision'), _('REV')),
1403 ('', 'decode', None, _('apply any matching decode filter')),
1403 ('', 'decode', None, _('apply any matching decode filter')),
1404 ] + walkopts,
1404 ] + walkopts,
1405 _('[OPTION]... FILE...'),
1405 _('[OPTION]... FILE...'),
1406 inferrepo=True)
1406 inferrepo=True)
1407 def cat(ui, repo, file1, *pats, **opts):
1407 def cat(ui, repo, file1, *pats, **opts):
1408 """output the current or given revision of files
1408 """output the current or given revision of files
1409
1409
1410 Print the specified files as they were at the given revision. If
1410 Print the specified files as they were at the given revision. If
1411 no revision is given, the parent of the working directory is used.
1411 no revision is given, the parent of the working directory is used.
1412
1412
1413 Output may be to a file, in which case the name of the file is
1413 Output may be to a file, in which case the name of the file is
1414 given using a format string. The formatting rules as follows:
1414 given using a format string. The formatting rules as follows:
1415
1415
1416 :``%%``: literal "%" character
1416 :``%%``: literal "%" character
1417 :``%s``: basename of file being printed
1417 :``%s``: basename of file being printed
1418 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%d``: dirname of file being printed, or '.' if in repository root
1419 :``%p``: root-relative path name of file being printed
1419 :``%p``: root-relative path name of file being printed
1420 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%H``: changeset hash (40 hexadecimal digits)
1421 :``%R``: changeset revision number
1421 :``%R``: changeset revision number
1422 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%h``: short-form changeset hash (12 hexadecimal digits)
1423 :``%r``: zero-padded changeset revision number
1423 :``%r``: zero-padded changeset revision number
1424 :``%b``: basename of the exporting repository
1424 :``%b``: basename of the exporting repository
1425
1425
1426 Returns 0 on success.
1426 Returns 0 on success.
1427 """
1427 """
1428 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 ctx = scmutil.revsingle(repo, opts.get('rev'))
1429 m = scmutil.match(ctx, (file1,) + pats, opts)
1429 m = scmutil.match(ctx, (file1,) + pats, opts)
1430
1430
1431 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1431 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1432
1432
1433 @command('^clone',
1433 @command('^clone',
1434 [('U', 'noupdate', None, _('the clone will include an empty working '
1434 [('U', 'noupdate', None, _('the clone will include an empty working '
1435 'directory (only a repository)')),
1435 'directory (only a repository)')),
1436 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1436 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1437 _('REV')),
1437 _('REV')),
1438 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1438 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1439 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1439 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1440 ('', 'pull', None, _('use pull protocol to copy metadata')),
1440 ('', 'pull', None, _('use pull protocol to copy metadata')),
1441 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1441 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1442 ] + remoteopts,
1442 ] + remoteopts,
1443 _('[OPTION]... SOURCE [DEST]'),
1443 _('[OPTION]... SOURCE [DEST]'),
1444 norepo=True)
1444 norepo=True)
1445 def clone(ui, source, dest=None, **opts):
1445 def clone(ui, source, dest=None, **opts):
1446 """make a copy of an existing repository
1446 """make a copy of an existing repository
1447
1447
1448 Create a copy of an existing repository in a new directory.
1448 Create a copy of an existing repository in a new directory.
1449
1449
1450 If no destination directory name is specified, it defaults to the
1450 If no destination directory name is specified, it defaults to the
1451 basename of the source.
1451 basename of the source.
1452
1452
1453 The location of the source is added to the new repository's
1453 The location of the source is added to the new repository's
1454 ``.hg/hgrc`` file, as the default to be used for future pulls.
1454 ``.hg/hgrc`` file, as the default to be used for future pulls.
1455
1455
1456 Only local paths and ``ssh://`` URLs are supported as
1456 Only local paths and ``ssh://`` URLs are supported as
1457 destinations. For ``ssh://`` destinations, no working directory or
1457 destinations. For ``ssh://`` destinations, no working directory or
1458 ``.hg/hgrc`` will be created on the remote side.
1458 ``.hg/hgrc`` will be created on the remote side.
1459
1459
1460 To pull only a subset of changesets, specify one or more revisions
1460 To pull only a subset of changesets, specify one or more revisions
1461 identifiers with -r/--rev or branches with -b/--branch. The
1461 identifiers with -r/--rev or branches with -b/--branch. The
1462 resulting clone will contain only the specified changesets and
1462 resulting clone will contain only the specified changesets and
1463 their ancestors. These options (or 'clone src#rev dest') imply
1463 their ancestors. These options (or 'clone src#rev dest') imply
1464 --pull, even for local source repositories.
1464 --pull, even for local source repositories.
1465
1465
1466 .. note::
1466 .. note::
1467
1467
1468 Specifying a tag will include the tagged changeset but not the
1468 Specifying a tag will include the tagged changeset but not the
1469 changeset containing the tag.
1469 changeset containing the tag.
1470
1470
1471 If the source repository has a bookmark called '@' set, that
1471 If the source repository has a bookmark called '@' set, that
1472 revision will be checked out in the new repository by default.
1472 revision will be checked out in the new repository by default.
1473
1473
1474 To check out a particular version, use -u/--update, or
1474 To check out a particular version, use -u/--update, or
1475 -U/--noupdate to create a clone with no working directory.
1475 -U/--noupdate to create a clone with no working directory.
1476
1476
1477 .. container:: verbose
1477 .. container:: verbose
1478
1478
1479 For efficiency, hardlinks are used for cloning whenever the
1479 For efficiency, hardlinks are used for cloning whenever the
1480 source and destination are on the same filesystem (note this
1480 source and destination are on the same filesystem (note this
1481 applies only to the repository data, not to the working
1481 applies only to the repository data, not to the working
1482 directory). Some filesystems, such as AFS, implement hardlinking
1482 directory). Some filesystems, such as AFS, implement hardlinking
1483 incorrectly, but do not report errors. In these cases, use the
1483 incorrectly, but do not report errors. In these cases, use the
1484 --pull option to avoid hardlinking.
1484 --pull option to avoid hardlinking.
1485
1485
1486 In some cases, you can clone repositories and the working
1486 In some cases, you can clone repositories and the working
1487 directory using full hardlinks with ::
1487 directory using full hardlinks with ::
1488
1488
1489 $ cp -al REPO REPOCLONE
1489 $ cp -al REPO REPOCLONE
1490
1490
1491 This is the fastest way to clone, but it is not always safe. The
1491 This is the fastest way to clone, but it is not always safe. The
1492 operation is not atomic (making sure REPO is not modified during
1492 operation is not atomic (making sure REPO is not modified during
1493 the operation is up to you) and you have to make sure your
1493 the operation is up to you) and you have to make sure your
1494 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1494 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1495 so). Also, this is not compatible with certain extensions that
1495 so). Also, this is not compatible with certain extensions that
1496 place their metadata under the .hg directory, such as mq.
1496 place their metadata under the .hg directory, such as mq.
1497
1497
1498 Mercurial will update the working directory to the first applicable
1498 Mercurial will update the working directory to the first applicable
1499 revision from this list:
1499 revision from this list:
1500
1500
1501 a) null if -U or the source repository has no changesets
1501 a) null if -U or the source repository has no changesets
1502 b) if -u . and the source repository is local, the first parent of
1502 b) if -u . and the source repository is local, the first parent of
1503 the source repository's working directory
1503 the source repository's working directory
1504 c) the changeset specified with -u (if a branch name, this means the
1504 c) the changeset specified with -u (if a branch name, this means the
1505 latest head of that branch)
1505 latest head of that branch)
1506 d) the changeset specified with -r
1506 d) the changeset specified with -r
1507 e) the tipmost head specified with -b
1507 e) the tipmost head specified with -b
1508 f) the tipmost head specified with the url#branch source syntax
1508 f) the tipmost head specified with the url#branch source syntax
1509 g) the revision marked with the '@' bookmark, if present
1509 g) the revision marked with the '@' bookmark, if present
1510 h) the tipmost head of the default branch
1510 h) the tipmost head of the default branch
1511 i) tip
1511 i) tip
1512
1512
1513 Examples:
1513 Examples:
1514
1514
1515 - clone a remote repository to a new directory named hg/::
1515 - clone a remote repository to a new directory named hg/::
1516
1516
1517 hg clone http://selenic.com/hg
1517 hg clone http://selenic.com/hg
1518
1518
1519 - create a lightweight local clone::
1519 - create a lightweight local clone::
1520
1520
1521 hg clone project/ project-feature/
1521 hg clone project/ project-feature/
1522
1522
1523 - clone from an absolute path on an ssh server (note double-slash)::
1523 - clone from an absolute path on an ssh server (note double-slash)::
1524
1524
1525 hg clone ssh://user@server//home/projects/alpha/
1525 hg clone ssh://user@server//home/projects/alpha/
1526
1526
1527 - do a high-speed clone over a LAN while checking out a
1527 - do a high-speed clone over a LAN while checking out a
1528 specified version::
1528 specified version::
1529
1529
1530 hg clone --uncompressed http://server/repo -u 1.5
1530 hg clone --uncompressed http://server/repo -u 1.5
1531
1531
1532 - create a repository without changesets after a particular revision::
1532 - create a repository without changesets after a particular revision::
1533
1533
1534 hg clone -r 04e544 experimental/ good/
1534 hg clone -r 04e544 experimental/ good/
1535
1535
1536 - clone (and track) a particular named branch::
1536 - clone (and track) a particular named branch::
1537
1537
1538 hg clone http://selenic.com/hg#stable
1538 hg clone http://selenic.com/hg#stable
1539
1539
1540 See :hg:`help urls` for details on specifying URLs.
1540 See :hg:`help urls` for details on specifying URLs.
1541
1541
1542 Returns 0 on success.
1542 Returns 0 on success.
1543 """
1543 """
1544 if opts.get('noupdate') and opts.get('updaterev'):
1544 if opts.get('noupdate') and opts.get('updaterev'):
1545 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1545 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1546
1546
1547 r = hg.clone(ui, opts, source, dest,
1547 r = hg.clone(ui, opts, source, dest,
1548 pull=opts.get('pull'),
1548 pull=opts.get('pull'),
1549 stream=opts.get('uncompressed'),
1549 stream=opts.get('uncompressed'),
1550 rev=opts.get('rev'),
1550 rev=opts.get('rev'),
1551 update=opts.get('updaterev') or not opts.get('noupdate'),
1551 update=opts.get('updaterev') or not opts.get('noupdate'),
1552 branch=opts.get('branch'),
1552 branch=opts.get('branch'),
1553 shareopts=opts.get('shareopts'))
1553 shareopts=opts.get('shareopts'))
1554
1554
1555 return r is None
1555 return r is None
1556
1556
1557 @command('^commit|ci',
1557 @command('^commit|ci',
1558 [('A', 'addremove', None,
1558 [('A', 'addremove', None,
1559 _('mark new/missing files as added/removed before committing')),
1559 _('mark new/missing files as added/removed before committing')),
1560 ('', 'close-branch', None,
1560 ('', 'close-branch', None,
1561 _('mark a branch head as closed')),
1561 _('mark a branch head as closed')),
1562 ('', 'amend', None, _('amend the parent of the working directory')),
1562 ('', 'amend', None, _('amend the parent of the working directory')),
1563 ('s', 'secret', None, _('use the secret phase for committing')),
1563 ('s', 'secret', None, _('use the secret phase for committing')),
1564 ('e', 'edit', None, _('invoke editor on commit messages')),
1564 ('e', 'edit', None, _('invoke editor on commit messages')),
1565 ('i', 'interactive', None, _('use interactive mode')),
1565 ('i', 'interactive', None, _('use interactive mode')),
1566 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1566 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1567 _('[OPTION]... [FILE]...'),
1567 _('[OPTION]... [FILE]...'),
1568 inferrepo=True)
1568 inferrepo=True)
1569 def commit(ui, repo, *pats, **opts):
1569 def commit(ui, repo, *pats, **opts):
1570 """commit the specified files or all outstanding changes
1570 """commit the specified files or all outstanding changes
1571
1571
1572 Commit changes to the given files into the repository. Unlike a
1572 Commit changes to the given files into the repository. Unlike a
1573 centralized SCM, this operation is a local operation. See
1573 centralized SCM, this operation is a local operation. See
1574 :hg:`push` for a way to actively distribute your changes.
1574 :hg:`push` for a way to actively distribute your changes.
1575
1575
1576 If a list of files is omitted, all changes reported by :hg:`status`
1576 If a list of files is omitted, all changes reported by :hg:`status`
1577 will be committed.
1577 will be committed.
1578
1578
1579 If you are committing the result of a merge, do not provide any
1579 If you are committing the result of a merge, do not provide any
1580 filenames or -I/-X filters.
1580 filenames or -I/-X filters.
1581
1581
1582 If no commit message is specified, Mercurial starts your
1582 If no commit message is specified, Mercurial starts your
1583 configured editor where you can enter a message. In case your
1583 configured editor where you can enter a message. In case your
1584 commit fails, you will find a backup of your message in
1584 commit fails, you will find a backup of your message in
1585 ``.hg/last-message.txt``.
1585 ``.hg/last-message.txt``.
1586
1586
1587 The --close-branch flag can be used to mark the current branch
1587 The --close-branch flag can be used to mark the current branch
1588 head closed. When all heads of a branch are closed, the branch
1588 head closed. When all heads of a branch are closed, the branch
1589 will be considered closed and no longer listed.
1589 will be considered closed and no longer listed.
1590
1590
1591 The --amend flag can be used to amend the parent of the
1591 The --amend flag can be used to amend the parent of the
1592 working directory with a new commit that contains the changes
1592 working directory with a new commit that contains the changes
1593 in the parent in addition to those currently reported by :hg:`status`,
1593 in the parent in addition to those currently reported by :hg:`status`,
1594 if there are any. The old commit is stored in a backup bundle in
1594 if there are any. The old commit is stored in a backup bundle in
1595 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1595 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1596 on how to restore it).
1596 on how to restore it).
1597
1597
1598 Message, user and date are taken from the amended commit unless
1598 Message, user and date are taken from the amended commit unless
1599 specified. When a message isn't specified on the command line,
1599 specified. When a message isn't specified on the command line,
1600 the editor will open with the message of the amended commit.
1600 the editor will open with the message of the amended commit.
1601
1601
1602 It is not possible to amend public changesets (see :hg:`help phases`)
1602 It is not possible to amend public changesets (see :hg:`help phases`)
1603 or changesets that have children.
1603 or changesets that have children.
1604
1604
1605 See :hg:`help dates` for a list of formats valid for -d/--date.
1605 See :hg:`help dates` for a list of formats valid for -d/--date.
1606
1606
1607 Returns 0 on success, 1 if nothing changed.
1607 Returns 0 on success, 1 if nothing changed.
1608
1608
1609 .. container:: verbose
1609 .. container:: verbose
1610
1610
1611 Examples:
1611 Examples:
1612
1612
1613 - commit all files ending in .py::
1613 - commit all files ending in .py::
1614
1614
1615 hg commit --include "set:**.py"
1615 hg commit --include "set:**.py"
1616
1616
1617 - commit all non-binary files::
1617 - commit all non-binary files::
1618
1618
1619 hg commit --exclude "set:binary()"
1619 hg commit --exclude "set:binary()"
1620
1620
1621 - amend the current commit and set the date to now::
1621 - amend the current commit and set the date to now::
1622
1622
1623 hg commit --amend --date now
1623 hg commit --amend --date now
1624 """
1624 """
1625 wlock = lock = None
1625 wlock = lock = None
1626 try:
1626 try:
1627 wlock = repo.wlock()
1627 wlock = repo.wlock()
1628 lock = repo.lock()
1628 lock = repo.lock()
1629 return _docommit(ui, repo, *pats, **opts)
1629 return _docommit(ui, repo, *pats, **opts)
1630 finally:
1630 finally:
1631 release(lock, wlock)
1631 release(lock, wlock)
1632
1632
1633 def _docommit(ui, repo, *pats, **opts):
1633 def _docommit(ui, repo, *pats, **opts):
1634 if opts.get('interactive'):
1634 if opts.get('interactive'):
1635 opts.pop('interactive')
1635 opts.pop('interactive')
1636 cmdutil.dorecord(ui, repo, commit, None, False,
1636 cmdutil.dorecord(ui, repo, commit, None, False,
1637 cmdutil.recordfilter, *pats, **opts)
1637 cmdutil.recordfilter, *pats, **opts)
1638 return
1638 return
1639
1639
1640 if opts.get('subrepos'):
1640 if opts.get('subrepos'):
1641 if opts.get('amend'):
1641 if opts.get('amend'):
1642 raise error.Abort(_('cannot amend with --subrepos'))
1642 raise error.Abort(_('cannot amend with --subrepos'))
1643 # Let --subrepos on the command line override config setting.
1643 # Let --subrepos on the command line override config setting.
1644 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1644 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1645
1645
1646 cmdutil.checkunfinished(repo, commit=True)
1646 cmdutil.checkunfinished(repo, commit=True)
1647
1647
1648 branch = repo[None].branch()
1648 branch = repo[None].branch()
1649 bheads = repo.branchheads(branch)
1649 bheads = repo.branchheads(branch)
1650
1650
1651 extra = {}
1651 extra = {}
1652 if opts.get('close_branch'):
1652 if opts.get('close_branch'):
1653 extra['close'] = 1
1653 extra['close'] = 1
1654
1654
1655 if not bheads:
1655 if not bheads:
1656 raise error.Abort(_('can only close branch heads'))
1656 raise error.Abort(_('can only close branch heads'))
1657 elif opts.get('amend'):
1657 elif opts.get('amend'):
1658 if repo[None].parents()[0].p1().branch() != branch and \
1658 if repo[None].parents()[0].p1().branch() != branch and \
1659 repo[None].parents()[0].p2().branch() != branch:
1659 repo[None].parents()[0].p2().branch() != branch:
1660 raise error.Abort(_('can only close branch heads'))
1660 raise error.Abort(_('can only close branch heads'))
1661
1661
1662 if opts.get('amend'):
1662 if opts.get('amend'):
1663 if ui.configbool('ui', 'commitsubrepos'):
1663 if ui.configbool('ui', 'commitsubrepos'):
1664 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1664 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1665
1665
1666 old = repo['.']
1666 old = repo['.']
1667 if not old.mutable():
1667 if not old.mutable():
1668 raise error.Abort(_('cannot amend public changesets'))
1668 raise error.Abort(_('cannot amend public changesets'))
1669 if len(repo[None].parents()) > 1:
1669 if len(repo[None].parents()) > 1:
1670 raise error.Abort(_('cannot amend while merging'))
1670 raise error.Abort(_('cannot amend while merging'))
1671 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1671 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1672 if not allowunstable and old.children():
1672 if not allowunstable and old.children():
1673 raise error.Abort(_('cannot amend changeset with children'))
1673 raise error.Abort(_('cannot amend changeset with children'))
1674
1674
1675 newextra = extra.copy()
1675 newextra = extra.copy()
1676 newextra['branch'] = branch
1676 newextra['branch'] = branch
1677 extra = newextra
1677 extra = newextra
1678 # commitfunc is used only for temporary amend commit by cmdutil.amend
1678 # commitfunc is used only for temporary amend commit by cmdutil.amend
1679 def commitfunc(ui, repo, message, match, opts):
1679 def commitfunc(ui, repo, message, match, opts):
1680 return repo.commit(message,
1680 return repo.commit(message,
1681 opts.get('user') or old.user(),
1681 opts.get('user') or old.user(),
1682 opts.get('date') or old.date(),
1682 opts.get('date') or old.date(),
1683 match,
1683 match,
1684 extra=extra)
1684 extra=extra)
1685
1685
1686 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1686 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1687 if node == old.node():
1687 if node == old.node():
1688 ui.status(_("nothing changed\n"))
1688 ui.status(_("nothing changed\n"))
1689 return 1
1689 return 1
1690 else:
1690 else:
1691 def commitfunc(ui, repo, message, match, opts):
1691 def commitfunc(ui, repo, message, match, opts):
1692 backup = ui.backupconfig('phases', 'new-commit')
1692 backup = ui.backupconfig('phases', 'new-commit')
1693 baseui = repo.baseui
1693 baseui = repo.baseui
1694 basebackup = baseui.backupconfig('phases', 'new-commit')
1694 basebackup = baseui.backupconfig('phases', 'new-commit')
1695 try:
1695 try:
1696 if opts.get('secret'):
1696 if opts.get('secret'):
1697 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1697 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1698 # Propagate to subrepos
1698 # Propagate to subrepos
1699 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1699 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1700
1700
1701 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1701 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1702 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1702 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1703 return repo.commit(message, opts.get('user'), opts.get('date'),
1703 return repo.commit(message, opts.get('user'), opts.get('date'),
1704 match,
1704 match,
1705 editor=editor,
1705 editor=editor,
1706 extra=extra)
1706 extra=extra)
1707 finally:
1707 finally:
1708 ui.restoreconfig(backup)
1708 ui.restoreconfig(backup)
1709 repo.baseui.restoreconfig(basebackup)
1709 repo.baseui.restoreconfig(basebackup)
1710
1710
1711
1711
1712 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1712 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1713
1713
1714 if not node:
1714 if not node:
1715 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1715 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1716 if stat[3]:
1716 if stat[3]:
1717 ui.status(_("nothing changed (%d missing files, see "
1717 ui.status(_("nothing changed (%d missing files, see "
1718 "'hg status')\n") % len(stat[3]))
1718 "'hg status')\n") % len(stat[3]))
1719 else:
1719 else:
1720 ui.status(_("nothing changed\n"))
1720 ui.status(_("nothing changed\n"))
1721 return 1
1721 return 1
1722
1722
1723 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1723 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1724
1724
1725 @command('config|showconfig|debugconfig',
1725 @command('config|showconfig|debugconfig',
1726 [('u', 'untrusted', None, _('show untrusted configuration options')),
1726 [('u', 'untrusted', None, _('show untrusted configuration options')),
1727 ('e', 'edit', None, _('edit user config')),
1727 ('e', 'edit', None, _('edit user config')),
1728 ('l', 'local', None, _('edit repository config')),
1728 ('l', 'local', None, _('edit repository config')),
1729 ('g', 'global', None, _('edit global config'))],
1729 ('g', 'global', None, _('edit global config'))],
1730 _('[-u] [NAME]...'),
1730 _('[-u] [NAME]...'),
1731 optionalrepo=True)
1731 optionalrepo=True)
1732 def config(ui, repo, *values, **opts):
1732 def config(ui, repo, *values, **opts):
1733 """show combined config settings from all hgrc files
1733 """show combined config settings from all hgrc files
1734
1734
1735 With no arguments, print names and values of all config items.
1735 With no arguments, print names and values of all config items.
1736
1736
1737 With one argument of the form section.name, print just the value
1737 With one argument of the form section.name, print just the value
1738 of that config item.
1738 of that config item.
1739
1739
1740 With multiple arguments, print names and values of all config
1740 With multiple arguments, print names and values of all config
1741 items with matching section names.
1741 items with matching section names.
1742
1742
1743 With --edit, start an editor on the user-level config file. With
1743 With --edit, start an editor on the user-level config file. With
1744 --global, edit the system-wide config file. With --local, edit the
1744 --global, edit the system-wide config file. With --local, edit the
1745 repository-level config file.
1745 repository-level config file.
1746
1746
1747 With --debug, the source (filename and line number) is printed
1747 With --debug, the source (filename and line number) is printed
1748 for each config item.
1748 for each config item.
1749
1749
1750 See :hg:`help config` for more information about config files.
1750 See :hg:`help config` for more information about config files.
1751
1751
1752 Returns 0 on success, 1 if NAME does not exist.
1752 Returns 0 on success, 1 if NAME does not exist.
1753
1753
1754 """
1754 """
1755
1755
1756 if opts.get('edit') or opts.get('local') or opts.get('global'):
1756 if opts.get('edit') or opts.get('local') or opts.get('global'):
1757 if opts.get('local') and opts.get('global'):
1757 if opts.get('local') and opts.get('global'):
1758 raise error.Abort(_("can't use --local and --global together"))
1758 raise error.Abort(_("can't use --local and --global together"))
1759
1759
1760 if opts.get('local'):
1760 if opts.get('local'):
1761 if not repo:
1761 if not repo:
1762 raise error.Abort(_("can't use --local outside a repository"))
1762 raise error.Abort(_("can't use --local outside a repository"))
1763 paths = [repo.join('hgrc')]
1763 paths = [repo.join('hgrc')]
1764 elif opts.get('global'):
1764 elif opts.get('global'):
1765 paths = scmutil.systemrcpath()
1765 paths = scmutil.systemrcpath()
1766 else:
1766 else:
1767 paths = scmutil.userrcpath()
1767 paths = scmutil.userrcpath()
1768
1768
1769 for f in paths:
1769 for f in paths:
1770 if os.path.exists(f):
1770 if os.path.exists(f):
1771 break
1771 break
1772 else:
1772 else:
1773 if opts.get('global'):
1773 if opts.get('global'):
1774 samplehgrc = uimod.samplehgrcs['global']
1774 samplehgrc = uimod.samplehgrcs['global']
1775 elif opts.get('local'):
1775 elif opts.get('local'):
1776 samplehgrc = uimod.samplehgrcs['local']
1776 samplehgrc = uimod.samplehgrcs['local']
1777 else:
1777 else:
1778 samplehgrc = uimod.samplehgrcs['user']
1778 samplehgrc = uimod.samplehgrcs['user']
1779
1779
1780 f = paths[0]
1780 f = paths[0]
1781 fp = open(f, "w")
1781 fp = open(f, "w")
1782 fp.write(samplehgrc)
1782 fp.write(samplehgrc)
1783 fp.close()
1783 fp.close()
1784
1784
1785 editor = ui.geteditor()
1785 editor = ui.geteditor()
1786 ui.system("%s \"%s\"" % (editor, f),
1786 ui.system("%s \"%s\"" % (editor, f),
1787 onerr=error.Abort, errprefix=_("edit failed"))
1787 onerr=error.Abort, errprefix=_("edit failed"))
1788 return
1788 return
1789
1789
1790 for f in scmutil.rcpath():
1790 for f in scmutil.rcpath():
1791 ui.debug('read config from: %s\n' % f)
1791 ui.debug('read config from: %s\n' % f)
1792 untrusted = bool(opts.get('untrusted'))
1792 untrusted = bool(opts.get('untrusted'))
1793 if values:
1793 if values:
1794 sections = [v for v in values if '.' not in v]
1794 sections = [v for v in values if '.' not in v]
1795 items = [v for v in values if '.' in v]
1795 items = [v for v in values if '.' in v]
1796 if len(items) > 1 or items and sections:
1796 if len(items) > 1 or items and sections:
1797 raise error.Abort(_('only one config item permitted'))
1797 raise error.Abort(_('only one config item permitted'))
1798 matched = False
1798 matched = False
1799 for section, name, value in ui.walkconfig(untrusted=untrusted):
1799 for section, name, value in ui.walkconfig(untrusted=untrusted):
1800 value = str(value).replace('\n', '\\n')
1800 value = str(value).replace('\n', '\\n')
1801 sectname = section + '.' + name
1801 sectname = section + '.' + name
1802 if values:
1802 if values:
1803 for v in values:
1803 for v in values:
1804 if v == section:
1804 if v == section:
1805 ui.debug('%s: ' %
1805 ui.debug('%s: ' %
1806 ui.configsource(section, name, untrusted))
1806 ui.configsource(section, name, untrusted))
1807 ui.write('%s=%s\n' % (sectname, value))
1807 ui.write('%s=%s\n' % (sectname, value))
1808 matched = True
1808 matched = True
1809 elif v == sectname:
1809 elif v == sectname:
1810 ui.debug('%s: ' %
1810 ui.debug('%s: ' %
1811 ui.configsource(section, name, untrusted))
1811 ui.configsource(section, name, untrusted))
1812 ui.write(value, '\n')
1812 ui.write(value, '\n')
1813 matched = True
1813 matched = True
1814 else:
1814 else:
1815 ui.debug('%s: ' %
1815 ui.debug('%s: ' %
1816 ui.configsource(section, name, untrusted))
1816 ui.configsource(section, name, untrusted))
1817 ui.write('%s=%s\n' % (sectname, value))
1817 ui.write('%s=%s\n' % (sectname, value))
1818 matched = True
1818 matched = True
1819 if matched:
1819 if matched:
1820 return 0
1820 return 0
1821 return 1
1821 return 1
1822
1822
1823 @command('copy|cp',
1823 @command('copy|cp',
1824 [('A', 'after', None, _('record a copy that has already occurred')),
1824 [('A', 'after', None, _('record a copy that has already occurred')),
1825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1825 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1826 ] + walkopts + dryrunopts,
1826 ] + walkopts + dryrunopts,
1827 _('[OPTION]... [SOURCE]... DEST'))
1827 _('[OPTION]... [SOURCE]... DEST'))
1828 def copy(ui, repo, *pats, **opts):
1828 def copy(ui, repo, *pats, **opts):
1829 """mark files as copied for the next commit
1829 """mark files as copied for the next commit
1830
1830
1831 Mark dest as having copies of source files. If dest is a
1831 Mark dest as having copies of source files. If dest is a
1832 directory, copies are put in that directory. If dest is a file,
1832 directory, copies are put in that directory. If dest is a file,
1833 the source must be a single file.
1833 the source must be a single file.
1834
1834
1835 By default, this command copies the contents of files as they
1835 By default, this command copies the contents of files as they
1836 exist in the working directory. If invoked with -A/--after, the
1836 exist in the working directory. If invoked with -A/--after, the
1837 operation is recorded, but no copying is performed.
1837 operation is recorded, but no copying is performed.
1838
1838
1839 This command takes effect with the next commit. To undo a copy
1839 This command takes effect with the next commit. To undo a copy
1840 before that, see :hg:`revert`.
1840 before that, see :hg:`revert`.
1841
1841
1842 Returns 0 on success, 1 if errors are encountered.
1842 Returns 0 on success, 1 if errors are encountered.
1843 """
1843 """
1844 wlock = repo.wlock(False)
1844 wlock = repo.wlock(False)
1845 try:
1845 try:
1846 return cmdutil.copy(ui, repo, pats, opts)
1846 return cmdutil.copy(ui, repo, pats, opts)
1847 finally:
1847 finally:
1848 wlock.release()
1848 wlock.release()
1849
1849
1850 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1850 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1851 def debugancestor(ui, repo, *args):
1851 def debugancestor(ui, repo, *args):
1852 """find the ancestor revision of two revisions in a given index"""
1852 """find the ancestor revision of two revisions in a given index"""
1853 if len(args) == 3:
1853 if len(args) == 3:
1854 index, rev1, rev2 = args
1854 index, rev1, rev2 = args
1855 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1855 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1856 lookup = r.lookup
1856 lookup = r.lookup
1857 elif len(args) == 2:
1857 elif len(args) == 2:
1858 if not repo:
1858 if not repo:
1859 raise error.Abort(_("there is no Mercurial repository here "
1859 raise error.Abort(_("there is no Mercurial repository here "
1860 "(.hg not found)"))
1860 "(.hg not found)"))
1861 rev1, rev2 = args
1861 rev1, rev2 = args
1862 r = repo.changelog
1862 r = repo.changelog
1863 lookup = repo.lookup
1863 lookup = repo.lookup
1864 else:
1864 else:
1865 raise error.Abort(_('either two or three arguments required'))
1865 raise error.Abort(_('either two or three arguments required'))
1866 a = r.ancestor(lookup(rev1), lookup(rev2))
1866 a = r.ancestor(lookup(rev1), lookup(rev2))
1867 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1867 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1868
1868
1869 @command('debugbuilddag',
1869 @command('debugbuilddag',
1870 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1870 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1871 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1871 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1872 ('n', 'new-file', None, _('add new file at each rev'))],
1872 ('n', 'new-file', None, _('add new file at each rev'))],
1873 _('[OPTION]... [TEXT]'))
1873 _('[OPTION]... [TEXT]'))
1874 def debugbuilddag(ui, repo, text=None,
1874 def debugbuilddag(ui, repo, text=None,
1875 mergeable_file=False,
1875 mergeable_file=False,
1876 overwritten_file=False,
1876 overwritten_file=False,
1877 new_file=False):
1877 new_file=False):
1878 """builds a repo with a given DAG from scratch in the current empty repo
1878 """builds a repo with a given DAG from scratch in the current empty repo
1879
1879
1880 The description of the DAG is read from stdin if not given on the
1880 The description of the DAG is read from stdin if not given on the
1881 command line.
1881 command line.
1882
1882
1883 Elements:
1883 Elements:
1884
1884
1885 - "+n" is a linear run of n nodes based on the current default parent
1885 - "+n" is a linear run of n nodes based on the current default parent
1886 - "." is a single node based on the current default parent
1886 - "." is a single node based on the current default parent
1887 - "$" resets the default parent to null (implied at the start);
1887 - "$" resets the default parent to null (implied at the start);
1888 otherwise the default parent is always the last node created
1888 otherwise the default parent is always the last node created
1889 - "<p" sets the default parent to the backref p
1889 - "<p" sets the default parent to the backref p
1890 - "*p" is a fork at parent p, which is a backref
1890 - "*p" is a fork at parent p, which is a backref
1891 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1891 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1892 - "/p2" is a merge of the preceding node and p2
1892 - "/p2" is a merge of the preceding node and p2
1893 - ":tag" defines a local tag for the preceding node
1893 - ":tag" defines a local tag for the preceding node
1894 - "@branch" sets the named branch for subsequent nodes
1894 - "@branch" sets the named branch for subsequent nodes
1895 - "#...\\n" is a comment up to the end of the line
1895 - "#...\\n" is a comment up to the end of the line
1896
1896
1897 Whitespace between the above elements is ignored.
1897 Whitespace between the above elements is ignored.
1898
1898
1899 A backref is either
1899 A backref is either
1900
1900
1901 - a number n, which references the node curr-n, where curr is the current
1901 - a number n, which references the node curr-n, where curr is the current
1902 node, or
1902 node, or
1903 - the name of a local tag you placed earlier using ":tag", or
1903 - the name of a local tag you placed earlier using ":tag", or
1904 - empty to denote the default parent.
1904 - empty to denote the default parent.
1905
1905
1906 All string valued-elements are either strictly alphanumeric, or must
1906 All string valued-elements are either strictly alphanumeric, or must
1907 be enclosed in double quotes ("..."), with "\\" as escape character.
1907 be enclosed in double quotes ("..."), with "\\" as escape character.
1908 """
1908 """
1909
1909
1910 if text is None:
1910 if text is None:
1911 ui.status(_("reading DAG from stdin\n"))
1911 ui.status(_("reading DAG from stdin\n"))
1912 text = ui.fin.read()
1912 text = ui.fin.read()
1913
1913
1914 cl = repo.changelog
1914 cl = repo.changelog
1915 if len(cl) > 0:
1915 if len(cl) > 0:
1916 raise error.Abort(_('repository is not empty'))
1916 raise error.Abort(_('repository is not empty'))
1917
1917
1918 # determine number of revs in DAG
1918 # determine number of revs in DAG
1919 total = 0
1919 total = 0
1920 for type, data in dagparser.parsedag(text):
1920 for type, data in dagparser.parsedag(text):
1921 if type == 'n':
1921 if type == 'n':
1922 total += 1
1922 total += 1
1923
1923
1924 if mergeable_file:
1924 if mergeable_file:
1925 linesperrev = 2
1925 linesperrev = 2
1926 # make a file with k lines per rev
1926 # make a file with k lines per rev
1927 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1927 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1928 initialmergedlines.append("")
1928 initialmergedlines.append("")
1929
1929
1930 tags = []
1930 tags = []
1931
1931
1932 lock = tr = None
1932 lock = tr = None
1933 try:
1933 try:
1934 lock = repo.lock()
1934 lock = repo.lock()
1935 tr = repo.transaction("builddag")
1935 tr = repo.transaction("builddag")
1936
1936
1937 at = -1
1937 at = -1
1938 atbranch = 'default'
1938 atbranch = 'default'
1939 nodeids = []
1939 nodeids = []
1940 id = 0
1940 id = 0
1941 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1941 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1942 for type, data in dagparser.parsedag(text):
1942 for type, data in dagparser.parsedag(text):
1943 if type == 'n':
1943 if type == 'n':
1944 ui.note(('node %s\n' % str(data)))
1944 ui.note(('node %s\n' % str(data)))
1945 id, ps = data
1945 id, ps = data
1946
1946
1947 files = []
1947 files = []
1948 fctxs = {}
1948 fctxs = {}
1949
1949
1950 p2 = None
1950 p2 = None
1951 if mergeable_file:
1951 if mergeable_file:
1952 fn = "mf"
1952 fn = "mf"
1953 p1 = repo[ps[0]]
1953 p1 = repo[ps[0]]
1954 if len(ps) > 1:
1954 if len(ps) > 1:
1955 p2 = repo[ps[1]]
1955 p2 = repo[ps[1]]
1956 pa = p1.ancestor(p2)
1956 pa = p1.ancestor(p2)
1957 base, local, other = [x[fn].data() for x in (pa, p1,
1957 base, local, other = [x[fn].data() for x in (pa, p1,
1958 p2)]
1958 p2)]
1959 m3 = simplemerge.Merge3Text(base, local, other)
1959 m3 = simplemerge.Merge3Text(base, local, other)
1960 ml = [l.strip() for l in m3.merge_lines()]
1960 ml = [l.strip() for l in m3.merge_lines()]
1961 ml.append("")
1961 ml.append("")
1962 elif at > 0:
1962 elif at > 0:
1963 ml = p1[fn].data().split("\n")
1963 ml = p1[fn].data().split("\n")
1964 else:
1964 else:
1965 ml = initialmergedlines
1965 ml = initialmergedlines
1966 ml[id * linesperrev] += " r%i" % id
1966 ml[id * linesperrev] += " r%i" % id
1967 mergedtext = "\n".join(ml)
1967 mergedtext = "\n".join(ml)
1968 files.append(fn)
1968 files.append(fn)
1969 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1969 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1970
1970
1971 if overwritten_file:
1971 if overwritten_file:
1972 fn = "of"
1972 fn = "of"
1973 files.append(fn)
1973 files.append(fn)
1974 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1974 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1975
1975
1976 if new_file:
1976 if new_file:
1977 fn = "nf%i" % id
1977 fn = "nf%i" % id
1978 files.append(fn)
1978 files.append(fn)
1979 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1979 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1980 if len(ps) > 1:
1980 if len(ps) > 1:
1981 if not p2:
1981 if not p2:
1982 p2 = repo[ps[1]]
1982 p2 = repo[ps[1]]
1983 for fn in p2:
1983 for fn in p2:
1984 if fn.startswith("nf"):
1984 if fn.startswith("nf"):
1985 files.append(fn)
1985 files.append(fn)
1986 fctxs[fn] = p2[fn]
1986 fctxs[fn] = p2[fn]
1987
1987
1988 def fctxfn(repo, cx, path):
1988 def fctxfn(repo, cx, path):
1989 return fctxs.get(path)
1989 return fctxs.get(path)
1990
1990
1991 if len(ps) == 0 or ps[0] < 0:
1991 if len(ps) == 0 or ps[0] < 0:
1992 pars = [None, None]
1992 pars = [None, None]
1993 elif len(ps) == 1:
1993 elif len(ps) == 1:
1994 pars = [nodeids[ps[0]], None]
1994 pars = [nodeids[ps[0]], None]
1995 else:
1995 else:
1996 pars = [nodeids[p] for p in ps]
1996 pars = [nodeids[p] for p in ps]
1997 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1997 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1998 date=(id, 0),
1998 date=(id, 0),
1999 user="debugbuilddag",
1999 user="debugbuilddag",
2000 extra={'branch': atbranch})
2000 extra={'branch': atbranch})
2001 nodeid = repo.commitctx(cx)
2001 nodeid = repo.commitctx(cx)
2002 nodeids.append(nodeid)
2002 nodeids.append(nodeid)
2003 at = id
2003 at = id
2004 elif type == 'l':
2004 elif type == 'l':
2005 id, name = data
2005 id, name = data
2006 ui.note(('tag %s\n' % name))
2006 ui.note(('tag %s\n' % name))
2007 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2007 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2008 elif type == 'a':
2008 elif type == 'a':
2009 ui.note(('branch %s\n' % data))
2009 ui.note(('branch %s\n' % data))
2010 atbranch = data
2010 atbranch = data
2011 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2011 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2012 tr.close()
2012 tr.close()
2013
2013
2014 if tags:
2014 if tags:
2015 repo.vfs.write("localtags", "".join(tags))
2015 repo.vfs.write("localtags", "".join(tags))
2016 finally:
2016 finally:
2017 ui.progress(_('building'), None)
2017 ui.progress(_('building'), None)
2018 release(tr, lock)
2018 release(tr, lock)
2019
2019
2020 @command('debugbundle',
2020 @command('debugbundle',
2021 [('a', 'all', None, _('show all details'))],
2021 [('a', 'all', None, _('show all details'))],
2022 _('FILE'),
2022 _('FILE'),
2023 norepo=True)
2023 norepo=True)
2024 def debugbundle(ui, bundlepath, all=None, **opts):
2024 def debugbundle(ui, bundlepath, all=None, **opts):
2025 """lists the contents of a bundle"""
2025 """lists the contents of a bundle"""
2026 f = hg.openpath(ui, bundlepath)
2026 f = hg.openpath(ui, bundlepath)
2027 try:
2027 try:
2028 gen = exchange.readbundle(ui, f, bundlepath)
2028 gen = exchange.readbundle(ui, f, bundlepath)
2029 if isinstance(gen, bundle2.unbundle20):
2029 if isinstance(gen, bundle2.unbundle20):
2030 return _debugbundle2(ui, gen, all=all, **opts)
2030 return _debugbundle2(ui, gen, all=all, **opts)
2031 if all:
2031 if all:
2032 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2032 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2033
2033
2034 def showchunks(named):
2034 def showchunks(named):
2035 ui.write("\n%s\n" % named)
2035 ui.write("\n%s\n" % named)
2036 chain = None
2036 chain = None
2037 while True:
2037 while True:
2038 chunkdata = gen.deltachunk(chain)
2038 chunkdata = gen.deltachunk(chain)
2039 if not chunkdata:
2039 if not chunkdata:
2040 break
2040 break
2041 node = chunkdata['node']
2041 node = chunkdata['node']
2042 p1 = chunkdata['p1']
2042 p1 = chunkdata['p1']
2043 p2 = chunkdata['p2']
2043 p2 = chunkdata['p2']
2044 cs = chunkdata['cs']
2044 cs = chunkdata['cs']
2045 deltabase = chunkdata['deltabase']
2045 deltabase = chunkdata['deltabase']
2046 delta = chunkdata['delta']
2046 delta = chunkdata['delta']
2047 ui.write("%s %s %s %s %s %s\n" %
2047 ui.write("%s %s %s %s %s %s\n" %
2048 (hex(node), hex(p1), hex(p2),
2048 (hex(node), hex(p1), hex(p2),
2049 hex(cs), hex(deltabase), len(delta)))
2049 hex(cs), hex(deltabase), len(delta)))
2050 chain = node
2050 chain = node
2051
2051
2052 chunkdata = gen.changelogheader()
2052 chunkdata = gen.changelogheader()
2053 showchunks("changelog")
2053 showchunks("changelog")
2054 chunkdata = gen.manifestheader()
2054 chunkdata = gen.manifestheader()
2055 showchunks("manifest")
2055 showchunks("manifest")
2056 while True:
2056 while True:
2057 chunkdata = gen.filelogheader()
2057 chunkdata = gen.filelogheader()
2058 if not chunkdata:
2058 if not chunkdata:
2059 break
2059 break
2060 fname = chunkdata['filename']
2060 fname = chunkdata['filename']
2061 showchunks(fname)
2061 showchunks(fname)
2062 else:
2062 else:
2063 if isinstance(gen, bundle2.unbundle20):
2063 if isinstance(gen, bundle2.unbundle20):
2064 raise error.Abort(_('use debugbundle2 for this file'))
2064 raise error.Abort(_('use debugbundle2 for this file'))
2065 chunkdata = gen.changelogheader()
2065 chunkdata = gen.changelogheader()
2066 chain = None
2066 chain = None
2067 while True:
2067 while True:
2068 chunkdata = gen.deltachunk(chain)
2068 chunkdata = gen.deltachunk(chain)
2069 if not chunkdata:
2069 if not chunkdata:
2070 break
2070 break
2071 node = chunkdata['node']
2071 node = chunkdata['node']
2072 ui.write("%s\n" % hex(node))
2072 ui.write("%s\n" % hex(node))
2073 chain = node
2073 chain = node
2074 finally:
2074 finally:
2075 f.close()
2075 f.close()
2076
2076
2077 def _debugbundle2(ui, gen, **opts):
2077 def _debugbundle2(ui, gen, **opts):
2078 """lists the contents of a bundle2"""
2078 """lists the contents of a bundle2"""
2079 if not isinstance(gen, bundle2.unbundle20):
2079 if not isinstance(gen, bundle2.unbundle20):
2080 raise error.Abort(_('not a bundle2 file'))
2080 raise error.Abort(_('not a bundle2 file'))
2081 ui.write(('Stream params: %s\n' % repr(gen.params)))
2081 ui.write(('Stream params: %s\n' % repr(gen.params)))
2082 for part in gen.iterparts():
2082 for part in gen.iterparts():
2083 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2083 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2084 if part.type == 'changegroup':
2084 if part.type == 'changegroup':
2085 version = part.params.get('version', '01')
2085 version = part.params.get('version', '01')
2086 cg = changegroup.packermap[version][1](part, 'UN')
2086 cg = changegroup.packermap[version][1](part, 'UN')
2087 chunkdata = cg.changelogheader()
2087 chunkdata = cg.changelogheader()
2088 chain = None
2088 chain = None
2089 while True:
2089 while True:
2090 chunkdata = cg.deltachunk(chain)
2090 chunkdata = cg.deltachunk(chain)
2091 if not chunkdata:
2091 if not chunkdata:
2092 break
2092 break
2093 node = chunkdata['node']
2093 node = chunkdata['node']
2094 ui.write(" %s\n" % hex(node))
2094 ui.write(" %s\n" % hex(node))
2095 chain = node
2095 chain = node
2096
2096
2097 @command('debugcreatestreamclonebundle', [], 'FILE')
2097 @command('debugcreatestreamclonebundle', [], 'FILE')
2098 def debugcreatestreamclonebundle(ui, repo, fname):
2098 def debugcreatestreamclonebundle(ui, repo, fname):
2099 """create a stream clone bundle file
2099 """create a stream clone bundle file
2100
2100
2101 Stream bundles are special bundles that are essentially archives of
2101 Stream bundles are special bundles that are essentially archives of
2102 revlog files. They are commonly used for cloning very quickly.
2102 revlog files. They are commonly used for cloning very quickly.
2103 """
2103 """
2104 requirements, gen = streamclone.generatebundlev1(repo)
2104 requirements, gen = streamclone.generatebundlev1(repo)
2105 changegroup.writechunks(ui, gen, fname)
2105 changegroup.writechunks(ui, gen, fname)
2106
2106
2107 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2107 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2108
2108
2109 @command('debugapplystreamclonebundle', [], 'FILE')
2109 @command('debugapplystreamclonebundle', [], 'FILE')
2110 def debugapplystreamclonebundle(ui, repo, fname):
2110 def debugapplystreamclonebundle(ui, repo, fname):
2111 """apply a stream clone bundle file"""
2111 """apply a stream clone bundle file"""
2112 f = hg.openpath(ui, fname)
2112 f = hg.openpath(ui, fname)
2113 gen = exchange.readbundle(ui, f, fname)
2113 gen = exchange.readbundle(ui, f, fname)
2114 gen.apply(repo)
2114 gen.apply(repo)
2115
2115
2116 @command('debugcheckstate', [], '')
2116 @command('debugcheckstate', [], '')
2117 def debugcheckstate(ui, repo):
2117 def debugcheckstate(ui, repo):
2118 """validate the correctness of the current dirstate"""
2118 """validate the correctness of the current dirstate"""
2119 parent1, parent2 = repo.dirstate.parents()
2119 parent1, parent2 = repo.dirstate.parents()
2120 m1 = repo[parent1].manifest()
2120 m1 = repo[parent1].manifest()
2121 m2 = repo[parent2].manifest()
2121 m2 = repo[parent2].manifest()
2122 errors = 0
2122 errors = 0
2123 for f in repo.dirstate:
2123 for f in repo.dirstate:
2124 state = repo.dirstate[f]
2124 state = repo.dirstate[f]
2125 if state in "nr" and f not in m1:
2125 if state in "nr" and f not in m1:
2126 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2126 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2127 errors += 1
2127 errors += 1
2128 if state in "a" and f in m1:
2128 if state in "a" and f in m1:
2129 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2129 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2130 errors += 1
2130 errors += 1
2131 if state in "m" and f not in m1 and f not in m2:
2131 if state in "m" and f not in m1 and f not in m2:
2132 ui.warn(_("%s in state %s, but not in either manifest\n") %
2132 ui.warn(_("%s in state %s, but not in either manifest\n") %
2133 (f, state))
2133 (f, state))
2134 errors += 1
2134 errors += 1
2135 for f in m1:
2135 for f in m1:
2136 state = repo.dirstate[f]
2136 state = repo.dirstate[f]
2137 if state not in "nrm":
2137 if state not in "nrm":
2138 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2138 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2139 errors += 1
2139 errors += 1
2140 if errors:
2140 if errors:
2141 error = _(".hg/dirstate inconsistent with current parent's manifest")
2141 error = _(".hg/dirstate inconsistent with current parent's manifest")
2142 raise error.Abort(error)
2142 raise error.Abort(error)
2143
2143
2144 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2144 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2145 def debugcommands(ui, cmd='', *args):
2145 def debugcommands(ui, cmd='', *args):
2146 """list all available commands and options"""
2146 """list all available commands and options"""
2147 for cmd, vals in sorted(table.iteritems()):
2147 for cmd, vals in sorted(table.iteritems()):
2148 cmd = cmd.split('|')[0].strip('^')
2148 cmd = cmd.split('|')[0].strip('^')
2149 opts = ', '.join([i[1] for i in vals[1]])
2149 opts = ', '.join([i[1] for i in vals[1]])
2150 ui.write('%s: %s\n' % (cmd, opts))
2150 ui.write('%s: %s\n' % (cmd, opts))
2151
2151
2152 @command('debugcomplete',
2152 @command('debugcomplete',
2153 [('o', 'options', None, _('show the command options'))],
2153 [('o', 'options', None, _('show the command options'))],
2154 _('[-o] CMD'),
2154 _('[-o] CMD'),
2155 norepo=True)
2155 norepo=True)
2156 def debugcomplete(ui, cmd='', **opts):
2156 def debugcomplete(ui, cmd='', **opts):
2157 """returns the completion list associated with the given command"""
2157 """returns the completion list associated with the given command"""
2158
2158
2159 if opts.get('options'):
2159 if opts.get('options'):
2160 options = []
2160 options = []
2161 otables = [globalopts]
2161 otables = [globalopts]
2162 if cmd:
2162 if cmd:
2163 aliases, entry = cmdutil.findcmd(cmd, table, False)
2163 aliases, entry = cmdutil.findcmd(cmd, table, False)
2164 otables.append(entry[1])
2164 otables.append(entry[1])
2165 for t in otables:
2165 for t in otables:
2166 for o in t:
2166 for o in t:
2167 if "(DEPRECATED)" in o[3]:
2167 if "(DEPRECATED)" in o[3]:
2168 continue
2168 continue
2169 if o[0]:
2169 if o[0]:
2170 options.append('-%s' % o[0])
2170 options.append('-%s' % o[0])
2171 options.append('--%s' % o[1])
2171 options.append('--%s' % o[1])
2172 ui.write("%s\n" % "\n".join(options))
2172 ui.write("%s\n" % "\n".join(options))
2173 return
2173 return
2174
2174
2175 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2175 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2176 if ui.verbose:
2176 if ui.verbose:
2177 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2177 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2178 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2178 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2179
2179
2180 @command('debugdag',
2180 @command('debugdag',
2181 [('t', 'tags', None, _('use tags as labels')),
2181 [('t', 'tags', None, _('use tags as labels')),
2182 ('b', 'branches', None, _('annotate with branch names')),
2182 ('b', 'branches', None, _('annotate with branch names')),
2183 ('', 'dots', None, _('use dots for runs')),
2183 ('', 'dots', None, _('use dots for runs')),
2184 ('s', 'spaces', None, _('separate elements by spaces'))],
2184 ('s', 'spaces', None, _('separate elements by spaces'))],
2185 _('[OPTION]... [FILE [REV]...]'),
2185 _('[OPTION]... [FILE [REV]...]'),
2186 optionalrepo=True)
2186 optionalrepo=True)
2187 def debugdag(ui, repo, file_=None, *revs, **opts):
2187 def debugdag(ui, repo, file_=None, *revs, **opts):
2188 """format the changelog or an index DAG as a concise textual description
2188 """format the changelog or an index DAG as a concise textual description
2189
2189
2190 If you pass a revlog index, the revlog's DAG is emitted. If you list
2190 If you pass a revlog index, the revlog's DAG is emitted. If you list
2191 revision numbers, they get labeled in the output as rN.
2191 revision numbers, they get labeled in the output as rN.
2192
2192
2193 Otherwise, the changelog DAG of the current repo is emitted.
2193 Otherwise, the changelog DAG of the current repo is emitted.
2194 """
2194 """
2195 spaces = opts.get('spaces')
2195 spaces = opts.get('spaces')
2196 dots = opts.get('dots')
2196 dots = opts.get('dots')
2197 if file_:
2197 if file_:
2198 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2198 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2199 revs = set((int(r) for r in revs))
2199 revs = set((int(r) for r in revs))
2200 def events():
2200 def events():
2201 for r in rlog:
2201 for r in rlog:
2202 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2202 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2203 if p != -1))
2203 if p != -1))
2204 if r in revs:
2204 if r in revs:
2205 yield 'l', (r, "r%i" % r)
2205 yield 'l', (r, "r%i" % r)
2206 elif repo:
2206 elif repo:
2207 cl = repo.changelog
2207 cl = repo.changelog
2208 tags = opts.get('tags')
2208 tags = opts.get('tags')
2209 branches = opts.get('branches')
2209 branches = opts.get('branches')
2210 if tags:
2210 if tags:
2211 labels = {}
2211 labels = {}
2212 for l, n in repo.tags().items():
2212 for l, n in repo.tags().items():
2213 labels.setdefault(cl.rev(n), []).append(l)
2213 labels.setdefault(cl.rev(n), []).append(l)
2214 def events():
2214 def events():
2215 b = "default"
2215 b = "default"
2216 for r in cl:
2216 for r in cl:
2217 if branches:
2217 if branches:
2218 newb = cl.read(cl.node(r))[5]['branch']
2218 newb = cl.read(cl.node(r))[5]['branch']
2219 if newb != b:
2219 if newb != b:
2220 yield 'a', newb
2220 yield 'a', newb
2221 b = newb
2221 b = newb
2222 yield 'n', (r, list(p for p in cl.parentrevs(r)
2222 yield 'n', (r, list(p for p in cl.parentrevs(r)
2223 if p != -1))
2223 if p != -1))
2224 if tags:
2224 if tags:
2225 ls = labels.get(r)
2225 ls = labels.get(r)
2226 if ls:
2226 if ls:
2227 for l in ls:
2227 for l in ls:
2228 yield 'l', (r, l)
2228 yield 'l', (r, l)
2229 else:
2229 else:
2230 raise error.Abort(_('need repo for changelog dag'))
2230 raise error.Abort(_('need repo for changelog dag'))
2231
2231
2232 for line in dagparser.dagtextlines(events(),
2232 for line in dagparser.dagtextlines(events(),
2233 addspaces=spaces,
2233 addspaces=spaces,
2234 wraplabels=True,
2234 wraplabels=True,
2235 wrapannotations=True,
2235 wrapannotations=True,
2236 wrapnonlinear=dots,
2236 wrapnonlinear=dots,
2237 usedots=dots,
2237 usedots=dots,
2238 maxlinewidth=70):
2238 maxlinewidth=70):
2239 ui.write(line)
2239 ui.write(line)
2240 ui.write("\n")
2240 ui.write("\n")
2241
2241
2242 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2242 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2243 def debugdata(ui, repo, file_, rev=None, **opts):
2243 def debugdata(ui, repo, file_, rev=None, **opts):
2244 """dump the contents of a data file revision"""
2244 """dump the contents of a data file revision"""
2245 if opts.get('changelog') or opts.get('manifest'):
2245 if opts.get('changelog') or opts.get('manifest'):
2246 file_, rev = None, file_
2246 file_, rev = None, file_
2247 elif rev is None:
2247 elif rev is None:
2248 raise error.CommandError('debugdata', _('invalid arguments'))
2248 raise error.CommandError('debugdata', _('invalid arguments'))
2249 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2249 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2250 try:
2250 try:
2251 ui.write(r.revision(r.lookup(rev)))
2251 ui.write(r.revision(r.lookup(rev)))
2252 except KeyError:
2252 except KeyError:
2253 raise error.Abort(_('invalid revision identifier %s') % rev)
2253 raise error.Abort(_('invalid revision identifier %s') % rev)
2254
2254
2255 @command('debugdate',
2255 @command('debugdate',
2256 [('e', 'extended', None, _('try extended date formats'))],
2256 [('e', 'extended', None, _('try extended date formats'))],
2257 _('[-e] DATE [RANGE]'),
2257 _('[-e] DATE [RANGE]'),
2258 norepo=True, optionalrepo=True)
2258 norepo=True, optionalrepo=True)
2259 def debugdate(ui, date, range=None, **opts):
2259 def debugdate(ui, date, range=None, **opts):
2260 """parse and display a date"""
2260 """parse and display a date"""
2261 if opts["extended"]:
2261 if opts["extended"]:
2262 d = util.parsedate(date, util.extendeddateformats)
2262 d = util.parsedate(date, util.extendeddateformats)
2263 else:
2263 else:
2264 d = util.parsedate(date)
2264 d = util.parsedate(date)
2265 ui.write(("internal: %s %s\n") % d)
2265 ui.write(("internal: %s %s\n") % d)
2266 ui.write(("standard: %s\n") % util.datestr(d))
2266 ui.write(("standard: %s\n") % util.datestr(d))
2267 if range:
2267 if range:
2268 m = util.matchdate(range)
2268 m = util.matchdate(range)
2269 ui.write(("match: %s\n") % m(d[0]))
2269 ui.write(("match: %s\n") % m(d[0]))
2270
2270
2271 @command('debugdiscovery',
2271 @command('debugdiscovery',
2272 [('', 'old', None, _('use old-style discovery')),
2272 [('', 'old', None, _('use old-style discovery')),
2273 ('', 'nonheads', None,
2273 ('', 'nonheads', None,
2274 _('use old-style discovery with non-heads included')),
2274 _('use old-style discovery with non-heads included')),
2275 ] + remoteopts,
2275 ] + remoteopts,
2276 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2276 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2277 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2277 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2278 """runs the changeset discovery protocol in isolation"""
2278 """runs the changeset discovery protocol in isolation"""
2279 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2279 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2280 opts.get('branch'))
2280 opts.get('branch'))
2281 remote = hg.peer(repo, opts, remoteurl)
2281 remote = hg.peer(repo, opts, remoteurl)
2282 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2282 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2283
2283
2284 # make sure tests are repeatable
2284 # make sure tests are repeatable
2285 random.seed(12323)
2285 random.seed(12323)
2286
2286
2287 def doit(localheads, remoteheads, remote=remote):
2287 def doit(localheads, remoteheads, remote=remote):
2288 if opts.get('old'):
2288 if opts.get('old'):
2289 if localheads:
2289 if localheads:
2290 raise error.Abort('cannot use localheads with old style '
2290 raise error.Abort('cannot use localheads with old style '
2291 'discovery')
2291 'discovery')
2292 if not util.safehasattr(remote, 'branches'):
2292 if not util.safehasattr(remote, 'branches'):
2293 # enable in-client legacy support
2293 # enable in-client legacy support
2294 remote = localrepo.locallegacypeer(remote.local())
2294 remote = localrepo.locallegacypeer(remote.local())
2295 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2295 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2296 force=True)
2296 force=True)
2297 common = set(common)
2297 common = set(common)
2298 if not opts.get('nonheads'):
2298 if not opts.get('nonheads'):
2299 ui.write(("unpruned common: %s\n") %
2299 ui.write(("unpruned common: %s\n") %
2300 " ".join(sorted(short(n) for n in common)))
2300 " ".join(sorted(short(n) for n in common)))
2301 dag = dagutil.revlogdag(repo.changelog)
2301 dag = dagutil.revlogdag(repo.changelog)
2302 all = dag.ancestorset(dag.internalizeall(common))
2302 all = dag.ancestorset(dag.internalizeall(common))
2303 common = dag.externalizeall(dag.headsetofconnecteds(all))
2303 common = dag.externalizeall(dag.headsetofconnecteds(all))
2304 else:
2304 else:
2305 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2305 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2306 common = set(common)
2306 common = set(common)
2307 rheads = set(hds)
2307 rheads = set(hds)
2308 lheads = set(repo.heads())
2308 lheads = set(repo.heads())
2309 ui.write(("common heads: %s\n") %
2309 ui.write(("common heads: %s\n") %
2310 " ".join(sorted(short(n) for n in common)))
2310 " ".join(sorted(short(n) for n in common)))
2311 if lheads <= common:
2311 if lheads <= common:
2312 ui.write(("local is subset\n"))
2312 ui.write(("local is subset\n"))
2313 elif rheads <= common:
2313 elif rheads <= common:
2314 ui.write(("remote is subset\n"))
2314 ui.write(("remote is subset\n"))
2315
2315
2316 serverlogs = opts.get('serverlog')
2316 serverlogs = opts.get('serverlog')
2317 if serverlogs:
2317 if serverlogs:
2318 for filename in serverlogs:
2318 for filename in serverlogs:
2319 logfile = open(filename, 'r')
2319 logfile = open(filename, 'r')
2320 try:
2320 try:
2321 line = logfile.readline()
2321 line = logfile.readline()
2322 while line:
2322 while line:
2323 parts = line.strip().split(';')
2323 parts = line.strip().split(';')
2324 op = parts[1]
2324 op = parts[1]
2325 if op == 'cg':
2325 if op == 'cg':
2326 pass
2326 pass
2327 elif op == 'cgss':
2327 elif op == 'cgss':
2328 doit(parts[2].split(' '), parts[3].split(' '))
2328 doit(parts[2].split(' '), parts[3].split(' '))
2329 elif op == 'unb':
2329 elif op == 'unb':
2330 doit(parts[3].split(' '), parts[2].split(' '))
2330 doit(parts[3].split(' '), parts[2].split(' '))
2331 line = logfile.readline()
2331 line = logfile.readline()
2332 finally:
2332 finally:
2333 logfile.close()
2333 logfile.close()
2334
2334
2335 else:
2335 else:
2336 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2336 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2337 opts.get('remote_head'))
2337 opts.get('remote_head'))
2338 localrevs = opts.get('local_head')
2338 localrevs = opts.get('local_head')
2339 doit(localrevs, remoterevs)
2339 doit(localrevs, remoterevs)
2340
2340
2341 @command('debugextensions', formatteropts, [], norepo=True)
2341 @command('debugextensions', formatteropts, [], norepo=True)
2342 def debugextensions(ui, **opts):
2342 def debugextensions(ui, **opts):
2343 '''show information about active extensions'''
2343 '''show information about active extensions'''
2344 exts = extensions.extensions(ui)
2344 exts = extensions.extensions(ui)
2345 fm = ui.formatter('debugextensions', opts)
2345 fm = ui.formatter('debugextensions', opts)
2346 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2346 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2347 extsource = extmod.__file__
2347 extsource = extmod.__file__
2348 exttestedwith = getattr(extmod, 'testedwith', None)
2348 exttestedwith = getattr(extmod, 'testedwith', None)
2349 if exttestedwith is not None:
2349 if exttestedwith is not None:
2350 exttestedwith = exttestedwith.split()
2350 exttestedwith = exttestedwith.split()
2351 extbuglink = getattr(extmod, 'buglink', None)
2351 extbuglink = getattr(extmod, 'buglink', None)
2352
2352
2353 fm.startitem()
2353 fm.startitem()
2354
2354
2355 if ui.quiet or ui.verbose:
2355 if ui.quiet or ui.verbose:
2356 fm.write('name', '%s\n', extname)
2356 fm.write('name', '%s\n', extname)
2357 else:
2357 else:
2358 fm.write('name', '%s', extname)
2358 fm.write('name', '%s', extname)
2359 if not exttestedwith:
2359 if not exttestedwith:
2360 fm.plain(_(' (untested!)\n'))
2360 fm.plain(_(' (untested!)\n'))
2361 else:
2361 else:
2362 if exttestedwith == ['internal'] or \
2362 if exttestedwith == ['internal'] or \
2363 util.version() in exttestedwith:
2363 util.version() in exttestedwith:
2364 fm.plain('\n')
2364 fm.plain('\n')
2365 else:
2365 else:
2366 lasttestedversion = exttestedwith[-1]
2366 lasttestedversion = exttestedwith[-1]
2367 fm.plain(' (%s!)\n' % lasttestedversion)
2367 fm.plain(' (%s!)\n' % lasttestedversion)
2368
2368
2369 fm.condwrite(ui.verbose and extsource, 'source',
2369 fm.condwrite(ui.verbose and extsource, 'source',
2370 _(' location: %s\n'), extsource or "")
2370 _(' location: %s\n'), extsource or "")
2371
2371
2372 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2372 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2373 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2373 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2374
2374
2375 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2375 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2376 _(' bug reporting: %s\n'), extbuglink or "")
2376 _(' bug reporting: %s\n'), extbuglink or "")
2377
2377
2378 fm.end()
2378 fm.end()
2379
2379
2380 @command('debugfileset',
2380 @command('debugfileset',
2381 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2381 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2382 _('[-r REV] FILESPEC'))
2382 _('[-r REV] FILESPEC'))
2383 def debugfileset(ui, repo, expr, **opts):
2383 def debugfileset(ui, repo, expr, **opts):
2384 '''parse and apply a fileset specification'''
2384 '''parse and apply a fileset specification'''
2385 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2385 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2386 if ui.verbose:
2386 if ui.verbose:
2387 tree = fileset.parse(expr)
2387 tree = fileset.parse(expr)
2388 ui.note(fileset.prettyformat(tree), "\n")
2388 ui.note(fileset.prettyformat(tree), "\n")
2389
2389
2390 for f in ctx.getfileset(expr):
2390 for f in ctx.getfileset(expr):
2391 ui.write("%s\n" % f)
2391 ui.write("%s\n" % f)
2392
2392
2393 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2393 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2394 def debugfsinfo(ui, path="."):
2394 def debugfsinfo(ui, path="."):
2395 """show information detected about current filesystem"""
2395 """show information detected about current filesystem"""
2396 util.writefile('.debugfsinfo', '')
2396 util.writefile('.debugfsinfo', '')
2397 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2397 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2398 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2398 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2399 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2399 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2400 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2400 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2401 and 'yes' or 'no'))
2401 and 'yes' or 'no'))
2402 os.unlink('.debugfsinfo')
2402 os.unlink('.debugfsinfo')
2403
2403
2404 @command('debuggetbundle',
2404 @command('debuggetbundle',
2405 [('H', 'head', [], _('id of head node'), _('ID')),
2405 [('H', 'head', [], _('id of head node'), _('ID')),
2406 ('C', 'common', [], _('id of common node'), _('ID')),
2406 ('C', 'common', [], _('id of common node'), _('ID')),
2407 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2407 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2408 _('REPO FILE [-H|-C ID]...'),
2408 _('REPO FILE [-H|-C ID]...'),
2409 norepo=True)
2409 norepo=True)
2410 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2410 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2411 """retrieves a bundle from a repo
2411 """retrieves a bundle from a repo
2412
2412
2413 Every ID must be a full-length hex node id string. Saves the bundle to the
2413 Every ID must be a full-length hex node id string. Saves the bundle to the
2414 given file.
2414 given file.
2415 """
2415 """
2416 repo = hg.peer(ui, opts, repopath)
2416 repo = hg.peer(ui, opts, repopath)
2417 if not repo.capable('getbundle'):
2417 if not repo.capable('getbundle'):
2418 raise error.Abort("getbundle() not supported by target repository")
2418 raise error.Abort("getbundle() not supported by target repository")
2419 args = {}
2419 args = {}
2420 if common:
2420 if common:
2421 args['common'] = [bin(s) for s in common]
2421 args['common'] = [bin(s) for s in common]
2422 if head:
2422 if head:
2423 args['heads'] = [bin(s) for s in head]
2423 args['heads'] = [bin(s) for s in head]
2424 # TODO: get desired bundlecaps from command line.
2424 # TODO: get desired bundlecaps from command line.
2425 args['bundlecaps'] = None
2425 args['bundlecaps'] = None
2426 bundle = repo.getbundle('debug', **args)
2426 bundle = repo.getbundle('debug', **args)
2427
2427
2428 bundletype = opts.get('type', 'bzip2').lower()
2428 bundletype = opts.get('type', 'bzip2').lower()
2429 btypes = {'none': 'HG10UN',
2429 btypes = {'none': 'HG10UN',
2430 'bzip2': 'HG10BZ',
2430 'bzip2': 'HG10BZ',
2431 'gzip': 'HG10GZ',
2431 'gzip': 'HG10GZ',
2432 'bundle2': 'HG20'}
2432 'bundle2': 'HG20'}
2433 bundletype = btypes.get(bundletype)
2433 bundletype = btypes.get(bundletype)
2434 if bundletype not in changegroup.bundletypes:
2434 if bundletype not in changegroup.bundletypes:
2435 raise error.Abort(_('unknown bundle type specified with --type'))
2435 raise error.Abort(_('unknown bundle type specified with --type'))
2436 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2436 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2437
2437
2438 @command('debugignore', [], '')
2438 @command('debugignore', [], '')
2439 def debugignore(ui, repo, *values, **opts):
2439 def debugignore(ui, repo, *values, **opts):
2440 """display the combined ignore pattern"""
2440 """display the combined ignore pattern"""
2441 ignore = repo.dirstate._ignore
2441 ignore = repo.dirstate._ignore
2442 includepat = getattr(ignore, 'includepat', None)
2442 includepat = getattr(ignore, 'includepat', None)
2443 if includepat is not None:
2443 if includepat is not None:
2444 ui.write("%s\n" % includepat)
2444 ui.write("%s\n" % includepat)
2445 else:
2445 else:
2446 raise error.Abort(_("no ignore patterns found"))
2446 raise error.Abort(_("no ignore patterns found"))
2447
2447
2448 @command('debugindex', debugrevlogopts +
2448 @command('debugindex', debugrevlogopts +
2449 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2449 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2450 _('[-f FORMAT] -c|-m|FILE'),
2450 _('[-f FORMAT] -c|-m|FILE'),
2451 optionalrepo=True)
2451 optionalrepo=True)
2452 def debugindex(ui, repo, file_=None, **opts):
2452 def debugindex(ui, repo, file_=None, **opts):
2453 """dump the contents of an index file"""
2453 """dump the contents of an index file"""
2454 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2454 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2455 format = opts.get('format', 0)
2455 format = opts.get('format', 0)
2456 if format not in (0, 1):
2456 if format not in (0, 1):
2457 raise error.Abort(_("unknown format %d") % format)
2457 raise error.Abort(_("unknown format %d") % format)
2458
2458
2459 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2459 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2460 if generaldelta:
2460 if generaldelta:
2461 basehdr = ' delta'
2461 basehdr = ' delta'
2462 else:
2462 else:
2463 basehdr = ' base'
2463 basehdr = ' base'
2464
2464
2465 if ui.debugflag:
2465 if ui.debugflag:
2466 shortfn = hex
2466 shortfn = hex
2467 else:
2467 else:
2468 shortfn = short
2468 shortfn = short
2469
2469
2470 # There might not be anything in r, so have a sane default
2470 # There might not be anything in r, so have a sane default
2471 idlen = 12
2471 idlen = 12
2472 for i in r:
2472 for i in r:
2473 idlen = len(shortfn(r.node(i)))
2473 idlen = len(shortfn(r.node(i)))
2474 break
2474 break
2475
2475
2476 if format == 0:
2476 if format == 0:
2477 ui.write(" rev offset length " + basehdr + " linkrev"
2477 ui.write(" rev offset length " + basehdr + " linkrev"
2478 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2478 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2479 elif format == 1:
2479 elif format == 1:
2480 ui.write(" rev flag offset length"
2480 ui.write(" rev flag offset length"
2481 " size " + basehdr + " link p1 p2"
2481 " size " + basehdr + " link p1 p2"
2482 " %s\n" % "nodeid".rjust(idlen))
2482 " %s\n" % "nodeid".rjust(idlen))
2483
2483
2484 for i in r:
2484 for i in r:
2485 node = r.node(i)
2485 node = r.node(i)
2486 if generaldelta:
2486 if generaldelta:
2487 base = r.deltaparent(i)
2487 base = r.deltaparent(i)
2488 else:
2488 else:
2489 base = r.chainbase(i)
2489 base = r.chainbase(i)
2490 if format == 0:
2490 if format == 0:
2491 try:
2491 try:
2492 pp = r.parents(node)
2492 pp = r.parents(node)
2493 except Exception:
2493 except Exception:
2494 pp = [nullid, nullid]
2494 pp = [nullid, nullid]
2495 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2495 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2496 i, r.start(i), r.length(i), base, r.linkrev(i),
2496 i, r.start(i), r.length(i), base, r.linkrev(i),
2497 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2497 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2498 elif format == 1:
2498 elif format == 1:
2499 pr = r.parentrevs(i)
2499 pr = r.parentrevs(i)
2500 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2500 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2501 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2501 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2502 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2502 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2503
2503
2504 @command('debugindexdot', debugrevlogopts,
2504 @command('debugindexdot', debugrevlogopts,
2505 _('-c|-m|FILE'), optionalrepo=True)
2505 _('-c|-m|FILE'), optionalrepo=True)
2506 def debugindexdot(ui, repo, file_=None, **opts):
2506 def debugindexdot(ui, repo, file_=None, **opts):
2507 """dump an index DAG as a graphviz dot file"""
2507 """dump an index DAG as a graphviz dot file"""
2508 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2508 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2509 ui.write(("digraph G {\n"))
2509 ui.write(("digraph G {\n"))
2510 for i in r:
2510 for i in r:
2511 node = r.node(i)
2511 node = r.node(i)
2512 pp = r.parents(node)
2512 pp = r.parents(node)
2513 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2513 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2514 if pp[1] != nullid:
2514 if pp[1] != nullid:
2515 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2515 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2516 ui.write("}\n")
2516 ui.write("}\n")
2517
2517
2518 @command('debugdeltachain',
2518 @command('debugdeltachain',
2519 debugrevlogopts + formatteropts,
2519 debugrevlogopts + formatteropts,
2520 _('-c|-m|FILE'),
2520 _('-c|-m|FILE'),
2521 optionalrepo=True)
2521 optionalrepo=True)
2522 def debugdeltachain(ui, repo, file_=None, **opts):
2522 def debugdeltachain(ui, repo, file_=None, **opts):
2523 """dump information about delta chains in a revlog
2523 """dump information about delta chains in a revlog
2524
2524
2525 Output can be templatized. Available template keywords are:
2525 Output can be templatized. Available template keywords are:
2526
2526
2527 rev revision number
2527 rev revision number
2528 chainid delta chain identifier (numbered by unique base)
2528 chainid delta chain identifier (numbered by unique base)
2529 chainlen delta chain length to this revision
2529 chainlen delta chain length to this revision
2530 prevrev previous revision in delta chain
2530 prevrev previous revision in delta chain
2531 deltatype role of delta / how it was computed
2531 deltatype role of delta / how it was computed
2532 compsize compressed size of revision
2532 compsize compressed size of revision
2533 uncompsize uncompressed size of revision
2533 uncompsize uncompressed size of revision
2534 chainsize total size of compressed revisions in chain
2534 chainsize total size of compressed revisions in chain
2535 chainratio total chain size divided by uncompressed revision size
2535 chainratio total chain size divided by uncompressed revision size
2536 (new delta chains typically start at ratio 2.00)
2536 (new delta chains typically start at ratio 2.00)
2537 lindist linear distance from base revision in delta chain to end
2537 lindist linear distance from base revision in delta chain to end
2538 of this revision
2538 of this revision
2539 extradist total size of revisions not part of this delta chain from
2539 extradist total size of revisions not part of this delta chain from
2540 base of delta chain to end of this revision; a measurement
2540 base of delta chain to end of this revision; a measurement
2541 of how much extra data we need to read/seek across to read
2541 of how much extra data we need to read/seek across to read
2542 the delta chain for this revision
2542 the delta chain for this revision
2543 extraratio extradist divided by chainsize; another representation of
2543 extraratio extradist divided by chainsize; another representation of
2544 how much unrelated data is needed to load this delta chain
2544 how much unrelated data is needed to load this delta chain
2545 """
2545 """
2546 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2546 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2547 index = r.index
2547 index = r.index
2548 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2549
2549
2550 def revinfo(rev):
2550 def revinfo(rev):
2551 e = index[rev]
2551 e = index[rev]
2552 compsize = e[1]
2552 compsize = e[1]
2553 uncompsize = e[2]
2553 uncompsize = e[2]
2554 chainsize = 0
2554 chainsize = 0
2555
2555
2556 if generaldelta:
2556 if generaldelta:
2557 if e[3] == e[5]:
2557 if e[3] == e[5]:
2558 deltatype = 'p1'
2558 deltatype = 'p1'
2559 elif e[3] == e[6]:
2559 elif e[3] == e[6]:
2560 deltatype = 'p2'
2560 deltatype = 'p2'
2561 elif e[3] == rev - 1:
2561 elif e[3] == rev - 1:
2562 deltatype = 'prev'
2562 deltatype = 'prev'
2563 elif e[3] == rev:
2563 elif e[3] == rev:
2564 deltatype = 'base'
2564 deltatype = 'base'
2565 else:
2565 else:
2566 deltatype = 'other'
2566 deltatype = 'other'
2567 else:
2567 else:
2568 if e[3] == rev:
2568 if e[3] == rev:
2569 deltatype = 'base'
2569 deltatype = 'base'
2570 else:
2570 else:
2571 deltatype = 'prev'
2571 deltatype = 'prev'
2572
2572
2573 chain = r._deltachain(rev)[0]
2573 chain = r._deltachain(rev)[0]
2574 for iterrev in chain:
2574 for iterrev in chain:
2575 e = index[iterrev]
2575 e = index[iterrev]
2576 chainsize += e[1]
2576 chainsize += e[1]
2577
2577
2578 return compsize, uncompsize, deltatype, chain, chainsize
2578 return compsize, uncompsize, deltatype, chain, chainsize
2579
2579
2580 fm = ui.formatter('debugdeltachain', opts)
2580 fm = ui.formatter('debugdeltachain', opts)
2581
2581
2582 fm.plain(' rev chain# chainlen prev delta '
2582 fm.plain(' rev chain# chainlen prev delta '
2583 'size rawsize chainsize ratio lindist extradist '
2583 'size rawsize chainsize ratio lindist extradist '
2584 'extraratio\n')
2584 'extraratio\n')
2585
2585
2586 chainbases = {}
2586 chainbases = {}
2587 for rev in r:
2587 for rev in r:
2588 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2588 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2589 chainbase = chain[0]
2589 chainbase = chain[0]
2590 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2590 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2591 basestart = r.start(chainbase)
2591 basestart = r.start(chainbase)
2592 revstart = r.start(rev)
2592 revstart = r.start(rev)
2593 lineardist = revstart + comp - basestart
2593 lineardist = revstart + comp - basestart
2594 extradist = lineardist - chainsize
2594 extradist = lineardist - chainsize
2595 try:
2595 try:
2596 prevrev = chain[-2]
2596 prevrev = chain[-2]
2597 except IndexError:
2597 except IndexError:
2598 prevrev = -1
2598 prevrev = -1
2599
2599
2600 chainratio = float(chainsize) / float(uncomp)
2600 chainratio = float(chainsize) / float(uncomp)
2601 extraratio = float(extradist) / float(chainsize)
2601 extraratio = float(extradist) / float(chainsize)
2602
2602
2603 fm.startitem()
2603 fm.startitem()
2604 fm.write('rev chainid chainlen prevrev deltatype compsize '
2604 fm.write('rev chainid chainlen prevrev deltatype compsize '
2605 'uncompsize chainsize chainratio lindist extradist '
2605 'uncompsize chainsize chainratio lindist extradist '
2606 'extraratio',
2606 'extraratio',
2607 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2607 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2608 rev, chainid, len(chain), prevrev, deltatype, comp,
2608 rev, chainid, len(chain), prevrev, deltatype, comp,
2609 uncomp, chainsize, chainratio, lineardist, extradist,
2609 uncomp, chainsize, chainratio, lineardist, extradist,
2610 extraratio,
2610 extraratio,
2611 rev=rev, chainid=chainid, chainlen=len(chain),
2611 rev=rev, chainid=chainid, chainlen=len(chain),
2612 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2612 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2613 uncompsize=uncomp, chainsize=chainsize,
2613 uncompsize=uncomp, chainsize=chainsize,
2614 chainratio=chainratio, lindist=lineardist,
2614 chainratio=chainratio, lindist=lineardist,
2615 extradist=extradist, extraratio=extraratio)
2615 extradist=extradist, extraratio=extraratio)
2616
2616
2617 fm.end()
2617 fm.end()
2618
2618
2619 @command('debuginstall', [], '', norepo=True)
2619 @command('debuginstall', [], '', norepo=True)
2620 def debuginstall(ui):
2620 def debuginstall(ui):
2621 '''test Mercurial installation
2621 '''test Mercurial installation
2622
2622
2623 Returns 0 on success.
2623 Returns 0 on success.
2624 '''
2624 '''
2625
2625
2626 def writetemp(contents):
2626 def writetemp(contents):
2627 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2627 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2628 f = os.fdopen(fd, "wb")
2628 f = os.fdopen(fd, "wb")
2629 f.write(contents)
2629 f.write(contents)
2630 f.close()
2630 f.close()
2631 return name
2631 return name
2632
2632
2633 problems = 0
2633 problems = 0
2634
2634
2635 # encoding
2635 # encoding
2636 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2636 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2637 try:
2637 try:
2638 encoding.fromlocal("test")
2638 encoding.fromlocal("test")
2639 except error.Abort as inst:
2639 except error.Abort as inst:
2640 ui.write(" %s\n" % inst)
2640 ui.write(" %s\n" % inst)
2641 ui.write(_(" (check that your locale is properly set)\n"))
2641 ui.write(_(" (check that your locale is properly set)\n"))
2642 problems += 1
2642 problems += 1
2643
2643
2644 # Python
2644 # Python
2645 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2645 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2646 ui.status(_("checking Python version (%s)\n")
2646 ui.status(_("checking Python version (%s)\n")
2647 % ("%s.%s.%s" % sys.version_info[:3]))
2647 % ("%s.%s.%s" % sys.version_info[:3]))
2648 ui.status(_("checking Python lib (%s)...\n")
2648 ui.status(_("checking Python lib (%s)...\n")
2649 % os.path.dirname(os.__file__))
2649 % os.path.dirname(os.__file__))
2650
2650
2651 # compiled modules
2651 # compiled modules
2652 ui.status(_("checking installed modules (%s)...\n")
2652 ui.status(_("checking installed modules (%s)...\n")
2653 % os.path.dirname(__file__))
2653 % os.path.dirname(__file__))
2654 try:
2654 try:
2655 import bdiff, mpatch, base85, osutil
2655 import bdiff, mpatch, base85, osutil
2656 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2656 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2657 except Exception as inst:
2657 except Exception as inst:
2658 ui.write(" %s\n" % inst)
2658 ui.write(" %s\n" % inst)
2659 ui.write(_(" One or more extensions could not be found"))
2659 ui.write(_(" One or more extensions could not be found"))
2660 ui.write(_(" (check that you compiled the extensions)\n"))
2660 ui.write(_(" (check that you compiled the extensions)\n"))
2661 problems += 1
2661 problems += 1
2662
2662
2663 # templates
2663 # templates
2664 import templater
2664 import templater
2665 p = templater.templatepaths()
2665 p = templater.templatepaths()
2666 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2666 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2667 if p:
2667 if p:
2668 m = templater.templatepath("map-cmdline.default")
2668 m = templater.templatepath("map-cmdline.default")
2669 if m:
2669 if m:
2670 # template found, check if it is working
2670 # template found, check if it is working
2671 try:
2671 try:
2672 templater.templater(m)
2672 templater.templater(m)
2673 except Exception as inst:
2673 except Exception as inst:
2674 ui.write(" %s\n" % inst)
2674 ui.write(" %s\n" % inst)
2675 p = None
2675 p = None
2676 else:
2676 else:
2677 ui.write(_(" template 'default' not found\n"))
2677 ui.write(_(" template 'default' not found\n"))
2678 p = None
2678 p = None
2679 else:
2679 else:
2680 ui.write(_(" no template directories found\n"))
2680 ui.write(_(" no template directories found\n"))
2681 if not p:
2681 if not p:
2682 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2682 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2683 problems += 1
2683 problems += 1
2684
2684
2685 # editor
2685 # editor
2686 ui.status(_("checking commit editor...\n"))
2686 ui.status(_("checking commit editor...\n"))
2687 editor = ui.geteditor()
2687 editor = ui.geteditor()
2688 editor = util.expandpath(editor)
2688 editor = util.expandpath(editor)
2689 cmdpath = util.findexe(shlex.split(editor)[0])
2689 cmdpath = util.findexe(shlex.split(editor)[0])
2690 if not cmdpath:
2690 if not cmdpath:
2691 if editor == 'vi':
2691 if editor == 'vi':
2692 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2692 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2693 ui.write(_(" (specify a commit editor in your configuration"
2693 ui.write(_(" (specify a commit editor in your configuration"
2694 " file)\n"))
2694 " file)\n"))
2695 else:
2695 else:
2696 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2696 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2697 ui.write(_(" (specify a commit editor in your configuration"
2697 ui.write(_(" (specify a commit editor in your configuration"
2698 " file)\n"))
2698 " file)\n"))
2699 problems += 1
2699 problems += 1
2700
2700
2701 # check username
2701 # check username
2702 ui.status(_("checking username...\n"))
2702 ui.status(_("checking username...\n"))
2703 try:
2703 try:
2704 ui.username()
2704 ui.username()
2705 except error.Abort as e:
2705 except error.Abort as e:
2706 ui.write(" %s\n" % e)
2706 ui.write(" %s\n" % e)
2707 ui.write(_(" (specify a username in your configuration file)\n"))
2707 ui.write(_(" (specify a username in your configuration file)\n"))
2708 problems += 1
2708 problems += 1
2709
2709
2710 if not problems:
2710 if not problems:
2711 ui.status(_("no problems detected\n"))
2711 ui.status(_("no problems detected\n"))
2712 else:
2712 else:
2713 ui.write(_("%s problems detected,"
2713 ui.write(_("%s problems detected,"
2714 " please check your install!\n") % problems)
2714 " please check your install!\n") % problems)
2715
2715
2716 return problems
2716 return problems
2717
2717
2718 @command('debugknown', [], _('REPO ID...'), norepo=True)
2718 @command('debugknown', [], _('REPO ID...'), norepo=True)
2719 def debugknown(ui, repopath, *ids, **opts):
2719 def debugknown(ui, repopath, *ids, **opts):
2720 """test whether node ids are known to a repo
2720 """test whether node ids are known to a repo
2721
2721
2722 Every ID must be a full-length hex node id string. Returns a list of 0s
2722 Every ID must be a full-length hex node id string. Returns a list of 0s
2723 and 1s indicating unknown/known.
2723 and 1s indicating unknown/known.
2724 """
2724 """
2725 repo = hg.peer(ui, opts, repopath)
2725 repo = hg.peer(ui, opts, repopath)
2726 if not repo.capable('known'):
2726 if not repo.capable('known'):
2727 raise error.Abort("known() not supported by target repository")
2727 raise error.Abort("known() not supported by target repository")
2728 flags = repo.known([bin(s) for s in ids])
2728 flags = repo.known([bin(s) for s in ids])
2729 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2729 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2730
2730
2731 @command('debuglabelcomplete', [], _('LABEL...'))
2731 @command('debuglabelcomplete', [], _('LABEL...'))
2732 def debuglabelcomplete(ui, repo, *args):
2732 def debuglabelcomplete(ui, repo, *args):
2733 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2733 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2734 debugnamecomplete(ui, repo, *args)
2734 debugnamecomplete(ui, repo, *args)
2735
2735
2736 @command('debugmergestate', [], '')
2736 @command('debugmergestate', [], '')
2737 def debugmergestate(ui, repo, *args):
2737 def debugmergestate(ui, repo, *args):
2738 """print merge state
2738 """print merge state
2739
2739
2740 Use --verbose to print out information about whether v1 or v2 merge state
2740 Use --verbose to print out information about whether v1 or v2 merge state
2741 was chosen."""
2741 was chosen."""
2742 def _hashornull(h):
2742 def _hashornull(h):
2743 if h == nullhex:
2743 if h == nullhex:
2744 return 'null'
2744 return 'null'
2745 else:
2745 else:
2746 return h
2746 return h
2747
2747
2748 def printrecords(version):
2748 def printrecords(version):
2749 ui.write(('* version %s records\n') % version)
2749 ui.write(('* version %s records\n') % version)
2750 if version == 1:
2750 if version == 1:
2751 records = v1records
2751 records = v1records
2752 else:
2752 else:
2753 records = v2records
2753 records = v2records
2754
2754
2755 for rtype, record in records:
2755 for rtype, record in records:
2756 # pretty print some record types
2756 # pretty print some record types
2757 if rtype == 'L':
2757 if rtype == 'L':
2758 ui.write(('local: %s\n') % record)
2758 ui.write(('local: %s\n') % record)
2759 elif rtype == 'O':
2759 elif rtype == 'O':
2760 ui.write(('other: %s\n') % record)
2760 ui.write(('other: %s\n') % record)
2761 elif rtype == 'm':
2761 elif rtype == 'm':
2762 driver, mdstate = record.split('\0', 1)
2762 driver, mdstate = record.split('\0', 1)
2763 ui.write(('merge driver: %s (state "%s")\n')
2763 ui.write(('merge driver: %s (state "%s")\n')
2764 % (driver, mdstate))
2764 % (driver, mdstate))
2765 elif rtype in 'FDC':
2765 elif rtype in 'FDC':
2766 r = record.split('\0')
2766 r = record.split('\0')
2767 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2767 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2768 if version == 1:
2768 if version == 1:
2769 onode = 'not stored in v1 format'
2769 onode = 'not stored in v1 format'
2770 flags = r[7]
2770 flags = r[7]
2771 else:
2771 else:
2772 onode, flags = r[7:9]
2772 onode, flags = r[7:9]
2773 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2773 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2774 % (f, rtype, state, _hashornull(hash)))
2774 % (f, rtype, state, _hashornull(hash)))
2775 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2775 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2776 ui.write((' ancestor path: %s (node %s)\n')
2776 ui.write((' ancestor path: %s (node %s)\n')
2777 % (afile, _hashornull(anode)))
2777 % (afile, _hashornull(anode)))
2778 ui.write((' other path: %s (node %s)\n')
2778 ui.write((' other path: %s (node %s)\n')
2779 % (ofile, _hashornull(onode)))
2779 % (ofile, _hashornull(onode)))
2780 else:
2780 else:
2781 ui.write(('unrecognized entry: %s\t%s\n')
2781 ui.write(('unrecognized entry: %s\t%s\n')
2782 % (rtype, record.replace('\0', '\t')))
2782 % (rtype, record.replace('\0', '\t')))
2783
2783
2784 # Avoid mergestate.read() since it may raise an exception for unsupported
2784 # Avoid mergestate.read() since it may raise an exception for unsupported
2785 # merge state records. We shouldn't be doing this, but this is OK since this
2785 # merge state records. We shouldn't be doing this, but this is OK since this
2786 # command is pretty low-level.
2786 # command is pretty low-level.
2787 ms = mergemod.mergestate(repo)
2787 ms = mergemod.mergestate(repo)
2788
2788
2789 # sort so that reasonable information is on top
2789 # sort so that reasonable information is on top
2790 v1records = ms._readrecordsv1()
2790 v1records = ms._readrecordsv1()
2791 v2records = ms._readrecordsv2()
2791 v2records = ms._readrecordsv2()
2792 order = 'LOm'
2792 order = 'LOm'
2793 def key(r):
2793 def key(r):
2794 idx = order.find(r[0])
2794 idx = order.find(r[0])
2795 if idx == -1:
2795 if idx == -1:
2796 return (1, r[1])
2796 return (1, r[1])
2797 else:
2797 else:
2798 return (0, idx)
2798 return (0, idx)
2799 v1records.sort(key=key)
2799 v1records.sort(key=key)
2800 v2records.sort(key=key)
2800 v2records.sort(key=key)
2801
2801
2802 if not v1records and not v2records:
2802 if not v1records and not v2records:
2803 ui.write(('no merge state found\n'))
2803 ui.write(('no merge state found\n'))
2804 elif not v2records:
2804 elif not v2records:
2805 ui.note(('no version 2 merge state\n'))
2805 ui.note(('no version 2 merge state\n'))
2806 printrecords(1)
2806 printrecords(1)
2807 elif ms._v1v2match(v1records, v2records):
2807 elif ms._v1v2match(v1records, v2records):
2808 ui.note(('v1 and v2 states match: using v2\n'))
2808 ui.note(('v1 and v2 states match: using v2\n'))
2809 printrecords(2)
2809 printrecords(2)
2810 else:
2810 else:
2811 ui.note(('v1 and v2 states mismatch: using v1\n'))
2811 ui.note(('v1 and v2 states mismatch: using v1\n'))
2812 printrecords(1)
2812 printrecords(1)
2813 if ui.verbose:
2813 if ui.verbose:
2814 printrecords(2)
2814 printrecords(2)
2815
2815
2816 @command('debugnamecomplete', [], _('NAME...'))
2816 @command('debugnamecomplete', [], _('NAME...'))
2817 def debugnamecomplete(ui, repo, *args):
2817 def debugnamecomplete(ui, repo, *args):
2818 '''complete "names" - tags, open branch names, bookmark names'''
2818 '''complete "names" - tags, open branch names, bookmark names'''
2819
2819
2820 names = set()
2820 names = set()
2821 # since we previously only listed open branches, we will handle that
2821 # since we previously only listed open branches, we will handle that
2822 # specially (after this for loop)
2822 # specially (after this for loop)
2823 for name, ns in repo.names.iteritems():
2823 for name, ns in repo.names.iteritems():
2824 if name != 'branches':
2824 if name != 'branches':
2825 names.update(ns.listnames(repo))
2825 names.update(ns.listnames(repo))
2826 names.update(tag for (tag, heads, tip, closed)
2826 names.update(tag for (tag, heads, tip, closed)
2827 in repo.branchmap().iterbranches() if not closed)
2827 in repo.branchmap().iterbranches() if not closed)
2828 completions = set()
2828 completions = set()
2829 if not args:
2829 if not args:
2830 args = ['']
2830 args = ['']
2831 for a in args:
2831 for a in args:
2832 completions.update(n for n in names if n.startswith(a))
2832 completions.update(n for n in names if n.startswith(a))
2833 ui.write('\n'.join(sorted(completions)))
2833 ui.write('\n'.join(sorted(completions)))
2834 ui.write('\n')
2834 ui.write('\n')
2835
2835
2836 @command('debuglocks',
2836 @command('debuglocks',
2837 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2837 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2838 ('W', 'force-wlock', None,
2838 ('W', 'force-wlock', None,
2839 _('free the working state lock (DANGEROUS)'))],
2839 _('free the working state lock (DANGEROUS)'))],
2840 _('[OPTION]...'))
2840 _('[OPTION]...'))
2841 def debuglocks(ui, repo, **opts):
2841 def debuglocks(ui, repo, **opts):
2842 """show or modify state of locks
2842 """show or modify state of locks
2843
2843
2844 By default, this command will show which locks are held. This
2844 By default, this command will show which locks are held. This
2845 includes the user and process holding the lock, the amount of time
2845 includes the user and process holding the lock, the amount of time
2846 the lock has been held, and the machine name where the process is
2846 the lock has been held, and the machine name where the process is
2847 running if it's not local.
2847 running if it's not local.
2848
2848
2849 Locks protect the integrity of Mercurial's data, so should be
2849 Locks protect the integrity of Mercurial's data, so should be
2850 treated with care. System crashes or other interruptions may cause
2850 treated with care. System crashes or other interruptions may cause
2851 locks to not be properly released, though Mercurial will usually
2851 locks to not be properly released, though Mercurial will usually
2852 detect and remove such stale locks automatically.
2852 detect and remove such stale locks automatically.
2853
2853
2854 However, detecting stale locks may not always be possible (for
2854 However, detecting stale locks may not always be possible (for
2855 instance, on a shared filesystem). Removing locks may also be
2855 instance, on a shared filesystem). Removing locks may also be
2856 blocked by filesystem permissions.
2856 blocked by filesystem permissions.
2857
2857
2858 Returns 0 if no locks are held.
2858 Returns 0 if no locks are held.
2859
2859
2860 """
2860 """
2861
2861
2862 if opts.get('force_lock'):
2862 if opts.get('force_lock'):
2863 repo.svfs.unlink('lock')
2863 repo.svfs.unlink('lock')
2864 if opts.get('force_wlock'):
2864 if opts.get('force_wlock'):
2865 repo.vfs.unlink('wlock')
2865 repo.vfs.unlink('wlock')
2866 if opts.get('force_lock') or opts.get('force_lock'):
2866 if opts.get('force_lock') or opts.get('force_lock'):
2867 return 0
2867 return 0
2868
2868
2869 now = time.time()
2869 now = time.time()
2870 held = 0
2870 held = 0
2871
2871
2872 def report(vfs, name, method):
2872 def report(vfs, name, method):
2873 # this causes stale locks to get reaped for more accurate reporting
2873 # this causes stale locks to get reaped for more accurate reporting
2874 try:
2874 try:
2875 l = method(False)
2875 l = method(False)
2876 except error.LockHeld:
2876 except error.LockHeld:
2877 l = None
2877 l = None
2878
2878
2879 if l:
2879 if l:
2880 l.release()
2880 l.release()
2881 else:
2881 else:
2882 try:
2882 try:
2883 stat = vfs.lstat(name)
2883 stat = vfs.lstat(name)
2884 age = now - stat.st_mtime
2884 age = now - stat.st_mtime
2885 user = util.username(stat.st_uid)
2885 user = util.username(stat.st_uid)
2886 locker = vfs.readlock(name)
2886 locker = vfs.readlock(name)
2887 if ":" in locker:
2887 if ":" in locker:
2888 host, pid = locker.split(':')
2888 host, pid = locker.split(':')
2889 if host == socket.gethostname():
2889 if host == socket.gethostname():
2890 locker = 'user %s, process %s' % (user, pid)
2890 locker = 'user %s, process %s' % (user, pid)
2891 else:
2891 else:
2892 locker = 'user %s, process %s, host %s' \
2892 locker = 'user %s, process %s, host %s' \
2893 % (user, pid, host)
2893 % (user, pid, host)
2894 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2894 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2895 return 1
2895 return 1
2896 except OSError as e:
2896 except OSError as e:
2897 if e.errno != errno.ENOENT:
2897 if e.errno != errno.ENOENT:
2898 raise
2898 raise
2899
2899
2900 ui.write("%-6s free\n" % (name + ":"))
2900 ui.write("%-6s free\n" % (name + ":"))
2901 return 0
2901 return 0
2902
2902
2903 held += report(repo.svfs, "lock", repo.lock)
2903 held += report(repo.svfs, "lock", repo.lock)
2904 held += report(repo.vfs, "wlock", repo.wlock)
2904 held += report(repo.vfs, "wlock", repo.wlock)
2905
2905
2906 return held
2906 return held
2907
2907
2908 @command('debugobsolete',
2908 @command('debugobsolete',
2909 [('', 'flags', 0, _('markers flag')),
2909 [('', 'flags', 0, _('markers flag')),
2910 ('', 'record-parents', False,
2910 ('', 'record-parents', False,
2911 _('record parent information for the precursor')),
2911 _('record parent information for the precursor')),
2912 ('r', 'rev', [], _('display markers relevant to REV')),
2912 ('r', 'rev', [], _('display markers relevant to REV')),
2913 ] + commitopts2,
2913 ] + commitopts2,
2914 _('[OBSOLETED [REPLACEMENT ...]]'))
2914 _('[OBSOLETED [REPLACEMENT ...]]'))
2915 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2915 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2916 """create arbitrary obsolete marker
2916 """create arbitrary obsolete marker
2917
2917
2918 With no arguments, displays the list of obsolescence markers."""
2918 With no arguments, displays the list of obsolescence markers."""
2919
2919
2920 def parsenodeid(s):
2920 def parsenodeid(s):
2921 try:
2921 try:
2922 # We do not use revsingle/revrange functions here to accept
2922 # We do not use revsingle/revrange functions here to accept
2923 # arbitrary node identifiers, possibly not present in the
2923 # arbitrary node identifiers, possibly not present in the
2924 # local repository.
2924 # local repository.
2925 n = bin(s)
2925 n = bin(s)
2926 if len(n) != len(nullid):
2926 if len(n) != len(nullid):
2927 raise TypeError()
2927 raise TypeError()
2928 return n
2928 return n
2929 except TypeError:
2929 except TypeError:
2930 raise error.Abort('changeset references must be full hexadecimal '
2930 raise error.Abort('changeset references must be full hexadecimal '
2931 'node identifiers')
2931 'node identifiers')
2932
2932
2933 if precursor is not None:
2933 if precursor is not None:
2934 if opts['rev']:
2934 if opts['rev']:
2935 raise error.Abort('cannot select revision when creating marker')
2935 raise error.Abort('cannot select revision when creating marker')
2936 metadata = {}
2936 metadata = {}
2937 metadata['user'] = opts['user'] or ui.username()
2937 metadata['user'] = opts['user'] or ui.username()
2938 succs = tuple(parsenodeid(succ) for succ in successors)
2938 succs = tuple(parsenodeid(succ) for succ in successors)
2939 l = repo.lock()
2939 l = repo.lock()
2940 try:
2940 try:
2941 tr = repo.transaction('debugobsolete')
2941 tr = repo.transaction('debugobsolete')
2942 try:
2942 try:
2943 date = opts.get('date')
2943 date = opts.get('date')
2944 if date:
2944 if date:
2945 date = util.parsedate(date)
2945 date = util.parsedate(date)
2946 else:
2946 else:
2947 date = None
2947 date = None
2948 prec = parsenodeid(precursor)
2948 prec = parsenodeid(precursor)
2949 parents = None
2949 parents = None
2950 if opts['record_parents']:
2950 if opts['record_parents']:
2951 if prec not in repo.unfiltered():
2951 if prec not in repo.unfiltered():
2952 raise error.Abort('cannot used --record-parents on '
2952 raise error.Abort('cannot used --record-parents on '
2953 'unknown changesets')
2953 'unknown changesets')
2954 parents = repo.unfiltered()[prec].parents()
2954 parents = repo.unfiltered()[prec].parents()
2955 parents = tuple(p.node() for p in parents)
2955 parents = tuple(p.node() for p in parents)
2956 repo.obsstore.create(tr, prec, succs, opts['flags'],
2956 repo.obsstore.create(tr, prec, succs, opts['flags'],
2957 parents=parents, date=date,
2957 parents=parents, date=date,
2958 metadata=metadata)
2958 metadata=metadata)
2959 tr.close()
2959 tr.close()
2960 except ValueError as exc:
2960 except ValueError as exc:
2961 raise error.Abort(_('bad obsmarker input: %s') % exc)
2961 raise error.Abort(_('bad obsmarker input: %s') % exc)
2962 finally:
2962 finally:
2963 tr.release()
2963 tr.release()
2964 finally:
2964 finally:
2965 l.release()
2965 l.release()
2966 else:
2966 else:
2967 if opts['rev']:
2967 if opts['rev']:
2968 revs = scmutil.revrange(repo, opts['rev'])
2968 revs = scmutil.revrange(repo, opts['rev'])
2969 nodes = [repo[r].node() for r in revs]
2969 nodes = [repo[r].node() for r in revs]
2970 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2970 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2971 markers.sort(key=lambda x: x._data)
2971 markers.sort(key=lambda x: x._data)
2972 else:
2972 else:
2973 markers = obsolete.getmarkers(repo)
2973 markers = obsolete.getmarkers(repo)
2974
2974
2975 for m in markers:
2975 for m in markers:
2976 cmdutil.showmarker(ui, m)
2976 cmdutil.showmarker(ui, m)
2977
2977
2978 @command('debugpathcomplete',
2978 @command('debugpathcomplete',
2979 [('f', 'full', None, _('complete an entire path')),
2979 [('f', 'full', None, _('complete an entire path')),
2980 ('n', 'normal', None, _('show only normal files')),
2980 ('n', 'normal', None, _('show only normal files')),
2981 ('a', 'added', None, _('show only added files')),
2981 ('a', 'added', None, _('show only added files')),
2982 ('r', 'removed', None, _('show only removed files'))],
2982 ('r', 'removed', None, _('show only removed files'))],
2983 _('FILESPEC...'))
2983 _('FILESPEC...'))
2984 def debugpathcomplete(ui, repo, *specs, **opts):
2984 def debugpathcomplete(ui, repo, *specs, **opts):
2985 '''complete part or all of a tracked path
2985 '''complete part or all of a tracked path
2986
2986
2987 This command supports shells that offer path name completion. It
2987 This command supports shells that offer path name completion. It
2988 currently completes only files already known to the dirstate.
2988 currently completes only files already known to the dirstate.
2989
2989
2990 Completion extends only to the next path segment unless
2990 Completion extends only to the next path segment unless
2991 --full is specified, in which case entire paths are used.'''
2991 --full is specified, in which case entire paths are used.'''
2992
2992
2993 def complete(path, acceptable):
2993 def complete(path, acceptable):
2994 dirstate = repo.dirstate
2994 dirstate = repo.dirstate
2995 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2995 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2996 rootdir = repo.root + os.sep
2996 rootdir = repo.root + os.sep
2997 if spec != repo.root and not spec.startswith(rootdir):
2997 if spec != repo.root and not spec.startswith(rootdir):
2998 return [], []
2998 return [], []
2999 if os.path.isdir(spec):
2999 if os.path.isdir(spec):
3000 spec += '/'
3000 spec += '/'
3001 spec = spec[len(rootdir):]
3001 spec = spec[len(rootdir):]
3002 fixpaths = os.sep != '/'
3002 fixpaths = os.sep != '/'
3003 if fixpaths:
3003 if fixpaths:
3004 spec = spec.replace(os.sep, '/')
3004 spec = spec.replace(os.sep, '/')
3005 speclen = len(spec)
3005 speclen = len(spec)
3006 fullpaths = opts['full']
3006 fullpaths = opts['full']
3007 files, dirs = set(), set()
3007 files, dirs = set(), set()
3008 adddir, addfile = dirs.add, files.add
3008 adddir, addfile = dirs.add, files.add
3009 for f, st in dirstate.iteritems():
3009 for f, st in dirstate.iteritems():
3010 if f.startswith(spec) and st[0] in acceptable:
3010 if f.startswith(spec) and st[0] in acceptable:
3011 if fixpaths:
3011 if fixpaths:
3012 f = f.replace('/', os.sep)
3012 f = f.replace('/', os.sep)
3013 if fullpaths:
3013 if fullpaths:
3014 addfile(f)
3014 addfile(f)
3015 continue
3015 continue
3016 s = f.find(os.sep, speclen)
3016 s = f.find(os.sep, speclen)
3017 if s >= 0:
3017 if s >= 0:
3018 adddir(f[:s])
3018 adddir(f[:s])
3019 else:
3019 else:
3020 addfile(f)
3020 addfile(f)
3021 return files, dirs
3021 return files, dirs
3022
3022
3023 acceptable = ''
3023 acceptable = ''
3024 if opts['normal']:
3024 if opts['normal']:
3025 acceptable += 'nm'
3025 acceptable += 'nm'
3026 if opts['added']:
3026 if opts['added']:
3027 acceptable += 'a'
3027 acceptable += 'a'
3028 if opts['removed']:
3028 if opts['removed']:
3029 acceptable += 'r'
3029 acceptable += 'r'
3030 cwd = repo.getcwd()
3030 cwd = repo.getcwd()
3031 if not specs:
3031 if not specs:
3032 specs = ['.']
3032 specs = ['.']
3033
3033
3034 files, dirs = set(), set()
3034 files, dirs = set(), set()
3035 for spec in specs:
3035 for spec in specs:
3036 f, d = complete(spec, acceptable or 'nmar')
3036 f, d = complete(spec, acceptable or 'nmar')
3037 files.update(f)
3037 files.update(f)
3038 dirs.update(d)
3038 dirs.update(d)
3039 files.update(dirs)
3039 files.update(dirs)
3040 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3040 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3041 ui.write('\n')
3041 ui.write('\n')
3042
3042
3043 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3043 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3044 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3044 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3045 '''access the pushkey key/value protocol
3045 '''access the pushkey key/value protocol
3046
3046
3047 With two args, list the keys in the given namespace.
3047 With two args, list the keys in the given namespace.
3048
3048
3049 With five args, set a key to new if it currently is set to old.
3049 With five args, set a key to new if it currently is set to old.
3050 Reports success or failure.
3050 Reports success or failure.
3051 '''
3051 '''
3052
3052
3053 target = hg.peer(ui, {}, repopath)
3053 target = hg.peer(ui, {}, repopath)
3054 if keyinfo:
3054 if keyinfo:
3055 key, old, new = keyinfo
3055 key, old, new = keyinfo
3056 r = target.pushkey(namespace, key, old, new)
3056 r = target.pushkey(namespace, key, old, new)
3057 ui.status(str(r) + '\n')
3057 ui.status(str(r) + '\n')
3058 return not r
3058 return not r
3059 else:
3059 else:
3060 for k, v in sorted(target.listkeys(namespace).iteritems()):
3060 for k, v in sorted(target.listkeys(namespace).iteritems()):
3061 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3061 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3062 v.encode('string-escape')))
3062 v.encode('string-escape')))
3063
3063
3064 @command('debugpvec', [], _('A B'))
3064 @command('debugpvec', [], _('A B'))
3065 def debugpvec(ui, repo, a, b=None):
3065 def debugpvec(ui, repo, a, b=None):
3066 ca = scmutil.revsingle(repo, a)
3066 ca = scmutil.revsingle(repo, a)
3067 cb = scmutil.revsingle(repo, b)
3067 cb = scmutil.revsingle(repo, b)
3068 pa = pvec.ctxpvec(ca)
3068 pa = pvec.ctxpvec(ca)
3069 pb = pvec.ctxpvec(cb)
3069 pb = pvec.ctxpvec(cb)
3070 if pa == pb:
3070 if pa == pb:
3071 rel = "="
3071 rel = "="
3072 elif pa > pb:
3072 elif pa > pb:
3073 rel = ">"
3073 rel = ">"
3074 elif pa < pb:
3074 elif pa < pb:
3075 rel = "<"
3075 rel = "<"
3076 elif pa | pb:
3076 elif pa | pb:
3077 rel = "|"
3077 rel = "|"
3078 ui.write(_("a: %s\n") % pa)
3078 ui.write(_("a: %s\n") % pa)
3079 ui.write(_("b: %s\n") % pb)
3079 ui.write(_("b: %s\n") % pb)
3080 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3080 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3081 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3081 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3082 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3082 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3083 pa.distance(pb), rel))
3083 pa.distance(pb), rel))
3084
3084
3085 @command('debugrebuilddirstate|debugrebuildstate',
3085 @command('debugrebuilddirstate|debugrebuildstate',
3086 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3086 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3087 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3087 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3088 'the working copy parent')),
3088 'the working copy parent')),
3089 ],
3089 ],
3090 _('[-r REV]'))
3090 _('[-r REV]'))
3091 def debugrebuilddirstate(ui, repo, rev, **opts):
3091 def debugrebuilddirstate(ui, repo, rev, **opts):
3092 """rebuild the dirstate as it would look like for the given revision
3092 """rebuild the dirstate as it would look like for the given revision
3093
3093
3094 If no revision is specified the first current parent will be used.
3094 If no revision is specified the first current parent will be used.
3095
3095
3096 The dirstate will be set to the files of the given revision.
3096 The dirstate will be set to the files of the given revision.
3097 The actual working directory content or existing dirstate
3097 The actual working directory content or existing dirstate
3098 information such as adds or removes is not considered.
3098 information such as adds or removes is not considered.
3099
3099
3100 ``minimal`` will only rebuild the dirstate status for files that claim to be
3100 ``minimal`` will only rebuild the dirstate status for files that claim to be
3101 tracked but are not in the parent manifest, or that exist in the parent
3101 tracked but are not in the parent manifest, or that exist in the parent
3102 manifest but are not in the dirstate. It will not change adds, removes, or
3102 manifest but are not in the dirstate. It will not change adds, removes, or
3103 modified files that are in the working copy parent.
3103 modified files that are in the working copy parent.
3104
3104
3105 One use of this command is to make the next :hg:`status` invocation
3105 One use of this command is to make the next :hg:`status` invocation
3106 check the actual file content.
3106 check the actual file content.
3107 """
3107 """
3108 ctx = scmutil.revsingle(repo, rev)
3108 ctx = scmutil.revsingle(repo, rev)
3109 wlock = repo.wlock()
3109 wlock = repo.wlock()
3110 try:
3110 try:
3111 dirstate = repo.dirstate
3111 dirstate = repo.dirstate
3112 changedfiles = None
3112 changedfiles = None
3113 # See command doc for what minimal does.
3113 # See command doc for what minimal does.
3114 if opts.get('minimal'):
3114 if opts.get('minimal'):
3115 manifestfiles = set(ctx.manifest().keys())
3115 manifestfiles = set(ctx.manifest().keys())
3116 dirstatefiles = set(dirstate)
3116 dirstatefiles = set(dirstate)
3117 manifestonly = manifestfiles - dirstatefiles
3117 manifestonly = manifestfiles - dirstatefiles
3118 dsonly = dirstatefiles - manifestfiles
3118 dsonly = dirstatefiles - manifestfiles
3119 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3119 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3120 changedfiles = manifestonly | dsnotadded
3120 changedfiles = manifestonly | dsnotadded
3121
3121
3122 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3122 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3123 finally:
3123 finally:
3124 wlock.release()
3124 wlock.release()
3125
3125
3126 @command('debugrebuildfncache', [], '')
3126 @command('debugrebuildfncache', [], '')
3127 def debugrebuildfncache(ui, repo):
3127 def debugrebuildfncache(ui, repo):
3128 """rebuild the fncache file"""
3128 """rebuild the fncache file"""
3129 repair.rebuildfncache(ui, repo)
3129 repair.rebuildfncache(ui, repo)
3130
3130
3131 @command('debugrename',
3131 @command('debugrename',
3132 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3132 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3133 _('[-r REV] FILE'))
3133 _('[-r REV] FILE'))
3134 def debugrename(ui, repo, file1, *pats, **opts):
3134 def debugrename(ui, repo, file1, *pats, **opts):
3135 """dump rename information"""
3135 """dump rename information"""
3136
3136
3137 ctx = scmutil.revsingle(repo, opts.get('rev'))
3137 ctx = scmutil.revsingle(repo, opts.get('rev'))
3138 m = scmutil.match(ctx, (file1,) + pats, opts)
3138 m = scmutil.match(ctx, (file1,) + pats, opts)
3139 for abs in ctx.walk(m):
3139 for abs in ctx.walk(m):
3140 fctx = ctx[abs]
3140 fctx = ctx[abs]
3141 o = fctx.filelog().renamed(fctx.filenode())
3141 o = fctx.filelog().renamed(fctx.filenode())
3142 rel = m.rel(abs)
3142 rel = m.rel(abs)
3143 if o:
3143 if o:
3144 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3144 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3145 else:
3145 else:
3146 ui.write(_("%s not renamed\n") % rel)
3146 ui.write(_("%s not renamed\n") % rel)
3147
3147
3148 @command('debugrevlog', debugrevlogopts +
3148 @command('debugrevlog', debugrevlogopts +
3149 [('d', 'dump', False, _('dump index data'))],
3149 [('d', 'dump', False, _('dump index data'))],
3150 _('-c|-m|FILE'),
3150 _('-c|-m|FILE'),
3151 optionalrepo=True)
3151 optionalrepo=True)
3152 def debugrevlog(ui, repo, file_=None, **opts):
3152 def debugrevlog(ui, repo, file_=None, **opts):
3153 """show data and statistics about a revlog"""
3153 """show data and statistics about a revlog"""
3154 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3154 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3155
3155
3156 if opts.get("dump"):
3156 if opts.get("dump"):
3157 numrevs = len(r)
3157 numrevs = len(r)
3158 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3158 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3159 " rawsize totalsize compression heads chainlen\n")
3159 " rawsize totalsize compression heads chainlen\n")
3160 ts = 0
3160 ts = 0
3161 heads = set()
3161 heads = set()
3162
3162
3163 for rev in xrange(numrevs):
3163 for rev in xrange(numrevs):
3164 dbase = r.deltaparent(rev)
3164 dbase = r.deltaparent(rev)
3165 if dbase == -1:
3165 if dbase == -1:
3166 dbase = rev
3166 dbase = rev
3167 cbase = r.chainbase(rev)
3167 cbase = r.chainbase(rev)
3168 clen = r.chainlen(rev)
3168 clen = r.chainlen(rev)
3169 p1, p2 = r.parentrevs(rev)
3169 p1, p2 = r.parentrevs(rev)
3170 rs = r.rawsize(rev)
3170 rs = r.rawsize(rev)
3171 ts = ts + rs
3171 ts = ts + rs
3172 heads -= set(r.parentrevs(rev))
3172 heads -= set(r.parentrevs(rev))
3173 heads.add(rev)
3173 heads.add(rev)
3174 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3174 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3175 "%11d %5d %8d\n" %
3175 "%11d %5d %8d\n" %
3176 (rev, p1, p2, r.start(rev), r.end(rev),
3176 (rev, p1, p2, r.start(rev), r.end(rev),
3177 r.start(dbase), r.start(cbase),
3177 r.start(dbase), r.start(cbase),
3178 r.start(p1), r.start(p2),
3178 r.start(p1), r.start(p2),
3179 rs, ts, ts / r.end(rev), len(heads), clen))
3179 rs, ts, ts / r.end(rev), len(heads), clen))
3180 return 0
3180 return 0
3181
3181
3182 v = r.version
3182 v = r.version
3183 format = v & 0xFFFF
3183 format = v & 0xFFFF
3184 flags = []
3184 flags = []
3185 gdelta = False
3185 gdelta = False
3186 if v & revlog.REVLOGNGINLINEDATA:
3186 if v & revlog.REVLOGNGINLINEDATA:
3187 flags.append('inline')
3187 flags.append('inline')
3188 if v & revlog.REVLOGGENERALDELTA:
3188 if v & revlog.REVLOGGENERALDELTA:
3189 gdelta = True
3189 gdelta = True
3190 flags.append('generaldelta')
3190 flags.append('generaldelta')
3191 if not flags:
3191 if not flags:
3192 flags = ['(none)']
3192 flags = ['(none)']
3193
3193
3194 nummerges = 0
3194 nummerges = 0
3195 numfull = 0
3195 numfull = 0
3196 numprev = 0
3196 numprev = 0
3197 nump1 = 0
3197 nump1 = 0
3198 nump2 = 0
3198 nump2 = 0
3199 numother = 0
3199 numother = 0
3200 nump1prev = 0
3200 nump1prev = 0
3201 nump2prev = 0
3201 nump2prev = 0
3202 chainlengths = []
3202 chainlengths = []
3203
3203
3204 datasize = [None, 0, 0L]
3204 datasize = [None, 0, 0L]
3205 fullsize = [None, 0, 0L]
3205 fullsize = [None, 0, 0L]
3206 deltasize = [None, 0, 0L]
3206 deltasize = [None, 0, 0L]
3207
3207
3208 def addsize(size, l):
3208 def addsize(size, l):
3209 if l[0] is None or size < l[0]:
3209 if l[0] is None or size < l[0]:
3210 l[0] = size
3210 l[0] = size
3211 if size > l[1]:
3211 if size > l[1]:
3212 l[1] = size
3212 l[1] = size
3213 l[2] += size
3213 l[2] += size
3214
3214
3215 numrevs = len(r)
3215 numrevs = len(r)
3216 for rev in xrange(numrevs):
3216 for rev in xrange(numrevs):
3217 p1, p2 = r.parentrevs(rev)
3217 p1, p2 = r.parentrevs(rev)
3218 delta = r.deltaparent(rev)
3218 delta = r.deltaparent(rev)
3219 if format > 0:
3219 if format > 0:
3220 addsize(r.rawsize(rev), datasize)
3220 addsize(r.rawsize(rev), datasize)
3221 if p2 != nullrev:
3221 if p2 != nullrev:
3222 nummerges += 1
3222 nummerges += 1
3223 size = r.length(rev)
3223 size = r.length(rev)
3224 if delta == nullrev:
3224 if delta == nullrev:
3225 chainlengths.append(0)
3225 chainlengths.append(0)
3226 numfull += 1
3226 numfull += 1
3227 addsize(size, fullsize)
3227 addsize(size, fullsize)
3228 else:
3228 else:
3229 chainlengths.append(chainlengths[delta] + 1)
3229 chainlengths.append(chainlengths[delta] + 1)
3230 addsize(size, deltasize)
3230 addsize(size, deltasize)
3231 if delta == rev - 1:
3231 if delta == rev - 1:
3232 numprev += 1
3232 numprev += 1
3233 if delta == p1:
3233 if delta == p1:
3234 nump1prev += 1
3234 nump1prev += 1
3235 elif delta == p2:
3235 elif delta == p2:
3236 nump2prev += 1
3236 nump2prev += 1
3237 elif delta == p1:
3237 elif delta == p1:
3238 nump1 += 1
3238 nump1 += 1
3239 elif delta == p2:
3239 elif delta == p2:
3240 nump2 += 1
3240 nump2 += 1
3241 elif delta != nullrev:
3241 elif delta != nullrev:
3242 numother += 1
3242 numother += 1
3243
3243
3244 # Adjust size min value for empty cases
3244 # Adjust size min value for empty cases
3245 for size in (datasize, fullsize, deltasize):
3245 for size in (datasize, fullsize, deltasize):
3246 if size[0] is None:
3246 if size[0] is None:
3247 size[0] = 0
3247 size[0] = 0
3248
3248
3249 numdeltas = numrevs - numfull
3249 numdeltas = numrevs - numfull
3250 numoprev = numprev - nump1prev - nump2prev
3250 numoprev = numprev - nump1prev - nump2prev
3251 totalrawsize = datasize[2]
3251 totalrawsize = datasize[2]
3252 datasize[2] /= numrevs
3252 datasize[2] /= numrevs
3253 fulltotal = fullsize[2]
3253 fulltotal = fullsize[2]
3254 fullsize[2] /= numfull
3254 fullsize[2] /= numfull
3255 deltatotal = deltasize[2]
3255 deltatotal = deltasize[2]
3256 if numrevs - numfull > 0:
3256 if numrevs - numfull > 0:
3257 deltasize[2] /= numrevs - numfull
3257 deltasize[2] /= numrevs - numfull
3258 totalsize = fulltotal + deltatotal
3258 totalsize = fulltotal + deltatotal
3259 avgchainlen = sum(chainlengths) / numrevs
3259 avgchainlen = sum(chainlengths) / numrevs
3260 maxchainlen = max(chainlengths)
3260 maxchainlen = max(chainlengths)
3261 compratio = 1
3261 compratio = 1
3262 if totalsize:
3262 if totalsize:
3263 compratio = totalrawsize / totalsize
3263 compratio = totalrawsize / totalsize
3264
3264
3265 basedfmtstr = '%%%dd\n'
3265 basedfmtstr = '%%%dd\n'
3266 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3266 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3267
3267
3268 def dfmtstr(max):
3268 def dfmtstr(max):
3269 return basedfmtstr % len(str(max))
3269 return basedfmtstr % len(str(max))
3270 def pcfmtstr(max, padding=0):
3270 def pcfmtstr(max, padding=0):
3271 return basepcfmtstr % (len(str(max)), ' ' * padding)
3271 return basepcfmtstr % (len(str(max)), ' ' * padding)
3272
3272
3273 def pcfmt(value, total):
3273 def pcfmt(value, total):
3274 if total:
3274 if total:
3275 return (value, 100 * float(value) / total)
3275 return (value, 100 * float(value) / total)
3276 else:
3276 else:
3277 return value, 100.0
3277 return value, 100.0
3278
3278
3279 ui.write(('format : %d\n') % format)
3279 ui.write(('format : %d\n') % format)
3280 ui.write(('flags : %s\n') % ', '.join(flags))
3280 ui.write(('flags : %s\n') % ', '.join(flags))
3281
3281
3282 ui.write('\n')
3282 ui.write('\n')
3283 fmt = pcfmtstr(totalsize)
3283 fmt = pcfmtstr(totalsize)
3284 fmt2 = dfmtstr(totalsize)
3284 fmt2 = dfmtstr(totalsize)
3285 ui.write(('revisions : ') + fmt2 % numrevs)
3285 ui.write(('revisions : ') + fmt2 % numrevs)
3286 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3286 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3287 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3287 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3288 ui.write(('revisions : ') + fmt2 % numrevs)
3288 ui.write(('revisions : ') + fmt2 % numrevs)
3289 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3289 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3290 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3290 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3291 ui.write(('revision size : ') + fmt2 % totalsize)
3291 ui.write(('revision size : ') + fmt2 % totalsize)
3292 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3292 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3293 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3293 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3294
3294
3295 ui.write('\n')
3295 ui.write('\n')
3296 fmt = dfmtstr(max(avgchainlen, compratio))
3296 fmt = dfmtstr(max(avgchainlen, compratio))
3297 ui.write(('avg chain length : ') + fmt % avgchainlen)
3297 ui.write(('avg chain length : ') + fmt % avgchainlen)
3298 ui.write(('max chain length : ') + fmt % maxchainlen)
3298 ui.write(('max chain length : ') + fmt % maxchainlen)
3299 ui.write(('compression ratio : ') + fmt % compratio)
3299 ui.write(('compression ratio : ') + fmt % compratio)
3300
3300
3301 if format > 0:
3301 if format > 0:
3302 ui.write('\n')
3302 ui.write('\n')
3303 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3303 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3304 % tuple(datasize))
3304 % tuple(datasize))
3305 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3305 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3306 % tuple(fullsize))
3306 % tuple(fullsize))
3307 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3307 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3308 % tuple(deltasize))
3308 % tuple(deltasize))
3309
3309
3310 if numdeltas > 0:
3310 if numdeltas > 0:
3311 ui.write('\n')
3311 ui.write('\n')
3312 fmt = pcfmtstr(numdeltas)
3312 fmt = pcfmtstr(numdeltas)
3313 fmt2 = pcfmtstr(numdeltas, 4)
3313 fmt2 = pcfmtstr(numdeltas, 4)
3314 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3314 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3315 if numprev > 0:
3315 if numprev > 0:
3316 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3316 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3317 numprev))
3317 numprev))
3318 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3318 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3319 numprev))
3319 numprev))
3320 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3320 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3321 numprev))
3321 numprev))
3322 if gdelta:
3322 if gdelta:
3323 ui.write(('deltas against p1 : ')
3323 ui.write(('deltas against p1 : ')
3324 + fmt % pcfmt(nump1, numdeltas))
3324 + fmt % pcfmt(nump1, numdeltas))
3325 ui.write(('deltas against p2 : ')
3325 ui.write(('deltas against p2 : ')
3326 + fmt % pcfmt(nump2, numdeltas))
3326 + fmt % pcfmt(nump2, numdeltas))
3327 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3327 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3328 numdeltas))
3328 numdeltas))
3329
3329
3330 @command('debugrevspec',
3330 @command('debugrevspec',
3331 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3331 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3332 ('REVSPEC'))
3332 ('REVSPEC'))
3333 def debugrevspec(ui, repo, expr, **opts):
3333 def debugrevspec(ui, repo, expr, **opts):
3334 """parse and apply a revision specification
3334 """parse and apply a revision specification
3335
3335
3336 Use --verbose to print the parsed tree before and after aliases
3336 Use --verbose to print the parsed tree before and after aliases
3337 expansion.
3337 expansion.
3338 """
3338 """
3339 if ui.verbose:
3339 if ui.verbose:
3340 tree = revset.parse(expr, lookup=repo.__contains__)
3340 tree = revset.parse(expr, lookup=repo.__contains__)
3341 ui.note(revset.prettyformat(tree), "\n")
3341 ui.note(revset.prettyformat(tree), "\n")
3342 newtree = revset.findaliases(ui, tree)
3342 newtree = revset.findaliases(ui, tree)
3343 if newtree != tree:
3343 if newtree != tree:
3344 ui.note(revset.prettyformat(newtree), "\n")
3344 ui.note(revset.prettyformat(newtree), "\n")
3345 tree = newtree
3345 tree = newtree
3346 newtree = revset.foldconcat(tree)
3346 newtree = revset.foldconcat(tree)
3347 if newtree != tree:
3347 if newtree != tree:
3348 ui.note(revset.prettyformat(newtree), "\n")
3348 ui.note(revset.prettyformat(newtree), "\n")
3349 if opts["optimize"]:
3349 if opts["optimize"]:
3350 weight, optimizedtree = revset.optimize(newtree, True)
3350 weight, optimizedtree = revset.optimize(newtree, True)
3351 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3351 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3352 func = revset.match(ui, expr, repo)
3352 func = revset.match(ui, expr, repo)
3353 revs = func(repo)
3353 revs = func(repo)
3354 if ui.verbose:
3354 if ui.verbose:
3355 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3355 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3356 for c in revs:
3356 for c in revs:
3357 ui.write("%s\n" % c)
3357 ui.write("%s\n" % c)
3358
3358
3359 @command('debugsetparents', [], _('REV1 [REV2]'))
3359 @command('debugsetparents', [], _('REV1 [REV2]'))
3360 def debugsetparents(ui, repo, rev1, rev2=None):
3360 def debugsetparents(ui, repo, rev1, rev2=None):
3361 """manually set the parents of the current working directory
3361 """manually set the parents of the current working directory
3362
3362
3363 This is useful for writing repository conversion tools, but should
3363 This is useful for writing repository conversion tools, but should
3364 be used with care. For example, neither the working directory nor the
3364 be used with care. For example, neither the working directory nor the
3365 dirstate is updated, so file status may be incorrect after running this
3365 dirstate is updated, so file status may be incorrect after running this
3366 command.
3366 command.
3367
3367
3368 Returns 0 on success.
3368 Returns 0 on success.
3369 """
3369 """
3370
3370
3371 r1 = scmutil.revsingle(repo, rev1).node()
3371 r1 = scmutil.revsingle(repo, rev1).node()
3372 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3372 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3373
3373
3374 wlock = repo.wlock()
3374 wlock = repo.wlock()
3375 try:
3375 try:
3376 repo.dirstate.beginparentchange()
3376 repo.dirstate.beginparentchange()
3377 repo.setparents(r1, r2)
3377 repo.setparents(r1, r2)
3378 repo.dirstate.endparentchange()
3378 repo.dirstate.endparentchange()
3379 finally:
3379 finally:
3380 wlock.release()
3380 wlock.release()
3381
3381
3382 @command('debugdirstate|debugstate',
3382 @command('debugdirstate|debugstate',
3383 [('', 'nodates', None, _('do not display the saved mtime')),
3383 [('', 'nodates', None, _('do not display the saved mtime')),
3384 ('', 'datesort', None, _('sort by saved mtime'))],
3384 ('', 'datesort', None, _('sort by saved mtime'))],
3385 _('[OPTION]...'))
3385 _('[OPTION]...'))
3386 def debugstate(ui, repo, **opts):
3386 def debugstate(ui, repo, **opts):
3387 """show the contents of the current dirstate"""
3387 """show the contents of the current dirstate"""
3388
3388
3389 nodates = opts.get('nodates')
3389 nodates = opts.get('nodates')
3390 datesort = opts.get('datesort')
3390 datesort = opts.get('datesort')
3391
3391
3392 timestr = ""
3392 timestr = ""
3393 if datesort:
3393 if datesort:
3394 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3394 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3395 else:
3395 else:
3396 keyfunc = None # sort by filename
3396 keyfunc = None # sort by filename
3397 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3397 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3398 if ent[3] == -1:
3398 if ent[3] == -1:
3399 timestr = 'unset '
3399 timestr = 'unset '
3400 elif nodates:
3400 elif nodates:
3401 timestr = 'set '
3401 timestr = 'set '
3402 else:
3402 else:
3403 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3403 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3404 time.localtime(ent[3]))
3404 time.localtime(ent[3]))
3405 if ent[1] & 0o20000:
3405 if ent[1] & 0o20000:
3406 mode = 'lnk'
3406 mode = 'lnk'
3407 else:
3407 else:
3408 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3408 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3409 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3409 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3410 for f in repo.dirstate.copies():
3410 for f in repo.dirstate.copies():
3411 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3411 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3412
3412
3413 @command('debugsub',
3413 @command('debugsub',
3414 [('r', 'rev', '',
3414 [('r', 'rev', '',
3415 _('revision to check'), _('REV'))],
3415 _('revision to check'), _('REV'))],
3416 _('[-r REV] [REV]'))
3416 _('[-r REV] [REV]'))
3417 def debugsub(ui, repo, rev=None):
3417 def debugsub(ui, repo, rev=None):
3418 ctx = scmutil.revsingle(repo, rev, None)
3418 ctx = scmutil.revsingle(repo, rev, None)
3419 for k, v in sorted(ctx.substate.items()):
3419 for k, v in sorted(ctx.substate.items()):
3420 ui.write(('path %s\n') % k)
3420 ui.write(('path %s\n') % k)
3421 ui.write((' source %s\n') % v[0])
3421 ui.write((' source %s\n') % v[0])
3422 ui.write((' revision %s\n') % v[1])
3422 ui.write((' revision %s\n') % v[1])
3423
3423
3424 @command('debugsuccessorssets',
3424 @command('debugsuccessorssets',
3425 [],
3425 [],
3426 _('[REV]'))
3426 _('[REV]'))
3427 def debugsuccessorssets(ui, repo, *revs):
3427 def debugsuccessorssets(ui, repo, *revs):
3428 """show set of successors for revision
3428 """show set of successors for revision
3429
3429
3430 A successors set of changeset A is a consistent group of revisions that
3430 A successors set of changeset A is a consistent group of revisions that
3431 succeed A. It contains non-obsolete changesets only.
3431 succeed A. It contains non-obsolete changesets only.
3432
3432
3433 In most cases a changeset A has a single successors set containing a single
3433 In most cases a changeset A has a single successors set containing a single
3434 successor (changeset A replaced by A').
3434 successor (changeset A replaced by A').
3435
3435
3436 A changeset that is made obsolete with no successors are called "pruned".
3436 A changeset that is made obsolete with no successors are called "pruned".
3437 Such changesets have no successors sets at all.
3437 Such changesets have no successors sets at all.
3438
3438
3439 A changeset that has been "split" will have a successors set containing
3439 A changeset that has been "split" will have a successors set containing
3440 more than one successor.
3440 more than one successor.
3441
3441
3442 A changeset that has been rewritten in multiple different ways is called
3442 A changeset that has been rewritten in multiple different ways is called
3443 "divergent". Such changesets have multiple successor sets (each of which
3443 "divergent". Such changesets have multiple successor sets (each of which
3444 may also be split, i.e. have multiple successors).
3444 may also be split, i.e. have multiple successors).
3445
3445
3446 Results are displayed as follows::
3446 Results are displayed as follows::
3447
3447
3448 <rev1>
3448 <rev1>
3449 <successors-1A>
3449 <successors-1A>
3450 <rev2>
3450 <rev2>
3451 <successors-2A>
3451 <successors-2A>
3452 <successors-2B1> <successors-2B2> <successors-2B3>
3452 <successors-2B1> <successors-2B2> <successors-2B3>
3453
3453
3454 Here rev2 has two possible (i.e. divergent) successors sets. The first
3454 Here rev2 has two possible (i.e. divergent) successors sets. The first
3455 holds one element, whereas the second holds three (i.e. the changeset has
3455 holds one element, whereas the second holds three (i.e. the changeset has
3456 been split).
3456 been split).
3457 """
3457 """
3458 # passed to successorssets caching computation from one call to another
3458 # passed to successorssets caching computation from one call to another
3459 cache = {}
3459 cache = {}
3460 ctx2str = str
3460 ctx2str = str
3461 node2str = short
3461 node2str = short
3462 if ui.debug():
3462 if ui.debug():
3463 def ctx2str(ctx):
3463 def ctx2str(ctx):
3464 return ctx.hex()
3464 return ctx.hex()
3465 node2str = hex
3465 node2str = hex
3466 for rev in scmutil.revrange(repo, revs):
3466 for rev in scmutil.revrange(repo, revs):
3467 ctx = repo[rev]
3467 ctx = repo[rev]
3468 ui.write('%s\n'% ctx2str(ctx))
3468 ui.write('%s\n'% ctx2str(ctx))
3469 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3469 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3470 if succsset:
3470 if succsset:
3471 ui.write(' ')
3471 ui.write(' ')
3472 ui.write(node2str(succsset[0]))
3472 ui.write(node2str(succsset[0]))
3473 for node in succsset[1:]:
3473 for node in succsset[1:]:
3474 ui.write(' ')
3474 ui.write(' ')
3475 ui.write(node2str(node))
3475 ui.write(node2str(node))
3476 ui.write('\n')
3476 ui.write('\n')
3477
3477
3478 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3478 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3479 def debugwalk(ui, repo, *pats, **opts):
3479 def debugwalk(ui, repo, *pats, **opts):
3480 """show how files match on given patterns"""
3480 """show how files match on given patterns"""
3481 m = scmutil.match(repo[None], pats, opts)
3481 m = scmutil.match(repo[None], pats, opts)
3482 items = list(repo.walk(m))
3482 items = list(repo.walk(m))
3483 if not items:
3483 if not items:
3484 return
3484 return
3485 f = lambda fn: fn
3485 f = lambda fn: fn
3486 if ui.configbool('ui', 'slash') and os.sep != '/':
3486 if ui.configbool('ui', 'slash') and os.sep != '/':
3487 f = lambda fn: util.normpath(fn)
3487 f = lambda fn: util.normpath(fn)
3488 fmt = 'f %%-%ds %%-%ds %%s' % (
3488 fmt = 'f %%-%ds %%-%ds %%s' % (
3489 max([len(abs) for abs in items]),
3489 max([len(abs) for abs in items]),
3490 max([len(m.rel(abs)) for abs in items]))
3490 max([len(m.rel(abs)) for abs in items]))
3491 for abs in items:
3491 for abs in items:
3492 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3492 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3493 ui.write("%s\n" % line.rstrip())
3493 ui.write("%s\n" % line.rstrip())
3494
3494
3495 @command('debugwireargs',
3495 @command('debugwireargs',
3496 [('', 'three', '', 'three'),
3496 [('', 'three', '', 'three'),
3497 ('', 'four', '', 'four'),
3497 ('', 'four', '', 'four'),
3498 ('', 'five', '', 'five'),
3498 ('', 'five', '', 'five'),
3499 ] + remoteopts,
3499 ] + remoteopts,
3500 _('REPO [OPTIONS]... [ONE [TWO]]'),
3500 _('REPO [OPTIONS]... [ONE [TWO]]'),
3501 norepo=True)
3501 norepo=True)
3502 def debugwireargs(ui, repopath, *vals, **opts):
3502 def debugwireargs(ui, repopath, *vals, **opts):
3503 repo = hg.peer(ui, opts, repopath)
3503 repo = hg.peer(ui, opts, repopath)
3504 for opt in remoteopts:
3504 for opt in remoteopts:
3505 del opts[opt[1]]
3505 del opts[opt[1]]
3506 args = {}
3506 args = {}
3507 for k, v in opts.iteritems():
3507 for k, v in opts.iteritems():
3508 if v:
3508 if v:
3509 args[k] = v
3509 args[k] = v
3510 # run twice to check that we don't mess up the stream for the next command
3510 # run twice to check that we don't mess up the stream for the next command
3511 res1 = repo.debugwireargs(*vals, **args)
3511 res1 = repo.debugwireargs(*vals, **args)
3512 res2 = repo.debugwireargs(*vals, **args)
3512 res2 = repo.debugwireargs(*vals, **args)
3513 ui.write("%s\n" % res1)
3513 ui.write("%s\n" % res1)
3514 if res1 != res2:
3514 if res1 != res2:
3515 ui.warn("%s\n" % res2)
3515 ui.warn("%s\n" % res2)
3516
3516
3517 @command('^diff',
3517 @command('^diff',
3518 [('r', 'rev', [], _('revision'), _('REV')),
3518 [('r', 'rev', [], _('revision'), _('REV')),
3519 ('c', 'change', '', _('change made by revision'), _('REV'))
3519 ('c', 'change', '', _('change made by revision'), _('REV'))
3520 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3520 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3521 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3521 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3522 inferrepo=True)
3522 inferrepo=True)
3523 def diff(ui, repo, *pats, **opts):
3523 def diff(ui, repo, *pats, **opts):
3524 """diff repository (or selected files)
3524 """diff repository (or selected files)
3525
3525
3526 Show differences between revisions for the specified files.
3526 Show differences between revisions for the specified files.
3527
3527
3528 Differences between files are shown using the unified diff format.
3528 Differences between files are shown using the unified diff format.
3529
3529
3530 .. note::
3530 .. note::
3531
3531
3532 :hg:`diff` may generate unexpected results for merges, as it will
3532 :hg:`diff` may generate unexpected results for merges, as it will
3533 default to comparing against the working directory's first
3533 default to comparing against the working directory's first
3534 parent changeset if no revisions are specified.
3534 parent changeset if no revisions are specified.
3535
3535
3536 When two revision arguments are given, then changes are shown
3536 When two revision arguments are given, then changes are shown
3537 between those revisions. If only one revision is specified then
3537 between those revisions. If only one revision is specified then
3538 that revision is compared to the working directory, and, when no
3538 that revision is compared to the working directory, and, when no
3539 revisions are specified, the working directory files are compared
3539 revisions are specified, the working directory files are compared
3540 to its first parent.
3540 to its first parent.
3541
3541
3542 Alternatively you can specify -c/--change with a revision to see
3542 Alternatively you can specify -c/--change with a revision to see
3543 the changes in that changeset relative to its first parent.
3543 the changes in that changeset relative to its first parent.
3544
3544
3545 Without the -a/--text option, diff will avoid generating diffs of
3545 Without the -a/--text option, diff will avoid generating diffs of
3546 files it detects as binary. With -a, diff will generate a diff
3546 files it detects as binary. With -a, diff will generate a diff
3547 anyway, probably with undesirable results.
3547 anyway, probably with undesirable results.
3548
3548
3549 Use the -g/--git option to generate diffs in the git extended diff
3549 Use the -g/--git option to generate diffs in the git extended diff
3550 format. For more information, read :hg:`help diffs`.
3550 format. For more information, read :hg:`help diffs`.
3551
3551
3552 .. container:: verbose
3552 .. container:: verbose
3553
3553
3554 Examples:
3554 Examples:
3555
3555
3556 - compare a file in the current working directory to its parent::
3556 - compare a file in the current working directory to its parent::
3557
3557
3558 hg diff foo.c
3558 hg diff foo.c
3559
3559
3560 - compare two historical versions of a directory, with rename info::
3560 - compare two historical versions of a directory, with rename info::
3561
3561
3562 hg diff --git -r 1.0:1.2 lib/
3562 hg diff --git -r 1.0:1.2 lib/
3563
3563
3564 - get change stats relative to the last change on some date::
3564 - get change stats relative to the last change on some date::
3565
3565
3566 hg diff --stat -r "date('may 2')"
3566 hg diff --stat -r "date('may 2')"
3567
3567
3568 - diff all newly-added files that contain a keyword::
3568 - diff all newly-added files that contain a keyword::
3569
3569
3570 hg diff "set:added() and grep(GNU)"
3570 hg diff "set:added() and grep(GNU)"
3571
3571
3572 - compare a revision and its parents::
3572 - compare a revision and its parents::
3573
3573
3574 hg diff -c 9353 # compare against first parent
3574 hg diff -c 9353 # compare against first parent
3575 hg diff -r 9353^:9353 # same using revset syntax
3575 hg diff -r 9353^:9353 # same using revset syntax
3576 hg diff -r 9353^2:9353 # compare against the second parent
3576 hg diff -r 9353^2:9353 # compare against the second parent
3577
3577
3578 Returns 0 on success.
3578 Returns 0 on success.
3579 """
3579 """
3580
3580
3581 revs = opts.get('rev')
3581 revs = opts.get('rev')
3582 change = opts.get('change')
3582 change = opts.get('change')
3583 stat = opts.get('stat')
3583 stat = opts.get('stat')
3584 reverse = opts.get('reverse')
3584 reverse = opts.get('reverse')
3585
3585
3586 if revs and change:
3586 if revs and change:
3587 msg = _('cannot specify --rev and --change at the same time')
3587 msg = _('cannot specify --rev and --change at the same time')
3588 raise error.Abort(msg)
3588 raise error.Abort(msg)
3589 elif change:
3589 elif change:
3590 node2 = scmutil.revsingle(repo, change, None).node()
3590 node2 = scmutil.revsingle(repo, change, None).node()
3591 node1 = repo[node2].p1().node()
3591 node1 = repo[node2].p1().node()
3592 else:
3592 else:
3593 node1, node2 = scmutil.revpair(repo, revs)
3593 node1, node2 = scmutil.revpair(repo, revs)
3594
3594
3595 if reverse:
3595 if reverse:
3596 node1, node2 = node2, node1
3596 node1, node2 = node2, node1
3597
3597
3598 diffopts = patch.diffallopts(ui, opts)
3598 diffopts = patch.diffallopts(ui, opts)
3599 m = scmutil.match(repo[node2], pats, opts)
3599 m = scmutil.match(repo[node2], pats, opts)
3600 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3600 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3601 listsubrepos=opts.get('subrepos'),
3601 listsubrepos=opts.get('subrepos'),
3602 root=opts.get('root'))
3602 root=opts.get('root'))
3603
3603
3604 @command('^export',
3604 @command('^export',
3605 [('o', 'output', '',
3605 [('o', 'output', '',
3606 _('print output to file with formatted name'), _('FORMAT')),
3606 _('print output to file with formatted name'), _('FORMAT')),
3607 ('', 'switch-parent', None, _('diff against the second parent')),
3607 ('', 'switch-parent', None, _('diff against the second parent')),
3608 ('r', 'rev', [], _('revisions to export'), _('REV')),
3608 ('r', 'rev', [], _('revisions to export'), _('REV')),
3609 ] + diffopts,
3609 ] + diffopts,
3610 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3610 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3611 def export(ui, repo, *changesets, **opts):
3611 def export(ui, repo, *changesets, **opts):
3612 """dump the header and diffs for one or more changesets
3612 """dump the header and diffs for one or more changesets
3613
3613
3614 Print the changeset header and diffs for one or more revisions.
3614 Print the changeset header and diffs for one or more revisions.
3615 If no revision is given, the parent of the working directory is used.
3615 If no revision is given, the parent of the working directory is used.
3616
3616
3617 The information shown in the changeset header is: author, date,
3617 The information shown in the changeset header is: author, date,
3618 branch name (if non-default), changeset hash, parent(s) and commit
3618 branch name (if non-default), changeset hash, parent(s) and commit
3619 comment.
3619 comment.
3620
3620
3621 .. note::
3621 .. note::
3622
3622
3623 :hg:`export` may generate unexpected diff output for merge
3623 :hg:`export` may generate unexpected diff output for merge
3624 changesets, as it will compare the merge changeset against its
3624 changesets, as it will compare the merge changeset against its
3625 first parent only.
3625 first parent only.
3626
3626
3627 Output may be to a file, in which case the name of the file is
3627 Output may be to a file, in which case the name of the file is
3628 given using a format string. The formatting rules are as follows:
3628 given using a format string. The formatting rules are as follows:
3629
3629
3630 :``%%``: literal "%" character
3630 :``%%``: literal "%" character
3631 :``%H``: changeset hash (40 hexadecimal digits)
3631 :``%H``: changeset hash (40 hexadecimal digits)
3632 :``%N``: number of patches being generated
3632 :``%N``: number of patches being generated
3633 :``%R``: changeset revision number
3633 :``%R``: changeset revision number
3634 :``%b``: basename of the exporting repository
3634 :``%b``: basename of the exporting repository
3635 :``%h``: short-form changeset hash (12 hexadecimal digits)
3635 :``%h``: short-form changeset hash (12 hexadecimal digits)
3636 :``%m``: first line of the commit message (only alphanumeric characters)
3636 :``%m``: first line of the commit message (only alphanumeric characters)
3637 :``%n``: zero-padded sequence number, starting at 1
3637 :``%n``: zero-padded sequence number, starting at 1
3638 :``%r``: zero-padded changeset revision number
3638 :``%r``: zero-padded changeset revision number
3639
3639
3640 Without the -a/--text option, export will avoid generating diffs
3640 Without the -a/--text option, export will avoid generating diffs
3641 of files it detects as binary. With -a, export will generate a
3641 of files it detects as binary. With -a, export will generate a
3642 diff anyway, probably with undesirable results.
3642 diff anyway, probably with undesirable results.
3643
3643
3644 Use the -g/--git option to generate diffs in the git extended diff
3644 Use the -g/--git option to generate diffs in the git extended diff
3645 format. See :hg:`help diffs` for more information.
3645 format. See :hg:`help diffs` for more information.
3646
3646
3647 With the --switch-parent option, the diff will be against the
3647 With the --switch-parent option, the diff will be against the
3648 second parent. It can be useful to review a merge.
3648 second parent. It can be useful to review a merge.
3649
3649
3650 .. container:: verbose
3650 .. container:: verbose
3651
3651
3652 Examples:
3652 Examples:
3653
3653
3654 - use export and import to transplant a bugfix to the current
3654 - use export and import to transplant a bugfix to the current
3655 branch::
3655 branch::
3656
3656
3657 hg export -r 9353 | hg import -
3657 hg export -r 9353 | hg import -
3658
3658
3659 - export all the changesets between two revisions to a file with
3659 - export all the changesets between two revisions to a file with
3660 rename information::
3660 rename information::
3661
3661
3662 hg export --git -r 123:150 > changes.txt
3662 hg export --git -r 123:150 > changes.txt
3663
3663
3664 - split outgoing changes into a series of patches with
3664 - split outgoing changes into a series of patches with
3665 descriptive names::
3665 descriptive names::
3666
3666
3667 hg export -r "outgoing()" -o "%n-%m.patch"
3667 hg export -r "outgoing()" -o "%n-%m.patch"
3668
3668
3669 Returns 0 on success.
3669 Returns 0 on success.
3670 """
3670 """
3671 changesets += tuple(opts.get('rev', []))
3671 changesets += tuple(opts.get('rev', []))
3672 if not changesets:
3672 if not changesets:
3673 changesets = ['.']
3673 changesets = ['.']
3674 revs = scmutil.revrange(repo, changesets)
3674 revs = scmutil.revrange(repo, changesets)
3675 if not revs:
3675 if not revs:
3676 raise error.Abort(_("export requires at least one changeset"))
3676 raise error.Abort(_("export requires at least one changeset"))
3677 if len(revs) > 1:
3677 if len(revs) > 1:
3678 ui.note(_('exporting patches:\n'))
3678 ui.note(_('exporting patches:\n'))
3679 else:
3679 else:
3680 ui.note(_('exporting patch:\n'))
3680 ui.note(_('exporting patch:\n'))
3681 cmdutil.export(repo, revs, template=opts.get('output'),
3681 cmdutil.export(repo, revs, template=opts.get('output'),
3682 switch_parent=opts.get('switch_parent'),
3682 switch_parent=opts.get('switch_parent'),
3683 opts=patch.diffallopts(ui, opts))
3683 opts=patch.diffallopts(ui, opts))
3684
3684
3685 @command('files',
3685 @command('files',
3686 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3686 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3687 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3687 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3688 ] + walkopts + formatteropts + subrepoopts,
3688 ] + walkopts + formatteropts + subrepoopts,
3689 _('[OPTION]... [PATTERN]...'))
3689 _('[OPTION]... [PATTERN]...'))
3690 def files(ui, repo, *pats, **opts):
3690 def files(ui, repo, *pats, **opts):
3691 """list tracked files
3691 """list tracked files
3692
3692
3693 Print files under Mercurial control in the working directory or
3693 Print files under Mercurial control in the working directory or
3694 specified revision whose names match the given patterns (excluding
3694 specified revision whose names match the given patterns (excluding
3695 removed files).
3695 removed files).
3696
3696
3697 If no patterns are given to match, this command prints the names
3697 If no patterns are given to match, this command prints the names
3698 of all files under Mercurial control in the working directory.
3698 of all files under Mercurial control in the working directory.
3699
3699
3700 .. container:: verbose
3700 .. container:: verbose
3701
3701
3702 Examples:
3702 Examples:
3703
3703
3704 - list all files under the current directory::
3704 - list all files under the current directory::
3705
3705
3706 hg files .
3706 hg files .
3707
3707
3708 - shows sizes and flags for current revision::
3708 - shows sizes and flags for current revision::
3709
3709
3710 hg files -vr .
3710 hg files -vr .
3711
3711
3712 - list all files named README::
3712 - list all files named README::
3713
3713
3714 hg files -I "**/README"
3714 hg files -I "**/README"
3715
3715
3716 - list all binary files::
3716 - list all binary files::
3717
3717
3718 hg files "set:binary()"
3718 hg files "set:binary()"
3719
3719
3720 - find files containing a regular expression::
3720 - find files containing a regular expression::
3721
3721
3722 hg files "set:grep('bob')"
3722 hg files "set:grep('bob')"
3723
3723
3724 - search tracked file contents with xargs and grep::
3724 - search tracked file contents with xargs and grep::
3725
3725
3726 hg files -0 | xargs -0 grep foo
3726 hg files -0 | xargs -0 grep foo
3727
3727
3728 See :hg:`help patterns` and :hg:`help filesets` for more information
3728 See :hg:`help patterns` and :hg:`help filesets` for more information
3729 on specifying file patterns.
3729 on specifying file patterns.
3730
3730
3731 Returns 0 if a match is found, 1 otherwise.
3731 Returns 0 if a match is found, 1 otherwise.
3732
3732
3733 """
3733 """
3734 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3734 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3735
3735
3736 end = '\n'
3736 end = '\n'
3737 if opts.get('print0'):
3737 if opts.get('print0'):
3738 end = '\0'
3738 end = '\0'
3739 fm = ui.formatter('files', opts)
3739 fm = ui.formatter('files', opts)
3740 fmt = '%s' + end
3740 fmt = '%s' + end
3741
3741
3742 m = scmutil.match(ctx, pats, opts)
3742 m = scmutil.match(ctx, pats, opts)
3743 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3743 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3744
3744
3745 fm.end()
3745 fm.end()
3746
3746
3747 return ret
3747 return ret
3748
3748
3749 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3749 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3750 def forget(ui, repo, *pats, **opts):
3750 def forget(ui, repo, *pats, **opts):
3751 """forget the specified files on the next commit
3751 """forget the specified files on the next commit
3752
3752
3753 Mark the specified files so they will no longer be tracked
3753 Mark the specified files so they will no longer be tracked
3754 after the next commit.
3754 after the next commit.
3755
3755
3756 This only removes files from the current branch, not from the
3756 This only removes files from the current branch, not from the
3757 entire project history, and it does not delete them from the
3757 entire project history, and it does not delete them from the
3758 working directory.
3758 working directory.
3759
3759
3760 To delete the file from the working directory, see :hg:`remove`.
3760 To delete the file from the working directory, see :hg:`remove`.
3761
3761
3762 To undo a forget before the next commit, see :hg:`add`.
3762 To undo a forget before the next commit, see :hg:`add`.
3763
3763
3764 .. container:: verbose
3764 .. container:: verbose
3765
3765
3766 Examples:
3766 Examples:
3767
3767
3768 - forget newly-added binary files::
3768 - forget newly-added binary files::
3769
3769
3770 hg forget "set:added() and binary()"
3770 hg forget "set:added() and binary()"
3771
3771
3772 - forget files that would be excluded by .hgignore::
3772 - forget files that would be excluded by .hgignore::
3773
3773
3774 hg forget "set:hgignore()"
3774 hg forget "set:hgignore()"
3775
3775
3776 Returns 0 on success.
3776 Returns 0 on success.
3777 """
3777 """
3778
3778
3779 if not pats:
3779 if not pats:
3780 raise error.Abort(_('no files specified'))
3780 raise error.Abort(_('no files specified'))
3781
3781
3782 m = scmutil.match(repo[None], pats, opts)
3782 m = scmutil.match(repo[None], pats, opts)
3783 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3783 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3784 return rejected and 1 or 0
3784 return rejected and 1 or 0
3785
3785
3786 @command(
3786 @command(
3787 'graft',
3787 'graft',
3788 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3788 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3789 ('c', 'continue', False, _('resume interrupted graft')),
3789 ('c', 'continue', False, _('resume interrupted graft')),
3790 ('e', 'edit', False, _('invoke editor on commit messages')),
3790 ('e', 'edit', False, _('invoke editor on commit messages')),
3791 ('', 'log', None, _('append graft info to log message')),
3791 ('', 'log', None, _('append graft info to log message')),
3792 ('f', 'force', False, _('force graft')),
3792 ('f', 'force', False, _('force graft')),
3793 ('D', 'currentdate', False,
3793 ('D', 'currentdate', False,
3794 _('record the current date as commit date')),
3794 _('record the current date as commit date')),
3795 ('U', 'currentuser', False,
3795 ('U', 'currentuser', False,
3796 _('record the current user as committer'), _('DATE'))]
3796 _('record the current user as committer'), _('DATE'))]
3797 + commitopts2 + mergetoolopts + dryrunopts,
3797 + commitopts2 + mergetoolopts + dryrunopts,
3798 _('[OPTION]... [-r] REV...'))
3798 _('[OPTION]... [-r] REV...'))
3799 def graft(ui, repo, *revs, **opts):
3799 def graft(ui, repo, *revs, **opts):
3800 '''copy changes from other branches onto the current branch
3800 '''copy changes from other branches onto the current branch
3801
3801
3802 This command uses Mercurial's merge logic to copy individual
3802 This command uses Mercurial's merge logic to copy individual
3803 changes from other branches without merging branches in the
3803 changes from other branches without merging branches in the
3804 history graph. This is sometimes known as 'backporting' or
3804 history graph. This is sometimes known as 'backporting' or
3805 'cherry-picking'. By default, graft will copy user, date, and
3805 'cherry-picking'. By default, graft will copy user, date, and
3806 description from the source changesets.
3806 description from the source changesets.
3807
3807
3808 Changesets that are ancestors of the current revision, that have
3808 Changesets that are ancestors of the current revision, that have
3809 already been grafted, or that are merges will be skipped.
3809 already been grafted, or that are merges will be skipped.
3810
3810
3811 If --log is specified, log messages will have a comment appended
3811 If --log is specified, log messages will have a comment appended
3812 of the form::
3812 of the form::
3813
3813
3814 (grafted from CHANGESETHASH)
3814 (grafted from CHANGESETHASH)
3815
3815
3816 If --force is specified, revisions will be grafted even if they
3816 If --force is specified, revisions will be grafted even if they
3817 are already ancestors of or have been grafted to the destination.
3817 are already ancestors of or have been grafted to the destination.
3818 This is useful when the revisions have since been backed out.
3818 This is useful when the revisions have since been backed out.
3819
3819
3820 If a graft merge results in conflicts, the graft process is
3820 If a graft merge results in conflicts, the graft process is
3821 interrupted so that the current merge can be manually resolved.
3821 interrupted so that the current merge can be manually resolved.
3822 Once all conflicts are addressed, the graft process can be
3822 Once all conflicts are addressed, the graft process can be
3823 continued with the -c/--continue option.
3823 continued with the -c/--continue option.
3824
3824
3825 .. note::
3825 .. note::
3826
3826
3827 The -c/--continue option does not reapply earlier options, except
3827 The -c/--continue option does not reapply earlier options, except
3828 for --force.
3828 for --force.
3829
3829
3830 .. container:: verbose
3830 .. container:: verbose
3831
3831
3832 Examples:
3832 Examples:
3833
3833
3834 - copy a single change to the stable branch and edit its description::
3834 - copy a single change to the stable branch and edit its description::
3835
3835
3836 hg update stable
3836 hg update stable
3837 hg graft --edit 9393
3837 hg graft --edit 9393
3838
3838
3839 - graft a range of changesets with one exception, updating dates::
3839 - graft a range of changesets with one exception, updating dates::
3840
3840
3841 hg graft -D "2085::2093 and not 2091"
3841 hg graft -D "2085::2093 and not 2091"
3842
3842
3843 - continue a graft after resolving conflicts::
3843 - continue a graft after resolving conflicts::
3844
3844
3845 hg graft -c
3845 hg graft -c
3846
3846
3847 - show the source of a grafted changeset::
3847 - show the source of a grafted changeset::
3848
3848
3849 hg log --debug -r .
3849 hg log --debug -r .
3850
3850
3851 See :hg:`help revisions` and :hg:`help revsets` for more about
3851 See :hg:`help revisions` and :hg:`help revsets` for more about
3852 specifying revisions.
3852 specifying revisions.
3853
3853
3854 Returns 0 on successful completion.
3854 Returns 0 on successful completion.
3855 '''
3855 '''
3856 wlock = None
3856 wlock = None
3857 try:
3857 try:
3858 wlock = repo.wlock()
3858 wlock = repo.wlock()
3859 return _dograft(ui, repo, *revs, **opts)
3859 return _dograft(ui, repo, *revs, **opts)
3860 finally:
3860 finally:
3861 release(wlock)
3861 release(wlock)
3862
3862
3863 def _dograft(ui, repo, *revs, **opts):
3863 def _dograft(ui, repo, *revs, **opts):
3864 revs = list(revs)
3864 revs = list(revs)
3865 revs.extend(opts['rev'])
3865 revs.extend(opts['rev'])
3866
3866
3867 if not opts.get('user') and opts.get('currentuser'):
3867 if not opts.get('user') and opts.get('currentuser'):
3868 opts['user'] = ui.username()
3868 opts['user'] = ui.username()
3869 if not opts.get('date') and opts.get('currentdate'):
3869 if not opts.get('date') and opts.get('currentdate'):
3870 opts['date'] = "%d %d" % util.makedate()
3870 opts['date'] = "%d %d" % util.makedate()
3871
3871
3872 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3872 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3873
3873
3874 cont = False
3874 cont = False
3875 if opts['continue']:
3875 if opts['continue']:
3876 cont = True
3876 cont = True
3877 if revs:
3877 if revs:
3878 raise error.Abort(_("can't specify --continue and revisions"))
3878 raise error.Abort(_("can't specify --continue and revisions"))
3879 # read in unfinished revisions
3879 # read in unfinished revisions
3880 try:
3880 try:
3881 nodes = repo.vfs.read('graftstate').splitlines()
3881 nodes = repo.vfs.read('graftstate').splitlines()
3882 revs = [repo[node].rev() for node in nodes]
3882 revs = [repo[node].rev() for node in nodes]
3883 except IOError as inst:
3883 except IOError as inst:
3884 if inst.errno != errno.ENOENT:
3884 if inst.errno != errno.ENOENT:
3885 raise
3885 raise
3886 raise error.Abort(_("no graft state found, can't continue"))
3886 raise error.Abort(_("no graft state found, can't continue"))
3887 else:
3887 else:
3888 cmdutil.checkunfinished(repo)
3888 cmdutil.checkunfinished(repo)
3889 cmdutil.bailifchanged(repo)
3889 cmdutil.bailifchanged(repo)
3890 if not revs:
3890 if not revs:
3891 raise error.Abort(_('no revisions specified'))
3891 raise error.Abort(_('no revisions specified'))
3892 revs = scmutil.revrange(repo, revs)
3892 revs = scmutil.revrange(repo, revs)
3893
3893
3894 skipped = set()
3894 skipped = set()
3895 # check for merges
3895 # check for merges
3896 for rev in repo.revs('%ld and merge()', revs):
3896 for rev in repo.revs('%ld and merge()', revs):
3897 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3897 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3898 skipped.add(rev)
3898 skipped.add(rev)
3899 revs = [r for r in revs if r not in skipped]
3899 revs = [r for r in revs if r not in skipped]
3900 if not revs:
3900 if not revs:
3901 return -1
3901 return -1
3902
3902
3903 # Don't check in the --continue case, in effect retaining --force across
3903 # Don't check in the --continue case, in effect retaining --force across
3904 # --continues. That's because without --force, any revisions we decided to
3904 # --continues. That's because without --force, any revisions we decided to
3905 # skip would have been filtered out here, so they wouldn't have made their
3905 # skip would have been filtered out here, so they wouldn't have made their
3906 # way to the graftstate. With --force, any revisions we would have otherwise
3906 # way to the graftstate. With --force, any revisions we would have otherwise
3907 # skipped would not have been filtered out, and if they hadn't been applied
3907 # skipped would not have been filtered out, and if they hadn't been applied
3908 # already, they'd have been in the graftstate.
3908 # already, they'd have been in the graftstate.
3909 if not (cont or opts.get('force')):
3909 if not (cont or opts.get('force')):
3910 # check for ancestors of dest branch
3910 # check for ancestors of dest branch
3911 crev = repo['.'].rev()
3911 crev = repo['.'].rev()
3912 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3912 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3913 # Cannot use x.remove(y) on smart set, this has to be a list.
3913 # Cannot use x.remove(y) on smart set, this has to be a list.
3914 # XXX make this lazy in the future
3914 # XXX make this lazy in the future
3915 revs = list(revs)
3915 revs = list(revs)
3916 # don't mutate while iterating, create a copy
3916 # don't mutate while iterating, create a copy
3917 for rev in list(revs):
3917 for rev in list(revs):
3918 if rev in ancestors:
3918 if rev in ancestors:
3919 ui.warn(_('skipping ancestor revision %d:%s\n') %
3919 ui.warn(_('skipping ancestor revision %d:%s\n') %
3920 (rev, repo[rev]))
3920 (rev, repo[rev]))
3921 # XXX remove on list is slow
3921 # XXX remove on list is slow
3922 revs.remove(rev)
3922 revs.remove(rev)
3923 if not revs:
3923 if not revs:
3924 return -1
3924 return -1
3925
3925
3926 # analyze revs for earlier grafts
3926 # analyze revs for earlier grafts
3927 ids = {}
3927 ids = {}
3928 for ctx in repo.set("%ld", revs):
3928 for ctx in repo.set("%ld", revs):
3929 ids[ctx.hex()] = ctx.rev()
3929 ids[ctx.hex()] = ctx.rev()
3930 n = ctx.extra().get('source')
3930 n = ctx.extra().get('source')
3931 if n:
3931 if n:
3932 ids[n] = ctx.rev()
3932 ids[n] = ctx.rev()
3933
3933
3934 # check ancestors for earlier grafts
3934 # check ancestors for earlier grafts
3935 ui.debug('scanning for duplicate grafts\n')
3935 ui.debug('scanning for duplicate grafts\n')
3936
3936
3937 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3937 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3938 ctx = repo[rev]
3938 ctx = repo[rev]
3939 n = ctx.extra().get('source')
3939 n = ctx.extra().get('source')
3940 if n in ids:
3940 if n in ids:
3941 try:
3941 try:
3942 r = repo[n].rev()
3942 r = repo[n].rev()
3943 except error.RepoLookupError:
3943 except error.RepoLookupError:
3944 r = None
3944 r = None
3945 if r in revs:
3945 if r in revs:
3946 ui.warn(_('skipping revision %d:%s '
3946 ui.warn(_('skipping revision %d:%s '
3947 '(already grafted to %d:%s)\n')
3947 '(already grafted to %d:%s)\n')
3948 % (r, repo[r], rev, ctx))
3948 % (r, repo[r], rev, ctx))
3949 revs.remove(r)
3949 revs.remove(r)
3950 elif ids[n] in revs:
3950 elif ids[n] in revs:
3951 if r is None:
3951 if r is None:
3952 ui.warn(_('skipping already grafted revision %d:%s '
3952 ui.warn(_('skipping already grafted revision %d:%s '
3953 '(%d:%s also has unknown origin %s)\n')
3953 '(%d:%s also has unknown origin %s)\n')
3954 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3954 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3955 else:
3955 else:
3956 ui.warn(_('skipping already grafted revision %d:%s '
3956 ui.warn(_('skipping already grafted revision %d:%s '
3957 '(%d:%s also has origin %d:%s)\n')
3957 '(%d:%s also has origin %d:%s)\n')
3958 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3958 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3959 revs.remove(ids[n])
3959 revs.remove(ids[n])
3960 elif ctx.hex() in ids:
3960 elif ctx.hex() in ids:
3961 r = ids[ctx.hex()]
3961 r = ids[ctx.hex()]
3962 ui.warn(_('skipping already grafted revision %d:%s '
3962 ui.warn(_('skipping already grafted revision %d:%s '
3963 '(was grafted from %d:%s)\n') %
3963 '(was grafted from %d:%s)\n') %
3964 (r, repo[r], rev, ctx))
3964 (r, repo[r], rev, ctx))
3965 revs.remove(r)
3965 revs.remove(r)
3966 if not revs:
3966 if not revs:
3967 return -1
3967 return -1
3968
3968
3969 try:
3969 try:
3970 for pos, ctx in enumerate(repo.set("%ld", revs)):
3970 for pos, ctx in enumerate(repo.set("%ld", revs)):
3971 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3971 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3972 ctx.description().split('\n', 1)[0])
3972 ctx.description().split('\n', 1)[0])
3973 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3973 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3974 if names:
3974 if names:
3975 desc += ' (%s)' % ' '.join(names)
3975 desc += ' (%s)' % ' '.join(names)
3976 ui.status(_('grafting %s\n') % desc)
3976 ui.status(_('grafting %s\n') % desc)
3977 if opts.get('dry_run'):
3977 if opts.get('dry_run'):
3978 continue
3978 continue
3979
3979
3980 extra = ctx.extra().copy()
3980 extra = ctx.extra().copy()
3981 del extra['branch']
3981 del extra['branch']
3982 source = extra.get('source')
3982 source = extra.get('source')
3983 if source:
3983 if source:
3984 extra['intermediate-source'] = ctx.hex()
3984 extra['intermediate-source'] = ctx.hex()
3985 else:
3985 else:
3986 extra['source'] = ctx.hex()
3986 extra['source'] = ctx.hex()
3987 user = ctx.user()
3987 user = ctx.user()
3988 if opts.get('user'):
3988 if opts.get('user'):
3989 user = opts['user']
3989 user = opts['user']
3990 date = ctx.date()
3990 date = ctx.date()
3991 if opts.get('date'):
3991 if opts.get('date'):
3992 date = opts['date']
3992 date = opts['date']
3993 message = ctx.description()
3993 message = ctx.description()
3994 if opts.get('log'):
3994 if opts.get('log'):
3995 message += '\n(grafted from %s)' % ctx.hex()
3995 message += '\n(grafted from %s)' % ctx.hex()
3996
3996
3997 # we don't merge the first commit when continuing
3997 # we don't merge the first commit when continuing
3998 if not cont:
3998 if not cont:
3999 # perform the graft merge with p1(rev) as 'ancestor'
3999 # perform the graft merge with p1(rev) as 'ancestor'
4000 try:
4000 try:
4001 # ui.forcemerge is an internal variable, do not document
4001 # ui.forcemerge is an internal variable, do not document
4002 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4002 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4003 'graft')
4003 'graft')
4004 stats = mergemod.graft(repo, ctx, ctx.p1(),
4004 stats = mergemod.graft(repo, ctx, ctx.p1(),
4005 ['local', 'graft'])
4005 ['local', 'graft'])
4006 finally:
4006 finally:
4007 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4007 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4008 # report any conflicts
4008 # report any conflicts
4009 if stats and stats[3] > 0:
4009 if stats and stats[3] > 0:
4010 # write out state for --continue
4010 # write out state for --continue
4011 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4011 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4012 repo.vfs.write('graftstate', ''.join(nodelines))
4012 repo.vfs.write('graftstate', ''.join(nodelines))
4013 extra = ''
4013 extra = ''
4014 if opts.get('user'):
4014 if opts.get('user'):
4015 extra += ' --user %s' % opts['user']
4015 extra += ' --user %s' % opts['user']
4016 if opts.get('date'):
4016 if opts.get('date'):
4017 extra += ' --date %s' % opts['date']
4017 extra += ' --date %s' % opts['date']
4018 if opts.get('log'):
4018 if opts.get('log'):
4019 extra += ' --log'
4019 extra += ' --log'
4020 hint=_('use hg resolve and hg graft --continue%s') % extra
4020 hint=_('use hg resolve and hg graft --continue%s') % extra
4021 raise error.Abort(
4021 raise error.Abort(
4022 _("unresolved conflicts, can't continue"),
4022 _("unresolved conflicts, can't continue"),
4023 hint=hint)
4023 hint=hint)
4024 else:
4024 else:
4025 cont = False
4025 cont = False
4026
4026
4027 # commit
4027 # commit
4028 node = repo.commit(text=message, user=user,
4028 node = repo.commit(text=message, user=user,
4029 date=date, extra=extra, editor=editor)
4029 date=date, extra=extra, editor=editor)
4030 if node is None:
4030 if node is None:
4031 ui.warn(
4031 ui.warn(
4032 _('note: graft of %d:%s created no changes to commit\n') %
4032 _('note: graft of %d:%s created no changes to commit\n') %
4033 (ctx.rev(), ctx))
4033 (ctx.rev(), ctx))
4034 finally:
4034 finally:
4035 # TODO: get rid of this meaningless try/finally enclosing.
4035 # TODO: get rid of this meaningless try/finally enclosing.
4036 # this is kept only to reduce changes in a patch.
4036 # this is kept only to reduce changes in a patch.
4037 pass
4037 pass
4038
4038
4039 # remove state when we complete successfully
4039 # remove state when we complete successfully
4040 if not opts.get('dry_run'):
4040 if not opts.get('dry_run'):
4041 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4041 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4042
4042
4043 return 0
4043 return 0
4044
4044
4045 @command('grep',
4045 @command('grep',
4046 [('0', 'print0', None, _('end fields with NUL')),
4046 [('0', 'print0', None, _('end fields with NUL')),
4047 ('', 'all', None, _('print all revisions that match')),
4047 ('', 'all', None, _('print all revisions that match')),
4048 ('a', 'text', None, _('treat all files as text')),
4048 ('a', 'text', None, _('treat all files as text')),
4049 ('f', 'follow', None,
4049 ('f', 'follow', None,
4050 _('follow changeset history,'
4050 _('follow changeset history,'
4051 ' or file history across copies and renames')),
4051 ' or file history across copies and renames')),
4052 ('i', 'ignore-case', None, _('ignore case when matching')),
4052 ('i', 'ignore-case', None, _('ignore case when matching')),
4053 ('l', 'files-with-matches', None,
4053 ('l', 'files-with-matches', None,
4054 _('print only filenames and revisions that match')),
4054 _('print only filenames and revisions that match')),
4055 ('n', 'line-number', None, _('print matching line numbers')),
4055 ('n', 'line-number', None, _('print matching line numbers')),
4056 ('r', 'rev', [],
4056 ('r', 'rev', [],
4057 _('only search files changed within revision range'), _('REV')),
4057 _('only search files changed within revision range'), _('REV')),
4058 ('u', 'user', None, _('list the author (long with -v)')),
4058 ('u', 'user', None, _('list the author (long with -v)')),
4059 ('d', 'date', None, _('list the date (short with -q)')),
4059 ('d', 'date', None, _('list the date (short with -q)')),
4060 ] + walkopts,
4060 ] + walkopts,
4061 _('[OPTION]... PATTERN [FILE]...'),
4061 _('[OPTION]... PATTERN [FILE]...'),
4062 inferrepo=True)
4062 inferrepo=True)
4063 def grep(ui, repo, pattern, *pats, **opts):
4063 def grep(ui, repo, pattern, *pats, **opts):
4064 """search for a pattern in specified files and revisions
4064 """search for a pattern in specified files and revisions
4065
4065
4066 Search revisions of files for a regular expression.
4066 Search revisions of files for a regular expression.
4067
4067
4068 This command behaves differently than Unix grep. It only accepts
4068 This command behaves differently than Unix grep. It only accepts
4069 Python/Perl regexps. It searches repository history, not the
4069 Python/Perl regexps. It searches repository history, not the
4070 working directory. It always prints the revision number in which a
4070 working directory. It always prints the revision number in which a
4071 match appears.
4071 match appears.
4072
4072
4073 By default, grep only prints output for the first revision of a
4073 By default, grep only prints output for the first revision of a
4074 file in which it finds a match. To get it to print every revision
4074 file in which it finds a match. To get it to print every revision
4075 that contains a change in match status ("-" for a match that
4075 that contains a change in match status ("-" for a match that
4076 becomes a non-match, or "+" for a non-match that becomes a match),
4076 becomes a non-match, or "+" for a non-match that becomes a match),
4077 use the --all flag.
4077 use the --all flag.
4078
4078
4079 Returns 0 if a match is found, 1 otherwise.
4079 Returns 0 if a match is found, 1 otherwise.
4080 """
4080 """
4081 reflags = re.M
4081 reflags = re.M
4082 if opts.get('ignore_case'):
4082 if opts.get('ignore_case'):
4083 reflags |= re.I
4083 reflags |= re.I
4084 try:
4084 try:
4085 regexp = util.re.compile(pattern, reflags)
4085 regexp = util.re.compile(pattern, reflags)
4086 except re.error as inst:
4086 except re.error as inst:
4087 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4087 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4088 return 1
4088 return 1
4089 sep, eol = ':', '\n'
4089 sep, eol = ':', '\n'
4090 if opts.get('print0'):
4090 if opts.get('print0'):
4091 sep = eol = '\0'
4091 sep = eol = '\0'
4092
4092
4093 getfile = util.lrucachefunc(repo.file)
4093 getfile = util.lrucachefunc(repo.file)
4094
4094
4095 def matchlines(body):
4095 def matchlines(body):
4096 begin = 0
4096 begin = 0
4097 linenum = 0
4097 linenum = 0
4098 while begin < len(body):
4098 while begin < len(body):
4099 match = regexp.search(body, begin)
4099 match = regexp.search(body, begin)
4100 if not match:
4100 if not match:
4101 break
4101 break
4102 mstart, mend = match.span()
4102 mstart, mend = match.span()
4103 linenum += body.count('\n', begin, mstart) + 1
4103 linenum += body.count('\n', begin, mstart) + 1
4104 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4104 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4105 begin = body.find('\n', mend) + 1 or len(body) + 1
4105 begin = body.find('\n', mend) + 1 or len(body) + 1
4106 lend = begin - 1
4106 lend = begin - 1
4107 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4107 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4108
4108
4109 class linestate(object):
4109 class linestate(object):
4110 def __init__(self, line, linenum, colstart, colend):
4110 def __init__(self, line, linenum, colstart, colend):
4111 self.line = line
4111 self.line = line
4112 self.linenum = linenum
4112 self.linenum = linenum
4113 self.colstart = colstart
4113 self.colstart = colstart
4114 self.colend = colend
4114 self.colend = colend
4115
4115
4116 def __hash__(self):
4116 def __hash__(self):
4117 return hash((self.linenum, self.line))
4117 return hash((self.linenum, self.line))
4118
4118
4119 def __eq__(self, other):
4119 def __eq__(self, other):
4120 return self.line == other.line
4120 return self.line == other.line
4121
4121
4122 def __iter__(self):
4122 def __iter__(self):
4123 yield (self.line[:self.colstart], '')
4123 yield (self.line[:self.colstart], '')
4124 yield (self.line[self.colstart:self.colend], 'grep.match')
4124 yield (self.line[self.colstart:self.colend], 'grep.match')
4125 rest = self.line[self.colend:]
4125 rest = self.line[self.colend:]
4126 while rest != '':
4126 while rest != '':
4127 match = regexp.search(rest)
4127 match = regexp.search(rest)
4128 if not match:
4128 if not match:
4129 yield (rest, '')
4129 yield (rest, '')
4130 break
4130 break
4131 mstart, mend = match.span()
4131 mstart, mend = match.span()
4132 yield (rest[:mstart], '')
4132 yield (rest[:mstart], '')
4133 yield (rest[mstart:mend], 'grep.match')
4133 yield (rest[mstart:mend], 'grep.match')
4134 rest = rest[mend:]
4134 rest = rest[mend:]
4135
4135
4136 matches = {}
4136 matches = {}
4137 copies = {}
4137 copies = {}
4138 def grepbody(fn, rev, body):
4138 def grepbody(fn, rev, body):
4139 matches[rev].setdefault(fn, [])
4139 matches[rev].setdefault(fn, [])
4140 m = matches[rev][fn]
4140 m = matches[rev][fn]
4141 for lnum, cstart, cend, line in matchlines(body):
4141 for lnum, cstart, cend, line in matchlines(body):
4142 s = linestate(line, lnum, cstart, cend)
4142 s = linestate(line, lnum, cstart, cend)
4143 m.append(s)
4143 m.append(s)
4144
4144
4145 def difflinestates(a, b):
4145 def difflinestates(a, b):
4146 sm = difflib.SequenceMatcher(None, a, b)
4146 sm = difflib.SequenceMatcher(None, a, b)
4147 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4147 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4148 if tag == 'insert':
4148 if tag == 'insert':
4149 for i in xrange(blo, bhi):
4149 for i in xrange(blo, bhi):
4150 yield ('+', b[i])
4150 yield ('+', b[i])
4151 elif tag == 'delete':
4151 elif tag == 'delete':
4152 for i in xrange(alo, ahi):
4152 for i in xrange(alo, ahi):
4153 yield ('-', a[i])
4153 yield ('-', a[i])
4154 elif tag == 'replace':
4154 elif tag == 'replace':
4155 for i in xrange(alo, ahi):
4155 for i in xrange(alo, ahi):
4156 yield ('-', a[i])
4156 yield ('-', a[i])
4157 for i in xrange(blo, bhi):
4157 for i in xrange(blo, bhi):
4158 yield ('+', b[i])
4158 yield ('+', b[i])
4159
4159
4160 def display(fn, ctx, pstates, states):
4160 def display(fn, ctx, pstates, states):
4161 rev = ctx.rev()
4161 rev = ctx.rev()
4162 if ui.quiet:
4162 if ui.quiet:
4163 datefunc = util.shortdate
4163 datefunc = util.shortdate
4164 else:
4164 else:
4165 datefunc = util.datestr
4165 datefunc = util.datestr
4166 found = False
4166 found = False
4167 @util.cachefunc
4167 @util.cachefunc
4168 def binary():
4168 def binary():
4169 flog = getfile(fn)
4169 flog = getfile(fn)
4170 return util.binary(flog.read(ctx.filenode(fn)))
4170 return util.binary(flog.read(ctx.filenode(fn)))
4171
4171
4172 if opts.get('all'):
4172 if opts.get('all'):
4173 iter = difflinestates(pstates, states)
4173 iter = difflinestates(pstates, states)
4174 else:
4174 else:
4175 iter = [('', l) for l in states]
4175 iter = [('', l) for l in states]
4176 for change, l in iter:
4176 for change, l in iter:
4177 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4177 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4178
4178
4179 if opts.get('line_number'):
4179 if opts.get('line_number'):
4180 cols.append((str(l.linenum), 'grep.linenumber'))
4180 cols.append((str(l.linenum), 'grep.linenumber'))
4181 if opts.get('all'):
4181 if opts.get('all'):
4182 cols.append((change, 'grep.change'))
4182 cols.append((change, 'grep.change'))
4183 if opts.get('user'):
4183 if opts.get('user'):
4184 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4184 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4185 if opts.get('date'):
4185 if opts.get('date'):
4186 cols.append((datefunc(ctx.date()), 'grep.date'))
4186 cols.append((datefunc(ctx.date()), 'grep.date'))
4187 for col, label in cols[:-1]:
4187 for col, label in cols[:-1]:
4188 ui.write(col, label=label)
4188 ui.write(col, label=label)
4189 ui.write(sep, label='grep.sep')
4189 ui.write(sep, label='grep.sep')
4190 ui.write(cols[-1][0], label=cols[-1][1])
4190 ui.write(cols[-1][0], label=cols[-1][1])
4191 if not opts.get('files_with_matches'):
4191 if not opts.get('files_with_matches'):
4192 ui.write(sep, label='grep.sep')
4192 ui.write(sep, label='grep.sep')
4193 if not opts.get('text') and binary():
4193 if not opts.get('text') and binary():
4194 ui.write(" Binary file matches")
4194 ui.write(" Binary file matches")
4195 else:
4195 else:
4196 for s, label in l:
4196 for s, label in l:
4197 ui.write(s, label=label)
4197 ui.write(s, label=label)
4198 ui.write(eol)
4198 ui.write(eol)
4199 found = True
4199 found = True
4200 if opts.get('files_with_matches'):
4200 if opts.get('files_with_matches'):
4201 break
4201 break
4202 return found
4202 return found
4203
4203
4204 skip = {}
4204 skip = {}
4205 revfiles = {}
4205 revfiles = {}
4206 matchfn = scmutil.match(repo[None], pats, opts)
4206 matchfn = scmutil.match(repo[None], pats, opts)
4207 found = False
4207 found = False
4208 follow = opts.get('follow')
4208 follow = opts.get('follow')
4209
4209
4210 def prep(ctx, fns):
4210 def prep(ctx, fns):
4211 rev = ctx.rev()
4211 rev = ctx.rev()
4212 pctx = ctx.p1()
4212 pctx = ctx.p1()
4213 parent = pctx.rev()
4213 parent = pctx.rev()
4214 matches.setdefault(rev, {})
4214 matches.setdefault(rev, {})
4215 matches.setdefault(parent, {})
4215 matches.setdefault(parent, {})
4216 files = revfiles.setdefault(rev, [])
4216 files = revfiles.setdefault(rev, [])
4217 for fn in fns:
4217 for fn in fns:
4218 flog = getfile(fn)
4218 flog = getfile(fn)
4219 try:
4219 try:
4220 fnode = ctx.filenode(fn)
4220 fnode = ctx.filenode(fn)
4221 except error.LookupError:
4221 except error.LookupError:
4222 continue
4222 continue
4223
4223
4224 copied = flog.renamed(fnode)
4224 copied = flog.renamed(fnode)
4225 copy = follow and copied and copied[0]
4225 copy = follow and copied and copied[0]
4226 if copy:
4226 if copy:
4227 copies.setdefault(rev, {})[fn] = copy
4227 copies.setdefault(rev, {})[fn] = copy
4228 if fn in skip:
4228 if fn in skip:
4229 if copy:
4229 if copy:
4230 skip[copy] = True
4230 skip[copy] = True
4231 continue
4231 continue
4232 files.append(fn)
4232 files.append(fn)
4233
4233
4234 if fn not in matches[rev]:
4234 if fn not in matches[rev]:
4235 grepbody(fn, rev, flog.read(fnode))
4235 grepbody(fn, rev, flog.read(fnode))
4236
4236
4237 pfn = copy or fn
4237 pfn = copy or fn
4238 if pfn not in matches[parent]:
4238 if pfn not in matches[parent]:
4239 try:
4239 try:
4240 fnode = pctx.filenode(pfn)
4240 fnode = pctx.filenode(pfn)
4241 grepbody(pfn, parent, flog.read(fnode))
4241 grepbody(pfn, parent, flog.read(fnode))
4242 except error.LookupError:
4242 except error.LookupError:
4243 pass
4243 pass
4244
4244
4245 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4245 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4246 rev = ctx.rev()
4246 rev = ctx.rev()
4247 parent = ctx.p1().rev()
4247 parent = ctx.p1().rev()
4248 for fn in sorted(revfiles.get(rev, [])):
4248 for fn in sorted(revfiles.get(rev, [])):
4249 states = matches[rev][fn]
4249 states = matches[rev][fn]
4250 copy = copies.get(rev, {}).get(fn)
4250 copy = copies.get(rev, {}).get(fn)
4251 if fn in skip:
4251 if fn in skip:
4252 if copy:
4252 if copy:
4253 skip[copy] = True
4253 skip[copy] = True
4254 continue
4254 continue
4255 pstates = matches.get(parent, {}).get(copy or fn, [])
4255 pstates = matches.get(parent, {}).get(copy or fn, [])
4256 if pstates or states:
4256 if pstates or states:
4257 r = display(fn, ctx, pstates, states)
4257 r = display(fn, ctx, pstates, states)
4258 found = found or r
4258 found = found or r
4259 if r and not opts.get('all'):
4259 if r and not opts.get('all'):
4260 skip[fn] = True
4260 skip[fn] = True
4261 if copy:
4261 if copy:
4262 skip[copy] = True
4262 skip[copy] = True
4263 del matches[rev]
4263 del matches[rev]
4264 del revfiles[rev]
4264 del revfiles[rev]
4265
4265
4266 return not found
4266 return not found
4267
4267
4268 @command('heads',
4268 @command('heads',
4269 [('r', 'rev', '',
4269 [('r', 'rev', '',
4270 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4270 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4271 ('t', 'topo', False, _('show topological heads only')),
4271 ('t', 'topo', False, _('show topological heads only')),
4272 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4272 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4273 ('c', 'closed', False, _('show normal and closed branch heads')),
4273 ('c', 'closed', False, _('show normal and closed branch heads')),
4274 ] + templateopts,
4274 ] + templateopts,
4275 _('[-ct] [-r STARTREV] [REV]...'))
4275 _('[-ct] [-r STARTREV] [REV]...'))
4276 def heads(ui, repo, *branchrevs, **opts):
4276 def heads(ui, repo, *branchrevs, **opts):
4277 """show branch heads
4277 """show branch heads
4278
4278
4279 With no arguments, show all open branch heads in the repository.
4279 With no arguments, show all open branch heads in the repository.
4280 Branch heads are changesets that have no descendants on the
4280 Branch heads are changesets that have no descendants on the
4281 same branch. They are where development generally takes place and
4281 same branch. They are where development generally takes place and
4282 are the usual targets for update and merge operations.
4282 are the usual targets for update and merge operations.
4283
4283
4284 If one or more REVs are given, only open branch heads on the
4284 If one or more REVs are given, only open branch heads on the
4285 branches associated with the specified changesets are shown. This
4285 branches associated with the specified changesets are shown. This
4286 means that you can use :hg:`heads .` to see the heads on the
4286 means that you can use :hg:`heads .` to see the heads on the
4287 currently checked-out branch.
4287 currently checked-out branch.
4288
4288
4289 If -c/--closed is specified, also show branch heads marked closed
4289 If -c/--closed is specified, also show branch heads marked closed
4290 (see :hg:`commit --close-branch`).
4290 (see :hg:`commit --close-branch`).
4291
4291
4292 If STARTREV is specified, only those heads that are descendants of
4292 If STARTREV is specified, only those heads that are descendants of
4293 STARTREV will be displayed.
4293 STARTREV will be displayed.
4294
4294
4295 If -t/--topo is specified, named branch mechanics will be ignored and only
4295 If -t/--topo is specified, named branch mechanics will be ignored and only
4296 topological heads (changesets with no children) will be shown.
4296 topological heads (changesets with no children) will be shown.
4297
4297
4298 Returns 0 if matching heads are found, 1 if not.
4298 Returns 0 if matching heads are found, 1 if not.
4299 """
4299 """
4300
4300
4301 start = None
4301 start = None
4302 if 'rev' in opts:
4302 if 'rev' in opts:
4303 start = scmutil.revsingle(repo, opts['rev'], None).node()
4303 start = scmutil.revsingle(repo, opts['rev'], None).node()
4304
4304
4305 if opts.get('topo'):
4305 if opts.get('topo'):
4306 heads = [repo[h] for h in repo.heads(start)]
4306 heads = [repo[h] for h in repo.heads(start)]
4307 else:
4307 else:
4308 heads = []
4308 heads = []
4309 for branch in repo.branchmap():
4309 for branch in repo.branchmap():
4310 heads += repo.branchheads(branch, start, opts.get('closed'))
4310 heads += repo.branchheads(branch, start, opts.get('closed'))
4311 heads = [repo[h] for h in heads]
4311 heads = [repo[h] for h in heads]
4312
4312
4313 if branchrevs:
4313 if branchrevs:
4314 branches = set(repo[br].branch() for br in branchrevs)
4314 branches = set(repo[br].branch() for br in branchrevs)
4315 heads = [h for h in heads if h.branch() in branches]
4315 heads = [h for h in heads if h.branch() in branches]
4316
4316
4317 if opts.get('active') and branchrevs:
4317 if opts.get('active') and branchrevs:
4318 dagheads = repo.heads(start)
4318 dagheads = repo.heads(start)
4319 heads = [h for h in heads if h.node() in dagheads]
4319 heads = [h for h in heads if h.node() in dagheads]
4320
4320
4321 if branchrevs:
4321 if branchrevs:
4322 haveheads = set(h.branch() for h in heads)
4322 haveheads = set(h.branch() for h in heads)
4323 if branches - haveheads:
4323 if branches - haveheads:
4324 headless = ', '.join(b for b in branches - haveheads)
4324 headless = ', '.join(b for b in branches - haveheads)
4325 msg = _('no open branch heads found on branches %s')
4325 msg = _('no open branch heads found on branches %s')
4326 if opts.get('rev'):
4326 if opts.get('rev'):
4327 msg += _(' (started at %s)') % opts['rev']
4327 msg += _(' (started at %s)') % opts['rev']
4328 ui.warn((msg + '\n') % headless)
4328 ui.warn((msg + '\n') % headless)
4329
4329
4330 if not heads:
4330 if not heads:
4331 return 1
4331 return 1
4332
4332
4333 heads = sorted(heads, key=lambda x: -x.rev())
4333 heads = sorted(heads, key=lambda x: -x.rev())
4334 displayer = cmdutil.show_changeset(ui, repo, opts)
4334 displayer = cmdutil.show_changeset(ui, repo, opts)
4335 for ctx in heads:
4335 for ctx in heads:
4336 displayer.show(ctx)
4336 displayer.show(ctx)
4337 displayer.close()
4337 displayer.close()
4338
4338
4339 @command('help',
4339 @command('help',
4340 [('e', 'extension', None, _('show only help for extensions')),
4340 [('e', 'extension', None, _('show only help for extensions')),
4341 ('c', 'command', None, _('show only help for commands')),
4341 ('c', 'command', None, _('show only help for commands')),
4342 ('k', 'keyword', None, _('show topics matching keyword')),
4342 ('k', 'keyword', None, _('show topics matching keyword')),
4343 ],
4343 ],
4344 _('[-eck] [TOPIC]'),
4344 _('[-eck] [TOPIC]'),
4345 norepo=True)
4345 norepo=True)
4346 def help_(ui, name=None, **opts):
4346 def help_(ui, name=None, **opts):
4347 """show help for a given topic or a help overview
4347 """show help for a given topic or a help overview
4348
4348
4349 With no arguments, print a list of commands with short help messages.
4349 With no arguments, print a list of commands with short help messages.
4350
4350
4351 Given a topic, extension, or command name, print help for that
4351 Given a topic, extension, or command name, print help for that
4352 topic.
4352 topic.
4353
4353
4354 Returns 0 if successful.
4354 Returns 0 if successful.
4355 """
4355 """
4356
4356
4357 textwidth = min(ui.termwidth(), 80) - 2
4357 textwidth = min(ui.termwidth(), 80) - 2
4358
4358
4359 keep = []
4359 keep = []
4360 if ui.verbose:
4360 if ui.verbose:
4361 keep.append('verbose')
4361 keep.append('verbose')
4362 if sys.platform.startswith('win'):
4362 if sys.platform.startswith('win'):
4363 keep.append('windows')
4363 keep.append('windows')
4364 elif sys.platform == 'OpenVMS':
4364 elif sys.platform == 'OpenVMS':
4365 keep.append('vms')
4365 keep.append('vms')
4366 elif sys.platform == 'plan9':
4366 elif sys.platform == 'plan9':
4367 keep.append('plan9')
4367 keep.append('plan9')
4368 else:
4368 else:
4369 keep.append('unix')
4369 keep.append('unix')
4370 keep.append(sys.platform.lower())
4370 keep.append(sys.platform.lower())
4371
4371
4372 section = None
4372 section = None
4373 subtopic = None
4373 subtopic = None
4374 if name and '.' in name:
4374 if name and '.' in name:
4375 name, section = name.split('.', 1)
4375 name, section = name.split('.', 1)
4376 section = section.lower()
4376 section = section.lower()
4377 if '.' in section:
4377 if '.' in section:
4378 subtopic, section = section.split('.', 1)
4378 subtopic, section = section.split('.', 1)
4379 else:
4379 else:
4380 subtopic = section
4380 subtopic = section
4381
4381
4382 text = help.help_(ui, name, subtopic=subtopic, **opts)
4382 text = help.help_(ui, name, subtopic=subtopic, **opts)
4383
4383
4384 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4384 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4385 section=section)
4385 section=section)
4386
4386
4387 # We could have been given a weird ".foo" section without a name
4387 # We could have been given a weird ".foo" section without a name
4388 # to look for, or we could have simply failed to found "foo.bar"
4388 # to look for, or we could have simply failed to found "foo.bar"
4389 # because bar isn't a section of foo
4389 # because bar isn't a section of foo
4390 if section and not (formatted and name):
4390 if section and not (formatted and name):
4391 raise error.Abort(_("help section not found"))
4391 raise error.Abort(_("help section not found"))
4392
4392
4393 if 'verbose' in pruned:
4393 if 'verbose' in pruned:
4394 keep.append('omitted')
4394 keep.append('omitted')
4395 else:
4395 else:
4396 keep.append('notomitted')
4396 keep.append('notomitted')
4397 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4397 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4398 section=section)
4398 section=section)
4399 ui.write(formatted)
4399 ui.write(formatted)
4400
4400
4401
4401
4402 @command('identify|id',
4402 @command('identify|id',
4403 [('r', 'rev', '',
4403 [('r', 'rev', '',
4404 _('identify the specified revision'), _('REV')),
4404 _('identify the specified revision'), _('REV')),
4405 ('n', 'num', None, _('show local revision number')),
4405 ('n', 'num', None, _('show local revision number')),
4406 ('i', 'id', None, _('show global revision id')),
4406 ('i', 'id', None, _('show global revision id')),
4407 ('b', 'branch', None, _('show branch')),
4407 ('b', 'branch', None, _('show branch')),
4408 ('t', 'tags', None, _('show tags')),
4408 ('t', 'tags', None, _('show tags')),
4409 ('B', 'bookmarks', None, _('show bookmarks')),
4409 ('B', 'bookmarks', None, _('show bookmarks')),
4410 ] + remoteopts,
4410 ] + remoteopts,
4411 _('[-nibtB] [-r REV] [SOURCE]'),
4411 _('[-nibtB] [-r REV] [SOURCE]'),
4412 optionalrepo=True)
4412 optionalrepo=True)
4413 def identify(ui, repo, source=None, rev=None,
4413 def identify(ui, repo, source=None, rev=None,
4414 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4414 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4415 """identify the working directory or specified revision
4415 """identify the working directory or specified revision
4416
4416
4417 Print a summary identifying the repository state at REV using one or
4417 Print a summary identifying the repository state at REV using one or
4418 two parent hash identifiers, followed by a "+" if the working
4418 two parent hash identifiers, followed by a "+" if the working
4419 directory has uncommitted changes, the branch name (if not default),
4419 directory has uncommitted changes, the branch name (if not default),
4420 a list of tags, and a list of bookmarks.
4420 a list of tags, and a list of bookmarks.
4421
4421
4422 When REV is not given, print a summary of the current state of the
4422 When REV is not given, print a summary of the current state of the
4423 repository.
4423 repository.
4424
4424
4425 Specifying a path to a repository root or Mercurial bundle will
4425 Specifying a path to a repository root or Mercurial bundle will
4426 cause lookup to operate on that repository/bundle.
4426 cause lookup to operate on that repository/bundle.
4427
4427
4428 .. container:: verbose
4428 .. container:: verbose
4429
4429
4430 Examples:
4430 Examples:
4431
4431
4432 - generate a build identifier for the working directory::
4432 - generate a build identifier for the working directory::
4433
4433
4434 hg id --id > build-id.dat
4434 hg id --id > build-id.dat
4435
4435
4436 - find the revision corresponding to a tag::
4436 - find the revision corresponding to a tag::
4437
4437
4438 hg id -n -r 1.3
4438 hg id -n -r 1.3
4439
4439
4440 - check the most recent revision of a remote repository::
4440 - check the most recent revision of a remote repository::
4441
4441
4442 hg id -r tip http://selenic.com/hg/
4442 hg id -r tip http://selenic.com/hg/
4443
4443
4444 See :hg:`log` for generating more information about specific revisions,
4444 See :hg:`log` for generating more information about specific revisions,
4445 including full hash identifiers.
4445 including full hash identifiers.
4446
4446
4447 Returns 0 if successful.
4447 Returns 0 if successful.
4448 """
4448 """
4449
4449
4450 if not repo and not source:
4450 if not repo and not source:
4451 raise error.Abort(_("there is no Mercurial repository here "
4451 raise error.Abort(_("there is no Mercurial repository here "
4452 "(.hg not found)"))
4452 "(.hg not found)"))
4453
4453
4454 if ui.debugflag:
4454 if ui.debugflag:
4455 hexfunc = hex
4455 hexfunc = hex
4456 else:
4456 else:
4457 hexfunc = short
4457 hexfunc = short
4458 default = not (num or id or branch or tags or bookmarks)
4458 default = not (num or id or branch or tags or bookmarks)
4459 output = []
4459 output = []
4460 revs = []
4460 revs = []
4461
4461
4462 if source:
4462 if source:
4463 source, branches = hg.parseurl(ui.expandpath(source))
4463 source, branches = hg.parseurl(ui.expandpath(source))
4464 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4464 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4465 repo = peer.local()
4465 repo = peer.local()
4466 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4466 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4467
4467
4468 if not repo:
4468 if not repo:
4469 if num or branch or tags:
4469 if num or branch or tags:
4470 raise error.Abort(
4470 raise error.Abort(
4471 _("can't query remote revision number, branch, or tags"))
4471 _("can't query remote revision number, branch, or tags"))
4472 if not rev and revs:
4472 if not rev and revs:
4473 rev = revs[0]
4473 rev = revs[0]
4474 if not rev:
4474 if not rev:
4475 rev = "tip"
4475 rev = "tip"
4476
4476
4477 remoterev = peer.lookup(rev)
4477 remoterev = peer.lookup(rev)
4478 if default or id:
4478 if default or id:
4479 output = [hexfunc(remoterev)]
4479 output = [hexfunc(remoterev)]
4480
4480
4481 def getbms():
4481 def getbms():
4482 bms = []
4482 bms = []
4483
4483
4484 if 'bookmarks' in peer.listkeys('namespaces'):
4484 if 'bookmarks' in peer.listkeys('namespaces'):
4485 hexremoterev = hex(remoterev)
4485 hexremoterev = hex(remoterev)
4486 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4486 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4487 if bmr == hexremoterev]
4487 if bmr == hexremoterev]
4488
4488
4489 return sorted(bms)
4489 return sorted(bms)
4490
4490
4491 if bookmarks:
4491 if bookmarks:
4492 output.extend(getbms())
4492 output.extend(getbms())
4493 elif default and not ui.quiet:
4493 elif default and not ui.quiet:
4494 # multiple bookmarks for a single parent separated by '/'
4494 # multiple bookmarks for a single parent separated by '/'
4495 bm = '/'.join(getbms())
4495 bm = '/'.join(getbms())
4496 if bm:
4496 if bm:
4497 output.append(bm)
4497 output.append(bm)
4498 else:
4498 else:
4499 ctx = scmutil.revsingle(repo, rev, None)
4499 ctx = scmutil.revsingle(repo, rev, None)
4500
4500
4501 if ctx.rev() is None:
4501 if ctx.rev() is None:
4502 ctx = repo[None]
4502 ctx = repo[None]
4503 parents = ctx.parents()
4503 parents = ctx.parents()
4504 taglist = []
4504 taglist = []
4505 for p in parents:
4505 for p in parents:
4506 taglist.extend(p.tags())
4506 taglist.extend(p.tags())
4507
4507
4508 changed = ""
4508 changed = ""
4509 if default or id or num:
4509 if default or id or num:
4510 if (any(repo.status())
4510 if (any(repo.status())
4511 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4511 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4512 changed = '+'
4512 changed = '+'
4513 if default or id:
4513 if default or id:
4514 output = ["%s%s" %
4514 output = ["%s%s" %
4515 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4515 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4516 if num:
4516 if num:
4517 output.append("%s%s" %
4517 output.append("%s%s" %
4518 ('+'.join([str(p.rev()) for p in parents]), changed))
4518 ('+'.join([str(p.rev()) for p in parents]), changed))
4519 else:
4519 else:
4520 if default or id:
4520 if default or id:
4521 output = [hexfunc(ctx.node())]
4521 output = [hexfunc(ctx.node())]
4522 if num:
4522 if num:
4523 output.append(str(ctx.rev()))
4523 output.append(str(ctx.rev()))
4524 taglist = ctx.tags()
4524 taglist = ctx.tags()
4525
4525
4526 if default and not ui.quiet:
4526 if default and not ui.quiet:
4527 b = ctx.branch()
4527 b = ctx.branch()
4528 if b != 'default':
4528 if b != 'default':
4529 output.append("(%s)" % b)
4529 output.append("(%s)" % b)
4530
4530
4531 # multiple tags for a single parent separated by '/'
4531 # multiple tags for a single parent separated by '/'
4532 t = '/'.join(taglist)
4532 t = '/'.join(taglist)
4533 if t:
4533 if t:
4534 output.append(t)
4534 output.append(t)
4535
4535
4536 # multiple bookmarks for a single parent separated by '/'
4536 # multiple bookmarks for a single parent separated by '/'
4537 bm = '/'.join(ctx.bookmarks())
4537 bm = '/'.join(ctx.bookmarks())
4538 if bm:
4538 if bm:
4539 output.append(bm)
4539 output.append(bm)
4540 else:
4540 else:
4541 if branch:
4541 if branch:
4542 output.append(ctx.branch())
4542 output.append(ctx.branch())
4543
4543
4544 if tags:
4544 if tags:
4545 output.extend(taglist)
4545 output.extend(taglist)
4546
4546
4547 if bookmarks:
4547 if bookmarks:
4548 output.extend(ctx.bookmarks())
4548 output.extend(ctx.bookmarks())
4549
4549
4550 ui.write("%s\n" % ' '.join(output))
4550 ui.write("%s\n" % ' '.join(output))
4551
4551
4552 @command('import|patch',
4552 @command('import|patch',
4553 [('p', 'strip', 1,
4553 [('p', 'strip', 1,
4554 _('directory strip option for patch. This has the same '
4554 _('directory strip option for patch. This has the same '
4555 'meaning as the corresponding patch option'), _('NUM')),
4555 'meaning as the corresponding patch option'), _('NUM')),
4556 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4556 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4557 ('e', 'edit', False, _('invoke editor on commit messages')),
4557 ('e', 'edit', False, _('invoke editor on commit messages')),
4558 ('f', 'force', None,
4558 ('f', 'force', None,
4559 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4559 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4560 ('', 'no-commit', None,
4560 ('', 'no-commit', None,
4561 _("don't commit, just update the working directory")),
4561 _("don't commit, just update the working directory")),
4562 ('', 'bypass', None,
4562 ('', 'bypass', None,
4563 _("apply patch without touching the working directory")),
4563 _("apply patch without touching the working directory")),
4564 ('', 'partial', None,
4564 ('', 'partial', None,
4565 _('commit even if some hunks fail')),
4565 _('commit even if some hunks fail')),
4566 ('', 'exact', None,
4566 ('', 'exact', None,
4567 _('apply patch to the nodes from which it was generated')),
4567 _('apply patch to the nodes from which it was generated')),
4568 ('', 'prefix', '',
4568 ('', 'prefix', '',
4569 _('apply patch to subdirectory'), _('DIR')),
4569 _('apply patch to subdirectory'), _('DIR')),
4570 ('', 'import-branch', None,
4570 ('', 'import-branch', None,
4571 _('use any branch information in patch (implied by --exact)'))] +
4571 _('use any branch information in patch (implied by --exact)'))] +
4572 commitopts + commitopts2 + similarityopts,
4572 commitopts + commitopts2 + similarityopts,
4573 _('[OPTION]... PATCH...'))
4573 _('[OPTION]... PATCH...'))
4574 def import_(ui, repo, patch1=None, *patches, **opts):
4574 def import_(ui, repo, patch1=None, *patches, **opts):
4575 """import an ordered set of patches
4575 """import an ordered set of patches
4576
4576
4577 Import a list of patches and commit them individually (unless
4577 Import a list of patches and commit them individually (unless
4578 --no-commit is specified).
4578 --no-commit is specified).
4579
4579
4580 To read a patch from standard input, use "-" as the patch name. If
4580 To read a patch from standard input, use "-" as the patch name. If
4581 a URL is specified, the patch will be downloaded from there.
4581 a URL is specified, the patch will be downloaded from there.
4582
4582
4583 Import first applies changes to the working directory (unless
4583 Import first applies changes to the working directory (unless
4584 --bypass is specified), import will abort if there are outstanding
4584 --bypass is specified), import will abort if there are outstanding
4585 changes.
4585 changes.
4586
4586
4587 Use --bypass to apply and commit patches directly to the
4587 Use --bypass to apply and commit patches directly to the
4588 repository, without affecting the working directory. Without
4588 repository, without affecting the working directory. Without
4589 --exact, patches will be applied on top of the working directory
4589 --exact, patches will be applied on top of the working directory
4590 parent revision.
4590 parent revision.
4591
4591
4592 You can import a patch straight from a mail message. Even patches
4592 You can import a patch straight from a mail message. Even patches
4593 as attachments work (to use the body part, it must have type
4593 as attachments work (to use the body part, it must have type
4594 text/plain or text/x-patch). From and Subject headers of email
4594 text/plain or text/x-patch). From and Subject headers of email
4595 message are used as default committer and commit message. All
4595 message are used as default committer and commit message. All
4596 text/plain body parts before first diff are added to the commit
4596 text/plain body parts before first diff are added to the commit
4597 message.
4597 message.
4598
4598
4599 If the imported patch was generated by :hg:`export`, user and
4599 If the imported patch was generated by :hg:`export`, user and
4600 description from patch override values from message headers and
4600 description from patch override values from message headers and
4601 body. Values given on command line with -m/--message and -u/--user
4601 body. Values given on command line with -m/--message and -u/--user
4602 override these.
4602 override these.
4603
4603
4604 If --exact is specified, import will set the working directory to
4604 If --exact is specified, import will set the working directory to
4605 the parent of each patch before applying it, and will abort if the
4605 the parent of each patch before applying it, and will abort if the
4606 resulting changeset has a different ID than the one recorded in
4606 resulting changeset has a different ID than the one recorded in
4607 the patch. This may happen due to character set problems or other
4607 the patch. This may happen due to character set problems or other
4608 deficiencies in the text patch format.
4608 deficiencies in the text patch format.
4609
4609
4610 Use --partial to ensure a changeset will be created from the patch
4610 Use --partial to ensure a changeset will be created from the patch
4611 even if some hunks fail to apply. Hunks that fail to apply will be
4611 even if some hunks fail to apply. Hunks that fail to apply will be
4612 written to a <target-file>.rej file. Conflicts can then be resolved
4612 written to a <target-file>.rej file. Conflicts can then be resolved
4613 by hand before :hg:`commit --amend` is run to update the created
4613 by hand before :hg:`commit --amend` is run to update the created
4614 changeset. This flag exists to let people import patches that
4614 changeset. This flag exists to let people import patches that
4615 partially apply without losing the associated metadata (author,
4615 partially apply without losing the associated metadata (author,
4616 date, description, ...).
4616 date, description, ...).
4617
4617
4618 .. note::
4618 .. note::
4619
4619
4620 When no hunks apply cleanly, :hg:`import --partial` will create
4620 When no hunks apply cleanly, :hg:`import --partial` will create
4621 an empty changeset, importing only the patch metadata.
4621 an empty changeset, importing only the patch metadata.
4622
4622
4623 With -s/--similarity, hg will attempt to discover renames and
4623 With -s/--similarity, hg will attempt to discover renames and
4624 copies in the patch in the same way as :hg:`addremove`.
4624 copies in the patch in the same way as :hg:`addremove`.
4625
4625
4626 It is possible to use external patch programs to perform the patch
4626 It is possible to use external patch programs to perform the patch
4627 by setting the ``ui.patch`` configuration option. For the default
4627 by setting the ``ui.patch`` configuration option. For the default
4628 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4628 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4629 See :hg:`help config` for more information about configuration
4629 See :hg:`help config` for more information about configuration
4630 files and how to use these options.
4630 files and how to use these options.
4631
4631
4632 See :hg:`help dates` for a list of formats valid for -d/--date.
4632 See :hg:`help dates` for a list of formats valid for -d/--date.
4633
4633
4634 .. container:: verbose
4634 .. container:: verbose
4635
4635
4636 Examples:
4636 Examples:
4637
4637
4638 - import a traditional patch from a website and detect renames::
4638 - import a traditional patch from a website and detect renames::
4639
4639
4640 hg import -s 80 http://example.com/bugfix.patch
4640 hg import -s 80 http://example.com/bugfix.patch
4641
4641
4642 - import a changeset from an hgweb server::
4642 - import a changeset from an hgweb server::
4643
4643
4644 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4644 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4645
4645
4646 - import all the patches in an Unix-style mbox::
4646 - import all the patches in an Unix-style mbox::
4647
4647
4648 hg import incoming-patches.mbox
4648 hg import incoming-patches.mbox
4649
4649
4650 - attempt to exactly restore an exported changeset (not always
4650 - attempt to exactly restore an exported changeset (not always
4651 possible)::
4651 possible)::
4652
4652
4653 hg import --exact proposed-fix.patch
4653 hg import --exact proposed-fix.patch
4654
4654
4655 - use an external tool to apply a patch which is too fuzzy for
4655 - use an external tool to apply a patch which is too fuzzy for
4656 the default internal tool.
4656 the default internal tool.
4657
4657
4658 hg import --config ui.patch="patch --merge" fuzzy.patch
4658 hg import --config ui.patch="patch --merge" fuzzy.patch
4659
4659
4660 - change the default fuzzing from 2 to a less strict 7
4660 - change the default fuzzing from 2 to a less strict 7
4661
4661
4662 hg import --config ui.fuzz=7 fuzz.patch
4662 hg import --config ui.fuzz=7 fuzz.patch
4663
4663
4664 Returns 0 on success, 1 on partial success (see --partial).
4664 Returns 0 on success, 1 on partial success (see --partial).
4665 """
4665 """
4666
4666
4667 if not patch1:
4667 if not patch1:
4668 raise error.Abort(_('need at least one patch to import'))
4668 raise error.Abort(_('need at least one patch to import'))
4669
4669
4670 patches = (patch1,) + patches
4670 patches = (patch1,) + patches
4671
4671
4672 date = opts.get('date')
4672 date = opts.get('date')
4673 if date:
4673 if date:
4674 opts['date'] = util.parsedate(date)
4674 opts['date'] = util.parsedate(date)
4675
4675
4676 exact = opts.get('exact')
4676 exact = opts.get('exact')
4677 update = not opts.get('bypass')
4677 update = not opts.get('bypass')
4678 if not update and opts.get('no_commit'):
4678 if not update and opts.get('no_commit'):
4679 raise error.Abort(_('cannot use --no-commit with --bypass'))
4679 raise error.Abort(_('cannot use --no-commit with --bypass'))
4680 try:
4680 try:
4681 sim = float(opts.get('similarity') or 0)
4681 sim = float(opts.get('similarity') or 0)
4682 except ValueError:
4682 except ValueError:
4683 raise error.Abort(_('similarity must be a number'))
4683 raise error.Abort(_('similarity must be a number'))
4684 if sim < 0 or sim > 100:
4684 if sim < 0 or sim > 100:
4685 raise error.Abort(_('similarity must be between 0 and 100'))
4685 raise error.Abort(_('similarity must be between 0 and 100'))
4686 if sim and not update:
4686 if sim and not update:
4687 raise error.Abort(_('cannot use --similarity with --bypass'))
4687 raise error.Abort(_('cannot use --similarity with --bypass'))
4688 if exact:
4688 if exact:
4689 if opts.get('edit'):
4689 if opts.get('edit'):
4690 raise error.Abort(_('cannot use --exact with --edit'))
4690 raise error.Abort(_('cannot use --exact with --edit'))
4691 if opts.get('prefix'):
4691 if opts.get('prefix'):
4692 raise error.Abort(_('cannot use --exact with --prefix'))
4692 raise error.Abort(_('cannot use --exact with --prefix'))
4693
4693
4694 base = opts["base"]
4694 base = opts["base"]
4695 wlock = dsguard = lock = tr = None
4695 wlock = dsguard = lock = tr = None
4696 msgs = []
4696 msgs = []
4697 ret = 0
4697 ret = 0
4698
4698
4699
4699
4700 try:
4700 try:
4701 try:
4701 try:
4702 wlock = repo.wlock()
4702 wlock = repo.wlock()
4703
4703
4704 if update:
4704 if update:
4705 cmdutil.checkunfinished(repo)
4705 cmdutil.checkunfinished(repo)
4706 if (exact or not opts.get('force')):
4706 if (exact or not opts.get('force')):
4707 cmdutil.bailifchanged(repo)
4707 cmdutil.bailifchanged(repo)
4708
4708
4709 if not opts.get('no_commit'):
4709 if not opts.get('no_commit'):
4710 lock = repo.lock()
4710 lock = repo.lock()
4711 tr = repo.transaction('import')
4711 tr = repo.transaction('import')
4712 else:
4712 else:
4713 dsguard = cmdutil.dirstateguard(repo, 'import')
4713 dsguard = cmdutil.dirstateguard(repo, 'import')
4714 parents = repo[None].parents()
4714 parents = repo[None].parents()
4715 for patchurl in patches:
4715 for patchurl in patches:
4716 if patchurl == '-':
4716 if patchurl == '-':
4717 ui.status(_('applying patch from stdin\n'))
4717 ui.status(_('applying patch from stdin\n'))
4718 patchfile = ui.fin
4718 patchfile = ui.fin
4719 patchurl = 'stdin' # for error message
4719 patchurl = 'stdin' # for error message
4720 else:
4720 else:
4721 patchurl = os.path.join(base, patchurl)
4721 patchurl = os.path.join(base, patchurl)
4722 ui.status(_('applying %s\n') % patchurl)
4722 ui.status(_('applying %s\n') % patchurl)
4723 patchfile = hg.openpath(ui, patchurl)
4723 patchfile = hg.openpath(ui, patchurl)
4724
4724
4725 haspatch = False
4725 haspatch = False
4726 for hunk in patch.split(patchfile):
4726 for hunk in patch.split(patchfile):
4727 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4727 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4728 parents, opts,
4728 parents, opts,
4729 msgs, hg.clean)
4729 msgs, hg.clean)
4730 if msg:
4730 if msg:
4731 haspatch = True
4731 haspatch = True
4732 ui.note(msg + '\n')
4732 ui.note(msg + '\n')
4733 if update or exact:
4733 if update or exact:
4734 parents = repo[None].parents()
4734 parents = repo[None].parents()
4735 else:
4735 else:
4736 parents = [repo[node]]
4736 parents = [repo[node]]
4737 if rej:
4737 if rej:
4738 ui.write_err(_("patch applied partially\n"))
4738 ui.write_err(_("patch applied partially\n"))
4739 ui.write_err(_("(fix the .rej files and run "
4739 ui.write_err(_("(fix the .rej files and run "
4740 "`hg commit --amend`)\n"))
4740 "`hg commit --amend`)\n"))
4741 ret = 1
4741 ret = 1
4742 break
4742 break
4743
4743
4744 if not haspatch:
4744 if not haspatch:
4745 raise error.Abort(_('%s: no diffs found') % patchurl)
4745 raise error.Abort(_('%s: no diffs found') % patchurl)
4746
4746
4747 if tr:
4747 if tr:
4748 tr.close()
4748 tr.close()
4749 if msgs:
4749 if msgs:
4750 repo.savecommitmessage('\n* * *\n'.join(msgs))
4750 repo.savecommitmessage('\n* * *\n'.join(msgs))
4751 if dsguard:
4751 if dsguard:
4752 dsguard.close()
4752 dsguard.close()
4753 return ret
4753 return ret
4754 finally:
4754 finally:
4755 # TODO: get rid of this meaningless try/finally enclosing.
4755 # TODO: get rid of this meaningless try/finally enclosing.
4756 # this is kept only to reduce changes in a patch.
4756 # this is kept only to reduce changes in a patch.
4757 pass
4757 pass
4758 finally:
4758 finally:
4759 if tr:
4759 if tr:
4760 tr.release()
4760 tr.release()
4761 release(lock, dsguard, wlock)
4761 release(lock, dsguard, wlock)
4762
4762
4763 @command('incoming|in',
4763 @command('incoming|in',
4764 [('f', 'force', None,
4764 [('f', 'force', None,
4765 _('run even if remote repository is unrelated')),
4765 _('run even if remote repository is unrelated')),
4766 ('n', 'newest-first', None, _('show newest record first')),
4766 ('n', 'newest-first', None, _('show newest record first')),
4767 ('', 'bundle', '',
4767 ('', 'bundle', '',
4768 _('file to store the bundles into'), _('FILE')),
4768 _('file to store the bundles into'), _('FILE')),
4769 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4769 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4770 ('B', 'bookmarks', False, _("compare bookmarks")),
4770 ('B', 'bookmarks', False, _("compare bookmarks")),
4771 ('b', 'branch', [],
4771 ('b', 'branch', [],
4772 _('a specific branch you would like to pull'), _('BRANCH')),
4772 _('a specific branch you would like to pull'), _('BRANCH')),
4773 ] + logopts + remoteopts + subrepoopts,
4773 ] + logopts + remoteopts + subrepoopts,
4774 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4774 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4775 def incoming(ui, repo, source="default", **opts):
4775 def incoming(ui, repo, source="default", **opts):
4776 """show new changesets found in source
4776 """show new changesets found in source
4777
4777
4778 Show new changesets found in the specified path/URL or the default
4778 Show new changesets found in the specified path/URL or the default
4779 pull location. These are the changesets that would have been pulled
4779 pull location. These are the changesets that would have been pulled
4780 if a pull at the time you issued this command.
4780 if a pull at the time you issued this command.
4781
4781
4782 See pull for valid source format details.
4782 See pull for valid source format details.
4783
4783
4784 .. container:: verbose
4784 .. container:: verbose
4785
4785
4786 With -B/--bookmarks, the result of bookmark comparison between
4786 With -B/--bookmarks, the result of bookmark comparison between
4787 local and remote repositories is displayed. With -v/--verbose,
4787 local and remote repositories is displayed. With -v/--verbose,
4788 status is also displayed for each bookmark like below::
4788 status is also displayed for each bookmark like below::
4789
4789
4790 BM1 01234567890a added
4790 BM1 01234567890a added
4791 BM2 1234567890ab advanced
4791 BM2 1234567890ab advanced
4792 BM3 234567890abc diverged
4792 BM3 234567890abc diverged
4793 BM4 34567890abcd changed
4793 BM4 34567890abcd changed
4794
4794
4795 The action taken locally when pulling depends on the
4795 The action taken locally when pulling depends on the
4796 status of each bookmark:
4796 status of each bookmark:
4797
4797
4798 :``added``: pull will create it
4798 :``added``: pull will create it
4799 :``advanced``: pull will update it
4799 :``advanced``: pull will update it
4800 :``diverged``: pull will create a divergent bookmark
4800 :``diverged``: pull will create a divergent bookmark
4801 :``changed``: result depends on remote changesets
4801 :``changed``: result depends on remote changesets
4802
4802
4803 From the point of view of pulling behavior, bookmark
4803 From the point of view of pulling behavior, bookmark
4804 existing only in the remote repository are treated as ``added``,
4804 existing only in the remote repository are treated as ``added``,
4805 even if it is in fact locally deleted.
4805 even if it is in fact locally deleted.
4806
4806
4807 .. container:: verbose
4807 .. container:: verbose
4808
4808
4809 For remote repository, using --bundle avoids downloading the
4809 For remote repository, using --bundle avoids downloading the
4810 changesets twice if the incoming is followed by a pull.
4810 changesets twice if the incoming is followed by a pull.
4811
4811
4812 Examples:
4812 Examples:
4813
4813
4814 - show incoming changes with patches and full description::
4814 - show incoming changes with patches and full description::
4815
4815
4816 hg incoming -vp
4816 hg incoming -vp
4817
4817
4818 - show incoming changes excluding merges, store a bundle::
4818 - show incoming changes excluding merges, store a bundle::
4819
4819
4820 hg in -vpM --bundle incoming.hg
4820 hg in -vpM --bundle incoming.hg
4821 hg pull incoming.hg
4821 hg pull incoming.hg
4822
4822
4823 - briefly list changes inside a bundle::
4823 - briefly list changes inside a bundle::
4824
4824
4825 hg in changes.hg -T "{desc|firstline}\\n"
4825 hg in changes.hg -T "{desc|firstline}\\n"
4826
4826
4827 Returns 0 if there are incoming changes, 1 otherwise.
4827 Returns 0 if there are incoming changes, 1 otherwise.
4828 """
4828 """
4829 if opts.get('graph'):
4829 if opts.get('graph'):
4830 cmdutil.checkunsupportedgraphflags([], opts)
4830 cmdutil.checkunsupportedgraphflags([], opts)
4831 def display(other, chlist, displayer):
4831 def display(other, chlist, displayer):
4832 revdag = cmdutil.graphrevs(other, chlist, opts)
4832 revdag = cmdutil.graphrevs(other, chlist, opts)
4833 cmdutil.displaygraph(ui, repo, revdag, displayer,
4833 cmdutil.displaygraph(ui, repo, revdag, displayer,
4834 graphmod.asciiedges)
4834 graphmod.asciiedges)
4835
4835
4836 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4836 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4837 return 0
4837 return 0
4838
4838
4839 if opts.get('bundle') and opts.get('subrepos'):
4839 if opts.get('bundle') and opts.get('subrepos'):
4840 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4840 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4841
4841
4842 if opts.get('bookmarks'):
4842 if opts.get('bookmarks'):
4843 source, branches = hg.parseurl(ui.expandpath(source),
4843 source, branches = hg.parseurl(ui.expandpath(source),
4844 opts.get('branch'))
4844 opts.get('branch'))
4845 other = hg.peer(repo, opts, source)
4845 other = hg.peer(repo, opts, source)
4846 if 'bookmarks' not in other.listkeys('namespaces'):
4846 if 'bookmarks' not in other.listkeys('namespaces'):
4847 ui.warn(_("remote doesn't support bookmarks\n"))
4847 ui.warn(_("remote doesn't support bookmarks\n"))
4848 return 0
4848 return 0
4849 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4849 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4850 return bookmarks.incoming(ui, repo, other)
4850 return bookmarks.incoming(ui, repo, other)
4851
4851
4852 repo._subtoppath = ui.expandpath(source)
4852 repo._subtoppath = ui.expandpath(source)
4853 try:
4853 try:
4854 return hg.incoming(ui, repo, source, opts)
4854 return hg.incoming(ui, repo, source, opts)
4855 finally:
4855 finally:
4856 del repo._subtoppath
4856 del repo._subtoppath
4857
4857
4858
4858
4859 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4859 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4860 norepo=True)
4860 norepo=True)
4861 def init(ui, dest=".", **opts):
4861 def init(ui, dest=".", **opts):
4862 """create a new repository in the given directory
4862 """create a new repository in the given directory
4863
4863
4864 Initialize a new repository in the given directory. If the given
4864 Initialize a new repository in the given directory. If the given
4865 directory does not exist, it will be created.
4865 directory does not exist, it will be created.
4866
4866
4867 If no directory is given, the current directory is used.
4867 If no directory is given, the current directory is used.
4868
4868
4869 It is possible to specify an ``ssh://`` URL as the destination.
4869 It is possible to specify an ``ssh://`` URL as the destination.
4870 See :hg:`help urls` for more information.
4870 See :hg:`help urls` for more information.
4871
4871
4872 Returns 0 on success.
4872 Returns 0 on success.
4873 """
4873 """
4874 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4874 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4875
4875
4876 @command('locate',
4876 @command('locate',
4877 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4877 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4878 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4878 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4879 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4879 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4880 ] + walkopts,
4880 ] + walkopts,
4881 _('[OPTION]... [PATTERN]...'))
4881 _('[OPTION]... [PATTERN]...'))
4882 def locate(ui, repo, *pats, **opts):
4882 def locate(ui, repo, *pats, **opts):
4883 """locate files matching specific patterns (DEPRECATED)
4883 """locate files matching specific patterns (DEPRECATED)
4884
4884
4885 Print files under Mercurial control in the working directory whose
4885 Print files under Mercurial control in the working directory whose
4886 names match the given patterns.
4886 names match the given patterns.
4887
4887
4888 By default, this command searches all directories in the working
4888 By default, this command searches all directories in the working
4889 directory. To search just the current directory and its
4889 directory. To search just the current directory and its
4890 subdirectories, use "--include .".
4890 subdirectories, use "--include .".
4891
4891
4892 If no patterns are given to match, this command prints the names
4892 If no patterns are given to match, this command prints the names
4893 of all files under Mercurial control in the working directory.
4893 of all files under Mercurial control in the working directory.
4894
4894
4895 If you want to feed the output of this command into the "xargs"
4895 If you want to feed the output of this command into the "xargs"
4896 command, use the -0 option to both this command and "xargs". This
4896 command, use the -0 option to both this command and "xargs". This
4897 will avoid the problem of "xargs" treating single filenames that
4897 will avoid the problem of "xargs" treating single filenames that
4898 contain whitespace as multiple filenames.
4898 contain whitespace as multiple filenames.
4899
4899
4900 See :hg:`help files` for a more versatile command.
4900 See :hg:`help files` for a more versatile command.
4901
4901
4902 Returns 0 if a match is found, 1 otherwise.
4902 Returns 0 if a match is found, 1 otherwise.
4903 """
4903 """
4904 if opts.get('print0'):
4904 if opts.get('print0'):
4905 end = '\0'
4905 end = '\0'
4906 else:
4906 else:
4907 end = '\n'
4907 end = '\n'
4908 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4908 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4909
4909
4910 ret = 1
4910 ret = 1
4911 ctx = repo[rev]
4911 ctx = repo[rev]
4912 m = scmutil.match(ctx, pats, opts, default='relglob',
4912 m = scmutil.match(ctx, pats, opts, default='relglob',
4913 badfn=lambda x, y: False)
4913 badfn=lambda x, y: False)
4914
4914
4915 for abs in ctx.matches(m):
4915 for abs in ctx.matches(m):
4916 if opts.get('fullpath'):
4916 if opts.get('fullpath'):
4917 ui.write(repo.wjoin(abs), end)
4917 ui.write(repo.wjoin(abs), end)
4918 else:
4918 else:
4919 ui.write(((pats and m.rel(abs)) or abs), end)
4919 ui.write(((pats and m.rel(abs)) or abs), end)
4920 ret = 0
4920 ret = 0
4921
4921
4922 return ret
4922 return ret
4923
4923
4924 @command('^log|history',
4924 @command('^log|history',
4925 [('f', 'follow', None,
4925 [('f', 'follow', None,
4926 _('follow changeset history, or file history across copies and renames')),
4926 _('follow changeset history, or file history across copies and renames')),
4927 ('', 'follow-first', None,
4927 ('', 'follow-first', None,
4928 _('only follow the first parent of merge changesets (DEPRECATED)')),
4928 _('only follow the first parent of merge changesets (DEPRECATED)')),
4929 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4929 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4930 ('C', 'copies', None, _('show copied files')),
4930 ('C', 'copies', None, _('show copied files')),
4931 ('k', 'keyword', [],
4931 ('k', 'keyword', [],
4932 _('do case-insensitive search for a given text'), _('TEXT')),
4932 _('do case-insensitive search for a given text'), _('TEXT')),
4933 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4933 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4934 ('', 'removed', None, _('include revisions where files were removed')),
4934 ('', 'removed', None, _('include revisions where files were removed')),
4935 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4935 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4936 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4936 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4937 ('', 'only-branch', [],
4937 ('', 'only-branch', [],
4938 _('show only changesets within the given named branch (DEPRECATED)'),
4938 _('show only changesets within the given named branch (DEPRECATED)'),
4939 _('BRANCH')),
4939 _('BRANCH')),
4940 ('b', 'branch', [],
4940 ('b', 'branch', [],
4941 _('show changesets within the given named branch'), _('BRANCH')),
4941 _('show changesets within the given named branch'), _('BRANCH')),
4942 ('P', 'prune', [],
4942 ('P', 'prune', [],
4943 _('do not display revision or any of its ancestors'), _('REV')),
4943 _('do not display revision or any of its ancestors'), _('REV')),
4944 ] + logopts + walkopts,
4944 ] + logopts + walkopts,
4945 _('[OPTION]... [FILE]'),
4945 _('[OPTION]... [FILE]'),
4946 inferrepo=True)
4946 inferrepo=True)
4947 def log(ui, repo, *pats, **opts):
4947 def log(ui, repo, *pats, **opts):
4948 """show revision history of entire repository or files
4948 """show revision history of entire repository or files
4949
4949
4950 Print the revision history of the specified files or the entire
4950 Print the revision history of the specified files or the entire
4951 project.
4951 project.
4952
4952
4953 If no revision range is specified, the default is ``tip:0`` unless
4953 If no revision range is specified, the default is ``tip:0`` unless
4954 --follow is set, in which case the working directory parent is
4954 --follow is set, in which case the working directory parent is
4955 used as the starting revision.
4955 used as the starting revision.
4956
4956
4957 File history is shown without following rename or copy history of
4957 File history is shown without following rename or copy history of
4958 files. Use -f/--follow with a filename to follow history across
4958 files. Use -f/--follow with a filename to follow history across
4959 renames and copies. --follow without a filename will only show
4959 renames and copies. --follow without a filename will only show
4960 ancestors or descendants of the starting revision.
4960 ancestors or descendants of the starting revision.
4961
4961
4962 By default this command prints revision number and changeset id,
4962 By default this command prints revision number and changeset id,
4963 tags, non-trivial parents, user, date and time, and a summary for
4963 tags, non-trivial parents, user, date and time, and a summary for
4964 each commit. When the -v/--verbose switch is used, the list of
4964 each commit. When the -v/--verbose switch is used, the list of
4965 changed files and full commit message are shown.
4965 changed files and full commit message are shown.
4966
4966
4967 With --graph the revisions are shown as an ASCII art DAG with the most
4967 With --graph the revisions are shown as an ASCII art DAG with the most
4968 recent changeset at the top.
4968 recent changeset at the top.
4969 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4969 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4970 and '+' represents a fork where the changeset from the lines below is a
4970 and '+' represents a fork where the changeset from the lines below is a
4971 parent of the 'o' merge on the same line.
4971 parent of the 'o' merge on the same line.
4972
4972
4973 .. note::
4973 .. note::
4974
4974
4975 :hg:`log --patch` may generate unexpected diff output for merge
4975 :hg:`log --patch` may generate unexpected diff output for merge
4976 changesets, as it will only compare the merge changeset against
4976 changesets, as it will only compare the merge changeset against
4977 its first parent. Also, only files different from BOTH parents
4977 its first parent. Also, only files different from BOTH parents
4978 will appear in files:.
4978 will appear in files:.
4979
4979
4980 .. note::
4980 .. note::
4981
4981
4982 For performance reasons, :hg:`log FILE` may omit duplicate changes
4982 For performance reasons, :hg:`log FILE` may omit duplicate changes
4983 made on branches and will not show removals or mode changes. To
4983 made on branches and will not show removals or mode changes. To
4984 see all such changes, use the --removed switch.
4984 see all such changes, use the --removed switch.
4985
4985
4986 .. container:: verbose
4986 .. container:: verbose
4987
4987
4988 Some examples:
4988 Some examples:
4989
4989
4990 - changesets with full descriptions and file lists::
4990 - changesets with full descriptions and file lists::
4991
4991
4992 hg log -v
4992 hg log -v
4993
4993
4994 - changesets ancestral to the working directory::
4994 - changesets ancestral to the working directory::
4995
4995
4996 hg log -f
4996 hg log -f
4997
4997
4998 - last 10 commits on the current branch::
4998 - last 10 commits on the current branch::
4999
4999
5000 hg log -l 10 -b .
5000 hg log -l 10 -b .
5001
5001
5002 - changesets showing all modifications of a file, including removals::
5002 - changesets showing all modifications of a file, including removals::
5003
5003
5004 hg log --removed file.c
5004 hg log --removed file.c
5005
5005
5006 - all changesets that touch a directory, with diffs, excluding merges::
5006 - all changesets that touch a directory, with diffs, excluding merges::
5007
5007
5008 hg log -Mp lib/
5008 hg log -Mp lib/
5009
5009
5010 - all revision numbers that match a keyword::
5010 - all revision numbers that match a keyword::
5011
5011
5012 hg log -k bug --template "{rev}\\n"
5012 hg log -k bug --template "{rev}\\n"
5013
5013
5014 - the full hash identifier of the working directory parent::
5014 - the full hash identifier of the working directory parent::
5015
5015
5016 hg log -r . --template "{node}\\n"
5016 hg log -r . --template "{node}\\n"
5017
5017
5018 - list available log templates::
5018 - list available log templates::
5019
5019
5020 hg log -T list
5020 hg log -T list
5021
5021
5022 - check if a given changeset is included in a tagged release::
5022 - check if a given changeset is included in a tagged release::
5023
5023
5024 hg log -r "a21ccf and ancestor(1.9)"
5024 hg log -r "a21ccf and ancestor(1.9)"
5025
5025
5026 - find all changesets by some user in a date range::
5026 - find all changesets by some user in a date range::
5027
5027
5028 hg log -k alice -d "may 2008 to jul 2008"
5028 hg log -k alice -d "may 2008 to jul 2008"
5029
5029
5030 - summary of all changesets after the last tag::
5030 - summary of all changesets after the last tag::
5031
5031
5032 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5032 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5033
5033
5034 See :hg:`help dates` for a list of formats valid for -d/--date.
5034 See :hg:`help dates` for a list of formats valid for -d/--date.
5035
5035
5036 See :hg:`help revisions` and :hg:`help revsets` for more about
5036 See :hg:`help revisions` and :hg:`help revsets` for more about
5037 specifying revisions.
5037 specifying and ordering revisions.
5038
5038
5039 See :hg:`help templates` for more about pre-packaged styles and
5039 See :hg:`help templates` for more about pre-packaged styles and
5040 specifying custom templates.
5040 specifying custom templates.
5041
5041
5042 Returns 0 on success.
5042 Returns 0 on success.
5043
5043
5044 """
5044 """
5045 if opts.get('follow') and opts.get('rev'):
5045 if opts.get('follow') and opts.get('rev'):
5046 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5046 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5047 del opts['follow']
5047 del opts['follow']
5048
5048
5049 if opts.get('graph'):
5049 if opts.get('graph'):
5050 return cmdutil.graphlog(ui, repo, *pats, **opts)
5050 return cmdutil.graphlog(ui, repo, *pats, **opts)
5051
5051
5052 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5052 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5053 limit = cmdutil.loglimit(opts)
5053 limit = cmdutil.loglimit(opts)
5054 count = 0
5054 count = 0
5055
5055
5056 getrenamed = None
5056 getrenamed = None
5057 if opts.get('copies'):
5057 if opts.get('copies'):
5058 endrev = None
5058 endrev = None
5059 if opts.get('rev'):
5059 if opts.get('rev'):
5060 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5060 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5061 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5061 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5062
5062
5063 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5063 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5064 for rev in revs:
5064 for rev in revs:
5065 if count == limit:
5065 if count == limit:
5066 break
5066 break
5067 ctx = repo[rev]
5067 ctx = repo[rev]
5068 copies = None
5068 copies = None
5069 if getrenamed is not None and rev:
5069 if getrenamed is not None and rev:
5070 copies = []
5070 copies = []
5071 for fn in ctx.files():
5071 for fn in ctx.files():
5072 rename = getrenamed(fn, rev)
5072 rename = getrenamed(fn, rev)
5073 if rename:
5073 if rename:
5074 copies.append((fn, rename[0]))
5074 copies.append((fn, rename[0]))
5075 if filematcher:
5075 if filematcher:
5076 revmatchfn = filematcher(ctx.rev())
5076 revmatchfn = filematcher(ctx.rev())
5077 else:
5077 else:
5078 revmatchfn = None
5078 revmatchfn = None
5079 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5079 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5080 if displayer.flush(ctx):
5080 if displayer.flush(ctx):
5081 count += 1
5081 count += 1
5082
5082
5083 displayer.close()
5083 displayer.close()
5084
5084
5085 @command('manifest',
5085 @command('manifest',
5086 [('r', 'rev', '', _('revision to display'), _('REV')),
5086 [('r', 'rev', '', _('revision to display'), _('REV')),
5087 ('', 'all', False, _("list files from all revisions"))]
5087 ('', 'all', False, _("list files from all revisions"))]
5088 + formatteropts,
5088 + formatteropts,
5089 _('[-r REV]'))
5089 _('[-r REV]'))
5090 def manifest(ui, repo, node=None, rev=None, **opts):
5090 def manifest(ui, repo, node=None, rev=None, **opts):
5091 """output the current or given revision of the project manifest
5091 """output the current or given revision of the project manifest
5092
5092
5093 Print a list of version controlled files for the given revision.
5093 Print a list of version controlled files for the given revision.
5094 If no revision is given, the first parent of the working directory
5094 If no revision is given, the first parent of the working directory
5095 is used, or the null revision if no revision is checked out.
5095 is used, or the null revision if no revision is checked out.
5096
5096
5097 With -v, print file permissions, symlink and executable bits.
5097 With -v, print file permissions, symlink and executable bits.
5098 With --debug, print file revision hashes.
5098 With --debug, print file revision hashes.
5099
5099
5100 If option --all is specified, the list of all files from all revisions
5100 If option --all is specified, the list of all files from all revisions
5101 is printed. This includes deleted and renamed files.
5101 is printed. This includes deleted and renamed files.
5102
5102
5103 Returns 0 on success.
5103 Returns 0 on success.
5104 """
5104 """
5105
5105
5106 fm = ui.formatter('manifest', opts)
5106 fm = ui.formatter('manifest', opts)
5107
5107
5108 if opts.get('all'):
5108 if opts.get('all'):
5109 if rev or node:
5109 if rev or node:
5110 raise error.Abort(_("can't specify a revision with --all"))
5110 raise error.Abort(_("can't specify a revision with --all"))
5111
5111
5112 res = []
5112 res = []
5113 prefix = "data/"
5113 prefix = "data/"
5114 suffix = ".i"
5114 suffix = ".i"
5115 plen = len(prefix)
5115 plen = len(prefix)
5116 slen = len(suffix)
5116 slen = len(suffix)
5117 lock = repo.lock()
5117 lock = repo.lock()
5118 try:
5118 try:
5119 for fn, b, size in repo.store.datafiles():
5119 for fn, b, size in repo.store.datafiles():
5120 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5120 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5121 res.append(fn[plen:-slen])
5121 res.append(fn[plen:-slen])
5122 finally:
5122 finally:
5123 lock.release()
5123 lock.release()
5124 for f in res:
5124 for f in res:
5125 fm.startitem()
5125 fm.startitem()
5126 fm.write("path", '%s\n', f)
5126 fm.write("path", '%s\n', f)
5127 fm.end()
5127 fm.end()
5128 return
5128 return
5129
5129
5130 if rev and node:
5130 if rev and node:
5131 raise error.Abort(_("please specify just one revision"))
5131 raise error.Abort(_("please specify just one revision"))
5132
5132
5133 if not node:
5133 if not node:
5134 node = rev
5134 node = rev
5135
5135
5136 char = {'l': '@', 'x': '*', '': ''}
5136 char = {'l': '@', 'x': '*', '': ''}
5137 mode = {'l': '644', 'x': '755', '': '644'}
5137 mode = {'l': '644', 'x': '755', '': '644'}
5138 ctx = scmutil.revsingle(repo, node)
5138 ctx = scmutil.revsingle(repo, node)
5139 mf = ctx.manifest()
5139 mf = ctx.manifest()
5140 for f in ctx:
5140 for f in ctx:
5141 fm.startitem()
5141 fm.startitem()
5142 fl = ctx[f].flags()
5142 fl = ctx[f].flags()
5143 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5143 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5144 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5144 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5145 fm.write('path', '%s\n', f)
5145 fm.write('path', '%s\n', f)
5146 fm.end()
5146 fm.end()
5147
5147
5148 @command('^merge',
5148 @command('^merge',
5149 [('f', 'force', None,
5149 [('f', 'force', None,
5150 _('force a merge including outstanding changes (DEPRECATED)')),
5150 _('force a merge including outstanding changes (DEPRECATED)')),
5151 ('r', 'rev', '', _('revision to merge'), _('REV')),
5151 ('r', 'rev', '', _('revision to merge'), _('REV')),
5152 ('P', 'preview', None,
5152 ('P', 'preview', None,
5153 _('review revisions to merge (no merge is performed)'))
5153 _('review revisions to merge (no merge is performed)'))
5154 ] + mergetoolopts,
5154 ] + mergetoolopts,
5155 _('[-P] [-f] [[-r] REV]'))
5155 _('[-P] [-f] [[-r] REV]'))
5156 def merge(ui, repo, node=None, **opts):
5156 def merge(ui, repo, node=None, **opts):
5157 """merge another revision into working directory
5157 """merge another revision into working directory
5158
5158
5159 The current working directory is updated with all changes made in
5159 The current working directory is updated with all changes made in
5160 the requested revision since the last common predecessor revision.
5160 the requested revision since the last common predecessor revision.
5161
5161
5162 Files that changed between either parent are marked as changed for
5162 Files that changed between either parent are marked as changed for
5163 the next commit and a commit must be performed before any further
5163 the next commit and a commit must be performed before any further
5164 updates to the repository are allowed. The next commit will have
5164 updates to the repository are allowed. The next commit will have
5165 two parents.
5165 two parents.
5166
5166
5167 ``--tool`` can be used to specify the merge tool used for file
5167 ``--tool`` can be used to specify the merge tool used for file
5168 merges. It overrides the HGMERGE environment variable and your
5168 merges. It overrides the HGMERGE environment variable and your
5169 configuration files. See :hg:`help merge-tools` for options.
5169 configuration files. See :hg:`help merge-tools` for options.
5170
5170
5171 If no revision is specified, the working directory's parent is a
5171 If no revision is specified, the working directory's parent is a
5172 head revision, and the current branch contains exactly one other
5172 head revision, and the current branch contains exactly one other
5173 head, the other head is merged with by default. Otherwise, an
5173 head, the other head is merged with by default. Otherwise, an
5174 explicit revision with which to merge with must be provided.
5174 explicit revision with which to merge with must be provided.
5175
5175
5176 See :hg:`help resolve` for information on handling file conflicts.
5176 See :hg:`help resolve` for information on handling file conflicts.
5177
5177
5178 To undo an uncommitted merge, use :hg:`update --clean .` which
5178 To undo an uncommitted merge, use :hg:`update --clean .` which
5179 will check out a clean copy of the original merge parent, losing
5179 will check out a clean copy of the original merge parent, losing
5180 all changes.
5180 all changes.
5181
5181
5182 Returns 0 on success, 1 if there are unresolved files.
5182 Returns 0 on success, 1 if there are unresolved files.
5183 """
5183 """
5184
5184
5185 if opts.get('rev') and node:
5185 if opts.get('rev') and node:
5186 raise error.Abort(_("please specify just one revision"))
5186 raise error.Abort(_("please specify just one revision"))
5187 if not node:
5187 if not node:
5188 node = opts.get('rev')
5188 node = opts.get('rev')
5189
5189
5190 if node:
5190 if node:
5191 node = scmutil.revsingle(repo, node).node()
5191 node = scmutil.revsingle(repo, node).node()
5192
5192
5193 if not node:
5193 if not node:
5194 node = repo[destutil.destmerge(repo)].node()
5194 node = repo[destutil.destmerge(repo)].node()
5195
5195
5196 if opts.get('preview'):
5196 if opts.get('preview'):
5197 # find nodes that are ancestors of p2 but not of p1
5197 # find nodes that are ancestors of p2 but not of p1
5198 p1 = repo.lookup('.')
5198 p1 = repo.lookup('.')
5199 p2 = repo.lookup(node)
5199 p2 = repo.lookup(node)
5200 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5200 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5201
5201
5202 displayer = cmdutil.show_changeset(ui, repo, opts)
5202 displayer = cmdutil.show_changeset(ui, repo, opts)
5203 for node in nodes:
5203 for node in nodes:
5204 displayer.show(repo[node])
5204 displayer.show(repo[node])
5205 displayer.close()
5205 displayer.close()
5206 return 0
5206 return 0
5207
5207
5208 try:
5208 try:
5209 # ui.forcemerge is an internal variable, do not document
5209 # ui.forcemerge is an internal variable, do not document
5210 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5210 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5211 return hg.merge(repo, node, force=opts.get('force'))
5211 return hg.merge(repo, node, force=opts.get('force'))
5212 finally:
5212 finally:
5213 ui.setconfig('ui', 'forcemerge', '', 'merge')
5213 ui.setconfig('ui', 'forcemerge', '', 'merge')
5214
5214
5215 @command('outgoing|out',
5215 @command('outgoing|out',
5216 [('f', 'force', None, _('run even when the destination is unrelated')),
5216 [('f', 'force', None, _('run even when the destination is unrelated')),
5217 ('r', 'rev', [],
5217 ('r', 'rev', [],
5218 _('a changeset intended to be included in the destination'), _('REV')),
5218 _('a changeset intended to be included in the destination'), _('REV')),
5219 ('n', 'newest-first', None, _('show newest record first')),
5219 ('n', 'newest-first', None, _('show newest record first')),
5220 ('B', 'bookmarks', False, _('compare bookmarks')),
5220 ('B', 'bookmarks', False, _('compare bookmarks')),
5221 ('b', 'branch', [], _('a specific branch you would like to push'),
5221 ('b', 'branch', [], _('a specific branch you would like to push'),
5222 _('BRANCH')),
5222 _('BRANCH')),
5223 ] + logopts + remoteopts + subrepoopts,
5223 ] + logopts + remoteopts + subrepoopts,
5224 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5224 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5225 def outgoing(ui, repo, dest=None, **opts):
5225 def outgoing(ui, repo, dest=None, **opts):
5226 """show changesets not found in the destination
5226 """show changesets not found in the destination
5227
5227
5228 Show changesets not found in the specified destination repository
5228 Show changesets not found in the specified destination repository
5229 or the default push location. These are the changesets that would
5229 or the default push location. These are the changesets that would
5230 be pushed if a push was requested.
5230 be pushed if a push was requested.
5231
5231
5232 See pull for details of valid destination formats.
5232 See pull for details of valid destination formats.
5233
5233
5234 .. container:: verbose
5234 .. container:: verbose
5235
5235
5236 With -B/--bookmarks, the result of bookmark comparison between
5236 With -B/--bookmarks, the result of bookmark comparison between
5237 local and remote repositories is displayed. With -v/--verbose,
5237 local and remote repositories is displayed. With -v/--verbose,
5238 status is also displayed for each bookmark like below::
5238 status is also displayed for each bookmark like below::
5239
5239
5240 BM1 01234567890a added
5240 BM1 01234567890a added
5241 BM2 deleted
5241 BM2 deleted
5242 BM3 234567890abc advanced
5242 BM3 234567890abc advanced
5243 BM4 34567890abcd diverged
5243 BM4 34567890abcd diverged
5244 BM5 4567890abcde changed
5244 BM5 4567890abcde changed
5245
5245
5246 The action taken when pushing depends on the
5246 The action taken when pushing depends on the
5247 status of each bookmark:
5247 status of each bookmark:
5248
5248
5249 :``added``: push with ``-B`` will create it
5249 :``added``: push with ``-B`` will create it
5250 :``deleted``: push with ``-B`` will delete it
5250 :``deleted``: push with ``-B`` will delete it
5251 :``advanced``: push will update it
5251 :``advanced``: push will update it
5252 :``diverged``: push with ``-B`` will update it
5252 :``diverged``: push with ``-B`` will update it
5253 :``changed``: push with ``-B`` will update it
5253 :``changed``: push with ``-B`` will update it
5254
5254
5255 From the point of view of pushing behavior, bookmarks
5255 From the point of view of pushing behavior, bookmarks
5256 existing only in the remote repository are treated as
5256 existing only in the remote repository are treated as
5257 ``deleted``, even if it is in fact added remotely.
5257 ``deleted``, even if it is in fact added remotely.
5258
5258
5259 Returns 0 if there are outgoing changes, 1 otherwise.
5259 Returns 0 if there are outgoing changes, 1 otherwise.
5260 """
5260 """
5261 if opts.get('graph'):
5261 if opts.get('graph'):
5262 cmdutil.checkunsupportedgraphflags([], opts)
5262 cmdutil.checkunsupportedgraphflags([], opts)
5263 o, other = hg._outgoing(ui, repo, dest, opts)
5263 o, other = hg._outgoing(ui, repo, dest, opts)
5264 if not o:
5264 if not o:
5265 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5265 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5266 return
5266 return
5267
5267
5268 revdag = cmdutil.graphrevs(repo, o, opts)
5268 revdag = cmdutil.graphrevs(repo, o, opts)
5269 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5269 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5270 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5270 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5271 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5271 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5272 return 0
5272 return 0
5273
5273
5274 if opts.get('bookmarks'):
5274 if opts.get('bookmarks'):
5275 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5275 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5276 dest, branches = hg.parseurl(dest, opts.get('branch'))
5276 dest, branches = hg.parseurl(dest, opts.get('branch'))
5277 other = hg.peer(repo, opts, dest)
5277 other = hg.peer(repo, opts, dest)
5278 if 'bookmarks' not in other.listkeys('namespaces'):
5278 if 'bookmarks' not in other.listkeys('namespaces'):
5279 ui.warn(_("remote doesn't support bookmarks\n"))
5279 ui.warn(_("remote doesn't support bookmarks\n"))
5280 return 0
5280 return 0
5281 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5281 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5282 return bookmarks.outgoing(ui, repo, other)
5282 return bookmarks.outgoing(ui, repo, other)
5283
5283
5284 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5284 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5285 try:
5285 try:
5286 return hg.outgoing(ui, repo, dest, opts)
5286 return hg.outgoing(ui, repo, dest, opts)
5287 finally:
5287 finally:
5288 del repo._subtoppath
5288 del repo._subtoppath
5289
5289
5290 @command('parents',
5290 @command('parents',
5291 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5291 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5292 ] + templateopts,
5292 ] + templateopts,
5293 _('[-r REV] [FILE]'),
5293 _('[-r REV] [FILE]'),
5294 inferrepo=True)
5294 inferrepo=True)
5295 def parents(ui, repo, file_=None, **opts):
5295 def parents(ui, repo, file_=None, **opts):
5296 """show the parents of the working directory or revision (DEPRECATED)
5296 """show the parents of the working directory or revision (DEPRECATED)
5297
5297
5298 Print the working directory's parent revisions. If a revision is
5298 Print the working directory's parent revisions. If a revision is
5299 given via -r/--rev, the parent of that revision will be printed.
5299 given via -r/--rev, the parent of that revision will be printed.
5300 If a file argument is given, the revision in which the file was
5300 If a file argument is given, the revision in which the file was
5301 last changed (before the working directory revision or the
5301 last changed (before the working directory revision or the
5302 argument to --rev if given) is printed.
5302 argument to --rev if given) is printed.
5303
5303
5304 This command is equivalent to::
5304 This command is equivalent to::
5305
5305
5306 hg log -r "p1()+p2()" or
5306 hg log -r "p1()+p2()" or
5307 hg log -r "p1(REV)+p2(REV)" or
5307 hg log -r "p1(REV)+p2(REV)" or
5308 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5308 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5309 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5309 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5310
5310
5311 See :hg:`summary` and :hg:`help revsets` for related information.
5311 See :hg:`summary` and :hg:`help revsets` for related information.
5312
5312
5313 Returns 0 on success.
5313 Returns 0 on success.
5314 """
5314 """
5315
5315
5316 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5316 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5317
5317
5318 if file_:
5318 if file_:
5319 m = scmutil.match(ctx, (file_,), opts)
5319 m = scmutil.match(ctx, (file_,), opts)
5320 if m.anypats() or len(m.files()) != 1:
5320 if m.anypats() or len(m.files()) != 1:
5321 raise error.Abort(_('can only specify an explicit filename'))
5321 raise error.Abort(_('can only specify an explicit filename'))
5322 file_ = m.files()[0]
5322 file_ = m.files()[0]
5323 filenodes = []
5323 filenodes = []
5324 for cp in ctx.parents():
5324 for cp in ctx.parents():
5325 if not cp:
5325 if not cp:
5326 continue
5326 continue
5327 try:
5327 try:
5328 filenodes.append(cp.filenode(file_))
5328 filenodes.append(cp.filenode(file_))
5329 except error.LookupError:
5329 except error.LookupError:
5330 pass
5330 pass
5331 if not filenodes:
5331 if not filenodes:
5332 raise error.Abort(_("'%s' not found in manifest!") % file_)
5332 raise error.Abort(_("'%s' not found in manifest!") % file_)
5333 p = []
5333 p = []
5334 for fn in filenodes:
5334 for fn in filenodes:
5335 fctx = repo.filectx(file_, fileid=fn)
5335 fctx = repo.filectx(file_, fileid=fn)
5336 p.append(fctx.node())
5336 p.append(fctx.node())
5337 else:
5337 else:
5338 p = [cp.node() for cp in ctx.parents()]
5338 p = [cp.node() for cp in ctx.parents()]
5339
5339
5340 displayer = cmdutil.show_changeset(ui, repo, opts)
5340 displayer = cmdutil.show_changeset(ui, repo, opts)
5341 for n in p:
5341 for n in p:
5342 if n != nullid:
5342 if n != nullid:
5343 displayer.show(repo[n])
5343 displayer.show(repo[n])
5344 displayer.close()
5344 displayer.close()
5345
5345
5346 @command('paths', [], _('[NAME]'), optionalrepo=True)
5346 @command('paths', [], _('[NAME]'), optionalrepo=True)
5347 def paths(ui, repo, search=None):
5347 def paths(ui, repo, search=None):
5348 """show aliases for remote repositories
5348 """show aliases for remote repositories
5349
5349
5350 Show definition of symbolic path name NAME. If no name is given,
5350 Show definition of symbolic path name NAME. If no name is given,
5351 show definition of all available names.
5351 show definition of all available names.
5352
5352
5353 Option -q/--quiet suppresses all output when searching for NAME
5353 Option -q/--quiet suppresses all output when searching for NAME
5354 and shows only the path names when listing all definitions.
5354 and shows only the path names when listing all definitions.
5355
5355
5356 Path names are defined in the [paths] section of your
5356 Path names are defined in the [paths] section of your
5357 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5357 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5358 repository, ``.hg/hgrc`` is used, too.
5358 repository, ``.hg/hgrc`` is used, too.
5359
5359
5360 The path names ``default`` and ``default-push`` have a special
5360 The path names ``default`` and ``default-push`` have a special
5361 meaning. When performing a push or pull operation, they are used
5361 meaning. When performing a push or pull operation, they are used
5362 as fallbacks if no location is specified on the command-line.
5362 as fallbacks if no location is specified on the command-line.
5363 When ``default-push`` is set, it will be used for push and
5363 When ``default-push`` is set, it will be used for push and
5364 ``default`` will be used for pull; otherwise ``default`` is used
5364 ``default`` will be used for pull; otherwise ``default`` is used
5365 as the fallback for both. When cloning a repository, the clone
5365 as the fallback for both. When cloning a repository, the clone
5366 source is written as ``default`` in ``.hg/hgrc``.
5366 source is written as ``default`` in ``.hg/hgrc``.
5367
5367
5368 .. note::
5368 .. note::
5369
5369
5370 ``default`` and ``default-push`` apply to all inbound (e.g.
5370 ``default`` and ``default-push`` apply to all inbound (e.g.
5371 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5371 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5372 and :hg:`bundle`) operations.
5372 and :hg:`bundle`) operations.
5373
5373
5374 See :hg:`help urls` for more information.
5374 See :hg:`help urls` for more information.
5375
5375
5376 Returns 0 on success.
5376 Returns 0 on success.
5377 """
5377 """
5378 if search:
5378 if search:
5379 for name, path in sorted(ui.paths.iteritems()):
5379 for name, path in sorted(ui.paths.iteritems()):
5380 if name == search:
5380 if name == search:
5381 ui.status("%s\n" % util.hidepassword(path.rawloc))
5381 ui.status("%s\n" % util.hidepassword(path.rawloc))
5382 return
5382 return
5383 if not ui.quiet:
5383 if not ui.quiet:
5384 ui.warn(_("not found!\n"))
5384 ui.warn(_("not found!\n"))
5385 return 1
5385 return 1
5386 else:
5386 else:
5387 for name, path in sorted(ui.paths.iteritems()):
5387 for name, path in sorted(ui.paths.iteritems()):
5388 if ui.quiet:
5388 if ui.quiet:
5389 ui.write("%s\n" % name)
5389 ui.write("%s\n" % name)
5390 else:
5390 else:
5391 ui.write("%s = %s\n" % (name,
5391 ui.write("%s = %s\n" % (name,
5392 util.hidepassword(path.rawloc)))
5392 util.hidepassword(path.rawloc)))
5393 for subopt, value in sorted(path.suboptions.items()):
5393 for subopt, value in sorted(path.suboptions.items()):
5394 ui.write('%s:%s = %s\n' % (name, subopt, value))
5394 ui.write('%s:%s = %s\n' % (name, subopt, value))
5395
5395
5396 @command('phase',
5396 @command('phase',
5397 [('p', 'public', False, _('set changeset phase to public')),
5397 [('p', 'public', False, _('set changeset phase to public')),
5398 ('d', 'draft', False, _('set changeset phase to draft')),
5398 ('d', 'draft', False, _('set changeset phase to draft')),
5399 ('s', 'secret', False, _('set changeset phase to secret')),
5399 ('s', 'secret', False, _('set changeset phase to secret')),
5400 ('f', 'force', False, _('allow to move boundary backward')),
5400 ('f', 'force', False, _('allow to move boundary backward')),
5401 ('r', 'rev', [], _('target revision'), _('REV')),
5401 ('r', 'rev', [], _('target revision'), _('REV')),
5402 ],
5402 ],
5403 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5403 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5404 def phase(ui, repo, *revs, **opts):
5404 def phase(ui, repo, *revs, **opts):
5405 """set or show the current phase name
5405 """set or show the current phase name
5406
5406
5407 With no argument, show the phase name of the current revision(s).
5407 With no argument, show the phase name of the current revision(s).
5408
5408
5409 With one of -p/--public, -d/--draft or -s/--secret, change the
5409 With one of -p/--public, -d/--draft or -s/--secret, change the
5410 phase value of the specified revisions.
5410 phase value of the specified revisions.
5411
5411
5412 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5412 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5413 lower phase to an higher phase. Phases are ordered as follows::
5413 lower phase to an higher phase. Phases are ordered as follows::
5414
5414
5415 public < draft < secret
5415 public < draft < secret
5416
5416
5417 Returns 0 on success, 1 if some phases could not be changed.
5417 Returns 0 on success, 1 if some phases could not be changed.
5418
5418
5419 (For more information about the phases concept, see :hg:`help phases`.)
5419 (For more information about the phases concept, see :hg:`help phases`.)
5420 """
5420 """
5421 # search for a unique phase argument
5421 # search for a unique phase argument
5422 targetphase = None
5422 targetphase = None
5423 for idx, name in enumerate(phases.phasenames):
5423 for idx, name in enumerate(phases.phasenames):
5424 if opts[name]:
5424 if opts[name]:
5425 if targetphase is not None:
5425 if targetphase is not None:
5426 raise error.Abort(_('only one phase can be specified'))
5426 raise error.Abort(_('only one phase can be specified'))
5427 targetphase = idx
5427 targetphase = idx
5428
5428
5429 # look for specified revision
5429 # look for specified revision
5430 revs = list(revs)
5430 revs = list(revs)
5431 revs.extend(opts['rev'])
5431 revs.extend(opts['rev'])
5432 if not revs:
5432 if not revs:
5433 # display both parents as the second parent phase can influence
5433 # display both parents as the second parent phase can influence
5434 # the phase of a merge commit
5434 # the phase of a merge commit
5435 revs = [c.rev() for c in repo[None].parents()]
5435 revs = [c.rev() for c in repo[None].parents()]
5436
5436
5437 revs = scmutil.revrange(repo, revs)
5437 revs = scmutil.revrange(repo, revs)
5438
5438
5439 lock = None
5439 lock = None
5440 ret = 0
5440 ret = 0
5441 if targetphase is None:
5441 if targetphase is None:
5442 # display
5442 # display
5443 for r in revs:
5443 for r in revs:
5444 ctx = repo[r]
5444 ctx = repo[r]
5445 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5445 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5446 else:
5446 else:
5447 tr = None
5447 tr = None
5448 lock = repo.lock()
5448 lock = repo.lock()
5449 try:
5449 try:
5450 tr = repo.transaction("phase")
5450 tr = repo.transaction("phase")
5451 # set phase
5451 # set phase
5452 if not revs:
5452 if not revs:
5453 raise error.Abort(_('empty revision set'))
5453 raise error.Abort(_('empty revision set'))
5454 nodes = [repo[r].node() for r in revs]
5454 nodes = [repo[r].node() for r in revs]
5455 # moving revision from public to draft may hide them
5455 # moving revision from public to draft may hide them
5456 # We have to check result on an unfiltered repository
5456 # We have to check result on an unfiltered repository
5457 unfi = repo.unfiltered()
5457 unfi = repo.unfiltered()
5458 getphase = unfi._phasecache.phase
5458 getphase = unfi._phasecache.phase
5459 olddata = [getphase(unfi, r) for r in unfi]
5459 olddata = [getphase(unfi, r) for r in unfi]
5460 phases.advanceboundary(repo, tr, targetphase, nodes)
5460 phases.advanceboundary(repo, tr, targetphase, nodes)
5461 if opts['force']:
5461 if opts['force']:
5462 phases.retractboundary(repo, tr, targetphase, nodes)
5462 phases.retractboundary(repo, tr, targetphase, nodes)
5463 tr.close()
5463 tr.close()
5464 finally:
5464 finally:
5465 if tr is not None:
5465 if tr is not None:
5466 tr.release()
5466 tr.release()
5467 lock.release()
5467 lock.release()
5468 getphase = unfi._phasecache.phase
5468 getphase = unfi._phasecache.phase
5469 newdata = [getphase(unfi, r) for r in unfi]
5469 newdata = [getphase(unfi, r) for r in unfi]
5470 changes = sum(newdata[r] != olddata[r] for r in unfi)
5470 changes = sum(newdata[r] != olddata[r] for r in unfi)
5471 cl = unfi.changelog
5471 cl = unfi.changelog
5472 rejected = [n for n in nodes
5472 rejected = [n for n in nodes
5473 if newdata[cl.rev(n)] < targetphase]
5473 if newdata[cl.rev(n)] < targetphase]
5474 if rejected:
5474 if rejected:
5475 ui.warn(_('cannot move %i changesets to a higher '
5475 ui.warn(_('cannot move %i changesets to a higher '
5476 'phase, use --force\n') % len(rejected))
5476 'phase, use --force\n') % len(rejected))
5477 ret = 1
5477 ret = 1
5478 if changes:
5478 if changes:
5479 msg = _('phase changed for %i changesets\n') % changes
5479 msg = _('phase changed for %i changesets\n') % changes
5480 if ret:
5480 if ret:
5481 ui.status(msg)
5481 ui.status(msg)
5482 else:
5482 else:
5483 ui.note(msg)
5483 ui.note(msg)
5484 else:
5484 else:
5485 ui.warn(_('no phases changed\n'))
5485 ui.warn(_('no phases changed\n'))
5486 return ret
5486 return ret
5487
5487
5488 def postincoming(ui, repo, modheads, optupdate, checkout):
5488 def postincoming(ui, repo, modheads, optupdate, checkout):
5489 if modheads == 0:
5489 if modheads == 0:
5490 return
5490 return
5491 if optupdate:
5491 if optupdate:
5492 try:
5492 try:
5493 brev = checkout
5493 brev = checkout
5494 movemarkfrom = None
5494 movemarkfrom = None
5495 if not checkout:
5495 if not checkout:
5496 updata = destutil.destupdate(repo)
5496 updata = destutil.destupdate(repo)
5497 checkout, movemarkfrom, brev = updata
5497 checkout, movemarkfrom, brev = updata
5498 ret = hg.update(repo, checkout)
5498 ret = hg.update(repo, checkout)
5499 except error.UpdateAbort as inst:
5499 except error.UpdateAbort as inst:
5500 msg = _("not updating: %s") % str(inst)
5500 msg = _("not updating: %s") % str(inst)
5501 hint = inst.hint
5501 hint = inst.hint
5502 raise error.UpdateAbort(msg, hint=hint)
5502 raise error.UpdateAbort(msg, hint=hint)
5503 if not ret and not checkout:
5503 if not ret and not checkout:
5504 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5504 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5505 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5505 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5506 return ret
5506 return ret
5507 if modheads > 1:
5507 if modheads > 1:
5508 currentbranchheads = len(repo.branchheads())
5508 currentbranchheads = len(repo.branchheads())
5509 if currentbranchheads == modheads:
5509 if currentbranchheads == modheads:
5510 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5510 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5511 elif currentbranchheads > 1:
5511 elif currentbranchheads > 1:
5512 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5512 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5513 "merge)\n"))
5513 "merge)\n"))
5514 else:
5514 else:
5515 ui.status(_("(run 'hg heads' to see heads)\n"))
5515 ui.status(_("(run 'hg heads' to see heads)\n"))
5516 else:
5516 else:
5517 ui.status(_("(run 'hg update' to get a working copy)\n"))
5517 ui.status(_("(run 'hg update' to get a working copy)\n"))
5518
5518
5519 @command('^pull',
5519 @command('^pull',
5520 [('u', 'update', None,
5520 [('u', 'update', None,
5521 _('update to new branch head if changesets were pulled')),
5521 _('update to new branch head if changesets were pulled')),
5522 ('f', 'force', None, _('run even when remote repository is unrelated')),
5522 ('f', 'force', None, _('run even when remote repository is unrelated')),
5523 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5523 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5524 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5524 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5525 ('b', 'branch', [], _('a specific branch you would like to pull'),
5525 ('b', 'branch', [], _('a specific branch you would like to pull'),
5526 _('BRANCH')),
5526 _('BRANCH')),
5527 ] + remoteopts,
5527 ] + remoteopts,
5528 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5528 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5529 def pull(ui, repo, source="default", **opts):
5529 def pull(ui, repo, source="default", **opts):
5530 """pull changes from the specified source
5530 """pull changes from the specified source
5531
5531
5532 Pull changes from a remote repository to a local one.
5532 Pull changes from a remote repository to a local one.
5533
5533
5534 This finds all changes from the repository at the specified path
5534 This finds all changes from the repository at the specified path
5535 or URL and adds them to a local repository (the current one unless
5535 or URL and adds them to a local repository (the current one unless
5536 -R is specified). By default, this does not update the copy of the
5536 -R is specified). By default, this does not update the copy of the
5537 project in the working directory.
5537 project in the working directory.
5538
5538
5539 Use :hg:`incoming` if you want to see what would have been added
5539 Use :hg:`incoming` if you want to see what would have been added
5540 by a pull at the time you issued this command. If you then decide
5540 by a pull at the time you issued this command. If you then decide
5541 to add those changes to the repository, you should use :hg:`pull
5541 to add those changes to the repository, you should use :hg:`pull
5542 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5542 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5543
5543
5544 If SOURCE is omitted, the 'default' path will be used.
5544 If SOURCE is omitted, the 'default' path will be used.
5545 See :hg:`help urls` for more information.
5545 See :hg:`help urls` for more information.
5546
5546
5547 Returns 0 on success, 1 if an update had unresolved files.
5547 Returns 0 on success, 1 if an update had unresolved files.
5548 """
5548 """
5549 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5549 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5550 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5550 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5551 other = hg.peer(repo, opts, source)
5551 other = hg.peer(repo, opts, source)
5552 try:
5552 try:
5553 revs, checkout = hg.addbranchrevs(repo, other, branches,
5553 revs, checkout = hg.addbranchrevs(repo, other, branches,
5554 opts.get('rev'))
5554 opts.get('rev'))
5555
5555
5556
5556
5557 pullopargs = {}
5557 pullopargs = {}
5558 if opts.get('bookmark'):
5558 if opts.get('bookmark'):
5559 if not revs:
5559 if not revs:
5560 revs = []
5560 revs = []
5561 # The list of bookmark used here is not the one used to actually
5561 # The list of bookmark used here is not the one used to actually
5562 # update the bookmark name. This can result in the revision pulled
5562 # update the bookmark name. This can result in the revision pulled
5563 # not ending up with the name of the bookmark because of a race
5563 # not ending up with the name of the bookmark because of a race
5564 # condition on the server. (See issue 4689 for details)
5564 # condition on the server. (See issue 4689 for details)
5565 remotebookmarks = other.listkeys('bookmarks')
5565 remotebookmarks = other.listkeys('bookmarks')
5566 pullopargs['remotebookmarks'] = remotebookmarks
5566 pullopargs['remotebookmarks'] = remotebookmarks
5567 for b in opts['bookmark']:
5567 for b in opts['bookmark']:
5568 if b not in remotebookmarks:
5568 if b not in remotebookmarks:
5569 raise error.Abort(_('remote bookmark %s not found!') % b)
5569 raise error.Abort(_('remote bookmark %s not found!') % b)
5570 revs.append(remotebookmarks[b])
5570 revs.append(remotebookmarks[b])
5571
5571
5572 if revs:
5572 if revs:
5573 try:
5573 try:
5574 # When 'rev' is a bookmark name, we cannot guarantee that it
5574 # When 'rev' is a bookmark name, we cannot guarantee that it
5575 # will be updated with that name because of a race condition
5575 # will be updated with that name because of a race condition
5576 # server side. (See issue 4689 for details)
5576 # server side. (See issue 4689 for details)
5577 oldrevs = revs
5577 oldrevs = revs
5578 revs = [] # actually, nodes
5578 revs = [] # actually, nodes
5579 for r in oldrevs:
5579 for r in oldrevs:
5580 node = other.lookup(r)
5580 node = other.lookup(r)
5581 revs.append(node)
5581 revs.append(node)
5582 if r == checkout:
5582 if r == checkout:
5583 checkout = node
5583 checkout = node
5584 except error.CapabilityError:
5584 except error.CapabilityError:
5585 err = _("other repository doesn't support revision lookup, "
5585 err = _("other repository doesn't support revision lookup, "
5586 "so a rev cannot be specified.")
5586 "so a rev cannot be specified.")
5587 raise error.Abort(err)
5587 raise error.Abort(err)
5588
5588
5589 pullopargs.update(opts.get('opargs', {}))
5589 pullopargs.update(opts.get('opargs', {}))
5590 modheads = exchange.pull(repo, other, heads=revs,
5590 modheads = exchange.pull(repo, other, heads=revs,
5591 force=opts.get('force'),
5591 force=opts.get('force'),
5592 bookmarks=opts.get('bookmark', ()),
5592 bookmarks=opts.get('bookmark', ()),
5593 opargs=pullopargs).cgresult
5593 opargs=pullopargs).cgresult
5594 if checkout:
5594 if checkout:
5595 checkout = str(repo.changelog.rev(checkout))
5595 checkout = str(repo.changelog.rev(checkout))
5596 repo._subtoppath = source
5596 repo._subtoppath = source
5597 try:
5597 try:
5598 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5598 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5599
5599
5600 finally:
5600 finally:
5601 del repo._subtoppath
5601 del repo._subtoppath
5602
5602
5603 finally:
5603 finally:
5604 other.close()
5604 other.close()
5605 return ret
5605 return ret
5606
5606
5607 @command('^push',
5607 @command('^push',
5608 [('f', 'force', None, _('force push')),
5608 [('f', 'force', None, _('force push')),
5609 ('r', 'rev', [],
5609 ('r', 'rev', [],
5610 _('a changeset intended to be included in the destination'),
5610 _('a changeset intended to be included in the destination'),
5611 _('REV')),
5611 _('REV')),
5612 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5612 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5613 ('b', 'branch', [],
5613 ('b', 'branch', [],
5614 _('a specific branch you would like to push'), _('BRANCH')),
5614 _('a specific branch you would like to push'), _('BRANCH')),
5615 ('', 'new-branch', False, _('allow pushing a new branch')),
5615 ('', 'new-branch', False, _('allow pushing a new branch')),
5616 ] + remoteopts,
5616 ] + remoteopts,
5617 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5617 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5618 def push(ui, repo, dest=None, **opts):
5618 def push(ui, repo, dest=None, **opts):
5619 """push changes to the specified destination
5619 """push changes to the specified destination
5620
5620
5621 Push changesets from the local repository to the specified
5621 Push changesets from the local repository to the specified
5622 destination.
5622 destination.
5623
5623
5624 This operation is symmetrical to pull: it is identical to a pull
5624 This operation is symmetrical to pull: it is identical to a pull
5625 in the destination repository from the current one.
5625 in the destination repository from the current one.
5626
5626
5627 By default, push will not allow creation of new heads at the
5627 By default, push will not allow creation of new heads at the
5628 destination, since multiple heads would make it unclear which head
5628 destination, since multiple heads would make it unclear which head
5629 to use. In this situation, it is recommended to pull and merge
5629 to use. In this situation, it is recommended to pull and merge
5630 before pushing.
5630 before pushing.
5631
5631
5632 Use --new-branch if you want to allow push to create a new named
5632 Use --new-branch if you want to allow push to create a new named
5633 branch that is not present at the destination. This allows you to
5633 branch that is not present at the destination. This allows you to
5634 only create a new branch without forcing other changes.
5634 only create a new branch without forcing other changes.
5635
5635
5636 .. note::
5636 .. note::
5637
5637
5638 Extra care should be taken with the -f/--force option,
5638 Extra care should be taken with the -f/--force option,
5639 which will push all new heads on all branches, an action which will
5639 which will push all new heads on all branches, an action which will
5640 almost always cause confusion for collaborators.
5640 almost always cause confusion for collaborators.
5641
5641
5642 If -r/--rev is used, the specified revision and all its ancestors
5642 If -r/--rev is used, the specified revision and all its ancestors
5643 will be pushed to the remote repository.
5643 will be pushed to the remote repository.
5644
5644
5645 If -B/--bookmark is used, the specified bookmarked revision, its
5645 If -B/--bookmark is used, the specified bookmarked revision, its
5646 ancestors, and the bookmark will be pushed to the remote
5646 ancestors, and the bookmark will be pushed to the remote
5647 repository.
5647 repository.
5648
5648
5649 Please see :hg:`help urls` for important details about ``ssh://``
5649 Please see :hg:`help urls` for important details about ``ssh://``
5650 URLs. If DESTINATION is omitted, a default path will be used.
5650 URLs. If DESTINATION is omitted, a default path will be used.
5651
5651
5652 Returns 0 if push was successful, 1 if nothing to push.
5652 Returns 0 if push was successful, 1 if nothing to push.
5653 """
5653 """
5654
5654
5655 if opts.get('bookmark'):
5655 if opts.get('bookmark'):
5656 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5656 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5657 for b in opts['bookmark']:
5657 for b in opts['bookmark']:
5658 # translate -B options to -r so changesets get pushed
5658 # translate -B options to -r so changesets get pushed
5659 if b in repo._bookmarks:
5659 if b in repo._bookmarks:
5660 opts.setdefault('rev', []).append(b)
5660 opts.setdefault('rev', []).append(b)
5661 else:
5661 else:
5662 # if we try to push a deleted bookmark, translate it to null
5662 # if we try to push a deleted bookmark, translate it to null
5663 # this lets simultaneous -r, -b options continue working
5663 # this lets simultaneous -r, -b options continue working
5664 opts.setdefault('rev', []).append("null")
5664 opts.setdefault('rev', []).append("null")
5665
5665
5666 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5666 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5667 if not path:
5667 if not path:
5668 raise error.Abort(_('default repository not configured!'),
5668 raise error.Abort(_('default repository not configured!'),
5669 hint=_('see the "path" section in "hg help config"'))
5669 hint=_('see the "path" section in "hg help config"'))
5670 dest = path.pushloc or path.loc
5670 dest = path.pushloc or path.loc
5671 branches = (path.branch, opts.get('branch') or [])
5671 branches = (path.branch, opts.get('branch') or [])
5672 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5672 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5673 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5673 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5674 other = hg.peer(repo, opts, dest)
5674 other = hg.peer(repo, opts, dest)
5675
5675
5676 if revs:
5676 if revs:
5677 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5677 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5678 if not revs:
5678 if not revs:
5679 raise error.Abort(_("specified revisions evaluate to an empty set"),
5679 raise error.Abort(_("specified revisions evaluate to an empty set"),
5680 hint=_("use different revision arguments"))
5680 hint=_("use different revision arguments"))
5681
5681
5682 repo._subtoppath = dest
5682 repo._subtoppath = dest
5683 try:
5683 try:
5684 # push subrepos depth-first for coherent ordering
5684 # push subrepos depth-first for coherent ordering
5685 c = repo['']
5685 c = repo['']
5686 subs = c.substate # only repos that are committed
5686 subs = c.substate # only repos that are committed
5687 for s in sorted(subs):
5687 for s in sorted(subs):
5688 result = c.sub(s).push(opts)
5688 result = c.sub(s).push(opts)
5689 if result == 0:
5689 if result == 0:
5690 return not result
5690 return not result
5691 finally:
5691 finally:
5692 del repo._subtoppath
5692 del repo._subtoppath
5693 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5693 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5694 newbranch=opts.get('new_branch'),
5694 newbranch=opts.get('new_branch'),
5695 bookmarks=opts.get('bookmark', ()),
5695 bookmarks=opts.get('bookmark', ()),
5696 opargs=opts.get('opargs'))
5696 opargs=opts.get('opargs'))
5697
5697
5698 result = not pushop.cgresult
5698 result = not pushop.cgresult
5699
5699
5700 if pushop.bkresult is not None:
5700 if pushop.bkresult is not None:
5701 if pushop.bkresult == 2:
5701 if pushop.bkresult == 2:
5702 result = 2
5702 result = 2
5703 elif not result and pushop.bkresult:
5703 elif not result and pushop.bkresult:
5704 result = 2
5704 result = 2
5705
5705
5706 return result
5706 return result
5707
5707
5708 @command('recover', [])
5708 @command('recover', [])
5709 def recover(ui, repo):
5709 def recover(ui, repo):
5710 """roll back an interrupted transaction
5710 """roll back an interrupted transaction
5711
5711
5712 Recover from an interrupted commit or pull.
5712 Recover from an interrupted commit or pull.
5713
5713
5714 This command tries to fix the repository status after an
5714 This command tries to fix the repository status after an
5715 interrupted operation. It should only be necessary when Mercurial
5715 interrupted operation. It should only be necessary when Mercurial
5716 suggests it.
5716 suggests it.
5717
5717
5718 Returns 0 if successful, 1 if nothing to recover or verify fails.
5718 Returns 0 if successful, 1 if nothing to recover or verify fails.
5719 """
5719 """
5720 if repo.recover():
5720 if repo.recover():
5721 return hg.verify(repo)
5721 return hg.verify(repo)
5722 return 1
5722 return 1
5723
5723
5724 @command('^remove|rm',
5724 @command('^remove|rm',
5725 [('A', 'after', None, _('record delete for missing files')),
5725 [('A', 'after', None, _('record delete for missing files')),
5726 ('f', 'force', None,
5726 ('f', 'force', None,
5727 _('remove (and delete) file even if added or modified')),
5727 _('remove (and delete) file even if added or modified')),
5728 ] + subrepoopts + walkopts,
5728 ] + subrepoopts + walkopts,
5729 _('[OPTION]... FILE...'),
5729 _('[OPTION]... FILE...'),
5730 inferrepo=True)
5730 inferrepo=True)
5731 def remove(ui, repo, *pats, **opts):
5731 def remove(ui, repo, *pats, **opts):
5732 """remove the specified files on the next commit
5732 """remove the specified files on the next commit
5733
5733
5734 Schedule the indicated files for removal from the current branch.
5734 Schedule the indicated files for removal from the current branch.
5735
5735
5736 This command schedules the files to be removed at the next commit.
5736 This command schedules the files to be removed at the next commit.
5737 To undo a remove before that, see :hg:`revert`. To undo added
5737 To undo a remove before that, see :hg:`revert`. To undo added
5738 files, see :hg:`forget`.
5738 files, see :hg:`forget`.
5739
5739
5740 .. container:: verbose
5740 .. container:: verbose
5741
5741
5742 -A/--after can be used to remove only files that have already
5742 -A/--after can be used to remove only files that have already
5743 been deleted, -f/--force can be used to force deletion, and -Af
5743 been deleted, -f/--force can be used to force deletion, and -Af
5744 can be used to remove files from the next revision without
5744 can be used to remove files from the next revision without
5745 deleting them from the working directory.
5745 deleting them from the working directory.
5746
5746
5747 The following table details the behavior of remove for different
5747 The following table details the behavior of remove for different
5748 file states (columns) and option combinations (rows). The file
5748 file states (columns) and option combinations (rows). The file
5749 states are Added [A], Clean [C], Modified [M] and Missing [!]
5749 states are Added [A], Clean [C], Modified [M] and Missing [!]
5750 (as reported by :hg:`status`). The actions are Warn, Remove
5750 (as reported by :hg:`status`). The actions are Warn, Remove
5751 (from branch) and Delete (from disk):
5751 (from branch) and Delete (from disk):
5752
5752
5753 ========= == == == ==
5753 ========= == == == ==
5754 opt/state A C M !
5754 opt/state A C M !
5755 ========= == == == ==
5755 ========= == == == ==
5756 none W RD W R
5756 none W RD W R
5757 -f R RD RD R
5757 -f R RD RD R
5758 -A W W W R
5758 -A W W W R
5759 -Af R R R R
5759 -Af R R R R
5760 ========= == == == ==
5760 ========= == == == ==
5761
5761
5762 .. note::
5762 .. note::
5763
5763
5764 :hg:`remove` never deletes files in Added [A] state from the
5764 :hg:`remove` never deletes files in Added [A] state from the
5765 working directory, not even if ``--force`` is specified.
5765 working directory, not even if ``--force`` is specified.
5766
5766
5767 Returns 0 on success, 1 if any warnings encountered.
5767 Returns 0 on success, 1 if any warnings encountered.
5768 """
5768 """
5769
5769
5770 after, force = opts.get('after'), opts.get('force')
5770 after, force = opts.get('after'), opts.get('force')
5771 if not pats and not after:
5771 if not pats and not after:
5772 raise error.Abort(_('no files specified'))
5772 raise error.Abort(_('no files specified'))
5773
5773
5774 m = scmutil.match(repo[None], pats, opts)
5774 m = scmutil.match(repo[None], pats, opts)
5775 subrepos = opts.get('subrepos')
5775 subrepos = opts.get('subrepos')
5776 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5776 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5777
5777
5778 @command('rename|move|mv',
5778 @command('rename|move|mv',
5779 [('A', 'after', None, _('record a rename that has already occurred')),
5779 [('A', 'after', None, _('record a rename that has already occurred')),
5780 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5780 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5781 ] + walkopts + dryrunopts,
5781 ] + walkopts + dryrunopts,
5782 _('[OPTION]... SOURCE... DEST'))
5782 _('[OPTION]... SOURCE... DEST'))
5783 def rename(ui, repo, *pats, **opts):
5783 def rename(ui, repo, *pats, **opts):
5784 """rename files; equivalent of copy + remove
5784 """rename files; equivalent of copy + remove
5785
5785
5786 Mark dest as copies of sources; mark sources for deletion. If dest
5786 Mark dest as copies of sources; mark sources for deletion. If dest
5787 is a directory, copies are put in that directory. If dest is a
5787 is a directory, copies are put in that directory. If dest is a
5788 file, there can only be one source.
5788 file, there can only be one source.
5789
5789
5790 By default, this command copies the contents of files as they
5790 By default, this command copies the contents of files as they
5791 exist in the working directory. If invoked with -A/--after, the
5791 exist in the working directory. If invoked with -A/--after, the
5792 operation is recorded, but no copying is performed.
5792 operation is recorded, but no copying is performed.
5793
5793
5794 This command takes effect at the next commit. To undo a rename
5794 This command takes effect at the next commit. To undo a rename
5795 before that, see :hg:`revert`.
5795 before that, see :hg:`revert`.
5796
5796
5797 Returns 0 on success, 1 if errors are encountered.
5797 Returns 0 on success, 1 if errors are encountered.
5798 """
5798 """
5799 wlock = repo.wlock(False)
5799 wlock = repo.wlock(False)
5800 try:
5800 try:
5801 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5801 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5802 finally:
5802 finally:
5803 wlock.release()
5803 wlock.release()
5804
5804
5805 @command('resolve',
5805 @command('resolve',
5806 [('a', 'all', None, _('select all unresolved files')),
5806 [('a', 'all', None, _('select all unresolved files')),
5807 ('l', 'list', None, _('list state of files needing merge')),
5807 ('l', 'list', None, _('list state of files needing merge')),
5808 ('m', 'mark', None, _('mark files as resolved')),
5808 ('m', 'mark', None, _('mark files as resolved')),
5809 ('u', 'unmark', None, _('mark files as unresolved')),
5809 ('u', 'unmark', None, _('mark files as unresolved')),
5810 ('n', 'no-status', None, _('hide status prefix'))]
5810 ('n', 'no-status', None, _('hide status prefix'))]
5811 + mergetoolopts + walkopts + formatteropts,
5811 + mergetoolopts + walkopts + formatteropts,
5812 _('[OPTION]... [FILE]...'),
5812 _('[OPTION]... [FILE]...'),
5813 inferrepo=True)
5813 inferrepo=True)
5814 def resolve(ui, repo, *pats, **opts):
5814 def resolve(ui, repo, *pats, **opts):
5815 """redo merges or set/view the merge status of files
5815 """redo merges or set/view the merge status of files
5816
5816
5817 Merges with unresolved conflicts are often the result of
5817 Merges with unresolved conflicts are often the result of
5818 non-interactive merging using the ``internal:merge`` configuration
5818 non-interactive merging using the ``internal:merge`` configuration
5819 setting, or a command-line merge tool like ``diff3``. The resolve
5819 setting, or a command-line merge tool like ``diff3``. The resolve
5820 command is used to manage the files involved in a merge, after
5820 command is used to manage the files involved in a merge, after
5821 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5821 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5822 working directory must have two parents). See :hg:`help
5822 working directory must have two parents). See :hg:`help
5823 merge-tools` for information on configuring merge tools.
5823 merge-tools` for information on configuring merge tools.
5824
5824
5825 The resolve command can be used in the following ways:
5825 The resolve command can be used in the following ways:
5826
5826
5827 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5827 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5828 files, discarding any previous merge attempts. Re-merging is not
5828 files, discarding any previous merge attempts. Re-merging is not
5829 performed for files already marked as resolved. Use ``--all/-a``
5829 performed for files already marked as resolved. Use ``--all/-a``
5830 to select all unresolved files. ``--tool`` can be used to specify
5830 to select all unresolved files. ``--tool`` can be used to specify
5831 the merge tool used for the given files. It overrides the HGMERGE
5831 the merge tool used for the given files. It overrides the HGMERGE
5832 environment variable and your configuration files. Previous file
5832 environment variable and your configuration files. Previous file
5833 contents are saved with a ``.orig`` suffix.
5833 contents are saved with a ``.orig`` suffix.
5834
5834
5835 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5835 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5836 (e.g. after having manually fixed-up the files). The default is
5836 (e.g. after having manually fixed-up the files). The default is
5837 to mark all unresolved files.
5837 to mark all unresolved files.
5838
5838
5839 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5839 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5840 default is to mark all resolved files.
5840 default is to mark all resolved files.
5841
5841
5842 - :hg:`resolve -l`: list files which had or still have conflicts.
5842 - :hg:`resolve -l`: list files which had or still have conflicts.
5843 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5843 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5844
5844
5845 .. note::
5845 .. note::
5846
5846
5847 Mercurial will not let you commit files with unresolved merge
5847 Mercurial will not let you commit files with unresolved merge
5848 conflicts. You must use :hg:`resolve -m ...` before you can
5848 conflicts. You must use :hg:`resolve -m ...` before you can
5849 commit after a conflicting merge.
5849 commit after a conflicting merge.
5850
5850
5851 Returns 0 on success, 1 if any files fail a resolve attempt.
5851 Returns 0 on success, 1 if any files fail a resolve attempt.
5852 """
5852 """
5853
5853
5854 all, mark, unmark, show, nostatus = \
5854 all, mark, unmark, show, nostatus = \
5855 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5855 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5856
5856
5857 if (show and (mark or unmark)) or (mark and unmark):
5857 if (show and (mark or unmark)) or (mark and unmark):
5858 raise error.Abort(_("too many options specified"))
5858 raise error.Abort(_("too many options specified"))
5859 if pats and all:
5859 if pats and all:
5860 raise error.Abort(_("can't specify --all and patterns"))
5860 raise error.Abort(_("can't specify --all and patterns"))
5861 if not (all or pats or show or mark or unmark):
5861 if not (all or pats or show or mark or unmark):
5862 raise error.Abort(_('no files or directories specified'),
5862 raise error.Abort(_('no files or directories specified'),
5863 hint=('use --all to re-merge all unresolved files'))
5863 hint=('use --all to re-merge all unresolved files'))
5864
5864
5865 if show:
5865 if show:
5866 fm = ui.formatter('resolve', opts)
5866 fm = ui.formatter('resolve', opts)
5867 ms = mergemod.mergestate.read(repo)
5867 ms = mergemod.mergestate.read(repo)
5868 m = scmutil.match(repo[None], pats, opts)
5868 m = scmutil.match(repo[None], pats, opts)
5869 for f in ms:
5869 for f in ms:
5870 if not m(f):
5870 if not m(f):
5871 continue
5871 continue
5872 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5872 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5873 'd': 'driverresolved'}[ms[f]]
5873 'd': 'driverresolved'}[ms[f]]
5874 fm.startitem()
5874 fm.startitem()
5875 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5875 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5876 fm.write('path', '%s\n', f, label=l)
5876 fm.write('path', '%s\n', f, label=l)
5877 fm.end()
5877 fm.end()
5878 return 0
5878 return 0
5879
5879
5880 wlock = repo.wlock()
5880 wlock = repo.wlock()
5881 try:
5881 try:
5882 ms = mergemod.mergestate.read(repo)
5882 ms = mergemod.mergestate.read(repo)
5883
5883
5884 if not (ms.active() or repo.dirstate.p2() != nullid):
5884 if not (ms.active() or repo.dirstate.p2() != nullid):
5885 raise error.Abort(
5885 raise error.Abort(
5886 _('resolve command not applicable when not merging'))
5886 _('resolve command not applicable when not merging'))
5887
5887
5888 wctx = repo[None]
5888 wctx = repo[None]
5889
5889
5890 if ms.mergedriver and ms.mdstate() == 'u':
5890 if ms.mergedriver and ms.mdstate() == 'u':
5891 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5891 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5892 ms.commit()
5892 ms.commit()
5893 # allow mark and unmark to go through
5893 # allow mark and unmark to go through
5894 if not mark and not unmark and not proceed:
5894 if not mark and not unmark and not proceed:
5895 return 1
5895 return 1
5896
5896
5897 m = scmutil.match(wctx, pats, opts)
5897 m = scmutil.match(wctx, pats, opts)
5898 ret = 0
5898 ret = 0
5899 didwork = False
5899 didwork = False
5900 runconclude = False
5900 runconclude = False
5901
5901
5902 tocomplete = []
5902 tocomplete = []
5903 for f in ms:
5903 for f in ms:
5904 if not m(f):
5904 if not m(f):
5905 continue
5905 continue
5906
5906
5907 didwork = True
5907 didwork = True
5908
5908
5909 # don't let driver-resolved files be marked, and run the conclude
5909 # don't let driver-resolved files be marked, and run the conclude
5910 # step if asked to resolve
5910 # step if asked to resolve
5911 if ms[f] == "d":
5911 if ms[f] == "d":
5912 exact = m.exact(f)
5912 exact = m.exact(f)
5913 if mark:
5913 if mark:
5914 if exact:
5914 if exact:
5915 ui.warn(_('not marking %s as it is driver-resolved\n')
5915 ui.warn(_('not marking %s as it is driver-resolved\n')
5916 % f)
5916 % f)
5917 elif unmark:
5917 elif unmark:
5918 if exact:
5918 if exact:
5919 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5919 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5920 % f)
5920 % f)
5921 else:
5921 else:
5922 runconclude = True
5922 runconclude = True
5923 continue
5923 continue
5924
5924
5925 if mark:
5925 if mark:
5926 ms.mark(f, "r")
5926 ms.mark(f, "r")
5927 elif unmark:
5927 elif unmark:
5928 ms.mark(f, "u")
5928 ms.mark(f, "u")
5929 else:
5929 else:
5930 # backup pre-resolve (merge uses .orig for its own purposes)
5930 # backup pre-resolve (merge uses .orig for its own purposes)
5931 a = repo.wjoin(f)
5931 a = repo.wjoin(f)
5932 try:
5932 try:
5933 util.copyfile(a, a + ".resolve")
5933 util.copyfile(a, a + ".resolve")
5934 except (IOError, OSError) as inst:
5934 except (IOError, OSError) as inst:
5935 if inst.errno != errno.ENOENT:
5935 if inst.errno != errno.ENOENT:
5936 raise
5936 raise
5937
5937
5938 try:
5938 try:
5939 # preresolve file
5939 # preresolve file
5940 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5940 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5941 'resolve')
5941 'resolve')
5942 complete, r = ms.preresolve(f, wctx)
5942 complete, r = ms.preresolve(f, wctx)
5943 if not complete:
5943 if not complete:
5944 tocomplete.append(f)
5944 tocomplete.append(f)
5945 elif r:
5945 elif r:
5946 ret = 1
5946 ret = 1
5947 finally:
5947 finally:
5948 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5948 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5949 ms.commit()
5949 ms.commit()
5950
5950
5951 # replace filemerge's .orig file with our resolve file, but only
5951 # replace filemerge's .orig file with our resolve file, but only
5952 # for merges that are complete
5952 # for merges that are complete
5953 if complete:
5953 if complete:
5954 try:
5954 try:
5955 util.rename(a + ".resolve",
5955 util.rename(a + ".resolve",
5956 scmutil.origpath(ui, repo, a))
5956 scmutil.origpath(ui, repo, a))
5957 except OSError as inst:
5957 except OSError as inst:
5958 if inst.errno != errno.ENOENT:
5958 if inst.errno != errno.ENOENT:
5959 raise
5959 raise
5960
5960
5961 for f in tocomplete:
5961 for f in tocomplete:
5962 try:
5962 try:
5963 # resolve file
5963 # resolve file
5964 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5964 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5965 'resolve')
5965 'resolve')
5966 r = ms.resolve(f, wctx)
5966 r = ms.resolve(f, wctx)
5967 if r:
5967 if r:
5968 ret = 1
5968 ret = 1
5969 finally:
5969 finally:
5970 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5970 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5971 ms.commit()
5971 ms.commit()
5972
5972
5973 # replace filemerge's .orig file with our resolve file
5973 # replace filemerge's .orig file with our resolve file
5974 a = repo.wjoin(f)
5974 a = repo.wjoin(f)
5975 try:
5975 try:
5976 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5976 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
5977 except OSError as inst:
5977 except OSError as inst:
5978 if inst.errno != errno.ENOENT:
5978 if inst.errno != errno.ENOENT:
5979 raise
5979 raise
5980
5980
5981 ms.commit()
5981 ms.commit()
5982 ms.recordactions()
5982 ms.recordactions()
5983
5983
5984 if not didwork and pats:
5984 if not didwork and pats:
5985 ui.warn(_("arguments do not match paths that need resolving\n"))
5985 ui.warn(_("arguments do not match paths that need resolving\n"))
5986 elif ms.mergedriver and ms.mdstate() != 's':
5986 elif ms.mergedriver and ms.mdstate() != 's':
5987 # run conclude step when either a driver-resolved file is requested
5987 # run conclude step when either a driver-resolved file is requested
5988 # or there are no driver-resolved files
5988 # or there are no driver-resolved files
5989 # we can't use 'ret' to determine whether any files are unresolved
5989 # we can't use 'ret' to determine whether any files are unresolved
5990 # because we might not have tried to resolve some
5990 # because we might not have tried to resolve some
5991 if ((runconclude or not list(ms.driverresolved()))
5991 if ((runconclude or not list(ms.driverresolved()))
5992 and not list(ms.unresolved())):
5992 and not list(ms.unresolved())):
5993 proceed = mergemod.driverconclude(repo, ms, wctx)
5993 proceed = mergemod.driverconclude(repo, ms, wctx)
5994 ms.commit()
5994 ms.commit()
5995 if not proceed:
5995 if not proceed:
5996 return 1
5996 return 1
5997
5997
5998 finally:
5998 finally:
5999 wlock.release()
5999 wlock.release()
6000
6000
6001 # Nudge users into finishing an unfinished operation
6001 # Nudge users into finishing an unfinished operation
6002 unresolvedf = list(ms.unresolved())
6002 unresolvedf = list(ms.unresolved())
6003 driverresolvedf = list(ms.driverresolved())
6003 driverresolvedf = list(ms.driverresolved())
6004 if not unresolvedf and not driverresolvedf:
6004 if not unresolvedf and not driverresolvedf:
6005 ui.status(_('(no more unresolved files)\n'))
6005 ui.status(_('(no more unresolved files)\n'))
6006 cmdutil.checkafterresolved(repo)
6006 cmdutil.checkafterresolved(repo)
6007 elif not unresolvedf:
6007 elif not unresolvedf:
6008 ui.status(_('(no more unresolved files -- '
6008 ui.status(_('(no more unresolved files -- '
6009 'run "hg resolve --all" to conclude)\n'))
6009 'run "hg resolve --all" to conclude)\n'))
6010
6010
6011 return ret
6011 return ret
6012
6012
6013 @command('revert',
6013 @command('revert',
6014 [('a', 'all', None, _('revert all changes when no arguments given')),
6014 [('a', 'all', None, _('revert all changes when no arguments given')),
6015 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6015 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6016 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6016 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6017 ('C', 'no-backup', None, _('do not save backup copies of files')),
6017 ('C', 'no-backup', None, _('do not save backup copies of files')),
6018 ('i', 'interactive', None,
6018 ('i', 'interactive', None,
6019 _('interactively select the changes (EXPERIMENTAL)')),
6019 _('interactively select the changes (EXPERIMENTAL)')),
6020 ] + walkopts + dryrunopts,
6020 ] + walkopts + dryrunopts,
6021 _('[OPTION]... [-r REV] [NAME]...'))
6021 _('[OPTION]... [-r REV] [NAME]...'))
6022 def revert(ui, repo, *pats, **opts):
6022 def revert(ui, repo, *pats, **opts):
6023 """restore files to their checkout state
6023 """restore files to their checkout state
6024
6024
6025 .. note::
6025 .. note::
6026
6026
6027 To check out earlier revisions, you should use :hg:`update REV`.
6027 To check out earlier revisions, you should use :hg:`update REV`.
6028 To cancel an uncommitted merge (and lose your changes),
6028 To cancel an uncommitted merge (and lose your changes),
6029 use :hg:`update --clean .`.
6029 use :hg:`update --clean .`.
6030
6030
6031 With no revision specified, revert the specified files or directories
6031 With no revision specified, revert the specified files or directories
6032 to the contents they had in the parent of the working directory.
6032 to the contents they had in the parent of the working directory.
6033 This restores the contents of files to an unmodified
6033 This restores the contents of files to an unmodified
6034 state and unschedules adds, removes, copies, and renames. If the
6034 state and unschedules adds, removes, copies, and renames. If the
6035 working directory has two parents, you must explicitly specify a
6035 working directory has two parents, you must explicitly specify a
6036 revision.
6036 revision.
6037
6037
6038 Using the -r/--rev or -d/--date options, revert the given files or
6038 Using the -r/--rev or -d/--date options, revert the given files or
6039 directories to their states as of a specific revision. Because
6039 directories to their states as of a specific revision. Because
6040 revert does not change the working directory parents, this will
6040 revert does not change the working directory parents, this will
6041 cause these files to appear modified. This can be helpful to "back
6041 cause these files to appear modified. This can be helpful to "back
6042 out" some or all of an earlier change. See :hg:`backout` for a
6042 out" some or all of an earlier change. See :hg:`backout` for a
6043 related method.
6043 related method.
6044
6044
6045 Modified files are saved with a .orig suffix before reverting.
6045 Modified files are saved with a .orig suffix before reverting.
6046 To disable these backups, use --no-backup.
6046 To disable these backups, use --no-backup.
6047
6047
6048 See :hg:`help dates` for a list of formats valid for -d/--date.
6048 See :hg:`help dates` for a list of formats valid for -d/--date.
6049
6049
6050 See :hg:`help backout` for a way to reverse the effect of an
6050 See :hg:`help backout` for a way to reverse the effect of an
6051 earlier changeset.
6051 earlier changeset.
6052
6052
6053 Returns 0 on success.
6053 Returns 0 on success.
6054 """
6054 """
6055
6055
6056 if opts.get("date"):
6056 if opts.get("date"):
6057 if opts.get("rev"):
6057 if opts.get("rev"):
6058 raise error.Abort(_("you can't specify a revision and a date"))
6058 raise error.Abort(_("you can't specify a revision and a date"))
6059 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6059 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6060
6060
6061 parent, p2 = repo.dirstate.parents()
6061 parent, p2 = repo.dirstate.parents()
6062 if not opts.get('rev') and p2 != nullid:
6062 if not opts.get('rev') and p2 != nullid:
6063 # revert after merge is a trap for new users (issue2915)
6063 # revert after merge is a trap for new users (issue2915)
6064 raise error.Abort(_('uncommitted merge with no revision specified'),
6064 raise error.Abort(_('uncommitted merge with no revision specified'),
6065 hint=_('use "hg update" or see "hg help revert"'))
6065 hint=_('use "hg update" or see "hg help revert"'))
6066
6066
6067 ctx = scmutil.revsingle(repo, opts.get('rev'))
6067 ctx = scmutil.revsingle(repo, opts.get('rev'))
6068
6068
6069 if (not (pats or opts.get('include') or opts.get('exclude') or
6069 if (not (pats or opts.get('include') or opts.get('exclude') or
6070 opts.get('all') or opts.get('interactive'))):
6070 opts.get('all') or opts.get('interactive'))):
6071 msg = _("no files or directories specified")
6071 msg = _("no files or directories specified")
6072 if p2 != nullid:
6072 if p2 != nullid:
6073 hint = _("uncommitted merge, use --all to discard all changes,"
6073 hint = _("uncommitted merge, use --all to discard all changes,"
6074 " or 'hg update -C .' to abort the merge")
6074 " or 'hg update -C .' to abort the merge")
6075 raise error.Abort(msg, hint=hint)
6075 raise error.Abort(msg, hint=hint)
6076 dirty = any(repo.status())
6076 dirty = any(repo.status())
6077 node = ctx.node()
6077 node = ctx.node()
6078 if node != parent:
6078 if node != parent:
6079 if dirty:
6079 if dirty:
6080 hint = _("uncommitted changes, use --all to discard all"
6080 hint = _("uncommitted changes, use --all to discard all"
6081 " changes, or 'hg update %s' to update") % ctx.rev()
6081 " changes, or 'hg update %s' to update") % ctx.rev()
6082 else:
6082 else:
6083 hint = _("use --all to revert all files,"
6083 hint = _("use --all to revert all files,"
6084 " or 'hg update %s' to update") % ctx.rev()
6084 " or 'hg update %s' to update") % ctx.rev()
6085 elif dirty:
6085 elif dirty:
6086 hint = _("uncommitted changes, use --all to discard all changes")
6086 hint = _("uncommitted changes, use --all to discard all changes")
6087 else:
6087 else:
6088 hint = _("use --all to revert all files")
6088 hint = _("use --all to revert all files")
6089 raise error.Abort(msg, hint=hint)
6089 raise error.Abort(msg, hint=hint)
6090
6090
6091 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6091 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6092
6092
6093 @command('rollback', dryrunopts +
6093 @command('rollback', dryrunopts +
6094 [('f', 'force', False, _('ignore safety measures'))])
6094 [('f', 'force', False, _('ignore safety measures'))])
6095 def rollback(ui, repo, **opts):
6095 def rollback(ui, repo, **opts):
6096 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6096 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6097
6097
6098 Please use :hg:`commit --amend` instead of rollback to correct
6098 Please use :hg:`commit --amend` instead of rollback to correct
6099 mistakes in the last commit.
6099 mistakes in the last commit.
6100
6100
6101 This command should be used with care. There is only one level of
6101 This command should be used with care. There is only one level of
6102 rollback, and there is no way to undo a rollback. It will also
6102 rollback, and there is no way to undo a rollback. It will also
6103 restore the dirstate at the time of the last transaction, losing
6103 restore the dirstate at the time of the last transaction, losing
6104 any dirstate changes since that time. This command does not alter
6104 any dirstate changes since that time. This command does not alter
6105 the working directory.
6105 the working directory.
6106
6106
6107 Transactions are used to encapsulate the effects of all commands
6107 Transactions are used to encapsulate the effects of all commands
6108 that create new changesets or propagate existing changesets into a
6108 that create new changesets or propagate existing changesets into a
6109 repository.
6109 repository.
6110
6110
6111 .. container:: verbose
6111 .. container:: verbose
6112
6112
6113 For example, the following commands are transactional, and their
6113 For example, the following commands are transactional, and their
6114 effects can be rolled back:
6114 effects can be rolled back:
6115
6115
6116 - commit
6116 - commit
6117 - import
6117 - import
6118 - pull
6118 - pull
6119 - push (with this repository as the destination)
6119 - push (with this repository as the destination)
6120 - unbundle
6120 - unbundle
6121
6121
6122 To avoid permanent data loss, rollback will refuse to rollback a
6122 To avoid permanent data loss, rollback will refuse to rollback a
6123 commit transaction if it isn't checked out. Use --force to
6123 commit transaction if it isn't checked out. Use --force to
6124 override this protection.
6124 override this protection.
6125
6125
6126 This command is not intended for use on public repositories. Once
6126 This command is not intended for use on public repositories. Once
6127 changes are visible for pull by other users, rolling a transaction
6127 changes are visible for pull by other users, rolling a transaction
6128 back locally is ineffective (someone else may already have pulled
6128 back locally is ineffective (someone else may already have pulled
6129 the changes). Furthermore, a race is possible with readers of the
6129 the changes). Furthermore, a race is possible with readers of the
6130 repository; for example an in-progress pull from the repository
6130 repository; for example an in-progress pull from the repository
6131 may fail if a rollback is performed.
6131 may fail if a rollback is performed.
6132
6132
6133 Returns 0 on success, 1 if no rollback data is available.
6133 Returns 0 on success, 1 if no rollback data is available.
6134 """
6134 """
6135 return repo.rollback(dryrun=opts.get('dry_run'),
6135 return repo.rollback(dryrun=opts.get('dry_run'),
6136 force=opts.get('force'))
6136 force=opts.get('force'))
6137
6137
6138 @command('root', [])
6138 @command('root', [])
6139 def root(ui, repo):
6139 def root(ui, repo):
6140 """print the root (top) of the current working directory
6140 """print the root (top) of the current working directory
6141
6141
6142 Print the root directory of the current repository.
6142 Print the root directory of the current repository.
6143
6143
6144 Returns 0 on success.
6144 Returns 0 on success.
6145 """
6145 """
6146 ui.write(repo.root + "\n")
6146 ui.write(repo.root + "\n")
6147
6147
6148 @command('^serve',
6148 @command('^serve',
6149 [('A', 'accesslog', '', _('name of access log file to write to'),
6149 [('A', 'accesslog', '', _('name of access log file to write to'),
6150 _('FILE')),
6150 _('FILE')),
6151 ('d', 'daemon', None, _('run server in background')),
6151 ('d', 'daemon', None, _('run server in background')),
6152 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6152 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6153 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6153 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6154 # use string type, then we can check if something was passed
6154 # use string type, then we can check if something was passed
6155 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6155 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6156 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6156 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6157 _('ADDR')),
6157 _('ADDR')),
6158 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6158 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6159 _('PREFIX')),
6159 _('PREFIX')),
6160 ('n', 'name', '',
6160 ('n', 'name', '',
6161 _('name to show in web pages (default: working directory)'), _('NAME')),
6161 _('name to show in web pages (default: working directory)'), _('NAME')),
6162 ('', 'web-conf', '',
6162 ('', 'web-conf', '',
6163 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6163 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6164 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6164 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6165 _('FILE')),
6165 _('FILE')),
6166 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6166 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6167 ('', 'stdio', None, _('for remote clients')),
6167 ('', 'stdio', None, _('for remote clients')),
6168 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6168 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6169 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6169 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6170 ('', 'style', '', _('template style to use'), _('STYLE')),
6170 ('', 'style', '', _('template style to use'), _('STYLE')),
6171 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6171 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6172 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6172 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6173 _('[OPTION]...'),
6173 _('[OPTION]...'),
6174 optionalrepo=True)
6174 optionalrepo=True)
6175 def serve(ui, repo, **opts):
6175 def serve(ui, repo, **opts):
6176 """start stand-alone webserver
6176 """start stand-alone webserver
6177
6177
6178 Start a local HTTP repository browser and pull server. You can use
6178 Start a local HTTP repository browser and pull server. You can use
6179 this for ad-hoc sharing and browsing of repositories. It is
6179 this for ad-hoc sharing and browsing of repositories. It is
6180 recommended to use a real web server to serve a repository for
6180 recommended to use a real web server to serve a repository for
6181 longer periods of time.
6181 longer periods of time.
6182
6182
6183 Please note that the server does not implement access control.
6183 Please note that the server does not implement access control.
6184 This means that, by default, anybody can read from the server and
6184 This means that, by default, anybody can read from the server and
6185 nobody can write to it by default. Set the ``web.allow_push``
6185 nobody can write to it by default. Set the ``web.allow_push``
6186 option to ``*`` to allow everybody to push to the server. You
6186 option to ``*`` to allow everybody to push to the server. You
6187 should use a real web server if you need to authenticate users.
6187 should use a real web server if you need to authenticate users.
6188
6188
6189 By default, the server logs accesses to stdout and errors to
6189 By default, the server logs accesses to stdout and errors to
6190 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6190 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6191 files.
6191 files.
6192
6192
6193 To have the server choose a free port number to listen on, specify
6193 To have the server choose a free port number to listen on, specify
6194 a port number of 0; in this case, the server will print the port
6194 a port number of 0; in this case, the server will print the port
6195 number it uses.
6195 number it uses.
6196
6196
6197 Returns 0 on success.
6197 Returns 0 on success.
6198 """
6198 """
6199
6199
6200 if opts["stdio"] and opts["cmdserver"]:
6200 if opts["stdio"] and opts["cmdserver"]:
6201 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6201 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6202
6202
6203 if opts["stdio"]:
6203 if opts["stdio"]:
6204 if repo is None:
6204 if repo is None:
6205 raise error.RepoError(_("there is no Mercurial repository here"
6205 raise error.RepoError(_("there is no Mercurial repository here"
6206 " (.hg not found)"))
6206 " (.hg not found)"))
6207 s = sshserver.sshserver(ui, repo)
6207 s = sshserver.sshserver(ui, repo)
6208 s.serve_forever()
6208 s.serve_forever()
6209
6209
6210 if opts["cmdserver"]:
6210 if opts["cmdserver"]:
6211 service = commandserver.createservice(ui, repo, opts)
6211 service = commandserver.createservice(ui, repo, opts)
6212 else:
6212 else:
6213 service = hgweb.createservice(ui, repo, opts)
6213 service = hgweb.createservice(ui, repo, opts)
6214 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6214 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6215
6215
6216 @command('^status|st',
6216 @command('^status|st',
6217 [('A', 'all', None, _('show status of all files')),
6217 [('A', 'all', None, _('show status of all files')),
6218 ('m', 'modified', None, _('show only modified files')),
6218 ('m', 'modified', None, _('show only modified files')),
6219 ('a', 'added', None, _('show only added files')),
6219 ('a', 'added', None, _('show only added files')),
6220 ('r', 'removed', None, _('show only removed files')),
6220 ('r', 'removed', None, _('show only removed files')),
6221 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6221 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6222 ('c', 'clean', None, _('show only files without changes')),
6222 ('c', 'clean', None, _('show only files without changes')),
6223 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6223 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6224 ('i', 'ignored', None, _('show only ignored files')),
6224 ('i', 'ignored', None, _('show only ignored files')),
6225 ('n', 'no-status', None, _('hide status prefix')),
6225 ('n', 'no-status', None, _('hide status prefix')),
6226 ('C', 'copies', None, _('show source of copied files')),
6226 ('C', 'copies', None, _('show source of copied files')),
6227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6228 ('', 'rev', [], _('show difference from revision'), _('REV')),
6228 ('', 'rev', [], _('show difference from revision'), _('REV')),
6229 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6229 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6230 ] + walkopts + subrepoopts + formatteropts,
6230 ] + walkopts + subrepoopts + formatteropts,
6231 _('[OPTION]... [FILE]...'),
6231 _('[OPTION]... [FILE]...'),
6232 inferrepo=True)
6232 inferrepo=True)
6233 def status(ui, repo, *pats, **opts):
6233 def status(ui, repo, *pats, **opts):
6234 """show changed files in the working directory
6234 """show changed files in the working directory
6235
6235
6236 Show status of files in the repository. If names are given, only
6236 Show status of files in the repository. If names are given, only
6237 files that match are shown. Files that are clean or ignored or
6237 files that match are shown. Files that are clean or ignored or
6238 the source of a copy/move operation, are not listed unless
6238 the source of a copy/move operation, are not listed unless
6239 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6239 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6240 Unless options described with "show only ..." are given, the
6240 Unless options described with "show only ..." are given, the
6241 options -mardu are used.
6241 options -mardu are used.
6242
6242
6243 Option -q/--quiet hides untracked (unknown and ignored) files
6243 Option -q/--quiet hides untracked (unknown and ignored) files
6244 unless explicitly requested with -u/--unknown or -i/--ignored.
6244 unless explicitly requested with -u/--unknown or -i/--ignored.
6245
6245
6246 .. note::
6246 .. note::
6247
6247
6248 :hg:`status` may appear to disagree with diff if permissions have
6248 :hg:`status` may appear to disagree with diff if permissions have
6249 changed or a merge has occurred. The standard diff format does
6249 changed or a merge has occurred. The standard diff format does
6250 not report permission changes and diff only reports changes
6250 not report permission changes and diff only reports changes
6251 relative to one merge parent.
6251 relative to one merge parent.
6252
6252
6253 If one revision is given, it is used as the base revision.
6253 If one revision is given, it is used as the base revision.
6254 If two revisions are given, the differences between them are
6254 If two revisions are given, the differences between them are
6255 shown. The --change option can also be used as a shortcut to list
6255 shown. The --change option can also be used as a shortcut to list
6256 the changed files of a revision from its first parent.
6256 the changed files of a revision from its first parent.
6257
6257
6258 The codes used to show the status of files are::
6258 The codes used to show the status of files are::
6259
6259
6260 M = modified
6260 M = modified
6261 A = added
6261 A = added
6262 R = removed
6262 R = removed
6263 C = clean
6263 C = clean
6264 ! = missing (deleted by non-hg command, but still tracked)
6264 ! = missing (deleted by non-hg command, but still tracked)
6265 ? = not tracked
6265 ? = not tracked
6266 I = ignored
6266 I = ignored
6267 = origin of the previous file (with --copies)
6267 = origin of the previous file (with --copies)
6268
6268
6269 .. container:: verbose
6269 .. container:: verbose
6270
6270
6271 Examples:
6271 Examples:
6272
6272
6273 - show changes in the working directory relative to a
6273 - show changes in the working directory relative to a
6274 changeset::
6274 changeset::
6275
6275
6276 hg status --rev 9353
6276 hg status --rev 9353
6277
6277
6278 - show changes in the working directory relative to the
6278 - show changes in the working directory relative to the
6279 current directory (see :hg:`help patterns` for more information)::
6279 current directory (see :hg:`help patterns` for more information)::
6280
6280
6281 hg status re:
6281 hg status re:
6282
6282
6283 - show all changes including copies in an existing changeset::
6283 - show all changes including copies in an existing changeset::
6284
6284
6285 hg status --copies --change 9353
6285 hg status --copies --change 9353
6286
6286
6287 - get a NUL separated list of added files, suitable for xargs::
6287 - get a NUL separated list of added files, suitable for xargs::
6288
6288
6289 hg status -an0
6289 hg status -an0
6290
6290
6291 Returns 0 on success.
6291 Returns 0 on success.
6292 """
6292 """
6293
6293
6294 revs = opts.get('rev')
6294 revs = opts.get('rev')
6295 change = opts.get('change')
6295 change = opts.get('change')
6296
6296
6297 if revs and change:
6297 if revs and change:
6298 msg = _('cannot specify --rev and --change at the same time')
6298 msg = _('cannot specify --rev and --change at the same time')
6299 raise error.Abort(msg)
6299 raise error.Abort(msg)
6300 elif change:
6300 elif change:
6301 node2 = scmutil.revsingle(repo, change, None).node()
6301 node2 = scmutil.revsingle(repo, change, None).node()
6302 node1 = repo[node2].p1().node()
6302 node1 = repo[node2].p1().node()
6303 else:
6303 else:
6304 node1, node2 = scmutil.revpair(repo, revs)
6304 node1, node2 = scmutil.revpair(repo, revs)
6305
6305
6306 if pats:
6306 if pats:
6307 cwd = repo.getcwd()
6307 cwd = repo.getcwd()
6308 else:
6308 else:
6309 cwd = ''
6309 cwd = ''
6310
6310
6311 if opts.get('print0'):
6311 if opts.get('print0'):
6312 end = '\0'
6312 end = '\0'
6313 else:
6313 else:
6314 end = '\n'
6314 end = '\n'
6315 copy = {}
6315 copy = {}
6316 states = 'modified added removed deleted unknown ignored clean'.split()
6316 states = 'modified added removed deleted unknown ignored clean'.split()
6317 show = [k for k in states if opts.get(k)]
6317 show = [k for k in states if opts.get(k)]
6318 if opts.get('all'):
6318 if opts.get('all'):
6319 show += ui.quiet and (states[:4] + ['clean']) or states
6319 show += ui.quiet and (states[:4] + ['clean']) or states
6320 if not show:
6320 if not show:
6321 if ui.quiet:
6321 if ui.quiet:
6322 show = states[:4]
6322 show = states[:4]
6323 else:
6323 else:
6324 show = states[:5]
6324 show = states[:5]
6325
6325
6326 m = scmutil.match(repo[node2], pats, opts)
6326 m = scmutil.match(repo[node2], pats, opts)
6327 stat = repo.status(node1, node2, m,
6327 stat = repo.status(node1, node2, m,
6328 'ignored' in show, 'clean' in show, 'unknown' in show,
6328 'ignored' in show, 'clean' in show, 'unknown' in show,
6329 opts.get('subrepos'))
6329 opts.get('subrepos'))
6330 changestates = zip(states, 'MAR!?IC', stat)
6330 changestates = zip(states, 'MAR!?IC', stat)
6331
6331
6332 if (opts.get('all') or opts.get('copies')
6332 if (opts.get('all') or opts.get('copies')
6333 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6333 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6334 copy = copies.pathcopies(repo[node1], repo[node2], m)
6334 copy = copies.pathcopies(repo[node1], repo[node2], m)
6335
6335
6336 fm = ui.formatter('status', opts)
6336 fm = ui.formatter('status', opts)
6337 fmt = '%s' + end
6337 fmt = '%s' + end
6338 showchar = not opts.get('no_status')
6338 showchar = not opts.get('no_status')
6339
6339
6340 for state, char, files in changestates:
6340 for state, char, files in changestates:
6341 if state in show:
6341 if state in show:
6342 label = 'status.' + state
6342 label = 'status.' + state
6343 for f in files:
6343 for f in files:
6344 fm.startitem()
6344 fm.startitem()
6345 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6345 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6346 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6346 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6347 if f in copy:
6347 if f in copy:
6348 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6348 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6349 label='status.copied')
6349 label='status.copied')
6350 fm.end()
6350 fm.end()
6351
6351
6352 @command('^summary|sum',
6352 @command('^summary|sum',
6353 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6353 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6354 def summary(ui, repo, **opts):
6354 def summary(ui, repo, **opts):
6355 """summarize working directory state
6355 """summarize working directory state
6356
6356
6357 This generates a brief summary of the working directory state,
6357 This generates a brief summary of the working directory state,
6358 including parents, branch, commit status, phase and available updates.
6358 including parents, branch, commit status, phase and available updates.
6359
6359
6360 With the --remote option, this will check the default paths for
6360 With the --remote option, this will check the default paths for
6361 incoming and outgoing changes. This can be time-consuming.
6361 incoming and outgoing changes. This can be time-consuming.
6362
6362
6363 Returns 0 on success.
6363 Returns 0 on success.
6364 """
6364 """
6365
6365
6366 ctx = repo[None]
6366 ctx = repo[None]
6367 parents = ctx.parents()
6367 parents = ctx.parents()
6368 pnode = parents[0].node()
6368 pnode = parents[0].node()
6369 marks = []
6369 marks = []
6370
6370
6371 for p in parents:
6371 for p in parents:
6372 # label with log.changeset (instead of log.parent) since this
6372 # label with log.changeset (instead of log.parent) since this
6373 # shows a working directory parent *changeset*:
6373 # shows a working directory parent *changeset*:
6374 # i18n: column positioning for "hg summary"
6374 # i18n: column positioning for "hg summary"
6375 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6375 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6376 label='log.changeset changeset.%s' % p.phasestr())
6376 label='log.changeset changeset.%s' % p.phasestr())
6377 ui.write(' '.join(p.tags()), label='log.tag')
6377 ui.write(' '.join(p.tags()), label='log.tag')
6378 if p.bookmarks():
6378 if p.bookmarks():
6379 marks.extend(p.bookmarks())
6379 marks.extend(p.bookmarks())
6380 if p.rev() == -1:
6380 if p.rev() == -1:
6381 if not len(repo):
6381 if not len(repo):
6382 ui.write(_(' (empty repository)'))
6382 ui.write(_(' (empty repository)'))
6383 else:
6383 else:
6384 ui.write(_(' (no revision checked out)'))
6384 ui.write(_(' (no revision checked out)'))
6385 ui.write('\n')
6385 ui.write('\n')
6386 if p.description():
6386 if p.description():
6387 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6387 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6388 label='log.summary')
6388 label='log.summary')
6389
6389
6390 branch = ctx.branch()
6390 branch = ctx.branch()
6391 bheads = repo.branchheads(branch)
6391 bheads = repo.branchheads(branch)
6392 # i18n: column positioning for "hg summary"
6392 # i18n: column positioning for "hg summary"
6393 m = _('branch: %s\n') % branch
6393 m = _('branch: %s\n') % branch
6394 if branch != 'default':
6394 if branch != 'default':
6395 ui.write(m, label='log.branch')
6395 ui.write(m, label='log.branch')
6396 else:
6396 else:
6397 ui.status(m, label='log.branch')
6397 ui.status(m, label='log.branch')
6398
6398
6399 if marks:
6399 if marks:
6400 active = repo._activebookmark
6400 active = repo._activebookmark
6401 # i18n: column positioning for "hg summary"
6401 # i18n: column positioning for "hg summary"
6402 ui.write(_('bookmarks:'), label='log.bookmark')
6402 ui.write(_('bookmarks:'), label='log.bookmark')
6403 if active is not None:
6403 if active is not None:
6404 if active in marks:
6404 if active in marks:
6405 ui.write(' *' + active, label=activebookmarklabel)
6405 ui.write(' *' + active, label=activebookmarklabel)
6406 marks.remove(active)
6406 marks.remove(active)
6407 else:
6407 else:
6408 ui.write(' [%s]' % active, label=activebookmarklabel)
6408 ui.write(' [%s]' % active, label=activebookmarklabel)
6409 for m in marks:
6409 for m in marks:
6410 ui.write(' ' + m, label='log.bookmark')
6410 ui.write(' ' + m, label='log.bookmark')
6411 ui.write('\n', label='log.bookmark')
6411 ui.write('\n', label='log.bookmark')
6412
6412
6413 status = repo.status(unknown=True)
6413 status = repo.status(unknown=True)
6414
6414
6415 c = repo.dirstate.copies()
6415 c = repo.dirstate.copies()
6416 copied, renamed = [], []
6416 copied, renamed = [], []
6417 for d, s in c.iteritems():
6417 for d, s in c.iteritems():
6418 if s in status.removed:
6418 if s in status.removed:
6419 status.removed.remove(s)
6419 status.removed.remove(s)
6420 renamed.append(d)
6420 renamed.append(d)
6421 else:
6421 else:
6422 copied.append(d)
6422 copied.append(d)
6423 if d in status.added:
6423 if d in status.added:
6424 status.added.remove(d)
6424 status.added.remove(d)
6425
6425
6426 try:
6426 try:
6427 ms = mergemod.mergestate.read(repo)
6427 ms = mergemod.mergestate.read(repo)
6428 except error.UnsupportedMergeRecords as e:
6428 except error.UnsupportedMergeRecords as e:
6429 s = ' '.join(e.recordtypes)
6429 s = ' '.join(e.recordtypes)
6430 ui.warn(
6430 ui.warn(
6431 _('warning: merge state has unsupported record types: %s\n') % s)
6431 _('warning: merge state has unsupported record types: %s\n') % s)
6432 unresolved = 0
6432 unresolved = 0
6433 else:
6433 else:
6434 unresolved = [f for f in ms if ms[f] == 'u']
6434 unresolved = [f for f in ms if ms[f] == 'u']
6435
6435
6436 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6436 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6437
6437
6438 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6438 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6439 (ui.label(_('%d added'), 'status.added'), status.added),
6439 (ui.label(_('%d added'), 'status.added'), status.added),
6440 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6440 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6441 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6441 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6442 (ui.label(_('%d copied'), 'status.copied'), copied),
6442 (ui.label(_('%d copied'), 'status.copied'), copied),
6443 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6443 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6444 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6444 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6445 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6445 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6446 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6446 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6447 t = []
6447 t = []
6448 for l, s in labels:
6448 for l, s in labels:
6449 if s:
6449 if s:
6450 t.append(l % len(s))
6450 t.append(l % len(s))
6451
6451
6452 t = ', '.join(t)
6452 t = ', '.join(t)
6453 cleanworkdir = False
6453 cleanworkdir = False
6454
6454
6455 if repo.vfs.exists('graftstate'):
6455 if repo.vfs.exists('graftstate'):
6456 t += _(' (graft in progress)')
6456 t += _(' (graft in progress)')
6457 if repo.vfs.exists('updatestate'):
6457 if repo.vfs.exists('updatestate'):
6458 t += _(' (interrupted update)')
6458 t += _(' (interrupted update)')
6459 elif len(parents) > 1:
6459 elif len(parents) > 1:
6460 t += _(' (merge)')
6460 t += _(' (merge)')
6461 elif branch != parents[0].branch():
6461 elif branch != parents[0].branch():
6462 t += _(' (new branch)')
6462 t += _(' (new branch)')
6463 elif (parents[0].closesbranch() and
6463 elif (parents[0].closesbranch() and
6464 pnode in repo.branchheads(branch, closed=True)):
6464 pnode in repo.branchheads(branch, closed=True)):
6465 t += _(' (head closed)')
6465 t += _(' (head closed)')
6466 elif not (status.modified or status.added or status.removed or renamed or
6466 elif not (status.modified or status.added or status.removed or renamed or
6467 copied or subs):
6467 copied or subs):
6468 t += _(' (clean)')
6468 t += _(' (clean)')
6469 cleanworkdir = True
6469 cleanworkdir = True
6470 elif pnode not in bheads:
6470 elif pnode not in bheads:
6471 t += _(' (new branch head)')
6471 t += _(' (new branch head)')
6472
6472
6473 if parents:
6473 if parents:
6474 pendingphase = max(p.phase() for p in parents)
6474 pendingphase = max(p.phase() for p in parents)
6475 else:
6475 else:
6476 pendingphase = phases.public
6476 pendingphase = phases.public
6477
6477
6478 if pendingphase > phases.newcommitphase(ui):
6478 if pendingphase > phases.newcommitphase(ui):
6479 t += ' (%s)' % phases.phasenames[pendingphase]
6479 t += ' (%s)' % phases.phasenames[pendingphase]
6480
6480
6481 if cleanworkdir:
6481 if cleanworkdir:
6482 # i18n: column positioning for "hg summary"
6482 # i18n: column positioning for "hg summary"
6483 ui.status(_('commit: %s\n') % t.strip())
6483 ui.status(_('commit: %s\n') % t.strip())
6484 else:
6484 else:
6485 # i18n: column positioning for "hg summary"
6485 # i18n: column positioning for "hg summary"
6486 ui.write(_('commit: %s\n') % t.strip())
6486 ui.write(_('commit: %s\n') % t.strip())
6487
6487
6488 # all ancestors of branch heads - all ancestors of parent = new csets
6488 # all ancestors of branch heads - all ancestors of parent = new csets
6489 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6489 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6490 bheads))
6490 bheads))
6491
6491
6492 if new == 0:
6492 if new == 0:
6493 # i18n: column positioning for "hg summary"
6493 # i18n: column positioning for "hg summary"
6494 ui.status(_('update: (current)\n'))
6494 ui.status(_('update: (current)\n'))
6495 elif pnode not in bheads:
6495 elif pnode not in bheads:
6496 # i18n: column positioning for "hg summary"
6496 # i18n: column positioning for "hg summary"
6497 ui.write(_('update: %d new changesets (update)\n') % new)
6497 ui.write(_('update: %d new changesets (update)\n') % new)
6498 else:
6498 else:
6499 # i18n: column positioning for "hg summary"
6499 # i18n: column positioning for "hg summary"
6500 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6500 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6501 (new, len(bheads)))
6501 (new, len(bheads)))
6502
6502
6503 t = []
6503 t = []
6504 draft = len(repo.revs('draft()'))
6504 draft = len(repo.revs('draft()'))
6505 if draft:
6505 if draft:
6506 t.append(_('%d draft') % draft)
6506 t.append(_('%d draft') % draft)
6507 secret = len(repo.revs('secret()'))
6507 secret = len(repo.revs('secret()'))
6508 if secret:
6508 if secret:
6509 t.append(_('%d secret') % secret)
6509 t.append(_('%d secret') % secret)
6510
6510
6511 if draft or secret:
6511 if draft or secret:
6512 ui.status(_('phases: %s\n') % ', '.join(t))
6512 ui.status(_('phases: %s\n') % ', '.join(t))
6513
6513
6514 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6514 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6515 for trouble in ("unstable", "divergent", "bumped"):
6515 for trouble in ("unstable", "divergent", "bumped"):
6516 numtrouble = len(repo.revs(trouble + "()"))
6516 numtrouble = len(repo.revs(trouble + "()"))
6517 # We write all the possibilities to ease translation
6517 # We write all the possibilities to ease translation
6518 troublemsg = {
6518 troublemsg = {
6519 "unstable": _("unstable: %d changeset"),
6519 "unstable": _("unstable: %d changeset"),
6520 "divergent": _("divergent: %d changeset"),
6520 "divergent": _("divergent: %d changeset"),
6521 "bumped": _("bumped: %d changeset"),
6521 "bumped": _("bumped: %d changeset"),
6522 }
6522 }
6523 if numtrouble > 0:
6523 if numtrouble > 0:
6524 ui.status(troublemsg[trouble] % numtrouble + "\n")
6524 ui.status(troublemsg[trouble] % numtrouble + "\n")
6525
6525
6526 cmdutil.summaryhooks(ui, repo)
6526 cmdutil.summaryhooks(ui, repo)
6527
6527
6528 if opts.get('remote'):
6528 if opts.get('remote'):
6529 needsincoming, needsoutgoing = True, True
6529 needsincoming, needsoutgoing = True, True
6530 else:
6530 else:
6531 needsincoming, needsoutgoing = False, False
6531 needsincoming, needsoutgoing = False, False
6532 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6532 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6533 if i:
6533 if i:
6534 needsincoming = True
6534 needsincoming = True
6535 if o:
6535 if o:
6536 needsoutgoing = True
6536 needsoutgoing = True
6537 if not needsincoming and not needsoutgoing:
6537 if not needsincoming and not needsoutgoing:
6538 return
6538 return
6539
6539
6540 def getincoming():
6540 def getincoming():
6541 source, branches = hg.parseurl(ui.expandpath('default'))
6541 source, branches = hg.parseurl(ui.expandpath('default'))
6542 sbranch = branches[0]
6542 sbranch = branches[0]
6543 try:
6543 try:
6544 other = hg.peer(repo, {}, source)
6544 other = hg.peer(repo, {}, source)
6545 except error.RepoError:
6545 except error.RepoError:
6546 if opts.get('remote'):
6546 if opts.get('remote'):
6547 raise
6547 raise
6548 return source, sbranch, None, None, None
6548 return source, sbranch, None, None, None
6549 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6549 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6550 if revs:
6550 if revs:
6551 revs = [other.lookup(rev) for rev in revs]
6551 revs = [other.lookup(rev) for rev in revs]
6552 ui.debug('comparing with %s\n' % util.hidepassword(source))
6552 ui.debug('comparing with %s\n' % util.hidepassword(source))
6553 repo.ui.pushbuffer()
6553 repo.ui.pushbuffer()
6554 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6554 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6555 repo.ui.popbuffer()
6555 repo.ui.popbuffer()
6556 return source, sbranch, other, commoninc, commoninc[1]
6556 return source, sbranch, other, commoninc, commoninc[1]
6557
6557
6558 if needsincoming:
6558 if needsincoming:
6559 source, sbranch, sother, commoninc, incoming = getincoming()
6559 source, sbranch, sother, commoninc, incoming = getincoming()
6560 else:
6560 else:
6561 source = sbranch = sother = commoninc = incoming = None
6561 source = sbranch = sother = commoninc = incoming = None
6562
6562
6563 def getoutgoing():
6563 def getoutgoing():
6564 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6564 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6565 dbranch = branches[0]
6565 dbranch = branches[0]
6566 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6566 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6567 if source != dest:
6567 if source != dest:
6568 try:
6568 try:
6569 dother = hg.peer(repo, {}, dest)
6569 dother = hg.peer(repo, {}, dest)
6570 except error.RepoError:
6570 except error.RepoError:
6571 if opts.get('remote'):
6571 if opts.get('remote'):
6572 raise
6572 raise
6573 return dest, dbranch, None, None
6573 return dest, dbranch, None, None
6574 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6574 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6575 elif sother is None:
6575 elif sother is None:
6576 # there is no explicit destination peer, but source one is invalid
6576 # there is no explicit destination peer, but source one is invalid
6577 return dest, dbranch, None, None
6577 return dest, dbranch, None, None
6578 else:
6578 else:
6579 dother = sother
6579 dother = sother
6580 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6580 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6581 common = None
6581 common = None
6582 else:
6582 else:
6583 common = commoninc
6583 common = commoninc
6584 if revs:
6584 if revs:
6585 revs = [repo.lookup(rev) for rev in revs]
6585 revs = [repo.lookup(rev) for rev in revs]
6586 repo.ui.pushbuffer()
6586 repo.ui.pushbuffer()
6587 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6587 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6588 commoninc=common)
6588 commoninc=common)
6589 repo.ui.popbuffer()
6589 repo.ui.popbuffer()
6590 return dest, dbranch, dother, outgoing
6590 return dest, dbranch, dother, outgoing
6591
6591
6592 if needsoutgoing:
6592 if needsoutgoing:
6593 dest, dbranch, dother, outgoing = getoutgoing()
6593 dest, dbranch, dother, outgoing = getoutgoing()
6594 else:
6594 else:
6595 dest = dbranch = dother = outgoing = None
6595 dest = dbranch = dother = outgoing = None
6596
6596
6597 if opts.get('remote'):
6597 if opts.get('remote'):
6598 t = []
6598 t = []
6599 if incoming:
6599 if incoming:
6600 t.append(_('1 or more incoming'))
6600 t.append(_('1 or more incoming'))
6601 o = outgoing.missing
6601 o = outgoing.missing
6602 if o:
6602 if o:
6603 t.append(_('%d outgoing') % len(o))
6603 t.append(_('%d outgoing') % len(o))
6604 other = dother or sother
6604 other = dother or sother
6605 if 'bookmarks' in other.listkeys('namespaces'):
6605 if 'bookmarks' in other.listkeys('namespaces'):
6606 counts = bookmarks.summary(repo, other)
6606 counts = bookmarks.summary(repo, other)
6607 if counts[0] > 0:
6607 if counts[0] > 0:
6608 t.append(_('%d incoming bookmarks') % counts[0])
6608 t.append(_('%d incoming bookmarks') % counts[0])
6609 if counts[1] > 0:
6609 if counts[1] > 0:
6610 t.append(_('%d outgoing bookmarks') % counts[1])
6610 t.append(_('%d outgoing bookmarks') % counts[1])
6611
6611
6612 if t:
6612 if t:
6613 # i18n: column positioning for "hg summary"
6613 # i18n: column positioning for "hg summary"
6614 ui.write(_('remote: %s\n') % (', '.join(t)))
6614 ui.write(_('remote: %s\n') % (', '.join(t)))
6615 else:
6615 else:
6616 # i18n: column positioning for "hg summary"
6616 # i18n: column positioning for "hg summary"
6617 ui.status(_('remote: (synced)\n'))
6617 ui.status(_('remote: (synced)\n'))
6618
6618
6619 cmdutil.summaryremotehooks(ui, repo, opts,
6619 cmdutil.summaryremotehooks(ui, repo, opts,
6620 ((source, sbranch, sother, commoninc),
6620 ((source, sbranch, sother, commoninc),
6621 (dest, dbranch, dother, outgoing)))
6621 (dest, dbranch, dother, outgoing)))
6622
6622
6623 @command('tag',
6623 @command('tag',
6624 [('f', 'force', None, _('force tag')),
6624 [('f', 'force', None, _('force tag')),
6625 ('l', 'local', None, _('make the tag local')),
6625 ('l', 'local', None, _('make the tag local')),
6626 ('r', 'rev', '', _('revision to tag'), _('REV')),
6626 ('r', 'rev', '', _('revision to tag'), _('REV')),
6627 ('', 'remove', None, _('remove a tag')),
6627 ('', 'remove', None, _('remove a tag')),
6628 # -l/--local is already there, commitopts cannot be used
6628 # -l/--local is already there, commitopts cannot be used
6629 ('e', 'edit', None, _('invoke editor on commit messages')),
6629 ('e', 'edit', None, _('invoke editor on commit messages')),
6630 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6630 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6631 ] + commitopts2,
6631 ] + commitopts2,
6632 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6632 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6633 def tag(ui, repo, name1, *names, **opts):
6633 def tag(ui, repo, name1, *names, **opts):
6634 """add one or more tags for the current or given revision
6634 """add one or more tags for the current or given revision
6635
6635
6636 Name a particular revision using <name>.
6636 Name a particular revision using <name>.
6637
6637
6638 Tags are used to name particular revisions of the repository and are
6638 Tags are used to name particular revisions of the repository and are
6639 very useful to compare different revisions, to go back to significant
6639 very useful to compare different revisions, to go back to significant
6640 earlier versions or to mark branch points as releases, etc. Changing
6640 earlier versions or to mark branch points as releases, etc. Changing
6641 an existing tag is normally disallowed; use -f/--force to override.
6641 an existing tag is normally disallowed; use -f/--force to override.
6642
6642
6643 If no revision is given, the parent of the working directory is
6643 If no revision is given, the parent of the working directory is
6644 used.
6644 used.
6645
6645
6646 To facilitate version control, distribution, and merging of tags,
6646 To facilitate version control, distribution, and merging of tags,
6647 they are stored as a file named ".hgtags" which is managed similarly
6647 they are stored as a file named ".hgtags" which is managed similarly
6648 to other project files and can be hand-edited if necessary. This
6648 to other project files and can be hand-edited if necessary. This
6649 also means that tagging creates a new commit. The file
6649 also means that tagging creates a new commit. The file
6650 ".hg/localtags" is used for local tags (not shared among
6650 ".hg/localtags" is used for local tags (not shared among
6651 repositories).
6651 repositories).
6652
6652
6653 Tag commits are usually made at the head of a branch. If the parent
6653 Tag commits are usually made at the head of a branch. If the parent
6654 of the working directory is not a branch head, :hg:`tag` aborts; use
6654 of the working directory is not a branch head, :hg:`tag` aborts; use
6655 -f/--force to force the tag commit to be based on a non-head
6655 -f/--force to force the tag commit to be based on a non-head
6656 changeset.
6656 changeset.
6657
6657
6658 See :hg:`help dates` for a list of formats valid for -d/--date.
6658 See :hg:`help dates` for a list of formats valid for -d/--date.
6659
6659
6660 Since tag names have priority over branch names during revision
6660 Since tag names have priority over branch names during revision
6661 lookup, using an existing branch name as a tag name is discouraged.
6661 lookup, using an existing branch name as a tag name is discouraged.
6662
6662
6663 Returns 0 on success.
6663 Returns 0 on success.
6664 """
6664 """
6665 wlock = lock = None
6665 wlock = lock = None
6666 try:
6666 try:
6667 wlock = repo.wlock()
6667 wlock = repo.wlock()
6668 lock = repo.lock()
6668 lock = repo.lock()
6669 rev_ = "."
6669 rev_ = "."
6670 names = [t.strip() for t in (name1,) + names]
6670 names = [t.strip() for t in (name1,) + names]
6671 if len(names) != len(set(names)):
6671 if len(names) != len(set(names)):
6672 raise error.Abort(_('tag names must be unique'))
6672 raise error.Abort(_('tag names must be unique'))
6673 for n in names:
6673 for n in names:
6674 scmutil.checknewlabel(repo, n, 'tag')
6674 scmutil.checknewlabel(repo, n, 'tag')
6675 if not n:
6675 if not n:
6676 raise error.Abort(_('tag names cannot consist entirely of '
6676 raise error.Abort(_('tag names cannot consist entirely of '
6677 'whitespace'))
6677 'whitespace'))
6678 if opts.get('rev') and opts.get('remove'):
6678 if opts.get('rev') and opts.get('remove'):
6679 raise error.Abort(_("--rev and --remove are incompatible"))
6679 raise error.Abort(_("--rev and --remove are incompatible"))
6680 if opts.get('rev'):
6680 if opts.get('rev'):
6681 rev_ = opts['rev']
6681 rev_ = opts['rev']
6682 message = opts.get('message')
6682 message = opts.get('message')
6683 if opts.get('remove'):
6683 if opts.get('remove'):
6684 if opts.get('local'):
6684 if opts.get('local'):
6685 expectedtype = 'local'
6685 expectedtype = 'local'
6686 else:
6686 else:
6687 expectedtype = 'global'
6687 expectedtype = 'global'
6688
6688
6689 for n in names:
6689 for n in names:
6690 if not repo.tagtype(n):
6690 if not repo.tagtype(n):
6691 raise error.Abort(_("tag '%s' does not exist") % n)
6691 raise error.Abort(_("tag '%s' does not exist") % n)
6692 if repo.tagtype(n) != expectedtype:
6692 if repo.tagtype(n) != expectedtype:
6693 if expectedtype == 'global':
6693 if expectedtype == 'global':
6694 raise error.Abort(_("tag '%s' is not a global tag") % n)
6694 raise error.Abort(_("tag '%s' is not a global tag") % n)
6695 else:
6695 else:
6696 raise error.Abort(_("tag '%s' is not a local tag") % n)
6696 raise error.Abort(_("tag '%s' is not a local tag") % n)
6697 rev_ = 'null'
6697 rev_ = 'null'
6698 if not message:
6698 if not message:
6699 # we don't translate commit messages
6699 # we don't translate commit messages
6700 message = 'Removed tag %s' % ', '.join(names)
6700 message = 'Removed tag %s' % ', '.join(names)
6701 elif not opts.get('force'):
6701 elif not opts.get('force'):
6702 for n in names:
6702 for n in names:
6703 if n in repo.tags():
6703 if n in repo.tags():
6704 raise error.Abort(_("tag '%s' already exists "
6704 raise error.Abort(_("tag '%s' already exists "
6705 "(use -f to force)") % n)
6705 "(use -f to force)") % n)
6706 if not opts.get('local'):
6706 if not opts.get('local'):
6707 p1, p2 = repo.dirstate.parents()
6707 p1, p2 = repo.dirstate.parents()
6708 if p2 != nullid:
6708 if p2 != nullid:
6709 raise error.Abort(_('uncommitted merge'))
6709 raise error.Abort(_('uncommitted merge'))
6710 bheads = repo.branchheads()
6710 bheads = repo.branchheads()
6711 if not opts.get('force') and bheads and p1 not in bheads:
6711 if not opts.get('force') and bheads and p1 not in bheads:
6712 raise error.Abort(_('not at a branch head (use -f to force)'))
6712 raise error.Abort(_('not at a branch head (use -f to force)'))
6713 r = scmutil.revsingle(repo, rev_).node()
6713 r = scmutil.revsingle(repo, rev_).node()
6714
6714
6715 if not message:
6715 if not message:
6716 # we don't translate commit messages
6716 # we don't translate commit messages
6717 message = ('Added tag %s for changeset %s' %
6717 message = ('Added tag %s for changeset %s' %
6718 (', '.join(names), short(r)))
6718 (', '.join(names), short(r)))
6719
6719
6720 date = opts.get('date')
6720 date = opts.get('date')
6721 if date:
6721 if date:
6722 date = util.parsedate(date)
6722 date = util.parsedate(date)
6723
6723
6724 if opts.get('remove'):
6724 if opts.get('remove'):
6725 editform = 'tag.remove'
6725 editform = 'tag.remove'
6726 else:
6726 else:
6727 editform = 'tag.add'
6727 editform = 'tag.add'
6728 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6728 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6729
6729
6730 # don't allow tagging the null rev
6730 # don't allow tagging the null rev
6731 if (not opts.get('remove') and
6731 if (not opts.get('remove') and
6732 scmutil.revsingle(repo, rev_).rev() == nullrev):
6732 scmutil.revsingle(repo, rev_).rev() == nullrev):
6733 raise error.Abort(_("cannot tag null revision"))
6733 raise error.Abort(_("cannot tag null revision"))
6734
6734
6735 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6735 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6736 editor=editor)
6736 editor=editor)
6737 finally:
6737 finally:
6738 release(lock, wlock)
6738 release(lock, wlock)
6739
6739
6740 @command('tags', formatteropts, '')
6740 @command('tags', formatteropts, '')
6741 def tags(ui, repo, **opts):
6741 def tags(ui, repo, **opts):
6742 """list repository tags
6742 """list repository tags
6743
6743
6744 This lists both regular and local tags. When the -v/--verbose
6744 This lists both regular and local tags. When the -v/--verbose
6745 switch is used, a third column "local" is printed for local tags.
6745 switch is used, a third column "local" is printed for local tags.
6746 When the -q/--quiet switch is used, only the tag name is printed.
6746 When the -q/--quiet switch is used, only the tag name is printed.
6747
6747
6748 Returns 0 on success.
6748 Returns 0 on success.
6749 """
6749 """
6750
6750
6751 fm = ui.formatter('tags', opts)
6751 fm = ui.formatter('tags', opts)
6752 hexfunc = fm.hexfunc
6752 hexfunc = fm.hexfunc
6753 tagtype = ""
6753 tagtype = ""
6754
6754
6755 for t, n in reversed(repo.tagslist()):
6755 for t, n in reversed(repo.tagslist()):
6756 hn = hexfunc(n)
6756 hn = hexfunc(n)
6757 label = 'tags.normal'
6757 label = 'tags.normal'
6758 tagtype = ''
6758 tagtype = ''
6759 if repo.tagtype(t) == 'local':
6759 if repo.tagtype(t) == 'local':
6760 label = 'tags.local'
6760 label = 'tags.local'
6761 tagtype = 'local'
6761 tagtype = 'local'
6762
6762
6763 fm.startitem()
6763 fm.startitem()
6764 fm.write('tag', '%s', t, label=label)
6764 fm.write('tag', '%s', t, label=label)
6765 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6765 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6766 fm.condwrite(not ui.quiet, 'rev node', fmt,
6766 fm.condwrite(not ui.quiet, 'rev node', fmt,
6767 repo.changelog.rev(n), hn, label=label)
6767 repo.changelog.rev(n), hn, label=label)
6768 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6768 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6769 tagtype, label=label)
6769 tagtype, label=label)
6770 fm.plain('\n')
6770 fm.plain('\n')
6771 fm.end()
6771 fm.end()
6772
6772
6773 @command('tip',
6773 @command('tip',
6774 [('p', 'patch', None, _('show patch')),
6774 [('p', 'patch', None, _('show patch')),
6775 ('g', 'git', None, _('use git extended diff format')),
6775 ('g', 'git', None, _('use git extended diff format')),
6776 ] + templateopts,
6776 ] + templateopts,
6777 _('[-p] [-g]'))
6777 _('[-p] [-g]'))
6778 def tip(ui, repo, **opts):
6778 def tip(ui, repo, **opts):
6779 """show the tip revision (DEPRECATED)
6779 """show the tip revision (DEPRECATED)
6780
6780
6781 The tip revision (usually just called the tip) is the changeset
6781 The tip revision (usually just called the tip) is the changeset
6782 most recently added to the repository (and therefore the most
6782 most recently added to the repository (and therefore the most
6783 recently changed head).
6783 recently changed head).
6784
6784
6785 If you have just made a commit, that commit will be the tip. If
6785 If you have just made a commit, that commit will be the tip. If
6786 you have just pulled changes from another repository, the tip of
6786 you have just pulled changes from another repository, the tip of
6787 that repository becomes the current tip. The "tip" tag is special
6787 that repository becomes the current tip. The "tip" tag is special
6788 and cannot be renamed or assigned to a different changeset.
6788 and cannot be renamed or assigned to a different changeset.
6789
6789
6790 This command is deprecated, please use :hg:`heads` instead.
6790 This command is deprecated, please use :hg:`heads` instead.
6791
6791
6792 Returns 0 on success.
6792 Returns 0 on success.
6793 """
6793 """
6794 displayer = cmdutil.show_changeset(ui, repo, opts)
6794 displayer = cmdutil.show_changeset(ui, repo, opts)
6795 displayer.show(repo['tip'])
6795 displayer.show(repo['tip'])
6796 displayer.close()
6796 displayer.close()
6797
6797
6798 @command('unbundle',
6798 @command('unbundle',
6799 [('u', 'update', None,
6799 [('u', 'update', None,
6800 _('update to new branch head if changesets were unbundled'))],
6800 _('update to new branch head if changesets were unbundled'))],
6801 _('[-u] FILE...'))
6801 _('[-u] FILE...'))
6802 def unbundle(ui, repo, fname1, *fnames, **opts):
6802 def unbundle(ui, repo, fname1, *fnames, **opts):
6803 """apply one or more changegroup files
6803 """apply one or more changegroup files
6804
6804
6805 Apply one or more compressed changegroup files generated by the
6805 Apply one or more compressed changegroup files generated by the
6806 bundle command.
6806 bundle command.
6807
6807
6808 Returns 0 on success, 1 if an update has unresolved files.
6808 Returns 0 on success, 1 if an update has unresolved files.
6809 """
6809 """
6810 fnames = (fname1,) + fnames
6810 fnames = (fname1,) + fnames
6811
6811
6812 lock = repo.lock()
6812 lock = repo.lock()
6813 try:
6813 try:
6814 for fname in fnames:
6814 for fname in fnames:
6815 f = hg.openpath(ui, fname)
6815 f = hg.openpath(ui, fname)
6816 gen = exchange.readbundle(ui, f, fname)
6816 gen = exchange.readbundle(ui, f, fname)
6817 if isinstance(gen, bundle2.unbundle20):
6817 if isinstance(gen, bundle2.unbundle20):
6818 tr = repo.transaction('unbundle')
6818 tr = repo.transaction('unbundle')
6819 try:
6819 try:
6820 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6820 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6821 url='bundle:' + fname)
6821 url='bundle:' + fname)
6822 tr.close()
6822 tr.close()
6823 except error.BundleUnknownFeatureError as exc:
6823 except error.BundleUnknownFeatureError as exc:
6824 raise error.Abort(_('%s: unknown bundle feature, %s')
6824 raise error.Abort(_('%s: unknown bundle feature, %s')
6825 % (fname, exc),
6825 % (fname, exc),
6826 hint=_("see https://mercurial-scm.org/"
6826 hint=_("see https://mercurial-scm.org/"
6827 "wiki/BundleFeature for more "
6827 "wiki/BundleFeature for more "
6828 "information"))
6828 "information"))
6829 finally:
6829 finally:
6830 if tr:
6830 if tr:
6831 tr.release()
6831 tr.release()
6832 changes = [r.get('return', 0)
6832 changes = [r.get('return', 0)
6833 for r in op.records['changegroup']]
6833 for r in op.records['changegroup']]
6834 modheads = changegroup.combineresults(changes)
6834 modheads = changegroup.combineresults(changes)
6835 elif isinstance(gen, streamclone.streamcloneapplier):
6835 elif isinstance(gen, streamclone.streamcloneapplier):
6836 raise error.Abort(
6836 raise error.Abort(
6837 _('packed bundles cannot be applied with '
6837 _('packed bundles cannot be applied with '
6838 '"hg unbundle"'),
6838 '"hg unbundle"'),
6839 hint=_('use "hg debugapplystreamclonebundle"'))
6839 hint=_('use "hg debugapplystreamclonebundle"'))
6840 else:
6840 else:
6841 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6841 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6842 finally:
6842 finally:
6843 lock.release()
6843 lock.release()
6844
6844
6845 return postincoming(ui, repo, modheads, opts.get('update'), None)
6845 return postincoming(ui, repo, modheads, opts.get('update'), None)
6846
6846
6847 @command('^update|up|checkout|co',
6847 @command('^update|up|checkout|co',
6848 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6848 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6849 ('c', 'check', None,
6849 ('c', 'check', None,
6850 _('update across branches if no uncommitted changes')),
6850 _('update across branches if no uncommitted changes')),
6851 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6851 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6852 ('r', 'rev', '', _('revision'), _('REV'))
6852 ('r', 'rev', '', _('revision'), _('REV'))
6853 ] + mergetoolopts,
6853 ] + mergetoolopts,
6854 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6854 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6855 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6855 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6856 tool=None):
6856 tool=None):
6857 """update working directory (or switch revisions)
6857 """update working directory (or switch revisions)
6858
6858
6859 Update the repository's working directory to the specified
6859 Update the repository's working directory to the specified
6860 changeset. If no changeset is specified, update to the tip of the
6860 changeset. If no changeset is specified, update to the tip of the
6861 current named branch and move the active bookmark (see :hg:`help
6861 current named branch and move the active bookmark (see :hg:`help
6862 bookmarks`).
6862 bookmarks`).
6863
6863
6864 Update sets the working directory's parent revision to the specified
6864 Update sets the working directory's parent revision to the specified
6865 changeset (see :hg:`help parents`).
6865 changeset (see :hg:`help parents`).
6866
6866
6867 If the changeset is not a descendant or ancestor of the working
6867 If the changeset is not a descendant or ancestor of the working
6868 directory's parent, the update is aborted. With the -c/--check
6868 directory's parent, the update is aborted. With the -c/--check
6869 option, the working directory is checked for uncommitted changes; if
6869 option, the working directory is checked for uncommitted changes; if
6870 none are found, the working directory is updated to the specified
6870 none are found, the working directory is updated to the specified
6871 changeset.
6871 changeset.
6872
6872
6873 .. container:: verbose
6873 .. container:: verbose
6874
6874
6875 The following rules apply when the working directory contains
6875 The following rules apply when the working directory contains
6876 uncommitted changes:
6876 uncommitted changes:
6877
6877
6878 1. If neither -c/--check nor -C/--clean is specified, and if
6878 1. If neither -c/--check nor -C/--clean is specified, and if
6879 the requested changeset is an ancestor or descendant of
6879 the requested changeset is an ancestor or descendant of
6880 the working directory's parent, the uncommitted changes
6880 the working directory's parent, the uncommitted changes
6881 are merged into the requested changeset and the merged
6881 are merged into the requested changeset and the merged
6882 result is left uncommitted. If the requested changeset is
6882 result is left uncommitted. If the requested changeset is
6883 not an ancestor or descendant (that is, it is on another
6883 not an ancestor or descendant (that is, it is on another
6884 branch), the update is aborted and the uncommitted changes
6884 branch), the update is aborted and the uncommitted changes
6885 are preserved.
6885 are preserved.
6886
6886
6887 2. With the -c/--check option, the update is aborted and the
6887 2. With the -c/--check option, the update is aborted and the
6888 uncommitted changes are preserved.
6888 uncommitted changes are preserved.
6889
6889
6890 3. With the -C/--clean option, uncommitted changes are discarded and
6890 3. With the -C/--clean option, uncommitted changes are discarded and
6891 the working directory is updated to the requested changeset.
6891 the working directory is updated to the requested changeset.
6892
6892
6893 To cancel an uncommitted merge (and lose your changes), use
6893 To cancel an uncommitted merge (and lose your changes), use
6894 :hg:`update --clean .`.
6894 :hg:`update --clean .`.
6895
6895
6896 Use null as the changeset to remove the working directory (like
6896 Use null as the changeset to remove the working directory (like
6897 :hg:`clone -U`).
6897 :hg:`clone -U`).
6898
6898
6899 If you want to revert just one file to an older revision, use
6899 If you want to revert just one file to an older revision, use
6900 :hg:`revert [-r REV] NAME`.
6900 :hg:`revert [-r REV] NAME`.
6901
6901
6902 See :hg:`help dates` for a list of formats valid for -d/--date.
6902 See :hg:`help dates` for a list of formats valid for -d/--date.
6903
6903
6904 Returns 0 on success, 1 if there are unresolved files.
6904 Returns 0 on success, 1 if there are unresolved files.
6905 """
6905 """
6906 movemarkfrom = None
6906 movemarkfrom = None
6907 if rev and node:
6907 if rev and node:
6908 raise error.Abort(_("please specify just one revision"))
6908 raise error.Abort(_("please specify just one revision"))
6909
6909
6910 if rev is None or rev == '':
6910 if rev is None or rev == '':
6911 rev = node
6911 rev = node
6912
6912
6913 wlock = repo.wlock()
6913 wlock = repo.wlock()
6914 try:
6914 try:
6915 cmdutil.clearunfinished(repo)
6915 cmdutil.clearunfinished(repo)
6916
6916
6917 if date:
6917 if date:
6918 if rev is not None:
6918 if rev is not None:
6919 raise error.Abort(_("you can't specify a revision and a date"))
6919 raise error.Abort(_("you can't specify a revision and a date"))
6920 rev = cmdutil.finddate(ui, repo, date)
6920 rev = cmdutil.finddate(ui, repo, date)
6921
6921
6922 # if we defined a bookmark, we have to remember the original name
6922 # if we defined a bookmark, we have to remember the original name
6923 brev = rev
6923 brev = rev
6924 rev = scmutil.revsingle(repo, rev, rev).rev()
6924 rev = scmutil.revsingle(repo, rev, rev).rev()
6925
6925
6926 if check and clean:
6926 if check and clean:
6927 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6927 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6928 )
6928 )
6929
6929
6930 if check:
6930 if check:
6931 cmdutil.bailifchanged(repo, merge=False)
6931 cmdutil.bailifchanged(repo, merge=False)
6932 if rev is None:
6932 if rev is None:
6933 updata = destutil.destupdate(repo, clean=clean, check=check)
6933 updata = destutil.destupdate(repo, clean=clean, check=check)
6934 rev, movemarkfrom, brev = updata
6934 rev, movemarkfrom, brev = updata
6935
6935
6936 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6936 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6937
6937
6938 if clean:
6938 if clean:
6939 ret = hg.clean(repo, rev)
6939 ret = hg.clean(repo, rev)
6940 else:
6940 else:
6941 ret = hg.update(repo, rev)
6941 ret = hg.update(repo, rev)
6942
6942
6943 if not ret and movemarkfrom:
6943 if not ret and movemarkfrom:
6944 if movemarkfrom == repo['.'].node():
6944 if movemarkfrom == repo['.'].node():
6945 pass # no-op update
6945 pass # no-op update
6946 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6946 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6947 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6947 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6948 else:
6948 else:
6949 # this can happen with a non-linear update
6949 # this can happen with a non-linear update
6950 ui.status(_("(leaving bookmark %s)\n") %
6950 ui.status(_("(leaving bookmark %s)\n") %
6951 repo._activebookmark)
6951 repo._activebookmark)
6952 bookmarks.deactivate(repo)
6952 bookmarks.deactivate(repo)
6953 elif brev in repo._bookmarks:
6953 elif brev in repo._bookmarks:
6954 bookmarks.activate(repo, brev)
6954 bookmarks.activate(repo, brev)
6955 ui.status(_("(activating bookmark %s)\n") % brev)
6955 ui.status(_("(activating bookmark %s)\n") % brev)
6956 elif brev:
6956 elif brev:
6957 if repo._activebookmark:
6957 if repo._activebookmark:
6958 ui.status(_("(leaving bookmark %s)\n") %
6958 ui.status(_("(leaving bookmark %s)\n") %
6959 repo._activebookmark)
6959 repo._activebookmark)
6960 bookmarks.deactivate(repo)
6960 bookmarks.deactivate(repo)
6961 finally:
6961 finally:
6962 wlock.release()
6962 wlock.release()
6963
6963
6964 return ret
6964 return ret
6965
6965
6966 @command('verify', [])
6966 @command('verify', [])
6967 def verify(ui, repo):
6967 def verify(ui, repo):
6968 """verify the integrity of the repository
6968 """verify the integrity of the repository
6969
6969
6970 Verify the integrity of the current repository.
6970 Verify the integrity of the current repository.
6971
6971
6972 This will perform an extensive check of the repository's
6972 This will perform an extensive check of the repository's
6973 integrity, validating the hashes and checksums of each entry in
6973 integrity, validating the hashes and checksums of each entry in
6974 the changelog, manifest, and tracked files, as well as the
6974 the changelog, manifest, and tracked files, as well as the
6975 integrity of their crosslinks and indices.
6975 integrity of their crosslinks and indices.
6976
6976
6977 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6977 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6978 for more information about recovery from corruption of the
6978 for more information about recovery from corruption of the
6979 repository.
6979 repository.
6980
6980
6981 Returns 0 on success, 1 if errors are encountered.
6981 Returns 0 on success, 1 if errors are encountered.
6982 """
6982 """
6983 return hg.verify(repo)
6983 return hg.verify(repo)
6984
6984
6985 @command('version', [], norepo=True)
6985 @command('version', [], norepo=True)
6986 def version_(ui):
6986 def version_(ui):
6987 """output version and copyright information"""
6987 """output version and copyright information"""
6988 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6988 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6989 % util.version())
6989 % util.version())
6990 ui.status(_(
6990 ui.status(_(
6991 "(see https://mercurial-scm.org for more information)\n"
6991 "(see https://mercurial-scm.org for more information)\n"
6992 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6992 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6993 "This is free software; see the source for copying conditions. "
6993 "This is free software; see the source for copying conditions. "
6994 "There is NO\nwarranty; "
6994 "There is NO\nwarranty; "
6995 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6995 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6996 ))
6996 ))
6997
6997
6998 ui.note(_("\nEnabled extensions:\n\n"))
6998 ui.note(_("\nEnabled extensions:\n\n"))
6999 if ui.verbose:
6999 if ui.verbose:
7000 # format names and versions into columns
7000 # format names and versions into columns
7001 names = []
7001 names = []
7002 vers = []
7002 vers = []
7003 for name, module in extensions.extensions():
7003 for name, module in extensions.extensions():
7004 names.append(name)
7004 names.append(name)
7005 vers.append(extensions.moduleversion(module))
7005 vers.append(extensions.moduleversion(module))
7006 if names:
7006 if names:
7007 maxnamelen = max(len(n) for n in names)
7007 maxnamelen = max(len(n) for n in names)
7008 for i, name in enumerate(names):
7008 for i, name in enumerate(names):
7009 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
7009 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now