##// END OF EJS Templates
debugsetparents: remove redundant invocations of begin/endparentchange...
liscju -
r28654:5474dc73 default
parent child Browse files
Show More
@@ -1,7206 +1,7204 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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import difflib
10 import difflib
11 import errno
11 import errno
12 import operator
12 import operator
13 import os
13 import os
14 import random
14 import random
15 import re
15 import re
16 import shlex
16 import shlex
17 import socket
17 import socket
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import time
20 import time
21
21
22 from .i18n import _
22 from .i18n import _
23 from .node import (
23 from .node import (
24 bin,
24 bin,
25 hex,
25 hex,
26 nullhex,
26 nullhex,
27 nullid,
27 nullid,
28 nullrev,
28 nullrev,
29 short,
29 short,
30 )
30 )
31 from . import (
31 from . import (
32 archival,
32 archival,
33 bookmarks,
33 bookmarks,
34 bundle2,
34 bundle2,
35 changegroup,
35 changegroup,
36 cmdutil,
36 cmdutil,
37 commandserver,
37 commandserver,
38 context,
38 context,
39 copies,
39 copies,
40 dagparser,
40 dagparser,
41 dagutil,
41 dagutil,
42 destutil,
42 destutil,
43 discovery,
43 discovery,
44 encoding,
44 encoding,
45 error,
45 error,
46 exchange,
46 exchange,
47 extensions,
47 extensions,
48 fileset,
48 fileset,
49 graphmod,
49 graphmod,
50 hbisect,
50 hbisect,
51 help,
51 help,
52 hg,
52 hg,
53 hgweb,
53 hgweb,
54 localrepo,
54 localrepo,
55 lock as lockmod,
55 lock as lockmod,
56 merge as mergemod,
56 merge as mergemod,
57 minirst,
57 minirst,
58 obsolete,
58 obsolete,
59 patch,
59 patch,
60 phases,
60 phases,
61 pvec,
61 pvec,
62 repair,
62 repair,
63 revlog,
63 revlog,
64 revset,
64 revset,
65 scmutil,
65 scmutil,
66 setdiscovery,
66 setdiscovery,
67 simplemerge,
67 simplemerge,
68 sshserver,
68 sshserver,
69 streamclone,
69 streamclone,
70 templatekw,
70 templatekw,
71 templater,
71 templater,
72 treediscovery,
72 treediscovery,
73 ui as uimod,
73 ui as uimod,
74 util,
74 util,
75 )
75 )
76
76
77 release = lockmod.release
77 release = lockmod.release
78
78
79 table = {}
79 table = {}
80
80
81 command = cmdutil.command(table)
81 command = cmdutil.command(table)
82
82
83 # label constants
83 # label constants
84 # until 3.5, bookmarks.current was the advertised name, not
84 # until 3.5, bookmarks.current was the advertised name, not
85 # bookmarks.active, so we must use both to avoid breaking old
85 # bookmarks.active, so we must use both to avoid breaking old
86 # custom styles
86 # custom styles
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
87 activebookmarklabel = 'bookmarks.active bookmarks.current'
88
88
89 # common command options
89 # common command options
90
90
91 globalopts = [
91 globalopts = [
92 ('R', 'repository', '',
92 ('R', 'repository', '',
93 _('repository root directory or name of overlay bundle file'),
93 _('repository root directory or name of overlay bundle file'),
94 _('REPO')),
94 _('REPO')),
95 ('', 'cwd', '',
95 ('', 'cwd', '',
96 _('change working directory'), _('DIR')),
96 _('change working directory'), _('DIR')),
97 ('y', 'noninteractive', None,
97 ('y', 'noninteractive', None,
98 _('do not prompt, automatically pick the first choice for all prompts')),
98 _('do not prompt, automatically pick the first choice for all prompts')),
99 ('q', 'quiet', None, _('suppress output')),
99 ('q', 'quiet', None, _('suppress output')),
100 ('v', 'verbose', None, _('enable additional output')),
100 ('v', 'verbose', None, _('enable additional output')),
101 ('', 'config', [],
101 ('', 'config', [],
102 _('set/override config option (use \'section.name=value\')'),
102 _('set/override config option (use \'section.name=value\')'),
103 _('CONFIG')),
103 _('CONFIG')),
104 ('', 'debug', None, _('enable debugging output')),
104 ('', 'debug', None, _('enable debugging output')),
105 ('', 'debugger', None, _('start debugger')),
105 ('', 'debugger', None, _('start debugger')),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
106 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
107 _('ENCODE')),
107 _('ENCODE')),
108 ('', 'encodingmode', encoding.encodingmode,
108 ('', 'encodingmode', encoding.encodingmode,
109 _('set the charset encoding mode'), _('MODE')),
109 _('set the charset encoding mode'), _('MODE')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
110 ('', 'traceback', None, _('always print a traceback on exception')),
111 ('', 'time', None, _('time how long the command takes')),
111 ('', 'time', None, _('time how long the command takes')),
112 ('', 'profile', None, _('print command execution profile')),
112 ('', 'profile', None, _('print command execution profile')),
113 ('', 'version', None, _('output version information and exit')),
113 ('', 'version', None, _('output version information and exit')),
114 ('h', 'help', None, _('display help and exit')),
114 ('h', 'help', None, _('display help and exit')),
115 ('', 'hidden', False, _('consider hidden changesets')),
115 ('', 'hidden', False, _('consider hidden changesets')),
116 ]
116 ]
117
117
118 dryrunopts = [('n', 'dry-run', None,
118 dryrunopts = [('n', 'dry-run', None,
119 _('do not perform actions, just print output'))]
119 _('do not perform actions, just print output'))]
120
120
121 remoteopts = [
121 remoteopts = [
122 ('e', 'ssh', '',
122 ('e', 'ssh', '',
123 _('specify ssh command to use'), _('CMD')),
123 _('specify ssh command to use'), _('CMD')),
124 ('', 'remotecmd', '',
124 ('', 'remotecmd', '',
125 _('specify hg command to run on the remote side'), _('CMD')),
125 _('specify hg command to run on the remote side'), _('CMD')),
126 ('', 'insecure', None,
126 ('', 'insecure', None,
127 _('do not verify server certificate (ignoring web.cacerts config)')),
127 _('do not verify server certificate (ignoring web.cacerts config)')),
128 ]
128 ]
129
129
130 walkopts = [
130 walkopts = [
131 ('I', 'include', [],
131 ('I', 'include', [],
132 _('include names matching the given patterns'), _('PATTERN')),
132 _('include names matching the given patterns'), _('PATTERN')),
133 ('X', 'exclude', [],
133 ('X', 'exclude', [],
134 _('exclude names matching the given patterns'), _('PATTERN')),
134 _('exclude names matching the given patterns'), _('PATTERN')),
135 ]
135 ]
136
136
137 commitopts = [
137 commitopts = [
138 ('m', 'message', '',
138 ('m', 'message', '',
139 _('use text as commit message'), _('TEXT')),
139 _('use text as commit message'), _('TEXT')),
140 ('l', 'logfile', '',
140 ('l', 'logfile', '',
141 _('read commit message from file'), _('FILE')),
141 _('read commit message from file'), _('FILE')),
142 ]
142 ]
143
143
144 commitopts2 = [
144 commitopts2 = [
145 ('d', 'date', '',
145 ('d', 'date', '',
146 _('record the specified date as commit date'), _('DATE')),
146 _('record the specified date as commit date'), _('DATE')),
147 ('u', 'user', '',
147 ('u', 'user', '',
148 _('record the specified user as committer'), _('USER')),
148 _('record the specified user as committer'), _('USER')),
149 ]
149 ]
150
150
151 # hidden for now
151 # hidden for now
152 formatteropts = [
152 formatteropts = [
153 ('T', 'template', '',
153 ('T', 'template', '',
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
154 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
155 ]
155 ]
156
156
157 templateopts = [
157 templateopts = [
158 ('', 'style', '',
158 ('', 'style', '',
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
159 _('display using template map file (DEPRECATED)'), _('STYLE')),
160 ('T', 'template', '',
160 ('T', 'template', '',
161 _('display with template'), _('TEMPLATE')),
161 _('display with template'), _('TEMPLATE')),
162 ]
162 ]
163
163
164 logopts = [
164 logopts = [
165 ('p', 'patch', None, _('show patch')),
165 ('p', 'patch', None, _('show patch')),
166 ('g', 'git', None, _('use git extended diff format')),
166 ('g', 'git', None, _('use git extended diff format')),
167 ('l', 'limit', '',
167 ('l', 'limit', '',
168 _('limit number of changes displayed'), _('NUM')),
168 _('limit number of changes displayed'), _('NUM')),
169 ('M', 'no-merges', None, _('do not show merges')),
169 ('M', 'no-merges', None, _('do not show merges')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
170 ('', 'stat', None, _('output diffstat-style summary of changes')),
171 ('G', 'graph', None, _("show the revision DAG")),
171 ('G', 'graph', None, _("show the revision DAG")),
172 ] + templateopts
172 ] + templateopts
173
173
174 diffopts = [
174 diffopts = [
175 ('a', 'text', None, _('treat all files as text')),
175 ('a', 'text', None, _('treat all files as text')),
176 ('g', 'git', None, _('use git extended diff format')),
176 ('g', 'git', None, _('use git extended diff format')),
177 ('', 'nodates', None, _('omit dates from diff headers'))
177 ('', 'nodates', None, _('omit dates from diff headers'))
178 ]
178 ]
179
179
180 diffwsopts = [
180 diffwsopts = [
181 ('w', 'ignore-all-space', None,
181 ('w', 'ignore-all-space', None,
182 _('ignore white space when comparing lines')),
182 _('ignore white space when comparing lines')),
183 ('b', 'ignore-space-change', None,
183 ('b', 'ignore-space-change', None,
184 _('ignore changes in the amount of white space')),
184 _('ignore changes in the amount of white space')),
185 ('B', 'ignore-blank-lines', None,
185 ('B', 'ignore-blank-lines', None,
186 _('ignore changes whose lines are all blank')),
186 _('ignore changes whose lines are all blank')),
187 ]
187 ]
188
188
189 diffopts2 = [
189 diffopts2 = [
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
190 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
191 ('p', 'show-function', None, _('show which function each change is in')),
191 ('p', 'show-function', None, _('show which function each change is in')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
192 ('', 'reverse', None, _('produce a diff that undoes the changes')),
193 ] + diffwsopts + [
193 ] + diffwsopts + [
194 ('U', 'unified', '',
194 ('U', 'unified', '',
195 _('number of lines of context to show'), _('NUM')),
195 _('number of lines of context to show'), _('NUM')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
196 ('', 'stat', None, _('output diffstat-style summary of changes')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
197 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
198 ]
198 ]
199
199
200 mergetoolopts = [
200 mergetoolopts = [
201 ('t', 'tool', '', _('specify merge tool')),
201 ('t', 'tool', '', _('specify merge tool')),
202 ]
202 ]
203
203
204 similarityopts = [
204 similarityopts = [
205 ('s', 'similarity', '',
205 ('s', 'similarity', '',
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
206 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
207 ]
207 ]
208
208
209 subrepoopts = [
209 subrepoopts = [
210 ('S', 'subrepos', None,
210 ('S', 'subrepos', None,
211 _('recurse into subrepositories'))
211 _('recurse into subrepositories'))
212 ]
212 ]
213
213
214 debugrevlogopts = [
214 debugrevlogopts = [
215 ('c', 'changelog', False, _('open changelog')),
215 ('c', 'changelog', False, _('open changelog')),
216 ('m', 'manifest', False, _('open manifest')),
216 ('m', 'manifest', False, _('open manifest')),
217 ('', 'dir', False, _('open directory manifest')),
217 ('', 'dir', False, _('open directory manifest')),
218 ]
218 ]
219
219
220 # Commands start here, listed alphabetically
220 # Commands start here, listed alphabetically
221
221
222 @command('^add',
222 @command('^add',
223 walkopts + subrepoopts + dryrunopts,
223 walkopts + subrepoopts + dryrunopts,
224 _('[OPTION]... [FILE]...'),
224 _('[OPTION]... [FILE]...'),
225 inferrepo=True)
225 inferrepo=True)
226 def add(ui, repo, *pats, **opts):
226 def add(ui, repo, *pats, **opts):
227 """add the specified files on the next commit
227 """add the specified files on the next commit
228
228
229 Schedule files to be version controlled and added to the
229 Schedule files to be version controlled and added to the
230 repository.
230 repository.
231
231
232 The files will be added to the repository at the next commit. To
232 The files will be added to the repository at the next commit. To
233 undo an add before that, see :hg:`forget`.
233 undo an add before that, see :hg:`forget`.
234
234
235 If no names are given, add all files to the repository (except
235 If no names are given, add all files to the repository (except
236 files matching ``.hgignore``).
236 files matching ``.hgignore``).
237
237
238 .. container:: verbose
238 .. container:: verbose
239
239
240 Examples:
240 Examples:
241
241
242 - New (unknown) files are added
242 - New (unknown) files are added
243 automatically by :hg:`add`::
243 automatically by :hg:`add`::
244
244
245 $ ls
245 $ ls
246 foo.c
246 foo.c
247 $ hg status
247 $ hg status
248 ? foo.c
248 ? foo.c
249 $ hg add
249 $ hg add
250 adding foo.c
250 adding foo.c
251 $ hg status
251 $ hg status
252 A foo.c
252 A foo.c
253
253
254 - Specific files to be added can be specified::
254 - Specific files to be added can be specified::
255
255
256 $ ls
256 $ ls
257 bar.c foo.c
257 bar.c foo.c
258 $ hg status
258 $ hg status
259 ? bar.c
259 ? bar.c
260 ? foo.c
260 ? foo.c
261 $ hg add bar.c
261 $ hg add bar.c
262 $ hg status
262 $ hg status
263 A bar.c
263 A bar.c
264 ? foo.c
264 ? foo.c
265
265
266 Returns 0 if all files are successfully added.
266 Returns 0 if all files are successfully added.
267 """
267 """
268
268
269 m = scmutil.match(repo[None], pats, opts)
269 m = scmutil.match(repo[None], pats, opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
270 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
271 return rejected and 1 or 0
271 return rejected and 1 or 0
272
272
273 @command('addremove',
273 @command('addremove',
274 similarityopts + subrepoopts + walkopts + dryrunopts,
274 similarityopts + subrepoopts + walkopts + dryrunopts,
275 _('[OPTION]... [FILE]...'),
275 _('[OPTION]... [FILE]...'),
276 inferrepo=True)
276 inferrepo=True)
277 def addremove(ui, repo, *pats, **opts):
277 def addremove(ui, repo, *pats, **opts):
278 """add all new files, delete all missing files
278 """add all new files, delete all missing files
279
279
280 Add all new files and remove all missing files from the
280 Add all new files and remove all missing files from the
281 repository.
281 repository.
282
282
283 Unless names are given, new files are ignored if they match any of
283 Unless names are given, new files are ignored if they match any of
284 the patterns in ``.hgignore``. As with add, these changes take
284 the patterns in ``.hgignore``. As with add, these changes take
285 effect at the next commit.
285 effect at the next commit.
286
286
287 Use the -s/--similarity option to detect renamed files. This
287 Use the -s/--similarity option to detect renamed files. This
288 option takes a percentage between 0 (disabled) and 100 (files must
288 option takes a percentage between 0 (disabled) and 100 (files must
289 be identical) as its parameter. With a parameter greater than 0,
289 be identical) as its parameter. With a parameter greater than 0,
290 this compares every removed file with every added file and records
290 this compares every removed file with every added file and records
291 those similar enough as renames. Detecting renamed files this way
291 those similar enough as renames. Detecting renamed files this way
292 can be expensive. After using this option, :hg:`status -C` can be
292 can be expensive. After using this option, :hg:`status -C` can be
293 used to check which files were identified as moved or renamed. If
293 used to check which files were identified as moved or renamed. If
294 not specified, -s/--similarity defaults to 100 and only renames of
294 not specified, -s/--similarity defaults to 100 and only renames of
295 identical files are detected.
295 identical files are detected.
296
296
297 .. container:: verbose
297 .. container:: verbose
298
298
299 Examples:
299 Examples:
300
300
301 - A number of files (bar.c and foo.c) are new,
301 - A number of files (bar.c and foo.c) are new,
302 while foobar.c has been removed (without using :hg:`remove`)
302 while foobar.c has been removed (without using :hg:`remove`)
303 from the repository::
303 from the repository::
304
304
305 $ ls
305 $ ls
306 bar.c foo.c
306 bar.c foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? bar.c
309 ? bar.c
310 ? foo.c
310 ? foo.c
311 $ hg addremove
311 $ hg addremove
312 adding bar.c
312 adding bar.c
313 adding foo.c
313 adding foo.c
314 removing foobar.c
314 removing foobar.c
315 $ hg status
315 $ hg status
316 A bar.c
316 A bar.c
317 A foo.c
317 A foo.c
318 R foobar.c
318 R foobar.c
319
319
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
320 - A file foobar.c was moved to foo.c without using :hg:`rename`.
321 Afterwards, it was edited slightly::
321 Afterwards, it was edited slightly::
322
322
323 $ ls
323 $ ls
324 foo.c
324 foo.c
325 $ hg status
325 $ hg status
326 ! foobar.c
326 ! foobar.c
327 ? foo.c
327 ? foo.c
328 $ hg addremove --similarity 90
328 $ hg addremove --similarity 90
329 removing foobar.c
329 removing foobar.c
330 adding foo.c
330 adding foo.c
331 recording removal of foobar.c as rename to foo.c (94% similar)
331 recording removal of foobar.c as rename to foo.c (94% similar)
332 $ hg status -C
332 $ hg status -C
333 A foo.c
333 A foo.c
334 foobar.c
334 foobar.c
335 R foobar.c
335 R foobar.c
336
336
337 Returns 0 if all files are successfully added.
337 Returns 0 if all files are successfully added.
338 """
338 """
339 try:
339 try:
340 sim = float(opts.get('similarity') or 100)
340 sim = float(opts.get('similarity') or 100)
341 except ValueError:
341 except ValueError:
342 raise error.Abort(_('similarity must be a number'))
342 raise error.Abort(_('similarity must be a number'))
343 if sim < 0 or sim > 100:
343 if sim < 0 or sim > 100:
344 raise error.Abort(_('similarity must be between 0 and 100'))
344 raise error.Abort(_('similarity must be between 0 and 100'))
345 matcher = scmutil.match(repo[None], pats, opts)
345 matcher = scmutil.match(repo[None], pats, opts)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
346 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
347
347
348 @command('^annotate|blame',
348 @command('^annotate|blame',
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
349 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
350 ('', 'follow', None,
350 ('', 'follow', None,
351 _('follow copies/renames and list the filename (DEPRECATED)')),
351 _('follow copies/renames and list the filename (DEPRECATED)')),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
352 ('', 'no-follow', None, _("don't follow copies and renames")),
353 ('a', 'text', None, _('treat all files as text')),
353 ('a', 'text', None, _('treat all files as text')),
354 ('u', 'user', None, _('list the author (long with -v)')),
354 ('u', 'user', None, _('list the author (long with -v)')),
355 ('f', 'file', None, _('list the filename')),
355 ('f', 'file', None, _('list the filename')),
356 ('d', 'date', None, _('list the date (short with -q)')),
356 ('d', 'date', None, _('list the date (short with -q)')),
357 ('n', 'number', None, _('list the revision number (default)')),
357 ('n', 'number', None, _('list the revision number (default)')),
358 ('c', 'changeset', None, _('list the changeset')),
358 ('c', 'changeset', None, _('list the changeset')),
359 ('l', 'line-number', None, _('show line number at the first appearance'))
359 ('l', 'line-number', None, _('show line number at the first appearance'))
360 ] + diffwsopts + walkopts + formatteropts,
360 ] + diffwsopts + walkopts + formatteropts,
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
361 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
362 inferrepo=True)
362 inferrepo=True)
363 def annotate(ui, repo, *pats, **opts):
363 def annotate(ui, repo, *pats, **opts):
364 """show changeset information by line for each file
364 """show changeset information by line for each file
365
365
366 List changes in files, showing the revision id responsible for
366 List changes in files, showing the revision id responsible for
367 each line.
367 each line.
368
368
369 This command is useful for discovering when a change was made and
369 This command is useful for discovering when a change was made and
370 by whom.
370 by whom.
371
371
372 If you include --file, --user, or --date, the revision number is
372 If you include --file, --user, or --date, the revision number is
373 suppressed unless you also include --number.
373 suppressed unless you also include --number.
374
374
375 Without the -a/--text option, annotate will avoid processing files
375 Without the -a/--text option, annotate will avoid processing files
376 it detects as binary. With -a, annotate will annotate the file
376 it detects as binary. With -a, annotate will annotate the file
377 anyway, although the results will probably be neither useful
377 anyway, although the results will probably be neither useful
378 nor desirable.
378 nor desirable.
379
379
380 Returns 0 on success.
380 Returns 0 on success.
381 """
381 """
382 if not pats:
382 if not pats:
383 raise error.Abort(_('at least one filename or pattern is required'))
383 raise error.Abort(_('at least one filename or pattern is required'))
384
384
385 if opts.get('follow'):
385 if opts.get('follow'):
386 # --follow is deprecated and now just an alias for -f/--file
386 # --follow is deprecated and now just an alias for -f/--file
387 # to mimic the behavior of Mercurial before version 1.5
387 # to mimic the behavior of Mercurial before version 1.5
388 opts['file'] = True
388 opts['file'] = True
389
389
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
390 ctx = scmutil.revsingle(repo, opts.get('rev'))
391
391
392 fm = ui.formatter('annotate', opts)
392 fm = ui.formatter('annotate', opts)
393 if ui.quiet:
393 if ui.quiet:
394 datefunc = util.shortdate
394 datefunc = util.shortdate
395 else:
395 else:
396 datefunc = util.datestr
396 datefunc = util.datestr
397 if ctx.rev() is None:
397 if ctx.rev() is None:
398 def hexfn(node):
398 def hexfn(node):
399 if node is None:
399 if node is None:
400 return None
400 return None
401 else:
401 else:
402 return fm.hexfunc(node)
402 return fm.hexfunc(node)
403 if opts.get('changeset'):
403 if opts.get('changeset'):
404 # omit "+" suffix which is appended to node hex
404 # omit "+" suffix which is appended to node hex
405 def formatrev(rev):
405 def formatrev(rev):
406 if rev is None:
406 if rev is None:
407 return '%d' % ctx.p1().rev()
407 return '%d' % ctx.p1().rev()
408 else:
408 else:
409 return '%d' % rev
409 return '%d' % rev
410 else:
410 else:
411 def formatrev(rev):
411 def formatrev(rev):
412 if rev is None:
412 if rev is None:
413 return '%d+' % ctx.p1().rev()
413 return '%d+' % ctx.p1().rev()
414 else:
414 else:
415 return '%d ' % rev
415 return '%d ' % rev
416 def formathex(hex):
416 def formathex(hex):
417 if hex is None:
417 if hex is None:
418 return '%s+' % fm.hexfunc(ctx.p1().node())
418 return '%s+' % fm.hexfunc(ctx.p1().node())
419 else:
419 else:
420 return '%s ' % hex
420 return '%s ' % hex
421 else:
421 else:
422 hexfn = fm.hexfunc
422 hexfn = fm.hexfunc
423 formatrev = formathex = str
423 formatrev = formathex = str
424
424
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
425 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
426 ('number', ' ', lambda x: x[0].rev(), formatrev),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
427 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
428 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
429 ('file', ' ', lambda x: x[0].path(), str),
429 ('file', ' ', lambda x: x[0].path(), str),
430 ('line_number', ':', lambda x: x[1], str),
430 ('line_number', ':', lambda x: x[1], str),
431 ]
431 ]
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
432 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
433
433
434 if (not opts.get('user') and not opts.get('changeset')
434 if (not opts.get('user') and not opts.get('changeset')
435 and not opts.get('date') and not opts.get('file')):
435 and not opts.get('date') and not opts.get('file')):
436 opts['number'] = True
436 opts['number'] = True
437
437
438 linenumber = opts.get('line_number') is not None
438 linenumber = opts.get('line_number') is not None
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
439 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
440 raise error.Abort(_('at least one of -n/-c is required for -l'))
441
441
442 if fm:
442 if fm:
443 def makefunc(get, fmt):
443 def makefunc(get, fmt):
444 return get
444 return get
445 else:
445 else:
446 def makefunc(get, fmt):
446 def makefunc(get, fmt):
447 return lambda x: fmt(get(x))
447 return lambda x: fmt(get(x))
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
448 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
449 if opts.get(op)]
449 if opts.get(op)]
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
450 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
451 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
452 if opts.get(op))
452 if opts.get(op))
453
453
454 def bad(x, y):
454 def bad(x, y):
455 raise error.Abort("%s: %s" % (x, y))
455 raise error.Abort("%s: %s" % (x, y))
456
456
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
457 m = scmutil.match(ctx, pats, opts, badfn=bad)
458
458
459 follow = not opts.get('no_follow')
459 follow = not opts.get('no_follow')
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
460 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
461 whitespace=True)
461 whitespace=True)
462 for abs in ctx.walk(m):
462 for abs in ctx.walk(m):
463 fctx = ctx[abs]
463 fctx = ctx[abs]
464 if not opts.get('text') and util.binary(fctx.data()):
464 if not opts.get('text') and util.binary(fctx.data()):
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
465 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
466 continue
466 continue
467
467
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
468 lines = fctx.annotate(follow=follow, linenumber=linenumber,
469 diffopts=diffopts)
469 diffopts=diffopts)
470 formats = []
470 formats = []
471 pieces = []
471 pieces = []
472
472
473 for f, sep in funcmap:
473 for f, sep in funcmap:
474 l = [f(n) for n, dummy in lines]
474 l = [f(n) for n, dummy in lines]
475 if l:
475 if l:
476 if fm:
476 if fm:
477 formats.append(['%s' for x in l])
477 formats.append(['%s' for x in l])
478 else:
478 else:
479 sizes = [encoding.colwidth(x) for x in l]
479 sizes = [encoding.colwidth(x) for x in l]
480 ml = max(sizes)
480 ml = max(sizes)
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
481 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
482 pieces.append(l)
482 pieces.append(l)
483
483
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
484 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
485 fm.startitem()
485 fm.startitem()
486 fm.write(fields, "".join(f), *p)
486 fm.write(fields, "".join(f), *p)
487 fm.write('line', ": %s", l[1])
487 fm.write('line', ": %s", l[1])
488
488
489 if lines and not lines[-1][1].endswith('\n'):
489 if lines and not lines[-1][1].endswith('\n'):
490 fm.plain('\n')
490 fm.plain('\n')
491
491
492 fm.end()
492 fm.end()
493
493
494 @command('archive',
494 @command('archive',
495 [('', 'no-decode', None, _('do not pass files through decoders')),
495 [('', 'no-decode', None, _('do not pass files through decoders')),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
496 ('p', 'prefix', '', _('directory prefix for files in archive'),
497 _('PREFIX')),
497 _('PREFIX')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
498 ('r', 'rev', '', _('revision to distribute'), _('REV')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
499 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
500 ] + subrepoopts + walkopts,
500 ] + subrepoopts + walkopts,
501 _('[OPTION]... DEST'))
501 _('[OPTION]... DEST'))
502 def archive(ui, repo, dest, **opts):
502 def archive(ui, repo, dest, **opts):
503 '''create an unversioned archive of a repository revision
503 '''create an unversioned archive of a repository revision
504
504
505 By default, the revision used is the parent of the working
505 By default, the revision used is the parent of the working
506 directory; use -r/--rev to specify a different revision.
506 directory; use -r/--rev to specify a different revision.
507
507
508 The archive type is automatically detected based on file
508 The archive type is automatically detected based on file
509 extension (to override, use -t/--type).
509 extension (to override, use -t/--type).
510
510
511 .. container:: verbose
511 .. container:: verbose
512
512
513 Examples:
513 Examples:
514
514
515 - create a zip file containing the 1.0 release::
515 - create a zip file containing the 1.0 release::
516
516
517 hg archive -r 1.0 project-1.0.zip
517 hg archive -r 1.0 project-1.0.zip
518
518
519 - create a tarball excluding .hg files::
519 - create a tarball excluding .hg files::
520
520
521 hg archive project.tar.gz -X ".hg*"
521 hg archive project.tar.gz -X ".hg*"
522
522
523 Valid types are:
523 Valid types are:
524
524
525 :``files``: a directory full of files (default)
525 :``files``: a directory full of files (default)
526 :``tar``: tar archive, uncompressed
526 :``tar``: tar archive, uncompressed
527 :``tbz2``: tar archive, compressed using bzip2
527 :``tbz2``: tar archive, compressed using bzip2
528 :``tgz``: tar archive, compressed using gzip
528 :``tgz``: tar archive, compressed using gzip
529 :``uzip``: zip archive, uncompressed
529 :``uzip``: zip archive, uncompressed
530 :``zip``: zip archive, compressed using deflate
530 :``zip``: zip archive, compressed using deflate
531
531
532 The exact name of the destination archive or directory is given
532 The exact name of the destination archive or directory is given
533 using a format string; see :hg:`help export` for details.
533 using a format string; see :hg:`help export` for details.
534
534
535 Each member added to an archive file has a directory prefix
535 Each member added to an archive file has a directory prefix
536 prepended. Use -p/--prefix to specify a format string for the
536 prepended. Use -p/--prefix to specify a format string for the
537 prefix. The default is the basename of the archive, with suffixes
537 prefix. The default is the basename of the archive, with suffixes
538 removed.
538 removed.
539
539
540 Returns 0 on success.
540 Returns 0 on success.
541 '''
541 '''
542
542
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
543 ctx = scmutil.revsingle(repo, opts.get('rev'))
544 if not ctx:
544 if not ctx:
545 raise error.Abort(_('no working directory: please specify a revision'))
545 raise error.Abort(_('no working directory: please specify a revision'))
546 node = ctx.node()
546 node = ctx.node()
547 dest = cmdutil.makefilename(repo, dest, node)
547 dest = cmdutil.makefilename(repo, dest, node)
548 if os.path.realpath(dest) == repo.root:
548 if os.path.realpath(dest) == repo.root:
549 raise error.Abort(_('repository root cannot be destination'))
549 raise error.Abort(_('repository root cannot be destination'))
550
550
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
551 kind = opts.get('type') or archival.guesskind(dest) or 'files'
552 prefix = opts.get('prefix')
552 prefix = opts.get('prefix')
553
553
554 if dest == '-':
554 if dest == '-':
555 if kind == 'files':
555 if kind == 'files':
556 raise error.Abort(_('cannot archive plain files to stdout'))
556 raise error.Abort(_('cannot archive plain files to stdout'))
557 dest = cmdutil.makefileobj(repo, dest)
557 dest = cmdutil.makefileobj(repo, dest)
558 if not prefix:
558 if not prefix:
559 prefix = os.path.basename(repo.root) + '-%h'
559 prefix = os.path.basename(repo.root) + '-%h'
560
560
561 prefix = cmdutil.makefilename(repo, prefix, node)
561 prefix = cmdutil.makefilename(repo, prefix, node)
562 matchfn = scmutil.match(ctx, [], opts)
562 matchfn = scmutil.match(ctx, [], opts)
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
563 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
564 matchfn, prefix, subrepos=opts.get('subrepos'))
564 matchfn, prefix, subrepos=opts.get('subrepos'))
565
565
566 @command('backout',
566 @command('backout',
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
567 [('', 'merge', None, _('merge with old dirstate parent after backout')),
568 ('', 'commit', None,
568 ('', 'commit', None,
569 _('commit if no conflicts were encountered (DEPRECATED)')),
569 _('commit if no conflicts were encountered (DEPRECATED)')),
570 ('', 'no-commit', None, _('do not commit')),
570 ('', 'no-commit', None, _('do not commit')),
571 ('', 'parent', '',
571 ('', 'parent', '',
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
572 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
573 ('r', 'rev', '', _('revision to backout'), _('REV')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
574 ('e', 'edit', False, _('invoke editor on commit messages')),
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
575 ] + mergetoolopts + walkopts + commitopts + commitopts2,
576 _('[OPTION]... [-r] REV'))
576 _('[OPTION]... [-r] REV'))
577 def backout(ui, repo, node=None, rev=None, **opts):
577 def backout(ui, repo, node=None, rev=None, **opts):
578 '''reverse effect of earlier changeset
578 '''reverse effect of earlier changeset
579
579
580 Prepare a new changeset with the effect of REV undone in the
580 Prepare a new changeset with the effect of REV undone in the
581 current working directory. If no conflicts were encountered,
581 current working directory. If no conflicts were encountered,
582 it will be committed immediately.
582 it will be committed immediately.
583
583
584 If REV is the parent of the working directory, then this new changeset
584 If REV is the parent of the working directory, then this new changeset
585 is committed automatically (unless --no-commit is specified).
585 is committed automatically (unless --no-commit is specified).
586
586
587 .. note::
587 .. note::
588
588
589 :hg:`backout` cannot be used to fix either an unwanted or
589 :hg:`backout` cannot be used to fix either an unwanted or
590 incorrect merge.
590 incorrect merge.
591
591
592 .. container:: verbose
592 .. container:: verbose
593
593
594 Examples:
594 Examples:
595
595
596 - Reverse the effect of the parent of the working directory.
596 - Reverse the effect of the parent of the working directory.
597 This backout will be committed immediately::
597 This backout will be committed immediately::
598
598
599 hg backout -r .
599 hg backout -r .
600
600
601 - Reverse the effect of previous bad revision 23::
601 - Reverse the effect of previous bad revision 23::
602
602
603 hg backout -r 23
603 hg backout -r 23
604
604
605 - Reverse the effect of previous bad revision 23 and
605 - Reverse the effect of previous bad revision 23 and
606 leave changes uncommitted::
606 leave changes uncommitted::
607
607
608 hg backout -r 23 --no-commit
608 hg backout -r 23 --no-commit
609 hg commit -m "Backout revision 23"
609 hg commit -m "Backout revision 23"
610
610
611 By default, the pending changeset will have one parent,
611 By default, the pending changeset will have one parent,
612 maintaining a linear history. With --merge, the pending
612 maintaining a linear history. With --merge, the pending
613 changeset will instead have two parents: the old parent of the
613 changeset will instead have two parents: the old parent of the
614 working directory and a new child of REV that simply undoes REV.
614 working directory and a new child of REV that simply undoes REV.
615
615
616 Before version 1.7, the behavior without --merge was equivalent
616 Before version 1.7, the behavior without --merge was equivalent
617 to specifying --merge followed by :hg:`update --clean .` to
617 to specifying --merge followed by :hg:`update --clean .` to
618 cancel the merge and leave the child of REV as a head to be
618 cancel the merge and leave the child of REV as a head to be
619 merged separately.
619 merged separately.
620
620
621 See :hg:`help dates` for a list of formats valid for -d/--date.
621 See :hg:`help dates` for a list of formats valid for -d/--date.
622
622
623 See :hg:`help revert` for a way to restore files to the state
623 See :hg:`help revert` for a way to restore files to the state
624 of another revision.
624 of another revision.
625
625
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
626 Returns 0 on success, 1 if nothing to backout or there are unresolved
627 files.
627 files.
628 '''
628 '''
629 wlock = lock = None
629 wlock = lock = None
630 try:
630 try:
631 wlock = repo.wlock()
631 wlock = repo.wlock()
632 lock = repo.lock()
632 lock = repo.lock()
633 return _dobackout(ui, repo, node, rev, **opts)
633 return _dobackout(ui, repo, node, rev, **opts)
634 finally:
634 finally:
635 release(lock, wlock)
635 release(lock, wlock)
636
636
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
637 def _dobackout(ui, repo, node=None, rev=None, **opts):
638 if opts.get('commit') and opts.get('no_commit'):
638 if opts.get('commit') and opts.get('no_commit'):
639 raise error.Abort(_("cannot use --commit with --no-commit"))
639 raise error.Abort(_("cannot use --commit with --no-commit"))
640 if opts.get('merge') and opts.get('no_commit'):
640 if opts.get('merge') and opts.get('no_commit'):
641 raise error.Abort(_("cannot use --merge with --no-commit"))
641 raise error.Abort(_("cannot use --merge with --no-commit"))
642
642
643 if rev and node:
643 if rev and node:
644 raise error.Abort(_("please specify just one revision"))
644 raise error.Abort(_("please specify just one revision"))
645
645
646 if not rev:
646 if not rev:
647 rev = node
647 rev = node
648
648
649 if not rev:
649 if not rev:
650 raise error.Abort(_("please specify a revision to backout"))
650 raise error.Abort(_("please specify a revision to backout"))
651
651
652 date = opts.get('date')
652 date = opts.get('date')
653 if date:
653 if date:
654 opts['date'] = util.parsedate(date)
654 opts['date'] = util.parsedate(date)
655
655
656 cmdutil.checkunfinished(repo)
656 cmdutil.checkunfinished(repo)
657 cmdutil.bailifchanged(repo)
657 cmdutil.bailifchanged(repo)
658 node = scmutil.revsingle(repo, rev).node()
658 node = scmutil.revsingle(repo, rev).node()
659
659
660 op1, op2 = repo.dirstate.parents()
660 op1, op2 = repo.dirstate.parents()
661 if not repo.changelog.isancestor(node, op1):
661 if not repo.changelog.isancestor(node, op1):
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
662 raise error.Abort(_('cannot backout change that is not an ancestor'))
663
663
664 p1, p2 = repo.changelog.parents(node)
664 p1, p2 = repo.changelog.parents(node)
665 if p1 == nullid:
665 if p1 == nullid:
666 raise error.Abort(_('cannot backout a change with no parents'))
666 raise error.Abort(_('cannot backout a change with no parents'))
667 if p2 != nullid:
667 if p2 != nullid:
668 if not opts.get('parent'):
668 if not opts.get('parent'):
669 raise error.Abort(_('cannot backout a merge changeset'))
669 raise error.Abort(_('cannot backout a merge changeset'))
670 p = repo.lookup(opts['parent'])
670 p = repo.lookup(opts['parent'])
671 if p not in (p1, p2):
671 if p not in (p1, p2):
672 raise error.Abort(_('%s is not a parent of %s') %
672 raise error.Abort(_('%s is not a parent of %s') %
673 (short(p), short(node)))
673 (short(p), short(node)))
674 parent = p
674 parent = p
675 else:
675 else:
676 if opts.get('parent'):
676 if opts.get('parent'):
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
677 raise error.Abort(_('cannot use --parent on non-merge changeset'))
678 parent = p1
678 parent = p1
679
679
680 # the backout should appear on the same branch
680 # the backout should appear on the same branch
681 branch = repo.dirstate.branch()
681 branch = repo.dirstate.branch()
682 bheads = repo.branchheads(branch)
682 bheads = repo.branchheads(branch)
683 rctx = scmutil.revsingle(repo, hex(parent))
683 rctx = scmutil.revsingle(repo, hex(parent))
684 if not opts.get('merge') and op1 != node:
684 if not opts.get('merge') and op1 != node:
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
685 dsguard = cmdutil.dirstateguard(repo, 'backout')
686 try:
686 try:
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
687 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
688 'backout')
688 'backout')
689 stats = mergemod.update(repo, parent, True, True, node, False)
689 stats = mergemod.update(repo, parent, True, True, node, False)
690 repo.setparents(op1, op2)
690 repo.setparents(op1, op2)
691 dsguard.close()
691 dsguard.close()
692 hg._showstats(repo, stats)
692 hg._showstats(repo, stats)
693 if stats[3]:
693 if stats[3]:
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
694 repo.ui.status(_("use 'hg resolve' to retry unresolved "
695 "file merges\n"))
695 "file merges\n"))
696 return 1
696 return 1
697 finally:
697 finally:
698 ui.setconfig('ui', 'forcemerge', '', '')
698 ui.setconfig('ui', 'forcemerge', '', '')
699 lockmod.release(dsguard)
699 lockmod.release(dsguard)
700 else:
700 else:
701 hg.clean(repo, node, show_stats=False)
701 hg.clean(repo, node, show_stats=False)
702 repo.dirstate.setbranch(branch)
702 repo.dirstate.setbranch(branch)
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
703 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
704
704
705 if opts.get('no_commit'):
705 if opts.get('no_commit'):
706 msg = _("changeset %s backed out, "
706 msg = _("changeset %s backed out, "
707 "don't forget to commit.\n")
707 "don't forget to commit.\n")
708 ui.status(msg % short(node))
708 ui.status(msg % short(node))
709 return 0
709 return 0
710
710
711 def commitfunc(ui, repo, message, match, opts):
711 def commitfunc(ui, repo, message, match, opts):
712 editform = 'backout'
712 editform = 'backout'
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
713 e = cmdutil.getcommiteditor(editform=editform, **opts)
714 if not message:
714 if not message:
715 # we don't translate commit messages
715 # we don't translate commit messages
716 message = "Backed out changeset %s" % short(node)
716 message = "Backed out changeset %s" % short(node)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
717 e = cmdutil.getcommiteditor(edit=True, editform=editform)
718 return repo.commit(message, opts.get('user'), opts.get('date'),
718 return repo.commit(message, opts.get('user'), opts.get('date'),
719 match, editor=e)
719 match, editor=e)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
720 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
721 if not newnode:
721 if not newnode:
722 ui.status(_("nothing changed\n"))
722 ui.status(_("nothing changed\n"))
723 return 1
723 return 1
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
724 cmdutil.commitstatus(repo, newnode, branch, bheads)
725
725
726 def nice(node):
726 def nice(node):
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
727 return '%d:%s' % (repo.changelog.rev(node), short(node))
728 ui.status(_('changeset %s backs out changeset %s\n') %
728 ui.status(_('changeset %s backs out changeset %s\n') %
729 (nice(repo.changelog.tip()), nice(node)))
729 (nice(repo.changelog.tip()), nice(node)))
730 if opts.get('merge') and op1 != node:
730 if opts.get('merge') and op1 != node:
731 hg.clean(repo, op1, show_stats=False)
731 hg.clean(repo, op1, show_stats=False)
732 ui.status(_('merging with changeset %s\n')
732 ui.status(_('merging with changeset %s\n')
733 % nice(repo.changelog.tip()))
733 % nice(repo.changelog.tip()))
734 try:
734 try:
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
735 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
736 'backout')
736 'backout')
737 return hg.merge(repo, hex(repo.changelog.tip()))
737 return hg.merge(repo, hex(repo.changelog.tip()))
738 finally:
738 finally:
739 ui.setconfig('ui', 'forcemerge', '', '')
739 ui.setconfig('ui', 'forcemerge', '', '')
740 return 0
740 return 0
741
741
742 @command('bisect',
742 @command('bisect',
743 [('r', 'reset', False, _('reset bisect state')),
743 [('r', 'reset', False, _('reset bisect state')),
744 ('g', 'good', False, _('mark changeset good')),
744 ('g', 'good', False, _('mark changeset good')),
745 ('b', 'bad', False, _('mark changeset bad')),
745 ('b', 'bad', False, _('mark changeset bad')),
746 ('s', 'skip', False, _('skip testing changeset')),
746 ('s', 'skip', False, _('skip testing changeset')),
747 ('e', 'extend', False, _('extend the bisect range')),
747 ('e', 'extend', False, _('extend the bisect range')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
748 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
749 ('U', 'noupdate', False, _('do not update to target'))],
749 ('U', 'noupdate', False, _('do not update to target'))],
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
750 _("[-gbsr] [-U] [-c CMD] [REV]"))
751 def bisect(ui, repo, rev=None, extra=None, command=None,
751 def bisect(ui, repo, rev=None, extra=None, command=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
752 reset=None, good=None, bad=None, skip=None, extend=None,
753 noupdate=None):
753 noupdate=None):
754 """subdivision search of changesets
754 """subdivision search of changesets
755
755
756 This command helps to find changesets which introduce problems. To
756 This command helps to find changesets which introduce problems. To
757 use, mark the earliest changeset you know exhibits the problem as
757 use, mark the earliest changeset you know exhibits the problem as
758 bad, then mark the latest changeset which is free from the problem
758 bad, then mark the latest changeset which is free from the problem
759 as good. Bisect will update your working directory to a revision
759 as good. Bisect will update your working directory to a revision
760 for testing (unless the -U/--noupdate option is specified). Once
760 for testing (unless the -U/--noupdate option is specified). Once
761 you have performed tests, mark the working directory as good or
761 you have performed tests, mark the working directory as good or
762 bad, and bisect will either update to another candidate changeset
762 bad, and bisect will either update to another candidate changeset
763 or announce that it has found the bad revision.
763 or announce that it has found the bad revision.
764
764
765 As a shortcut, you can also use the revision argument to mark a
765 As a shortcut, you can also use the revision argument to mark a
766 revision as good or bad without checking it out first.
766 revision as good or bad without checking it out first.
767
767
768 If you supply a command, it will be used for automatic bisection.
768 If you supply a command, it will be used for automatic bisection.
769 The environment variable HG_NODE will contain the ID of the
769 The environment variable HG_NODE will contain the ID of the
770 changeset being tested. The exit status of the command will be
770 changeset being tested. The exit status of the command will be
771 used to mark revisions as good or bad: status 0 means good, 125
771 used to mark revisions as good or bad: status 0 means good, 125
772 means to skip the revision, 127 (command not found) will abort the
772 means to skip the revision, 127 (command not found) will abort the
773 bisection, and any other non-zero exit status means the revision
773 bisection, and any other non-zero exit status means the revision
774 is bad.
774 is bad.
775
775
776 .. container:: verbose
776 .. container:: verbose
777
777
778 Some examples:
778 Some examples:
779
779
780 - start a bisection with known bad revision 34, and good revision 12::
780 - start a bisection with known bad revision 34, and good revision 12::
781
781
782 hg bisect --bad 34
782 hg bisect --bad 34
783 hg bisect --good 12
783 hg bisect --good 12
784
784
785 - advance the current bisection by marking current revision as good or
785 - advance the current bisection by marking current revision as good or
786 bad::
786 bad::
787
787
788 hg bisect --good
788 hg bisect --good
789 hg bisect --bad
789 hg bisect --bad
790
790
791 - mark the current revision, or a known revision, to be skipped (e.g. if
791 - mark the current revision, or a known revision, to be skipped (e.g. if
792 that revision is not usable because of another issue)::
792 that revision is not usable because of another issue)::
793
793
794 hg bisect --skip
794 hg bisect --skip
795 hg bisect --skip 23
795 hg bisect --skip 23
796
796
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
797 - skip all revisions that do not touch directories ``foo`` or ``bar``::
798
798
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
799 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
800
800
801 - forget the current bisection::
801 - forget the current bisection::
802
802
803 hg bisect --reset
803 hg bisect --reset
804
804
805 - use 'make && make tests' to automatically find the first broken
805 - use 'make && make tests' to automatically find the first broken
806 revision::
806 revision::
807
807
808 hg bisect --reset
808 hg bisect --reset
809 hg bisect --bad 34
809 hg bisect --bad 34
810 hg bisect --good 12
810 hg bisect --good 12
811 hg bisect --command "make && make tests"
811 hg bisect --command "make && make tests"
812
812
813 - see all changesets whose states are already known in the current
813 - see all changesets whose states are already known in the current
814 bisection::
814 bisection::
815
815
816 hg log -r "bisect(pruned)"
816 hg log -r "bisect(pruned)"
817
817
818 - see the changeset currently being bisected (especially useful
818 - see the changeset currently being bisected (especially useful
819 if running with -U/--noupdate)::
819 if running with -U/--noupdate)::
820
820
821 hg log -r "bisect(current)"
821 hg log -r "bisect(current)"
822
822
823 - see all changesets that took part in the current bisection::
823 - see all changesets that took part in the current bisection::
824
824
825 hg log -r "bisect(range)"
825 hg log -r "bisect(range)"
826
826
827 - you can even get a nice graph::
827 - you can even get a nice graph::
828
828
829 hg log --graph -r "bisect(range)"
829 hg log --graph -r "bisect(range)"
830
830
831 See :hg:`help revsets` for more about the `bisect()` keyword.
831 See :hg:`help revsets` for more about the `bisect()` keyword.
832
832
833 Returns 0 on success.
833 Returns 0 on success.
834 """
834 """
835 def extendbisectrange(nodes, good):
835 def extendbisectrange(nodes, good):
836 # bisect is incomplete when it ends on a merge node and
836 # bisect is incomplete when it ends on a merge node and
837 # one of the parent was not checked.
837 # one of the parent was not checked.
838 parents = repo[nodes[0]].parents()
838 parents = repo[nodes[0]].parents()
839 if len(parents) > 1:
839 if len(parents) > 1:
840 if good:
840 if good:
841 side = state['bad']
841 side = state['bad']
842 else:
842 else:
843 side = state['good']
843 side = state['good']
844 num = len(set(i.node() for i in parents) & set(side))
844 num = len(set(i.node() for i in parents) & set(side))
845 if num == 1:
845 if num == 1:
846 return parents[0].ancestor(parents[1])
846 return parents[0].ancestor(parents[1])
847 return None
847 return None
848
848
849 def print_result(nodes, good):
849 def print_result(nodes, good):
850 displayer = cmdutil.show_changeset(ui, repo, {})
850 displayer = cmdutil.show_changeset(ui, repo, {})
851 if len(nodes) == 1:
851 if len(nodes) == 1:
852 # narrowed it down to a single revision
852 # narrowed it down to a single revision
853 if good:
853 if good:
854 ui.write(_("The first good revision is:\n"))
854 ui.write(_("The first good revision is:\n"))
855 else:
855 else:
856 ui.write(_("The first bad revision is:\n"))
856 ui.write(_("The first bad revision is:\n"))
857 displayer.show(repo[nodes[0]])
857 displayer.show(repo[nodes[0]])
858 extendnode = extendbisectrange(nodes, good)
858 extendnode = extendbisectrange(nodes, good)
859 if extendnode is not None:
859 if extendnode is not None:
860 ui.write(_('Not all ancestors of this changeset have been'
860 ui.write(_('Not all ancestors of this changeset have been'
861 ' checked.\nUse bisect --extend to continue the '
861 ' checked.\nUse bisect --extend to continue the '
862 'bisection from\nthe common ancestor, %s.\n')
862 'bisection from\nthe common ancestor, %s.\n')
863 % extendnode)
863 % extendnode)
864 else:
864 else:
865 # multiple possible revisions
865 # multiple possible revisions
866 if good:
866 if good:
867 ui.write(_("Due to skipped revisions, the first "
867 ui.write(_("Due to skipped revisions, the first "
868 "good revision could be any of:\n"))
868 "good revision could be any of:\n"))
869 else:
869 else:
870 ui.write(_("Due to skipped revisions, the first "
870 ui.write(_("Due to skipped revisions, the first "
871 "bad revision could be any of:\n"))
871 "bad revision could be any of:\n"))
872 for n in nodes:
872 for n in nodes:
873 displayer.show(repo[n])
873 displayer.show(repo[n])
874 displayer.close()
874 displayer.close()
875
875
876 def check_state(state, interactive=True):
876 def check_state(state, interactive=True):
877 if not state['good'] or not state['bad']:
877 if not state['good'] or not state['bad']:
878 if (good or bad or skip or reset) and interactive:
878 if (good or bad or skip or reset) and interactive:
879 return
879 return
880 if not state['good']:
880 if not state['good']:
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
881 raise error.Abort(_('cannot bisect (no known good revisions)'))
882 else:
882 else:
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
883 raise error.Abort(_('cannot bisect (no known bad revisions)'))
884 return True
884 return True
885
885
886 # backward compatibility
886 # backward compatibility
887 if rev in "good bad reset init".split():
887 if rev in "good bad reset init".split():
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
888 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
889 cmd, rev, extra = rev, extra, None
889 cmd, rev, extra = rev, extra, None
890 if cmd == "good":
890 if cmd == "good":
891 good = True
891 good = True
892 elif cmd == "bad":
892 elif cmd == "bad":
893 bad = True
893 bad = True
894 else:
894 else:
895 reset = True
895 reset = True
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
896 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
897 raise error.Abort(_('incompatible arguments'))
897 raise error.Abort(_('incompatible arguments'))
898
898
899 cmdutil.checkunfinished(repo)
899 cmdutil.checkunfinished(repo)
900
900
901 if reset:
901 if reset:
902 p = repo.join("bisect.state")
902 p = repo.join("bisect.state")
903 if os.path.exists(p):
903 if os.path.exists(p):
904 os.unlink(p)
904 os.unlink(p)
905 return
905 return
906
906
907 state = hbisect.load_state(repo)
907 state = hbisect.load_state(repo)
908
908
909 if command:
909 if command:
910 changesets = 1
910 changesets = 1
911 if noupdate:
911 if noupdate:
912 try:
912 try:
913 node = state['current'][0]
913 node = state['current'][0]
914 except LookupError:
914 except LookupError:
915 raise error.Abort(_('current bisect revision is unknown - '
915 raise error.Abort(_('current bisect revision is unknown - '
916 'start a new bisect to fix'))
916 'start a new bisect to fix'))
917 else:
917 else:
918 node, p2 = repo.dirstate.parents()
918 node, p2 = repo.dirstate.parents()
919 if p2 != nullid:
919 if p2 != nullid:
920 raise error.Abort(_('current bisect revision is a merge'))
920 raise error.Abort(_('current bisect revision is a merge'))
921 try:
921 try:
922 while changesets:
922 while changesets:
923 # update state
923 # update state
924 state['current'] = [node]
924 state['current'] = [node]
925 hbisect.save_state(repo, state)
925 hbisect.save_state(repo, state)
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
926 status = ui.system(command, environ={'HG_NODE': hex(node)})
927 if status == 125:
927 if status == 125:
928 transition = "skip"
928 transition = "skip"
929 elif status == 0:
929 elif status == 0:
930 transition = "good"
930 transition = "good"
931 # status < 0 means process was killed
931 # status < 0 means process was killed
932 elif status == 127:
932 elif status == 127:
933 raise error.Abort(_("failed to execute %s") % command)
933 raise error.Abort(_("failed to execute %s") % command)
934 elif status < 0:
934 elif status < 0:
935 raise error.Abort(_("%s killed") % command)
935 raise error.Abort(_("%s killed") % command)
936 else:
936 else:
937 transition = "bad"
937 transition = "bad"
938 ctx = scmutil.revsingle(repo, rev, node)
938 ctx = scmutil.revsingle(repo, rev, node)
939 rev = None # clear for future iterations
939 rev = None # clear for future iterations
940 state[transition].append(ctx.node())
940 state[transition].append(ctx.node())
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
941 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
942 check_state(state, interactive=False)
942 check_state(state, interactive=False)
943 # bisect
943 # bisect
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
944 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
945 # update to next check
945 # update to next check
946 node = nodes[0]
946 node = nodes[0]
947 if not noupdate:
947 if not noupdate:
948 cmdutil.bailifchanged(repo)
948 cmdutil.bailifchanged(repo)
949 hg.clean(repo, node, show_stats=False)
949 hg.clean(repo, node, show_stats=False)
950 finally:
950 finally:
951 state['current'] = [node]
951 state['current'] = [node]
952 hbisect.save_state(repo, state)
952 hbisect.save_state(repo, state)
953 print_result(nodes, bgood)
953 print_result(nodes, bgood)
954 return
954 return
955
955
956 # update state
956 # update state
957
957
958 if rev:
958 if rev:
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
959 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
960 else:
960 else:
961 nodes = [repo.lookup('.')]
961 nodes = [repo.lookup('.')]
962
962
963 if good or bad or skip:
963 if good or bad or skip:
964 if good:
964 if good:
965 state['good'] += nodes
965 state['good'] += nodes
966 elif bad:
966 elif bad:
967 state['bad'] += nodes
967 state['bad'] += nodes
968 elif skip:
968 elif skip:
969 state['skip'] += nodes
969 state['skip'] += nodes
970 hbisect.save_state(repo, state)
970 hbisect.save_state(repo, state)
971
971
972 if not check_state(state):
972 if not check_state(state):
973 return
973 return
974
974
975 # actually bisect
975 # actually bisect
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
976 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
977 if extend:
977 if extend:
978 if not changesets:
978 if not changesets:
979 extendnode = extendbisectrange(nodes, good)
979 extendnode = extendbisectrange(nodes, good)
980 if extendnode is not None:
980 if extendnode is not None:
981 ui.write(_("Extending search to changeset %d:%s\n")
981 ui.write(_("Extending search to changeset %d:%s\n")
982 % (extendnode.rev(), extendnode))
982 % (extendnode.rev(), extendnode))
983 state['current'] = [extendnode.node()]
983 state['current'] = [extendnode.node()]
984 hbisect.save_state(repo, state)
984 hbisect.save_state(repo, state)
985 if noupdate:
985 if noupdate:
986 return
986 return
987 cmdutil.bailifchanged(repo)
987 cmdutil.bailifchanged(repo)
988 return hg.clean(repo, extendnode.node())
988 return hg.clean(repo, extendnode.node())
989 raise error.Abort(_("nothing to extend"))
989 raise error.Abort(_("nothing to extend"))
990
990
991 if changesets == 0:
991 if changesets == 0:
992 print_result(nodes, good)
992 print_result(nodes, good)
993 else:
993 else:
994 assert len(nodes) == 1 # only a single node can be tested next
994 assert len(nodes) == 1 # only a single node can be tested next
995 node = nodes[0]
995 node = nodes[0]
996 # compute the approximate number of remaining tests
996 # compute the approximate number of remaining tests
997 tests, size = 0, 2
997 tests, size = 0, 2
998 while size <= changesets:
998 while size <= changesets:
999 tests, size = tests + 1, size * 2
999 tests, size = tests + 1, size * 2
1000 rev = repo.changelog.rev(node)
1000 rev = repo.changelog.rev(node)
1001 ui.write(_("Testing changeset %d:%s "
1001 ui.write(_("Testing changeset %d:%s "
1002 "(%d changesets remaining, ~%d tests)\n")
1002 "(%d changesets remaining, ~%d tests)\n")
1003 % (rev, short(node), changesets, tests))
1003 % (rev, short(node), changesets, tests))
1004 state['current'] = [node]
1004 state['current'] = [node]
1005 hbisect.save_state(repo, state)
1005 hbisect.save_state(repo, state)
1006 if not noupdate:
1006 if not noupdate:
1007 cmdutil.bailifchanged(repo)
1007 cmdutil.bailifchanged(repo)
1008 return hg.clean(repo, node)
1008 return hg.clean(repo, node)
1009
1009
1010 @command('bookmarks|bookmark',
1010 @command('bookmarks|bookmark',
1011 [('f', 'force', False, _('force')),
1011 [('f', 'force', False, _('force')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1012 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1013 ('d', 'delete', False, _('delete a given bookmark')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1014 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1015 ('i', 'inactive', False, _('mark a bookmark inactive')),
1016 ] + formatteropts,
1016 ] + formatteropts,
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1017 _('hg bookmarks [OPTIONS]... [NAME]...'))
1018 def bookmark(ui, repo, *names, **opts):
1018 def bookmark(ui, repo, *names, **opts):
1019 '''create a new bookmark or list existing bookmarks
1019 '''create a new bookmark or list existing bookmarks
1020
1020
1021 Bookmarks are labels on changesets to help track lines of development.
1021 Bookmarks are labels on changesets to help track lines of development.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1022 Bookmarks are unversioned and can be moved, renamed and deleted.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1023 Deleting or moving a bookmark has no effect on the associated changesets.
1024
1024
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1025 Creating or updating to a bookmark causes it to be marked as 'active'.
1026 The active bookmark is indicated with a '*'.
1026 The active bookmark is indicated with a '*'.
1027 When a commit is made, the active bookmark will advance to the new commit.
1027 When a commit is made, the active bookmark will advance to the new commit.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1028 A plain :hg:`update` will also advance an active bookmark, if possible.
1029 Updating away from a bookmark will cause it to be deactivated.
1029 Updating away from a bookmark will cause it to be deactivated.
1030
1030
1031 Bookmarks can be pushed and pulled between repositories (see
1031 Bookmarks can be pushed and pulled between repositories (see
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1032 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1033 diverged, a new 'divergent bookmark' of the form 'name@path' will
1034 be created. Using :hg:`merge` will resolve the divergence.
1034 be created. Using :hg:`merge` will resolve the divergence.
1035
1035
1036 A bookmark named '@' has the special property that :hg:`clone` will
1036 A bookmark named '@' has the special property that :hg:`clone` will
1037 check it out by default if it exists.
1037 check it out by default if it exists.
1038
1038
1039 .. container:: verbose
1039 .. container:: verbose
1040
1040
1041 Examples:
1041 Examples:
1042
1042
1043 - create an active bookmark for a new line of development::
1043 - create an active bookmark for a new line of development::
1044
1044
1045 hg book new-feature
1045 hg book new-feature
1046
1046
1047 - create an inactive bookmark as a place marker::
1047 - create an inactive bookmark as a place marker::
1048
1048
1049 hg book -i reviewed
1049 hg book -i reviewed
1050
1050
1051 - create an inactive bookmark on another changeset::
1051 - create an inactive bookmark on another changeset::
1052
1052
1053 hg book -r .^ tested
1053 hg book -r .^ tested
1054
1054
1055 - rename bookmark turkey to dinner::
1055 - rename bookmark turkey to dinner::
1056
1056
1057 hg book -m turkey dinner
1057 hg book -m turkey dinner
1058
1058
1059 - move the '@' bookmark from another branch::
1059 - move the '@' bookmark from another branch::
1060
1060
1061 hg book -f @
1061 hg book -f @
1062 '''
1062 '''
1063 force = opts.get('force')
1063 force = opts.get('force')
1064 rev = opts.get('rev')
1064 rev = opts.get('rev')
1065 delete = opts.get('delete')
1065 delete = opts.get('delete')
1066 rename = opts.get('rename')
1066 rename = opts.get('rename')
1067 inactive = opts.get('inactive')
1067 inactive = opts.get('inactive')
1068
1068
1069 def checkformat(mark):
1069 def checkformat(mark):
1070 mark = mark.strip()
1070 mark = mark.strip()
1071 if not mark:
1071 if not mark:
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1072 raise error.Abort(_("bookmark names cannot consist entirely of "
1073 "whitespace"))
1073 "whitespace"))
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1074 scmutil.checknewlabel(repo, mark, 'bookmark')
1075 return mark
1075 return mark
1076
1076
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1077 def checkconflict(repo, mark, cur, force=False, target=None):
1078 if mark in marks and not force:
1078 if mark in marks and not force:
1079 if target:
1079 if target:
1080 if marks[mark] == target and target == cur:
1080 if marks[mark] == target and target == cur:
1081 # re-activating a bookmark
1081 # re-activating a bookmark
1082 return
1082 return
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1083 anc = repo.changelog.ancestors([repo[target].rev()])
1084 bmctx = repo[marks[mark]]
1084 bmctx = repo[marks[mark]]
1085 divs = [repo[b].node() for b in marks
1085 divs = [repo[b].node() for b in marks
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1086 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1087
1087
1088 # allow resolving a single divergent bookmark even if moving
1088 # allow resolving a single divergent bookmark even if moving
1089 # the bookmark across branches when a revision is specified
1089 # the bookmark across branches when a revision is specified
1090 # that contains a divergent bookmark
1090 # that contains a divergent bookmark
1091 if bmctx.rev() not in anc and target in divs:
1091 if bmctx.rev() not in anc and target in divs:
1092 bookmarks.deletedivergent(repo, [target], mark)
1092 bookmarks.deletedivergent(repo, [target], mark)
1093 return
1093 return
1094
1094
1095 deletefrom = [b for b in divs
1095 deletefrom = [b for b in divs
1096 if repo[b].rev() in anc or b == target]
1096 if repo[b].rev() in anc or b == target]
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1097 bookmarks.deletedivergent(repo, deletefrom, mark)
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1098 if bookmarks.validdest(repo, bmctx, repo[target]):
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1099 ui.status(_("moving bookmark '%s' forward from %s\n") %
1100 (mark, short(bmctx.node())))
1100 (mark, short(bmctx.node())))
1101 return
1101 return
1102 raise error.Abort(_("bookmark '%s' already exists "
1102 raise error.Abort(_("bookmark '%s' already exists "
1103 "(use -f to force)") % mark)
1103 "(use -f to force)") % mark)
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1104 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1105 and not force):
1105 and not force):
1106 raise error.Abort(
1106 raise error.Abort(
1107 _("a bookmark cannot have the name of an existing branch"))
1107 _("a bookmark cannot have the name of an existing branch"))
1108
1108
1109 if delete and rename:
1109 if delete and rename:
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1110 raise error.Abort(_("--delete and --rename are incompatible"))
1111 if delete and rev:
1111 if delete and rev:
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1112 raise error.Abort(_("--rev is incompatible with --delete"))
1113 if rename and rev:
1113 if rename and rev:
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1114 raise error.Abort(_("--rev is incompatible with --rename"))
1115 if not names and (delete or rev):
1115 if not names and (delete or rev):
1116 raise error.Abort(_("bookmark name required"))
1116 raise error.Abort(_("bookmark name required"))
1117
1117
1118 if delete or rename or names or inactive:
1118 if delete or rename or names or inactive:
1119 wlock = lock = tr = None
1119 wlock = lock = tr = None
1120 try:
1120 try:
1121 wlock = repo.wlock()
1121 wlock = repo.wlock()
1122 lock = repo.lock()
1122 lock = repo.lock()
1123 cur = repo.changectx('.').node()
1123 cur = repo.changectx('.').node()
1124 marks = repo._bookmarks
1124 marks = repo._bookmarks
1125 if delete:
1125 if delete:
1126 tr = repo.transaction('bookmark')
1126 tr = repo.transaction('bookmark')
1127 for mark in names:
1127 for mark in names:
1128 if mark not in marks:
1128 if mark not in marks:
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1129 raise error.Abort(_("bookmark '%s' does not exist") %
1130 mark)
1130 mark)
1131 if mark == repo._activebookmark:
1131 if mark == repo._activebookmark:
1132 bookmarks.deactivate(repo)
1132 bookmarks.deactivate(repo)
1133 del marks[mark]
1133 del marks[mark]
1134
1134
1135 elif rename:
1135 elif rename:
1136 tr = repo.transaction('bookmark')
1136 tr = repo.transaction('bookmark')
1137 if not names:
1137 if not names:
1138 raise error.Abort(_("new bookmark name required"))
1138 raise error.Abort(_("new bookmark name required"))
1139 elif len(names) > 1:
1139 elif len(names) > 1:
1140 raise error.Abort(_("only one new bookmark name allowed"))
1140 raise error.Abort(_("only one new bookmark name allowed"))
1141 mark = checkformat(names[0])
1141 mark = checkformat(names[0])
1142 if rename not in marks:
1142 if rename not in marks:
1143 raise error.Abort(_("bookmark '%s' does not exist")
1143 raise error.Abort(_("bookmark '%s' does not exist")
1144 % rename)
1144 % rename)
1145 checkconflict(repo, mark, cur, force)
1145 checkconflict(repo, mark, cur, force)
1146 marks[mark] = marks[rename]
1146 marks[mark] = marks[rename]
1147 if repo._activebookmark == rename and not inactive:
1147 if repo._activebookmark == rename and not inactive:
1148 bookmarks.activate(repo, mark)
1148 bookmarks.activate(repo, mark)
1149 del marks[rename]
1149 del marks[rename]
1150 elif names:
1150 elif names:
1151 tr = repo.transaction('bookmark')
1151 tr = repo.transaction('bookmark')
1152 newact = None
1152 newact = None
1153 for mark in names:
1153 for mark in names:
1154 mark = checkformat(mark)
1154 mark = checkformat(mark)
1155 if newact is None:
1155 if newact is None:
1156 newact = mark
1156 newact = mark
1157 if inactive and mark == repo._activebookmark:
1157 if inactive and mark == repo._activebookmark:
1158 bookmarks.deactivate(repo)
1158 bookmarks.deactivate(repo)
1159 return
1159 return
1160 tgt = cur
1160 tgt = cur
1161 if rev:
1161 if rev:
1162 tgt = scmutil.revsingle(repo, rev).node()
1162 tgt = scmutil.revsingle(repo, rev).node()
1163 checkconflict(repo, mark, cur, force, tgt)
1163 checkconflict(repo, mark, cur, force, tgt)
1164 marks[mark] = tgt
1164 marks[mark] = tgt
1165 if not inactive and cur == marks[newact] and not rev:
1165 if not inactive and cur == marks[newact] and not rev:
1166 bookmarks.activate(repo, newact)
1166 bookmarks.activate(repo, newact)
1167 elif cur != tgt and newact == repo._activebookmark:
1167 elif cur != tgt and newact == repo._activebookmark:
1168 bookmarks.deactivate(repo)
1168 bookmarks.deactivate(repo)
1169 elif inactive:
1169 elif inactive:
1170 if len(marks) == 0:
1170 if len(marks) == 0:
1171 ui.status(_("no bookmarks set\n"))
1171 ui.status(_("no bookmarks set\n"))
1172 elif not repo._activebookmark:
1172 elif not repo._activebookmark:
1173 ui.status(_("no active bookmark\n"))
1173 ui.status(_("no active bookmark\n"))
1174 else:
1174 else:
1175 bookmarks.deactivate(repo)
1175 bookmarks.deactivate(repo)
1176 if tr is not None:
1176 if tr is not None:
1177 marks.recordchange(tr)
1177 marks.recordchange(tr)
1178 tr.close()
1178 tr.close()
1179 finally:
1179 finally:
1180 lockmod.release(tr, lock, wlock)
1180 lockmod.release(tr, lock, wlock)
1181 else: # show bookmarks
1181 else: # show bookmarks
1182 fm = ui.formatter('bookmarks', opts)
1182 fm = ui.formatter('bookmarks', opts)
1183 hexfn = fm.hexfunc
1183 hexfn = fm.hexfunc
1184 marks = repo._bookmarks
1184 marks = repo._bookmarks
1185 if len(marks) == 0 and not fm:
1185 if len(marks) == 0 and not fm:
1186 ui.status(_("no bookmarks set\n"))
1186 ui.status(_("no bookmarks set\n"))
1187 for bmark, n in sorted(marks.iteritems()):
1187 for bmark, n in sorted(marks.iteritems()):
1188 active = repo._activebookmark
1188 active = repo._activebookmark
1189 if bmark == active:
1189 if bmark == active:
1190 prefix, label = '*', activebookmarklabel
1190 prefix, label = '*', activebookmarklabel
1191 else:
1191 else:
1192 prefix, label = ' ', ''
1192 prefix, label = ' ', ''
1193
1193
1194 fm.startitem()
1194 fm.startitem()
1195 if not ui.quiet:
1195 if not ui.quiet:
1196 fm.plain(' %s ' % prefix, label=label)
1196 fm.plain(' %s ' % prefix, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1197 fm.write('bookmark', '%s', bmark, label=label)
1198 pad = " " * (25 - encoding.colwidth(bmark))
1198 pad = " " * (25 - encoding.colwidth(bmark))
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1199 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1200 repo.changelog.rev(n), hexfn(n), label=label)
1200 repo.changelog.rev(n), hexfn(n), label=label)
1201 fm.data(active=(bmark == active))
1201 fm.data(active=(bmark == active))
1202 fm.plain('\n')
1202 fm.plain('\n')
1203 fm.end()
1203 fm.end()
1204
1204
1205 @command('branch',
1205 @command('branch',
1206 [('f', 'force', None,
1206 [('f', 'force', None,
1207 _('set branch name even if it shadows an existing branch')),
1207 _('set branch name even if it shadows an existing branch')),
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1208 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1209 _('[-fC] [NAME]'))
1209 _('[-fC] [NAME]'))
1210 def branch(ui, repo, label=None, **opts):
1210 def branch(ui, repo, label=None, **opts):
1211 """set or show the current branch name
1211 """set or show the current branch name
1212
1212
1213 .. note::
1213 .. note::
1214
1214
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1215 Branch names are permanent and global. Use :hg:`bookmark` to create a
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1216 light-weight bookmark instead. See :hg:`help glossary` for more
1217 information about named branches and bookmarks.
1217 information about named branches and bookmarks.
1218
1218
1219 With no argument, show the current branch name. With one argument,
1219 With no argument, show the current branch name. With one argument,
1220 set the working directory branch name (the branch will not exist
1220 set the working directory branch name (the branch will not exist
1221 in the repository until the next commit). Standard practice
1221 in the repository until the next commit). Standard practice
1222 recommends that primary development take place on the 'default'
1222 recommends that primary development take place on the 'default'
1223 branch.
1223 branch.
1224
1224
1225 Unless -f/--force is specified, branch will not let you set a
1225 Unless -f/--force is specified, branch will not let you set a
1226 branch name that already exists.
1226 branch name that already exists.
1227
1227
1228 Use -C/--clean to reset the working directory branch to that of
1228 Use -C/--clean to reset the working directory branch to that of
1229 the parent of the working directory, negating a previous branch
1229 the parent of the working directory, negating a previous branch
1230 change.
1230 change.
1231
1231
1232 Use the command :hg:`update` to switch to an existing branch. Use
1232 Use the command :hg:`update` to switch to an existing branch. Use
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1233 :hg:`commit --close-branch` to mark this branch head as closed.
1234 When all heads of a branch are closed, the branch will be
1234 When all heads of a branch are closed, the branch will be
1235 considered closed.
1235 considered closed.
1236
1236
1237 Returns 0 on success.
1237 Returns 0 on success.
1238 """
1238 """
1239 if label:
1239 if label:
1240 label = label.strip()
1240 label = label.strip()
1241
1241
1242 if not opts.get('clean') and not label:
1242 if not opts.get('clean') and not label:
1243 ui.write("%s\n" % repo.dirstate.branch())
1243 ui.write("%s\n" % repo.dirstate.branch())
1244 return
1244 return
1245
1245
1246 with repo.wlock():
1246 with repo.wlock():
1247 if opts.get('clean'):
1247 if opts.get('clean'):
1248 label = repo[None].p1().branch()
1248 label = repo[None].p1().branch()
1249 repo.dirstate.setbranch(label)
1249 repo.dirstate.setbranch(label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1250 ui.status(_('reset working directory to branch %s\n') % label)
1251 elif label:
1251 elif label:
1252 if not opts.get('force') and label in repo.branchmap():
1252 if not opts.get('force') and label in repo.branchmap():
1253 if label not in [p.branch() for p in repo[None].parents()]:
1253 if label not in [p.branch() for p in repo[None].parents()]:
1254 raise error.Abort(_('a branch of the same name already'
1254 raise error.Abort(_('a branch of the same name already'
1255 ' exists'),
1255 ' exists'),
1256 # i18n: "it" refers to an existing branch
1256 # i18n: "it" refers to an existing branch
1257 hint=_("use 'hg update' to switch to it"))
1257 hint=_("use 'hg update' to switch to it"))
1258 scmutil.checknewlabel(repo, label, 'branch')
1258 scmutil.checknewlabel(repo, label, 'branch')
1259 repo.dirstate.setbranch(label)
1259 repo.dirstate.setbranch(label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1260 ui.status(_('marked working directory as branch %s\n') % label)
1261
1261
1262 # find any open named branches aside from default
1262 # find any open named branches aside from default
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1263 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1264 if n != "default" and not c]
1264 if n != "default" and not c]
1265 if not others:
1265 if not others:
1266 ui.status(_('(branches are permanent and global, '
1266 ui.status(_('(branches are permanent and global, '
1267 'did you want a bookmark?)\n'))
1267 'did you want a bookmark?)\n'))
1268
1268
1269 @command('branches',
1269 @command('branches',
1270 [('a', 'active', False,
1270 [('a', 'active', False,
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1271 _('show only branches that have unmerged heads (DEPRECATED)')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1272 ('c', 'closed', False, _('show normal and closed branches')),
1273 ] + formatteropts,
1273 ] + formatteropts,
1274 _('[-c]'))
1274 _('[-c]'))
1275 def branches(ui, repo, active=False, closed=False, **opts):
1275 def branches(ui, repo, active=False, closed=False, **opts):
1276 """list repository named branches
1276 """list repository named branches
1277
1277
1278 List the repository's named branches, indicating which ones are
1278 List the repository's named branches, indicating which ones are
1279 inactive. If -c/--closed is specified, also list branches which have
1279 inactive. If -c/--closed is specified, also list branches which have
1280 been marked closed (see :hg:`commit --close-branch`).
1280 been marked closed (see :hg:`commit --close-branch`).
1281
1281
1282 Use the command :hg:`update` to switch to an existing branch.
1282 Use the command :hg:`update` to switch to an existing branch.
1283
1283
1284 Returns 0.
1284 Returns 0.
1285 """
1285 """
1286
1286
1287 fm = ui.formatter('branches', opts)
1287 fm = ui.formatter('branches', opts)
1288 hexfunc = fm.hexfunc
1288 hexfunc = fm.hexfunc
1289
1289
1290 allheads = set(repo.heads())
1290 allheads = set(repo.heads())
1291 branches = []
1291 branches = []
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1292 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1293 isactive = not isclosed and bool(set(heads) & allheads)
1293 isactive = not isclosed and bool(set(heads) & allheads)
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1294 branches.append((tag, repo[tip], isactive, not isclosed))
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1295 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1296 reverse=True)
1296 reverse=True)
1297
1297
1298 for tag, ctx, isactive, isopen in branches:
1298 for tag, ctx, isactive, isopen in branches:
1299 if active and not isactive:
1299 if active and not isactive:
1300 continue
1300 continue
1301 if isactive:
1301 if isactive:
1302 label = 'branches.active'
1302 label = 'branches.active'
1303 notice = ''
1303 notice = ''
1304 elif not isopen:
1304 elif not isopen:
1305 if not closed:
1305 if not closed:
1306 continue
1306 continue
1307 label = 'branches.closed'
1307 label = 'branches.closed'
1308 notice = _(' (closed)')
1308 notice = _(' (closed)')
1309 else:
1309 else:
1310 label = 'branches.inactive'
1310 label = 'branches.inactive'
1311 notice = _(' (inactive)')
1311 notice = _(' (inactive)')
1312 current = (tag == repo.dirstate.branch())
1312 current = (tag == repo.dirstate.branch())
1313 if current:
1313 if current:
1314 label = 'branches.current'
1314 label = 'branches.current'
1315
1315
1316 fm.startitem()
1316 fm.startitem()
1317 fm.write('branch', '%s', tag, label=label)
1317 fm.write('branch', '%s', tag, label=label)
1318 rev = ctx.rev()
1318 rev = ctx.rev()
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1319 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1320 fmt = ' ' * padsize + ' %d:%s'
1320 fmt = ' ' * padsize + ' %d:%s'
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1321 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1322 label='log.changeset changeset.%s' % ctx.phasestr())
1323 fm.data(active=isactive, closed=not isopen, current=current)
1323 fm.data(active=isactive, closed=not isopen, current=current)
1324 if not ui.quiet:
1324 if not ui.quiet:
1325 fm.plain(notice)
1325 fm.plain(notice)
1326 fm.plain('\n')
1326 fm.plain('\n')
1327 fm.end()
1327 fm.end()
1328
1328
1329 @command('bundle',
1329 @command('bundle',
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1330 [('f', 'force', None, _('run even when the destination is unrelated')),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1331 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1332 _('REV')),
1332 _('REV')),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1333 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1334 _('BRANCH')),
1334 _('BRANCH')),
1335 ('', 'base', [],
1335 ('', 'base', [],
1336 _('a base changeset assumed to be available at the destination'),
1336 _('a base changeset assumed to be available at the destination'),
1337 _('REV')),
1337 _('REV')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1338 ('a', 'all', None, _('bundle all changesets in the repository')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1339 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1340 ] + remoteopts,
1340 ] + remoteopts,
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1341 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1342 def bundle(ui, repo, fname, dest=None, **opts):
1342 def bundle(ui, repo, fname, dest=None, **opts):
1343 """create a changegroup file
1343 """create a changegroup file
1344
1344
1345 Generate a changegroup file collecting changesets to be added
1345 Generate a changegroup file collecting changesets to be added
1346 to a repository.
1346 to a repository.
1347
1347
1348 To create a bundle containing all changesets, use -a/--all
1348 To create a bundle containing all changesets, use -a/--all
1349 (or --base null). Otherwise, hg assumes the destination will have
1349 (or --base null). Otherwise, hg assumes the destination will have
1350 all the nodes you specify with --base parameters. Otherwise, hg
1350 all the nodes you specify with --base parameters. Otherwise, hg
1351 will assume the repository has all the nodes in destination, or
1351 will assume the repository has all the nodes in destination, or
1352 default-push/default if no destination is specified.
1352 default-push/default if no destination is specified.
1353
1353
1354 You can change bundle format with the -t/--type option. You can
1354 You can change bundle format with the -t/--type option. You can
1355 specify a compression, a bundle version or both using a dash
1355 specify a compression, a bundle version or both using a dash
1356 (comp-version). The available compression methods are: none, bzip2,
1356 (comp-version). The available compression methods are: none, bzip2,
1357 and gzip (by default, bundles are compressed using bzip2). The
1357 and gzip (by default, bundles are compressed using bzip2). The
1358 available formats are: v1, v2 (default to most suitable).
1358 available formats are: v1, v2 (default to most suitable).
1359
1359
1360 The bundle file can then be transferred using conventional means
1360 The bundle file can then be transferred using conventional means
1361 and applied to another repository with the unbundle or pull
1361 and applied to another repository with the unbundle or pull
1362 command. This is useful when direct push and pull are not
1362 command. This is useful when direct push and pull are not
1363 available or when exporting an entire repository is undesirable.
1363 available or when exporting an entire repository is undesirable.
1364
1364
1365 Applying bundles preserves all changeset contents including
1365 Applying bundles preserves all changeset contents including
1366 permissions, copy/rename information, and revision history.
1366 permissions, copy/rename information, and revision history.
1367
1367
1368 Returns 0 on success, 1 if no changes found.
1368 Returns 0 on success, 1 if no changes found.
1369 """
1369 """
1370 revs = None
1370 revs = None
1371 if 'rev' in opts:
1371 if 'rev' in opts:
1372 revstrings = opts['rev']
1372 revstrings = opts['rev']
1373 revs = scmutil.revrange(repo, revstrings)
1373 revs = scmutil.revrange(repo, revstrings)
1374 if revstrings and not revs:
1374 if revstrings and not revs:
1375 raise error.Abort(_('no commits to bundle'))
1375 raise error.Abort(_('no commits to bundle'))
1376
1376
1377 bundletype = opts.get('type', 'bzip2').lower()
1377 bundletype = opts.get('type', 'bzip2').lower()
1378 try:
1378 try:
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1379 bcompression, cgversion, params = exchange.parsebundlespec(
1380 repo, bundletype, strict=False)
1380 repo, bundletype, strict=False)
1381 except error.UnsupportedBundleSpecification as e:
1381 except error.UnsupportedBundleSpecification as e:
1382 raise error.Abort(str(e),
1382 raise error.Abort(str(e),
1383 hint=_('see "hg help bundle" for supported '
1383 hint=_('see "hg help bundle" for supported '
1384 'values for --type'))
1384 'values for --type'))
1385
1385
1386 # Packed bundles are a pseudo bundle format for now.
1386 # Packed bundles are a pseudo bundle format for now.
1387 if cgversion == 's1':
1387 if cgversion == 's1':
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1388 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1389 hint=_('use "hg debugcreatestreamclonebundle"'))
1390
1390
1391 if opts.get('all'):
1391 if opts.get('all'):
1392 if dest:
1392 if dest:
1393 raise error.Abort(_("--all is incompatible with specifying "
1393 raise error.Abort(_("--all is incompatible with specifying "
1394 "a destination"))
1394 "a destination"))
1395 if opts.get('base'):
1395 if opts.get('base'):
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1396 ui.warn(_("ignoring --base because --all was specified\n"))
1397 base = ['null']
1397 base = ['null']
1398 else:
1398 else:
1399 base = scmutil.revrange(repo, opts.get('base'))
1399 base = scmutil.revrange(repo, opts.get('base'))
1400 # TODO: get desired bundlecaps from command line.
1400 # TODO: get desired bundlecaps from command line.
1401 bundlecaps = None
1401 bundlecaps = None
1402 if base:
1402 if base:
1403 if dest:
1403 if dest:
1404 raise error.Abort(_("--base is incompatible with specifying "
1404 raise error.Abort(_("--base is incompatible with specifying "
1405 "a destination"))
1405 "a destination"))
1406 common = [repo.lookup(rev) for rev in base]
1406 common = [repo.lookup(rev) for rev in base]
1407 heads = revs and map(repo.lookup, revs) or revs
1407 heads = revs and map(repo.lookup, revs) or revs
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1409 common=common, bundlecaps=bundlecaps,
1409 common=common, bundlecaps=bundlecaps,
1410 version=cgversion)
1410 version=cgversion)
1411 outgoing = None
1411 outgoing = None
1412 else:
1412 else:
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1415 other = hg.peer(repo, opts, dest)
1415 other = hg.peer(repo, opts, dest)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1417 heads = revs and map(repo.lookup, revs) or revs
1417 heads = revs and map(repo.lookup, revs) or revs
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1419 onlyheads=heads,
1419 onlyheads=heads,
1420 force=opts.get('force'),
1420 force=opts.get('force'),
1421 portable=True)
1421 portable=True)
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1423 bundlecaps, version=cgversion)
1423 bundlecaps, version=cgversion)
1424 if not cg:
1424 if not cg:
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1426 return 1
1426 return 1
1427
1427
1428 if cgversion == '01': #bundle1
1428 if cgversion == '01': #bundle1
1429 if bcompression is None:
1429 if bcompression is None:
1430 bcompression = 'UN'
1430 bcompression = 'UN'
1431 bversion = 'HG10' + bcompression
1431 bversion = 'HG10' + bcompression
1432 bcompression = None
1432 bcompression = None
1433 else:
1433 else:
1434 assert cgversion == '02'
1434 assert cgversion == '02'
1435 bversion = 'HG20'
1435 bversion = 'HG20'
1436
1436
1437
1437
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1438 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1439
1439
1440 @command('cat',
1440 @command('cat',
1441 [('o', 'output', '',
1441 [('o', 'output', '',
1442 _('print output to file with formatted name'), _('FORMAT')),
1442 _('print output to file with formatted name'), _('FORMAT')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1443 ('r', 'rev', '', _('print the given revision'), _('REV')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1444 ('', 'decode', None, _('apply any matching decode filter')),
1445 ] + walkopts,
1445 ] + walkopts,
1446 _('[OPTION]... FILE...'),
1446 _('[OPTION]... FILE...'),
1447 inferrepo=True)
1447 inferrepo=True)
1448 def cat(ui, repo, file1, *pats, **opts):
1448 def cat(ui, repo, file1, *pats, **opts):
1449 """output the current or given revision of files
1449 """output the current or given revision of files
1450
1450
1451 Print the specified files as they were at the given revision. If
1451 Print the specified files as they were at the given revision. If
1452 no revision is given, the parent of the working directory is used.
1452 no revision is given, the parent of the working directory is used.
1453
1453
1454 Output may be to a file, in which case the name of the file is
1454 Output may be to a file, in which case the name of the file is
1455 given using a format string. The formatting rules as follows:
1455 given using a format string. The formatting rules as follows:
1456
1456
1457 :``%%``: literal "%" character
1457 :``%%``: literal "%" character
1458 :``%s``: basename of file being printed
1458 :``%s``: basename of file being printed
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1459 :``%d``: dirname of file being printed, or '.' if in repository root
1460 :``%p``: root-relative path name of file being printed
1460 :``%p``: root-relative path name of file being printed
1461 :``%H``: changeset hash (40 hexadecimal digits)
1461 :``%H``: changeset hash (40 hexadecimal digits)
1462 :``%R``: changeset revision number
1462 :``%R``: changeset revision number
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1463 :``%h``: short-form changeset hash (12 hexadecimal digits)
1464 :``%r``: zero-padded changeset revision number
1464 :``%r``: zero-padded changeset revision number
1465 :``%b``: basename of the exporting repository
1465 :``%b``: basename of the exporting repository
1466
1466
1467 Returns 0 on success.
1467 Returns 0 on success.
1468 """
1468 """
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1469 ctx = scmutil.revsingle(repo, opts.get('rev'))
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1470 m = scmutil.match(ctx, (file1,) + pats, opts)
1471
1471
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1472 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1473
1473
1474 @command('^clone',
1474 @command('^clone',
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1475 [('U', 'noupdate', None, _('the clone will include an empty working '
1476 'directory (only a repository)')),
1476 'directory (only a repository)')),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1477 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1478 _('REV')),
1478 _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1479 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1480 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1481 ('', 'pull', None, _('use pull protocol to copy metadata')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1482 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1483 ] + remoteopts,
1483 ] + remoteopts,
1484 _('[OPTION]... SOURCE [DEST]'),
1484 _('[OPTION]... SOURCE [DEST]'),
1485 norepo=True)
1485 norepo=True)
1486 def clone(ui, source, dest=None, **opts):
1486 def clone(ui, source, dest=None, **opts):
1487 """make a copy of an existing repository
1487 """make a copy of an existing repository
1488
1488
1489 Create a copy of an existing repository in a new directory.
1489 Create a copy of an existing repository in a new directory.
1490
1490
1491 If no destination directory name is specified, it defaults to the
1491 If no destination directory name is specified, it defaults to the
1492 basename of the source.
1492 basename of the source.
1493
1493
1494 The location of the source is added to the new repository's
1494 The location of the source is added to the new repository's
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1495 ``.hg/hgrc`` file, as the default to be used for future pulls.
1496
1496
1497 Only local paths and ``ssh://`` URLs are supported as
1497 Only local paths and ``ssh://`` URLs are supported as
1498 destinations. For ``ssh://`` destinations, no working directory or
1498 destinations. For ``ssh://`` destinations, no working directory or
1499 ``.hg/hgrc`` will be created on the remote side.
1499 ``.hg/hgrc`` will be created on the remote side.
1500
1500
1501 If the source repository has a bookmark called '@' set, that
1501 If the source repository has a bookmark called '@' set, that
1502 revision will be checked out in the new repository by default.
1502 revision will be checked out in the new repository by default.
1503
1503
1504 To check out a particular version, use -u/--update, or
1504 To check out a particular version, use -u/--update, or
1505 -U/--noupdate to create a clone with no working directory.
1505 -U/--noupdate to create a clone with no working directory.
1506
1506
1507 To pull only a subset of changesets, specify one or more revisions
1507 To pull only a subset of changesets, specify one or more revisions
1508 identifiers with -r/--rev or branches with -b/--branch. The
1508 identifiers with -r/--rev or branches with -b/--branch. The
1509 resulting clone will contain only the specified changesets and
1509 resulting clone will contain only the specified changesets and
1510 their ancestors. These options (or 'clone src#rev dest') imply
1510 their ancestors. These options (or 'clone src#rev dest') imply
1511 --pull, even for local source repositories.
1511 --pull, even for local source repositories.
1512
1512
1513 .. note::
1513 .. note::
1514
1514
1515 Specifying a tag will include the tagged changeset but not the
1515 Specifying a tag will include the tagged changeset but not the
1516 changeset containing the tag.
1516 changeset containing the tag.
1517
1517
1518 .. container:: verbose
1518 .. container:: verbose
1519
1519
1520 For efficiency, hardlinks are used for cloning whenever the
1520 For efficiency, hardlinks are used for cloning whenever the
1521 source and destination are on the same filesystem (note this
1521 source and destination are on the same filesystem (note this
1522 applies only to the repository data, not to the working
1522 applies only to the repository data, not to the working
1523 directory). Some filesystems, such as AFS, implement hardlinking
1523 directory). Some filesystems, such as AFS, implement hardlinking
1524 incorrectly, but do not report errors. In these cases, use the
1524 incorrectly, but do not report errors. In these cases, use the
1525 --pull option to avoid hardlinking.
1525 --pull option to avoid hardlinking.
1526
1526
1527 In some cases, you can clone repositories and the working
1527 In some cases, you can clone repositories and the working
1528 directory using full hardlinks with ::
1528 directory using full hardlinks with ::
1529
1529
1530 $ cp -al REPO REPOCLONE
1530 $ cp -al REPO REPOCLONE
1531
1531
1532 This is the fastest way to clone, but it is not always safe. The
1532 This is the fastest way to clone, but it is not always safe. The
1533 operation is not atomic (making sure REPO is not modified during
1533 operation is not atomic (making sure REPO is not modified during
1534 the operation is up to you) and you have to make sure your
1534 the operation is up to you) and you have to make sure your
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1535 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1536 so). Also, this is not compatible with certain extensions that
1536 so). Also, this is not compatible with certain extensions that
1537 place their metadata under the .hg directory, such as mq.
1537 place their metadata under the .hg directory, such as mq.
1538
1538
1539 Mercurial will update the working directory to the first applicable
1539 Mercurial will update the working directory to the first applicable
1540 revision from this list:
1540 revision from this list:
1541
1541
1542 a) null if -U or the source repository has no changesets
1542 a) null if -U or the source repository has no changesets
1543 b) if -u . and the source repository is local, the first parent of
1543 b) if -u . and the source repository is local, the first parent of
1544 the source repository's working directory
1544 the source repository's working directory
1545 c) the changeset specified with -u (if a branch name, this means the
1545 c) the changeset specified with -u (if a branch name, this means the
1546 latest head of that branch)
1546 latest head of that branch)
1547 d) the changeset specified with -r
1547 d) the changeset specified with -r
1548 e) the tipmost head specified with -b
1548 e) the tipmost head specified with -b
1549 f) the tipmost head specified with the url#branch source syntax
1549 f) the tipmost head specified with the url#branch source syntax
1550 g) the revision marked with the '@' bookmark, if present
1550 g) the revision marked with the '@' bookmark, if present
1551 h) the tipmost head of the default branch
1551 h) the tipmost head of the default branch
1552 i) tip
1552 i) tip
1553
1553
1554 When cloning from servers that support it, Mercurial may fetch
1554 When cloning from servers that support it, Mercurial may fetch
1555 pre-generated data from a server-advertised URL. When this is done,
1555 pre-generated data from a server-advertised URL. When this is done,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1556 hooks operating on incoming changesets and changegroups may fire twice,
1557 once for the bundle fetched from the URL and another for any additional
1557 once for the bundle fetched from the URL and another for any additional
1558 data not fetched from this URL. In addition, if an error occurs, the
1558 data not fetched from this URL. In addition, if an error occurs, the
1559 repository may be rolled back to a partial clone. This behavior may
1559 repository may be rolled back to a partial clone. This behavior may
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1560 change in future releases. See :hg:`help -e clonebundles` for more.
1561
1561
1562 Examples:
1562 Examples:
1563
1563
1564 - clone a remote repository to a new directory named hg/::
1564 - clone a remote repository to a new directory named hg/::
1565
1565
1566 hg clone http://selenic.com/hg
1566 hg clone http://selenic.com/hg
1567
1567
1568 - create a lightweight local clone::
1568 - create a lightweight local clone::
1569
1569
1570 hg clone project/ project-feature/
1570 hg clone project/ project-feature/
1571
1571
1572 - clone from an absolute path on an ssh server (note double-slash)::
1572 - clone from an absolute path on an ssh server (note double-slash)::
1573
1573
1574 hg clone ssh://user@server//home/projects/alpha/
1574 hg clone ssh://user@server//home/projects/alpha/
1575
1575
1576 - do a high-speed clone over a LAN while checking out a
1576 - do a high-speed clone over a LAN while checking out a
1577 specified version::
1577 specified version::
1578
1578
1579 hg clone --uncompressed http://server/repo -u 1.5
1579 hg clone --uncompressed http://server/repo -u 1.5
1580
1580
1581 - create a repository without changesets after a particular revision::
1581 - create a repository without changesets after a particular revision::
1582
1582
1583 hg clone -r 04e544 experimental/ good/
1583 hg clone -r 04e544 experimental/ good/
1584
1584
1585 - clone (and track) a particular named branch::
1585 - clone (and track) a particular named branch::
1586
1586
1587 hg clone http://selenic.com/hg#stable
1587 hg clone http://selenic.com/hg#stable
1588
1588
1589 See :hg:`help urls` for details on specifying URLs.
1589 See :hg:`help urls` for details on specifying URLs.
1590
1590
1591 Returns 0 on success.
1591 Returns 0 on success.
1592 """
1592 """
1593 if opts.get('noupdate') and opts.get('updaterev'):
1593 if opts.get('noupdate') and opts.get('updaterev'):
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1594 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1595
1595
1596 r = hg.clone(ui, opts, source, dest,
1596 r = hg.clone(ui, opts, source, dest,
1597 pull=opts.get('pull'),
1597 pull=opts.get('pull'),
1598 stream=opts.get('uncompressed'),
1598 stream=opts.get('uncompressed'),
1599 rev=opts.get('rev'),
1599 rev=opts.get('rev'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1600 update=opts.get('updaterev') or not opts.get('noupdate'),
1601 branch=opts.get('branch'),
1601 branch=opts.get('branch'),
1602 shareopts=opts.get('shareopts'))
1602 shareopts=opts.get('shareopts'))
1603
1603
1604 return r is None
1604 return r is None
1605
1605
1606 @command('^commit|ci',
1606 @command('^commit|ci',
1607 [('A', 'addremove', None,
1607 [('A', 'addremove', None,
1608 _('mark new/missing files as added/removed before committing')),
1608 _('mark new/missing files as added/removed before committing')),
1609 ('', 'close-branch', None,
1609 ('', 'close-branch', None,
1610 _('mark a branch head as closed')),
1610 _('mark a branch head as closed')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1611 ('', 'amend', None, _('amend the parent of the working directory')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1612 ('s', 'secret', None, _('use the secret phase for committing')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1613 ('e', 'edit', None, _('invoke editor on commit messages')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1614 ('i', 'interactive', None, _('use interactive mode')),
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1615 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1616 _('[OPTION]... [FILE]...'),
1616 _('[OPTION]... [FILE]...'),
1617 inferrepo=True)
1617 inferrepo=True)
1618 def commit(ui, repo, *pats, **opts):
1618 def commit(ui, repo, *pats, **opts):
1619 """commit the specified files or all outstanding changes
1619 """commit the specified files or all outstanding changes
1620
1620
1621 Commit changes to the given files into the repository. Unlike a
1621 Commit changes to the given files into the repository. Unlike a
1622 centralized SCM, this operation is a local operation. See
1622 centralized SCM, this operation is a local operation. See
1623 :hg:`push` for a way to actively distribute your changes.
1623 :hg:`push` for a way to actively distribute your changes.
1624
1624
1625 If a list of files is omitted, all changes reported by :hg:`status`
1625 If a list of files is omitted, all changes reported by :hg:`status`
1626 will be committed.
1626 will be committed.
1627
1627
1628 If you are committing the result of a merge, do not provide any
1628 If you are committing the result of a merge, do not provide any
1629 filenames or -I/-X filters.
1629 filenames or -I/-X filters.
1630
1630
1631 If no commit message is specified, Mercurial starts your
1631 If no commit message is specified, Mercurial starts your
1632 configured editor where you can enter a message. In case your
1632 configured editor where you can enter a message. In case your
1633 commit fails, you will find a backup of your message in
1633 commit fails, you will find a backup of your message in
1634 ``.hg/last-message.txt``.
1634 ``.hg/last-message.txt``.
1635
1635
1636 The --close-branch flag can be used to mark the current branch
1636 The --close-branch flag can be used to mark the current branch
1637 head closed. When all heads of a branch are closed, the branch
1637 head closed. When all heads of a branch are closed, the branch
1638 will be considered closed and no longer listed.
1638 will be considered closed and no longer listed.
1639
1639
1640 The --amend flag can be used to amend the parent of the
1640 The --amend flag can be used to amend the parent of the
1641 working directory with a new commit that contains the changes
1641 working directory with a new commit that contains the changes
1642 in the parent in addition to those currently reported by :hg:`status`,
1642 in the parent in addition to those currently reported by :hg:`status`,
1643 if there are any. The old commit is stored in a backup bundle in
1643 if there are any. The old commit is stored in a backup bundle in
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1644 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1645 on how to restore it).
1645 on how to restore it).
1646
1646
1647 Message, user and date are taken from the amended commit unless
1647 Message, user and date are taken from the amended commit unless
1648 specified. When a message isn't specified on the command line,
1648 specified. When a message isn't specified on the command line,
1649 the editor will open with the message of the amended commit.
1649 the editor will open with the message of the amended commit.
1650
1650
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1651 It is not possible to amend public changesets (see :hg:`help phases`)
1652 or changesets that have children.
1652 or changesets that have children.
1653
1653
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1654 See :hg:`help dates` for a list of formats valid for -d/--date.
1655
1655
1656 Returns 0 on success, 1 if nothing changed.
1656 Returns 0 on success, 1 if nothing changed.
1657
1657
1658 .. container:: verbose
1658 .. container:: verbose
1659
1659
1660 Examples:
1660 Examples:
1661
1661
1662 - commit all files ending in .py::
1662 - commit all files ending in .py::
1663
1663
1664 hg commit --include "set:**.py"
1664 hg commit --include "set:**.py"
1665
1665
1666 - commit all non-binary files::
1666 - commit all non-binary files::
1667
1667
1668 hg commit --exclude "set:binary()"
1668 hg commit --exclude "set:binary()"
1669
1669
1670 - amend the current commit and set the date to now::
1670 - amend the current commit and set the date to now::
1671
1671
1672 hg commit --amend --date now
1672 hg commit --amend --date now
1673 """
1673 """
1674 wlock = lock = None
1674 wlock = lock = None
1675 try:
1675 try:
1676 wlock = repo.wlock()
1676 wlock = repo.wlock()
1677 lock = repo.lock()
1677 lock = repo.lock()
1678 return _docommit(ui, repo, *pats, **opts)
1678 return _docommit(ui, repo, *pats, **opts)
1679 finally:
1679 finally:
1680 release(lock, wlock)
1680 release(lock, wlock)
1681
1681
1682 def _docommit(ui, repo, *pats, **opts):
1682 def _docommit(ui, repo, *pats, **opts):
1683 if opts.get('interactive'):
1683 if opts.get('interactive'):
1684 opts.pop('interactive')
1684 opts.pop('interactive')
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1685 cmdutil.dorecord(ui, repo, commit, None, False,
1686 cmdutil.recordfilter, *pats, **opts)
1686 cmdutil.recordfilter, *pats, **opts)
1687 return
1687 return
1688
1688
1689 if opts.get('subrepos'):
1689 if opts.get('subrepos'):
1690 if opts.get('amend'):
1690 if opts.get('amend'):
1691 raise error.Abort(_('cannot amend with --subrepos'))
1691 raise error.Abort(_('cannot amend with --subrepos'))
1692 # Let --subrepos on the command line override config setting.
1692 # Let --subrepos on the command line override config setting.
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1693 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1694
1694
1695 cmdutil.checkunfinished(repo, commit=True)
1695 cmdutil.checkunfinished(repo, commit=True)
1696
1696
1697 branch = repo[None].branch()
1697 branch = repo[None].branch()
1698 bheads = repo.branchheads(branch)
1698 bheads = repo.branchheads(branch)
1699
1699
1700 extra = {}
1700 extra = {}
1701 if opts.get('close_branch'):
1701 if opts.get('close_branch'):
1702 extra['close'] = 1
1702 extra['close'] = 1
1703
1703
1704 if not bheads:
1704 if not bheads:
1705 raise error.Abort(_('can only close branch heads'))
1705 raise error.Abort(_('can only close branch heads'))
1706 elif opts.get('amend'):
1706 elif opts.get('amend'):
1707 if repo[None].parents()[0].p1().branch() != branch and \
1707 if repo[None].parents()[0].p1().branch() != branch and \
1708 repo[None].parents()[0].p2().branch() != branch:
1708 repo[None].parents()[0].p2().branch() != branch:
1709 raise error.Abort(_('can only close branch heads'))
1709 raise error.Abort(_('can only close branch heads'))
1710
1710
1711 if opts.get('amend'):
1711 if opts.get('amend'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1712 if ui.configbool('ui', 'commitsubrepos'):
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1713 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1714
1714
1715 old = repo['.']
1715 old = repo['.']
1716 if not old.mutable():
1716 if not old.mutable():
1717 raise error.Abort(_('cannot amend public changesets'))
1717 raise error.Abort(_('cannot amend public changesets'))
1718 if len(repo[None].parents()) > 1:
1718 if len(repo[None].parents()) > 1:
1719 raise error.Abort(_('cannot amend while merging'))
1719 raise error.Abort(_('cannot amend while merging'))
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1720 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1721 if not allowunstable and old.children():
1721 if not allowunstable and old.children():
1722 raise error.Abort(_('cannot amend changeset with children'))
1722 raise error.Abort(_('cannot amend changeset with children'))
1723
1723
1724 # Currently histedit gets confused if an amend happens while histedit
1724 # Currently histedit gets confused if an amend happens while histedit
1725 # is in progress. Since we have a checkunfinished command, we are
1725 # is in progress. Since we have a checkunfinished command, we are
1726 # temporarily honoring it.
1726 # temporarily honoring it.
1727 #
1727 #
1728 # Note: eventually this guard will be removed. Please do not expect
1728 # Note: eventually this guard will be removed. Please do not expect
1729 # this behavior to remain.
1729 # this behavior to remain.
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1730 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1731 cmdutil.checkunfinished(repo)
1731 cmdutil.checkunfinished(repo)
1732
1732
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1733 # commitfunc is used only for temporary amend commit by cmdutil.amend
1734 def commitfunc(ui, repo, message, match, opts):
1734 def commitfunc(ui, repo, message, match, opts):
1735 return repo.commit(message,
1735 return repo.commit(message,
1736 opts.get('user') or old.user(),
1736 opts.get('user') or old.user(),
1737 opts.get('date') or old.date(),
1737 opts.get('date') or old.date(),
1738 match,
1738 match,
1739 extra=extra)
1739 extra=extra)
1740
1740
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1741 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1742 if node == old.node():
1742 if node == old.node():
1743 ui.status(_("nothing changed\n"))
1743 ui.status(_("nothing changed\n"))
1744 return 1
1744 return 1
1745 else:
1745 else:
1746 def commitfunc(ui, repo, message, match, opts):
1746 def commitfunc(ui, repo, message, match, opts):
1747 backup = ui.backupconfig('phases', 'new-commit')
1747 backup = ui.backupconfig('phases', 'new-commit')
1748 baseui = repo.baseui
1748 baseui = repo.baseui
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1749 basebackup = baseui.backupconfig('phases', 'new-commit')
1750 try:
1750 try:
1751 if opts.get('secret'):
1751 if opts.get('secret'):
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1752 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1753 # Propagate to subrepos
1753 # Propagate to subrepos
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1754 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755
1755
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1756 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1758 return repo.commit(message, opts.get('user'), opts.get('date'),
1759 match,
1759 match,
1760 editor=editor,
1760 editor=editor,
1761 extra=extra)
1761 extra=extra)
1762 finally:
1762 finally:
1763 ui.restoreconfig(backup)
1763 ui.restoreconfig(backup)
1764 repo.baseui.restoreconfig(basebackup)
1764 repo.baseui.restoreconfig(basebackup)
1765
1765
1766
1766
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1767 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1768
1768
1769 if not node:
1769 if not node:
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1770 stat = cmdutil.postcommitstatus(repo, pats, opts)
1771 if stat[3]:
1771 if stat[3]:
1772 ui.status(_("nothing changed (%d missing files, see "
1772 ui.status(_("nothing changed (%d missing files, see "
1773 "'hg status')\n") % len(stat[3]))
1773 "'hg status')\n") % len(stat[3]))
1774 else:
1774 else:
1775 ui.status(_("nothing changed\n"))
1775 ui.status(_("nothing changed\n"))
1776 return 1
1776 return 1
1777
1777
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1778 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1779
1779
1780 @command('config|showconfig|debugconfig',
1780 @command('config|showconfig|debugconfig',
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1781 [('u', 'untrusted', None, _('show untrusted configuration options')),
1782 ('e', 'edit', None, _('edit user config')),
1782 ('e', 'edit', None, _('edit user config')),
1783 ('l', 'local', None, _('edit repository config')),
1783 ('l', 'local', None, _('edit repository config')),
1784 ('g', 'global', None, _('edit global config'))],
1784 ('g', 'global', None, _('edit global config'))],
1785 _('[-u] [NAME]...'),
1785 _('[-u] [NAME]...'),
1786 optionalrepo=True)
1786 optionalrepo=True)
1787 def config(ui, repo, *values, **opts):
1787 def config(ui, repo, *values, **opts):
1788 """show combined config settings from all hgrc files
1788 """show combined config settings from all hgrc files
1789
1789
1790 With no arguments, print names and values of all config items.
1790 With no arguments, print names and values of all config items.
1791
1791
1792 With one argument of the form section.name, print just the value
1792 With one argument of the form section.name, print just the value
1793 of that config item.
1793 of that config item.
1794
1794
1795 With multiple arguments, print names and values of all config
1795 With multiple arguments, print names and values of all config
1796 items with matching section names.
1796 items with matching section names.
1797
1797
1798 With --edit, start an editor on the user-level config file. With
1798 With --edit, start an editor on the user-level config file. With
1799 --global, edit the system-wide config file. With --local, edit the
1799 --global, edit the system-wide config file. With --local, edit the
1800 repository-level config file.
1800 repository-level config file.
1801
1801
1802 With --debug, the source (filename and line number) is printed
1802 With --debug, the source (filename and line number) is printed
1803 for each config item.
1803 for each config item.
1804
1804
1805 See :hg:`help config` for more information about config files.
1805 See :hg:`help config` for more information about config files.
1806
1806
1807 Returns 0 on success, 1 if NAME does not exist.
1807 Returns 0 on success, 1 if NAME does not exist.
1808
1808
1809 """
1809 """
1810
1810
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1811 if opts.get('edit') or opts.get('local') or opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1812 if opts.get('local') and opts.get('global'):
1813 raise error.Abort(_("can't use --local and --global together"))
1813 raise error.Abort(_("can't use --local and --global together"))
1814
1814
1815 if opts.get('local'):
1815 if opts.get('local'):
1816 if not repo:
1816 if not repo:
1817 raise error.Abort(_("can't use --local outside a repository"))
1817 raise error.Abort(_("can't use --local outside a repository"))
1818 paths = [repo.join('hgrc')]
1818 paths = [repo.join('hgrc')]
1819 elif opts.get('global'):
1819 elif opts.get('global'):
1820 paths = scmutil.systemrcpath()
1820 paths = scmutil.systemrcpath()
1821 else:
1821 else:
1822 paths = scmutil.userrcpath()
1822 paths = scmutil.userrcpath()
1823
1823
1824 for f in paths:
1824 for f in paths:
1825 if os.path.exists(f):
1825 if os.path.exists(f):
1826 break
1826 break
1827 else:
1827 else:
1828 if opts.get('global'):
1828 if opts.get('global'):
1829 samplehgrc = uimod.samplehgrcs['global']
1829 samplehgrc = uimod.samplehgrcs['global']
1830 elif opts.get('local'):
1830 elif opts.get('local'):
1831 samplehgrc = uimod.samplehgrcs['local']
1831 samplehgrc = uimod.samplehgrcs['local']
1832 else:
1832 else:
1833 samplehgrc = uimod.samplehgrcs['user']
1833 samplehgrc = uimod.samplehgrcs['user']
1834
1834
1835 f = paths[0]
1835 f = paths[0]
1836 fp = open(f, "w")
1836 fp = open(f, "w")
1837 fp.write(samplehgrc)
1837 fp.write(samplehgrc)
1838 fp.close()
1838 fp.close()
1839
1839
1840 editor = ui.geteditor()
1840 editor = ui.geteditor()
1841 ui.system("%s \"%s\"" % (editor, f),
1841 ui.system("%s \"%s\"" % (editor, f),
1842 onerr=error.Abort, errprefix=_("edit failed"))
1842 onerr=error.Abort, errprefix=_("edit failed"))
1843 return
1843 return
1844
1844
1845 for f in scmutil.rcpath():
1845 for f in scmutil.rcpath():
1846 ui.debug('read config from: %s\n' % f)
1846 ui.debug('read config from: %s\n' % f)
1847 untrusted = bool(opts.get('untrusted'))
1847 untrusted = bool(opts.get('untrusted'))
1848 if values:
1848 if values:
1849 sections = [v for v in values if '.' not in v]
1849 sections = [v for v in values if '.' not in v]
1850 items = [v for v in values if '.' in v]
1850 items = [v for v in values if '.' in v]
1851 if len(items) > 1 or items and sections:
1851 if len(items) > 1 or items and sections:
1852 raise error.Abort(_('only one config item permitted'))
1852 raise error.Abort(_('only one config item permitted'))
1853 matched = False
1853 matched = False
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1854 for section, name, value in ui.walkconfig(untrusted=untrusted):
1855 value = str(value).replace('\n', '\\n')
1855 value = str(value).replace('\n', '\\n')
1856 sectname = section + '.' + name
1856 sectname = section + '.' + name
1857 if values:
1857 if values:
1858 for v in values:
1858 for v in values:
1859 if v == section:
1859 if v == section:
1860 ui.debug('%s: ' %
1860 ui.debug('%s: ' %
1861 ui.configsource(section, name, untrusted))
1861 ui.configsource(section, name, untrusted))
1862 ui.write('%s=%s\n' % (sectname, value))
1862 ui.write('%s=%s\n' % (sectname, value))
1863 matched = True
1863 matched = True
1864 elif v == sectname:
1864 elif v == sectname:
1865 ui.debug('%s: ' %
1865 ui.debug('%s: ' %
1866 ui.configsource(section, name, untrusted))
1866 ui.configsource(section, name, untrusted))
1867 ui.write(value, '\n')
1867 ui.write(value, '\n')
1868 matched = True
1868 matched = True
1869 else:
1869 else:
1870 ui.debug('%s: ' %
1870 ui.debug('%s: ' %
1871 ui.configsource(section, name, untrusted))
1871 ui.configsource(section, name, untrusted))
1872 ui.write('%s=%s\n' % (sectname, value))
1872 ui.write('%s=%s\n' % (sectname, value))
1873 matched = True
1873 matched = True
1874 if matched:
1874 if matched:
1875 return 0
1875 return 0
1876 return 1
1876 return 1
1877
1877
1878 @command('copy|cp',
1878 @command('copy|cp',
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1879 [('A', 'after', None, _('record a copy that has already occurred')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1880 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1881 ] + walkopts + dryrunopts,
1881 ] + walkopts + dryrunopts,
1882 _('[OPTION]... [SOURCE]... DEST'))
1882 _('[OPTION]... [SOURCE]... DEST'))
1883 def copy(ui, repo, *pats, **opts):
1883 def copy(ui, repo, *pats, **opts):
1884 """mark files as copied for the next commit
1884 """mark files as copied for the next commit
1885
1885
1886 Mark dest as having copies of source files. If dest is a
1886 Mark dest as having copies of source files. If dest is a
1887 directory, copies are put in that directory. If dest is a file,
1887 directory, copies are put in that directory. If dest is a file,
1888 the source must be a single file.
1888 the source must be a single file.
1889
1889
1890 By default, this command copies the contents of files as they
1890 By default, this command copies the contents of files as they
1891 exist in the working directory. If invoked with -A/--after, the
1891 exist in the working directory. If invoked with -A/--after, the
1892 operation is recorded, but no copying is performed.
1892 operation is recorded, but no copying is performed.
1893
1893
1894 This command takes effect with the next commit. To undo a copy
1894 This command takes effect with the next commit. To undo a copy
1895 before that, see :hg:`revert`.
1895 before that, see :hg:`revert`.
1896
1896
1897 Returns 0 on success, 1 if errors are encountered.
1897 Returns 0 on success, 1 if errors are encountered.
1898 """
1898 """
1899 with repo.wlock(False):
1899 with repo.wlock(False):
1900 return cmdutil.copy(ui, repo, pats, opts)
1900 return cmdutil.copy(ui, repo, pats, opts)
1901
1901
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1902 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1903 def debugancestor(ui, repo, *args):
1903 def debugancestor(ui, repo, *args):
1904 """find the ancestor revision of two revisions in a given index"""
1904 """find the ancestor revision of two revisions in a given index"""
1905 if len(args) == 3:
1905 if len(args) == 3:
1906 index, rev1, rev2 = args
1906 index, rev1, rev2 = args
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1907 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1908 lookup = r.lookup
1908 lookup = r.lookup
1909 elif len(args) == 2:
1909 elif len(args) == 2:
1910 if not repo:
1910 if not repo:
1911 raise error.Abort(_("there is no Mercurial repository here "
1911 raise error.Abort(_("there is no Mercurial repository here "
1912 "(.hg not found)"))
1912 "(.hg not found)"))
1913 rev1, rev2 = args
1913 rev1, rev2 = args
1914 r = repo.changelog
1914 r = repo.changelog
1915 lookup = repo.lookup
1915 lookup = repo.lookup
1916 else:
1916 else:
1917 raise error.Abort(_('either two or three arguments required'))
1917 raise error.Abort(_('either two or three arguments required'))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1918 a = r.ancestor(lookup(rev1), lookup(rev2))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1919 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1920
1920
1921 @command('debugbuilddag',
1921 @command('debugbuilddag',
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1922 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1923 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1924 ('n', 'new-file', None, _('add new file at each rev'))],
1925 _('[OPTION]... [TEXT]'))
1925 _('[OPTION]... [TEXT]'))
1926 def debugbuilddag(ui, repo, text=None,
1926 def debugbuilddag(ui, repo, text=None,
1927 mergeable_file=False,
1927 mergeable_file=False,
1928 overwritten_file=False,
1928 overwritten_file=False,
1929 new_file=False):
1929 new_file=False):
1930 """builds a repo with a given DAG from scratch in the current empty repo
1930 """builds a repo with a given DAG from scratch in the current empty repo
1931
1931
1932 The description of the DAG is read from stdin if not given on the
1932 The description of the DAG is read from stdin if not given on the
1933 command line.
1933 command line.
1934
1934
1935 Elements:
1935 Elements:
1936
1936
1937 - "+n" is a linear run of n nodes based on the current default parent
1937 - "+n" is a linear run of n nodes based on the current default parent
1938 - "." is a single node based on the current default parent
1938 - "." is a single node based on the current default parent
1939 - "$" resets the default parent to null (implied at the start);
1939 - "$" resets the default parent to null (implied at the start);
1940 otherwise the default parent is always the last node created
1940 otherwise the default parent is always the last node created
1941 - "<p" sets the default parent to the backref p
1941 - "<p" sets the default parent to the backref p
1942 - "*p" is a fork at parent p, which is a backref
1942 - "*p" is a fork at parent p, which is a backref
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1943 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1944 - "/p2" is a merge of the preceding node and p2
1944 - "/p2" is a merge of the preceding node and p2
1945 - ":tag" defines a local tag for the preceding node
1945 - ":tag" defines a local tag for the preceding node
1946 - "@branch" sets the named branch for subsequent nodes
1946 - "@branch" sets the named branch for subsequent nodes
1947 - "#...\\n" is a comment up to the end of the line
1947 - "#...\\n" is a comment up to the end of the line
1948
1948
1949 Whitespace between the above elements is ignored.
1949 Whitespace between the above elements is ignored.
1950
1950
1951 A backref is either
1951 A backref is either
1952
1952
1953 - a number n, which references the node curr-n, where curr is the current
1953 - a number n, which references the node curr-n, where curr is the current
1954 node, or
1954 node, or
1955 - the name of a local tag you placed earlier using ":tag", or
1955 - the name of a local tag you placed earlier using ":tag", or
1956 - empty to denote the default parent.
1956 - empty to denote the default parent.
1957
1957
1958 All string valued-elements are either strictly alphanumeric, or must
1958 All string valued-elements are either strictly alphanumeric, or must
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1959 be enclosed in double quotes ("..."), with "\\" as escape character.
1960 """
1960 """
1961
1961
1962 if text is None:
1962 if text is None:
1963 ui.status(_("reading DAG from stdin\n"))
1963 ui.status(_("reading DAG from stdin\n"))
1964 text = ui.fin.read()
1964 text = ui.fin.read()
1965
1965
1966 cl = repo.changelog
1966 cl = repo.changelog
1967 if len(cl) > 0:
1967 if len(cl) > 0:
1968 raise error.Abort(_('repository is not empty'))
1968 raise error.Abort(_('repository is not empty'))
1969
1969
1970 # determine number of revs in DAG
1970 # determine number of revs in DAG
1971 total = 0
1971 total = 0
1972 for type, data in dagparser.parsedag(text):
1972 for type, data in dagparser.parsedag(text):
1973 if type == 'n':
1973 if type == 'n':
1974 total += 1
1974 total += 1
1975
1975
1976 if mergeable_file:
1976 if mergeable_file:
1977 linesperrev = 2
1977 linesperrev = 2
1978 # make a file with k lines per rev
1978 # make a file with k lines per rev
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1979 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1980 initialmergedlines.append("")
1980 initialmergedlines.append("")
1981
1981
1982 tags = []
1982 tags = []
1983
1983
1984 lock = tr = None
1984 lock = tr = None
1985 try:
1985 try:
1986 lock = repo.lock()
1986 lock = repo.lock()
1987 tr = repo.transaction("builddag")
1987 tr = repo.transaction("builddag")
1988
1988
1989 at = -1
1989 at = -1
1990 atbranch = 'default'
1990 atbranch = 'default'
1991 nodeids = []
1991 nodeids = []
1992 id = 0
1992 id = 0
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1993 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1994 for type, data in dagparser.parsedag(text):
1994 for type, data in dagparser.parsedag(text):
1995 if type == 'n':
1995 if type == 'n':
1996 ui.note(('node %s\n' % str(data)))
1996 ui.note(('node %s\n' % str(data)))
1997 id, ps = data
1997 id, ps = data
1998
1998
1999 files = []
1999 files = []
2000 fctxs = {}
2000 fctxs = {}
2001
2001
2002 p2 = None
2002 p2 = None
2003 if mergeable_file:
2003 if mergeable_file:
2004 fn = "mf"
2004 fn = "mf"
2005 p1 = repo[ps[0]]
2005 p1 = repo[ps[0]]
2006 if len(ps) > 1:
2006 if len(ps) > 1:
2007 p2 = repo[ps[1]]
2007 p2 = repo[ps[1]]
2008 pa = p1.ancestor(p2)
2008 pa = p1.ancestor(p2)
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2009 base, local, other = [x[fn].data() for x in (pa, p1,
2010 p2)]
2010 p2)]
2011 m3 = simplemerge.Merge3Text(base, local, other)
2011 m3 = simplemerge.Merge3Text(base, local, other)
2012 ml = [l.strip() for l in m3.merge_lines()]
2012 ml = [l.strip() for l in m3.merge_lines()]
2013 ml.append("")
2013 ml.append("")
2014 elif at > 0:
2014 elif at > 0:
2015 ml = p1[fn].data().split("\n")
2015 ml = p1[fn].data().split("\n")
2016 else:
2016 else:
2017 ml = initialmergedlines
2017 ml = initialmergedlines
2018 ml[id * linesperrev] += " r%i" % id
2018 ml[id * linesperrev] += " r%i" % id
2019 mergedtext = "\n".join(ml)
2019 mergedtext = "\n".join(ml)
2020 files.append(fn)
2020 files.append(fn)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2021 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2022
2022
2023 if overwritten_file:
2023 if overwritten_file:
2024 fn = "of"
2024 fn = "of"
2025 files.append(fn)
2025 files.append(fn)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2026 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2027
2027
2028 if new_file:
2028 if new_file:
2029 fn = "nf%i" % id
2029 fn = "nf%i" % id
2030 files.append(fn)
2030 files.append(fn)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2032 if len(ps) > 1:
2032 if len(ps) > 1:
2033 if not p2:
2033 if not p2:
2034 p2 = repo[ps[1]]
2034 p2 = repo[ps[1]]
2035 for fn in p2:
2035 for fn in p2:
2036 if fn.startswith("nf"):
2036 if fn.startswith("nf"):
2037 files.append(fn)
2037 files.append(fn)
2038 fctxs[fn] = p2[fn]
2038 fctxs[fn] = p2[fn]
2039
2039
2040 def fctxfn(repo, cx, path):
2040 def fctxfn(repo, cx, path):
2041 return fctxs.get(path)
2041 return fctxs.get(path)
2042
2042
2043 if len(ps) == 0 or ps[0] < 0:
2043 if len(ps) == 0 or ps[0] < 0:
2044 pars = [None, None]
2044 pars = [None, None]
2045 elif len(ps) == 1:
2045 elif len(ps) == 1:
2046 pars = [nodeids[ps[0]], None]
2046 pars = [nodeids[ps[0]], None]
2047 else:
2047 else:
2048 pars = [nodeids[p] for p in ps]
2048 pars = [nodeids[p] for p in ps]
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2049 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2050 date=(id, 0),
2050 date=(id, 0),
2051 user="debugbuilddag",
2051 user="debugbuilddag",
2052 extra={'branch': atbranch})
2052 extra={'branch': atbranch})
2053 nodeid = repo.commitctx(cx)
2053 nodeid = repo.commitctx(cx)
2054 nodeids.append(nodeid)
2054 nodeids.append(nodeid)
2055 at = id
2055 at = id
2056 elif type == 'l':
2056 elif type == 'l':
2057 id, name = data
2057 id, name = data
2058 ui.note(('tag %s\n' % name))
2058 ui.note(('tag %s\n' % name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2059 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2060 elif type == 'a':
2060 elif type == 'a':
2061 ui.note(('branch %s\n' % data))
2061 ui.note(('branch %s\n' % data))
2062 atbranch = data
2062 atbranch = data
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2063 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2064 tr.close()
2064 tr.close()
2065
2065
2066 if tags:
2066 if tags:
2067 repo.vfs.write("localtags", "".join(tags))
2067 repo.vfs.write("localtags", "".join(tags))
2068 finally:
2068 finally:
2069 ui.progress(_('building'), None)
2069 ui.progress(_('building'), None)
2070 release(tr, lock)
2070 release(tr, lock)
2071
2071
2072 @command('debugbundle',
2072 @command('debugbundle',
2073 [('a', 'all', None, _('show all details')),
2073 [('a', 'all', None, _('show all details')),
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2074 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2075 _('FILE'),
2075 _('FILE'),
2076 norepo=True)
2076 norepo=True)
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2077 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2078 """lists the contents of a bundle"""
2078 """lists the contents of a bundle"""
2079 with hg.openpath(ui, bundlepath) as f:
2079 with hg.openpath(ui, bundlepath) as f:
2080 if spec:
2080 if spec:
2081 spec = exchange.getbundlespec(ui, f)
2081 spec = exchange.getbundlespec(ui, f)
2082 ui.write('%s\n' % spec)
2082 ui.write('%s\n' % spec)
2083 return
2083 return
2084
2084
2085 gen = exchange.readbundle(ui, f, bundlepath)
2085 gen = exchange.readbundle(ui, f, bundlepath)
2086 if isinstance(gen, bundle2.unbundle20):
2086 if isinstance(gen, bundle2.unbundle20):
2087 return _debugbundle2(ui, gen, all=all, **opts)
2087 return _debugbundle2(ui, gen, all=all, **opts)
2088 if all:
2088 if all:
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2089 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2090
2090
2091 def showchunks(named):
2091 def showchunks(named):
2092 ui.write("\n%s\n" % named)
2092 ui.write("\n%s\n" % named)
2093 chain = None
2093 chain = None
2094 while True:
2094 while True:
2095 chunkdata = gen.deltachunk(chain)
2095 chunkdata = gen.deltachunk(chain)
2096 if not chunkdata:
2096 if not chunkdata:
2097 break
2097 break
2098 node = chunkdata['node']
2098 node = chunkdata['node']
2099 p1 = chunkdata['p1']
2099 p1 = chunkdata['p1']
2100 p2 = chunkdata['p2']
2100 p2 = chunkdata['p2']
2101 cs = chunkdata['cs']
2101 cs = chunkdata['cs']
2102 deltabase = chunkdata['deltabase']
2102 deltabase = chunkdata['deltabase']
2103 delta = chunkdata['delta']
2103 delta = chunkdata['delta']
2104 ui.write("%s %s %s %s %s %s\n" %
2104 ui.write("%s %s %s %s %s %s\n" %
2105 (hex(node), hex(p1), hex(p2),
2105 (hex(node), hex(p1), hex(p2),
2106 hex(cs), hex(deltabase), len(delta)))
2106 hex(cs), hex(deltabase), len(delta)))
2107 chain = node
2107 chain = node
2108
2108
2109 chunkdata = gen.changelogheader()
2109 chunkdata = gen.changelogheader()
2110 showchunks("changelog")
2110 showchunks("changelog")
2111 chunkdata = gen.manifestheader()
2111 chunkdata = gen.manifestheader()
2112 showchunks("manifest")
2112 showchunks("manifest")
2113 while True:
2113 while True:
2114 chunkdata = gen.filelogheader()
2114 chunkdata = gen.filelogheader()
2115 if not chunkdata:
2115 if not chunkdata:
2116 break
2116 break
2117 fname = chunkdata['filename']
2117 fname = chunkdata['filename']
2118 showchunks(fname)
2118 showchunks(fname)
2119 else:
2119 else:
2120 if isinstance(gen, bundle2.unbundle20):
2120 if isinstance(gen, bundle2.unbundle20):
2121 raise error.Abort(_('use debugbundle2 for this file'))
2121 raise error.Abort(_('use debugbundle2 for this file'))
2122 chunkdata = gen.changelogheader()
2122 chunkdata = gen.changelogheader()
2123 chain = None
2123 chain = None
2124 while True:
2124 while True:
2125 chunkdata = gen.deltachunk(chain)
2125 chunkdata = gen.deltachunk(chain)
2126 if not chunkdata:
2126 if not chunkdata:
2127 break
2127 break
2128 node = chunkdata['node']
2128 node = chunkdata['node']
2129 ui.write("%s\n" % hex(node))
2129 ui.write("%s\n" % hex(node))
2130 chain = node
2130 chain = node
2131
2131
2132 def _debugbundle2(ui, gen, **opts):
2132 def _debugbundle2(ui, gen, **opts):
2133 """lists the contents of a bundle2"""
2133 """lists the contents of a bundle2"""
2134 if not isinstance(gen, bundle2.unbundle20):
2134 if not isinstance(gen, bundle2.unbundle20):
2135 raise error.Abort(_('not a bundle2 file'))
2135 raise error.Abort(_('not a bundle2 file'))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2136 ui.write(('Stream params: %s\n' % repr(gen.params)))
2137 for part in gen.iterparts():
2137 for part in gen.iterparts():
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2138 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2139 if part.type == 'changegroup':
2139 if part.type == 'changegroup':
2140 version = part.params.get('version', '01')
2140 version = part.params.get('version', '01')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2141 cg = changegroup.getunbundler(version, part, 'UN')
2142 chunkdata = cg.changelogheader()
2142 chunkdata = cg.changelogheader()
2143 chain = None
2143 chain = None
2144 while True:
2144 while True:
2145 chunkdata = cg.deltachunk(chain)
2145 chunkdata = cg.deltachunk(chain)
2146 if not chunkdata:
2146 if not chunkdata:
2147 break
2147 break
2148 node = chunkdata['node']
2148 node = chunkdata['node']
2149 ui.write(" %s\n" % hex(node))
2149 ui.write(" %s\n" % hex(node))
2150 chain = node
2150 chain = node
2151
2151
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2152 @command('debugcreatestreamclonebundle', [], 'FILE')
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2153 def debugcreatestreamclonebundle(ui, repo, fname):
2154 """create a stream clone bundle file
2154 """create a stream clone bundle file
2155
2155
2156 Stream bundles are special bundles that are essentially archives of
2156 Stream bundles are special bundles that are essentially archives of
2157 revlog files. They are commonly used for cloning very quickly.
2157 revlog files. They are commonly used for cloning very quickly.
2158 """
2158 """
2159 requirements, gen = streamclone.generatebundlev1(repo)
2159 requirements, gen = streamclone.generatebundlev1(repo)
2160 changegroup.writechunks(ui, gen, fname)
2160 changegroup.writechunks(ui, gen, fname)
2161
2161
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2162 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2163
2163
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2164 @command('debugapplystreamclonebundle', [], 'FILE')
2165 def debugapplystreamclonebundle(ui, repo, fname):
2165 def debugapplystreamclonebundle(ui, repo, fname):
2166 """apply a stream clone bundle file"""
2166 """apply a stream clone bundle file"""
2167 f = hg.openpath(ui, fname)
2167 f = hg.openpath(ui, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2168 gen = exchange.readbundle(ui, f, fname)
2169 gen.apply(repo)
2169 gen.apply(repo)
2170
2170
2171 @command('debugcheckstate', [], '')
2171 @command('debugcheckstate', [], '')
2172 def debugcheckstate(ui, repo):
2172 def debugcheckstate(ui, repo):
2173 """validate the correctness of the current dirstate"""
2173 """validate the correctness of the current dirstate"""
2174 parent1, parent2 = repo.dirstate.parents()
2174 parent1, parent2 = repo.dirstate.parents()
2175 m1 = repo[parent1].manifest()
2175 m1 = repo[parent1].manifest()
2176 m2 = repo[parent2].manifest()
2176 m2 = repo[parent2].manifest()
2177 errors = 0
2177 errors = 0
2178 for f in repo.dirstate:
2178 for f in repo.dirstate:
2179 state = repo.dirstate[f]
2179 state = repo.dirstate[f]
2180 if state in "nr" and f not in m1:
2180 if state in "nr" and f not in m1:
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2181 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2182 errors += 1
2182 errors += 1
2183 if state in "a" and f in m1:
2183 if state in "a" and f in m1:
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "m" and f not in m1 and f not in m2:
2186 if state in "m" and f not in m1 and f not in m2:
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2187 ui.warn(_("%s in state %s, but not in either manifest\n") %
2188 (f, state))
2188 (f, state))
2189 errors += 1
2189 errors += 1
2190 for f in m1:
2190 for f in m1:
2191 state = repo.dirstate[f]
2191 state = repo.dirstate[f]
2192 if state not in "nrm":
2192 if state not in "nrm":
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2193 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2194 errors += 1
2194 errors += 1
2195 if errors:
2195 if errors:
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2196 error = _(".hg/dirstate inconsistent with current parent's manifest")
2197 raise error.Abort(error)
2197 raise error.Abort(error)
2198
2198
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2199 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2200 def debugcommands(ui, cmd='', *args):
2200 def debugcommands(ui, cmd='', *args):
2201 """list all available commands and options"""
2201 """list all available commands and options"""
2202 for cmd, vals in sorted(table.iteritems()):
2202 for cmd, vals in sorted(table.iteritems()):
2203 cmd = cmd.split('|')[0].strip('^')
2203 cmd = cmd.split('|')[0].strip('^')
2204 opts = ', '.join([i[1] for i in vals[1]])
2204 opts = ', '.join([i[1] for i in vals[1]])
2205 ui.write('%s: %s\n' % (cmd, opts))
2205 ui.write('%s: %s\n' % (cmd, opts))
2206
2206
2207 @command('debugcomplete',
2207 @command('debugcomplete',
2208 [('o', 'options', None, _('show the command options'))],
2208 [('o', 'options', None, _('show the command options'))],
2209 _('[-o] CMD'),
2209 _('[-o] CMD'),
2210 norepo=True)
2210 norepo=True)
2211 def debugcomplete(ui, cmd='', **opts):
2211 def debugcomplete(ui, cmd='', **opts):
2212 """returns the completion list associated with the given command"""
2212 """returns the completion list associated with the given command"""
2213
2213
2214 if opts.get('options'):
2214 if opts.get('options'):
2215 options = []
2215 options = []
2216 otables = [globalopts]
2216 otables = [globalopts]
2217 if cmd:
2217 if cmd:
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2218 aliases, entry = cmdutil.findcmd(cmd, table, False)
2219 otables.append(entry[1])
2219 otables.append(entry[1])
2220 for t in otables:
2220 for t in otables:
2221 for o in t:
2221 for o in t:
2222 if "(DEPRECATED)" in o[3]:
2222 if "(DEPRECATED)" in o[3]:
2223 continue
2223 continue
2224 if o[0]:
2224 if o[0]:
2225 options.append('-%s' % o[0])
2225 options.append('-%s' % o[0])
2226 options.append('--%s' % o[1])
2226 options.append('--%s' % o[1])
2227 ui.write("%s\n" % "\n".join(options))
2227 ui.write("%s\n" % "\n".join(options))
2228 return
2228 return
2229
2229
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2230 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2231 if ui.verbose:
2231 if ui.verbose:
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2232 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2233 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2234
2234
2235 @command('debugdag',
2235 @command('debugdag',
2236 [('t', 'tags', None, _('use tags as labels')),
2236 [('t', 'tags', None, _('use tags as labels')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2237 ('b', 'branches', None, _('annotate with branch names')),
2238 ('', 'dots', None, _('use dots for runs')),
2238 ('', 'dots', None, _('use dots for runs')),
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2239 ('s', 'spaces', None, _('separate elements by spaces'))],
2240 _('[OPTION]... [FILE [REV]...]'),
2240 _('[OPTION]... [FILE [REV]...]'),
2241 optionalrepo=True)
2241 optionalrepo=True)
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2242 def debugdag(ui, repo, file_=None, *revs, **opts):
2243 """format the changelog or an index DAG as a concise textual description
2243 """format the changelog or an index DAG as a concise textual description
2244
2244
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2245 If you pass a revlog index, the revlog's DAG is emitted. If you list
2246 revision numbers, they get labeled in the output as rN.
2246 revision numbers, they get labeled in the output as rN.
2247
2247
2248 Otherwise, the changelog DAG of the current repo is emitted.
2248 Otherwise, the changelog DAG of the current repo is emitted.
2249 """
2249 """
2250 spaces = opts.get('spaces')
2250 spaces = opts.get('spaces')
2251 dots = opts.get('dots')
2251 dots = opts.get('dots')
2252 if file_:
2252 if file_:
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2254 revs = set((int(r) for r in revs))
2254 revs = set((int(r) for r in revs))
2255 def events():
2255 def events():
2256 for r in rlog:
2256 for r in rlog:
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2257 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2258 if p != -1))
2258 if p != -1))
2259 if r in revs:
2259 if r in revs:
2260 yield 'l', (r, "r%i" % r)
2260 yield 'l', (r, "r%i" % r)
2261 elif repo:
2261 elif repo:
2262 cl = repo.changelog
2262 cl = repo.changelog
2263 tags = opts.get('tags')
2263 tags = opts.get('tags')
2264 branches = opts.get('branches')
2264 branches = opts.get('branches')
2265 if tags:
2265 if tags:
2266 labels = {}
2266 labels = {}
2267 for l, n in repo.tags().items():
2267 for l, n in repo.tags().items():
2268 labels.setdefault(cl.rev(n), []).append(l)
2268 labels.setdefault(cl.rev(n), []).append(l)
2269 def events():
2269 def events():
2270 b = "default"
2270 b = "default"
2271 for r in cl:
2271 for r in cl:
2272 if branches:
2272 if branches:
2273 newb = cl.read(cl.node(r))[5]['branch']
2273 newb = cl.read(cl.node(r))[5]['branch']
2274 if newb != b:
2274 if newb != b:
2275 yield 'a', newb
2275 yield 'a', newb
2276 b = newb
2276 b = newb
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2277 yield 'n', (r, list(p for p in cl.parentrevs(r)
2278 if p != -1))
2278 if p != -1))
2279 if tags:
2279 if tags:
2280 ls = labels.get(r)
2280 ls = labels.get(r)
2281 if ls:
2281 if ls:
2282 for l in ls:
2282 for l in ls:
2283 yield 'l', (r, l)
2283 yield 'l', (r, l)
2284 else:
2284 else:
2285 raise error.Abort(_('need repo for changelog dag'))
2285 raise error.Abort(_('need repo for changelog dag'))
2286
2286
2287 for line in dagparser.dagtextlines(events(),
2287 for line in dagparser.dagtextlines(events(),
2288 addspaces=spaces,
2288 addspaces=spaces,
2289 wraplabels=True,
2289 wraplabels=True,
2290 wrapannotations=True,
2290 wrapannotations=True,
2291 wrapnonlinear=dots,
2291 wrapnonlinear=dots,
2292 usedots=dots,
2292 usedots=dots,
2293 maxlinewidth=70):
2293 maxlinewidth=70):
2294 ui.write(line)
2294 ui.write(line)
2295 ui.write("\n")
2295 ui.write("\n")
2296
2296
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2297 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2298 def debugdata(ui, repo, file_, rev=None, **opts):
2299 """dump the contents of a data file revision"""
2299 """dump the contents of a data file revision"""
2300 if opts.get('changelog') or opts.get('manifest'):
2300 if opts.get('changelog') or opts.get('manifest'):
2301 file_, rev = None, file_
2301 file_, rev = None, file_
2302 elif rev is None:
2302 elif rev is None:
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2303 raise error.CommandError('debugdata', _('invalid arguments'))
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2304 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2305 try:
2305 try:
2306 ui.write(r.revision(r.lookup(rev)))
2306 ui.write(r.revision(r.lookup(rev)))
2307 except KeyError:
2307 except KeyError:
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2308 raise error.Abort(_('invalid revision identifier %s') % rev)
2309
2309
2310 @command('debugdate',
2310 @command('debugdate',
2311 [('e', 'extended', None, _('try extended date formats'))],
2311 [('e', 'extended', None, _('try extended date formats'))],
2312 _('[-e] DATE [RANGE]'),
2312 _('[-e] DATE [RANGE]'),
2313 norepo=True, optionalrepo=True)
2313 norepo=True, optionalrepo=True)
2314 def debugdate(ui, date, range=None, **opts):
2314 def debugdate(ui, date, range=None, **opts):
2315 """parse and display a date"""
2315 """parse and display a date"""
2316 if opts["extended"]:
2316 if opts["extended"]:
2317 d = util.parsedate(date, util.extendeddateformats)
2317 d = util.parsedate(date, util.extendeddateformats)
2318 else:
2318 else:
2319 d = util.parsedate(date)
2319 d = util.parsedate(date)
2320 ui.write(("internal: %s %s\n") % d)
2320 ui.write(("internal: %s %s\n") % d)
2321 ui.write(("standard: %s\n") % util.datestr(d))
2321 ui.write(("standard: %s\n") % util.datestr(d))
2322 if range:
2322 if range:
2323 m = util.matchdate(range)
2323 m = util.matchdate(range)
2324 ui.write(("match: %s\n") % m(d[0]))
2324 ui.write(("match: %s\n") % m(d[0]))
2325
2325
2326 @command('debugdiscovery',
2326 @command('debugdiscovery',
2327 [('', 'old', None, _('use old-style discovery')),
2327 [('', 'old', None, _('use old-style discovery')),
2328 ('', 'nonheads', None,
2328 ('', 'nonheads', None,
2329 _('use old-style discovery with non-heads included')),
2329 _('use old-style discovery with non-heads included')),
2330 ] + remoteopts,
2330 ] + remoteopts,
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2331 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2332 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2333 """runs the changeset discovery protocol in isolation"""
2333 """runs the changeset discovery protocol in isolation"""
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2334 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2335 opts.get('branch'))
2335 opts.get('branch'))
2336 remote = hg.peer(repo, opts, remoteurl)
2336 remote = hg.peer(repo, opts, remoteurl)
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2337 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2338
2338
2339 # make sure tests are repeatable
2339 # make sure tests are repeatable
2340 random.seed(12323)
2340 random.seed(12323)
2341
2341
2342 def doit(localheads, remoteheads, remote=remote):
2342 def doit(localheads, remoteheads, remote=remote):
2343 if opts.get('old'):
2343 if opts.get('old'):
2344 if localheads:
2344 if localheads:
2345 raise error.Abort('cannot use localheads with old style '
2345 raise error.Abort('cannot use localheads with old style '
2346 'discovery')
2346 'discovery')
2347 if not util.safehasattr(remote, 'branches'):
2347 if not util.safehasattr(remote, 'branches'):
2348 # enable in-client legacy support
2348 # enable in-client legacy support
2349 remote = localrepo.locallegacypeer(remote.local())
2349 remote = localrepo.locallegacypeer(remote.local())
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2350 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2351 force=True)
2351 force=True)
2352 common = set(common)
2352 common = set(common)
2353 if not opts.get('nonheads'):
2353 if not opts.get('nonheads'):
2354 ui.write(("unpruned common: %s\n") %
2354 ui.write(("unpruned common: %s\n") %
2355 " ".join(sorted(short(n) for n in common)))
2355 " ".join(sorted(short(n) for n in common)))
2356 dag = dagutil.revlogdag(repo.changelog)
2356 dag = dagutil.revlogdag(repo.changelog)
2357 all = dag.ancestorset(dag.internalizeall(common))
2357 all = dag.ancestorset(dag.internalizeall(common))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2358 common = dag.externalizeall(dag.headsetofconnecteds(all))
2359 else:
2359 else:
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2360 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2361 common = set(common)
2361 common = set(common)
2362 rheads = set(hds)
2362 rheads = set(hds)
2363 lheads = set(repo.heads())
2363 lheads = set(repo.heads())
2364 ui.write(("common heads: %s\n") %
2364 ui.write(("common heads: %s\n") %
2365 " ".join(sorted(short(n) for n in common)))
2365 " ".join(sorted(short(n) for n in common)))
2366 if lheads <= common:
2366 if lheads <= common:
2367 ui.write(("local is subset\n"))
2367 ui.write(("local is subset\n"))
2368 elif rheads <= common:
2368 elif rheads <= common:
2369 ui.write(("remote is subset\n"))
2369 ui.write(("remote is subset\n"))
2370
2370
2371 serverlogs = opts.get('serverlog')
2371 serverlogs = opts.get('serverlog')
2372 if serverlogs:
2372 if serverlogs:
2373 for filename in serverlogs:
2373 for filename in serverlogs:
2374 with open(filename, 'r') as logfile:
2374 with open(filename, 'r') as logfile:
2375 line = logfile.readline()
2375 line = logfile.readline()
2376 while line:
2376 while line:
2377 parts = line.strip().split(';')
2377 parts = line.strip().split(';')
2378 op = parts[1]
2378 op = parts[1]
2379 if op == 'cg':
2379 if op == 'cg':
2380 pass
2380 pass
2381 elif op == 'cgss':
2381 elif op == 'cgss':
2382 doit(parts[2].split(' '), parts[3].split(' '))
2382 doit(parts[2].split(' '), parts[3].split(' '))
2383 elif op == 'unb':
2383 elif op == 'unb':
2384 doit(parts[3].split(' '), parts[2].split(' '))
2384 doit(parts[3].split(' '), parts[2].split(' '))
2385 line = logfile.readline()
2385 line = logfile.readline()
2386 else:
2386 else:
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2387 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2388 opts.get('remote_head'))
2388 opts.get('remote_head'))
2389 localrevs = opts.get('local_head')
2389 localrevs = opts.get('local_head')
2390 doit(localrevs, remoterevs)
2390 doit(localrevs, remoterevs)
2391
2391
2392 @command('debugextensions', formatteropts, [], norepo=True)
2392 @command('debugextensions', formatteropts, [], norepo=True)
2393 def debugextensions(ui, **opts):
2393 def debugextensions(ui, **opts):
2394 '''show information about active extensions'''
2394 '''show information about active extensions'''
2395 exts = extensions.extensions(ui)
2395 exts = extensions.extensions(ui)
2396 fm = ui.formatter('debugextensions', opts)
2396 fm = ui.formatter('debugextensions', opts)
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2397 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2398 extsource = extmod.__file__
2398 extsource = extmod.__file__
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2399 exttestedwith = getattr(extmod, 'testedwith', None)
2400 if exttestedwith is not None:
2400 if exttestedwith is not None:
2401 exttestedwith = exttestedwith.split()
2401 exttestedwith = exttestedwith.split()
2402 extbuglink = getattr(extmod, 'buglink', None)
2402 extbuglink = getattr(extmod, 'buglink', None)
2403
2403
2404 fm.startitem()
2404 fm.startitem()
2405
2405
2406 if ui.quiet or ui.verbose:
2406 if ui.quiet or ui.verbose:
2407 fm.write('name', '%s\n', extname)
2407 fm.write('name', '%s\n', extname)
2408 else:
2408 else:
2409 fm.write('name', '%s', extname)
2409 fm.write('name', '%s', extname)
2410 if not exttestedwith:
2410 if not exttestedwith:
2411 fm.plain(_(' (untested!)\n'))
2411 fm.plain(_(' (untested!)\n'))
2412 else:
2412 else:
2413 if exttestedwith == ['internal'] or \
2413 if exttestedwith == ['internal'] or \
2414 util.version() in exttestedwith:
2414 util.version() in exttestedwith:
2415 fm.plain('\n')
2415 fm.plain('\n')
2416 else:
2416 else:
2417 lasttestedversion = exttestedwith[-1]
2417 lasttestedversion = exttestedwith[-1]
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2418 fm.plain(' (%s!)\n' % lasttestedversion)
2419
2419
2420 fm.condwrite(ui.verbose and extsource, 'source',
2420 fm.condwrite(ui.verbose and extsource, 'source',
2421 _(' location: %s\n'), extsource or "")
2421 _(' location: %s\n'), extsource or "")
2422
2422
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2423 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2424 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2425
2425
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2426 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2427 _(' bug reporting: %s\n'), extbuglink or "")
2427 _(' bug reporting: %s\n'), extbuglink or "")
2428
2428
2429 fm.end()
2429 fm.end()
2430
2430
2431 @command('debugfileset',
2431 @command('debugfileset',
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2432 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2433 _('[-r REV] FILESPEC'))
2433 _('[-r REV] FILESPEC'))
2434 def debugfileset(ui, repo, expr, **opts):
2434 def debugfileset(ui, repo, expr, **opts):
2435 '''parse and apply a fileset specification'''
2435 '''parse and apply a fileset specification'''
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2436 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2437 if ui.verbose:
2437 if ui.verbose:
2438 tree = fileset.parse(expr)
2438 tree = fileset.parse(expr)
2439 ui.note(fileset.prettyformat(tree), "\n")
2439 ui.note(fileset.prettyformat(tree), "\n")
2440
2440
2441 for f in ctx.getfileset(expr):
2441 for f in ctx.getfileset(expr):
2442 ui.write("%s\n" % f)
2442 ui.write("%s\n" % f)
2443
2443
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2444 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2445 def debugfsinfo(ui, path="."):
2445 def debugfsinfo(ui, path="."):
2446 """show information detected about current filesystem"""
2446 """show information detected about current filesystem"""
2447 util.writefile('.debugfsinfo', '')
2447 util.writefile('.debugfsinfo', '')
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2448 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2449 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2450 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2451 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2452 and 'yes' or 'no'))
2452 and 'yes' or 'no'))
2453 os.unlink('.debugfsinfo')
2453 os.unlink('.debugfsinfo')
2454
2454
2455 @command('debuggetbundle',
2455 @command('debuggetbundle',
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2456 [('H', 'head', [], _('id of head node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2457 ('C', 'common', [], _('id of common node'), _('ID')),
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2458 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2459 _('REPO FILE [-H|-C ID]...'),
2459 _('REPO FILE [-H|-C ID]...'),
2460 norepo=True)
2460 norepo=True)
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2461 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2462 """retrieves a bundle from a repo
2462 """retrieves a bundle from a repo
2463
2463
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2464 Every ID must be a full-length hex node id string. Saves the bundle to the
2465 given file.
2465 given file.
2466 """
2466 """
2467 repo = hg.peer(ui, opts, repopath)
2467 repo = hg.peer(ui, opts, repopath)
2468 if not repo.capable('getbundle'):
2468 if not repo.capable('getbundle'):
2469 raise error.Abort("getbundle() not supported by target repository")
2469 raise error.Abort("getbundle() not supported by target repository")
2470 args = {}
2470 args = {}
2471 if common:
2471 if common:
2472 args['common'] = [bin(s) for s in common]
2472 args['common'] = [bin(s) for s in common]
2473 if head:
2473 if head:
2474 args['heads'] = [bin(s) for s in head]
2474 args['heads'] = [bin(s) for s in head]
2475 # TODO: get desired bundlecaps from command line.
2475 # TODO: get desired bundlecaps from command line.
2476 args['bundlecaps'] = None
2476 args['bundlecaps'] = None
2477 bundle = repo.getbundle('debug', **args)
2477 bundle = repo.getbundle('debug', **args)
2478
2478
2479 bundletype = opts.get('type', 'bzip2').lower()
2479 bundletype = opts.get('type', 'bzip2').lower()
2480 btypes = {'none': 'HG10UN',
2480 btypes = {'none': 'HG10UN',
2481 'bzip2': 'HG10BZ',
2481 'bzip2': 'HG10BZ',
2482 'gzip': 'HG10GZ',
2482 'gzip': 'HG10GZ',
2483 'bundle2': 'HG20'}
2483 'bundle2': 'HG20'}
2484 bundletype = btypes.get(bundletype)
2484 bundletype = btypes.get(bundletype)
2485 if bundletype not in changegroup.bundletypes:
2485 if bundletype not in changegroup.bundletypes:
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2486 raise error.Abort(_('unknown bundle type specified with --type'))
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2487 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2488
2488
2489 @command('debugignore', [], '[FILE]')
2489 @command('debugignore', [], '[FILE]')
2490 def debugignore(ui, repo, *files, **opts):
2490 def debugignore(ui, repo, *files, **opts):
2491 """display the combined ignore pattern and information about ignored files
2491 """display the combined ignore pattern and information about ignored files
2492
2492
2493 With no argument display the combined ignore pattern.
2493 With no argument display the combined ignore pattern.
2494
2494
2495 Given space separated file names, shows if the given file is ignored and
2495 Given space separated file names, shows if the given file is ignored and
2496 if so, show the ignore rule (file and line number) that matched it.
2496 if so, show the ignore rule (file and line number) that matched it.
2497 """
2497 """
2498 ignore = repo.dirstate._ignore
2498 ignore = repo.dirstate._ignore
2499 if not files:
2499 if not files:
2500 # Show all the patterns
2500 # Show all the patterns
2501 includepat = getattr(ignore, 'includepat', None)
2501 includepat = getattr(ignore, 'includepat', None)
2502 if includepat is not None:
2502 if includepat is not None:
2503 ui.write("%s\n" % includepat)
2503 ui.write("%s\n" % includepat)
2504 else:
2504 else:
2505 raise error.Abort(_("no ignore patterns found"))
2505 raise error.Abort(_("no ignore patterns found"))
2506 else:
2506 else:
2507 for f in files:
2507 for f in files:
2508 nf = util.normpath(f)
2508 nf = util.normpath(f)
2509 ignored = None
2509 ignored = None
2510 ignoredata = None
2510 ignoredata = None
2511 if nf != '.':
2511 if nf != '.':
2512 if ignore(nf):
2512 if ignore(nf):
2513 ignored = nf
2513 ignored = nf
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2514 ignoredata = repo.dirstate._ignorefileandline(nf)
2515 else:
2515 else:
2516 for p in util.finddirs(nf):
2516 for p in util.finddirs(nf):
2517 if ignore(p):
2517 if ignore(p):
2518 ignored = p
2518 ignored = p
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2519 ignoredata = repo.dirstate._ignorefileandline(p)
2520 break
2520 break
2521 if ignored:
2521 if ignored:
2522 if ignored == nf:
2522 if ignored == nf:
2523 ui.write("%s is ignored\n" % f)
2523 ui.write("%s is ignored\n" % f)
2524 else:
2524 else:
2525 ui.write("%s is ignored because of containing folder %s\n"
2525 ui.write("%s is ignored because of containing folder %s\n"
2526 % (f, ignored))
2526 % (f, ignored))
2527 ignorefile, lineno, line = ignoredata
2527 ignorefile, lineno, line = ignoredata
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2528 ui.write("(ignore rule in %s, line %d: '%s')\n"
2529 % (ignorefile, lineno, line))
2529 % (ignorefile, lineno, line))
2530 else:
2530 else:
2531 ui.write("%s is not ignored\n" % f)
2531 ui.write("%s is not ignored\n" % f)
2532
2532
2533 @command('debugindex', debugrevlogopts +
2533 @command('debugindex', debugrevlogopts +
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2534 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2535 _('[-f FORMAT] -c|-m|FILE'),
2535 _('[-f FORMAT] -c|-m|FILE'),
2536 optionalrepo=True)
2536 optionalrepo=True)
2537 def debugindex(ui, repo, file_=None, **opts):
2537 def debugindex(ui, repo, file_=None, **opts):
2538 """dump the contents of an index file"""
2538 """dump the contents of an index file"""
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2539 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2540 format = opts.get('format', 0)
2540 format = opts.get('format', 0)
2541 if format not in (0, 1):
2541 if format not in (0, 1):
2542 raise error.Abort(_("unknown format %d") % format)
2542 raise error.Abort(_("unknown format %d") % format)
2543
2543
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2544 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2545 if generaldelta:
2545 if generaldelta:
2546 basehdr = ' delta'
2546 basehdr = ' delta'
2547 else:
2547 else:
2548 basehdr = ' base'
2548 basehdr = ' base'
2549
2549
2550 if ui.debugflag:
2550 if ui.debugflag:
2551 shortfn = hex
2551 shortfn = hex
2552 else:
2552 else:
2553 shortfn = short
2553 shortfn = short
2554
2554
2555 # There might not be anything in r, so have a sane default
2555 # There might not be anything in r, so have a sane default
2556 idlen = 12
2556 idlen = 12
2557 for i in r:
2557 for i in r:
2558 idlen = len(shortfn(r.node(i)))
2558 idlen = len(shortfn(r.node(i)))
2559 break
2559 break
2560
2560
2561 if format == 0:
2561 if format == 0:
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2562 ui.write(" rev offset length " + basehdr + " linkrev"
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2563 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2564 elif format == 1:
2564 elif format == 1:
2565 ui.write(" rev flag offset length"
2565 ui.write(" rev flag offset length"
2566 " size " + basehdr + " link p1 p2"
2566 " size " + basehdr + " link p1 p2"
2567 " %s\n" % "nodeid".rjust(idlen))
2567 " %s\n" % "nodeid".rjust(idlen))
2568
2568
2569 for i in r:
2569 for i in r:
2570 node = r.node(i)
2570 node = r.node(i)
2571 if generaldelta:
2571 if generaldelta:
2572 base = r.deltaparent(i)
2572 base = r.deltaparent(i)
2573 else:
2573 else:
2574 base = r.chainbase(i)
2574 base = r.chainbase(i)
2575 if format == 0:
2575 if format == 0:
2576 try:
2576 try:
2577 pp = r.parents(node)
2577 pp = r.parents(node)
2578 except Exception:
2578 except Exception:
2579 pp = [nullid, nullid]
2579 pp = [nullid, nullid]
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2580 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2581 i, r.start(i), r.length(i), base, r.linkrev(i),
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2582 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2583 elif format == 1:
2583 elif format == 1:
2584 pr = r.parentrevs(i)
2584 pr = r.parentrevs(i)
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2585 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2586 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2587 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2588
2588
2589 @command('debugindexdot', debugrevlogopts,
2589 @command('debugindexdot', debugrevlogopts,
2590 _('-c|-m|FILE'), optionalrepo=True)
2590 _('-c|-m|FILE'), optionalrepo=True)
2591 def debugindexdot(ui, repo, file_=None, **opts):
2591 def debugindexdot(ui, repo, file_=None, **opts):
2592 """dump an index DAG as a graphviz dot file"""
2592 """dump an index DAG as a graphviz dot file"""
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2593 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2594 ui.write(("digraph G {\n"))
2594 ui.write(("digraph G {\n"))
2595 for i in r:
2595 for i in r:
2596 node = r.node(i)
2596 node = r.node(i)
2597 pp = r.parents(node)
2597 pp = r.parents(node)
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2598 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2599 if pp[1] != nullid:
2599 if pp[1] != nullid:
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2600 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2601 ui.write("}\n")
2601 ui.write("}\n")
2602
2602
2603 @command('debugdeltachain',
2603 @command('debugdeltachain',
2604 debugrevlogopts + formatteropts,
2604 debugrevlogopts + formatteropts,
2605 _('-c|-m|FILE'),
2605 _('-c|-m|FILE'),
2606 optionalrepo=True)
2606 optionalrepo=True)
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2607 def debugdeltachain(ui, repo, file_=None, **opts):
2608 """dump information about delta chains in a revlog
2608 """dump information about delta chains in a revlog
2609
2609
2610 Output can be templatized. Available template keywords are:
2610 Output can be templatized. Available template keywords are:
2611
2611
2612 rev revision number
2612 rev revision number
2613 chainid delta chain identifier (numbered by unique base)
2613 chainid delta chain identifier (numbered by unique base)
2614 chainlen delta chain length to this revision
2614 chainlen delta chain length to this revision
2615 prevrev previous revision in delta chain
2615 prevrev previous revision in delta chain
2616 deltatype role of delta / how it was computed
2616 deltatype role of delta / how it was computed
2617 compsize compressed size of revision
2617 compsize compressed size of revision
2618 uncompsize uncompressed size of revision
2618 uncompsize uncompressed size of revision
2619 chainsize total size of compressed revisions in chain
2619 chainsize total size of compressed revisions in chain
2620 chainratio total chain size divided by uncompressed revision size
2620 chainratio total chain size divided by uncompressed revision size
2621 (new delta chains typically start at ratio 2.00)
2621 (new delta chains typically start at ratio 2.00)
2622 lindist linear distance from base revision in delta chain to end
2622 lindist linear distance from base revision in delta chain to end
2623 of this revision
2623 of this revision
2624 extradist total size of revisions not part of this delta chain from
2624 extradist total size of revisions not part of this delta chain from
2625 base of delta chain to end of this revision; a measurement
2625 base of delta chain to end of this revision; a measurement
2626 of how much extra data we need to read/seek across to read
2626 of how much extra data we need to read/seek across to read
2627 the delta chain for this revision
2627 the delta chain for this revision
2628 extraratio extradist divided by chainsize; another representation of
2628 extraratio extradist divided by chainsize; another representation of
2629 how much unrelated data is needed to load this delta chain
2629 how much unrelated data is needed to load this delta chain
2630 """
2630 """
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2631 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2632 index = r.index
2632 index = r.index
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2633 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2634
2634
2635 def revinfo(rev):
2635 def revinfo(rev):
2636 e = index[rev]
2636 e = index[rev]
2637 compsize = e[1]
2637 compsize = e[1]
2638 uncompsize = e[2]
2638 uncompsize = e[2]
2639 chainsize = 0
2639 chainsize = 0
2640
2640
2641 if generaldelta:
2641 if generaldelta:
2642 if e[3] == e[5]:
2642 if e[3] == e[5]:
2643 deltatype = 'p1'
2643 deltatype = 'p1'
2644 elif e[3] == e[6]:
2644 elif e[3] == e[6]:
2645 deltatype = 'p2'
2645 deltatype = 'p2'
2646 elif e[3] == rev - 1:
2646 elif e[3] == rev - 1:
2647 deltatype = 'prev'
2647 deltatype = 'prev'
2648 elif e[3] == rev:
2648 elif e[3] == rev:
2649 deltatype = 'base'
2649 deltatype = 'base'
2650 else:
2650 else:
2651 deltatype = 'other'
2651 deltatype = 'other'
2652 else:
2652 else:
2653 if e[3] == rev:
2653 if e[3] == rev:
2654 deltatype = 'base'
2654 deltatype = 'base'
2655 else:
2655 else:
2656 deltatype = 'prev'
2656 deltatype = 'prev'
2657
2657
2658 chain = r._deltachain(rev)[0]
2658 chain = r._deltachain(rev)[0]
2659 for iterrev in chain:
2659 for iterrev in chain:
2660 e = index[iterrev]
2660 e = index[iterrev]
2661 chainsize += e[1]
2661 chainsize += e[1]
2662
2662
2663 return compsize, uncompsize, deltatype, chain, chainsize
2663 return compsize, uncompsize, deltatype, chain, chainsize
2664
2664
2665 fm = ui.formatter('debugdeltachain', opts)
2665 fm = ui.formatter('debugdeltachain', opts)
2666
2666
2667 fm.plain(' rev chain# chainlen prev delta '
2667 fm.plain(' rev chain# chainlen prev delta '
2668 'size rawsize chainsize ratio lindist extradist '
2668 'size rawsize chainsize ratio lindist extradist '
2669 'extraratio\n')
2669 'extraratio\n')
2670
2670
2671 chainbases = {}
2671 chainbases = {}
2672 for rev in r:
2672 for rev in r:
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2673 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2674 chainbase = chain[0]
2674 chainbase = chain[0]
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2675 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2676 basestart = r.start(chainbase)
2676 basestart = r.start(chainbase)
2677 revstart = r.start(rev)
2677 revstart = r.start(rev)
2678 lineardist = revstart + comp - basestart
2678 lineardist = revstart + comp - basestart
2679 extradist = lineardist - chainsize
2679 extradist = lineardist - chainsize
2680 try:
2680 try:
2681 prevrev = chain[-2]
2681 prevrev = chain[-2]
2682 except IndexError:
2682 except IndexError:
2683 prevrev = -1
2683 prevrev = -1
2684
2684
2685 chainratio = float(chainsize) / float(uncomp)
2685 chainratio = float(chainsize) / float(uncomp)
2686 extraratio = float(extradist) / float(chainsize)
2686 extraratio = float(extradist) / float(chainsize)
2687
2687
2688 fm.startitem()
2688 fm.startitem()
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2689 fm.write('rev chainid chainlen prevrev deltatype compsize '
2690 'uncompsize chainsize chainratio lindist extradist '
2690 'uncompsize chainsize chainratio lindist extradist '
2691 'extraratio',
2691 'extraratio',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2692 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2693 rev, chainid, len(chain), prevrev, deltatype, comp,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2694 uncomp, chainsize, chainratio, lineardist, extradist,
2695 extraratio,
2695 extraratio,
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2696 rev=rev, chainid=chainid, chainlen=len(chain),
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2697 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2698 uncompsize=uncomp, chainsize=chainsize,
2698 uncompsize=uncomp, chainsize=chainsize,
2699 chainratio=chainratio, lindist=lineardist,
2699 chainratio=chainratio, lindist=lineardist,
2700 extradist=extradist, extraratio=extraratio)
2700 extradist=extradist, extraratio=extraratio)
2701
2701
2702 fm.end()
2702 fm.end()
2703
2703
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2704 @command('debuginstall', [] + formatteropts, '', norepo=True)
2705 def debuginstall(ui, **opts):
2705 def debuginstall(ui, **opts):
2706 '''test Mercurial installation
2706 '''test Mercurial installation
2707
2707
2708 Returns 0 on success.
2708 Returns 0 on success.
2709 '''
2709 '''
2710
2710
2711 def writetemp(contents):
2711 def writetemp(contents):
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2712 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2713 f = os.fdopen(fd, "wb")
2713 f = os.fdopen(fd, "wb")
2714 f.write(contents)
2714 f.write(contents)
2715 f.close()
2715 f.close()
2716 return name
2716 return name
2717
2717
2718 problems = 0
2718 problems = 0
2719
2719
2720 fm = ui.formatter('debuginstall', opts)
2720 fm = ui.formatter('debuginstall', opts)
2721 fm.startitem()
2721 fm.startitem()
2722
2722
2723 # encoding
2723 # encoding
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2724 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2725 err = None
2725 err = None
2726 try:
2726 try:
2727 encoding.fromlocal("test")
2727 encoding.fromlocal("test")
2728 except error.Abort as inst:
2728 except error.Abort as inst:
2729 err = inst
2729 err = inst
2730 problems += 1
2730 problems += 1
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2731 fm.condwrite(err, 'encodingerror', _(" %s\n"
2732 " (check that your locale is properly set)\n"), err)
2732 " (check that your locale is properly set)\n"), err)
2733
2733
2734 # Python
2734 # Python
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2735 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2736 sys.executable)
2736 sys.executable)
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2737 fm.write('pythonver', _("checking Python version (%s)\n"),
2738 ("%s.%s.%s" % sys.version_info[:3]))
2738 ("%s.%s.%s" % sys.version_info[:3]))
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2739 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2740 os.path.dirname(os.__file__))
2740 os.path.dirname(os.__file__))
2741
2741
2742 # compiled modules
2742 # compiled modules
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2743 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2744 os.path.dirname(__file__))
2744 os.path.dirname(__file__))
2745
2745
2746 err = None
2746 err = None
2747 try:
2747 try:
2748 from . import (
2748 from . import (
2749 base85,
2749 base85,
2750 bdiff,
2750 bdiff,
2751 mpatch,
2751 mpatch,
2752 osutil,
2752 osutil,
2753 )
2753 )
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2754 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2755 except Exception as inst:
2755 except Exception as inst:
2756 err = inst
2756 err = inst
2757 problems += 1
2757 problems += 1
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2758 fm.condwrite(err, 'extensionserror', " %s\n", err)
2759
2759
2760 # templates
2760 # templates
2761 p = templater.templatepaths()
2761 p = templater.templatepaths()
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2762 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2763 fm.condwrite(not p, '', _(" no template directories found\n"))
2764 if p:
2764 if p:
2765 m = templater.templatepath("map-cmdline.default")
2765 m = templater.templatepath("map-cmdline.default")
2766 if m:
2766 if m:
2767 # template found, check if it is working
2767 # template found, check if it is working
2768 err = None
2768 err = None
2769 try:
2769 try:
2770 templater.templater(m)
2770 templater.templater(m)
2771 except Exception as inst:
2771 except Exception as inst:
2772 err = inst
2772 err = inst
2773 p = None
2773 p = None
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2774 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2775 else:
2775 else:
2776 p = None
2776 p = None
2777 fm.condwrite(p, 'defaulttemplate',
2777 fm.condwrite(p, 'defaulttemplate',
2778 _("checking default template (%s)\n"), m)
2778 _("checking default template (%s)\n"), m)
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2779 fm.condwrite(not m, 'defaulttemplatenotfound',
2780 _(" template '%s' not found\n"), "default")
2780 _(" template '%s' not found\n"), "default")
2781 if not p:
2781 if not p:
2782 problems += 1
2782 problems += 1
2783 fm.condwrite(not p, '',
2783 fm.condwrite(not p, '',
2784 _(" (templates seem to have been installed incorrectly)\n"))
2784 _(" (templates seem to have been installed incorrectly)\n"))
2785
2785
2786 # editor
2786 # editor
2787 editor = ui.geteditor()
2787 editor = ui.geteditor()
2788 editor = util.expandpath(editor)
2788 editor = util.expandpath(editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2789 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2790 cmdpath = util.findexe(shlex.split(editor)[0])
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2791 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2792 _(" No commit editor set and can't find %s in PATH\n"
2792 _(" No commit editor set and can't find %s in PATH\n"
2793 " (specify a commit editor in your configuration"
2793 " (specify a commit editor in your configuration"
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2794 " file)\n"), not cmdpath and editor == 'vi' and editor)
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2795 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2796 _(" Can't find editor '%s' in PATH\n"
2796 _(" Can't find editor '%s' in PATH\n"
2797 " (specify a commit editor in your configuration"
2797 " (specify a commit editor in your configuration"
2798 " file)\n"), not cmdpath and editor)
2798 " file)\n"), not cmdpath and editor)
2799 if not cmdpath and editor != 'vi':
2799 if not cmdpath and editor != 'vi':
2800 problems += 1
2800 problems += 1
2801
2801
2802 # check username
2802 # check username
2803 username = None
2803 username = None
2804 err = None
2804 err = None
2805 try:
2805 try:
2806 username = ui.username()
2806 username = ui.username()
2807 except error.Abort as e:
2807 except error.Abort as e:
2808 err = e
2808 err = e
2809 problems += 1
2809 problems += 1
2810
2810
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2811 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2812 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2813 " (specify a username in your configuration file)\n"), err)
2813 " (specify a username in your configuration file)\n"), err)
2814
2814
2815 fm.condwrite(not problems, '',
2815 fm.condwrite(not problems, '',
2816 _("no problems detected\n"))
2816 _("no problems detected\n"))
2817 if not problems:
2817 if not problems:
2818 fm.data(problems=problems)
2818 fm.data(problems=problems)
2819 fm.condwrite(problems, 'problems',
2819 fm.condwrite(problems, 'problems',
2820 _("%s problems detected,"
2820 _("%s problems detected,"
2821 " please check your install!\n"), problems)
2821 " please check your install!\n"), problems)
2822 fm.end()
2822 fm.end()
2823
2823
2824 return problems
2824 return problems
2825
2825
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2826 @command('debugknown', [], _('REPO ID...'), norepo=True)
2827 def debugknown(ui, repopath, *ids, **opts):
2827 def debugknown(ui, repopath, *ids, **opts):
2828 """test whether node ids are known to a repo
2828 """test whether node ids are known to a repo
2829
2829
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2830 Every ID must be a full-length hex node id string. Returns a list of 0s
2831 and 1s indicating unknown/known.
2831 and 1s indicating unknown/known.
2832 """
2832 """
2833 repo = hg.peer(ui, opts, repopath)
2833 repo = hg.peer(ui, opts, repopath)
2834 if not repo.capable('known'):
2834 if not repo.capable('known'):
2835 raise error.Abort("known() not supported by target repository")
2835 raise error.Abort("known() not supported by target repository")
2836 flags = repo.known([bin(s) for s in ids])
2836 flags = repo.known([bin(s) for s in ids])
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2837 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2838
2838
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2839 @command('debuglabelcomplete', [], _('LABEL...'))
2840 def debuglabelcomplete(ui, repo, *args):
2840 def debuglabelcomplete(ui, repo, *args):
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2841 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2842 debugnamecomplete(ui, repo, *args)
2842 debugnamecomplete(ui, repo, *args)
2843
2843
2844 @command('debugmergestate', [], '')
2844 @command('debugmergestate', [], '')
2845 def debugmergestate(ui, repo, *args):
2845 def debugmergestate(ui, repo, *args):
2846 """print merge state
2846 """print merge state
2847
2847
2848 Use --verbose to print out information about whether v1 or v2 merge state
2848 Use --verbose to print out information about whether v1 or v2 merge state
2849 was chosen."""
2849 was chosen."""
2850 def _hashornull(h):
2850 def _hashornull(h):
2851 if h == nullhex:
2851 if h == nullhex:
2852 return 'null'
2852 return 'null'
2853 else:
2853 else:
2854 return h
2854 return h
2855
2855
2856 def printrecords(version):
2856 def printrecords(version):
2857 ui.write(('* version %s records\n') % version)
2857 ui.write(('* version %s records\n') % version)
2858 if version == 1:
2858 if version == 1:
2859 records = v1records
2859 records = v1records
2860 else:
2860 else:
2861 records = v2records
2861 records = v2records
2862
2862
2863 for rtype, record in records:
2863 for rtype, record in records:
2864 # pretty print some record types
2864 # pretty print some record types
2865 if rtype == 'L':
2865 if rtype == 'L':
2866 ui.write(('local: %s\n') % record)
2866 ui.write(('local: %s\n') % record)
2867 elif rtype == 'O':
2867 elif rtype == 'O':
2868 ui.write(('other: %s\n') % record)
2868 ui.write(('other: %s\n') % record)
2869 elif rtype == 'm':
2869 elif rtype == 'm':
2870 driver, mdstate = record.split('\0', 1)
2870 driver, mdstate = record.split('\0', 1)
2871 ui.write(('merge driver: %s (state "%s")\n')
2871 ui.write(('merge driver: %s (state "%s")\n')
2872 % (driver, mdstate))
2872 % (driver, mdstate))
2873 elif rtype in 'FDC':
2873 elif rtype in 'FDC':
2874 r = record.split('\0')
2874 r = record.split('\0')
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2875 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2876 if version == 1:
2876 if version == 1:
2877 onode = 'not stored in v1 format'
2877 onode = 'not stored in v1 format'
2878 flags = r[7]
2878 flags = r[7]
2879 else:
2879 else:
2880 onode, flags = r[7:9]
2880 onode, flags = r[7:9]
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2881 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2882 % (f, rtype, state, _hashornull(hash)))
2882 % (f, rtype, state, _hashornull(hash)))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2883 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2884 ui.write((' ancestor path: %s (node %s)\n')
2884 ui.write((' ancestor path: %s (node %s)\n')
2885 % (afile, _hashornull(anode)))
2885 % (afile, _hashornull(anode)))
2886 ui.write((' other path: %s (node %s)\n')
2886 ui.write((' other path: %s (node %s)\n')
2887 % (ofile, _hashornull(onode)))
2887 % (ofile, _hashornull(onode)))
2888 elif rtype == 'f':
2888 elif rtype == 'f':
2889 filename, rawextras = record.split('\0', 1)
2889 filename, rawextras = record.split('\0', 1)
2890 extras = rawextras.split('\0')
2890 extras = rawextras.split('\0')
2891 i = 0
2891 i = 0
2892 extrastrings = []
2892 extrastrings = []
2893 while i < len(extras):
2893 while i < len(extras):
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2894 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2895 i += 2
2895 i += 2
2896
2896
2897 ui.write(('file extras: %s (%s)\n')
2897 ui.write(('file extras: %s (%s)\n')
2898 % (filename, ', '.join(extrastrings)))
2898 % (filename, ', '.join(extrastrings)))
2899 elif rtype == 'l':
2899 elif rtype == 'l':
2900 labels = record.split('\0', 2)
2900 labels = record.split('\0', 2)
2901 labels = [l for l in labels if len(l) > 0]
2901 labels = [l for l in labels if len(l) > 0]
2902 ui.write(('labels:\n'))
2902 ui.write(('labels:\n'))
2903 ui.write((' local: %s\n' % labels[0]))
2903 ui.write((' local: %s\n' % labels[0]))
2904 ui.write((' other: %s\n' % labels[1]))
2904 ui.write((' other: %s\n' % labels[1]))
2905 if len(labels) > 2:
2905 if len(labels) > 2:
2906 ui.write((' base: %s\n' % labels[2]))
2906 ui.write((' base: %s\n' % labels[2]))
2907 else:
2907 else:
2908 ui.write(('unrecognized entry: %s\t%s\n')
2908 ui.write(('unrecognized entry: %s\t%s\n')
2909 % (rtype, record.replace('\0', '\t')))
2909 % (rtype, record.replace('\0', '\t')))
2910
2910
2911 # Avoid mergestate.read() since it may raise an exception for unsupported
2911 # Avoid mergestate.read() since it may raise an exception for unsupported
2912 # merge state records. We shouldn't be doing this, but this is OK since this
2912 # merge state records. We shouldn't be doing this, but this is OK since this
2913 # command is pretty low-level.
2913 # command is pretty low-level.
2914 ms = mergemod.mergestate(repo)
2914 ms = mergemod.mergestate(repo)
2915
2915
2916 # sort so that reasonable information is on top
2916 # sort so that reasonable information is on top
2917 v1records = ms._readrecordsv1()
2917 v1records = ms._readrecordsv1()
2918 v2records = ms._readrecordsv2()
2918 v2records = ms._readrecordsv2()
2919 order = 'LOml'
2919 order = 'LOml'
2920 def key(r):
2920 def key(r):
2921 idx = order.find(r[0])
2921 idx = order.find(r[0])
2922 if idx == -1:
2922 if idx == -1:
2923 return (1, r[1])
2923 return (1, r[1])
2924 else:
2924 else:
2925 return (0, idx)
2925 return (0, idx)
2926 v1records.sort(key=key)
2926 v1records.sort(key=key)
2927 v2records.sort(key=key)
2927 v2records.sort(key=key)
2928
2928
2929 if not v1records and not v2records:
2929 if not v1records and not v2records:
2930 ui.write(('no merge state found\n'))
2930 ui.write(('no merge state found\n'))
2931 elif not v2records:
2931 elif not v2records:
2932 ui.note(('no version 2 merge state\n'))
2932 ui.note(('no version 2 merge state\n'))
2933 printrecords(1)
2933 printrecords(1)
2934 elif ms._v1v2match(v1records, v2records):
2934 elif ms._v1v2match(v1records, v2records):
2935 ui.note(('v1 and v2 states match: using v2\n'))
2935 ui.note(('v1 and v2 states match: using v2\n'))
2936 printrecords(2)
2936 printrecords(2)
2937 else:
2937 else:
2938 ui.note(('v1 and v2 states mismatch: using v1\n'))
2938 ui.note(('v1 and v2 states mismatch: using v1\n'))
2939 printrecords(1)
2939 printrecords(1)
2940 if ui.verbose:
2940 if ui.verbose:
2941 printrecords(2)
2941 printrecords(2)
2942
2942
2943 @command('debugnamecomplete', [], _('NAME...'))
2943 @command('debugnamecomplete', [], _('NAME...'))
2944 def debugnamecomplete(ui, repo, *args):
2944 def debugnamecomplete(ui, repo, *args):
2945 '''complete "names" - tags, open branch names, bookmark names'''
2945 '''complete "names" - tags, open branch names, bookmark names'''
2946
2946
2947 names = set()
2947 names = set()
2948 # since we previously only listed open branches, we will handle that
2948 # since we previously only listed open branches, we will handle that
2949 # specially (after this for loop)
2949 # specially (after this for loop)
2950 for name, ns in repo.names.iteritems():
2950 for name, ns in repo.names.iteritems():
2951 if name != 'branches':
2951 if name != 'branches':
2952 names.update(ns.listnames(repo))
2952 names.update(ns.listnames(repo))
2953 names.update(tag for (tag, heads, tip, closed)
2953 names.update(tag for (tag, heads, tip, closed)
2954 in repo.branchmap().iterbranches() if not closed)
2954 in repo.branchmap().iterbranches() if not closed)
2955 completions = set()
2955 completions = set()
2956 if not args:
2956 if not args:
2957 args = ['']
2957 args = ['']
2958 for a in args:
2958 for a in args:
2959 completions.update(n for n in names if n.startswith(a))
2959 completions.update(n for n in names if n.startswith(a))
2960 ui.write('\n'.join(sorted(completions)))
2960 ui.write('\n'.join(sorted(completions)))
2961 ui.write('\n')
2961 ui.write('\n')
2962
2962
2963 @command('debuglocks',
2963 @command('debuglocks',
2964 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2964 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2965 ('W', 'force-wlock', None,
2965 ('W', 'force-wlock', None,
2966 _('free the working state lock (DANGEROUS)'))],
2966 _('free the working state lock (DANGEROUS)'))],
2967 _('[OPTION]...'))
2967 _('[OPTION]...'))
2968 def debuglocks(ui, repo, **opts):
2968 def debuglocks(ui, repo, **opts):
2969 """show or modify state of locks
2969 """show or modify state of locks
2970
2970
2971 By default, this command will show which locks are held. This
2971 By default, this command will show which locks are held. This
2972 includes the user and process holding the lock, the amount of time
2972 includes the user and process holding the lock, the amount of time
2973 the lock has been held, and the machine name where the process is
2973 the lock has been held, and the machine name where the process is
2974 running if it's not local.
2974 running if it's not local.
2975
2975
2976 Locks protect the integrity of Mercurial's data, so should be
2976 Locks protect the integrity of Mercurial's data, so should be
2977 treated with care. System crashes or other interruptions may cause
2977 treated with care. System crashes or other interruptions may cause
2978 locks to not be properly released, though Mercurial will usually
2978 locks to not be properly released, though Mercurial will usually
2979 detect and remove such stale locks automatically.
2979 detect and remove such stale locks automatically.
2980
2980
2981 However, detecting stale locks may not always be possible (for
2981 However, detecting stale locks may not always be possible (for
2982 instance, on a shared filesystem). Removing locks may also be
2982 instance, on a shared filesystem). Removing locks may also be
2983 blocked by filesystem permissions.
2983 blocked by filesystem permissions.
2984
2984
2985 Returns 0 if no locks are held.
2985 Returns 0 if no locks are held.
2986
2986
2987 """
2987 """
2988
2988
2989 if opts.get('force_lock'):
2989 if opts.get('force_lock'):
2990 repo.svfs.unlink('lock')
2990 repo.svfs.unlink('lock')
2991 if opts.get('force_wlock'):
2991 if opts.get('force_wlock'):
2992 repo.vfs.unlink('wlock')
2992 repo.vfs.unlink('wlock')
2993 if opts.get('force_lock') or opts.get('force_lock'):
2993 if opts.get('force_lock') or opts.get('force_lock'):
2994 return 0
2994 return 0
2995
2995
2996 now = time.time()
2996 now = time.time()
2997 held = 0
2997 held = 0
2998
2998
2999 def report(vfs, name, method):
2999 def report(vfs, name, method):
3000 # this causes stale locks to get reaped for more accurate reporting
3000 # this causes stale locks to get reaped for more accurate reporting
3001 try:
3001 try:
3002 l = method(False)
3002 l = method(False)
3003 except error.LockHeld:
3003 except error.LockHeld:
3004 l = None
3004 l = None
3005
3005
3006 if l:
3006 if l:
3007 l.release()
3007 l.release()
3008 else:
3008 else:
3009 try:
3009 try:
3010 stat = vfs.lstat(name)
3010 stat = vfs.lstat(name)
3011 age = now - stat.st_mtime
3011 age = now - stat.st_mtime
3012 user = util.username(stat.st_uid)
3012 user = util.username(stat.st_uid)
3013 locker = vfs.readlock(name)
3013 locker = vfs.readlock(name)
3014 if ":" in locker:
3014 if ":" in locker:
3015 host, pid = locker.split(':')
3015 host, pid = locker.split(':')
3016 if host == socket.gethostname():
3016 if host == socket.gethostname():
3017 locker = 'user %s, process %s' % (user, pid)
3017 locker = 'user %s, process %s' % (user, pid)
3018 else:
3018 else:
3019 locker = 'user %s, process %s, host %s' \
3019 locker = 'user %s, process %s, host %s' \
3020 % (user, pid, host)
3020 % (user, pid, host)
3021 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3021 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3022 return 1
3022 return 1
3023 except OSError as e:
3023 except OSError as e:
3024 if e.errno != errno.ENOENT:
3024 if e.errno != errno.ENOENT:
3025 raise
3025 raise
3026
3026
3027 ui.write("%-6s free\n" % (name + ":"))
3027 ui.write("%-6s free\n" % (name + ":"))
3028 return 0
3028 return 0
3029
3029
3030 held += report(repo.svfs, "lock", repo.lock)
3030 held += report(repo.svfs, "lock", repo.lock)
3031 held += report(repo.vfs, "wlock", repo.wlock)
3031 held += report(repo.vfs, "wlock", repo.wlock)
3032
3032
3033 return held
3033 return held
3034
3034
3035 @command('debugobsolete',
3035 @command('debugobsolete',
3036 [('', 'flags', 0, _('markers flag')),
3036 [('', 'flags', 0, _('markers flag')),
3037 ('', 'record-parents', False,
3037 ('', 'record-parents', False,
3038 _('record parent information for the precursor')),
3038 _('record parent information for the precursor')),
3039 ('r', 'rev', [], _('display markers relevant to REV')),
3039 ('r', 'rev', [], _('display markers relevant to REV')),
3040 ('', 'index', False, _('display index of the marker')),
3040 ('', 'index', False, _('display index of the marker')),
3041 ] + commitopts2,
3041 ] + commitopts2,
3042 _('[OBSOLETED [REPLACEMENT ...]]'))
3042 _('[OBSOLETED [REPLACEMENT ...]]'))
3043 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3043 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3044 """create arbitrary obsolete marker
3044 """create arbitrary obsolete marker
3045
3045
3046 With no arguments, displays the list of obsolescence markers."""
3046 With no arguments, displays the list of obsolescence markers."""
3047
3047
3048 def parsenodeid(s):
3048 def parsenodeid(s):
3049 try:
3049 try:
3050 # We do not use revsingle/revrange functions here to accept
3050 # We do not use revsingle/revrange functions here to accept
3051 # arbitrary node identifiers, possibly not present in the
3051 # arbitrary node identifiers, possibly not present in the
3052 # local repository.
3052 # local repository.
3053 n = bin(s)
3053 n = bin(s)
3054 if len(n) != len(nullid):
3054 if len(n) != len(nullid):
3055 raise TypeError()
3055 raise TypeError()
3056 return n
3056 return n
3057 except TypeError:
3057 except TypeError:
3058 raise error.Abort('changeset references must be full hexadecimal '
3058 raise error.Abort('changeset references must be full hexadecimal '
3059 'node identifiers')
3059 'node identifiers')
3060
3060
3061 if precursor is not None:
3061 if precursor is not None:
3062 if opts['rev']:
3062 if opts['rev']:
3063 raise error.Abort('cannot select revision when creating marker')
3063 raise error.Abort('cannot select revision when creating marker')
3064 metadata = {}
3064 metadata = {}
3065 metadata['user'] = opts['user'] or ui.username()
3065 metadata['user'] = opts['user'] or ui.username()
3066 succs = tuple(parsenodeid(succ) for succ in successors)
3066 succs = tuple(parsenodeid(succ) for succ in successors)
3067 l = repo.lock()
3067 l = repo.lock()
3068 try:
3068 try:
3069 tr = repo.transaction('debugobsolete')
3069 tr = repo.transaction('debugobsolete')
3070 try:
3070 try:
3071 date = opts.get('date')
3071 date = opts.get('date')
3072 if date:
3072 if date:
3073 date = util.parsedate(date)
3073 date = util.parsedate(date)
3074 else:
3074 else:
3075 date = None
3075 date = None
3076 prec = parsenodeid(precursor)
3076 prec = parsenodeid(precursor)
3077 parents = None
3077 parents = None
3078 if opts['record_parents']:
3078 if opts['record_parents']:
3079 if prec not in repo.unfiltered():
3079 if prec not in repo.unfiltered():
3080 raise error.Abort('cannot used --record-parents on '
3080 raise error.Abort('cannot used --record-parents on '
3081 'unknown changesets')
3081 'unknown changesets')
3082 parents = repo.unfiltered()[prec].parents()
3082 parents = repo.unfiltered()[prec].parents()
3083 parents = tuple(p.node() for p in parents)
3083 parents = tuple(p.node() for p in parents)
3084 repo.obsstore.create(tr, prec, succs, opts['flags'],
3084 repo.obsstore.create(tr, prec, succs, opts['flags'],
3085 parents=parents, date=date,
3085 parents=parents, date=date,
3086 metadata=metadata)
3086 metadata=metadata)
3087 tr.close()
3087 tr.close()
3088 except ValueError as exc:
3088 except ValueError as exc:
3089 raise error.Abort(_('bad obsmarker input: %s') % exc)
3089 raise error.Abort(_('bad obsmarker input: %s') % exc)
3090 finally:
3090 finally:
3091 tr.release()
3091 tr.release()
3092 finally:
3092 finally:
3093 l.release()
3093 l.release()
3094 else:
3094 else:
3095 if opts['rev']:
3095 if opts['rev']:
3096 revs = scmutil.revrange(repo, opts['rev'])
3096 revs = scmutil.revrange(repo, opts['rev'])
3097 nodes = [repo[r].node() for r in revs]
3097 nodes = [repo[r].node() for r in revs]
3098 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3098 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3099 markers.sort(key=lambda x: x._data)
3099 markers.sort(key=lambda x: x._data)
3100 else:
3100 else:
3101 markers = obsolete.getmarkers(repo)
3101 markers = obsolete.getmarkers(repo)
3102
3102
3103 for i, m in enumerate(markers):
3103 for i, m in enumerate(markers):
3104 ind = i if opts.get('index') else None
3104 ind = i if opts.get('index') else None
3105 cmdutil.showmarker(ui, m, index=ind)
3105 cmdutil.showmarker(ui, m, index=ind)
3106
3106
3107 @command('debugpathcomplete',
3107 @command('debugpathcomplete',
3108 [('f', 'full', None, _('complete an entire path')),
3108 [('f', 'full', None, _('complete an entire path')),
3109 ('n', 'normal', None, _('show only normal files')),
3109 ('n', 'normal', None, _('show only normal files')),
3110 ('a', 'added', None, _('show only added files')),
3110 ('a', 'added', None, _('show only added files')),
3111 ('r', 'removed', None, _('show only removed files'))],
3111 ('r', 'removed', None, _('show only removed files'))],
3112 _('FILESPEC...'))
3112 _('FILESPEC...'))
3113 def debugpathcomplete(ui, repo, *specs, **opts):
3113 def debugpathcomplete(ui, repo, *specs, **opts):
3114 '''complete part or all of a tracked path
3114 '''complete part or all of a tracked path
3115
3115
3116 This command supports shells that offer path name completion. It
3116 This command supports shells that offer path name completion. It
3117 currently completes only files already known to the dirstate.
3117 currently completes only files already known to the dirstate.
3118
3118
3119 Completion extends only to the next path segment unless
3119 Completion extends only to the next path segment unless
3120 --full is specified, in which case entire paths are used.'''
3120 --full is specified, in which case entire paths are used.'''
3121
3121
3122 def complete(path, acceptable):
3122 def complete(path, acceptable):
3123 dirstate = repo.dirstate
3123 dirstate = repo.dirstate
3124 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3124 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3125 rootdir = repo.root + os.sep
3125 rootdir = repo.root + os.sep
3126 if spec != repo.root and not spec.startswith(rootdir):
3126 if spec != repo.root and not spec.startswith(rootdir):
3127 return [], []
3127 return [], []
3128 if os.path.isdir(spec):
3128 if os.path.isdir(spec):
3129 spec += '/'
3129 spec += '/'
3130 spec = spec[len(rootdir):]
3130 spec = spec[len(rootdir):]
3131 fixpaths = os.sep != '/'
3131 fixpaths = os.sep != '/'
3132 if fixpaths:
3132 if fixpaths:
3133 spec = spec.replace(os.sep, '/')
3133 spec = spec.replace(os.sep, '/')
3134 speclen = len(spec)
3134 speclen = len(spec)
3135 fullpaths = opts['full']
3135 fullpaths = opts['full']
3136 files, dirs = set(), set()
3136 files, dirs = set(), set()
3137 adddir, addfile = dirs.add, files.add
3137 adddir, addfile = dirs.add, files.add
3138 for f, st in dirstate.iteritems():
3138 for f, st in dirstate.iteritems():
3139 if f.startswith(spec) and st[0] in acceptable:
3139 if f.startswith(spec) and st[0] in acceptable:
3140 if fixpaths:
3140 if fixpaths:
3141 f = f.replace('/', os.sep)
3141 f = f.replace('/', os.sep)
3142 if fullpaths:
3142 if fullpaths:
3143 addfile(f)
3143 addfile(f)
3144 continue
3144 continue
3145 s = f.find(os.sep, speclen)
3145 s = f.find(os.sep, speclen)
3146 if s >= 0:
3146 if s >= 0:
3147 adddir(f[:s])
3147 adddir(f[:s])
3148 else:
3148 else:
3149 addfile(f)
3149 addfile(f)
3150 return files, dirs
3150 return files, dirs
3151
3151
3152 acceptable = ''
3152 acceptable = ''
3153 if opts['normal']:
3153 if opts['normal']:
3154 acceptable += 'nm'
3154 acceptable += 'nm'
3155 if opts['added']:
3155 if opts['added']:
3156 acceptable += 'a'
3156 acceptable += 'a'
3157 if opts['removed']:
3157 if opts['removed']:
3158 acceptable += 'r'
3158 acceptable += 'r'
3159 cwd = repo.getcwd()
3159 cwd = repo.getcwd()
3160 if not specs:
3160 if not specs:
3161 specs = ['.']
3161 specs = ['.']
3162
3162
3163 files, dirs = set(), set()
3163 files, dirs = set(), set()
3164 for spec in specs:
3164 for spec in specs:
3165 f, d = complete(spec, acceptable or 'nmar')
3165 f, d = complete(spec, acceptable or 'nmar')
3166 files.update(f)
3166 files.update(f)
3167 dirs.update(d)
3167 dirs.update(d)
3168 files.update(dirs)
3168 files.update(dirs)
3169 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3169 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3170 ui.write('\n')
3170 ui.write('\n')
3171
3171
3172 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3172 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3173 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3173 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3174 '''access the pushkey key/value protocol
3174 '''access the pushkey key/value protocol
3175
3175
3176 With two args, list the keys in the given namespace.
3176 With two args, list the keys in the given namespace.
3177
3177
3178 With five args, set a key to new if it currently is set to old.
3178 With five args, set a key to new if it currently is set to old.
3179 Reports success or failure.
3179 Reports success or failure.
3180 '''
3180 '''
3181
3181
3182 target = hg.peer(ui, {}, repopath)
3182 target = hg.peer(ui, {}, repopath)
3183 if keyinfo:
3183 if keyinfo:
3184 key, old, new = keyinfo
3184 key, old, new = keyinfo
3185 r = target.pushkey(namespace, key, old, new)
3185 r = target.pushkey(namespace, key, old, new)
3186 ui.status(str(r) + '\n')
3186 ui.status(str(r) + '\n')
3187 return not r
3187 return not r
3188 else:
3188 else:
3189 for k, v in sorted(target.listkeys(namespace).iteritems()):
3189 for k, v in sorted(target.listkeys(namespace).iteritems()):
3190 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3190 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3191 v.encode('string-escape')))
3191 v.encode('string-escape')))
3192
3192
3193 @command('debugpvec', [], _('A B'))
3193 @command('debugpvec', [], _('A B'))
3194 def debugpvec(ui, repo, a, b=None):
3194 def debugpvec(ui, repo, a, b=None):
3195 ca = scmutil.revsingle(repo, a)
3195 ca = scmutil.revsingle(repo, a)
3196 cb = scmutil.revsingle(repo, b)
3196 cb = scmutil.revsingle(repo, b)
3197 pa = pvec.ctxpvec(ca)
3197 pa = pvec.ctxpvec(ca)
3198 pb = pvec.ctxpvec(cb)
3198 pb = pvec.ctxpvec(cb)
3199 if pa == pb:
3199 if pa == pb:
3200 rel = "="
3200 rel = "="
3201 elif pa > pb:
3201 elif pa > pb:
3202 rel = ">"
3202 rel = ">"
3203 elif pa < pb:
3203 elif pa < pb:
3204 rel = "<"
3204 rel = "<"
3205 elif pa | pb:
3205 elif pa | pb:
3206 rel = "|"
3206 rel = "|"
3207 ui.write(_("a: %s\n") % pa)
3207 ui.write(_("a: %s\n") % pa)
3208 ui.write(_("b: %s\n") % pb)
3208 ui.write(_("b: %s\n") % pb)
3209 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3209 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3210 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3210 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3211 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3211 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3212 pa.distance(pb), rel))
3212 pa.distance(pb), rel))
3213
3213
3214 @command('debugrebuilddirstate|debugrebuildstate',
3214 @command('debugrebuilddirstate|debugrebuildstate',
3215 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3215 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3216 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3216 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3217 'the working copy parent')),
3217 'the working copy parent')),
3218 ],
3218 ],
3219 _('[-r REV]'))
3219 _('[-r REV]'))
3220 def debugrebuilddirstate(ui, repo, rev, **opts):
3220 def debugrebuilddirstate(ui, repo, rev, **opts):
3221 """rebuild the dirstate as it would look like for the given revision
3221 """rebuild the dirstate as it would look like for the given revision
3222
3222
3223 If no revision is specified the first current parent will be used.
3223 If no revision is specified the first current parent will be used.
3224
3224
3225 The dirstate will be set to the files of the given revision.
3225 The dirstate will be set to the files of the given revision.
3226 The actual working directory content or existing dirstate
3226 The actual working directory content or existing dirstate
3227 information such as adds or removes is not considered.
3227 information such as adds or removes is not considered.
3228
3228
3229 ``minimal`` will only rebuild the dirstate status for files that claim to be
3229 ``minimal`` will only rebuild the dirstate status for files that claim to be
3230 tracked but are not in the parent manifest, or that exist in the parent
3230 tracked but are not in the parent manifest, or that exist in the parent
3231 manifest but are not in the dirstate. It will not change adds, removes, or
3231 manifest but are not in the dirstate. It will not change adds, removes, or
3232 modified files that are in the working copy parent.
3232 modified files that are in the working copy parent.
3233
3233
3234 One use of this command is to make the next :hg:`status` invocation
3234 One use of this command is to make the next :hg:`status` invocation
3235 check the actual file content.
3235 check the actual file content.
3236 """
3236 """
3237 ctx = scmutil.revsingle(repo, rev)
3237 ctx = scmutil.revsingle(repo, rev)
3238 with repo.wlock():
3238 with repo.wlock():
3239 dirstate = repo.dirstate
3239 dirstate = repo.dirstate
3240 changedfiles = None
3240 changedfiles = None
3241 # See command doc for what minimal does.
3241 # See command doc for what minimal does.
3242 if opts.get('minimal'):
3242 if opts.get('minimal'):
3243 manifestfiles = set(ctx.manifest().keys())
3243 manifestfiles = set(ctx.manifest().keys())
3244 dirstatefiles = set(dirstate)
3244 dirstatefiles = set(dirstate)
3245 manifestonly = manifestfiles - dirstatefiles
3245 manifestonly = manifestfiles - dirstatefiles
3246 dsonly = dirstatefiles - manifestfiles
3246 dsonly = dirstatefiles - manifestfiles
3247 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3247 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3248 changedfiles = manifestonly | dsnotadded
3248 changedfiles = manifestonly | dsnotadded
3249
3249
3250 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3250 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3251
3251
3252 @command('debugrebuildfncache', [], '')
3252 @command('debugrebuildfncache', [], '')
3253 def debugrebuildfncache(ui, repo):
3253 def debugrebuildfncache(ui, repo):
3254 """rebuild the fncache file"""
3254 """rebuild the fncache file"""
3255 repair.rebuildfncache(ui, repo)
3255 repair.rebuildfncache(ui, repo)
3256
3256
3257 @command('debugrename',
3257 @command('debugrename',
3258 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3258 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3259 _('[-r REV] FILE'))
3259 _('[-r REV] FILE'))
3260 def debugrename(ui, repo, file1, *pats, **opts):
3260 def debugrename(ui, repo, file1, *pats, **opts):
3261 """dump rename information"""
3261 """dump rename information"""
3262
3262
3263 ctx = scmutil.revsingle(repo, opts.get('rev'))
3263 ctx = scmutil.revsingle(repo, opts.get('rev'))
3264 m = scmutil.match(ctx, (file1,) + pats, opts)
3264 m = scmutil.match(ctx, (file1,) + pats, opts)
3265 for abs in ctx.walk(m):
3265 for abs in ctx.walk(m):
3266 fctx = ctx[abs]
3266 fctx = ctx[abs]
3267 o = fctx.filelog().renamed(fctx.filenode())
3267 o = fctx.filelog().renamed(fctx.filenode())
3268 rel = m.rel(abs)
3268 rel = m.rel(abs)
3269 if o:
3269 if o:
3270 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3270 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3271 else:
3271 else:
3272 ui.write(_("%s not renamed\n") % rel)
3272 ui.write(_("%s not renamed\n") % rel)
3273
3273
3274 @command('debugrevlog', debugrevlogopts +
3274 @command('debugrevlog', debugrevlogopts +
3275 [('d', 'dump', False, _('dump index data'))],
3275 [('d', 'dump', False, _('dump index data'))],
3276 _('-c|-m|FILE'),
3276 _('-c|-m|FILE'),
3277 optionalrepo=True)
3277 optionalrepo=True)
3278 def debugrevlog(ui, repo, file_=None, **opts):
3278 def debugrevlog(ui, repo, file_=None, **opts):
3279 """show data and statistics about a revlog"""
3279 """show data and statistics about a revlog"""
3280 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3280 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3281
3281
3282 if opts.get("dump"):
3282 if opts.get("dump"):
3283 numrevs = len(r)
3283 numrevs = len(r)
3284 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3284 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3285 " rawsize totalsize compression heads chainlen\n")
3285 " rawsize totalsize compression heads chainlen\n")
3286 ts = 0
3286 ts = 0
3287 heads = set()
3287 heads = set()
3288
3288
3289 for rev in xrange(numrevs):
3289 for rev in xrange(numrevs):
3290 dbase = r.deltaparent(rev)
3290 dbase = r.deltaparent(rev)
3291 if dbase == -1:
3291 if dbase == -1:
3292 dbase = rev
3292 dbase = rev
3293 cbase = r.chainbase(rev)
3293 cbase = r.chainbase(rev)
3294 clen = r.chainlen(rev)
3294 clen = r.chainlen(rev)
3295 p1, p2 = r.parentrevs(rev)
3295 p1, p2 = r.parentrevs(rev)
3296 rs = r.rawsize(rev)
3296 rs = r.rawsize(rev)
3297 ts = ts + rs
3297 ts = ts + rs
3298 heads -= set(r.parentrevs(rev))
3298 heads -= set(r.parentrevs(rev))
3299 heads.add(rev)
3299 heads.add(rev)
3300 try:
3300 try:
3301 compression = ts / r.end(rev)
3301 compression = ts / r.end(rev)
3302 except ZeroDivisionError:
3302 except ZeroDivisionError:
3303 compression = 0
3303 compression = 0
3304 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3304 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3305 "%11d %5d %8d\n" %
3305 "%11d %5d %8d\n" %
3306 (rev, p1, p2, r.start(rev), r.end(rev),
3306 (rev, p1, p2, r.start(rev), r.end(rev),
3307 r.start(dbase), r.start(cbase),
3307 r.start(dbase), r.start(cbase),
3308 r.start(p1), r.start(p2),
3308 r.start(p1), r.start(p2),
3309 rs, ts, compression, len(heads), clen))
3309 rs, ts, compression, len(heads), clen))
3310 return 0
3310 return 0
3311
3311
3312 v = r.version
3312 v = r.version
3313 format = v & 0xFFFF
3313 format = v & 0xFFFF
3314 flags = []
3314 flags = []
3315 gdelta = False
3315 gdelta = False
3316 if v & revlog.REVLOGNGINLINEDATA:
3316 if v & revlog.REVLOGNGINLINEDATA:
3317 flags.append('inline')
3317 flags.append('inline')
3318 if v & revlog.REVLOGGENERALDELTA:
3318 if v & revlog.REVLOGGENERALDELTA:
3319 gdelta = True
3319 gdelta = True
3320 flags.append('generaldelta')
3320 flags.append('generaldelta')
3321 if not flags:
3321 if not flags:
3322 flags = ['(none)']
3322 flags = ['(none)']
3323
3323
3324 nummerges = 0
3324 nummerges = 0
3325 numfull = 0
3325 numfull = 0
3326 numprev = 0
3326 numprev = 0
3327 nump1 = 0
3327 nump1 = 0
3328 nump2 = 0
3328 nump2 = 0
3329 numother = 0
3329 numother = 0
3330 nump1prev = 0
3330 nump1prev = 0
3331 nump2prev = 0
3331 nump2prev = 0
3332 chainlengths = []
3332 chainlengths = []
3333
3333
3334 datasize = [None, 0, 0L]
3334 datasize = [None, 0, 0L]
3335 fullsize = [None, 0, 0L]
3335 fullsize = [None, 0, 0L]
3336 deltasize = [None, 0, 0L]
3336 deltasize = [None, 0, 0L]
3337
3337
3338 def addsize(size, l):
3338 def addsize(size, l):
3339 if l[0] is None or size < l[0]:
3339 if l[0] is None or size < l[0]:
3340 l[0] = size
3340 l[0] = size
3341 if size > l[1]:
3341 if size > l[1]:
3342 l[1] = size
3342 l[1] = size
3343 l[2] += size
3343 l[2] += size
3344
3344
3345 numrevs = len(r)
3345 numrevs = len(r)
3346 for rev in xrange(numrevs):
3346 for rev in xrange(numrevs):
3347 p1, p2 = r.parentrevs(rev)
3347 p1, p2 = r.parentrevs(rev)
3348 delta = r.deltaparent(rev)
3348 delta = r.deltaparent(rev)
3349 if format > 0:
3349 if format > 0:
3350 addsize(r.rawsize(rev), datasize)
3350 addsize(r.rawsize(rev), datasize)
3351 if p2 != nullrev:
3351 if p2 != nullrev:
3352 nummerges += 1
3352 nummerges += 1
3353 size = r.length(rev)
3353 size = r.length(rev)
3354 if delta == nullrev:
3354 if delta == nullrev:
3355 chainlengths.append(0)
3355 chainlengths.append(0)
3356 numfull += 1
3356 numfull += 1
3357 addsize(size, fullsize)
3357 addsize(size, fullsize)
3358 else:
3358 else:
3359 chainlengths.append(chainlengths[delta] + 1)
3359 chainlengths.append(chainlengths[delta] + 1)
3360 addsize(size, deltasize)
3360 addsize(size, deltasize)
3361 if delta == rev - 1:
3361 if delta == rev - 1:
3362 numprev += 1
3362 numprev += 1
3363 if delta == p1:
3363 if delta == p1:
3364 nump1prev += 1
3364 nump1prev += 1
3365 elif delta == p2:
3365 elif delta == p2:
3366 nump2prev += 1
3366 nump2prev += 1
3367 elif delta == p1:
3367 elif delta == p1:
3368 nump1 += 1
3368 nump1 += 1
3369 elif delta == p2:
3369 elif delta == p2:
3370 nump2 += 1
3370 nump2 += 1
3371 elif delta != nullrev:
3371 elif delta != nullrev:
3372 numother += 1
3372 numother += 1
3373
3373
3374 # Adjust size min value for empty cases
3374 # Adjust size min value for empty cases
3375 for size in (datasize, fullsize, deltasize):
3375 for size in (datasize, fullsize, deltasize):
3376 if size[0] is None:
3376 if size[0] is None:
3377 size[0] = 0
3377 size[0] = 0
3378
3378
3379 numdeltas = numrevs - numfull
3379 numdeltas = numrevs - numfull
3380 numoprev = numprev - nump1prev - nump2prev
3380 numoprev = numprev - nump1prev - nump2prev
3381 totalrawsize = datasize[2]
3381 totalrawsize = datasize[2]
3382 datasize[2] /= numrevs
3382 datasize[2] /= numrevs
3383 fulltotal = fullsize[2]
3383 fulltotal = fullsize[2]
3384 fullsize[2] /= numfull
3384 fullsize[2] /= numfull
3385 deltatotal = deltasize[2]
3385 deltatotal = deltasize[2]
3386 if numrevs - numfull > 0:
3386 if numrevs - numfull > 0:
3387 deltasize[2] /= numrevs - numfull
3387 deltasize[2] /= numrevs - numfull
3388 totalsize = fulltotal + deltatotal
3388 totalsize = fulltotal + deltatotal
3389 avgchainlen = sum(chainlengths) / numrevs
3389 avgchainlen = sum(chainlengths) / numrevs
3390 maxchainlen = max(chainlengths)
3390 maxchainlen = max(chainlengths)
3391 compratio = 1
3391 compratio = 1
3392 if totalsize:
3392 if totalsize:
3393 compratio = totalrawsize / totalsize
3393 compratio = totalrawsize / totalsize
3394
3394
3395 basedfmtstr = '%%%dd\n'
3395 basedfmtstr = '%%%dd\n'
3396 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3396 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3397
3397
3398 def dfmtstr(max):
3398 def dfmtstr(max):
3399 return basedfmtstr % len(str(max))
3399 return basedfmtstr % len(str(max))
3400 def pcfmtstr(max, padding=0):
3400 def pcfmtstr(max, padding=0):
3401 return basepcfmtstr % (len(str(max)), ' ' * padding)
3401 return basepcfmtstr % (len(str(max)), ' ' * padding)
3402
3402
3403 def pcfmt(value, total):
3403 def pcfmt(value, total):
3404 if total:
3404 if total:
3405 return (value, 100 * float(value) / total)
3405 return (value, 100 * float(value) / total)
3406 else:
3406 else:
3407 return value, 100.0
3407 return value, 100.0
3408
3408
3409 ui.write(('format : %d\n') % format)
3409 ui.write(('format : %d\n') % format)
3410 ui.write(('flags : %s\n') % ', '.join(flags))
3410 ui.write(('flags : %s\n') % ', '.join(flags))
3411
3411
3412 ui.write('\n')
3412 ui.write('\n')
3413 fmt = pcfmtstr(totalsize)
3413 fmt = pcfmtstr(totalsize)
3414 fmt2 = dfmtstr(totalsize)
3414 fmt2 = dfmtstr(totalsize)
3415 ui.write(('revisions : ') + fmt2 % numrevs)
3415 ui.write(('revisions : ') + fmt2 % numrevs)
3416 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3416 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3417 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3417 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3418 ui.write(('revisions : ') + fmt2 % numrevs)
3418 ui.write(('revisions : ') + fmt2 % numrevs)
3419 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3419 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3420 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3420 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3421 ui.write(('revision size : ') + fmt2 % totalsize)
3421 ui.write(('revision size : ') + fmt2 % totalsize)
3422 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3422 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3423 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3423 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3424
3424
3425 ui.write('\n')
3425 ui.write('\n')
3426 fmt = dfmtstr(max(avgchainlen, compratio))
3426 fmt = dfmtstr(max(avgchainlen, compratio))
3427 ui.write(('avg chain length : ') + fmt % avgchainlen)
3427 ui.write(('avg chain length : ') + fmt % avgchainlen)
3428 ui.write(('max chain length : ') + fmt % maxchainlen)
3428 ui.write(('max chain length : ') + fmt % maxchainlen)
3429 ui.write(('compression ratio : ') + fmt % compratio)
3429 ui.write(('compression ratio : ') + fmt % compratio)
3430
3430
3431 if format > 0:
3431 if format > 0:
3432 ui.write('\n')
3432 ui.write('\n')
3433 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3433 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3434 % tuple(datasize))
3434 % tuple(datasize))
3435 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3435 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3436 % tuple(fullsize))
3436 % tuple(fullsize))
3437 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3437 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3438 % tuple(deltasize))
3438 % tuple(deltasize))
3439
3439
3440 if numdeltas > 0:
3440 if numdeltas > 0:
3441 ui.write('\n')
3441 ui.write('\n')
3442 fmt = pcfmtstr(numdeltas)
3442 fmt = pcfmtstr(numdeltas)
3443 fmt2 = pcfmtstr(numdeltas, 4)
3443 fmt2 = pcfmtstr(numdeltas, 4)
3444 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3444 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3445 if numprev > 0:
3445 if numprev > 0:
3446 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3446 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3447 numprev))
3447 numprev))
3448 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3448 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3449 numprev))
3449 numprev))
3450 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3450 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3451 numprev))
3451 numprev))
3452 if gdelta:
3452 if gdelta:
3453 ui.write(('deltas against p1 : ')
3453 ui.write(('deltas against p1 : ')
3454 + fmt % pcfmt(nump1, numdeltas))
3454 + fmt % pcfmt(nump1, numdeltas))
3455 ui.write(('deltas against p2 : ')
3455 ui.write(('deltas against p2 : ')
3456 + fmt % pcfmt(nump2, numdeltas))
3456 + fmt % pcfmt(nump2, numdeltas))
3457 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3457 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3458 numdeltas))
3458 numdeltas))
3459
3459
3460 @command('debugrevspec',
3460 @command('debugrevspec',
3461 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3461 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3462 ('REVSPEC'))
3462 ('REVSPEC'))
3463 def debugrevspec(ui, repo, expr, **opts):
3463 def debugrevspec(ui, repo, expr, **opts):
3464 """parse and apply a revision specification
3464 """parse and apply a revision specification
3465
3465
3466 Use --verbose to print the parsed tree before and after aliases
3466 Use --verbose to print the parsed tree before and after aliases
3467 expansion.
3467 expansion.
3468 """
3468 """
3469 if ui.verbose:
3469 if ui.verbose:
3470 tree = revset.parse(expr, lookup=repo.__contains__)
3470 tree = revset.parse(expr, lookup=repo.__contains__)
3471 ui.note(revset.prettyformat(tree), "\n")
3471 ui.note(revset.prettyformat(tree), "\n")
3472 newtree = revset.findaliases(ui, tree)
3472 newtree = revset.findaliases(ui, tree)
3473 if newtree != tree:
3473 if newtree != tree:
3474 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3474 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3475 tree = newtree
3475 tree = newtree
3476 newtree = revset.foldconcat(tree)
3476 newtree = revset.foldconcat(tree)
3477 if newtree != tree:
3477 if newtree != tree:
3478 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3478 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3479 if opts["optimize"]:
3479 if opts["optimize"]:
3480 weight, optimizedtree = revset.optimize(newtree, True)
3480 weight, optimizedtree = revset.optimize(newtree, True)
3481 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3481 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3482 func = revset.match(ui, expr, repo)
3482 func = revset.match(ui, expr, repo)
3483 revs = func(repo)
3483 revs = func(repo)
3484 if ui.verbose:
3484 if ui.verbose:
3485 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3485 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3486 for c in revs:
3486 for c in revs:
3487 ui.write("%s\n" % c)
3487 ui.write("%s\n" % c)
3488
3488
3489 @command('debugsetparents', [], _('REV1 [REV2]'))
3489 @command('debugsetparents', [], _('REV1 [REV2]'))
3490 def debugsetparents(ui, repo, rev1, rev2=None):
3490 def debugsetparents(ui, repo, rev1, rev2=None):
3491 """manually set the parents of the current working directory
3491 """manually set the parents of the current working directory
3492
3492
3493 This is useful for writing repository conversion tools, but should
3493 This is useful for writing repository conversion tools, but should
3494 be used with care. For example, neither the working directory nor the
3494 be used with care. For example, neither the working directory nor the
3495 dirstate is updated, so file status may be incorrect after running this
3495 dirstate is updated, so file status may be incorrect after running this
3496 command.
3496 command.
3497
3497
3498 Returns 0 on success.
3498 Returns 0 on success.
3499 """
3499 """
3500
3500
3501 r1 = scmutil.revsingle(repo, rev1).node()
3501 r1 = scmutil.revsingle(repo, rev1).node()
3502 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3502 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3503
3503
3504 with repo.wlock():
3504 with repo.wlock():
3505 repo.dirstate.beginparentchange()
3506 repo.setparents(r1, r2)
3505 repo.setparents(r1, r2)
3507 repo.dirstate.endparentchange()
3508
3506
3509 @command('debugdirstate|debugstate',
3507 @command('debugdirstate|debugstate',
3510 [('', 'nodates', None, _('do not display the saved mtime')),
3508 [('', 'nodates', None, _('do not display the saved mtime')),
3511 ('', 'datesort', None, _('sort by saved mtime'))],
3509 ('', 'datesort', None, _('sort by saved mtime'))],
3512 _('[OPTION]...'))
3510 _('[OPTION]...'))
3513 def debugstate(ui, repo, **opts):
3511 def debugstate(ui, repo, **opts):
3514 """show the contents of the current dirstate"""
3512 """show the contents of the current dirstate"""
3515
3513
3516 nodates = opts.get('nodates')
3514 nodates = opts.get('nodates')
3517 datesort = opts.get('datesort')
3515 datesort = opts.get('datesort')
3518
3516
3519 timestr = ""
3517 timestr = ""
3520 if datesort:
3518 if datesort:
3521 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3519 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3522 else:
3520 else:
3523 keyfunc = None # sort by filename
3521 keyfunc = None # sort by filename
3524 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3522 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3525 if ent[3] == -1:
3523 if ent[3] == -1:
3526 timestr = 'unset '
3524 timestr = 'unset '
3527 elif nodates:
3525 elif nodates:
3528 timestr = 'set '
3526 timestr = 'set '
3529 else:
3527 else:
3530 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3528 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3531 time.localtime(ent[3]))
3529 time.localtime(ent[3]))
3532 if ent[1] & 0o20000:
3530 if ent[1] & 0o20000:
3533 mode = 'lnk'
3531 mode = 'lnk'
3534 else:
3532 else:
3535 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3533 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3536 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3534 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3537 for f in repo.dirstate.copies():
3535 for f in repo.dirstate.copies():
3538 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3536 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3539
3537
3540 @command('debugsub',
3538 @command('debugsub',
3541 [('r', 'rev', '',
3539 [('r', 'rev', '',
3542 _('revision to check'), _('REV'))],
3540 _('revision to check'), _('REV'))],
3543 _('[-r REV] [REV]'))
3541 _('[-r REV] [REV]'))
3544 def debugsub(ui, repo, rev=None):
3542 def debugsub(ui, repo, rev=None):
3545 ctx = scmutil.revsingle(repo, rev, None)
3543 ctx = scmutil.revsingle(repo, rev, None)
3546 for k, v in sorted(ctx.substate.items()):
3544 for k, v in sorted(ctx.substate.items()):
3547 ui.write(('path %s\n') % k)
3545 ui.write(('path %s\n') % k)
3548 ui.write((' source %s\n') % v[0])
3546 ui.write((' source %s\n') % v[0])
3549 ui.write((' revision %s\n') % v[1])
3547 ui.write((' revision %s\n') % v[1])
3550
3548
3551 @command('debugsuccessorssets',
3549 @command('debugsuccessorssets',
3552 [],
3550 [],
3553 _('[REV]'))
3551 _('[REV]'))
3554 def debugsuccessorssets(ui, repo, *revs):
3552 def debugsuccessorssets(ui, repo, *revs):
3555 """show set of successors for revision
3553 """show set of successors for revision
3556
3554
3557 A successors set of changeset A is a consistent group of revisions that
3555 A successors set of changeset A is a consistent group of revisions that
3558 succeed A. It contains non-obsolete changesets only.
3556 succeed A. It contains non-obsolete changesets only.
3559
3557
3560 In most cases a changeset A has a single successors set containing a single
3558 In most cases a changeset A has a single successors set containing a single
3561 successor (changeset A replaced by A').
3559 successor (changeset A replaced by A').
3562
3560
3563 A changeset that is made obsolete with no successors are called "pruned".
3561 A changeset that is made obsolete with no successors are called "pruned".
3564 Such changesets have no successors sets at all.
3562 Such changesets have no successors sets at all.
3565
3563
3566 A changeset that has been "split" will have a successors set containing
3564 A changeset that has been "split" will have a successors set containing
3567 more than one successor.
3565 more than one successor.
3568
3566
3569 A changeset that has been rewritten in multiple different ways is called
3567 A changeset that has been rewritten in multiple different ways is called
3570 "divergent". Such changesets have multiple successor sets (each of which
3568 "divergent". Such changesets have multiple successor sets (each of which
3571 may also be split, i.e. have multiple successors).
3569 may also be split, i.e. have multiple successors).
3572
3570
3573 Results are displayed as follows::
3571 Results are displayed as follows::
3574
3572
3575 <rev1>
3573 <rev1>
3576 <successors-1A>
3574 <successors-1A>
3577 <rev2>
3575 <rev2>
3578 <successors-2A>
3576 <successors-2A>
3579 <successors-2B1> <successors-2B2> <successors-2B3>
3577 <successors-2B1> <successors-2B2> <successors-2B3>
3580
3578
3581 Here rev2 has two possible (i.e. divergent) successors sets. The first
3579 Here rev2 has two possible (i.e. divergent) successors sets. The first
3582 holds one element, whereas the second holds three (i.e. the changeset has
3580 holds one element, whereas the second holds three (i.e. the changeset has
3583 been split).
3581 been split).
3584 """
3582 """
3585 # passed to successorssets caching computation from one call to another
3583 # passed to successorssets caching computation from one call to another
3586 cache = {}
3584 cache = {}
3587 ctx2str = str
3585 ctx2str = str
3588 node2str = short
3586 node2str = short
3589 if ui.debug():
3587 if ui.debug():
3590 def ctx2str(ctx):
3588 def ctx2str(ctx):
3591 return ctx.hex()
3589 return ctx.hex()
3592 node2str = hex
3590 node2str = hex
3593 for rev in scmutil.revrange(repo, revs):
3591 for rev in scmutil.revrange(repo, revs):
3594 ctx = repo[rev]
3592 ctx = repo[rev]
3595 ui.write('%s\n'% ctx2str(ctx))
3593 ui.write('%s\n'% ctx2str(ctx))
3596 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3594 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3597 if succsset:
3595 if succsset:
3598 ui.write(' ')
3596 ui.write(' ')
3599 ui.write(node2str(succsset[0]))
3597 ui.write(node2str(succsset[0]))
3600 for node in succsset[1:]:
3598 for node in succsset[1:]:
3601 ui.write(' ')
3599 ui.write(' ')
3602 ui.write(node2str(node))
3600 ui.write(node2str(node))
3603 ui.write('\n')
3601 ui.write('\n')
3604
3602
3605 @command('debugtemplate',
3603 @command('debugtemplate',
3606 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3604 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3607 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3605 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3608 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3606 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3609 optionalrepo=True)
3607 optionalrepo=True)
3610 def debugtemplate(ui, repo, tmpl, **opts):
3608 def debugtemplate(ui, repo, tmpl, **opts):
3611 """parse and apply a template
3609 """parse and apply a template
3612
3610
3613 If -r/--rev is given, the template is processed as a log template and
3611 If -r/--rev is given, the template is processed as a log template and
3614 applied to the given changesets. Otherwise, it is processed as a generic
3612 applied to the given changesets. Otherwise, it is processed as a generic
3615 template.
3613 template.
3616
3614
3617 Use --verbose to print the parsed tree.
3615 Use --verbose to print the parsed tree.
3618 """
3616 """
3619 revs = None
3617 revs = None
3620 if opts['rev']:
3618 if opts['rev']:
3621 if repo is None:
3619 if repo is None:
3622 raise error.RepoError(_('there is no Mercurial repository here '
3620 raise error.RepoError(_('there is no Mercurial repository here '
3623 '(.hg not found)'))
3621 '(.hg not found)'))
3624 revs = scmutil.revrange(repo, opts['rev'])
3622 revs = scmutil.revrange(repo, opts['rev'])
3625
3623
3626 props = {}
3624 props = {}
3627 for d in opts['define']:
3625 for d in opts['define']:
3628 try:
3626 try:
3629 k, v = (e.strip() for e in d.split('=', 1))
3627 k, v = (e.strip() for e in d.split('=', 1))
3630 if not k:
3628 if not k:
3631 raise ValueError
3629 raise ValueError
3632 props[k] = v
3630 props[k] = v
3633 except ValueError:
3631 except ValueError:
3634 raise error.Abort(_('malformed keyword definition: %s') % d)
3632 raise error.Abort(_('malformed keyword definition: %s') % d)
3635
3633
3636 if ui.verbose:
3634 if ui.verbose:
3637 tree = templater.parse(tmpl)
3635 tree = templater.parse(tmpl)
3638 ui.note(templater.prettyformat(tree), '\n')
3636 ui.note(templater.prettyformat(tree), '\n')
3639
3637
3640 mapfile = None
3638 mapfile = None
3641 if revs is None:
3639 if revs is None:
3642 k = 'debugtemplate'
3640 k = 'debugtemplate'
3643 t = templater.templater(mapfile)
3641 t = templater.templater(mapfile)
3644 t.cache[k] = tmpl
3642 t.cache[k] = tmpl
3645 ui.write(templater.stringify(t(k, **props)))
3643 ui.write(templater.stringify(t(k, **props)))
3646 else:
3644 else:
3647 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3645 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3648 mapfile, buffered=False)
3646 mapfile, buffered=False)
3649 for r in revs:
3647 for r in revs:
3650 displayer.show(repo[r], **props)
3648 displayer.show(repo[r], **props)
3651 displayer.close()
3649 displayer.close()
3652
3650
3653 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3651 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3654 def debugwalk(ui, repo, *pats, **opts):
3652 def debugwalk(ui, repo, *pats, **opts):
3655 """show how files match on given patterns"""
3653 """show how files match on given patterns"""
3656 m = scmutil.match(repo[None], pats, opts)
3654 m = scmutil.match(repo[None], pats, opts)
3657 items = list(repo.walk(m))
3655 items = list(repo.walk(m))
3658 if not items:
3656 if not items:
3659 return
3657 return
3660 f = lambda fn: fn
3658 f = lambda fn: fn
3661 if ui.configbool('ui', 'slash') and os.sep != '/':
3659 if ui.configbool('ui', 'slash') and os.sep != '/':
3662 f = lambda fn: util.normpath(fn)
3660 f = lambda fn: util.normpath(fn)
3663 fmt = 'f %%-%ds %%-%ds %%s' % (
3661 fmt = 'f %%-%ds %%-%ds %%s' % (
3664 max([len(abs) for abs in items]),
3662 max([len(abs) for abs in items]),
3665 max([len(m.rel(abs)) for abs in items]))
3663 max([len(m.rel(abs)) for abs in items]))
3666 for abs in items:
3664 for abs in items:
3667 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3665 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3668 ui.write("%s\n" % line.rstrip())
3666 ui.write("%s\n" % line.rstrip())
3669
3667
3670 @command('debugwireargs',
3668 @command('debugwireargs',
3671 [('', 'three', '', 'three'),
3669 [('', 'three', '', 'three'),
3672 ('', 'four', '', 'four'),
3670 ('', 'four', '', 'four'),
3673 ('', 'five', '', 'five'),
3671 ('', 'five', '', 'five'),
3674 ] + remoteopts,
3672 ] + remoteopts,
3675 _('REPO [OPTIONS]... [ONE [TWO]]'),
3673 _('REPO [OPTIONS]... [ONE [TWO]]'),
3676 norepo=True)
3674 norepo=True)
3677 def debugwireargs(ui, repopath, *vals, **opts):
3675 def debugwireargs(ui, repopath, *vals, **opts):
3678 repo = hg.peer(ui, opts, repopath)
3676 repo = hg.peer(ui, opts, repopath)
3679 for opt in remoteopts:
3677 for opt in remoteopts:
3680 del opts[opt[1]]
3678 del opts[opt[1]]
3681 args = {}
3679 args = {}
3682 for k, v in opts.iteritems():
3680 for k, v in opts.iteritems():
3683 if v:
3681 if v:
3684 args[k] = v
3682 args[k] = v
3685 # run twice to check that we don't mess up the stream for the next command
3683 # run twice to check that we don't mess up the stream for the next command
3686 res1 = repo.debugwireargs(*vals, **args)
3684 res1 = repo.debugwireargs(*vals, **args)
3687 res2 = repo.debugwireargs(*vals, **args)
3685 res2 = repo.debugwireargs(*vals, **args)
3688 ui.write("%s\n" % res1)
3686 ui.write("%s\n" % res1)
3689 if res1 != res2:
3687 if res1 != res2:
3690 ui.warn("%s\n" % res2)
3688 ui.warn("%s\n" % res2)
3691
3689
3692 @command('^diff',
3690 @command('^diff',
3693 [('r', 'rev', [], _('revision'), _('REV')),
3691 [('r', 'rev', [], _('revision'), _('REV')),
3694 ('c', 'change', '', _('change made by revision'), _('REV'))
3692 ('c', 'change', '', _('change made by revision'), _('REV'))
3695 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3693 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3696 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3694 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3697 inferrepo=True)
3695 inferrepo=True)
3698 def diff(ui, repo, *pats, **opts):
3696 def diff(ui, repo, *pats, **opts):
3699 """diff repository (or selected files)
3697 """diff repository (or selected files)
3700
3698
3701 Show differences between revisions for the specified files.
3699 Show differences between revisions for the specified files.
3702
3700
3703 Differences between files are shown using the unified diff format.
3701 Differences between files are shown using the unified diff format.
3704
3702
3705 .. note::
3703 .. note::
3706
3704
3707 :hg:`diff` may generate unexpected results for merges, as it will
3705 :hg:`diff` may generate unexpected results for merges, as it will
3708 default to comparing against the working directory's first
3706 default to comparing against the working directory's first
3709 parent changeset if no revisions are specified.
3707 parent changeset if no revisions are specified.
3710
3708
3711 When two revision arguments are given, then changes are shown
3709 When two revision arguments are given, then changes are shown
3712 between those revisions. If only one revision is specified then
3710 between those revisions. If only one revision is specified then
3713 that revision is compared to the working directory, and, when no
3711 that revision is compared to the working directory, and, when no
3714 revisions are specified, the working directory files are compared
3712 revisions are specified, the working directory files are compared
3715 to its first parent.
3713 to its first parent.
3716
3714
3717 Alternatively you can specify -c/--change with a revision to see
3715 Alternatively you can specify -c/--change with a revision to see
3718 the changes in that changeset relative to its first parent.
3716 the changes in that changeset relative to its first parent.
3719
3717
3720 Without the -a/--text option, diff will avoid generating diffs of
3718 Without the -a/--text option, diff will avoid generating diffs of
3721 files it detects as binary. With -a, diff will generate a diff
3719 files it detects as binary. With -a, diff will generate a diff
3722 anyway, probably with undesirable results.
3720 anyway, probably with undesirable results.
3723
3721
3724 Use the -g/--git option to generate diffs in the git extended diff
3722 Use the -g/--git option to generate diffs in the git extended diff
3725 format. For more information, read :hg:`help diffs`.
3723 format. For more information, read :hg:`help diffs`.
3726
3724
3727 .. container:: verbose
3725 .. container:: verbose
3728
3726
3729 Examples:
3727 Examples:
3730
3728
3731 - compare a file in the current working directory to its parent::
3729 - compare a file in the current working directory to its parent::
3732
3730
3733 hg diff foo.c
3731 hg diff foo.c
3734
3732
3735 - compare two historical versions of a directory, with rename info::
3733 - compare two historical versions of a directory, with rename info::
3736
3734
3737 hg diff --git -r 1.0:1.2 lib/
3735 hg diff --git -r 1.0:1.2 lib/
3738
3736
3739 - get change stats relative to the last change on some date::
3737 - get change stats relative to the last change on some date::
3740
3738
3741 hg diff --stat -r "date('may 2')"
3739 hg diff --stat -r "date('may 2')"
3742
3740
3743 - diff all newly-added files that contain a keyword::
3741 - diff all newly-added files that contain a keyword::
3744
3742
3745 hg diff "set:added() and grep(GNU)"
3743 hg diff "set:added() and grep(GNU)"
3746
3744
3747 - compare a revision and its parents::
3745 - compare a revision and its parents::
3748
3746
3749 hg diff -c 9353 # compare against first parent
3747 hg diff -c 9353 # compare against first parent
3750 hg diff -r 9353^:9353 # same using revset syntax
3748 hg diff -r 9353^:9353 # same using revset syntax
3751 hg diff -r 9353^2:9353 # compare against the second parent
3749 hg diff -r 9353^2:9353 # compare against the second parent
3752
3750
3753 Returns 0 on success.
3751 Returns 0 on success.
3754 """
3752 """
3755
3753
3756 revs = opts.get('rev')
3754 revs = opts.get('rev')
3757 change = opts.get('change')
3755 change = opts.get('change')
3758 stat = opts.get('stat')
3756 stat = opts.get('stat')
3759 reverse = opts.get('reverse')
3757 reverse = opts.get('reverse')
3760
3758
3761 if revs and change:
3759 if revs and change:
3762 msg = _('cannot specify --rev and --change at the same time')
3760 msg = _('cannot specify --rev and --change at the same time')
3763 raise error.Abort(msg)
3761 raise error.Abort(msg)
3764 elif change:
3762 elif change:
3765 node2 = scmutil.revsingle(repo, change, None).node()
3763 node2 = scmutil.revsingle(repo, change, None).node()
3766 node1 = repo[node2].p1().node()
3764 node1 = repo[node2].p1().node()
3767 else:
3765 else:
3768 node1, node2 = scmutil.revpair(repo, revs)
3766 node1, node2 = scmutil.revpair(repo, revs)
3769
3767
3770 if reverse:
3768 if reverse:
3771 node1, node2 = node2, node1
3769 node1, node2 = node2, node1
3772
3770
3773 diffopts = patch.diffallopts(ui, opts)
3771 diffopts = patch.diffallopts(ui, opts)
3774 m = scmutil.match(repo[node2], pats, opts)
3772 m = scmutil.match(repo[node2], pats, opts)
3775 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3773 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3776 listsubrepos=opts.get('subrepos'),
3774 listsubrepos=opts.get('subrepos'),
3777 root=opts.get('root'))
3775 root=opts.get('root'))
3778
3776
3779 @command('^export',
3777 @command('^export',
3780 [('o', 'output', '',
3778 [('o', 'output', '',
3781 _('print output to file with formatted name'), _('FORMAT')),
3779 _('print output to file with formatted name'), _('FORMAT')),
3782 ('', 'switch-parent', None, _('diff against the second parent')),
3780 ('', 'switch-parent', None, _('diff against the second parent')),
3783 ('r', 'rev', [], _('revisions to export'), _('REV')),
3781 ('r', 'rev', [], _('revisions to export'), _('REV')),
3784 ] + diffopts,
3782 ] + diffopts,
3785 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3783 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3786 def export(ui, repo, *changesets, **opts):
3784 def export(ui, repo, *changesets, **opts):
3787 """dump the header and diffs for one or more changesets
3785 """dump the header and diffs for one or more changesets
3788
3786
3789 Print the changeset header and diffs for one or more revisions.
3787 Print the changeset header and diffs for one or more revisions.
3790 If no revision is given, the parent of the working directory is used.
3788 If no revision is given, the parent of the working directory is used.
3791
3789
3792 The information shown in the changeset header is: author, date,
3790 The information shown in the changeset header is: author, date,
3793 branch name (if non-default), changeset hash, parent(s) and commit
3791 branch name (if non-default), changeset hash, parent(s) and commit
3794 comment.
3792 comment.
3795
3793
3796 .. note::
3794 .. note::
3797
3795
3798 :hg:`export` may generate unexpected diff output for merge
3796 :hg:`export` may generate unexpected diff output for merge
3799 changesets, as it will compare the merge changeset against its
3797 changesets, as it will compare the merge changeset against its
3800 first parent only.
3798 first parent only.
3801
3799
3802 Output may be to a file, in which case the name of the file is
3800 Output may be to a file, in which case the name of the file is
3803 given using a format string. The formatting rules are as follows:
3801 given using a format string. The formatting rules are as follows:
3804
3802
3805 :``%%``: literal "%" character
3803 :``%%``: literal "%" character
3806 :``%H``: changeset hash (40 hexadecimal digits)
3804 :``%H``: changeset hash (40 hexadecimal digits)
3807 :``%N``: number of patches being generated
3805 :``%N``: number of patches being generated
3808 :``%R``: changeset revision number
3806 :``%R``: changeset revision number
3809 :``%b``: basename of the exporting repository
3807 :``%b``: basename of the exporting repository
3810 :``%h``: short-form changeset hash (12 hexadecimal digits)
3808 :``%h``: short-form changeset hash (12 hexadecimal digits)
3811 :``%m``: first line of the commit message (only alphanumeric characters)
3809 :``%m``: first line of the commit message (only alphanumeric characters)
3812 :``%n``: zero-padded sequence number, starting at 1
3810 :``%n``: zero-padded sequence number, starting at 1
3813 :``%r``: zero-padded changeset revision number
3811 :``%r``: zero-padded changeset revision number
3814
3812
3815 Without the -a/--text option, export will avoid generating diffs
3813 Without the -a/--text option, export will avoid generating diffs
3816 of files it detects as binary. With -a, export will generate a
3814 of files it detects as binary. With -a, export will generate a
3817 diff anyway, probably with undesirable results.
3815 diff anyway, probably with undesirable results.
3818
3816
3819 Use the -g/--git option to generate diffs in the git extended diff
3817 Use the -g/--git option to generate diffs in the git extended diff
3820 format. See :hg:`help diffs` for more information.
3818 format. See :hg:`help diffs` for more information.
3821
3819
3822 With the --switch-parent option, the diff will be against the
3820 With the --switch-parent option, the diff will be against the
3823 second parent. It can be useful to review a merge.
3821 second parent. It can be useful to review a merge.
3824
3822
3825 .. container:: verbose
3823 .. container:: verbose
3826
3824
3827 Examples:
3825 Examples:
3828
3826
3829 - use export and import to transplant a bugfix to the current
3827 - use export and import to transplant a bugfix to the current
3830 branch::
3828 branch::
3831
3829
3832 hg export -r 9353 | hg import -
3830 hg export -r 9353 | hg import -
3833
3831
3834 - export all the changesets between two revisions to a file with
3832 - export all the changesets between two revisions to a file with
3835 rename information::
3833 rename information::
3836
3834
3837 hg export --git -r 123:150 > changes.txt
3835 hg export --git -r 123:150 > changes.txt
3838
3836
3839 - split outgoing changes into a series of patches with
3837 - split outgoing changes into a series of patches with
3840 descriptive names::
3838 descriptive names::
3841
3839
3842 hg export -r "outgoing()" -o "%n-%m.patch"
3840 hg export -r "outgoing()" -o "%n-%m.patch"
3843
3841
3844 Returns 0 on success.
3842 Returns 0 on success.
3845 """
3843 """
3846 changesets += tuple(opts.get('rev', []))
3844 changesets += tuple(opts.get('rev', []))
3847 if not changesets:
3845 if not changesets:
3848 changesets = ['.']
3846 changesets = ['.']
3849 revs = scmutil.revrange(repo, changesets)
3847 revs = scmutil.revrange(repo, changesets)
3850 if not revs:
3848 if not revs:
3851 raise error.Abort(_("export requires at least one changeset"))
3849 raise error.Abort(_("export requires at least one changeset"))
3852 if len(revs) > 1:
3850 if len(revs) > 1:
3853 ui.note(_('exporting patches:\n'))
3851 ui.note(_('exporting patches:\n'))
3854 else:
3852 else:
3855 ui.note(_('exporting patch:\n'))
3853 ui.note(_('exporting patch:\n'))
3856 cmdutil.export(repo, revs, template=opts.get('output'),
3854 cmdutil.export(repo, revs, template=opts.get('output'),
3857 switch_parent=opts.get('switch_parent'),
3855 switch_parent=opts.get('switch_parent'),
3858 opts=patch.diffallopts(ui, opts))
3856 opts=patch.diffallopts(ui, opts))
3859
3857
3860 @command('files',
3858 @command('files',
3861 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3859 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3862 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3860 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3863 ] + walkopts + formatteropts + subrepoopts,
3861 ] + walkopts + formatteropts + subrepoopts,
3864 _('[OPTION]... [PATTERN]...'))
3862 _('[OPTION]... [PATTERN]...'))
3865 def files(ui, repo, *pats, **opts):
3863 def files(ui, repo, *pats, **opts):
3866 """list tracked files
3864 """list tracked files
3867
3865
3868 Print files under Mercurial control in the working directory or
3866 Print files under Mercurial control in the working directory or
3869 specified revision whose names match the given patterns (excluding
3867 specified revision whose names match the given patterns (excluding
3870 removed files).
3868 removed files).
3871
3869
3872 If no patterns are given to match, this command prints the names
3870 If no patterns are given to match, this command prints the names
3873 of all files under Mercurial control in the working directory.
3871 of all files under Mercurial control in the working directory.
3874
3872
3875 .. container:: verbose
3873 .. container:: verbose
3876
3874
3877 Examples:
3875 Examples:
3878
3876
3879 - list all files under the current directory::
3877 - list all files under the current directory::
3880
3878
3881 hg files .
3879 hg files .
3882
3880
3883 - shows sizes and flags for current revision::
3881 - shows sizes and flags for current revision::
3884
3882
3885 hg files -vr .
3883 hg files -vr .
3886
3884
3887 - list all files named README::
3885 - list all files named README::
3888
3886
3889 hg files -I "**/README"
3887 hg files -I "**/README"
3890
3888
3891 - list all binary files::
3889 - list all binary files::
3892
3890
3893 hg files "set:binary()"
3891 hg files "set:binary()"
3894
3892
3895 - find files containing a regular expression::
3893 - find files containing a regular expression::
3896
3894
3897 hg files "set:grep('bob')"
3895 hg files "set:grep('bob')"
3898
3896
3899 - search tracked file contents with xargs and grep::
3897 - search tracked file contents with xargs and grep::
3900
3898
3901 hg files -0 | xargs -0 grep foo
3899 hg files -0 | xargs -0 grep foo
3902
3900
3903 See :hg:`help patterns` and :hg:`help filesets` for more information
3901 See :hg:`help patterns` and :hg:`help filesets` for more information
3904 on specifying file patterns.
3902 on specifying file patterns.
3905
3903
3906 Returns 0 if a match is found, 1 otherwise.
3904 Returns 0 if a match is found, 1 otherwise.
3907
3905
3908 """
3906 """
3909 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3907 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3910
3908
3911 end = '\n'
3909 end = '\n'
3912 if opts.get('print0'):
3910 if opts.get('print0'):
3913 end = '\0'
3911 end = '\0'
3914 fm = ui.formatter('files', opts)
3912 fm = ui.formatter('files', opts)
3915 fmt = '%s' + end
3913 fmt = '%s' + end
3916
3914
3917 m = scmutil.match(ctx, pats, opts)
3915 m = scmutil.match(ctx, pats, opts)
3918 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3916 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3919
3917
3920 fm.end()
3918 fm.end()
3921
3919
3922 return ret
3920 return ret
3923
3921
3924 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3922 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3925 def forget(ui, repo, *pats, **opts):
3923 def forget(ui, repo, *pats, **opts):
3926 """forget the specified files on the next commit
3924 """forget the specified files on the next commit
3927
3925
3928 Mark the specified files so they will no longer be tracked
3926 Mark the specified files so they will no longer be tracked
3929 after the next commit.
3927 after the next commit.
3930
3928
3931 This only removes files from the current branch, not from the
3929 This only removes files from the current branch, not from the
3932 entire project history, and it does not delete them from the
3930 entire project history, and it does not delete them from the
3933 working directory.
3931 working directory.
3934
3932
3935 To delete the file from the working directory, see :hg:`remove`.
3933 To delete the file from the working directory, see :hg:`remove`.
3936
3934
3937 To undo a forget before the next commit, see :hg:`add`.
3935 To undo a forget before the next commit, see :hg:`add`.
3938
3936
3939 .. container:: verbose
3937 .. container:: verbose
3940
3938
3941 Examples:
3939 Examples:
3942
3940
3943 - forget newly-added binary files::
3941 - forget newly-added binary files::
3944
3942
3945 hg forget "set:added() and binary()"
3943 hg forget "set:added() and binary()"
3946
3944
3947 - forget files that would be excluded by .hgignore::
3945 - forget files that would be excluded by .hgignore::
3948
3946
3949 hg forget "set:hgignore()"
3947 hg forget "set:hgignore()"
3950
3948
3951 Returns 0 on success.
3949 Returns 0 on success.
3952 """
3950 """
3953
3951
3954 if not pats:
3952 if not pats:
3955 raise error.Abort(_('no files specified'))
3953 raise error.Abort(_('no files specified'))
3956
3954
3957 m = scmutil.match(repo[None], pats, opts)
3955 m = scmutil.match(repo[None], pats, opts)
3958 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3956 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3959 return rejected and 1 or 0
3957 return rejected and 1 or 0
3960
3958
3961 @command(
3959 @command(
3962 'graft',
3960 'graft',
3963 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3961 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3964 ('c', 'continue', False, _('resume interrupted graft')),
3962 ('c', 'continue', False, _('resume interrupted graft')),
3965 ('e', 'edit', False, _('invoke editor on commit messages')),
3963 ('e', 'edit', False, _('invoke editor on commit messages')),
3966 ('', 'log', None, _('append graft info to log message')),
3964 ('', 'log', None, _('append graft info to log message')),
3967 ('f', 'force', False, _('force graft')),
3965 ('f', 'force', False, _('force graft')),
3968 ('D', 'currentdate', False,
3966 ('D', 'currentdate', False,
3969 _('record the current date as commit date')),
3967 _('record the current date as commit date')),
3970 ('U', 'currentuser', False,
3968 ('U', 'currentuser', False,
3971 _('record the current user as committer'), _('DATE'))]
3969 _('record the current user as committer'), _('DATE'))]
3972 + commitopts2 + mergetoolopts + dryrunopts,
3970 + commitopts2 + mergetoolopts + dryrunopts,
3973 _('[OPTION]... [-r REV]... REV...'))
3971 _('[OPTION]... [-r REV]... REV...'))
3974 def graft(ui, repo, *revs, **opts):
3972 def graft(ui, repo, *revs, **opts):
3975 '''copy changes from other branches onto the current branch
3973 '''copy changes from other branches onto the current branch
3976
3974
3977 This command uses Mercurial's merge logic to copy individual
3975 This command uses Mercurial's merge logic to copy individual
3978 changes from other branches without merging branches in the
3976 changes from other branches without merging branches in the
3979 history graph. This is sometimes known as 'backporting' or
3977 history graph. This is sometimes known as 'backporting' or
3980 'cherry-picking'. By default, graft will copy user, date, and
3978 'cherry-picking'. By default, graft will copy user, date, and
3981 description from the source changesets.
3979 description from the source changesets.
3982
3980
3983 Changesets that are ancestors of the current revision, that have
3981 Changesets that are ancestors of the current revision, that have
3984 already been grafted, or that are merges will be skipped.
3982 already been grafted, or that are merges will be skipped.
3985
3983
3986 If --log is specified, log messages will have a comment appended
3984 If --log is specified, log messages will have a comment appended
3987 of the form::
3985 of the form::
3988
3986
3989 (grafted from CHANGESETHASH)
3987 (grafted from CHANGESETHASH)
3990
3988
3991 If --force is specified, revisions will be grafted even if they
3989 If --force is specified, revisions will be grafted even if they
3992 are already ancestors of or have been grafted to the destination.
3990 are already ancestors of or have been grafted to the destination.
3993 This is useful when the revisions have since been backed out.
3991 This is useful when the revisions have since been backed out.
3994
3992
3995 If a graft merge results in conflicts, the graft process is
3993 If a graft merge results in conflicts, the graft process is
3996 interrupted so that the current merge can be manually resolved.
3994 interrupted so that the current merge can be manually resolved.
3997 Once all conflicts are addressed, the graft process can be
3995 Once all conflicts are addressed, the graft process can be
3998 continued with the -c/--continue option.
3996 continued with the -c/--continue option.
3999
3997
4000 .. note::
3998 .. note::
4001
3999
4002 The -c/--continue option does not reapply earlier options, except
4000 The -c/--continue option does not reapply earlier options, except
4003 for --force.
4001 for --force.
4004
4002
4005 .. container:: verbose
4003 .. container:: verbose
4006
4004
4007 Examples:
4005 Examples:
4008
4006
4009 - copy a single change to the stable branch and edit its description::
4007 - copy a single change to the stable branch and edit its description::
4010
4008
4011 hg update stable
4009 hg update stable
4012 hg graft --edit 9393
4010 hg graft --edit 9393
4013
4011
4014 - graft a range of changesets with one exception, updating dates::
4012 - graft a range of changesets with one exception, updating dates::
4015
4013
4016 hg graft -D "2085::2093 and not 2091"
4014 hg graft -D "2085::2093 and not 2091"
4017
4015
4018 - continue a graft after resolving conflicts::
4016 - continue a graft after resolving conflicts::
4019
4017
4020 hg graft -c
4018 hg graft -c
4021
4019
4022 - show the source of a grafted changeset::
4020 - show the source of a grafted changeset::
4023
4021
4024 hg log --debug -r .
4022 hg log --debug -r .
4025
4023
4026 - show revisions sorted by date::
4024 - show revisions sorted by date::
4027
4025
4028 hg log -r 'sort(all(), date)'
4026 hg log -r 'sort(all(), date)'
4029
4027
4030 See :hg:`help revisions` and :hg:`help revsets` for more about
4028 See :hg:`help revisions` and :hg:`help revsets` for more about
4031 specifying revisions.
4029 specifying revisions.
4032
4030
4033 Returns 0 on successful completion.
4031 Returns 0 on successful completion.
4034 '''
4032 '''
4035 with repo.wlock():
4033 with repo.wlock():
4036 return _dograft(ui, repo, *revs, **opts)
4034 return _dograft(ui, repo, *revs, **opts)
4037
4035
4038 def _dograft(ui, repo, *revs, **opts):
4036 def _dograft(ui, repo, *revs, **opts):
4039 if revs and opts['rev']:
4037 if revs and opts['rev']:
4040 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4038 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4041 'revision ordering!\n'))
4039 'revision ordering!\n'))
4042
4040
4043 revs = list(revs)
4041 revs = list(revs)
4044 revs.extend(opts['rev'])
4042 revs.extend(opts['rev'])
4045
4043
4046 if not opts.get('user') and opts.get('currentuser'):
4044 if not opts.get('user') and opts.get('currentuser'):
4047 opts['user'] = ui.username()
4045 opts['user'] = ui.username()
4048 if not opts.get('date') and opts.get('currentdate'):
4046 if not opts.get('date') and opts.get('currentdate'):
4049 opts['date'] = "%d %d" % util.makedate()
4047 opts['date'] = "%d %d" % util.makedate()
4050
4048
4051 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4049 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4052
4050
4053 cont = False
4051 cont = False
4054 if opts['continue']:
4052 if opts['continue']:
4055 cont = True
4053 cont = True
4056 if revs:
4054 if revs:
4057 raise error.Abort(_("can't specify --continue and revisions"))
4055 raise error.Abort(_("can't specify --continue and revisions"))
4058 # read in unfinished revisions
4056 # read in unfinished revisions
4059 try:
4057 try:
4060 nodes = repo.vfs.read('graftstate').splitlines()
4058 nodes = repo.vfs.read('graftstate').splitlines()
4061 revs = [repo[node].rev() for node in nodes]
4059 revs = [repo[node].rev() for node in nodes]
4062 except IOError as inst:
4060 except IOError as inst:
4063 if inst.errno != errno.ENOENT:
4061 if inst.errno != errno.ENOENT:
4064 raise
4062 raise
4065 cmdutil.wrongtooltocontinue(repo, _('graft'))
4063 cmdutil.wrongtooltocontinue(repo, _('graft'))
4066 else:
4064 else:
4067 cmdutil.checkunfinished(repo)
4065 cmdutil.checkunfinished(repo)
4068 cmdutil.bailifchanged(repo)
4066 cmdutil.bailifchanged(repo)
4069 if not revs:
4067 if not revs:
4070 raise error.Abort(_('no revisions specified'))
4068 raise error.Abort(_('no revisions specified'))
4071 revs = scmutil.revrange(repo, revs)
4069 revs = scmutil.revrange(repo, revs)
4072
4070
4073 skipped = set()
4071 skipped = set()
4074 # check for merges
4072 # check for merges
4075 for rev in repo.revs('%ld and merge()', revs):
4073 for rev in repo.revs('%ld and merge()', revs):
4076 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4074 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4077 skipped.add(rev)
4075 skipped.add(rev)
4078 revs = [r for r in revs if r not in skipped]
4076 revs = [r for r in revs if r not in skipped]
4079 if not revs:
4077 if not revs:
4080 return -1
4078 return -1
4081
4079
4082 # Don't check in the --continue case, in effect retaining --force across
4080 # Don't check in the --continue case, in effect retaining --force across
4083 # --continues. That's because without --force, any revisions we decided to
4081 # --continues. That's because without --force, any revisions we decided to
4084 # skip would have been filtered out here, so they wouldn't have made their
4082 # skip would have been filtered out here, so they wouldn't have made their
4085 # way to the graftstate. With --force, any revisions we would have otherwise
4083 # way to the graftstate. With --force, any revisions we would have otherwise
4086 # skipped would not have been filtered out, and if they hadn't been applied
4084 # skipped would not have been filtered out, and if they hadn't been applied
4087 # already, they'd have been in the graftstate.
4085 # already, they'd have been in the graftstate.
4088 if not (cont or opts.get('force')):
4086 if not (cont or opts.get('force')):
4089 # check for ancestors of dest branch
4087 # check for ancestors of dest branch
4090 crev = repo['.'].rev()
4088 crev = repo['.'].rev()
4091 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4089 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4092 # Cannot use x.remove(y) on smart set, this has to be a list.
4090 # Cannot use x.remove(y) on smart set, this has to be a list.
4093 # XXX make this lazy in the future
4091 # XXX make this lazy in the future
4094 revs = list(revs)
4092 revs = list(revs)
4095 # don't mutate while iterating, create a copy
4093 # don't mutate while iterating, create a copy
4096 for rev in list(revs):
4094 for rev in list(revs):
4097 if rev in ancestors:
4095 if rev in ancestors:
4098 ui.warn(_('skipping ancestor revision %d:%s\n') %
4096 ui.warn(_('skipping ancestor revision %d:%s\n') %
4099 (rev, repo[rev]))
4097 (rev, repo[rev]))
4100 # XXX remove on list is slow
4098 # XXX remove on list is slow
4101 revs.remove(rev)
4099 revs.remove(rev)
4102 if not revs:
4100 if not revs:
4103 return -1
4101 return -1
4104
4102
4105 # analyze revs for earlier grafts
4103 # analyze revs for earlier grafts
4106 ids = {}
4104 ids = {}
4107 for ctx in repo.set("%ld", revs):
4105 for ctx in repo.set("%ld", revs):
4108 ids[ctx.hex()] = ctx.rev()
4106 ids[ctx.hex()] = ctx.rev()
4109 n = ctx.extra().get('source')
4107 n = ctx.extra().get('source')
4110 if n:
4108 if n:
4111 ids[n] = ctx.rev()
4109 ids[n] = ctx.rev()
4112
4110
4113 # check ancestors for earlier grafts
4111 # check ancestors for earlier grafts
4114 ui.debug('scanning for duplicate grafts\n')
4112 ui.debug('scanning for duplicate grafts\n')
4115
4113
4116 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4114 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4117 ctx = repo[rev]
4115 ctx = repo[rev]
4118 n = ctx.extra().get('source')
4116 n = ctx.extra().get('source')
4119 if n in ids:
4117 if n in ids:
4120 try:
4118 try:
4121 r = repo[n].rev()
4119 r = repo[n].rev()
4122 except error.RepoLookupError:
4120 except error.RepoLookupError:
4123 r = None
4121 r = None
4124 if r in revs:
4122 if r in revs:
4125 ui.warn(_('skipping revision %d:%s '
4123 ui.warn(_('skipping revision %d:%s '
4126 '(already grafted to %d:%s)\n')
4124 '(already grafted to %d:%s)\n')
4127 % (r, repo[r], rev, ctx))
4125 % (r, repo[r], rev, ctx))
4128 revs.remove(r)
4126 revs.remove(r)
4129 elif ids[n] in revs:
4127 elif ids[n] in revs:
4130 if r is None:
4128 if r is None:
4131 ui.warn(_('skipping already grafted revision %d:%s '
4129 ui.warn(_('skipping already grafted revision %d:%s '
4132 '(%d:%s also has unknown origin %s)\n')
4130 '(%d:%s also has unknown origin %s)\n')
4133 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4131 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4134 else:
4132 else:
4135 ui.warn(_('skipping already grafted revision %d:%s '
4133 ui.warn(_('skipping already grafted revision %d:%s '
4136 '(%d:%s also has origin %d:%s)\n')
4134 '(%d:%s also has origin %d:%s)\n')
4137 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4135 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4138 revs.remove(ids[n])
4136 revs.remove(ids[n])
4139 elif ctx.hex() in ids:
4137 elif ctx.hex() in ids:
4140 r = ids[ctx.hex()]
4138 r = ids[ctx.hex()]
4141 ui.warn(_('skipping already grafted revision %d:%s '
4139 ui.warn(_('skipping already grafted revision %d:%s '
4142 '(was grafted from %d:%s)\n') %
4140 '(was grafted from %d:%s)\n') %
4143 (r, repo[r], rev, ctx))
4141 (r, repo[r], rev, ctx))
4144 revs.remove(r)
4142 revs.remove(r)
4145 if not revs:
4143 if not revs:
4146 return -1
4144 return -1
4147
4145
4148 for pos, ctx in enumerate(repo.set("%ld", revs)):
4146 for pos, ctx in enumerate(repo.set("%ld", revs)):
4149 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4147 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4150 ctx.description().split('\n', 1)[0])
4148 ctx.description().split('\n', 1)[0])
4151 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4149 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4152 if names:
4150 if names:
4153 desc += ' (%s)' % ' '.join(names)
4151 desc += ' (%s)' % ' '.join(names)
4154 ui.status(_('grafting %s\n') % desc)
4152 ui.status(_('grafting %s\n') % desc)
4155 if opts.get('dry_run'):
4153 if opts.get('dry_run'):
4156 continue
4154 continue
4157
4155
4158 source = ctx.extra().get('source')
4156 source = ctx.extra().get('source')
4159 extra = {}
4157 extra = {}
4160 if source:
4158 if source:
4161 extra['source'] = source
4159 extra['source'] = source
4162 extra['intermediate-source'] = ctx.hex()
4160 extra['intermediate-source'] = ctx.hex()
4163 else:
4161 else:
4164 extra['source'] = ctx.hex()
4162 extra['source'] = ctx.hex()
4165 user = ctx.user()
4163 user = ctx.user()
4166 if opts.get('user'):
4164 if opts.get('user'):
4167 user = opts['user']
4165 user = opts['user']
4168 date = ctx.date()
4166 date = ctx.date()
4169 if opts.get('date'):
4167 if opts.get('date'):
4170 date = opts['date']
4168 date = opts['date']
4171 message = ctx.description()
4169 message = ctx.description()
4172 if opts.get('log'):
4170 if opts.get('log'):
4173 message += '\n(grafted from %s)' % ctx.hex()
4171 message += '\n(grafted from %s)' % ctx.hex()
4174
4172
4175 # we don't merge the first commit when continuing
4173 # we don't merge the first commit when continuing
4176 if not cont:
4174 if not cont:
4177 # perform the graft merge with p1(rev) as 'ancestor'
4175 # perform the graft merge with p1(rev) as 'ancestor'
4178 try:
4176 try:
4179 # ui.forcemerge is an internal variable, do not document
4177 # ui.forcemerge is an internal variable, do not document
4180 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4178 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4181 'graft')
4179 'graft')
4182 stats = mergemod.graft(repo, ctx, ctx.p1(),
4180 stats = mergemod.graft(repo, ctx, ctx.p1(),
4183 ['local', 'graft'])
4181 ['local', 'graft'])
4184 finally:
4182 finally:
4185 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4183 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4186 # report any conflicts
4184 # report any conflicts
4187 if stats and stats[3] > 0:
4185 if stats and stats[3] > 0:
4188 # write out state for --continue
4186 # write out state for --continue
4189 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4187 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4190 repo.vfs.write('graftstate', ''.join(nodelines))
4188 repo.vfs.write('graftstate', ''.join(nodelines))
4191 extra = ''
4189 extra = ''
4192 if opts.get('user'):
4190 if opts.get('user'):
4193 extra += ' --user %s' % opts['user']
4191 extra += ' --user %s' % opts['user']
4194 if opts.get('date'):
4192 if opts.get('date'):
4195 extra += ' --date %s' % opts['date']
4193 extra += ' --date %s' % opts['date']
4196 if opts.get('log'):
4194 if opts.get('log'):
4197 extra += ' --log'
4195 extra += ' --log'
4198 hint=_('use hg resolve and hg graft --continue%s') % extra
4196 hint=_('use hg resolve and hg graft --continue%s') % extra
4199 raise error.Abort(
4197 raise error.Abort(
4200 _("unresolved conflicts, can't continue"),
4198 _("unresolved conflicts, can't continue"),
4201 hint=hint)
4199 hint=hint)
4202 else:
4200 else:
4203 cont = False
4201 cont = False
4204
4202
4205 # commit
4203 # commit
4206 node = repo.commit(text=message, user=user,
4204 node = repo.commit(text=message, user=user,
4207 date=date, extra=extra, editor=editor)
4205 date=date, extra=extra, editor=editor)
4208 if node is None:
4206 if node is None:
4209 ui.warn(
4207 ui.warn(
4210 _('note: graft of %d:%s created no changes to commit\n') %
4208 _('note: graft of %d:%s created no changes to commit\n') %
4211 (ctx.rev(), ctx))
4209 (ctx.rev(), ctx))
4212
4210
4213 # remove state when we complete successfully
4211 # remove state when we complete successfully
4214 if not opts.get('dry_run'):
4212 if not opts.get('dry_run'):
4215 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4213 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4216
4214
4217 return 0
4215 return 0
4218
4216
4219 @command('grep',
4217 @command('grep',
4220 [('0', 'print0', None, _('end fields with NUL')),
4218 [('0', 'print0', None, _('end fields with NUL')),
4221 ('', 'all', None, _('print all revisions that match')),
4219 ('', 'all', None, _('print all revisions that match')),
4222 ('a', 'text', None, _('treat all files as text')),
4220 ('a', 'text', None, _('treat all files as text')),
4223 ('f', 'follow', None,
4221 ('f', 'follow', None,
4224 _('follow changeset history,'
4222 _('follow changeset history,'
4225 ' or file history across copies and renames')),
4223 ' or file history across copies and renames')),
4226 ('i', 'ignore-case', None, _('ignore case when matching')),
4224 ('i', 'ignore-case', None, _('ignore case when matching')),
4227 ('l', 'files-with-matches', None,
4225 ('l', 'files-with-matches', None,
4228 _('print only filenames and revisions that match')),
4226 _('print only filenames and revisions that match')),
4229 ('n', 'line-number', None, _('print matching line numbers')),
4227 ('n', 'line-number', None, _('print matching line numbers')),
4230 ('r', 'rev', [],
4228 ('r', 'rev', [],
4231 _('only search files changed within revision range'), _('REV')),
4229 _('only search files changed within revision range'), _('REV')),
4232 ('u', 'user', None, _('list the author (long with -v)')),
4230 ('u', 'user', None, _('list the author (long with -v)')),
4233 ('d', 'date', None, _('list the date (short with -q)')),
4231 ('d', 'date', None, _('list the date (short with -q)')),
4234 ] + walkopts,
4232 ] + walkopts,
4235 _('[OPTION]... PATTERN [FILE]...'),
4233 _('[OPTION]... PATTERN [FILE]...'),
4236 inferrepo=True)
4234 inferrepo=True)
4237 def grep(ui, repo, pattern, *pats, **opts):
4235 def grep(ui, repo, pattern, *pats, **opts):
4238 """search for a pattern in specified files and revisions
4236 """search for a pattern in specified files and revisions
4239
4237
4240 Search revisions of files for a regular expression.
4238 Search revisions of files for a regular expression.
4241
4239
4242 This command behaves differently than Unix grep. It only accepts
4240 This command behaves differently than Unix grep. It only accepts
4243 Python/Perl regexps. It searches repository history, not the
4241 Python/Perl regexps. It searches repository history, not the
4244 working directory. It always prints the revision number in which a
4242 working directory. It always prints the revision number in which a
4245 match appears.
4243 match appears.
4246
4244
4247 By default, grep only prints output for the first revision of a
4245 By default, grep only prints output for the first revision of a
4248 file in which it finds a match. To get it to print every revision
4246 file in which it finds a match. To get it to print every revision
4249 that contains a change in match status ("-" for a match that
4247 that contains a change in match status ("-" for a match that
4250 becomes a non-match, or "+" for a non-match that becomes a match),
4248 becomes a non-match, or "+" for a non-match that becomes a match),
4251 use the --all flag.
4249 use the --all flag.
4252
4250
4253 Returns 0 if a match is found, 1 otherwise.
4251 Returns 0 if a match is found, 1 otherwise.
4254 """
4252 """
4255 reflags = re.M
4253 reflags = re.M
4256 if opts.get('ignore_case'):
4254 if opts.get('ignore_case'):
4257 reflags |= re.I
4255 reflags |= re.I
4258 try:
4256 try:
4259 regexp = util.re.compile(pattern, reflags)
4257 regexp = util.re.compile(pattern, reflags)
4260 except re.error as inst:
4258 except re.error as inst:
4261 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4259 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4262 return 1
4260 return 1
4263 sep, eol = ':', '\n'
4261 sep, eol = ':', '\n'
4264 if opts.get('print0'):
4262 if opts.get('print0'):
4265 sep = eol = '\0'
4263 sep = eol = '\0'
4266
4264
4267 getfile = util.lrucachefunc(repo.file)
4265 getfile = util.lrucachefunc(repo.file)
4268
4266
4269 def matchlines(body):
4267 def matchlines(body):
4270 begin = 0
4268 begin = 0
4271 linenum = 0
4269 linenum = 0
4272 while begin < len(body):
4270 while begin < len(body):
4273 match = regexp.search(body, begin)
4271 match = regexp.search(body, begin)
4274 if not match:
4272 if not match:
4275 break
4273 break
4276 mstart, mend = match.span()
4274 mstart, mend = match.span()
4277 linenum += body.count('\n', begin, mstart) + 1
4275 linenum += body.count('\n', begin, mstart) + 1
4278 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4276 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4279 begin = body.find('\n', mend) + 1 or len(body) + 1
4277 begin = body.find('\n', mend) + 1 or len(body) + 1
4280 lend = begin - 1
4278 lend = begin - 1
4281 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4279 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4282
4280
4283 class linestate(object):
4281 class linestate(object):
4284 def __init__(self, line, linenum, colstart, colend):
4282 def __init__(self, line, linenum, colstart, colend):
4285 self.line = line
4283 self.line = line
4286 self.linenum = linenum
4284 self.linenum = linenum
4287 self.colstart = colstart
4285 self.colstart = colstart
4288 self.colend = colend
4286 self.colend = colend
4289
4287
4290 def __hash__(self):
4288 def __hash__(self):
4291 return hash((self.linenum, self.line))
4289 return hash((self.linenum, self.line))
4292
4290
4293 def __eq__(self, other):
4291 def __eq__(self, other):
4294 return self.line == other.line
4292 return self.line == other.line
4295
4293
4296 def __iter__(self):
4294 def __iter__(self):
4297 yield (self.line[:self.colstart], '')
4295 yield (self.line[:self.colstart], '')
4298 yield (self.line[self.colstart:self.colend], 'grep.match')
4296 yield (self.line[self.colstart:self.colend], 'grep.match')
4299 rest = self.line[self.colend:]
4297 rest = self.line[self.colend:]
4300 while rest != '':
4298 while rest != '':
4301 match = regexp.search(rest)
4299 match = regexp.search(rest)
4302 if not match:
4300 if not match:
4303 yield (rest, '')
4301 yield (rest, '')
4304 break
4302 break
4305 mstart, mend = match.span()
4303 mstart, mend = match.span()
4306 yield (rest[:mstart], '')
4304 yield (rest[:mstart], '')
4307 yield (rest[mstart:mend], 'grep.match')
4305 yield (rest[mstart:mend], 'grep.match')
4308 rest = rest[mend:]
4306 rest = rest[mend:]
4309
4307
4310 matches = {}
4308 matches = {}
4311 copies = {}
4309 copies = {}
4312 def grepbody(fn, rev, body):
4310 def grepbody(fn, rev, body):
4313 matches[rev].setdefault(fn, [])
4311 matches[rev].setdefault(fn, [])
4314 m = matches[rev][fn]
4312 m = matches[rev][fn]
4315 for lnum, cstart, cend, line in matchlines(body):
4313 for lnum, cstart, cend, line in matchlines(body):
4316 s = linestate(line, lnum, cstart, cend)
4314 s = linestate(line, lnum, cstart, cend)
4317 m.append(s)
4315 m.append(s)
4318
4316
4319 def difflinestates(a, b):
4317 def difflinestates(a, b):
4320 sm = difflib.SequenceMatcher(None, a, b)
4318 sm = difflib.SequenceMatcher(None, a, b)
4321 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4319 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4322 if tag == 'insert':
4320 if tag == 'insert':
4323 for i in xrange(blo, bhi):
4321 for i in xrange(blo, bhi):
4324 yield ('+', b[i])
4322 yield ('+', b[i])
4325 elif tag == 'delete':
4323 elif tag == 'delete':
4326 for i in xrange(alo, ahi):
4324 for i in xrange(alo, ahi):
4327 yield ('-', a[i])
4325 yield ('-', a[i])
4328 elif tag == 'replace':
4326 elif tag == 'replace':
4329 for i in xrange(alo, ahi):
4327 for i in xrange(alo, ahi):
4330 yield ('-', a[i])
4328 yield ('-', a[i])
4331 for i in xrange(blo, bhi):
4329 for i in xrange(blo, bhi):
4332 yield ('+', b[i])
4330 yield ('+', b[i])
4333
4331
4334 def display(fn, ctx, pstates, states):
4332 def display(fn, ctx, pstates, states):
4335 rev = ctx.rev()
4333 rev = ctx.rev()
4336 if ui.quiet:
4334 if ui.quiet:
4337 datefunc = util.shortdate
4335 datefunc = util.shortdate
4338 else:
4336 else:
4339 datefunc = util.datestr
4337 datefunc = util.datestr
4340 found = False
4338 found = False
4341 @util.cachefunc
4339 @util.cachefunc
4342 def binary():
4340 def binary():
4343 flog = getfile(fn)
4341 flog = getfile(fn)
4344 return util.binary(flog.read(ctx.filenode(fn)))
4342 return util.binary(flog.read(ctx.filenode(fn)))
4345
4343
4346 if opts.get('all'):
4344 if opts.get('all'):
4347 iter = difflinestates(pstates, states)
4345 iter = difflinestates(pstates, states)
4348 else:
4346 else:
4349 iter = [('', l) for l in states]
4347 iter = [('', l) for l in states]
4350 for change, l in iter:
4348 for change, l in iter:
4351 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4349 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4352
4350
4353 if opts.get('line_number'):
4351 if opts.get('line_number'):
4354 cols.append((str(l.linenum), 'grep.linenumber'))
4352 cols.append((str(l.linenum), 'grep.linenumber'))
4355 if opts.get('all'):
4353 if opts.get('all'):
4356 cols.append((change, 'grep.change'))
4354 cols.append((change, 'grep.change'))
4357 if opts.get('user'):
4355 if opts.get('user'):
4358 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4356 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4359 if opts.get('date'):
4357 if opts.get('date'):
4360 cols.append((datefunc(ctx.date()), 'grep.date'))
4358 cols.append((datefunc(ctx.date()), 'grep.date'))
4361 for col, label in cols[:-1]:
4359 for col, label in cols[:-1]:
4362 ui.write(col, label=label)
4360 ui.write(col, label=label)
4363 ui.write(sep, label='grep.sep')
4361 ui.write(sep, label='grep.sep')
4364 ui.write(cols[-1][0], label=cols[-1][1])
4362 ui.write(cols[-1][0], label=cols[-1][1])
4365 if not opts.get('files_with_matches'):
4363 if not opts.get('files_with_matches'):
4366 ui.write(sep, label='grep.sep')
4364 ui.write(sep, label='grep.sep')
4367 if not opts.get('text') and binary():
4365 if not opts.get('text') and binary():
4368 ui.write(" Binary file matches")
4366 ui.write(" Binary file matches")
4369 else:
4367 else:
4370 for s, label in l:
4368 for s, label in l:
4371 ui.write(s, label=label)
4369 ui.write(s, label=label)
4372 ui.write(eol)
4370 ui.write(eol)
4373 found = True
4371 found = True
4374 if opts.get('files_with_matches'):
4372 if opts.get('files_with_matches'):
4375 break
4373 break
4376 return found
4374 return found
4377
4375
4378 skip = {}
4376 skip = {}
4379 revfiles = {}
4377 revfiles = {}
4380 matchfn = scmutil.match(repo[None], pats, opts)
4378 matchfn = scmutil.match(repo[None], pats, opts)
4381 found = False
4379 found = False
4382 follow = opts.get('follow')
4380 follow = opts.get('follow')
4383
4381
4384 def prep(ctx, fns):
4382 def prep(ctx, fns):
4385 rev = ctx.rev()
4383 rev = ctx.rev()
4386 pctx = ctx.p1()
4384 pctx = ctx.p1()
4387 parent = pctx.rev()
4385 parent = pctx.rev()
4388 matches.setdefault(rev, {})
4386 matches.setdefault(rev, {})
4389 matches.setdefault(parent, {})
4387 matches.setdefault(parent, {})
4390 files = revfiles.setdefault(rev, [])
4388 files = revfiles.setdefault(rev, [])
4391 for fn in fns:
4389 for fn in fns:
4392 flog = getfile(fn)
4390 flog = getfile(fn)
4393 try:
4391 try:
4394 fnode = ctx.filenode(fn)
4392 fnode = ctx.filenode(fn)
4395 except error.LookupError:
4393 except error.LookupError:
4396 continue
4394 continue
4397
4395
4398 copied = flog.renamed(fnode)
4396 copied = flog.renamed(fnode)
4399 copy = follow and copied and copied[0]
4397 copy = follow and copied and copied[0]
4400 if copy:
4398 if copy:
4401 copies.setdefault(rev, {})[fn] = copy
4399 copies.setdefault(rev, {})[fn] = copy
4402 if fn in skip:
4400 if fn in skip:
4403 if copy:
4401 if copy:
4404 skip[copy] = True
4402 skip[copy] = True
4405 continue
4403 continue
4406 files.append(fn)
4404 files.append(fn)
4407
4405
4408 if fn not in matches[rev]:
4406 if fn not in matches[rev]:
4409 grepbody(fn, rev, flog.read(fnode))
4407 grepbody(fn, rev, flog.read(fnode))
4410
4408
4411 pfn = copy or fn
4409 pfn = copy or fn
4412 if pfn not in matches[parent]:
4410 if pfn not in matches[parent]:
4413 try:
4411 try:
4414 fnode = pctx.filenode(pfn)
4412 fnode = pctx.filenode(pfn)
4415 grepbody(pfn, parent, flog.read(fnode))
4413 grepbody(pfn, parent, flog.read(fnode))
4416 except error.LookupError:
4414 except error.LookupError:
4417 pass
4415 pass
4418
4416
4419 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4417 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4420 rev = ctx.rev()
4418 rev = ctx.rev()
4421 parent = ctx.p1().rev()
4419 parent = ctx.p1().rev()
4422 for fn in sorted(revfiles.get(rev, [])):
4420 for fn in sorted(revfiles.get(rev, [])):
4423 states = matches[rev][fn]
4421 states = matches[rev][fn]
4424 copy = copies.get(rev, {}).get(fn)
4422 copy = copies.get(rev, {}).get(fn)
4425 if fn in skip:
4423 if fn in skip:
4426 if copy:
4424 if copy:
4427 skip[copy] = True
4425 skip[copy] = True
4428 continue
4426 continue
4429 pstates = matches.get(parent, {}).get(copy or fn, [])
4427 pstates = matches.get(parent, {}).get(copy or fn, [])
4430 if pstates or states:
4428 if pstates or states:
4431 r = display(fn, ctx, pstates, states)
4429 r = display(fn, ctx, pstates, states)
4432 found = found or r
4430 found = found or r
4433 if r and not opts.get('all'):
4431 if r and not opts.get('all'):
4434 skip[fn] = True
4432 skip[fn] = True
4435 if copy:
4433 if copy:
4436 skip[copy] = True
4434 skip[copy] = True
4437 del matches[rev]
4435 del matches[rev]
4438 del revfiles[rev]
4436 del revfiles[rev]
4439
4437
4440 return not found
4438 return not found
4441
4439
4442 @command('heads',
4440 @command('heads',
4443 [('r', 'rev', '',
4441 [('r', 'rev', '',
4444 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4442 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4445 ('t', 'topo', False, _('show topological heads only')),
4443 ('t', 'topo', False, _('show topological heads only')),
4446 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4444 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4447 ('c', 'closed', False, _('show normal and closed branch heads')),
4445 ('c', 'closed', False, _('show normal and closed branch heads')),
4448 ] + templateopts,
4446 ] + templateopts,
4449 _('[-ct] [-r STARTREV] [REV]...'))
4447 _('[-ct] [-r STARTREV] [REV]...'))
4450 def heads(ui, repo, *branchrevs, **opts):
4448 def heads(ui, repo, *branchrevs, **opts):
4451 """show branch heads
4449 """show branch heads
4452
4450
4453 With no arguments, show all open branch heads in the repository.
4451 With no arguments, show all open branch heads in the repository.
4454 Branch heads are changesets that have no descendants on the
4452 Branch heads are changesets that have no descendants on the
4455 same branch. They are where development generally takes place and
4453 same branch. They are where development generally takes place and
4456 are the usual targets for update and merge operations.
4454 are the usual targets for update and merge operations.
4457
4455
4458 If one or more REVs are given, only open branch heads on the
4456 If one or more REVs are given, only open branch heads on the
4459 branches associated with the specified changesets are shown. This
4457 branches associated with the specified changesets are shown. This
4460 means that you can use :hg:`heads .` to see the heads on the
4458 means that you can use :hg:`heads .` to see the heads on the
4461 currently checked-out branch.
4459 currently checked-out branch.
4462
4460
4463 If -c/--closed is specified, also show branch heads marked closed
4461 If -c/--closed is specified, also show branch heads marked closed
4464 (see :hg:`commit --close-branch`).
4462 (see :hg:`commit --close-branch`).
4465
4463
4466 If STARTREV is specified, only those heads that are descendants of
4464 If STARTREV is specified, only those heads that are descendants of
4467 STARTREV will be displayed.
4465 STARTREV will be displayed.
4468
4466
4469 If -t/--topo is specified, named branch mechanics will be ignored and only
4467 If -t/--topo is specified, named branch mechanics will be ignored and only
4470 topological heads (changesets with no children) will be shown.
4468 topological heads (changesets with no children) will be shown.
4471
4469
4472 Returns 0 if matching heads are found, 1 if not.
4470 Returns 0 if matching heads are found, 1 if not.
4473 """
4471 """
4474
4472
4475 start = None
4473 start = None
4476 if 'rev' in opts:
4474 if 'rev' in opts:
4477 start = scmutil.revsingle(repo, opts['rev'], None).node()
4475 start = scmutil.revsingle(repo, opts['rev'], None).node()
4478
4476
4479 if opts.get('topo'):
4477 if opts.get('topo'):
4480 heads = [repo[h] for h in repo.heads(start)]
4478 heads = [repo[h] for h in repo.heads(start)]
4481 else:
4479 else:
4482 heads = []
4480 heads = []
4483 for branch in repo.branchmap():
4481 for branch in repo.branchmap():
4484 heads += repo.branchheads(branch, start, opts.get('closed'))
4482 heads += repo.branchheads(branch, start, opts.get('closed'))
4485 heads = [repo[h] for h in heads]
4483 heads = [repo[h] for h in heads]
4486
4484
4487 if branchrevs:
4485 if branchrevs:
4488 branches = set(repo[br].branch() for br in branchrevs)
4486 branches = set(repo[br].branch() for br in branchrevs)
4489 heads = [h for h in heads if h.branch() in branches]
4487 heads = [h for h in heads if h.branch() in branches]
4490
4488
4491 if opts.get('active') and branchrevs:
4489 if opts.get('active') and branchrevs:
4492 dagheads = repo.heads(start)
4490 dagheads = repo.heads(start)
4493 heads = [h for h in heads if h.node() in dagheads]
4491 heads = [h for h in heads if h.node() in dagheads]
4494
4492
4495 if branchrevs:
4493 if branchrevs:
4496 haveheads = set(h.branch() for h in heads)
4494 haveheads = set(h.branch() for h in heads)
4497 if branches - haveheads:
4495 if branches - haveheads:
4498 headless = ', '.join(b for b in branches - haveheads)
4496 headless = ', '.join(b for b in branches - haveheads)
4499 msg = _('no open branch heads found on branches %s')
4497 msg = _('no open branch heads found on branches %s')
4500 if opts.get('rev'):
4498 if opts.get('rev'):
4501 msg += _(' (started at %s)') % opts['rev']
4499 msg += _(' (started at %s)') % opts['rev']
4502 ui.warn((msg + '\n') % headless)
4500 ui.warn((msg + '\n') % headless)
4503
4501
4504 if not heads:
4502 if not heads:
4505 return 1
4503 return 1
4506
4504
4507 heads = sorted(heads, key=lambda x: -x.rev())
4505 heads = sorted(heads, key=lambda x: -x.rev())
4508 displayer = cmdutil.show_changeset(ui, repo, opts)
4506 displayer = cmdutil.show_changeset(ui, repo, opts)
4509 for ctx in heads:
4507 for ctx in heads:
4510 displayer.show(ctx)
4508 displayer.show(ctx)
4511 displayer.close()
4509 displayer.close()
4512
4510
4513 @command('help',
4511 @command('help',
4514 [('e', 'extension', None, _('show only help for extensions')),
4512 [('e', 'extension', None, _('show only help for extensions')),
4515 ('c', 'command', None, _('show only help for commands')),
4513 ('c', 'command', None, _('show only help for commands')),
4516 ('k', 'keyword', None, _('show topics matching keyword')),
4514 ('k', 'keyword', None, _('show topics matching keyword')),
4517 ('s', 'system', [], _('show help for specific platform(s)')),
4515 ('s', 'system', [], _('show help for specific platform(s)')),
4518 ],
4516 ],
4519 _('[-ecks] [TOPIC]'),
4517 _('[-ecks] [TOPIC]'),
4520 norepo=True)
4518 norepo=True)
4521 def help_(ui, name=None, **opts):
4519 def help_(ui, name=None, **opts):
4522 """show help for a given topic or a help overview
4520 """show help for a given topic or a help overview
4523
4521
4524 With no arguments, print a list of commands with short help messages.
4522 With no arguments, print a list of commands with short help messages.
4525
4523
4526 Given a topic, extension, or command name, print help for that
4524 Given a topic, extension, or command name, print help for that
4527 topic.
4525 topic.
4528
4526
4529 Returns 0 if successful.
4527 Returns 0 if successful.
4530 """
4528 """
4531
4529
4532 textwidth = min(ui.termwidth(), 80) - 2
4530 textwidth = min(ui.termwidth(), 80) - 2
4533
4531
4534 keep = opts.get('system') or []
4532 keep = opts.get('system') or []
4535 if len(keep) == 0:
4533 if len(keep) == 0:
4536 if sys.platform.startswith('win'):
4534 if sys.platform.startswith('win'):
4537 keep.append('windows')
4535 keep.append('windows')
4538 elif sys.platform == 'OpenVMS':
4536 elif sys.platform == 'OpenVMS':
4539 keep.append('vms')
4537 keep.append('vms')
4540 elif sys.platform == 'plan9':
4538 elif sys.platform == 'plan9':
4541 keep.append('plan9')
4539 keep.append('plan9')
4542 else:
4540 else:
4543 keep.append('unix')
4541 keep.append('unix')
4544 keep.append(sys.platform.lower())
4542 keep.append(sys.platform.lower())
4545 if ui.verbose:
4543 if ui.verbose:
4546 keep.append('verbose')
4544 keep.append('verbose')
4547
4545
4548 section = None
4546 section = None
4549 subtopic = None
4547 subtopic = None
4550 if name and '.' in name:
4548 if name and '.' in name:
4551 name, section = name.split('.', 1)
4549 name, section = name.split('.', 1)
4552 section = section.lower()
4550 section = section.lower()
4553 if '.' in section:
4551 if '.' in section:
4554 subtopic, section = section.split('.', 1)
4552 subtopic, section = section.split('.', 1)
4555 else:
4553 else:
4556 subtopic = section
4554 subtopic = section
4557
4555
4558 text = help.help_(ui, name, subtopic=subtopic, **opts)
4556 text = help.help_(ui, name, subtopic=subtopic, **opts)
4559
4557
4560 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4558 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4561 section=section)
4559 section=section)
4562
4560
4563 # We could have been given a weird ".foo" section without a name
4561 # We could have been given a weird ".foo" section without a name
4564 # to look for, or we could have simply failed to found "foo.bar"
4562 # to look for, or we could have simply failed to found "foo.bar"
4565 # because bar isn't a section of foo
4563 # because bar isn't a section of foo
4566 if section and not (formatted and name):
4564 if section and not (formatted and name):
4567 raise error.Abort(_("help section not found"))
4565 raise error.Abort(_("help section not found"))
4568
4566
4569 if 'verbose' in pruned:
4567 if 'verbose' in pruned:
4570 keep.append('omitted')
4568 keep.append('omitted')
4571 else:
4569 else:
4572 keep.append('notomitted')
4570 keep.append('notomitted')
4573 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4571 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4574 section=section)
4572 section=section)
4575 ui.write(formatted)
4573 ui.write(formatted)
4576
4574
4577
4575
4578 @command('identify|id',
4576 @command('identify|id',
4579 [('r', 'rev', '',
4577 [('r', 'rev', '',
4580 _('identify the specified revision'), _('REV')),
4578 _('identify the specified revision'), _('REV')),
4581 ('n', 'num', None, _('show local revision number')),
4579 ('n', 'num', None, _('show local revision number')),
4582 ('i', 'id', None, _('show global revision id')),
4580 ('i', 'id', None, _('show global revision id')),
4583 ('b', 'branch', None, _('show branch')),
4581 ('b', 'branch', None, _('show branch')),
4584 ('t', 'tags', None, _('show tags')),
4582 ('t', 'tags', None, _('show tags')),
4585 ('B', 'bookmarks', None, _('show bookmarks')),
4583 ('B', 'bookmarks', None, _('show bookmarks')),
4586 ] + remoteopts,
4584 ] + remoteopts,
4587 _('[-nibtB] [-r REV] [SOURCE]'),
4585 _('[-nibtB] [-r REV] [SOURCE]'),
4588 optionalrepo=True)
4586 optionalrepo=True)
4589 def identify(ui, repo, source=None, rev=None,
4587 def identify(ui, repo, source=None, rev=None,
4590 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4588 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4591 """identify the working directory or specified revision
4589 """identify the working directory or specified revision
4592
4590
4593 Print a summary identifying the repository state at REV using one or
4591 Print a summary identifying the repository state at REV using one or
4594 two parent hash identifiers, followed by a "+" if the working
4592 two parent hash identifiers, followed by a "+" if the working
4595 directory has uncommitted changes, the branch name (if not default),
4593 directory has uncommitted changes, the branch name (if not default),
4596 a list of tags, and a list of bookmarks.
4594 a list of tags, and a list of bookmarks.
4597
4595
4598 When REV is not given, print a summary of the current state of the
4596 When REV is not given, print a summary of the current state of the
4599 repository.
4597 repository.
4600
4598
4601 Specifying a path to a repository root or Mercurial bundle will
4599 Specifying a path to a repository root or Mercurial bundle will
4602 cause lookup to operate on that repository/bundle.
4600 cause lookup to operate on that repository/bundle.
4603
4601
4604 .. container:: verbose
4602 .. container:: verbose
4605
4603
4606 Examples:
4604 Examples:
4607
4605
4608 - generate a build identifier for the working directory::
4606 - generate a build identifier for the working directory::
4609
4607
4610 hg id --id > build-id.dat
4608 hg id --id > build-id.dat
4611
4609
4612 - find the revision corresponding to a tag::
4610 - find the revision corresponding to a tag::
4613
4611
4614 hg id -n -r 1.3
4612 hg id -n -r 1.3
4615
4613
4616 - check the most recent revision of a remote repository::
4614 - check the most recent revision of a remote repository::
4617
4615
4618 hg id -r tip http://selenic.com/hg/
4616 hg id -r tip http://selenic.com/hg/
4619
4617
4620 See :hg:`log` for generating more information about specific revisions,
4618 See :hg:`log` for generating more information about specific revisions,
4621 including full hash identifiers.
4619 including full hash identifiers.
4622
4620
4623 Returns 0 if successful.
4621 Returns 0 if successful.
4624 """
4622 """
4625
4623
4626 if not repo and not source:
4624 if not repo and not source:
4627 raise error.Abort(_("there is no Mercurial repository here "
4625 raise error.Abort(_("there is no Mercurial repository here "
4628 "(.hg not found)"))
4626 "(.hg not found)"))
4629
4627
4630 if ui.debugflag:
4628 if ui.debugflag:
4631 hexfunc = hex
4629 hexfunc = hex
4632 else:
4630 else:
4633 hexfunc = short
4631 hexfunc = short
4634 default = not (num or id or branch or tags or bookmarks)
4632 default = not (num or id or branch or tags or bookmarks)
4635 output = []
4633 output = []
4636 revs = []
4634 revs = []
4637
4635
4638 if source:
4636 if source:
4639 source, branches = hg.parseurl(ui.expandpath(source))
4637 source, branches = hg.parseurl(ui.expandpath(source))
4640 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4638 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4641 repo = peer.local()
4639 repo = peer.local()
4642 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4640 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4643
4641
4644 if not repo:
4642 if not repo:
4645 if num or branch or tags:
4643 if num or branch or tags:
4646 raise error.Abort(
4644 raise error.Abort(
4647 _("can't query remote revision number, branch, or tags"))
4645 _("can't query remote revision number, branch, or tags"))
4648 if not rev and revs:
4646 if not rev and revs:
4649 rev = revs[0]
4647 rev = revs[0]
4650 if not rev:
4648 if not rev:
4651 rev = "tip"
4649 rev = "tip"
4652
4650
4653 remoterev = peer.lookup(rev)
4651 remoterev = peer.lookup(rev)
4654 if default or id:
4652 if default or id:
4655 output = [hexfunc(remoterev)]
4653 output = [hexfunc(remoterev)]
4656
4654
4657 def getbms():
4655 def getbms():
4658 bms = []
4656 bms = []
4659
4657
4660 if 'bookmarks' in peer.listkeys('namespaces'):
4658 if 'bookmarks' in peer.listkeys('namespaces'):
4661 hexremoterev = hex(remoterev)
4659 hexremoterev = hex(remoterev)
4662 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4660 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4663 if bmr == hexremoterev]
4661 if bmr == hexremoterev]
4664
4662
4665 return sorted(bms)
4663 return sorted(bms)
4666
4664
4667 if bookmarks:
4665 if bookmarks:
4668 output.extend(getbms())
4666 output.extend(getbms())
4669 elif default and not ui.quiet:
4667 elif default and not ui.quiet:
4670 # multiple bookmarks for a single parent separated by '/'
4668 # multiple bookmarks for a single parent separated by '/'
4671 bm = '/'.join(getbms())
4669 bm = '/'.join(getbms())
4672 if bm:
4670 if bm:
4673 output.append(bm)
4671 output.append(bm)
4674 else:
4672 else:
4675 ctx = scmutil.revsingle(repo, rev, None)
4673 ctx = scmutil.revsingle(repo, rev, None)
4676
4674
4677 if ctx.rev() is None:
4675 if ctx.rev() is None:
4678 ctx = repo[None]
4676 ctx = repo[None]
4679 parents = ctx.parents()
4677 parents = ctx.parents()
4680 taglist = []
4678 taglist = []
4681 for p in parents:
4679 for p in parents:
4682 taglist.extend(p.tags())
4680 taglist.extend(p.tags())
4683
4681
4684 changed = ""
4682 changed = ""
4685 if default or id or num:
4683 if default or id or num:
4686 if (any(repo.status())
4684 if (any(repo.status())
4687 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4685 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4688 changed = '+'
4686 changed = '+'
4689 if default or id:
4687 if default or id:
4690 output = ["%s%s" %
4688 output = ["%s%s" %
4691 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4689 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4692 if num:
4690 if num:
4693 output.append("%s%s" %
4691 output.append("%s%s" %
4694 ('+'.join([str(p.rev()) for p in parents]), changed))
4692 ('+'.join([str(p.rev()) for p in parents]), changed))
4695 else:
4693 else:
4696 if default or id:
4694 if default or id:
4697 output = [hexfunc(ctx.node())]
4695 output = [hexfunc(ctx.node())]
4698 if num:
4696 if num:
4699 output.append(str(ctx.rev()))
4697 output.append(str(ctx.rev()))
4700 taglist = ctx.tags()
4698 taglist = ctx.tags()
4701
4699
4702 if default and not ui.quiet:
4700 if default and not ui.quiet:
4703 b = ctx.branch()
4701 b = ctx.branch()
4704 if b != 'default':
4702 if b != 'default':
4705 output.append("(%s)" % b)
4703 output.append("(%s)" % b)
4706
4704
4707 # multiple tags for a single parent separated by '/'
4705 # multiple tags for a single parent separated by '/'
4708 t = '/'.join(taglist)
4706 t = '/'.join(taglist)
4709 if t:
4707 if t:
4710 output.append(t)
4708 output.append(t)
4711
4709
4712 # multiple bookmarks for a single parent separated by '/'
4710 # multiple bookmarks for a single parent separated by '/'
4713 bm = '/'.join(ctx.bookmarks())
4711 bm = '/'.join(ctx.bookmarks())
4714 if bm:
4712 if bm:
4715 output.append(bm)
4713 output.append(bm)
4716 else:
4714 else:
4717 if branch:
4715 if branch:
4718 output.append(ctx.branch())
4716 output.append(ctx.branch())
4719
4717
4720 if tags:
4718 if tags:
4721 output.extend(taglist)
4719 output.extend(taglist)
4722
4720
4723 if bookmarks:
4721 if bookmarks:
4724 output.extend(ctx.bookmarks())
4722 output.extend(ctx.bookmarks())
4725
4723
4726 ui.write("%s\n" % ' '.join(output))
4724 ui.write("%s\n" % ' '.join(output))
4727
4725
4728 @command('import|patch',
4726 @command('import|patch',
4729 [('p', 'strip', 1,
4727 [('p', 'strip', 1,
4730 _('directory strip option for patch. This has the same '
4728 _('directory strip option for patch. This has the same '
4731 'meaning as the corresponding patch option'), _('NUM')),
4729 'meaning as the corresponding patch option'), _('NUM')),
4732 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4730 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4733 ('e', 'edit', False, _('invoke editor on commit messages')),
4731 ('e', 'edit', False, _('invoke editor on commit messages')),
4734 ('f', 'force', None,
4732 ('f', 'force', None,
4735 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4733 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4736 ('', 'no-commit', None,
4734 ('', 'no-commit', None,
4737 _("don't commit, just update the working directory")),
4735 _("don't commit, just update the working directory")),
4738 ('', 'bypass', None,
4736 ('', 'bypass', None,
4739 _("apply patch without touching the working directory")),
4737 _("apply patch without touching the working directory")),
4740 ('', 'partial', None,
4738 ('', 'partial', None,
4741 _('commit even if some hunks fail')),
4739 _('commit even if some hunks fail')),
4742 ('', 'exact', None,
4740 ('', 'exact', None,
4743 _('apply patch to the nodes from which it was generated')),
4741 _('apply patch to the nodes from which it was generated')),
4744 ('', 'prefix', '',
4742 ('', 'prefix', '',
4745 _('apply patch to subdirectory'), _('DIR')),
4743 _('apply patch to subdirectory'), _('DIR')),
4746 ('', 'import-branch', None,
4744 ('', 'import-branch', None,
4747 _('use any branch information in patch (implied by --exact)'))] +
4745 _('use any branch information in patch (implied by --exact)'))] +
4748 commitopts + commitopts2 + similarityopts,
4746 commitopts + commitopts2 + similarityopts,
4749 _('[OPTION]... PATCH...'))
4747 _('[OPTION]... PATCH...'))
4750 def import_(ui, repo, patch1=None, *patches, **opts):
4748 def import_(ui, repo, patch1=None, *patches, **opts):
4751 """import an ordered set of patches
4749 """import an ordered set of patches
4752
4750
4753 Import a list of patches and commit them individually (unless
4751 Import a list of patches and commit them individually (unless
4754 --no-commit is specified).
4752 --no-commit is specified).
4755
4753
4756 To read a patch from standard input, use "-" as the patch name. If
4754 To read a patch from standard input, use "-" as the patch name. If
4757 a URL is specified, the patch will be downloaded from there.
4755 a URL is specified, the patch will be downloaded from there.
4758
4756
4759 Import first applies changes to the working directory (unless
4757 Import first applies changes to the working directory (unless
4760 --bypass is specified), import will abort if there are outstanding
4758 --bypass is specified), import will abort if there are outstanding
4761 changes.
4759 changes.
4762
4760
4763 Use --bypass to apply and commit patches directly to the
4761 Use --bypass to apply and commit patches directly to the
4764 repository, without affecting the working directory. Without
4762 repository, without affecting the working directory. Without
4765 --exact, patches will be applied on top of the working directory
4763 --exact, patches will be applied on top of the working directory
4766 parent revision.
4764 parent revision.
4767
4765
4768 You can import a patch straight from a mail message. Even patches
4766 You can import a patch straight from a mail message. Even patches
4769 as attachments work (to use the body part, it must have type
4767 as attachments work (to use the body part, it must have type
4770 text/plain or text/x-patch). From and Subject headers of email
4768 text/plain or text/x-patch). From and Subject headers of email
4771 message are used as default committer and commit message. All
4769 message are used as default committer and commit message. All
4772 text/plain body parts before first diff are added to the commit
4770 text/plain body parts before first diff are added to the commit
4773 message.
4771 message.
4774
4772
4775 If the imported patch was generated by :hg:`export`, user and
4773 If the imported patch was generated by :hg:`export`, user and
4776 description from patch override values from message headers and
4774 description from patch override values from message headers and
4777 body. Values given on command line with -m/--message and -u/--user
4775 body. Values given on command line with -m/--message and -u/--user
4778 override these.
4776 override these.
4779
4777
4780 If --exact is specified, import will set the working directory to
4778 If --exact is specified, import will set the working directory to
4781 the parent of each patch before applying it, and will abort if the
4779 the parent of each patch before applying it, and will abort if the
4782 resulting changeset has a different ID than the one recorded in
4780 resulting changeset has a different ID than the one recorded in
4783 the patch. This may happen due to character set problems or other
4781 the patch. This may happen due to character set problems or other
4784 deficiencies in the text patch format.
4782 deficiencies in the text patch format.
4785
4783
4786 Use --partial to ensure a changeset will be created from the patch
4784 Use --partial to ensure a changeset will be created from the patch
4787 even if some hunks fail to apply. Hunks that fail to apply will be
4785 even if some hunks fail to apply. Hunks that fail to apply will be
4788 written to a <target-file>.rej file. Conflicts can then be resolved
4786 written to a <target-file>.rej file. Conflicts can then be resolved
4789 by hand before :hg:`commit --amend` is run to update the created
4787 by hand before :hg:`commit --amend` is run to update the created
4790 changeset. This flag exists to let people import patches that
4788 changeset. This flag exists to let people import patches that
4791 partially apply without losing the associated metadata (author,
4789 partially apply without losing the associated metadata (author,
4792 date, description, ...).
4790 date, description, ...).
4793
4791
4794 .. note::
4792 .. note::
4795
4793
4796 When no hunks apply cleanly, :hg:`import --partial` will create
4794 When no hunks apply cleanly, :hg:`import --partial` will create
4797 an empty changeset, importing only the patch metadata.
4795 an empty changeset, importing only the patch metadata.
4798
4796
4799 With -s/--similarity, hg will attempt to discover renames and
4797 With -s/--similarity, hg will attempt to discover renames and
4800 copies in the patch in the same way as :hg:`addremove`.
4798 copies in the patch in the same way as :hg:`addremove`.
4801
4799
4802 It is possible to use external patch programs to perform the patch
4800 It is possible to use external patch programs to perform the patch
4803 by setting the ``ui.patch`` configuration option. For the default
4801 by setting the ``ui.patch`` configuration option. For the default
4804 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4802 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4805 See :hg:`help config` for more information about configuration
4803 See :hg:`help config` for more information about configuration
4806 files and how to use these options.
4804 files and how to use these options.
4807
4805
4808 See :hg:`help dates` for a list of formats valid for -d/--date.
4806 See :hg:`help dates` for a list of formats valid for -d/--date.
4809
4807
4810 .. container:: verbose
4808 .. container:: verbose
4811
4809
4812 Examples:
4810 Examples:
4813
4811
4814 - import a traditional patch from a website and detect renames::
4812 - import a traditional patch from a website and detect renames::
4815
4813
4816 hg import -s 80 http://example.com/bugfix.patch
4814 hg import -s 80 http://example.com/bugfix.patch
4817
4815
4818 - import a changeset from an hgweb server::
4816 - import a changeset from an hgweb server::
4819
4817
4820 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4818 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4821
4819
4822 - import all the patches in an Unix-style mbox::
4820 - import all the patches in an Unix-style mbox::
4823
4821
4824 hg import incoming-patches.mbox
4822 hg import incoming-patches.mbox
4825
4823
4826 - attempt to exactly restore an exported changeset (not always
4824 - attempt to exactly restore an exported changeset (not always
4827 possible)::
4825 possible)::
4828
4826
4829 hg import --exact proposed-fix.patch
4827 hg import --exact proposed-fix.patch
4830
4828
4831 - use an external tool to apply a patch which is too fuzzy for
4829 - use an external tool to apply a patch which is too fuzzy for
4832 the default internal tool.
4830 the default internal tool.
4833
4831
4834 hg import --config ui.patch="patch --merge" fuzzy.patch
4832 hg import --config ui.patch="patch --merge" fuzzy.patch
4835
4833
4836 - change the default fuzzing from 2 to a less strict 7
4834 - change the default fuzzing from 2 to a less strict 7
4837
4835
4838 hg import --config ui.fuzz=7 fuzz.patch
4836 hg import --config ui.fuzz=7 fuzz.patch
4839
4837
4840 Returns 0 on success, 1 on partial success (see --partial).
4838 Returns 0 on success, 1 on partial success (see --partial).
4841 """
4839 """
4842
4840
4843 if not patch1:
4841 if not patch1:
4844 raise error.Abort(_('need at least one patch to import'))
4842 raise error.Abort(_('need at least one patch to import'))
4845
4843
4846 patches = (patch1,) + patches
4844 patches = (patch1,) + patches
4847
4845
4848 date = opts.get('date')
4846 date = opts.get('date')
4849 if date:
4847 if date:
4850 opts['date'] = util.parsedate(date)
4848 opts['date'] = util.parsedate(date)
4851
4849
4852 exact = opts.get('exact')
4850 exact = opts.get('exact')
4853 update = not opts.get('bypass')
4851 update = not opts.get('bypass')
4854 if not update and opts.get('no_commit'):
4852 if not update and opts.get('no_commit'):
4855 raise error.Abort(_('cannot use --no-commit with --bypass'))
4853 raise error.Abort(_('cannot use --no-commit with --bypass'))
4856 try:
4854 try:
4857 sim = float(opts.get('similarity') or 0)
4855 sim = float(opts.get('similarity') or 0)
4858 except ValueError:
4856 except ValueError:
4859 raise error.Abort(_('similarity must be a number'))
4857 raise error.Abort(_('similarity must be a number'))
4860 if sim < 0 or sim > 100:
4858 if sim < 0 or sim > 100:
4861 raise error.Abort(_('similarity must be between 0 and 100'))
4859 raise error.Abort(_('similarity must be between 0 and 100'))
4862 if sim and not update:
4860 if sim and not update:
4863 raise error.Abort(_('cannot use --similarity with --bypass'))
4861 raise error.Abort(_('cannot use --similarity with --bypass'))
4864 if exact:
4862 if exact:
4865 if opts.get('edit'):
4863 if opts.get('edit'):
4866 raise error.Abort(_('cannot use --exact with --edit'))
4864 raise error.Abort(_('cannot use --exact with --edit'))
4867 if opts.get('prefix'):
4865 if opts.get('prefix'):
4868 raise error.Abort(_('cannot use --exact with --prefix'))
4866 raise error.Abort(_('cannot use --exact with --prefix'))
4869
4867
4870 base = opts["base"]
4868 base = opts["base"]
4871 wlock = dsguard = lock = tr = None
4869 wlock = dsguard = lock = tr = None
4872 msgs = []
4870 msgs = []
4873 ret = 0
4871 ret = 0
4874
4872
4875
4873
4876 try:
4874 try:
4877 wlock = repo.wlock()
4875 wlock = repo.wlock()
4878
4876
4879 if update:
4877 if update:
4880 cmdutil.checkunfinished(repo)
4878 cmdutil.checkunfinished(repo)
4881 if (exact or not opts.get('force')):
4879 if (exact or not opts.get('force')):
4882 cmdutil.bailifchanged(repo)
4880 cmdutil.bailifchanged(repo)
4883
4881
4884 if not opts.get('no_commit'):
4882 if not opts.get('no_commit'):
4885 lock = repo.lock()
4883 lock = repo.lock()
4886 tr = repo.transaction('import')
4884 tr = repo.transaction('import')
4887 else:
4885 else:
4888 dsguard = cmdutil.dirstateguard(repo, 'import')
4886 dsguard = cmdutil.dirstateguard(repo, 'import')
4889 parents = repo[None].parents()
4887 parents = repo[None].parents()
4890 for patchurl in patches:
4888 for patchurl in patches:
4891 if patchurl == '-':
4889 if patchurl == '-':
4892 ui.status(_('applying patch from stdin\n'))
4890 ui.status(_('applying patch from stdin\n'))
4893 patchfile = ui.fin
4891 patchfile = ui.fin
4894 patchurl = 'stdin' # for error message
4892 patchurl = 'stdin' # for error message
4895 else:
4893 else:
4896 patchurl = os.path.join(base, patchurl)
4894 patchurl = os.path.join(base, patchurl)
4897 ui.status(_('applying %s\n') % patchurl)
4895 ui.status(_('applying %s\n') % patchurl)
4898 patchfile = hg.openpath(ui, patchurl)
4896 patchfile = hg.openpath(ui, patchurl)
4899
4897
4900 haspatch = False
4898 haspatch = False
4901 for hunk in patch.split(patchfile):
4899 for hunk in patch.split(patchfile):
4902 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4900 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4903 parents, opts,
4901 parents, opts,
4904 msgs, hg.clean)
4902 msgs, hg.clean)
4905 if msg:
4903 if msg:
4906 haspatch = True
4904 haspatch = True
4907 ui.note(msg + '\n')
4905 ui.note(msg + '\n')
4908 if update or exact:
4906 if update or exact:
4909 parents = repo[None].parents()
4907 parents = repo[None].parents()
4910 else:
4908 else:
4911 parents = [repo[node]]
4909 parents = [repo[node]]
4912 if rej:
4910 if rej:
4913 ui.write_err(_("patch applied partially\n"))
4911 ui.write_err(_("patch applied partially\n"))
4914 ui.write_err(_("(fix the .rej files and run "
4912 ui.write_err(_("(fix the .rej files and run "
4915 "`hg commit --amend`)\n"))
4913 "`hg commit --amend`)\n"))
4916 ret = 1
4914 ret = 1
4917 break
4915 break
4918
4916
4919 if not haspatch:
4917 if not haspatch:
4920 raise error.Abort(_('%s: no diffs found') % patchurl)
4918 raise error.Abort(_('%s: no diffs found') % patchurl)
4921
4919
4922 if tr:
4920 if tr:
4923 tr.close()
4921 tr.close()
4924 if msgs:
4922 if msgs:
4925 repo.savecommitmessage('\n* * *\n'.join(msgs))
4923 repo.savecommitmessage('\n* * *\n'.join(msgs))
4926 if dsguard:
4924 if dsguard:
4927 dsguard.close()
4925 dsguard.close()
4928 return ret
4926 return ret
4929 finally:
4927 finally:
4930 if tr:
4928 if tr:
4931 tr.release()
4929 tr.release()
4932 release(lock, dsguard, wlock)
4930 release(lock, dsguard, wlock)
4933
4931
4934 @command('incoming|in',
4932 @command('incoming|in',
4935 [('f', 'force', None,
4933 [('f', 'force', None,
4936 _('run even if remote repository is unrelated')),
4934 _('run even if remote repository is unrelated')),
4937 ('n', 'newest-first', None, _('show newest record first')),
4935 ('n', 'newest-first', None, _('show newest record first')),
4938 ('', 'bundle', '',
4936 ('', 'bundle', '',
4939 _('file to store the bundles into'), _('FILE')),
4937 _('file to store the bundles into'), _('FILE')),
4940 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4938 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4941 ('B', 'bookmarks', False, _("compare bookmarks")),
4939 ('B', 'bookmarks', False, _("compare bookmarks")),
4942 ('b', 'branch', [],
4940 ('b', 'branch', [],
4943 _('a specific branch you would like to pull'), _('BRANCH')),
4941 _('a specific branch you would like to pull'), _('BRANCH')),
4944 ] + logopts + remoteopts + subrepoopts,
4942 ] + logopts + remoteopts + subrepoopts,
4945 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4943 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4946 def incoming(ui, repo, source="default", **opts):
4944 def incoming(ui, repo, source="default", **opts):
4947 """show new changesets found in source
4945 """show new changesets found in source
4948
4946
4949 Show new changesets found in the specified path/URL or the default
4947 Show new changesets found in the specified path/URL or the default
4950 pull location. These are the changesets that would have been pulled
4948 pull location. These are the changesets that would have been pulled
4951 if a pull at the time you issued this command.
4949 if a pull at the time you issued this command.
4952
4950
4953 See pull for valid source format details.
4951 See pull for valid source format details.
4954
4952
4955 .. container:: verbose
4953 .. container:: verbose
4956
4954
4957 With -B/--bookmarks, the result of bookmark comparison between
4955 With -B/--bookmarks, the result of bookmark comparison between
4958 local and remote repositories is displayed. With -v/--verbose,
4956 local and remote repositories is displayed. With -v/--verbose,
4959 status is also displayed for each bookmark like below::
4957 status is also displayed for each bookmark like below::
4960
4958
4961 BM1 01234567890a added
4959 BM1 01234567890a added
4962 BM2 1234567890ab advanced
4960 BM2 1234567890ab advanced
4963 BM3 234567890abc diverged
4961 BM3 234567890abc diverged
4964 BM4 34567890abcd changed
4962 BM4 34567890abcd changed
4965
4963
4966 The action taken locally when pulling depends on the
4964 The action taken locally when pulling depends on the
4967 status of each bookmark:
4965 status of each bookmark:
4968
4966
4969 :``added``: pull will create it
4967 :``added``: pull will create it
4970 :``advanced``: pull will update it
4968 :``advanced``: pull will update it
4971 :``diverged``: pull will create a divergent bookmark
4969 :``diverged``: pull will create a divergent bookmark
4972 :``changed``: result depends on remote changesets
4970 :``changed``: result depends on remote changesets
4973
4971
4974 From the point of view of pulling behavior, bookmark
4972 From the point of view of pulling behavior, bookmark
4975 existing only in the remote repository are treated as ``added``,
4973 existing only in the remote repository are treated as ``added``,
4976 even if it is in fact locally deleted.
4974 even if it is in fact locally deleted.
4977
4975
4978 .. container:: verbose
4976 .. container:: verbose
4979
4977
4980 For remote repository, using --bundle avoids downloading the
4978 For remote repository, using --bundle avoids downloading the
4981 changesets twice if the incoming is followed by a pull.
4979 changesets twice if the incoming is followed by a pull.
4982
4980
4983 Examples:
4981 Examples:
4984
4982
4985 - show incoming changes with patches and full description::
4983 - show incoming changes with patches and full description::
4986
4984
4987 hg incoming -vp
4985 hg incoming -vp
4988
4986
4989 - show incoming changes excluding merges, store a bundle::
4987 - show incoming changes excluding merges, store a bundle::
4990
4988
4991 hg in -vpM --bundle incoming.hg
4989 hg in -vpM --bundle incoming.hg
4992 hg pull incoming.hg
4990 hg pull incoming.hg
4993
4991
4994 - briefly list changes inside a bundle::
4992 - briefly list changes inside a bundle::
4995
4993
4996 hg in changes.hg -T "{desc|firstline}\\n"
4994 hg in changes.hg -T "{desc|firstline}\\n"
4997
4995
4998 Returns 0 if there are incoming changes, 1 otherwise.
4996 Returns 0 if there are incoming changes, 1 otherwise.
4999 """
4997 """
5000 if opts.get('graph'):
4998 if opts.get('graph'):
5001 cmdutil.checkunsupportedgraphflags([], opts)
4999 cmdutil.checkunsupportedgraphflags([], opts)
5002 def display(other, chlist, displayer):
5000 def display(other, chlist, displayer):
5003 revdag = cmdutil.graphrevs(other, chlist, opts)
5001 revdag = cmdutil.graphrevs(other, chlist, opts)
5004 cmdutil.displaygraph(ui, repo, revdag, displayer,
5002 cmdutil.displaygraph(ui, repo, revdag, displayer,
5005 graphmod.asciiedges)
5003 graphmod.asciiedges)
5006
5004
5007 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5005 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5008 return 0
5006 return 0
5009
5007
5010 if opts.get('bundle') and opts.get('subrepos'):
5008 if opts.get('bundle') and opts.get('subrepos'):
5011 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5009 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5012
5010
5013 if opts.get('bookmarks'):
5011 if opts.get('bookmarks'):
5014 source, branches = hg.parseurl(ui.expandpath(source),
5012 source, branches = hg.parseurl(ui.expandpath(source),
5015 opts.get('branch'))
5013 opts.get('branch'))
5016 other = hg.peer(repo, opts, source)
5014 other = hg.peer(repo, opts, source)
5017 if 'bookmarks' not in other.listkeys('namespaces'):
5015 if 'bookmarks' not in other.listkeys('namespaces'):
5018 ui.warn(_("remote doesn't support bookmarks\n"))
5016 ui.warn(_("remote doesn't support bookmarks\n"))
5019 return 0
5017 return 0
5020 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5018 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5021 return bookmarks.incoming(ui, repo, other)
5019 return bookmarks.incoming(ui, repo, other)
5022
5020
5023 repo._subtoppath = ui.expandpath(source)
5021 repo._subtoppath = ui.expandpath(source)
5024 try:
5022 try:
5025 return hg.incoming(ui, repo, source, opts)
5023 return hg.incoming(ui, repo, source, opts)
5026 finally:
5024 finally:
5027 del repo._subtoppath
5025 del repo._subtoppath
5028
5026
5029
5027
5030 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5028 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5031 norepo=True)
5029 norepo=True)
5032 def init(ui, dest=".", **opts):
5030 def init(ui, dest=".", **opts):
5033 """create a new repository in the given directory
5031 """create a new repository in the given directory
5034
5032
5035 Initialize a new repository in the given directory. If the given
5033 Initialize a new repository in the given directory. If the given
5036 directory does not exist, it will be created.
5034 directory does not exist, it will be created.
5037
5035
5038 If no directory is given, the current directory is used.
5036 If no directory is given, the current directory is used.
5039
5037
5040 It is possible to specify an ``ssh://`` URL as the destination.
5038 It is possible to specify an ``ssh://`` URL as the destination.
5041 See :hg:`help urls` for more information.
5039 See :hg:`help urls` for more information.
5042
5040
5043 Returns 0 on success.
5041 Returns 0 on success.
5044 """
5042 """
5045 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5043 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5046
5044
5047 @command('locate',
5045 @command('locate',
5048 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5046 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5049 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5047 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5050 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5048 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5051 ] + walkopts,
5049 ] + walkopts,
5052 _('[OPTION]... [PATTERN]...'))
5050 _('[OPTION]... [PATTERN]...'))
5053 def locate(ui, repo, *pats, **opts):
5051 def locate(ui, repo, *pats, **opts):
5054 """locate files matching specific patterns (DEPRECATED)
5052 """locate files matching specific patterns (DEPRECATED)
5055
5053
5056 Print files under Mercurial control in the working directory whose
5054 Print files under Mercurial control in the working directory whose
5057 names match the given patterns.
5055 names match the given patterns.
5058
5056
5059 By default, this command searches all directories in the working
5057 By default, this command searches all directories in the working
5060 directory. To search just the current directory and its
5058 directory. To search just the current directory and its
5061 subdirectories, use "--include .".
5059 subdirectories, use "--include .".
5062
5060
5063 If no patterns are given to match, this command prints the names
5061 If no patterns are given to match, this command prints the names
5064 of all files under Mercurial control in the working directory.
5062 of all files under Mercurial control in the working directory.
5065
5063
5066 If you want to feed the output of this command into the "xargs"
5064 If you want to feed the output of this command into the "xargs"
5067 command, use the -0 option to both this command and "xargs". This
5065 command, use the -0 option to both this command and "xargs". This
5068 will avoid the problem of "xargs" treating single filenames that
5066 will avoid the problem of "xargs" treating single filenames that
5069 contain whitespace as multiple filenames.
5067 contain whitespace as multiple filenames.
5070
5068
5071 See :hg:`help files` for a more versatile command.
5069 See :hg:`help files` for a more versatile command.
5072
5070
5073 Returns 0 if a match is found, 1 otherwise.
5071 Returns 0 if a match is found, 1 otherwise.
5074 """
5072 """
5075 if opts.get('print0'):
5073 if opts.get('print0'):
5076 end = '\0'
5074 end = '\0'
5077 else:
5075 else:
5078 end = '\n'
5076 end = '\n'
5079 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5077 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5080
5078
5081 ret = 1
5079 ret = 1
5082 ctx = repo[rev]
5080 ctx = repo[rev]
5083 m = scmutil.match(ctx, pats, opts, default='relglob',
5081 m = scmutil.match(ctx, pats, opts, default='relglob',
5084 badfn=lambda x, y: False)
5082 badfn=lambda x, y: False)
5085
5083
5086 for abs in ctx.matches(m):
5084 for abs in ctx.matches(m):
5087 if opts.get('fullpath'):
5085 if opts.get('fullpath'):
5088 ui.write(repo.wjoin(abs), end)
5086 ui.write(repo.wjoin(abs), end)
5089 else:
5087 else:
5090 ui.write(((pats and m.rel(abs)) or abs), end)
5088 ui.write(((pats and m.rel(abs)) or abs), end)
5091 ret = 0
5089 ret = 0
5092
5090
5093 return ret
5091 return ret
5094
5092
5095 @command('^log|history',
5093 @command('^log|history',
5096 [('f', 'follow', None,
5094 [('f', 'follow', None,
5097 _('follow changeset history, or file history across copies and renames')),
5095 _('follow changeset history, or file history across copies and renames')),
5098 ('', 'follow-first', None,
5096 ('', 'follow-first', None,
5099 _('only follow the first parent of merge changesets (DEPRECATED)')),
5097 _('only follow the first parent of merge changesets (DEPRECATED)')),
5100 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5098 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5101 ('C', 'copies', None, _('show copied files')),
5099 ('C', 'copies', None, _('show copied files')),
5102 ('k', 'keyword', [],
5100 ('k', 'keyword', [],
5103 _('do case-insensitive search for a given text'), _('TEXT')),
5101 _('do case-insensitive search for a given text'), _('TEXT')),
5104 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5102 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5105 ('', 'removed', None, _('include revisions where files were removed')),
5103 ('', 'removed', None, _('include revisions where files were removed')),
5106 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5104 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5107 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5105 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5108 ('', 'only-branch', [],
5106 ('', 'only-branch', [],
5109 _('show only changesets within the given named branch (DEPRECATED)'),
5107 _('show only changesets within the given named branch (DEPRECATED)'),
5110 _('BRANCH')),
5108 _('BRANCH')),
5111 ('b', 'branch', [],
5109 ('b', 'branch', [],
5112 _('show changesets within the given named branch'), _('BRANCH')),
5110 _('show changesets within the given named branch'), _('BRANCH')),
5113 ('P', 'prune', [],
5111 ('P', 'prune', [],
5114 _('do not display revision or any of its ancestors'), _('REV')),
5112 _('do not display revision or any of its ancestors'), _('REV')),
5115 ] + logopts + walkopts,
5113 ] + logopts + walkopts,
5116 _('[OPTION]... [FILE]'),
5114 _('[OPTION]... [FILE]'),
5117 inferrepo=True)
5115 inferrepo=True)
5118 def log(ui, repo, *pats, **opts):
5116 def log(ui, repo, *pats, **opts):
5119 """show revision history of entire repository or files
5117 """show revision history of entire repository or files
5120
5118
5121 Print the revision history of the specified files or the entire
5119 Print the revision history of the specified files or the entire
5122 project.
5120 project.
5123
5121
5124 If no revision range is specified, the default is ``tip:0`` unless
5122 If no revision range is specified, the default is ``tip:0`` unless
5125 --follow is set, in which case the working directory parent is
5123 --follow is set, in which case the working directory parent is
5126 used as the starting revision.
5124 used as the starting revision.
5127
5125
5128 File history is shown without following rename or copy history of
5126 File history is shown without following rename or copy history of
5129 files. Use -f/--follow with a filename to follow history across
5127 files. Use -f/--follow with a filename to follow history across
5130 renames and copies. --follow without a filename will only show
5128 renames and copies. --follow without a filename will only show
5131 ancestors or descendants of the starting revision.
5129 ancestors or descendants of the starting revision.
5132
5130
5133 By default this command prints revision number and changeset id,
5131 By default this command prints revision number and changeset id,
5134 tags, non-trivial parents, user, date and time, and a summary for
5132 tags, non-trivial parents, user, date and time, and a summary for
5135 each commit. When the -v/--verbose switch is used, the list of
5133 each commit. When the -v/--verbose switch is used, the list of
5136 changed files and full commit message are shown.
5134 changed files and full commit message are shown.
5137
5135
5138 With --graph the revisions are shown as an ASCII art DAG with the most
5136 With --graph the revisions are shown as an ASCII art DAG with the most
5139 recent changeset at the top.
5137 recent changeset at the top.
5140 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5138 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5141 and '+' represents a fork where the changeset from the lines below is a
5139 and '+' represents a fork where the changeset from the lines below is a
5142 parent of the 'o' merge on the same line.
5140 parent of the 'o' merge on the same line.
5143
5141
5144 .. note::
5142 .. note::
5145
5143
5146 :hg:`log --patch` may generate unexpected diff output for merge
5144 :hg:`log --patch` may generate unexpected diff output for merge
5147 changesets, as it will only compare the merge changeset against
5145 changesets, as it will only compare the merge changeset against
5148 its first parent. Also, only files different from BOTH parents
5146 its first parent. Also, only files different from BOTH parents
5149 will appear in files:.
5147 will appear in files:.
5150
5148
5151 .. note::
5149 .. note::
5152
5150
5153 For performance reasons, :hg:`log FILE` may omit duplicate changes
5151 For performance reasons, :hg:`log FILE` may omit duplicate changes
5154 made on branches and will not show removals or mode changes. To
5152 made on branches and will not show removals or mode changes. To
5155 see all such changes, use the --removed switch.
5153 see all such changes, use the --removed switch.
5156
5154
5157 .. container:: verbose
5155 .. container:: verbose
5158
5156
5159 Some examples:
5157 Some examples:
5160
5158
5161 - changesets with full descriptions and file lists::
5159 - changesets with full descriptions and file lists::
5162
5160
5163 hg log -v
5161 hg log -v
5164
5162
5165 - changesets ancestral to the working directory::
5163 - changesets ancestral to the working directory::
5166
5164
5167 hg log -f
5165 hg log -f
5168
5166
5169 - last 10 commits on the current branch::
5167 - last 10 commits on the current branch::
5170
5168
5171 hg log -l 10 -b .
5169 hg log -l 10 -b .
5172
5170
5173 - changesets showing all modifications of a file, including removals::
5171 - changesets showing all modifications of a file, including removals::
5174
5172
5175 hg log --removed file.c
5173 hg log --removed file.c
5176
5174
5177 - all changesets that touch a directory, with diffs, excluding merges::
5175 - all changesets that touch a directory, with diffs, excluding merges::
5178
5176
5179 hg log -Mp lib/
5177 hg log -Mp lib/
5180
5178
5181 - all revision numbers that match a keyword::
5179 - all revision numbers that match a keyword::
5182
5180
5183 hg log -k bug --template "{rev}\\n"
5181 hg log -k bug --template "{rev}\\n"
5184
5182
5185 - the full hash identifier of the working directory parent::
5183 - the full hash identifier of the working directory parent::
5186
5184
5187 hg log -r . --template "{node}\\n"
5185 hg log -r . --template "{node}\\n"
5188
5186
5189 - list available log templates::
5187 - list available log templates::
5190
5188
5191 hg log -T list
5189 hg log -T list
5192
5190
5193 - check if a given changeset is included in a tagged release::
5191 - check if a given changeset is included in a tagged release::
5194
5192
5195 hg log -r "a21ccf and ancestor(1.9)"
5193 hg log -r "a21ccf and ancestor(1.9)"
5196
5194
5197 - find all changesets by some user in a date range::
5195 - find all changesets by some user in a date range::
5198
5196
5199 hg log -k alice -d "may 2008 to jul 2008"
5197 hg log -k alice -d "may 2008 to jul 2008"
5200
5198
5201 - summary of all changesets after the last tag::
5199 - summary of all changesets after the last tag::
5202
5200
5203 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5201 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5204
5202
5205 See :hg:`help dates` for a list of formats valid for -d/--date.
5203 See :hg:`help dates` for a list of formats valid for -d/--date.
5206
5204
5207 See :hg:`help revisions` and :hg:`help revsets` for more about
5205 See :hg:`help revisions` and :hg:`help revsets` for more about
5208 specifying and ordering revisions.
5206 specifying and ordering revisions.
5209
5207
5210 See :hg:`help templates` for more about pre-packaged styles and
5208 See :hg:`help templates` for more about pre-packaged styles and
5211 specifying custom templates.
5209 specifying custom templates.
5212
5210
5213 Returns 0 on success.
5211 Returns 0 on success.
5214
5212
5215 """
5213 """
5216 if opts.get('follow') and opts.get('rev'):
5214 if opts.get('follow') and opts.get('rev'):
5217 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5215 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5218 del opts['follow']
5216 del opts['follow']
5219
5217
5220 if opts.get('graph'):
5218 if opts.get('graph'):
5221 return cmdutil.graphlog(ui, repo, *pats, **opts)
5219 return cmdutil.graphlog(ui, repo, *pats, **opts)
5222
5220
5223 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5221 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5224 limit = cmdutil.loglimit(opts)
5222 limit = cmdutil.loglimit(opts)
5225 count = 0
5223 count = 0
5226
5224
5227 getrenamed = None
5225 getrenamed = None
5228 if opts.get('copies'):
5226 if opts.get('copies'):
5229 endrev = None
5227 endrev = None
5230 if opts.get('rev'):
5228 if opts.get('rev'):
5231 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5229 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5232 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5230 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5233
5231
5234 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5232 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5235 for rev in revs:
5233 for rev in revs:
5236 if count == limit:
5234 if count == limit:
5237 break
5235 break
5238 ctx = repo[rev]
5236 ctx = repo[rev]
5239 copies = None
5237 copies = None
5240 if getrenamed is not None and rev:
5238 if getrenamed is not None and rev:
5241 copies = []
5239 copies = []
5242 for fn in ctx.files():
5240 for fn in ctx.files():
5243 rename = getrenamed(fn, rev)
5241 rename = getrenamed(fn, rev)
5244 if rename:
5242 if rename:
5245 copies.append((fn, rename[0]))
5243 copies.append((fn, rename[0]))
5246 if filematcher:
5244 if filematcher:
5247 revmatchfn = filematcher(ctx.rev())
5245 revmatchfn = filematcher(ctx.rev())
5248 else:
5246 else:
5249 revmatchfn = None
5247 revmatchfn = None
5250 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5248 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5251 if displayer.flush(ctx):
5249 if displayer.flush(ctx):
5252 count += 1
5250 count += 1
5253
5251
5254 displayer.close()
5252 displayer.close()
5255
5253
5256 @command('manifest',
5254 @command('manifest',
5257 [('r', 'rev', '', _('revision to display'), _('REV')),
5255 [('r', 'rev', '', _('revision to display'), _('REV')),
5258 ('', 'all', False, _("list files from all revisions"))]
5256 ('', 'all', False, _("list files from all revisions"))]
5259 + formatteropts,
5257 + formatteropts,
5260 _('[-r REV]'))
5258 _('[-r REV]'))
5261 def manifest(ui, repo, node=None, rev=None, **opts):
5259 def manifest(ui, repo, node=None, rev=None, **opts):
5262 """output the current or given revision of the project manifest
5260 """output the current or given revision of the project manifest
5263
5261
5264 Print a list of version controlled files for the given revision.
5262 Print a list of version controlled files for the given revision.
5265 If no revision is given, the first parent of the working directory
5263 If no revision is given, the first parent of the working directory
5266 is used, or the null revision if no revision is checked out.
5264 is used, or the null revision if no revision is checked out.
5267
5265
5268 With -v, print file permissions, symlink and executable bits.
5266 With -v, print file permissions, symlink and executable bits.
5269 With --debug, print file revision hashes.
5267 With --debug, print file revision hashes.
5270
5268
5271 If option --all is specified, the list of all files from all revisions
5269 If option --all is specified, the list of all files from all revisions
5272 is printed. This includes deleted and renamed files.
5270 is printed. This includes deleted and renamed files.
5273
5271
5274 Returns 0 on success.
5272 Returns 0 on success.
5275 """
5273 """
5276
5274
5277 fm = ui.formatter('manifest', opts)
5275 fm = ui.formatter('manifest', opts)
5278
5276
5279 if opts.get('all'):
5277 if opts.get('all'):
5280 if rev or node:
5278 if rev or node:
5281 raise error.Abort(_("can't specify a revision with --all"))
5279 raise error.Abort(_("can't specify a revision with --all"))
5282
5280
5283 res = []
5281 res = []
5284 prefix = "data/"
5282 prefix = "data/"
5285 suffix = ".i"
5283 suffix = ".i"
5286 plen = len(prefix)
5284 plen = len(prefix)
5287 slen = len(suffix)
5285 slen = len(suffix)
5288 with repo.lock():
5286 with repo.lock():
5289 for fn, b, size in repo.store.datafiles():
5287 for fn, b, size in repo.store.datafiles():
5290 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5288 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5291 res.append(fn[plen:-slen])
5289 res.append(fn[plen:-slen])
5292 for f in res:
5290 for f in res:
5293 fm.startitem()
5291 fm.startitem()
5294 fm.write("path", '%s\n', f)
5292 fm.write("path", '%s\n', f)
5295 fm.end()
5293 fm.end()
5296 return
5294 return
5297
5295
5298 if rev and node:
5296 if rev and node:
5299 raise error.Abort(_("please specify just one revision"))
5297 raise error.Abort(_("please specify just one revision"))
5300
5298
5301 if not node:
5299 if not node:
5302 node = rev
5300 node = rev
5303
5301
5304 char = {'l': '@', 'x': '*', '': ''}
5302 char = {'l': '@', 'x': '*', '': ''}
5305 mode = {'l': '644', 'x': '755', '': '644'}
5303 mode = {'l': '644', 'x': '755', '': '644'}
5306 ctx = scmutil.revsingle(repo, node)
5304 ctx = scmutil.revsingle(repo, node)
5307 mf = ctx.manifest()
5305 mf = ctx.manifest()
5308 for f in ctx:
5306 for f in ctx:
5309 fm.startitem()
5307 fm.startitem()
5310 fl = ctx[f].flags()
5308 fl = ctx[f].flags()
5311 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5309 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5312 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5310 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5313 fm.write('path', '%s\n', f)
5311 fm.write('path', '%s\n', f)
5314 fm.end()
5312 fm.end()
5315
5313
5316 @command('^merge',
5314 @command('^merge',
5317 [('f', 'force', None,
5315 [('f', 'force', None,
5318 _('force a merge including outstanding changes (DEPRECATED)')),
5316 _('force a merge including outstanding changes (DEPRECATED)')),
5319 ('r', 'rev', '', _('revision to merge'), _('REV')),
5317 ('r', 'rev', '', _('revision to merge'), _('REV')),
5320 ('P', 'preview', None,
5318 ('P', 'preview', None,
5321 _('review revisions to merge (no merge is performed)'))
5319 _('review revisions to merge (no merge is performed)'))
5322 ] + mergetoolopts,
5320 ] + mergetoolopts,
5323 _('[-P] [[-r] REV]'))
5321 _('[-P] [[-r] REV]'))
5324 def merge(ui, repo, node=None, **opts):
5322 def merge(ui, repo, node=None, **opts):
5325 """merge another revision into working directory
5323 """merge another revision into working directory
5326
5324
5327 The current working directory is updated with all changes made in
5325 The current working directory is updated with all changes made in
5328 the requested revision since the last common predecessor revision.
5326 the requested revision since the last common predecessor revision.
5329
5327
5330 Files that changed between either parent are marked as changed for
5328 Files that changed between either parent are marked as changed for
5331 the next commit and a commit must be performed before any further
5329 the next commit and a commit must be performed before any further
5332 updates to the repository are allowed. The next commit will have
5330 updates to the repository are allowed. The next commit will have
5333 two parents.
5331 two parents.
5334
5332
5335 ``--tool`` can be used to specify the merge tool used for file
5333 ``--tool`` can be used to specify the merge tool used for file
5336 merges. It overrides the HGMERGE environment variable and your
5334 merges. It overrides the HGMERGE environment variable and your
5337 configuration files. See :hg:`help merge-tools` for options.
5335 configuration files. See :hg:`help merge-tools` for options.
5338
5336
5339 If no revision is specified, the working directory's parent is a
5337 If no revision is specified, the working directory's parent is a
5340 head revision, and the current branch contains exactly one other
5338 head revision, and the current branch contains exactly one other
5341 head, the other head is merged with by default. Otherwise, an
5339 head, the other head is merged with by default. Otherwise, an
5342 explicit revision with which to merge with must be provided.
5340 explicit revision with which to merge with must be provided.
5343
5341
5344 See :hg:`help resolve` for information on handling file conflicts.
5342 See :hg:`help resolve` for information on handling file conflicts.
5345
5343
5346 To undo an uncommitted merge, use :hg:`update --clean .` which
5344 To undo an uncommitted merge, use :hg:`update --clean .` which
5347 will check out a clean copy of the original merge parent, losing
5345 will check out a clean copy of the original merge parent, losing
5348 all changes.
5346 all changes.
5349
5347
5350 Returns 0 on success, 1 if there are unresolved files.
5348 Returns 0 on success, 1 if there are unresolved files.
5351 """
5349 """
5352
5350
5353 if opts.get('rev') and node:
5351 if opts.get('rev') and node:
5354 raise error.Abort(_("please specify just one revision"))
5352 raise error.Abort(_("please specify just one revision"))
5355 if not node:
5353 if not node:
5356 node = opts.get('rev')
5354 node = opts.get('rev')
5357
5355
5358 if node:
5356 if node:
5359 node = scmutil.revsingle(repo, node).node()
5357 node = scmutil.revsingle(repo, node).node()
5360
5358
5361 if not node:
5359 if not node:
5362 node = repo[destutil.destmerge(repo)].node()
5360 node = repo[destutil.destmerge(repo)].node()
5363
5361
5364 if opts.get('preview'):
5362 if opts.get('preview'):
5365 # find nodes that are ancestors of p2 but not of p1
5363 # find nodes that are ancestors of p2 but not of p1
5366 p1 = repo.lookup('.')
5364 p1 = repo.lookup('.')
5367 p2 = repo.lookup(node)
5365 p2 = repo.lookup(node)
5368 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5366 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5369
5367
5370 displayer = cmdutil.show_changeset(ui, repo, opts)
5368 displayer = cmdutil.show_changeset(ui, repo, opts)
5371 for node in nodes:
5369 for node in nodes:
5372 displayer.show(repo[node])
5370 displayer.show(repo[node])
5373 displayer.close()
5371 displayer.close()
5374 return 0
5372 return 0
5375
5373
5376 try:
5374 try:
5377 # ui.forcemerge is an internal variable, do not document
5375 # ui.forcemerge is an internal variable, do not document
5378 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5376 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5379 force = opts.get('force')
5377 force = opts.get('force')
5380 return hg.merge(repo, node, force=force, mergeforce=force)
5378 return hg.merge(repo, node, force=force, mergeforce=force)
5381 finally:
5379 finally:
5382 ui.setconfig('ui', 'forcemerge', '', 'merge')
5380 ui.setconfig('ui', 'forcemerge', '', 'merge')
5383
5381
5384 @command('outgoing|out',
5382 @command('outgoing|out',
5385 [('f', 'force', None, _('run even when the destination is unrelated')),
5383 [('f', 'force', None, _('run even when the destination is unrelated')),
5386 ('r', 'rev', [],
5384 ('r', 'rev', [],
5387 _('a changeset intended to be included in the destination'), _('REV')),
5385 _('a changeset intended to be included in the destination'), _('REV')),
5388 ('n', 'newest-first', None, _('show newest record first')),
5386 ('n', 'newest-first', None, _('show newest record first')),
5389 ('B', 'bookmarks', False, _('compare bookmarks')),
5387 ('B', 'bookmarks', False, _('compare bookmarks')),
5390 ('b', 'branch', [], _('a specific branch you would like to push'),
5388 ('b', 'branch', [], _('a specific branch you would like to push'),
5391 _('BRANCH')),
5389 _('BRANCH')),
5392 ] + logopts + remoteopts + subrepoopts,
5390 ] + logopts + remoteopts + subrepoopts,
5393 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5391 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5394 def outgoing(ui, repo, dest=None, **opts):
5392 def outgoing(ui, repo, dest=None, **opts):
5395 """show changesets not found in the destination
5393 """show changesets not found in the destination
5396
5394
5397 Show changesets not found in the specified destination repository
5395 Show changesets not found in the specified destination repository
5398 or the default push location. These are the changesets that would
5396 or the default push location. These are the changesets that would
5399 be pushed if a push was requested.
5397 be pushed if a push was requested.
5400
5398
5401 See pull for details of valid destination formats.
5399 See pull for details of valid destination formats.
5402
5400
5403 .. container:: verbose
5401 .. container:: verbose
5404
5402
5405 With -B/--bookmarks, the result of bookmark comparison between
5403 With -B/--bookmarks, the result of bookmark comparison between
5406 local and remote repositories is displayed. With -v/--verbose,
5404 local and remote repositories is displayed. With -v/--verbose,
5407 status is also displayed for each bookmark like below::
5405 status is also displayed for each bookmark like below::
5408
5406
5409 BM1 01234567890a added
5407 BM1 01234567890a added
5410 BM2 deleted
5408 BM2 deleted
5411 BM3 234567890abc advanced
5409 BM3 234567890abc advanced
5412 BM4 34567890abcd diverged
5410 BM4 34567890abcd diverged
5413 BM5 4567890abcde changed
5411 BM5 4567890abcde changed
5414
5412
5415 The action taken when pushing depends on the
5413 The action taken when pushing depends on the
5416 status of each bookmark:
5414 status of each bookmark:
5417
5415
5418 :``added``: push with ``-B`` will create it
5416 :``added``: push with ``-B`` will create it
5419 :``deleted``: push with ``-B`` will delete it
5417 :``deleted``: push with ``-B`` will delete it
5420 :``advanced``: push will update it
5418 :``advanced``: push will update it
5421 :``diverged``: push with ``-B`` will update it
5419 :``diverged``: push with ``-B`` will update it
5422 :``changed``: push with ``-B`` will update it
5420 :``changed``: push with ``-B`` will update it
5423
5421
5424 From the point of view of pushing behavior, bookmarks
5422 From the point of view of pushing behavior, bookmarks
5425 existing only in the remote repository are treated as
5423 existing only in the remote repository are treated as
5426 ``deleted``, even if it is in fact added remotely.
5424 ``deleted``, even if it is in fact added remotely.
5427
5425
5428 Returns 0 if there are outgoing changes, 1 otherwise.
5426 Returns 0 if there are outgoing changes, 1 otherwise.
5429 """
5427 """
5430 if opts.get('graph'):
5428 if opts.get('graph'):
5431 cmdutil.checkunsupportedgraphflags([], opts)
5429 cmdutil.checkunsupportedgraphflags([], opts)
5432 o, other = hg._outgoing(ui, repo, dest, opts)
5430 o, other = hg._outgoing(ui, repo, dest, opts)
5433 if not o:
5431 if not o:
5434 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5432 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5435 return
5433 return
5436
5434
5437 revdag = cmdutil.graphrevs(repo, o, opts)
5435 revdag = cmdutil.graphrevs(repo, o, opts)
5438 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5436 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5439 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5437 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5440 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5438 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5441 return 0
5439 return 0
5442
5440
5443 if opts.get('bookmarks'):
5441 if opts.get('bookmarks'):
5444 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5442 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5445 dest, branches = hg.parseurl(dest, opts.get('branch'))
5443 dest, branches = hg.parseurl(dest, opts.get('branch'))
5446 other = hg.peer(repo, opts, dest)
5444 other = hg.peer(repo, opts, dest)
5447 if 'bookmarks' not in other.listkeys('namespaces'):
5445 if 'bookmarks' not in other.listkeys('namespaces'):
5448 ui.warn(_("remote doesn't support bookmarks\n"))
5446 ui.warn(_("remote doesn't support bookmarks\n"))
5449 return 0
5447 return 0
5450 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5448 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5451 return bookmarks.outgoing(ui, repo, other)
5449 return bookmarks.outgoing(ui, repo, other)
5452
5450
5453 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5451 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5454 try:
5452 try:
5455 return hg.outgoing(ui, repo, dest, opts)
5453 return hg.outgoing(ui, repo, dest, opts)
5456 finally:
5454 finally:
5457 del repo._subtoppath
5455 del repo._subtoppath
5458
5456
5459 @command('parents',
5457 @command('parents',
5460 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5458 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5461 ] + templateopts,
5459 ] + templateopts,
5462 _('[-r REV] [FILE]'),
5460 _('[-r REV] [FILE]'),
5463 inferrepo=True)
5461 inferrepo=True)
5464 def parents(ui, repo, file_=None, **opts):
5462 def parents(ui, repo, file_=None, **opts):
5465 """show the parents of the working directory or revision (DEPRECATED)
5463 """show the parents of the working directory or revision (DEPRECATED)
5466
5464
5467 Print the working directory's parent revisions. If a revision is
5465 Print the working directory's parent revisions. If a revision is
5468 given via -r/--rev, the parent of that revision will be printed.
5466 given via -r/--rev, the parent of that revision will be printed.
5469 If a file argument is given, the revision in which the file was
5467 If a file argument is given, the revision in which the file was
5470 last changed (before the working directory revision or the
5468 last changed (before the working directory revision or the
5471 argument to --rev if given) is printed.
5469 argument to --rev if given) is printed.
5472
5470
5473 This command is equivalent to::
5471 This command is equivalent to::
5474
5472
5475 hg log -r "p1()+p2()" or
5473 hg log -r "p1()+p2()" or
5476 hg log -r "p1(REV)+p2(REV)" or
5474 hg log -r "p1(REV)+p2(REV)" or
5477 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5475 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5478 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5476 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5479
5477
5480 See :hg:`summary` and :hg:`help revsets` for related information.
5478 See :hg:`summary` and :hg:`help revsets` for related information.
5481
5479
5482 Returns 0 on success.
5480 Returns 0 on success.
5483 """
5481 """
5484
5482
5485 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5483 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5486
5484
5487 if file_:
5485 if file_:
5488 m = scmutil.match(ctx, (file_,), opts)
5486 m = scmutil.match(ctx, (file_,), opts)
5489 if m.anypats() or len(m.files()) != 1:
5487 if m.anypats() or len(m.files()) != 1:
5490 raise error.Abort(_('can only specify an explicit filename'))
5488 raise error.Abort(_('can only specify an explicit filename'))
5491 file_ = m.files()[0]
5489 file_ = m.files()[0]
5492 filenodes = []
5490 filenodes = []
5493 for cp in ctx.parents():
5491 for cp in ctx.parents():
5494 if not cp:
5492 if not cp:
5495 continue
5493 continue
5496 try:
5494 try:
5497 filenodes.append(cp.filenode(file_))
5495 filenodes.append(cp.filenode(file_))
5498 except error.LookupError:
5496 except error.LookupError:
5499 pass
5497 pass
5500 if not filenodes:
5498 if not filenodes:
5501 raise error.Abort(_("'%s' not found in manifest!") % file_)
5499 raise error.Abort(_("'%s' not found in manifest!") % file_)
5502 p = []
5500 p = []
5503 for fn in filenodes:
5501 for fn in filenodes:
5504 fctx = repo.filectx(file_, fileid=fn)
5502 fctx = repo.filectx(file_, fileid=fn)
5505 p.append(fctx.node())
5503 p.append(fctx.node())
5506 else:
5504 else:
5507 p = [cp.node() for cp in ctx.parents()]
5505 p = [cp.node() for cp in ctx.parents()]
5508
5506
5509 displayer = cmdutil.show_changeset(ui, repo, opts)
5507 displayer = cmdutil.show_changeset(ui, repo, opts)
5510 for n in p:
5508 for n in p:
5511 if n != nullid:
5509 if n != nullid:
5512 displayer.show(repo[n])
5510 displayer.show(repo[n])
5513 displayer.close()
5511 displayer.close()
5514
5512
5515 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5513 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5516 def paths(ui, repo, search=None, **opts):
5514 def paths(ui, repo, search=None, **opts):
5517 """show aliases for remote repositories
5515 """show aliases for remote repositories
5518
5516
5519 Show definition of symbolic path name NAME. If no name is given,
5517 Show definition of symbolic path name NAME. If no name is given,
5520 show definition of all available names.
5518 show definition of all available names.
5521
5519
5522 Option -q/--quiet suppresses all output when searching for NAME
5520 Option -q/--quiet suppresses all output when searching for NAME
5523 and shows only the path names when listing all definitions.
5521 and shows only the path names when listing all definitions.
5524
5522
5525 Path names are defined in the [paths] section of your
5523 Path names are defined in the [paths] section of your
5526 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5524 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5527 repository, ``.hg/hgrc`` is used, too.
5525 repository, ``.hg/hgrc`` is used, too.
5528
5526
5529 The path names ``default`` and ``default-push`` have a special
5527 The path names ``default`` and ``default-push`` have a special
5530 meaning. When performing a push or pull operation, they are used
5528 meaning. When performing a push or pull operation, they are used
5531 as fallbacks if no location is specified on the command-line.
5529 as fallbacks if no location is specified on the command-line.
5532 When ``default-push`` is set, it will be used for push and
5530 When ``default-push`` is set, it will be used for push and
5533 ``default`` will be used for pull; otherwise ``default`` is used
5531 ``default`` will be used for pull; otherwise ``default`` is used
5534 as the fallback for both. When cloning a repository, the clone
5532 as the fallback for both. When cloning a repository, the clone
5535 source is written as ``default`` in ``.hg/hgrc``.
5533 source is written as ``default`` in ``.hg/hgrc``.
5536
5534
5537 .. note::
5535 .. note::
5538
5536
5539 ``default`` and ``default-push`` apply to all inbound (e.g.
5537 ``default`` and ``default-push`` apply to all inbound (e.g.
5540 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5538 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5541 and :hg:`bundle`) operations.
5539 and :hg:`bundle`) operations.
5542
5540
5543 See :hg:`help urls` for more information.
5541 See :hg:`help urls` for more information.
5544
5542
5545 Returns 0 on success.
5543 Returns 0 on success.
5546 """
5544 """
5547 if search:
5545 if search:
5548 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5546 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5549 if name == search]
5547 if name == search]
5550 else:
5548 else:
5551 pathitems = sorted(ui.paths.iteritems())
5549 pathitems = sorted(ui.paths.iteritems())
5552
5550
5553 fm = ui.formatter('paths', opts)
5551 fm = ui.formatter('paths', opts)
5554 if fm:
5552 if fm:
5555 hidepassword = str
5553 hidepassword = str
5556 else:
5554 else:
5557 hidepassword = util.hidepassword
5555 hidepassword = util.hidepassword
5558 if ui.quiet:
5556 if ui.quiet:
5559 namefmt = '%s\n'
5557 namefmt = '%s\n'
5560 else:
5558 else:
5561 namefmt = '%s = '
5559 namefmt = '%s = '
5562 showsubopts = not search and not ui.quiet
5560 showsubopts = not search and not ui.quiet
5563
5561
5564 for name, path in pathitems:
5562 for name, path in pathitems:
5565 fm.startitem()
5563 fm.startitem()
5566 fm.condwrite(not search, 'name', namefmt, name)
5564 fm.condwrite(not search, 'name', namefmt, name)
5567 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5565 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5568 for subopt, value in sorted(path.suboptions.items()):
5566 for subopt, value in sorted(path.suboptions.items()):
5569 assert subopt not in ('name', 'url')
5567 assert subopt not in ('name', 'url')
5570 if showsubopts:
5568 if showsubopts:
5571 fm.plain('%s:%s = ' % (name, subopt))
5569 fm.plain('%s:%s = ' % (name, subopt))
5572 fm.condwrite(showsubopts, subopt, '%s\n', value)
5570 fm.condwrite(showsubopts, subopt, '%s\n', value)
5573
5571
5574 fm.end()
5572 fm.end()
5575
5573
5576 if search and not pathitems:
5574 if search and not pathitems:
5577 if not ui.quiet:
5575 if not ui.quiet:
5578 ui.warn(_("not found!\n"))
5576 ui.warn(_("not found!\n"))
5579 return 1
5577 return 1
5580 else:
5578 else:
5581 return 0
5579 return 0
5582
5580
5583 @command('phase',
5581 @command('phase',
5584 [('p', 'public', False, _('set changeset phase to public')),
5582 [('p', 'public', False, _('set changeset phase to public')),
5585 ('d', 'draft', False, _('set changeset phase to draft')),
5583 ('d', 'draft', False, _('set changeset phase to draft')),
5586 ('s', 'secret', False, _('set changeset phase to secret')),
5584 ('s', 'secret', False, _('set changeset phase to secret')),
5587 ('f', 'force', False, _('allow to move boundary backward')),
5585 ('f', 'force', False, _('allow to move boundary backward')),
5588 ('r', 'rev', [], _('target revision'), _('REV')),
5586 ('r', 'rev', [], _('target revision'), _('REV')),
5589 ],
5587 ],
5590 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5588 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5591 def phase(ui, repo, *revs, **opts):
5589 def phase(ui, repo, *revs, **opts):
5592 """set or show the current phase name
5590 """set or show the current phase name
5593
5591
5594 With no argument, show the phase name of the current revision(s).
5592 With no argument, show the phase name of the current revision(s).
5595
5593
5596 With one of -p/--public, -d/--draft or -s/--secret, change the
5594 With one of -p/--public, -d/--draft or -s/--secret, change the
5597 phase value of the specified revisions.
5595 phase value of the specified revisions.
5598
5596
5599 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5597 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5600 lower phase to an higher phase. Phases are ordered as follows::
5598 lower phase to an higher phase. Phases are ordered as follows::
5601
5599
5602 public < draft < secret
5600 public < draft < secret
5603
5601
5604 Returns 0 on success, 1 if some phases could not be changed.
5602 Returns 0 on success, 1 if some phases could not be changed.
5605
5603
5606 (For more information about the phases concept, see :hg:`help phases`.)
5604 (For more information about the phases concept, see :hg:`help phases`.)
5607 """
5605 """
5608 # search for a unique phase argument
5606 # search for a unique phase argument
5609 targetphase = None
5607 targetphase = None
5610 for idx, name in enumerate(phases.phasenames):
5608 for idx, name in enumerate(phases.phasenames):
5611 if opts[name]:
5609 if opts[name]:
5612 if targetphase is not None:
5610 if targetphase is not None:
5613 raise error.Abort(_('only one phase can be specified'))
5611 raise error.Abort(_('only one phase can be specified'))
5614 targetphase = idx
5612 targetphase = idx
5615
5613
5616 # look for specified revision
5614 # look for specified revision
5617 revs = list(revs)
5615 revs = list(revs)
5618 revs.extend(opts['rev'])
5616 revs.extend(opts['rev'])
5619 if not revs:
5617 if not revs:
5620 # display both parents as the second parent phase can influence
5618 # display both parents as the second parent phase can influence
5621 # the phase of a merge commit
5619 # the phase of a merge commit
5622 revs = [c.rev() for c in repo[None].parents()]
5620 revs = [c.rev() for c in repo[None].parents()]
5623
5621
5624 revs = scmutil.revrange(repo, revs)
5622 revs = scmutil.revrange(repo, revs)
5625
5623
5626 lock = None
5624 lock = None
5627 ret = 0
5625 ret = 0
5628 if targetphase is None:
5626 if targetphase is None:
5629 # display
5627 # display
5630 for r in revs:
5628 for r in revs:
5631 ctx = repo[r]
5629 ctx = repo[r]
5632 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5630 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5633 else:
5631 else:
5634 tr = None
5632 tr = None
5635 lock = repo.lock()
5633 lock = repo.lock()
5636 try:
5634 try:
5637 tr = repo.transaction("phase")
5635 tr = repo.transaction("phase")
5638 # set phase
5636 # set phase
5639 if not revs:
5637 if not revs:
5640 raise error.Abort(_('empty revision set'))
5638 raise error.Abort(_('empty revision set'))
5641 nodes = [repo[r].node() for r in revs]
5639 nodes = [repo[r].node() for r in revs]
5642 # moving revision from public to draft may hide them
5640 # moving revision from public to draft may hide them
5643 # We have to check result on an unfiltered repository
5641 # We have to check result on an unfiltered repository
5644 unfi = repo.unfiltered()
5642 unfi = repo.unfiltered()
5645 getphase = unfi._phasecache.phase
5643 getphase = unfi._phasecache.phase
5646 olddata = [getphase(unfi, r) for r in unfi]
5644 olddata = [getphase(unfi, r) for r in unfi]
5647 phases.advanceboundary(repo, tr, targetphase, nodes)
5645 phases.advanceboundary(repo, tr, targetphase, nodes)
5648 if opts['force']:
5646 if opts['force']:
5649 phases.retractboundary(repo, tr, targetphase, nodes)
5647 phases.retractboundary(repo, tr, targetphase, nodes)
5650 tr.close()
5648 tr.close()
5651 finally:
5649 finally:
5652 if tr is not None:
5650 if tr is not None:
5653 tr.release()
5651 tr.release()
5654 lock.release()
5652 lock.release()
5655 getphase = unfi._phasecache.phase
5653 getphase = unfi._phasecache.phase
5656 newdata = [getphase(unfi, r) for r in unfi]
5654 newdata = [getphase(unfi, r) for r in unfi]
5657 changes = sum(newdata[r] != olddata[r] for r in unfi)
5655 changes = sum(newdata[r] != olddata[r] for r in unfi)
5658 cl = unfi.changelog
5656 cl = unfi.changelog
5659 rejected = [n for n in nodes
5657 rejected = [n for n in nodes
5660 if newdata[cl.rev(n)] < targetphase]
5658 if newdata[cl.rev(n)] < targetphase]
5661 if rejected:
5659 if rejected:
5662 ui.warn(_('cannot move %i changesets to a higher '
5660 ui.warn(_('cannot move %i changesets to a higher '
5663 'phase, use --force\n') % len(rejected))
5661 'phase, use --force\n') % len(rejected))
5664 ret = 1
5662 ret = 1
5665 if changes:
5663 if changes:
5666 msg = _('phase changed for %i changesets\n') % changes
5664 msg = _('phase changed for %i changesets\n') % changes
5667 if ret:
5665 if ret:
5668 ui.status(msg)
5666 ui.status(msg)
5669 else:
5667 else:
5670 ui.note(msg)
5668 ui.note(msg)
5671 else:
5669 else:
5672 ui.warn(_('no phases changed\n'))
5670 ui.warn(_('no phases changed\n'))
5673 return ret
5671 return ret
5674
5672
5675 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5673 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5676 """Run after a changegroup has been added via pull/unbundle
5674 """Run after a changegroup has been added via pull/unbundle
5677
5675
5678 This takes arguments below:
5676 This takes arguments below:
5679
5677
5680 :modheads: change of heads by pull/unbundle
5678 :modheads: change of heads by pull/unbundle
5681 :optupdate: updating working directory is needed or not
5679 :optupdate: updating working directory is needed or not
5682 :checkout: update destination revision (or None to default destination)
5680 :checkout: update destination revision (or None to default destination)
5683 :brev: a name, which might be a bookmark to be activated after updating
5681 :brev: a name, which might be a bookmark to be activated after updating
5684 """
5682 """
5685 if modheads == 0:
5683 if modheads == 0:
5686 return
5684 return
5687 if optupdate:
5685 if optupdate:
5688 try:
5686 try:
5689 return hg.updatetotally(ui, repo, checkout, brev)
5687 return hg.updatetotally(ui, repo, checkout, brev)
5690 except error.UpdateAbort as inst:
5688 except error.UpdateAbort as inst:
5691 msg = _("not updating: %s") % str(inst)
5689 msg = _("not updating: %s") % str(inst)
5692 hint = inst.hint
5690 hint = inst.hint
5693 raise error.UpdateAbort(msg, hint=hint)
5691 raise error.UpdateAbort(msg, hint=hint)
5694 if modheads > 1:
5692 if modheads > 1:
5695 currentbranchheads = len(repo.branchheads())
5693 currentbranchheads = len(repo.branchheads())
5696 if currentbranchheads == modheads:
5694 if currentbranchheads == modheads:
5697 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5695 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5698 elif currentbranchheads > 1:
5696 elif currentbranchheads > 1:
5699 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5697 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5700 "merge)\n"))
5698 "merge)\n"))
5701 else:
5699 else:
5702 ui.status(_("(run 'hg heads' to see heads)\n"))
5700 ui.status(_("(run 'hg heads' to see heads)\n"))
5703 else:
5701 else:
5704 ui.status(_("(run 'hg update' to get a working copy)\n"))
5702 ui.status(_("(run 'hg update' to get a working copy)\n"))
5705
5703
5706 @command('^pull',
5704 @command('^pull',
5707 [('u', 'update', None,
5705 [('u', 'update', None,
5708 _('update to new branch head if changesets were pulled')),
5706 _('update to new branch head if changesets were pulled')),
5709 ('f', 'force', None, _('run even when remote repository is unrelated')),
5707 ('f', 'force', None, _('run even when remote repository is unrelated')),
5710 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5708 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5711 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5709 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5712 ('b', 'branch', [], _('a specific branch you would like to pull'),
5710 ('b', 'branch', [], _('a specific branch you would like to pull'),
5713 _('BRANCH')),
5711 _('BRANCH')),
5714 ] + remoteopts,
5712 ] + remoteopts,
5715 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5713 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5716 def pull(ui, repo, source="default", **opts):
5714 def pull(ui, repo, source="default", **opts):
5717 """pull changes from the specified source
5715 """pull changes from the specified source
5718
5716
5719 Pull changes from a remote repository to a local one.
5717 Pull changes from a remote repository to a local one.
5720
5718
5721 This finds all changes from the repository at the specified path
5719 This finds all changes from the repository at the specified path
5722 or URL and adds them to a local repository (the current one unless
5720 or URL and adds them to a local repository (the current one unless
5723 -R is specified). By default, this does not update the copy of the
5721 -R is specified). By default, this does not update the copy of the
5724 project in the working directory.
5722 project in the working directory.
5725
5723
5726 Use :hg:`incoming` if you want to see what would have been added
5724 Use :hg:`incoming` if you want to see what would have been added
5727 by a pull at the time you issued this command. If you then decide
5725 by a pull at the time you issued this command. If you then decide
5728 to add those changes to the repository, you should use :hg:`pull
5726 to add those changes to the repository, you should use :hg:`pull
5729 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5727 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5730
5728
5731 If SOURCE is omitted, the 'default' path will be used.
5729 If SOURCE is omitted, the 'default' path will be used.
5732 See :hg:`help urls` for more information.
5730 See :hg:`help urls` for more information.
5733
5731
5734 Returns 0 on success, 1 if an update had unresolved files.
5732 Returns 0 on success, 1 if an update had unresolved files.
5735 """
5733 """
5736 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5734 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5737 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5735 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5738 other = hg.peer(repo, opts, source)
5736 other = hg.peer(repo, opts, source)
5739 try:
5737 try:
5740 revs, checkout = hg.addbranchrevs(repo, other, branches,
5738 revs, checkout = hg.addbranchrevs(repo, other, branches,
5741 opts.get('rev'))
5739 opts.get('rev'))
5742
5740
5743
5741
5744 pullopargs = {}
5742 pullopargs = {}
5745 if opts.get('bookmark'):
5743 if opts.get('bookmark'):
5746 if not revs:
5744 if not revs:
5747 revs = []
5745 revs = []
5748 # The list of bookmark used here is not the one used to actually
5746 # The list of bookmark used here is not the one used to actually
5749 # update the bookmark name. This can result in the revision pulled
5747 # update the bookmark name. This can result in the revision pulled
5750 # not ending up with the name of the bookmark because of a race
5748 # not ending up with the name of the bookmark because of a race
5751 # condition on the server. (See issue 4689 for details)
5749 # condition on the server. (See issue 4689 for details)
5752 remotebookmarks = other.listkeys('bookmarks')
5750 remotebookmarks = other.listkeys('bookmarks')
5753 pullopargs['remotebookmarks'] = remotebookmarks
5751 pullopargs['remotebookmarks'] = remotebookmarks
5754 for b in opts['bookmark']:
5752 for b in opts['bookmark']:
5755 if b not in remotebookmarks:
5753 if b not in remotebookmarks:
5756 raise error.Abort(_('remote bookmark %s not found!') % b)
5754 raise error.Abort(_('remote bookmark %s not found!') % b)
5757 revs.append(remotebookmarks[b])
5755 revs.append(remotebookmarks[b])
5758
5756
5759 if revs:
5757 if revs:
5760 try:
5758 try:
5761 # When 'rev' is a bookmark name, we cannot guarantee that it
5759 # When 'rev' is a bookmark name, we cannot guarantee that it
5762 # will be updated with that name because of a race condition
5760 # will be updated with that name because of a race condition
5763 # server side. (See issue 4689 for details)
5761 # server side. (See issue 4689 for details)
5764 oldrevs = revs
5762 oldrevs = revs
5765 revs = [] # actually, nodes
5763 revs = [] # actually, nodes
5766 for r in oldrevs:
5764 for r in oldrevs:
5767 node = other.lookup(r)
5765 node = other.lookup(r)
5768 revs.append(node)
5766 revs.append(node)
5769 if r == checkout:
5767 if r == checkout:
5770 checkout = node
5768 checkout = node
5771 except error.CapabilityError:
5769 except error.CapabilityError:
5772 err = _("other repository doesn't support revision lookup, "
5770 err = _("other repository doesn't support revision lookup, "
5773 "so a rev cannot be specified.")
5771 "so a rev cannot be specified.")
5774 raise error.Abort(err)
5772 raise error.Abort(err)
5775
5773
5776 pullopargs.update(opts.get('opargs', {}))
5774 pullopargs.update(opts.get('opargs', {}))
5777 modheads = exchange.pull(repo, other, heads=revs,
5775 modheads = exchange.pull(repo, other, heads=revs,
5778 force=opts.get('force'),
5776 force=opts.get('force'),
5779 bookmarks=opts.get('bookmark', ()),
5777 bookmarks=opts.get('bookmark', ()),
5780 opargs=pullopargs).cgresult
5778 opargs=pullopargs).cgresult
5781
5779
5782 # brev is a name, which might be a bookmark to be activated at
5780 # brev is a name, which might be a bookmark to be activated at
5783 # the end of the update. In other words, it is an explicit
5781 # the end of the update. In other words, it is an explicit
5784 # destination of the update
5782 # destination of the update
5785 brev = None
5783 brev = None
5786
5784
5787 if checkout:
5785 if checkout:
5788 checkout = str(repo.changelog.rev(checkout))
5786 checkout = str(repo.changelog.rev(checkout))
5789
5787
5790 # order below depends on implementation of
5788 # order below depends on implementation of
5791 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5789 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5792 # because 'checkout' is determined without it.
5790 # because 'checkout' is determined without it.
5793 if opts.get('rev'):
5791 if opts.get('rev'):
5794 brev = opts['rev'][0]
5792 brev = opts['rev'][0]
5795 elif opts.get('branch'):
5793 elif opts.get('branch'):
5796 brev = opts['branch'][0]
5794 brev = opts['branch'][0]
5797 else:
5795 else:
5798 brev = branches[0]
5796 brev = branches[0]
5799 repo._subtoppath = source
5797 repo._subtoppath = source
5800 try:
5798 try:
5801 ret = postincoming(ui, repo, modheads, opts.get('update'),
5799 ret = postincoming(ui, repo, modheads, opts.get('update'),
5802 checkout, brev)
5800 checkout, brev)
5803
5801
5804 finally:
5802 finally:
5805 del repo._subtoppath
5803 del repo._subtoppath
5806
5804
5807 finally:
5805 finally:
5808 other.close()
5806 other.close()
5809 return ret
5807 return ret
5810
5808
5811 @command('^push',
5809 @command('^push',
5812 [('f', 'force', None, _('force push')),
5810 [('f', 'force', None, _('force push')),
5813 ('r', 'rev', [],
5811 ('r', 'rev', [],
5814 _('a changeset intended to be included in the destination'),
5812 _('a changeset intended to be included in the destination'),
5815 _('REV')),
5813 _('REV')),
5816 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5814 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5817 ('b', 'branch', [],
5815 ('b', 'branch', [],
5818 _('a specific branch you would like to push'), _('BRANCH')),
5816 _('a specific branch you would like to push'), _('BRANCH')),
5819 ('', 'new-branch', False, _('allow pushing a new branch')),
5817 ('', 'new-branch', False, _('allow pushing a new branch')),
5820 ] + remoteopts,
5818 ] + remoteopts,
5821 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5819 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5822 def push(ui, repo, dest=None, **opts):
5820 def push(ui, repo, dest=None, **opts):
5823 """push changes to the specified destination
5821 """push changes to the specified destination
5824
5822
5825 Push changesets from the local repository to the specified
5823 Push changesets from the local repository to the specified
5826 destination.
5824 destination.
5827
5825
5828 This operation is symmetrical to pull: it is identical to a pull
5826 This operation is symmetrical to pull: it is identical to a pull
5829 in the destination repository from the current one.
5827 in the destination repository from the current one.
5830
5828
5831 By default, push will not allow creation of new heads at the
5829 By default, push will not allow creation of new heads at the
5832 destination, since multiple heads would make it unclear which head
5830 destination, since multiple heads would make it unclear which head
5833 to use. In this situation, it is recommended to pull and merge
5831 to use. In this situation, it is recommended to pull and merge
5834 before pushing.
5832 before pushing.
5835
5833
5836 Use --new-branch if you want to allow push to create a new named
5834 Use --new-branch if you want to allow push to create a new named
5837 branch that is not present at the destination. This allows you to
5835 branch that is not present at the destination. This allows you to
5838 only create a new branch without forcing other changes.
5836 only create a new branch without forcing other changes.
5839
5837
5840 .. note::
5838 .. note::
5841
5839
5842 Extra care should be taken with the -f/--force option,
5840 Extra care should be taken with the -f/--force option,
5843 which will push all new heads on all branches, an action which will
5841 which will push all new heads on all branches, an action which will
5844 almost always cause confusion for collaborators.
5842 almost always cause confusion for collaborators.
5845
5843
5846 If -r/--rev is used, the specified revision and all its ancestors
5844 If -r/--rev is used, the specified revision and all its ancestors
5847 will be pushed to the remote repository.
5845 will be pushed to the remote repository.
5848
5846
5849 If -B/--bookmark is used, the specified bookmarked revision, its
5847 If -B/--bookmark is used, the specified bookmarked revision, its
5850 ancestors, and the bookmark will be pushed to the remote
5848 ancestors, and the bookmark will be pushed to the remote
5851 repository. Specifying ``.`` is equivalent to specifying the active
5849 repository. Specifying ``.`` is equivalent to specifying the active
5852 bookmark's name.
5850 bookmark's name.
5853
5851
5854 Please see :hg:`help urls` for important details about ``ssh://``
5852 Please see :hg:`help urls` for important details about ``ssh://``
5855 URLs. If DESTINATION is omitted, a default path will be used.
5853 URLs. If DESTINATION is omitted, a default path will be used.
5856
5854
5857 Returns 0 if push was successful, 1 if nothing to push.
5855 Returns 0 if push was successful, 1 if nothing to push.
5858 """
5856 """
5859
5857
5860 if opts.get('bookmark'):
5858 if opts.get('bookmark'):
5861 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5859 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5862 for b in opts['bookmark']:
5860 for b in opts['bookmark']:
5863 # translate -B options to -r so changesets get pushed
5861 # translate -B options to -r so changesets get pushed
5864 b = repo._bookmarks.expandname(b)
5862 b = repo._bookmarks.expandname(b)
5865 if b in repo._bookmarks:
5863 if b in repo._bookmarks:
5866 opts.setdefault('rev', []).append(b)
5864 opts.setdefault('rev', []).append(b)
5867 else:
5865 else:
5868 # if we try to push a deleted bookmark, translate it to null
5866 # if we try to push a deleted bookmark, translate it to null
5869 # this lets simultaneous -r, -b options continue working
5867 # this lets simultaneous -r, -b options continue working
5870 opts.setdefault('rev', []).append("null")
5868 opts.setdefault('rev', []).append("null")
5871
5869
5872 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5870 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5873 if not path:
5871 if not path:
5874 raise error.Abort(_('default repository not configured!'),
5872 raise error.Abort(_('default repository not configured!'),
5875 hint=_('see the "path" section in "hg help config"'))
5873 hint=_('see the "path" section in "hg help config"'))
5876 dest = path.pushloc or path.loc
5874 dest = path.pushloc or path.loc
5877 branches = (path.branch, opts.get('branch') or [])
5875 branches = (path.branch, opts.get('branch') or [])
5878 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5876 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5879 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5877 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5880 other = hg.peer(repo, opts, dest)
5878 other = hg.peer(repo, opts, dest)
5881
5879
5882 if revs:
5880 if revs:
5883 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5881 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5884 if not revs:
5882 if not revs:
5885 raise error.Abort(_("specified revisions evaluate to an empty set"),
5883 raise error.Abort(_("specified revisions evaluate to an empty set"),
5886 hint=_("use different revision arguments"))
5884 hint=_("use different revision arguments"))
5887
5885
5888 repo._subtoppath = dest
5886 repo._subtoppath = dest
5889 try:
5887 try:
5890 # push subrepos depth-first for coherent ordering
5888 # push subrepos depth-first for coherent ordering
5891 c = repo['']
5889 c = repo['']
5892 subs = c.substate # only repos that are committed
5890 subs = c.substate # only repos that are committed
5893 for s in sorted(subs):
5891 for s in sorted(subs):
5894 result = c.sub(s).push(opts)
5892 result = c.sub(s).push(opts)
5895 if result == 0:
5893 if result == 0:
5896 return not result
5894 return not result
5897 finally:
5895 finally:
5898 del repo._subtoppath
5896 del repo._subtoppath
5899 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5897 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5900 newbranch=opts.get('new_branch'),
5898 newbranch=opts.get('new_branch'),
5901 bookmarks=opts.get('bookmark', ()),
5899 bookmarks=opts.get('bookmark', ()),
5902 opargs=opts.get('opargs'))
5900 opargs=opts.get('opargs'))
5903
5901
5904 result = not pushop.cgresult
5902 result = not pushop.cgresult
5905
5903
5906 if pushop.bkresult is not None:
5904 if pushop.bkresult is not None:
5907 if pushop.bkresult == 2:
5905 if pushop.bkresult == 2:
5908 result = 2
5906 result = 2
5909 elif not result and pushop.bkresult:
5907 elif not result and pushop.bkresult:
5910 result = 2
5908 result = 2
5911
5909
5912 return result
5910 return result
5913
5911
5914 @command('recover', [])
5912 @command('recover', [])
5915 def recover(ui, repo):
5913 def recover(ui, repo):
5916 """roll back an interrupted transaction
5914 """roll back an interrupted transaction
5917
5915
5918 Recover from an interrupted commit or pull.
5916 Recover from an interrupted commit or pull.
5919
5917
5920 This command tries to fix the repository status after an
5918 This command tries to fix the repository status after an
5921 interrupted operation. It should only be necessary when Mercurial
5919 interrupted operation. It should only be necessary when Mercurial
5922 suggests it.
5920 suggests it.
5923
5921
5924 Returns 0 if successful, 1 if nothing to recover or verify fails.
5922 Returns 0 if successful, 1 if nothing to recover or verify fails.
5925 """
5923 """
5926 if repo.recover():
5924 if repo.recover():
5927 return hg.verify(repo)
5925 return hg.verify(repo)
5928 return 1
5926 return 1
5929
5927
5930 @command('^remove|rm',
5928 @command('^remove|rm',
5931 [('A', 'after', None, _('record delete for missing files')),
5929 [('A', 'after', None, _('record delete for missing files')),
5932 ('f', 'force', None,
5930 ('f', 'force', None,
5933 _('remove (and delete) file even if added or modified')),
5931 _('remove (and delete) file even if added or modified')),
5934 ] + subrepoopts + walkopts,
5932 ] + subrepoopts + walkopts,
5935 _('[OPTION]... FILE...'),
5933 _('[OPTION]... FILE...'),
5936 inferrepo=True)
5934 inferrepo=True)
5937 def remove(ui, repo, *pats, **opts):
5935 def remove(ui, repo, *pats, **opts):
5938 """remove the specified files on the next commit
5936 """remove the specified files on the next commit
5939
5937
5940 Schedule the indicated files for removal from the current branch.
5938 Schedule the indicated files for removal from the current branch.
5941
5939
5942 This command schedules the files to be removed at the next commit.
5940 This command schedules the files to be removed at the next commit.
5943 To undo a remove before that, see :hg:`revert`. To undo added
5941 To undo a remove before that, see :hg:`revert`. To undo added
5944 files, see :hg:`forget`.
5942 files, see :hg:`forget`.
5945
5943
5946 .. container:: verbose
5944 .. container:: verbose
5947
5945
5948 -A/--after can be used to remove only files that have already
5946 -A/--after can be used to remove only files that have already
5949 been deleted, -f/--force can be used to force deletion, and -Af
5947 been deleted, -f/--force can be used to force deletion, and -Af
5950 can be used to remove files from the next revision without
5948 can be used to remove files from the next revision without
5951 deleting them from the working directory.
5949 deleting them from the working directory.
5952
5950
5953 The following table details the behavior of remove for different
5951 The following table details the behavior of remove for different
5954 file states (columns) and option combinations (rows). The file
5952 file states (columns) and option combinations (rows). The file
5955 states are Added [A], Clean [C], Modified [M] and Missing [!]
5953 states are Added [A], Clean [C], Modified [M] and Missing [!]
5956 (as reported by :hg:`status`). The actions are Warn, Remove
5954 (as reported by :hg:`status`). The actions are Warn, Remove
5957 (from branch) and Delete (from disk):
5955 (from branch) and Delete (from disk):
5958
5956
5959 ========= == == == ==
5957 ========= == == == ==
5960 opt/state A C M !
5958 opt/state A C M !
5961 ========= == == == ==
5959 ========= == == == ==
5962 none W RD W R
5960 none W RD W R
5963 -f R RD RD R
5961 -f R RD RD R
5964 -A W W W R
5962 -A W W W R
5965 -Af R R R R
5963 -Af R R R R
5966 ========= == == == ==
5964 ========= == == == ==
5967
5965
5968 .. note::
5966 .. note::
5969
5967
5970 :hg:`remove` never deletes files in Added [A] state from the
5968 :hg:`remove` never deletes files in Added [A] state from the
5971 working directory, not even if ``--force`` is specified.
5969 working directory, not even if ``--force`` is specified.
5972
5970
5973 Returns 0 on success, 1 if any warnings encountered.
5971 Returns 0 on success, 1 if any warnings encountered.
5974 """
5972 """
5975
5973
5976 after, force = opts.get('after'), opts.get('force')
5974 after, force = opts.get('after'), opts.get('force')
5977 if not pats and not after:
5975 if not pats and not after:
5978 raise error.Abort(_('no files specified'))
5976 raise error.Abort(_('no files specified'))
5979
5977
5980 m = scmutil.match(repo[None], pats, opts)
5978 m = scmutil.match(repo[None], pats, opts)
5981 subrepos = opts.get('subrepos')
5979 subrepos = opts.get('subrepos')
5982 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5980 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5983
5981
5984 @command('rename|move|mv',
5982 @command('rename|move|mv',
5985 [('A', 'after', None, _('record a rename that has already occurred')),
5983 [('A', 'after', None, _('record a rename that has already occurred')),
5986 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5984 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5987 ] + walkopts + dryrunopts,
5985 ] + walkopts + dryrunopts,
5988 _('[OPTION]... SOURCE... DEST'))
5986 _('[OPTION]... SOURCE... DEST'))
5989 def rename(ui, repo, *pats, **opts):
5987 def rename(ui, repo, *pats, **opts):
5990 """rename files; equivalent of copy + remove
5988 """rename files; equivalent of copy + remove
5991
5989
5992 Mark dest as copies of sources; mark sources for deletion. If dest
5990 Mark dest as copies of sources; mark sources for deletion. If dest
5993 is a directory, copies are put in that directory. If dest is a
5991 is a directory, copies are put in that directory. If dest is a
5994 file, there can only be one source.
5992 file, there can only be one source.
5995
5993
5996 By default, this command copies the contents of files as they
5994 By default, this command copies the contents of files as they
5997 exist in the working directory. If invoked with -A/--after, the
5995 exist in the working directory. If invoked with -A/--after, the
5998 operation is recorded, but no copying is performed.
5996 operation is recorded, but no copying is performed.
5999
5997
6000 This command takes effect at the next commit. To undo a rename
5998 This command takes effect at the next commit. To undo a rename
6001 before that, see :hg:`revert`.
5999 before that, see :hg:`revert`.
6002
6000
6003 Returns 0 on success, 1 if errors are encountered.
6001 Returns 0 on success, 1 if errors are encountered.
6004 """
6002 """
6005 with repo.wlock(False):
6003 with repo.wlock(False):
6006 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6004 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6007
6005
6008 @command('resolve',
6006 @command('resolve',
6009 [('a', 'all', None, _('select all unresolved files')),
6007 [('a', 'all', None, _('select all unresolved files')),
6010 ('l', 'list', None, _('list state of files needing merge')),
6008 ('l', 'list', None, _('list state of files needing merge')),
6011 ('m', 'mark', None, _('mark files as resolved')),
6009 ('m', 'mark', None, _('mark files as resolved')),
6012 ('u', 'unmark', None, _('mark files as unresolved')),
6010 ('u', 'unmark', None, _('mark files as unresolved')),
6013 ('n', 'no-status', None, _('hide status prefix'))]
6011 ('n', 'no-status', None, _('hide status prefix'))]
6014 + mergetoolopts + walkopts + formatteropts,
6012 + mergetoolopts + walkopts + formatteropts,
6015 _('[OPTION]... [FILE]...'),
6013 _('[OPTION]... [FILE]...'),
6016 inferrepo=True)
6014 inferrepo=True)
6017 def resolve(ui, repo, *pats, **opts):
6015 def resolve(ui, repo, *pats, **opts):
6018 """redo merges or set/view the merge status of files
6016 """redo merges or set/view the merge status of files
6019
6017
6020 Merges with unresolved conflicts are often the result of
6018 Merges with unresolved conflicts are often the result of
6021 non-interactive merging using the ``internal:merge`` configuration
6019 non-interactive merging using the ``internal:merge`` configuration
6022 setting, or a command-line merge tool like ``diff3``. The resolve
6020 setting, or a command-line merge tool like ``diff3``. The resolve
6023 command is used to manage the files involved in a merge, after
6021 command is used to manage the files involved in a merge, after
6024 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6022 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6025 working directory must have two parents). See :hg:`help
6023 working directory must have two parents). See :hg:`help
6026 merge-tools` for information on configuring merge tools.
6024 merge-tools` for information on configuring merge tools.
6027
6025
6028 The resolve command can be used in the following ways:
6026 The resolve command can be used in the following ways:
6029
6027
6030 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6028 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6031 files, discarding any previous merge attempts. Re-merging is not
6029 files, discarding any previous merge attempts. Re-merging is not
6032 performed for files already marked as resolved. Use ``--all/-a``
6030 performed for files already marked as resolved. Use ``--all/-a``
6033 to select all unresolved files. ``--tool`` can be used to specify
6031 to select all unresolved files. ``--tool`` can be used to specify
6034 the merge tool used for the given files. It overrides the HGMERGE
6032 the merge tool used for the given files. It overrides the HGMERGE
6035 environment variable and your configuration files. Previous file
6033 environment variable and your configuration files. Previous file
6036 contents are saved with a ``.orig`` suffix.
6034 contents are saved with a ``.orig`` suffix.
6037
6035
6038 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6036 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6039 (e.g. after having manually fixed-up the files). The default is
6037 (e.g. after having manually fixed-up the files). The default is
6040 to mark all unresolved files.
6038 to mark all unresolved files.
6041
6039
6042 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6040 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6043 default is to mark all resolved files.
6041 default is to mark all resolved files.
6044
6042
6045 - :hg:`resolve -l`: list files which had or still have conflicts.
6043 - :hg:`resolve -l`: list files which had or still have conflicts.
6046 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6044 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6047
6045
6048 .. note::
6046 .. note::
6049
6047
6050 Mercurial will not let you commit files with unresolved merge
6048 Mercurial will not let you commit files with unresolved merge
6051 conflicts. You must use :hg:`resolve -m ...` before you can
6049 conflicts. You must use :hg:`resolve -m ...` before you can
6052 commit after a conflicting merge.
6050 commit after a conflicting merge.
6053
6051
6054 Returns 0 on success, 1 if any files fail a resolve attempt.
6052 Returns 0 on success, 1 if any files fail a resolve attempt.
6055 """
6053 """
6056
6054
6057 flaglist = 'all mark unmark list no_status'.split()
6055 flaglist = 'all mark unmark list no_status'.split()
6058 all, mark, unmark, show, nostatus = \
6056 all, mark, unmark, show, nostatus = \
6059 [opts.get(o) for o in flaglist]
6057 [opts.get(o) for o in flaglist]
6060
6058
6061 if (show and (mark or unmark)) or (mark and unmark):
6059 if (show and (mark or unmark)) or (mark and unmark):
6062 raise error.Abort(_("too many options specified"))
6060 raise error.Abort(_("too many options specified"))
6063 if pats and all:
6061 if pats and all:
6064 raise error.Abort(_("can't specify --all and patterns"))
6062 raise error.Abort(_("can't specify --all and patterns"))
6065 if not (all or pats or show or mark or unmark):
6063 if not (all or pats or show or mark or unmark):
6066 raise error.Abort(_('no files or directories specified'),
6064 raise error.Abort(_('no files or directories specified'),
6067 hint=('use --all to re-merge all unresolved files'))
6065 hint=('use --all to re-merge all unresolved files'))
6068
6066
6069 if show:
6067 if show:
6070 fm = ui.formatter('resolve', opts)
6068 fm = ui.formatter('resolve', opts)
6071 ms = mergemod.mergestate.read(repo)
6069 ms = mergemod.mergestate.read(repo)
6072 m = scmutil.match(repo[None], pats, opts)
6070 m = scmutil.match(repo[None], pats, opts)
6073 for f in ms:
6071 for f in ms:
6074 if not m(f):
6072 if not m(f):
6075 continue
6073 continue
6076 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6074 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6077 'd': 'driverresolved'}[ms[f]]
6075 'd': 'driverresolved'}[ms[f]]
6078 fm.startitem()
6076 fm.startitem()
6079 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6077 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6080 fm.write('path', '%s\n', f, label=l)
6078 fm.write('path', '%s\n', f, label=l)
6081 fm.end()
6079 fm.end()
6082 return 0
6080 return 0
6083
6081
6084 with repo.wlock():
6082 with repo.wlock():
6085 ms = mergemod.mergestate.read(repo)
6083 ms = mergemod.mergestate.read(repo)
6086
6084
6087 if not (ms.active() or repo.dirstate.p2() != nullid):
6085 if not (ms.active() or repo.dirstate.p2() != nullid):
6088 raise error.Abort(
6086 raise error.Abort(
6089 _('resolve command not applicable when not merging'))
6087 _('resolve command not applicable when not merging'))
6090
6088
6091 wctx = repo[None]
6089 wctx = repo[None]
6092
6090
6093 if ms.mergedriver and ms.mdstate() == 'u':
6091 if ms.mergedriver and ms.mdstate() == 'u':
6094 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6092 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6095 ms.commit()
6093 ms.commit()
6096 # allow mark and unmark to go through
6094 # allow mark and unmark to go through
6097 if not mark and not unmark and not proceed:
6095 if not mark and not unmark and not proceed:
6098 return 1
6096 return 1
6099
6097
6100 m = scmutil.match(wctx, pats, opts)
6098 m = scmutil.match(wctx, pats, opts)
6101 ret = 0
6099 ret = 0
6102 didwork = False
6100 didwork = False
6103 runconclude = False
6101 runconclude = False
6104
6102
6105 tocomplete = []
6103 tocomplete = []
6106 for f in ms:
6104 for f in ms:
6107 if not m(f):
6105 if not m(f):
6108 continue
6106 continue
6109
6107
6110 didwork = True
6108 didwork = True
6111
6109
6112 # don't let driver-resolved files be marked, and run the conclude
6110 # don't let driver-resolved files be marked, and run the conclude
6113 # step if asked to resolve
6111 # step if asked to resolve
6114 if ms[f] == "d":
6112 if ms[f] == "d":
6115 exact = m.exact(f)
6113 exact = m.exact(f)
6116 if mark:
6114 if mark:
6117 if exact:
6115 if exact:
6118 ui.warn(_('not marking %s as it is driver-resolved\n')
6116 ui.warn(_('not marking %s as it is driver-resolved\n')
6119 % f)
6117 % f)
6120 elif unmark:
6118 elif unmark:
6121 if exact:
6119 if exact:
6122 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6120 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6123 % f)
6121 % f)
6124 else:
6122 else:
6125 runconclude = True
6123 runconclude = True
6126 continue
6124 continue
6127
6125
6128 if mark:
6126 if mark:
6129 ms.mark(f, "r")
6127 ms.mark(f, "r")
6130 elif unmark:
6128 elif unmark:
6131 ms.mark(f, "u")
6129 ms.mark(f, "u")
6132 else:
6130 else:
6133 # backup pre-resolve (merge uses .orig for its own purposes)
6131 # backup pre-resolve (merge uses .orig for its own purposes)
6134 a = repo.wjoin(f)
6132 a = repo.wjoin(f)
6135 try:
6133 try:
6136 util.copyfile(a, a + ".resolve")
6134 util.copyfile(a, a + ".resolve")
6137 except (IOError, OSError) as inst:
6135 except (IOError, OSError) as inst:
6138 if inst.errno != errno.ENOENT:
6136 if inst.errno != errno.ENOENT:
6139 raise
6137 raise
6140
6138
6141 try:
6139 try:
6142 # preresolve file
6140 # preresolve file
6143 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6141 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6144 'resolve')
6142 'resolve')
6145 complete, r = ms.preresolve(f, wctx)
6143 complete, r = ms.preresolve(f, wctx)
6146 if not complete:
6144 if not complete:
6147 tocomplete.append(f)
6145 tocomplete.append(f)
6148 elif r:
6146 elif r:
6149 ret = 1
6147 ret = 1
6150 finally:
6148 finally:
6151 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6149 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6152 ms.commit()
6150 ms.commit()
6153
6151
6154 # replace filemerge's .orig file with our resolve file, but only
6152 # replace filemerge's .orig file with our resolve file, but only
6155 # for merges that are complete
6153 # for merges that are complete
6156 if complete:
6154 if complete:
6157 try:
6155 try:
6158 util.rename(a + ".resolve",
6156 util.rename(a + ".resolve",
6159 scmutil.origpath(ui, repo, a))
6157 scmutil.origpath(ui, repo, a))
6160 except OSError as inst:
6158 except OSError as inst:
6161 if inst.errno != errno.ENOENT:
6159 if inst.errno != errno.ENOENT:
6162 raise
6160 raise
6163
6161
6164 for f in tocomplete:
6162 for f in tocomplete:
6165 try:
6163 try:
6166 # resolve file
6164 # resolve file
6167 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6165 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6168 'resolve')
6166 'resolve')
6169 r = ms.resolve(f, wctx)
6167 r = ms.resolve(f, wctx)
6170 if r:
6168 if r:
6171 ret = 1
6169 ret = 1
6172 finally:
6170 finally:
6173 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6171 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6174 ms.commit()
6172 ms.commit()
6175
6173
6176 # replace filemerge's .orig file with our resolve file
6174 # replace filemerge's .orig file with our resolve file
6177 a = repo.wjoin(f)
6175 a = repo.wjoin(f)
6178 try:
6176 try:
6179 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6177 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6180 except OSError as inst:
6178 except OSError as inst:
6181 if inst.errno != errno.ENOENT:
6179 if inst.errno != errno.ENOENT:
6182 raise
6180 raise
6183
6181
6184 ms.commit()
6182 ms.commit()
6185 ms.recordactions()
6183 ms.recordactions()
6186
6184
6187 if not didwork and pats:
6185 if not didwork and pats:
6188 hint = None
6186 hint = None
6189 if not any([p for p in pats if p.find(':') >= 0]):
6187 if not any([p for p in pats if p.find(':') >= 0]):
6190 pats = ['path:%s' % p for p in pats]
6188 pats = ['path:%s' % p for p in pats]
6191 m = scmutil.match(wctx, pats, opts)
6189 m = scmutil.match(wctx, pats, opts)
6192 for f in ms:
6190 for f in ms:
6193 if not m(f):
6191 if not m(f):
6194 continue
6192 continue
6195 flags = ''.join(['-%s ' % o[0] for o in flaglist
6193 flags = ''.join(['-%s ' % o[0] for o in flaglist
6196 if opts.get(o)])
6194 if opts.get(o)])
6197 hint = _("(try: hg resolve %s%s)\n") % (
6195 hint = _("(try: hg resolve %s%s)\n") % (
6198 flags,
6196 flags,
6199 ' '.join(pats))
6197 ' '.join(pats))
6200 break
6198 break
6201 ui.warn(_("arguments do not match paths that need resolving\n"))
6199 ui.warn(_("arguments do not match paths that need resolving\n"))
6202 if hint:
6200 if hint:
6203 ui.warn(hint)
6201 ui.warn(hint)
6204 elif ms.mergedriver and ms.mdstate() != 's':
6202 elif ms.mergedriver and ms.mdstate() != 's':
6205 # run conclude step when either a driver-resolved file is requested
6203 # run conclude step when either a driver-resolved file is requested
6206 # or there are no driver-resolved files
6204 # or there are no driver-resolved files
6207 # we can't use 'ret' to determine whether any files are unresolved
6205 # we can't use 'ret' to determine whether any files are unresolved
6208 # because we might not have tried to resolve some
6206 # because we might not have tried to resolve some
6209 if ((runconclude or not list(ms.driverresolved()))
6207 if ((runconclude or not list(ms.driverresolved()))
6210 and not list(ms.unresolved())):
6208 and not list(ms.unresolved())):
6211 proceed = mergemod.driverconclude(repo, ms, wctx)
6209 proceed = mergemod.driverconclude(repo, ms, wctx)
6212 ms.commit()
6210 ms.commit()
6213 if not proceed:
6211 if not proceed:
6214 return 1
6212 return 1
6215
6213
6216 # Nudge users into finishing an unfinished operation
6214 # Nudge users into finishing an unfinished operation
6217 unresolvedf = list(ms.unresolved())
6215 unresolvedf = list(ms.unresolved())
6218 driverresolvedf = list(ms.driverresolved())
6216 driverresolvedf = list(ms.driverresolved())
6219 if not unresolvedf and not driverresolvedf:
6217 if not unresolvedf and not driverresolvedf:
6220 ui.status(_('(no more unresolved files)\n'))
6218 ui.status(_('(no more unresolved files)\n'))
6221 cmdutil.checkafterresolved(repo)
6219 cmdutil.checkafterresolved(repo)
6222 elif not unresolvedf:
6220 elif not unresolvedf:
6223 ui.status(_('(no more unresolved files -- '
6221 ui.status(_('(no more unresolved files -- '
6224 'run "hg resolve --all" to conclude)\n'))
6222 'run "hg resolve --all" to conclude)\n'))
6225
6223
6226 return ret
6224 return ret
6227
6225
6228 @command('revert',
6226 @command('revert',
6229 [('a', 'all', None, _('revert all changes when no arguments given')),
6227 [('a', 'all', None, _('revert all changes when no arguments given')),
6230 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6228 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6231 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6229 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6232 ('C', 'no-backup', None, _('do not save backup copies of files')),
6230 ('C', 'no-backup', None, _('do not save backup copies of files')),
6233 ('i', 'interactive', None,
6231 ('i', 'interactive', None,
6234 _('interactively select the changes (EXPERIMENTAL)')),
6232 _('interactively select the changes (EXPERIMENTAL)')),
6235 ] + walkopts + dryrunopts,
6233 ] + walkopts + dryrunopts,
6236 _('[OPTION]... [-r REV] [NAME]...'))
6234 _('[OPTION]... [-r REV] [NAME]...'))
6237 def revert(ui, repo, *pats, **opts):
6235 def revert(ui, repo, *pats, **opts):
6238 """restore files to their checkout state
6236 """restore files to their checkout state
6239
6237
6240 .. note::
6238 .. note::
6241
6239
6242 To check out earlier revisions, you should use :hg:`update REV`.
6240 To check out earlier revisions, you should use :hg:`update REV`.
6243 To cancel an uncommitted merge (and lose your changes),
6241 To cancel an uncommitted merge (and lose your changes),
6244 use :hg:`update --clean .`.
6242 use :hg:`update --clean .`.
6245
6243
6246 With no revision specified, revert the specified files or directories
6244 With no revision specified, revert the specified files or directories
6247 to the contents they had in the parent of the working directory.
6245 to the contents they had in the parent of the working directory.
6248 This restores the contents of files to an unmodified
6246 This restores the contents of files to an unmodified
6249 state and unschedules adds, removes, copies, and renames. If the
6247 state and unschedules adds, removes, copies, and renames. If the
6250 working directory has two parents, you must explicitly specify a
6248 working directory has two parents, you must explicitly specify a
6251 revision.
6249 revision.
6252
6250
6253 Using the -r/--rev or -d/--date options, revert the given files or
6251 Using the -r/--rev or -d/--date options, revert the given files or
6254 directories to their states as of a specific revision. Because
6252 directories to their states as of a specific revision. Because
6255 revert does not change the working directory parents, this will
6253 revert does not change the working directory parents, this will
6256 cause these files to appear modified. This can be helpful to "back
6254 cause these files to appear modified. This can be helpful to "back
6257 out" some or all of an earlier change. See :hg:`backout` for a
6255 out" some or all of an earlier change. See :hg:`backout` for a
6258 related method.
6256 related method.
6259
6257
6260 Modified files are saved with a .orig suffix before reverting.
6258 Modified files are saved with a .orig suffix before reverting.
6261 To disable these backups, use --no-backup.
6259 To disable these backups, use --no-backup.
6262
6260
6263 See :hg:`help dates` for a list of formats valid for -d/--date.
6261 See :hg:`help dates` for a list of formats valid for -d/--date.
6264
6262
6265 See :hg:`help backout` for a way to reverse the effect of an
6263 See :hg:`help backout` for a way to reverse the effect of an
6266 earlier changeset.
6264 earlier changeset.
6267
6265
6268 Returns 0 on success.
6266 Returns 0 on success.
6269 """
6267 """
6270
6268
6271 if opts.get("date"):
6269 if opts.get("date"):
6272 if opts.get("rev"):
6270 if opts.get("rev"):
6273 raise error.Abort(_("you can't specify a revision and a date"))
6271 raise error.Abort(_("you can't specify a revision and a date"))
6274 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6272 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6275
6273
6276 parent, p2 = repo.dirstate.parents()
6274 parent, p2 = repo.dirstate.parents()
6277 if not opts.get('rev') and p2 != nullid:
6275 if not opts.get('rev') and p2 != nullid:
6278 # revert after merge is a trap for new users (issue2915)
6276 # revert after merge is a trap for new users (issue2915)
6279 raise error.Abort(_('uncommitted merge with no revision specified'),
6277 raise error.Abort(_('uncommitted merge with no revision specified'),
6280 hint=_('use "hg update" or see "hg help revert"'))
6278 hint=_('use "hg update" or see "hg help revert"'))
6281
6279
6282 ctx = scmutil.revsingle(repo, opts.get('rev'))
6280 ctx = scmutil.revsingle(repo, opts.get('rev'))
6283
6281
6284 if (not (pats or opts.get('include') or opts.get('exclude') or
6282 if (not (pats or opts.get('include') or opts.get('exclude') or
6285 opts.get('all') or opts.get('interactive'))):
6283 opts.get('all') or opts.get('interactive'))):
6286 msg = _("no files or directories specified")
6284 msg = _("no files or directories specified")
6287 if p2 != nullid:
6285 if p2 != nullid:
6288 hint = _("uncommitted merge, use --all to discard all changes,"
6286 hint = _("uncommitted merge, use --all to discard all changes,"
6289 " or 'hg update -C .' to abort the merge")
6287 " or 'hg update -C .' to abort the merge")
6290 raise error.Abort(msg, hint=hint)
6288 raise error.Abort(msg, hint=hint)
6291 dirty = any(repo.status())
6289 dirty = any(repo.status())
6292 node = ctx.node()
6290 node = ctx.node()
6293 if node != parent:
6291 if node != parent:
6294 if dirty:
6292 if dirty:
6295 hint = _("uncommitted changes, use --all to discard all"
6293 hint = _("uncommitted changes, use --all to discard all"
6296 " changes, or 'hg update %s' to update") % ctx.rev()
6294 " changes, or 'hg update %s' to update") % ctx.rev()
6297 else:
6295 else:
6298 hint = _("use --all to revert all files,"
6296 hint = _("use --all to revert all files,"
6299 " or 'hg update %s' to update") % ctx.rev()
6297 " or 'hg update %s' to update") % ctx.rev()
6300 elif dirty:
6298 elif dirty:
6301 hint = _("uncommitted changes, use --all to discard all changes")
6299 hint = _("uncommitted changes, use --all to discard all changes")
6302 else:
6300 else:
6303 hint = _("use --all to revert all files")
6301 hint = _("use --all to revert all files")
6304 raise error.Abort(msg, hint=hint)
6302 raise error.Abort(msg, hint=hint)
6305
6303
6306 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6304 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6307
6305
6308 @command('rollback', dryrunopts +
6306 @command('rollback', dryrunopts +
6309 [('f', 'force', False, _('ignore safety measures'))])
6307 [('f', 'force', False, _('ignore safety measures'))])
6310 def rollback(ui, repo, **opts):
6308 def rollback(ui, repo, **opts):
6311 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6309 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6312
6310
6313 Please use :hg:`commit --amend` instead of rollback to correct
6311 Please use :hg:`commit --amend` instead of rollback to correct
6314 mistakes in the last commit.
6312 mistakes in the last commit.
6315
6313
6316 This command should be used with care. There is only one level of
6314 This command should be used with care. There is only one level of
6317 rollback, and there is no way to undo a rollback. It will also
6315 rollback, and there is no way to undo a rollback. It will also
6318 restore the dirstate at the time of the last transaction, losing
6316 restore the dirstate at the time of the last transaction, losing
6319 any dirstate changes since that time. This command does not alter
6317 any dirstate changes since that time. This command does not alter
6320 the working directory.
6318 the working directory.
6321
6319
6322 Transactions are used to encapsulate the effects of all commands
6320 Transactions are used to encapsulate the effects of all commands
6323 that create new changesets or propagate existing changesets into a
6321 that create new changesets or propagate existing changesets into a
6324 repository.
6322 repository.
6325
6323
6326 .. container:: verbose
6324 .. container:: verbose
6327
6325
6328 For example, the following commands are transactional, and their
6326 For example, the following commands are transactional, and their
6329 effects can be rolled back:
6327 effects can be rolled back:
6330
6328
6331 - commit
6329 - commit
6332 - import
6330 - import
6333 - pull
6331 - pull
6334 - push (with this repository as the destination)
6332 - push (with this repository as the destination)
6335 - unbundle
6333 - unbundle
6336
6334
6337 To avoid permanent data loss, rollback will refuse to rollback a
6335 To avoid permanent data loss, rollback will refuse to rollback a
6338 commit transaction if it isn't checked out. Use --force to
6336 commit transaction if it isn't checked out. Use --force to
6339 override this protection.
6337 override this protection.
6340
6338
6341 This command is not intended for use on public repositories. Once
6339 This command is not intended for use on public repositories. Once
6342 changes are visible for pull by other users, rolling a transaction
6340 changes are visible for pull by other users, rolling a transaction
6343 back locally is ineffective (someone else may already have pulled
6341 back locally is ineffective (someone else may already have pulled
6344 the changes). Furthermore, a race is possible with readers of the
6342 the changes). Furthermore, a race is possible with readers of the
6345 repository; for example an in-progress pull from the repository
6343 repository; for example an in-progress pull from the repository
6346 may fail if a rollback is performed.
6344 may fail if a rollback is performed.
6347
6345
6348 Returns 0 on success, 1 if no rollback data is available.
6346 Returns 0 on success, 1 if no rollback data is available.
6349 """
6347 """
6350 return repo.rollback(dryrun=opts.get('dry_run'),
6348 return repo.rollback(dryrun=opts.get('dry_run'),
6351 force=opts.get('force'))
6349 force=opts.get('force'))
6352
6350
6353 @command('root', [])
6351 @command('root', [])
6354 def root(ui, repo):
6352 def root(ui, repo):
6355 """print the root (top) of the current working directory
6353 """print the root (top) of the current working directory
6356
6354
6357 Print the root directory of the current repository.
6355 Print the root directory of the current repository.
6358
6356
6359 Returns 0 on success.
6357 Returns 0 on success.
6360 """
6358 """
6361 ui.write(repo.root + "\n")
6359 ui.write(repo.root + "\n")
6362
6360
6363 @command('^serve',
6361 @command('^serve',
6364 [('A', 'accesslog', '', _('name of access log file to write to'),
6362 [('A', 'accesslog', '', _('name of access log file to write to'),
6365 _('FILE')),
6363 _('FILE')),
6366 ('d', 'daemon', None, _('run server in background')),
6364 ('d', 'daemon', None, _('run server in background')),
6367 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6365 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6368 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6366 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6369 # use string type, then we can check if something was passed
6367 # use string type, then we can check if something was passed
6370 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6368 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6371 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6369 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6372 _('ADDR')),
6370 _('ADDR')),
6373 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6371 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6374 _('PREFIX')),
6372 _('PREFIX')),
6375 ('n', 'name', '',
6373 ('n', 'name', '',
6376 _('name to show in web pages (default: working directory)'), _('NAME')),
6374 _('name to show in web pages (default: working directory)'), _('NAME')),
6377 ('', 'web-conf', '',
6375 ('', 'web-conf', '',
6378 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6376 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6379 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6377 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6380 _('FILE')),
6378 _('FILE')),
6381 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6379 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6382 ('', 'stdio', None, _('for remote clients')),
6380 ('', 'stdio', None, _('for remote clients')),
6383 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6381 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6384 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6382 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6385 ('', 'style', '', _('template style to use'), _('STYLE')),
6383 ('', 'style', '', _('template style to use'), _('STYLE')),
6386 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6384 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6387 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6385 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6388 _('[OPTION]...'),
6386 _('[OPTION]...'),
6389 optionalrepo=True)
6387 optionalrepo=True)
6390 def serve(ui, repo, **opts):
6388 def serve(ui, repo, **opts):
6391 """start stand-alone webserver
6389 """start stand-alone webserver
6392
6390
6393 Start a local HTTP repository browser and pull server. You can use
6391 Start a local HTTP repository browser and pull server. You can use
6394 this for ad-hoc sharing and browsing of repositories. It is
6392 this for ad-hoc sharing and browsing of repositories. It is
6395 recommended to use a real web server to serve a repository for
6393 recommended to use a real web server to serve a repository for
6396 longer periods of time.
6394 longer periods of time.
6397
6395
6398 Please note that the server does not implement access control.
6396 Please note that the server does not implement access control.
6399 This means that, by default, anybody can read from the server and
6397 This means that, by default, anybody can read from the server and
6400 nobody can write to it by default. Set the ``web.allow_push``
6398 nobody can write to it by default. Set the ``web.allow_push``
6401 option to ``*`` to allow everybody to push to the server. You
6399 option to ``*`` to allow everybody to push to the server. You
6402 should use a real web server if you need to authenticate users.
6400 should use a real web server if you need to authenticate users.
6403
6401
6404 By default, the server logs accesses to stdout and errors to
6402 By default, the server logs accesses to stdout and errors to
6405 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6403 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6406 files.
6404 files.
6407
6405
6408 To have the server choose a free port number to listen on, specify
6406 To have the server choose a free port number to listen on, specify
6409 a port number of 0; in this case, the server will print the port
6407 a port number of 0; in this case, the server will print the port
6410 number it uses.
6408 number it uses.
6411
6409
6412 Returns 0 on success.
6410 Returns 0 on success.
6413 """
6411 """
6414
6412
6415 if opts["stdio"] and opts["cmdserver"]:
6413 if opts["stdio"] and opts["cmdserver"]:
6416 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6414 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6417
6415
6418 if opts["stdio"]:
6416 if opts["stdio"]:
6419 if repo is None:
6417 if repo is None:
6420 raise error.RepoError(_("there is no Mercurial repository here"
6418 raise error.RepoError(_("there is no Mercurial repository here"
6421 " (.hg not found)"))
6419 " (.hg not found)"))
6422 s = sshserver.sshserver(ui, repo)
6420 s = sshserver.sshserver(ui, repo)
6423 s.serve_forever()
6421 s.serve_forever()
6424
6422
6425 if opts["cmdserver"]:
6423 if opts["cmdserver"]:
6426 service = commandserver.createservice(ui, repo, opts)
6424 service = commandserver.createservice(ui, repo, opts)
6427 else:
6425 else:
6428 service = hgweb.createservice(ui, repo, opts)
6426 service = hgweb.createservice(ui, repo, opts)
6429 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6427 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6430
6428
6431 @command('^status|st',
6429 @command('^status|st',
6432 [('A', 'all', None, _('show status of all files')),
6430 [('A', 'all', None, _('show status of all files')),
6433 ('m', 'modified', None, _('show only modified files')),
6431 ('m', 'modified', None, _('show only modified files')),
6434 ('a', 'added', None, _('show only added files')),
6432 ('a', 'added', None, _('show only added files')),
6435 ('r', 'removed', None, _('show only removed files')),
6433 ('r', 'removed', None, _('show only removed files')),
6436 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6434 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6437 ('c', 'clean', None, _('show only files without changes')),
6435 ('c', 'clean', None, _('show only files without changes')),
6438 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6436 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6439 ('i', 'ignored', None, _('show only ignored files')),
6437 ('i', 'ignored', None, _('show only ignored files')),
6440 ('n', 'no-status', None, _('hide status prefix')),
6438 ('n', 'no-status', None, _('hide status prefix')),
6441 ('C', 'copies', None, _('show source of copied files')),
6439 ('C', 'copies', None, _('show source of copied files')),
6442 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6440 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6443 ('', 'rev', [], _('show difference from revision'), _('REV')),
6441 ('', 'rev', [], _('show difference from revision'), _('REV')),
6444 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6442 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6445 ] + walkopts + subrepoopts + formatteropts,
6443 ] + walkopts + subrepoopts + formatteropts,
6446 _('[OPTION]... [FILE]...'),
6444 _('[OPTION]... [FILE]...'),
6447 inferrepo=True)
6445 inferrepo=True)
6448 def status(ui, repo, *pats, **opts):
6446 def status(ui, repo, *pats, **opts):
6449 """show changed files in the working directory
6447 """show changed files in the working directory
6450
6448
6451 Show status of files in the repository. If names are given, only
6449 Show status of files in the repository. If names are given, only
6452 files that match are shown. Files that are clean or ignored or
6450 files that match are shown. Files that are clean or ignored or
6453 the source of a copy/move operation, are not listed unless
6451 the source of a copy/move operation, are not listed unless
6454 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6452 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6455 Unless options described with "show only ..." are given, the
6453 Unless options described with "show only ..." are given, the
6456 options -mardu are used.
6454 options -mardu are used.
6457
6455
6458 Option -q/--quiet hides untracked (unknown and ignored) files
6456 Option -q/--quiet hides untracked (unknown and ignored) files
6459 unless explicitly requested with -u/--unknown or -i/--ignored.
6457 unless explicitly requested with -u/--unknown or -i/--ignored.
6460
6458
6461 .. note::
6459 .. note::
6462
6460
6463 :hg:`status` may appear to disagree with diff if permissions have
6461 :hg:`status` may appear to disagree with diff if permissions have
6464 changed or a merge has occurred. The standard diff format does
6462 changed or a merge has occurred. The standard diff format does
6465 not report permission changes and diff only reports changes
6463 not report permission changes and diff only reports changes
6466 relative to one merge parent.
6464 relative to one merge parent.
6467
6465
6468 If one revision is given, it is used as the base revision.
6466 If one revision is given, it is used as the base revision.
6469 If two revisions are given, the differences between them are
6467 If two revisions are given, the differences between them are
6470 shown. The --change option can also be used as a shortcut to list
6468 shown. The --change option can also be used as a shortcut to list
6471 the changed files of a revision from its first parent.
6469 the changed files of a revision from its first parent.
6472
6470
6473 The codes used to show the status of files are::
6471 The codes used to show the status of files are::
6474
6472
6475 M = modified
6473 M = modified
6476 A = added
6474 A = added
6477 R = removed
6475 R = removed
6478 C = clean
6476 C = clean
6479 ! = missing (deleted by non-hg command, but still tracked)
6477 ! = missing (deleted by non-hg command, but still tracked)
6480 ? = not tracked
6478 ? = not tracked
6481 I = ignored
6479 I = ignored
6482 = origin of the previous file (with --copies)
6480 = origin of the previous file (with --copies)
6483
6481
6484 .. container:: verbose
6482 .. container:: verbose
6485
6483
6486 Examples:
6484 Examples:
6487
6485
6488 - show changes in the working directory relative to a
6486 - show changes in the working directory relative to a
6489 changeset::
6487 changeset::
6490
6488
6491 hg status --rev 9353
6489 hg status --rev 9353
6492
6490
6493 - show changes in the working directory relative to the
6491 - show changes in the working directory relative to the
6494 current directory (see :hg:`help patterns` for more information)::
6492 current directory (see :hg:`help patterns` for more information)::
6495
6493
6496 hg status re:
6494 hg status re:
6497
6495
6498 - show all changes including copies in an existing changeset::
6496 - show all changes including copies in an existing changeset::
6499
6497
6500 hg status --copies --change 9353
6498 hg status --copies --change 9353
6501
6499
6502 - get a NUL separated list of added files, suitable for xargs::
6500 - get a NUL separated list of added files, suitable for xargs::
6503
6501
6504 hg status -an0
6502 hg status -an0
6505
6503
6506 Returns 0 on success.
6504 Returns 0 on success.
6507 """
6505 """
6508
6506
6509 revs = opts.get('rev')
6507 revs = opts.get('rev')
6510 change = opts.get('change')
6508 change = opts.get('change')
6511
6509
6512 if revs and change:
6510 if revs and change:
6513 msg = _('cannot specify --rev and --change at the same time')
6511 msg = _('cannot specify --rev and --change at the same time')
6514 raise error.Abort(msg)
6512 raise error.Abort(msg)
6515 elif change:
6513 elif change:
6516 node2 = scmutil.revsingle(repo, change, None).node()
6514 node2 = scmutil.revsingle(repo, change, None).node()
6517 node1 = repo[node2].p1().node()
6515 node1 = repo[node2].p1().node()
6518 else:
6516 else:
6519 node1, node2 = scmutil.revpair(repo, revs)
6517 node1, node2 = scmutil.revpair(repo, revs)
6520
6518
6521 if pats:
6519 if pats:
6522 cwd = repo.getcwd()
6520 cwd = repo.getcwd()
6523 else:
6521 else:
6524 cwd = ''
6522 cwd = ''
6525
6523
6526 if opts.get('print0'):
6524 if opts.get('print0'):
6527 end = '\0'
6525 end = '\0'
6528 else:
6526 else:
6529 end = '\n'
6527 end = '\n'
6530 copy = {}
6528 copy = {}
6531 states = 'modified added removed deleted unknown ignored clean'.split()
6529 states = 'modified added removed deleted unknown ignored clean'.split()
6532 show = [k for k in states if opts.get(k)]
6530 show = [k for k in states if opts.get(k)]
6533 if opts.get('all'):
6531 if opts.get('all'):
6534 show += ui.quiet and (states[:4] + ['clean']) or states
6532 show += ui.quiet and (states[:4] + ['clean']) or states
6535 if not show:
6533 if not show:
6536 if ui.quiet:
6534 if ui.quiet:
6537 show = states[:4]
6535 show = states[:4]
6538 else:
6536 else:
6539 show = states[:5]
6537 show = states[:5]
6540
6538
6541 m = scmutil.match(repo[node2], pats, opts)
6539 m = scmutil.match(repo[node2], pats, opts)
6542 stat = repo.status(node1, node2, m,
6540 stat = repo.status(node1, node2, m,
6543 'ignored' in show, 'clean' in show, 'unknown' in show,
6541 'ignored' in show, 'clean' in show, 'unknown' in show,
6544 opts.get('subrepos'))
6542 opts.get('subrepos'))
6545 changestates = zip(states, 'MAR!?IC', stat)
6543 changestates = zip(states, 'MAR!?IC', stat)
6546
6544
6547 if (opts.get('all') or opts.get('copies')
6545 if (opts.get('all') or opts.get('copies')
6548 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6546 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6549 copy = copies.pathcopies(repo[node1], repo[node2], m)
6547 copy = copies.pathcopies(repo[node1], repo[node2], m)
6550
6548
6551 fm = ui.formatter('status', opts)
6549 fm = ui.formatter('status', opts)
6552 fmt = '%s' + end
6550 fmt = '%s' + end
6553 showchar = not opts.get('no_status')
6551 showchar = not opts.get('no_status')
6554
6552
6555 for state, char, files in changestates:
6553 for state, char, files in changestates:
6556 if state in show:
6554 if state in show:
6557 label = 'status.' + state
6555 label = 'status.' + state
6558 for f in files:
6556 for f in files:
6559 fm.startitem()
6557 fm.startitem()
6560 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6558 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6561 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6559 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6562 if f in copy:
6560 if f in copy:
6563 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6561 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6564 label='status.copied')
6562 label='status.copied')
6565 fm.end()
6563 fm.end()
6566
6564
6567 @command('^summary|sum',
6565 @command('^summary|sum',
6568 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6566 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6569 def summary(ui, repo, **opts):
6567 def summary(ui, repo, **opts):
6570 """summarize working directory state
6568 """summarize working directory state
6571
6569
6572 This generates a brief summary of the working directory state,
6570 This generates a brief summary of the working directory state,
6573 including parents, branch, commit status, phase and available updates.
6571 including parents, branch, commit status, phase and available updates.
6574
6572
6575 With the --remote option, this will check the default paths for
6573 With the --remote option, this will check the default paths for
6576 incoming and outgoing changes. This can be time-consuming.
6574 incoming and outgoing changes. This can be time-consuming.
6577
6575
6578 Returns 0 on success.
6576 Returns 0 on success.
6579 """
6577 """
6580
6578
6581 ctx = repo[None]
6579 ctx = repo[None]
6582 parents = ctx.parents()
6580 parents = ctx.parents()
6583 pnode = parents[0].node()
6581 pnode = parents[0].node()
6584 marks = []
6582 marks = []
6585
6583
6586 ms = None
6584 ms = None
6587 try:
6585 try:
6588 ms = mergemod.mergestate.read(repo)
6586 ms = mergemod.mergestate.read(repo)
6589 except error.UnsupportedMergeRecords as e:
6587 except error.UnsupportedMergeRecords as e:
6590 s = ' '.join(e.recordtypes)
6588 s = ' '.join(e.recordtypes)
6591 ui.warn(
6589 ui.warn(
6592 _('warning: merge state has unsupported record types: %s\n') % s)
6590 _('warning: merge state has unsupported record types: %s\n') % s)
6593 unresolved = 0
6591 unresolved = 0
6594 else:
6592 else:
6595 unresolved = [f for f in ms if ms[f] == 'u']
6593 unresolved = [f for f in ms if ms[f] == 'u']
6596
6594
6597 for p in parents:
6595 for p in parents:
6598 # label with log.changeset (instead of log.parent) since this
6596 # label with log.changeset (instead of log.parent) since this
6599 # shows a working directory parent *changeset*:
6597 # shows a working directory parent *changeset*:
6600 # i18n: column positioning for "hg summary"
6598 # i18n: column positioning for "hg summary"
6601 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6599 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6602 label='log.changeset changeset.%s' % p.phasestr())
6600 label='log.changeset changeset.%s' % p.phasestr())
6603 ui.write(' '.join(p.tags()), label='log.tag')
6601 ui.write(' '.join(p.tags()), label='log.tag')
6604 if p.bookmarks():
6602 if p.bookmarks():
6605 marks.extend(p.bookmarks())
6603 marks.extend(p.bookmarks())
6606 if p.rev() == -1:
6604 if p.rev() == -1:
6607 if not len(repo):
6605 if not len(repo):
6608 ui.write(_(' (empty repository)'))
6606 ui.write(_(' (empty repository)'))
6609 else:
6607 else:
6610 ui.write(_(' (no revision checked out)'))
6608 ui.write(_(' (no revision checked out)'))
6611 ui.write('\n')
6609 ui.write('\n')
6612 if p.description():
6610 if p.description():
6613 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6611 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6614 label='log.summary')
6612 label='log.summary')
6615
6613
6616 branch = ctx.branch()
6614 branch = ctx.branch()
6617 bheads = repo.branchheads(branch)
6615 bheads = repo.branchheads(branch)
6618 # i18n: column positioning for "hg summary"
6616 # i18n: column positioning for "hg summary"
6619 m = _('branch: %s\n') % branch
6617 m = _('branch: %s\n') % branch
6620 if branch != 'default':
6618 if branch != 'default':
6621 ui.write(m, label='log.branch')
6619 ui.write(m, label='log.branch')
6622 else:
6620 else:
6623 ui.status(m, label='log.branch')
6621 ui.status(m, label='log.branch')
6624
6622
6625 if marks:
6623 if marks:
6626 active = repo._activebookmark
6624 active = repo._activebookmark
6627 # i18n: column positioning for "hg summary"
6625 # i18n: column positioning for "hg summary"
6628 ui.write(_('bookmarks:'), label='log.bookmark')
6626 ui.write(_('bookmarks:'), label='log.bookmark')
6629 if active is not None:
6627 if active is not None:
6630 if active in marks:
6628 if active in marks:
6631 ui.write(' *' + active, label=activebookmarklabel)
6629 ui.write(' *' + active, label=activebookmarklabel)
6632 marks.remove(active)
6630 marks.remove(active)
6633 else:
6631 else:
6634 ui.write(' [%s]' % active, label=activebookmarklabel)
6632 ui.write(' [%s]' % active, label=activebookmarklabel)
6635 for m in marks:
6633 for m in marks:
6636 ui.write(' ' + m, label='log.bookmark')
6634 ui.write(' ' + m, label='log.bookmark')
6637 ui.write('\n', label='log.bookmark')
6635 ui.write('\n', label='log.bookmark')
6638
6636
6639 status = repo.status(unknown=True)
6637 status = repo.status(unknown=True)
6640
6638
6641 c = repo.dirstate.copies()
6639 c = repo.dirstate.copies()
6642 copied, renamed = [], []
6640 copied, renamed = [], []
6643 for d, s in c.iteritems():
6641 for d, s in c.iteritems():
6644 if s in status.removed:
6642 if s in status.removed:
6645 status.removed.remove(s)
6643 status.removed.remove(s)
6646 renamed.append(d)
6644 renamed.append(d)
6647 else:
6645 else:
6648 copied.append(d)
6646 copied.append(d)
6649 if d in status.added:
6647 if d in status.added:
6650 status.added.remove(d)
6648 status.added.remove(d)
6651
6649
6652 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6650 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6653
6651
6654 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6652 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6655 (ui.label(_('%d added'), 'status.added'), status.added),
6653 (ui.label(_('%d added'), 'status.added'), status.added),
6656 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6654 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6657 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6655 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6658 (ui.label(_('%d copied'), 'status.copied'), copied),
6656 (ui.label(_('%d copied'), 'status.copied'), copied),
6659 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6657 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6660 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6658 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6661 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6659 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6662 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6660 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6663 t = []
6661 t = []
6664 for l, s in labels:
6662 for l, s in labels:
6665 if s:
6663 if s:
6666 t.append(l % len(s))
6664 t.append(l % len(s))
6667
6665
6668 t = ', '.join(t)
6666 t = ', '.join(t)
6669 cleanworkdir = False
6667 cleanworkdir = False
6670
6668
6671 if repo.vfs.exists('graftstate'):
6669 if repo.vfs.exists('graftstate'):
6672 t += _(' (graft in progress)')
6670 t += _(' (graft in progress)')
6673 if repo.vfs.exists('updatestate'):
6671 if repo.vfs.exists('updatestate'):
6674 t += _(' (interrupted update)')
6672 t += _(' (interrupted update)')
6675 elif len(parents) > 1:
6673 elif len(parents) > 1:
6676 t += _(' (merge)')
6674 t += _(' (merge)')
6677 elif branch != parents[0].branch():
6675 elif branch != parents[0].branch():
6678 t += _(' (new branch)')
6676 t += _(' (new branch)')
6679 elif (parents[0].closesbranch() and
6677 elif (parents[0].closesbranch() and
6680 pnode in repo.branchheads(branch, closed=True)):
6678 pnode in repo.branchheads(branch, closed=True)):
6681 t += _(' (head closed)')
6679 t += _(' (head closed)')
6682 elif not (status.modified or status.added or status.removed or renamed or
6680 elif not (status.modified or status.added or status.removed or renamed or
6683 copied or subs):
6681 copied or subs):
6684 t += _(' (clean)')
6682 t += _(' (clean)')
6685 cleanworkdir = True
6683 cleanworkdir = True
6686 elif pnode not in bheads:
6684 elif pnode not in bheads:
6687 t += _(' (new branch head)')
6685 t += _(' (new branch head)')
6688
6686
6689 if parents:
6687 if parents:
6690 pendingphase = max(p.phase() for p in parents)
6688 pendingphase = max(p.phase() for p in parents)
6691 else:
6689 else:
6692 pendingphase = phases.public
6690 pendingphase = phases.public
6693
6691
6694 if pendingphase > phases.newcommitphase(ui):
6692 if pendingphase > phases.newcommitphase(ui):
6695 t += ' (%s)' % phases.phasenames[pendingphase]
6693 t += ' (%s)' % phases.phasenames[pendingphase]
6696
6694
6697 if cleanworkdir:
6695 if cleanworkdir:
6698 # i18n: column positioning for "hg summary"
6696 # i18n: column positioning for "hg summary"
6699 ui.status(_('commit: %s\n') % t.strip())
6697 ui.status(_('commit: %s\n') % t.strip())
6700 else:
6698 else:
6701 # i18n: column positioning for "hg summary"
6699 # i18n: column positioning for "hg summary"
6702 ui.write(_('commit: %s\n') % t.strip())
6700 ui.write(_('commit: %s\n') % t.strip())
6703
6701
6704 # all ancestors of branch heads - all ancestors of parent = new csets
6702 # all ancestors of branch heads - all ancestors of parent = new csets
6705 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6703 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6706 bheads))
6704 bheads))
6707
6705
6708 if new == 0:
6706 if new == 0:
6709 # i18n: column positioning for "hg summary"
6707 # i18n: column positioning for "hg summary"
6710 ui.status(_('update: (current)\n'))
6708 ui.status(_('update: (current)\n'))
6711 elif pnode not in bheads:
6709 elif pnode not in bheads:
6712 # i18n: column positioning for "hg summary"
6710 # i18n: column positioning for "hg summary"
6713 ui.write(_('update: %d new changesets (update)\n') % new)
6711 ui.write(_('update: %d new changesets (update)\n') % new)
6714 else:
6712 else:
6715 # i18n: column positioning for "hg summary"
6713 # i18n: column positioning for "hg summary"
6716 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6714 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6717 (new, len(bheads)))
6715 (new, len(bheads)))
6718
6716
6719 t = []
6717 t = []
6720 draft = len(repo.revs('draft()'))
6718 draft = len(repo.revs('draft()'))
6721 if draft:
6719 if draft:
6722 t.append(_('%d draft') % draft)
6720 t.append(_('%d draft') % draft)
6723 secret = len(repo.revs('secret()'))
6721 secret = len(repo.revs('secret()'))
6724 if secret:
6722 if secret:
6725 t.append(_('%d secret') % secret)
6723 t.append(_('%d secret') % secret)
6726
6724
6727 if draft or secret:
6725 if draft or secret:
6728 ui.status(_('phases: %s\n') % ', '.join(t))
6726 ui.status(_('phases: %s\n') % ', '.join(t))
6729
6727
6730 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6728 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6731 for trouble in ("unstable", "divergent", "bumped"):
6729 for trouble in ("unstable", "divergent", "bumped"):
6732 numtrouble = len(repo.revs(trouble + "()"))
6730 numtrouble = len(repo.revs(trouble + "()"))
6733 # We write all the possibilities to ease translation
6731 # We write all the possibilities to ease translation
6734 troublemsg = {
6732 troublemsg = {
6735 "unstable": _("unstable: %d changesets"),
6733 "unstable": _("unstable: %d changesets"),
6736 "divergent": _("divergent: %d changesets"),
6734 "divergent": _("divergent: %d changesets"),
6737 "bumped": _("bumped: %d changesets"),
6735 "bumped": _("bumped: %d changesets"),
6738 }
6736 }
6739 if numtrouble > 0:
6737 if numtrouble > 0:
6740 ui.status(troublemsg[trouble] % numtrouble + "\n")
6738 ui.status(troublemsg[trouble] % numtrouble + "\n")
6741
6739
6742 cmdutil.summaryhooks(ui, repo)
6740 cmdutil.summaryhooks(ui, repo)
6743
6741
6744 if opts.get('remote'):
6742 if opts.get('remote'):
6745 needsincoming, needsoutgoing = True, True
6743 needsincoming, needsoutgoing = True, True
6746 else:
6744 else:
6747 needsincoming, needsoutgoing = False, False
6745 needsincoming, needsoutgoing = False, False
6748 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6746 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6749 if i:
6747 if i:
6750 needsincoming = True
6748 needsincoming = True
6751 if o:
6749 if o:
6752 needsoutgoing = True
6750 needsoutgoing = True
6753 if not needsincoming and not needsoutgoing:
6751 if not needsincoming and not needsoutgoing:
6754 return
6752 return
6755
6753
6756 def getincoming():
6754 def getincoming():
6757 source, branches = hg.parseurl(ui.expandpath('default'))
6755 source, branches = hg.parseurl(ui.expandpath('default'))
6758 sbranch = branches[0]
6756 sbranch = branches[0]
6759 try:
6757 try:
6760 other = hg.peer(repo, {}, source)
6758 other = hg.peer(repo, {}, source)
6761 except error.RepoError:
6759 except error.RepoError:
6762 if opts.get('remote'):
6760 if opts.get('remote'):
6763 raise
6761 raise
6764 return source, sbranch, None, None, None
6762 return source, sbranch, None, None, None
6765 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6763 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6766 if revs:
6764 if revs:
6767 revs = [other.lookup(rev) for rev in revs]
6765 revs = [other.lookup(rev) for rev in revs]
6768 ui.debug('comparing with %s\n' % util.hidepassword(source))
6766 ui.debug('comparing with %s\n' % util.hidepassword(source))
6769 repo.ui.pushbuffer()
6767 repo.ui.pushbuffer()
6770 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6768 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6771 repo.ui.popbuffer()
6769 repo.ui.popbuffer()
6772 return source, sbranch, other, commoninc, commoninc[1]
6770 return source, sbranch, other, commoninc, commoninc[1]
6773
6771
6774 if needsincoming:
6772 if needsincoming:
6775 source, sbranch, sother, commoninc, incoming = getincoming()
6773 source, sbranch, sother, commoninc, incoming = getincoming()
6776 else:
6774 else:
6777 source = sbranch = sother = commoninc = incoming = None
6775 source = sbranch = sother = commoninc = incoming = None
6778
6776
6779 def getoutgoing():
6777 def getoutgoing():
6780 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6778 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6781 dbranch = branches[0]
6779 dbranch = branches[0]
6782 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6780 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6783 if source != dest:
6781 if source != dest:
6784 try:
6782 try:
6785 dother = hg.peer(repo, {}, dest)
6783 dother = hg.peer(repo, {}, dest)
6786 except error.RepoError:
6784 except error.RepoError:
6787 if opts.get('remote'):
6785 if opts.get('remote'):
6788 raise
6786 raise
6789 return dest, dbranch, None, None
6787 return dest, dbranch, None, None
6790 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6788 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6791 elif sother is None:
6789 elif sother is None:
6792 # there is no explicit destination peer, but source one is invalid
6790 # there is no explicit destination peer, but source one is invalid
6793 return dest, dbranch, None, None
6791 return dest, dbranch, None, None
6794 else:
6792 else:
6795 dother = sother
6793 dother = sother
6796 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6794 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6797 common = None
6795 common = None
6798 else:
6796 else:
6799 common = commoninc
6797 common = commoninc
6800 if revs:
6798 if revs:
6801 revs = [repo.lookup(rev) for rev in revs]
6799 revs = [repo.lookup(rev) for rev in revs]
6802 repo.ui.pushbuffer()
6800 repo.ui.pushbuffer()
6803 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6801 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6804 commoninc=common)
6802 commoninc=common)
6805 repo.ui.popbuffer()
6803 repo.ui.popbuffer()
6806 return dest, dbranch, dother, outgoing
6804 return dest, dbranch, dother, outgoing
6807
6805
6808 if needsoutgoing:
6806 if needsoutgoing:
6809 dest, dbranch, dother, outgoing = getoutgoing()
6807 dest, dbranch, dother, outgoing = getoutgoing()
6810 else:
6808 else:
6811 dest = dbranch = dother = outgoing = None
6809 dest = dbranch = dother = outgoing = None
6812
6810
6813 if opts.get('remote'):
6811 if opts.get('remote'):
6814 t = []
6812 t = []
6815 if incoming:
6813 if incoming:
6816 t.append(_('1 or more incoming'))
6814 t.append(_('1 or more incoming'))
6817 o = outgoing.missing
6815 o = outgoing.missing
6818 if o:
6816 if o:
6819 t.append(_('%d outgoing') % len(o))
6817 t.append(_('%d outgoing') % len(o))
6820 other = dother or sother
6818 other = dother or sother
6821 if 'bookmarks' in other.listkeys('namespaces'):
6819 if 'bookmarks' in other.listkeys('namespaces'):
6822 counts = bookmarks.summary(repo, other)
6820 counts = bookmarks.summary(repo, other)
6823 if counts[0] > 0:
6821 if counts[0] > 0:
6824 t.append(_('%d incoming bookmarks') % counts[0])
6822 t.append(_('%d incoming bookmarks') % counts[0])
6825 if counts[1] > 0:
6823 if counts[1] > 0:
6826 t.append(_('%d outgoing bookmarks') % counts[1])
6824 t.append(_('%d outgoing bookmarks') % counts[1])
6827
6825
6828 if t:
6826 if t:
6829 # i18n: column positioning for "hg summary"
6827 # i18n: column positioning for "hg summary"
6830 ui.write(_('remote: %s\n') % (', '.join(t)))
6828 ui.write(_('remote: %s\n') % (', '.join(t)))
6831 else:
6829 else:
6832 # i18n: column positioning for "hg summary"
6830 # i18n: column positioning for "hg summary"
6833 ui.status(_('remote: (synced)\n'))
6831 ui.status(_('remote: (synced)\n'))
6834
6832
6835 cmdutil.summaryremotehooks(ui, repo, opts,
6833 cmdutil.summaryremotehooks(ui, repo, opts,
6836 ((source, sbranch, sother, commoninc),
6834 ((source, sbranch, sother, commoninc),
6837 (dest, dbranch, dother, outgoing)))
6835 (dest, dbranch, dother, outgoing)))
6838
6836
6839 @command('tag',
6837 @command('tag',
6840 [('f', 'force', None, _('force tag')),
6838 [('f', 'force', None, _('force tag')),
6841 ('l', 'local', None, _('make the tag local')),
6839 ('l', 'local', None, _('make the tag local')),
6842 ('r', 'rev', '', _('revision to tag'), _('REV')),
6840 ('r', 'rev', '', _('revision to tag'), _('REV')),
6843 ('', 'remove', None, _('remove a tag')),
6841 ('', 'remove', None, _('remove a tag')),
6844 # -l/--local is already there, commitopts cannot be used
6842 # -l/--local is already there, commitopts cannot be used
6845 ('e', 'edit', None, _('invoke editor on commit messages')),
6843 ('e', 'edit', None, _('invoke editor on commit messages')),
6846 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6844 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6847 ] + commitopts2,
6845 ] + commitopts2,
6848 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6846 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6849 def tag(ui, repo, name1, *names, **opts):
6847 def tag(ui, repo, name1, *names, **opts):
6850 """add one or more tags for the current or given revision
6848 """add one or more tags for the current or given revision
6851
6849
6852 Name a particular revision using <name>.
6850 Name a particular revision using <name>.
6853
6851
6854 Tags are used to name particular revisions of the repository and are
6852 Tags are used to name particular revisions of the repository and are
6855 very useful to compare different revisions, to go back to significant
6853 very useful to compare different revisions, to go back to significant
6856 earlier versions or to mark branch points as releases, etc. Changing
6854 earlier versions or to mark branch points as releases, etc. Changing
6857 an existing tag is normally disallowed; use -f/--force to override.
6855 an existing tag is normally disallowed; use -f/--force to override.
6858
6856
6859 If no revision is given, the parent of the working directory is
6857 If no revision is given, the parent of the working directory is
6860 used.
6858 used.
6861
6859
6862 To facilitate version control, distribution, and merging of tags,
6860 To facilitate version control, distribution, and merging of tags,
6863 they are stored as a file named ".hgtags" which is managed similarly
6861 they are stored as a file named ".hgtags" which is managed similarly
6864 to other project files and can be hand-edited if necessary. This
6862 to other project files and can be hand-edited if necessary. This
6865 also means that tagging creates a new commit. The file
6863 also means that tagging creates a new commit. The file
6866 ".hg/localtags" is used for local tags (not shared among
6864 ".hg/localtags" is used for local tags (not shared among
6867 repositories).
6865 repositories).
6868
6866
6869 Tag commits are usually made at the head of a branch. If the parent
6867 Tag commits are usually made at the head of a branch. If the parent
6870 of the working directory is not a branch head, :hg:`tag` aborts; use
6868 of the working directory is not a branch head, :hg:`tag` aborts; use
6871 -f/--force to force the tag commit to be based on a non-head
6869 -f/--force to force the tag commit to be based on a non-head
6872 changeset.
6870 changeset.
6873
6871
6874 See :hg:`help dates` for a list of formats valid for -d/--date.
6872 See :hg:`help dates` for a list of formats valid for -d/--date.
6875
6873
6876 Since tag names have priority over branch names during revision
6874 Since tag names have priority over branch names during revision
6877 lookup, using an existing branch name as a tag name is discouraged.
6875 lookup, using an existing branch name as a tag name is discouraged.
6878
6876
6879 Returns 0 on success.
6877 Returns 0 on success.
6880 """
6878 """
6881 wlock = lock = None
6879 wlock = lock = None
6882 try:
6880 try:
6883 wlock = repo.wlock()
6881 wlock = repo.wlock()
6884 lock = repo.lock()
6882 lock = repo.lock()
6885 rev_ = "."
6883 rev_ = "."
6886 names = [t.strip() for t in (name1,) + names]
6884 names = [t.strip() for t in (name1,) + names]
6887 if len(names) != len(set(names)):
6885 if len(names) != len(set(names)):
6888 raise error.Abort(_('tag names must be unique'))
6886 raise error.Abort(_('tag names must be unique'))
6889 for n in names:
6887 for n in names:
6890 scmutil.checknewlabel(repo, n, 'tag')
6888 scmutil.checknewlabel(repo, n, 'tag')
6891 if not n:
6889 if not n:
6892 raise error.Abort(_('tag names cannot consist entirely of '
6890 raise error.Abort(_('tag names cannot consist entirely of '
6893 'whitespace'))
6891 'whitespace'))
6894 if opts.get('rev') and opts.get('remove'):
6892 if opts.get('rev') and opts.get('remove'):
6895 raise error.Abort(_("--rev and --remove are incompatible"))
6893 raise error.Abort(_("--rev and --remove are incompatible"))
6896 if opts.get('rev'):
6894 if opts.get('rev'):
6897 rev_ = opts['rev']
6895 rev_ = opts['rev']
6898 message = opts.get('message')
6896 message = opts.get('message')
6899 if opts.get('remove'):
6897 if opts.get('remove'):
6900 if opts.get('local'):
6898 if opts.get('local'):
6901 expectedtype = 'local'
6899 expectedtype = 'local'
6902 else:
6900 else:
6903 expectedtype = 'global'
6901 expectedtype = 'global'
6904
6902
6905 for n in names:
6903 for n in names:
6906 if not repo.tagtype(n):
6904 if not repo.tagtype(n):
6907 raise error.Abort(_("tag '%s' does not exist") % n)
6905 raise error.Abort(_("tag '%s' does not exist") % n)
6908 if repo.tagtype(n) != expectedtype:
6906 if repo.tagtype(n) != expectedtype:
6909 if expectedtype == 'global':
6907 if expectedtype == 'global':
6910 raise error.Abort(_("tag '%s' is not a global tag") % n)
6908 raise error.Abort(_("tag '%s' is not a global tag") % n)
6911 else:
6909 else:
6912 raise error.Abort(_("tag '%s' is not a local tag") % n)
6910 raise error.Abort(_("tag '%s' is not a local tag") % n)
6913 rev_ = 'null'
6911 rev_ = 'null'
6914 if not message:
6912 if not message:
6915 # we don't translate commit messages
6913 # we don't translate commit messages
6916 message = 'Removed tag %s' % ', '.join(names)
6914 message = 'Removed tag %s' % ', '.join(names)
6917 elif not opts.get('force'):
6915 elif not opts.get('force'):
6918 for n in names:
6916 for n in names:
6919 if n in repo.tags():
6917 if n in repo.tags():
6920 raise error.Abort(_("tag '%s' already exists "
6918 raise error.Abort(_("tag '%s' already exists "
6921 "(use -f to force)") % n)
6919 "(use -f to force)") % n)
6922 if not opts.get('local'):
6920 if not opts.get('local'):
6923 p1, p2 = repo.dirstate.parents()
6921 p1, p2 = repo.dirstate.parents()
6924 if p2 != nullid:
6922 if p2 != nullid:
6925 raise error.Abort(_('uncommitted merge'))
6923 raise error.Abort(_('uncommitted merge'))
6926 bheads = repo.branchheads()
6924 bheads = repo.branchheads()
6927 if not opts.get('force') and bheads and p1 not in bheads:
6925 if not opts.get('force') and bheads and p1 not in bheads:
6928 raise error.Abort(_('not at a branch head (use -f to force)'))
6926 raise error.Abort(_('not at a branch head (use -f to force)'))
6929 r = scmutil.revsingle(repo, rev_).node()
6927 r = scmutil.revsingle(repo, rev_).node()
6930
6928
6931 if not message:
6929 if not message:
6932 # we don't translate commit messages
6930 # we don't translate commit messages
6933 message = ('Added tag %s for changeset %s' %
6931 message = ('Added tag %s for changeset %s' %
6934 (', '.join(names), short(r)))
6932 (', '.join(names), short(r)))
6935
6933
6936 date = opts.get('date')
6934 date = opts.get('date')
6937 if date:
6935 if date:
6938 date = util.parsedate(date)
6936 date = util.parsedate(date)
6939
6937
6940 if opts.get('remove'):
6938 if opts.get('remove'):
6941 editform = 'tag.remove'
6939 editform = 'tag.remove'
6942 else:
6940 else:
6943 editform = 'tag.add'
6941 editform = 'tag.add'
6944 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6942 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6945
6943
6946 # don't allow tagging the null rev
6944 # don't allow tagging the null rev
6947 if (not opts.get('remove') and
6945 if (not opts.get('remove') and
6948 scmutil.revsingle(repo, rev_).rev() == nullrev):
6946 scmutil.revsingle(repo, rev_).rev() == nullrev):
6949 raise error.Abort(_("cannot tag null revision"))
6947 raise error.Abort(_("cannot tag null revision"))
6950
6948
6951 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6949 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6952 editor=editor)
6950 editor=editor)
6953 finally:
6951 finally:
6954 release(lock, wlock)
6952 release(lock, wlock)
6955
6953
6956 @command('tags', formatteropts, '')
6954 @command('tags', formatteropts, '')
6957 def tags(ui, repo, **opts):
6955 def tags(ui, repo, **opts):
6958 """list repository tags
6956 """list repository tags
6959
6957
6960 This lists both regular and local tags. When the -v/--verbose
6958 This lists both regular and local tags. When the -v/--verbose
6961 switch is used, a third column "local" is printed for local tags.
6959 switch is used, a third column "local" is printed for local tags.
6962 When the -q/--quiet switch is used, only the tag name is printed.
6960 When the -q/--quiet switch is used, only the tag name is printed.
6963
6961
6964 Returns 0 on success.
6962 Returns 0 on success.
6965 """
6963 """
6966
6964
6967 fm = ui.formatter('tags', opts)
6965 fm = ui.formatter('tags', opts)
6968 hexfunc = fm.hexfunc
6966 hexfunc = fm.hexfunc
6969 tagtype = ""
6967 tagtype = ""
6970
6968
6971 for t, n in reversed(repo.tagslist()):
6969 for t, n in reversed(repo.tagslist()):
6972 hn = hexfunc(n)
6970 hn = hexfunc(n)
6973 label = 'tags.normal'
6971 label = 'tags.normal'
6974 tagtype = ''
6972 tagtype = ''
6975 if repo.tagtype(t) == 'local':
6973 if repo.tagtype(t) == 'local':
6976 label = 'tags.local'
6974 label = 'tags.local'
6977 tagtype = 'local'
6975 tagtype = 'local'
6978
6976
6979 fm.startitem()
6977 fm.startitem()
6980 fm.write('tag', '%s', t, label=label)
6978 fm.write('tag', '%s', t, label=label)
6981 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6979 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6982 fm.condwrite(not ui.quiet, 'rev node', fmt,
6980 fm.condwrite(not ui.quiet, 'rev node', fmt,
6983 repo.changelog.rev(n), hn, label=label)
6981 repo.changelog.rev(n), hn, label=label)
6984 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6982 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6985 tagtype, label=label)
6983 tagtype, label=label)
6986 fm.plain('\n')
6984 fm.plain('\n')
6987 fm.end()
6985 fm.end()
6988
6986
6989 @command('tip',
6987 @command('tip',
6990 [('p', 'patch', None, _('show patch')),
6988 [('p', 'patch', None, _('show patch')),
6991 ('g', 'git', None, _('use git extended diff format')),
6989 ('g', 'git', None, _('use git extended diff format')),
6992 ] + templateopts,
6990 ] + templateopts,
6993 _('[-p] [-g]'))
6991 _('[-p] [-g]'))
6994 def tip(ui, repo, **opts):
6992 def tip(ui, repo, **opts):
6995 """show the tip revision (DEPRECATED)
6993 """show the tip revision (DEPRECATED)
6996
6994
6997 The tip revision (usually just called the tip) is the changeset
6995 The tip revision (usually just called the tip) is the changeset
6998 most recently added to the repository (and therefore the most
6996 most recently added to the repository (and therefore the most
6999 recently changed head).
6997 recently changed head).
7000
6998
7001 If you have just made a commit, that commit will be the tip. If
6999 If you have just made a commit, that commit will be the tip. If
7002 you have just pulled changes from another repository, the tip of
7000 you have just pulled changes from another repository, the tip of
7003 that repository becomes the current tip. The "tip" tag is special
7001 that repository becomes the current tip. The "tip" tag is special
7004 and cannot be renamed or assigned to a different changeset.
7002 and cannot be renamed or assigned to a different changeset.
7005
7003
7006 This command is deprecated, please use :hg:`heads` instead.
7004 This command is deprecated, please use :hg:`heads` instead.
7007
7005
7008 Returns 0 on success.
7006 Returns 0 on success.
7009 """
7007 """
7010 displayer = cmdutil.show_changeset(ui, repo, opts)
7008 displayer = cmdutil.show_changeset(ui, repo, opts)
7011 displayer.show(repo['tip'])
7009 displayer.show(repo['tip'])
7012 displayer.close()
7010 displayer.close()
7013
7011
7014 @command('unbundle',
7012 @command('unbundle',
7015 [('u', 'update', None,
7013 [('u', 'update', None,
7016 _('update to new branch head if changesets were unbundled'))],
7014 _('update to new branch head if changesets were unbundled'))],
7017 _('[-u] FILE...'))
7015 _('[-u] FILE...'))
7018 def unbundle(ui, repo, fname1, *fnames, **opts):
7016 def unbundle(ui, repo, fname1, *fnames, **opts):
7019 """apply one or more changegroup files
7017 """apply one or more changegroup files
7020
7018
7021 Apply one or more compressed changegroup files generated by the
7019 Apply one or more compressed changegroup files generated by the
7022 bundle command.
7020 bundle command.
7023
7021
7024 Returns 0 on success, 1 if an update has unresolved files.
7022 Returns 0 on success, 1 if an update has unresolved files.
7025 """
7023 """
7026 fnames = (fname1,) + fnames
7024 fnames = (fname1,) + fnames
7027
7025
7028 with repo.lock():
7026 with repo.lock():
7029 for fname in fnames:
7027 for fname in fnames:
7030 f = hg.openpath(ui, fname)
7028 f = hg.openpath(ui, fname)
7031 gen = exchange.readbundle(ui, f, fname)
7029 gen = exchange.readbundle(ui, f, fname)
7032 if isinstance(gen, bundle2.unbundle20):
7030 if isinstance(gen, bundle2.unbundle20):
7033 tr = repo.transaction('unbundle')
7031 tr = repo.transaction('unbundle')
7034 try:
7032 try:
7035 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7033 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7036 url='bundle:' + fname)
7034 url='bundle:' + fname)
7037 tr.close()
7035 tr.close()
7038 except error.BundleUnknownFeatureError as exc:
7036 except error.BundleUnknownFeatureError as exc:
7039 raise error.Abort(_('%s: unknown bundle feature, %s')
7037 raise error.Abort(_('%s: unknown bundle feature, %s')
7040 % (fname, exc),
7038 % (fname, exc),
7041 hint=_("see https://mercurial-scm.org/"
7039 hint=_("see https://mercurial-scm.org/"
7042 "wiki/BundleFeature for more "
7040 "wiki/BundleFeature for more "
7043 "information"))
7041 "information"))
7044 finally:
7042 finally:
7045 if tr:
7043 if tr:
7046 tr.release()
7044 tr.release()
7047 changes = [r.get('return', 0)
7045 changes = [r.get('return', 0)
7048 for r in op.records['changegroup']]
7046 for r in op.records['changegroup']]
7049 modheads = changegroup.combineresults(changes)
7047 modheads = changegroup.combineresults(changes)
7050 elif isinstance(gen, streamclone.streamcloneapplier):
7048 elif isinstance(gen, streamclone.streamcloneapplier):
7051 raise error.Abort(
7049 raise error.Abort(
7052 _('packed bundles cannot be applied with '
7050 _('packed bundles cannot be applied with '
7053 '"hg unbundle"'),
7051 '"hg unbundle"'),
7054 hint=_('use "hg debugapplystreamclonebundle"'))
7052 hint=_('use "hg debugapplystreamclonebundle"'))
7055 else:
7053 else:
7056 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7054 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7057
7055
7058 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7056 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7059
7057
7060 @command('^update|up|checkout|co',
7058 @command('^update|up|checkout|co',
7061 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7059 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7062 ('c', 'check', None,
7060 ('c', 'check', None,
7063 _('update across branches if no uncommitted changes')),
7061 _('update across branches if no uncommitted changes')),
7064 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7062 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7065 ('r', 'rev', '', _('revision'), _('REV'))
7063 ('r', 'rev', '', _('revision'), _('REV'))
7066 ] + mergetoolopts,
7064 ] + mergetoolopts,
7067 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7065 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7068 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7066 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7069 tool=None):
7067 tool=None):
7070 """update working directory (or switch revisions)
7068 """update working directory (or switch revisions)
7071
7069
7072 Update the repository's working directory to the specified
7070 Update the repository's working directory to the specified
7073 changeset. If no changeset is specified, update to the tip of the
7071 changeset. If no changeset is specified, update to the tip of the
7074 current named branch and move the active bookmark (see :hg:`help
7072 current named branch and move the active bookmark (see :hg:`help
7075 bookmarks`).
7073 bookmarks`).
7076
7074
7077 Update sets the working directory's parent revision to the specified
7075 Update sets the working directory's parent revision to the specified
7078 changeset (see :hg:`help parents`).
7076 changeset (see :hg:`help parents`).
7079
7077
7080 If the changeset is not a descendant or ancestor of the working
7078 If the changeset is not a descendant or ancestor of the working
7081 directory's parent, the update is aborted. With the -c/--check
7079 directory's parent, the update is aborted. With the -c/--check
7082 option, the working directory is checked for uncommitted changes; if
7080 option, the working directory is checked for uncommitted changes; if
7083 none are found, the working directory is updated to the specified
7081 none are found, the working directory is updated to the specified
7084 changeset.
7082 changeset.
7085
7083
7086 .. container:: verbose
7084 .. container:: verbose
7087
7085
7088 The following rules apply when the working directory contains
7086 The following rules apply when the working directory contains
7089 uncommitted changes:
7087 uncommitted changes:
7090
7088
7091 1. If neither -c/--check nor -C/--clean is specified, and if
7089 1. If neither -c/--check nor -C/--clean is specified, and if
7092 the requested changeset is an ancestor or descendant of
7090 the requested changeset is an ancestor or descendant of
7093 the working directory's parent, the uncommitted changes
7091 the working directory's parent, the uncommitted changes
7094 are merged into the requested changeset and the merged
7092 are merged into the requested changeset and the merged
7095 result is left uncommitted. If the requested changeset is
7093 result is left uncommitted. If the requested changeset is
7096 not an ancestor or descendant (that is, it is on another
7094 not an ancestor or descendant (that is, it is on another
7097 branch), the update is aborted and the uncommitted changes
7095 branch), the update is aborted and the uncommitted changes
7098 are preserved.
7096 are preserved.
7099
7097
7100 2. With the -c/--check option, the update is aborted and the
7098 2. With the -c/--check option, the update is aborted and the
7101 uncommitted changes are preserved.
7099 uncommitted changes are preserved.
7102
7100
7103 3. With the -C/--clean option, uncommitted changes are discarded and
7101 3. With the -C/--clean option, uncommitted changes are discarded and
7104 the working directory is updated to the requested changeset.
7102 the working directory is updated to the requested changeset.
7105
7103
7106 To cancel an uncommitted merge (and lose your changes), use
7104 To cancel an uncommitted merge (and lose your changes), use
7107 :hg:`update --clean .`.
7105 :hg:`update --clean .`.
7108
7106
7109 Use null as the changeset to remove the working directory (like
7107 Use null as the changeset to remove the working directory (like
7110 :hg:`clone -U`).
7108 :hg:`clone -U`).
7111
7109
7112 If you want to revert just one file to an older revision, use
7110 If you want to revert just one file to an older revision, use
7113 :hg:`revert [-r REV] NAME`.
7111 :hg:`revert [-r REV] NAME`.
7114
7112
7115 See :hg:`help dates` for a list of formats valid for -d/--date.
7113 See :hg:`help dates` for a list of formats valid for -d/--date.
7116
7114
7117 Returns 0 on success, 1 if there are unresolved files.
7115 Returns 0 on success, 1 if there are unresolved files.
7118 """
7116 """
7119 if rev and node:
7117 if rev and node:
7120 raise error.Abort(_("please specify just one revision"))
7118 raise error.Abort(_("please specify just one revision"))
7121
7119
7122 if rev is None or rev == '':
7120 if rev is None or rev == '':
7123 rev = node
7121 rev = node
7124
7122
7125 if date and rev is not None:
7123 if date and rev is not None:
7126 raise error.Abort(_("you can't specify a revision and a date"))
7124 raise error.Abort(_("you can't specify a revision and a date"))
7127
7125
7128 if check and clean:
7126 if check and clean:
7129 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7127 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7130
7128
7131 with repo.wlock():
7129 with repo.wlock():
7132 cmdutil.clearunfinished(repo)
7130 cmdutil.clearunfinished(repo)
7133
7131
7134 if date:
7132 if date:
7135 rev = cmdutil.finddate(ui, repo, date)
7133 rev = cmdutil.finddate(ui, repo, date)
7136
7134
7137 # if we defined a bookmark, we have to remember the original name
7135 # if we defined a bookmark, we have to remember the original name
7138 brev = rev
7136 brev = rev
7139 rev = scmutil.revsingle(repo, rev, rev).rev()
7137 rev = scmutil.revsingle(repo, rev, rev).rev()
7140
7138
7141 if check:
7139 if check:
7142 cmdutil.bailifchanged(repo, merge=False)
7140 cmdutil.bailifchanged(repo, merge=False)
7143
7141
7144 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7142 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7145
7143
7146 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7144 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7147
7145
7148 @command('verify', [])
7146 @command('verify', [])
7149 def verify(ui, repo):
7147 def verify(ui, repo):
7150 """verify the integrity of the repository
7148 """verify the integrity of the repository
7151
7149
7152 Verify the integrity of the current repository.
7150 Verify the integrity of the current repository.
7153
7151
7154 This will perform an extensive check of the repository's
7152 This will perform an extensive check of the repository's
7155 integrity, validating the hashes and checksums of each entry in
7153 integrity, validating the hashes and checksums of each entry in
7156 the changelog, manifest, and tracked files, as well as the
7154 the changelog, manifest, and tracked files, as well as the
7157 integrity of their crosslinks and indices.
7155 integrity of their crosslinks and indices.
7158
7156
7159 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7157 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7160 for more information about recovery from corruption of the
7158 for more information about recovery from corruption of the
7161 repository.
7159 repository.
7162
7160
7163 Returns 0 on success, 1 if errors are encountered.
7161 Returns 0 on success, 1 if errors are encountered.
7164 """
7162 """
7165 return hg.verify(repo)
7163 return hg.verify(repo)
7166
7164
7167 @command('version', [], norepo=True)
7165 @command('version', [], norepo=True)
7168 def version_(ui):
7166 def version_(ui):
7169 """output version and copyright information"""
7167 """output version and copyright information"""
7170 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7168 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7171 % util.version())
7169 % util.version())
7172 ui.status(_(
7170 ui.status(_(
7173 "(see https://mercurial-scm.org for more information)\n"
7171 "(see https://mercurial-scm.org for more information)\n"
7174 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7172 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7175 "This is free software; see the source for copying conditions. "
7173 "This is free software; see the source for copying conditions. "
7176 "There is NO\nwarranty; "
7174 "There is NO\nwarranty; "
7177 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7175 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7178 ))
7176 ))
7179
7177
7180 ui.note(_("\nEnabled extensions:\n\n"))
7178 ui.note(_("\nEnabled extensions:\n\n"))
7181 if ui.verbose:
7179 if ui.verbose:
7182 # format names and versions into columns
7180 # format names and versions into columns
7183 names = []
7181 names = []
7184 vers = []
7182 vers = []
7185 place = []
7183 place = []
7186 for name, module in extensions.extensions():
7184 for name, module in extensions.extensions():
7187 names.append(name)
7185 names.append(name)
7188 vers.append(extensions.moduleversion(module))
7186 vers.append(extensions.moduleversion(module))
7189 if extensions.ismoduleinternal(module):
7187 if extensions.ismoduleinternal(module):
7190 place.append(_("internal"))
7188 place.append(_("internal"))
7191 else:
7189 else:
7192 place.append(_("external"))
7190 place.append(_("external"))
7193 if names:
7191 if names:
7194 maxnamelen = max(len(n) for n in names)
7192 maxnamelen = max(len(n) for n in names)
7195 for i, name in enumerate(names):
7193 for i, name in enumerate(names):
7196 ui.write(" %-*s %s %s\n" %
7194 ui.write(" %-*s %s %s\n" %
7197 (maxnamelen, name, place[i], vers[i]))
7195 (maxnamelen, name, place[i], vers[i]))
7198
7196
7199 def loadcmdtable(ui, name, cmdtable):
7197 def loadcmdtable(ui, name, cmdtable):
7200 """Load command functions from specified cmdtable
7198 """Load command functions from specified cmdtable
7201 """
7199 """
7202 overrides = [cmd for cmd in cmdtable if cmd in table]
7200 overrides = [cmd for cmd in cmdtable if cmd in table]
7203 if overrides:
7201 if overrides:
7204 ui.warn(_("extension '%s' overrides commands: %s\n")
7202 ui.warn(_("extension '%s' overrides commands: %s\n")
7205 % (name, " ".join(overrides)))
7203 % (name, " ".join(overrides)))
7206 table.update(cmdtable)
7204 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now