##// END OF EJS Templates
commands: disallow 'hg debugobsolete --index --rev <smth>'...
Kostia Balytskyi -
r28794:2637d6ad default
parent child Browse files
Show More
@@ -1,7207 +1,7210 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 cgversion not in changegroup.supportedoutgoingversions(repo):
1402 if cgversion not in changegroup.supportedoutgoingversions(repo):
1403 raise error.Abort(_("repository does not support bundle version %s") %
1403 raise error.Abort(_("repository does not support bundle version %s") %
1404 cgversion)
1404 cgversion)
1405
1405
1406 if base:
1406 if base:
1407 if dest:
1407 if dest:
1408 raise error.Abort(_("--base is incompatible with specifying "
1408 raise error.Abort(_("--base is incompatible with specifying "
1409 "a destination"))
1409 "a destination"))
1410 common = [repo.lookup(rev) for rev in base]
1410 common = [repo.lookup(rev) for rev in base]
1411 heads = revs and map(repo.lookup, revs) or revs
1411 heads = revs and map(repo.lookup, revs) or revs
1412 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1412 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1413 common=common, bundlecaps=bundlecaps,
1413 common=common, bundlecaps=bundlecaps,
1414 version=cgversion)
1414 version=cgversion)
1415 outgoing = None
1415 outgoing = None
1416 else:
1416 else:
1417 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1417 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1418 dest, branches = hg.parseurl(dest, opts.get('branch'))
1418 dest, branches = hg.parseurl(dest, opts.get('branch'))
1419 other = hg.peer(repo, opts, dest)
1419 other = hg.peer(repo, opts, dest)
1420 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1420 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1421 heads = revs and map(repo.lookup, revs) or revs
1421 heads = revs and map(repo.lookup, revs) or revs
1422 outgoing = discovery.findcommonoutgoing(repo, other,
1422 outgoing = discovery.findcommonoutgoing(repo, other,
1423 onlyheads=heads,
1423 onlyheads=heads,
1424 force=opts.get('force'),
1424 force=opts.get('force'),
1425 portable=True)
1425 portable=True)
1426 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1426 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1427 bundlecaps, version=cgversion)
1427 bundlecaps, version=cgversion)
1428 if not cg:
1428 if not cg:
1429 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1429 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1430 return 1
1430 return 1
1431
1431
1432 if cgversion == '01': #bundle1
1432 if cgversion == '01': #bundle1
1433 if bcompression is None:
1433 if bcompression is None:
1434 bcompression = 'UN'
1434 bcompression = 'UN'
1435 bversion = 'HG10' + bcompression
1435 bversion = 'HG10' + bcompression
1436 bcompression = None
1436 bcompression = None
1437 else:
1437 else:
1438 assert cgversion == '02'
1438 assert cgversion == '02'
1439 bversion = 'HG20'
1439 bversion = 'HG20'
1440
1440
1441 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1441 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1442
1442
1443 @command('cat',
1443 @command('cat',
1444 [('o', 'output', '',
1444 [('o', 'output', '',
1445 _('print output to file with formatted name'), _('FORMAT')),
1445 _('print output to file with formatted name'), _('FORMAT')),
1446 ('r', 'rev', '', _('print the given revision'), _('REV')),
1446 ('r', 'rev', '', _('print the given revision'), _('REV')),
1447 ('', 'decode', None, _('apply any matching decode filter')),
1447 ('', 'decode', None, _('apply any matching decode filter')),
1448 ] + walkopts,
1448 ] + walkopts,
1449 _('[OPTION]... FILE...'),
1449 _('[OPTION]... FILE...'),
1450 inferrepo=True)
1450 inferrepo=True)
1451 def cat(ui, repo, file1, *pats, **opts):
1451 def cat(ui, repo, file1, *pats, **opts):
1452 """output the current or given revision of files
1452 """output the current or given revision of files
1453
1453
1454 Print the specified files as they were at the given revision. If
1454 Print the specified files as they were at the given revision. If
1455 no revision is given, the parent of the working directory is used.
1455 no revision is given, the parent of the working directory is used.
1456
1456
1457 Output may be to a file, in which case the name of the file is
1457 Output may be to a file, in which case the name of the file is
1458 given using a format string. The formatting rules as follows:
1458 given using a format string. The formatting rules as follows:
1459
1459
1460 :``%%``: literal "%" character
1460 :``%%``: literal "%" character
1461 :``%s``: basename of file being printed
1461 :``%s``: basename of file being printed
1462 :``%d``: dirname of file being printed, or '.' if in repository root
1462 :``%d``: dirname of file being printed, or '.' if in repository root
1463 :``%p``: root-relative path name of file being printed
1463 :``%p``: root-relative path name of file being printed
1464 :``%H``: changeset hash (40 hexadecimal digits)
1464 :``%H``: changeset hash (40 hexadecimal digits)
1465 :``%R``: changeset revision number
1465 :``%R``: changeset revision number
1466 :``%h``: short-form changeset hash (12 hexadecimal digits)
1466 :``%h``: short-form changeset hash (12 hexadecimal digits)
1467 :``%r``: zero-padded changeset revision number
1467 :``%r``: zero-padded changeset revision number
1468 :``%b``: basename of the exporting repository
1468 :``%b``: basename of the exporting repository
1469
1469
1470 Returns 0 on success.
1470 Returns 0 on success.
1471 """
1471 """
1472 ctx = scmutil.revsingle(repo, opts.get('rev'))
1472 ctx = scmutil.revsingle(repo, opts.get('rev'))
1473 m = scmutil.match(ctx, (file1,) + pats, opts)
1473 m = scmutil.match(ctx, (file1,) + pats, opts)
1474
1474
1475 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1475 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1476
1476
1477 @command('^clone',
1477 @command('^clone',
1478 [('U', 'noupdate', None, _('the clone will include an empty working '
1478 [('U', 'noupdate', None, _('the clone will include an empty working '
1479 'directory (only a repository)')),
1479 'directory (only a repository)')),
1480 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1480 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1481 _('REV')),
1481 _('REV')),
1482 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1482 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1483 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1483 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1484 ('', 'pull', None, _('use pull protocol to copy metadata')),
1484 ('', 'pull', None, _('use pull protocol to copy metadata')),
1485 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1485 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1486 ] + remoteopts,
1486 ] + remoteopts,
1487 _('[OPTION]... SOURCE [DEST]'),
1487 _('[OPTION]... SOURCE [DEST]'),
1488 norepo=True)
1488 norepo=True)
1489 def clone(ui, source, dest=None, **opts):
1489 def clone(ui, source, dest=None, **opts):
1490 """make a copy of an existing repository
1490 """make a copy of an existing repository
1491
1491
1492 Create a copy of an existing repository in a new directory.
1492 Create a copy of an existing repository in a new directory.
1493
1493
1494 If no destination directory name is specified, it defaults to the
1494 If no destination directory name is specified, it defaults to the
1495 basename of the source.
1495 basename of the source.
1496
1496
1497 The location of the source is added to the new repository's
1497 The location of the source is added to the new repository's
1498 ``.hg/hgrc`` file, as the default to be used for future pulls.
1498 ``.hg/hgrc`` file, as the default to be used for future pulls.
1499
1499
1500 Only local paths and ``ssh://`` URLs are supported as
1500 Only local paths and ``ssh://`` URLs are supported as
1501 destinations. For ``ssh://`` destinations, no working directory or
1501 destinations. For ``ssh://`` destinations, no working directory or
1502 ``.hg/hgrc`` will be created on the remote side.
1502 ``.hg/hgrc`` will be created on the remote side.
1503
1503
1504 If the source repository has a bookmark called '@' set, that
1504 If the source repository has a bookmark called '@' set, that
1505 revision will be checked out in the new repository by default.
1505 revision will be checked out in the new repository by default.
1506
1506
1507 To check out a particular version, use -u/--update, or
1507 To check out a particular version, use -u/--update, or
1508 -U/--noupdate to create a clone with no working directory.
1508 -U/--noupdate to create a clone with no working directory.
1509
1509
1510 To pull only a subset of changesets, specify one or more revisions
1510 To pull only a subset of changesets, specify one or more revisions
1511 identifiers with -r/--rev or branches with -b/--branch. The
1511 identifiers with -r/--rev or branches with -b/--branch. The
1512 resulting clone will contain only the specified changesets and
1512 resulting clone will contain only the specified changesets and
1513 their ancestors. These options (or 'clone src#rev dest') imply
1513 their ancestors. These options (or 'clone src#rev dest') imply
1514 --pull, even for local source repositories.
1514 --pull, even for local source repositories.
1515
1515
1516 .. note::
1516 .. note::
1517
1517
1518 Specifying a tag will include the tagged changeset but not the
1518 Specifying a tag will include the tagged changeset but not the
1519 changeset containing the tag.
1519 changeset containing the tag.
1520
1520
1521 .. container:: verbose
1521 .. container:: verbose
1522
1522
1523 For efficiency, hardlinks are used for cloning whenever the
1523 For efficiency, hardlinks are used for cloning whenever the
1524 source and destination are on the same filesystem (note this
1524 source and destination are on the same filesystem (note this
1525 applies only to the repository data, not to the working
1525 applies only to the repository data, not to the working
1526 directory). Some filesystems, such as AFS, implement hardlinking
1526 directory). Some filesystems, such as AFS, implement hardlinking
1527 incorrectly, but do not report errors. In these cases, use the
1527 incorrectly, but do not report errors. In these cases, use the
1528 --pull option to avoid hardlinking.
1528 --pull option to avoid hardlinking.
1529
1529
1530 In some cases, you can clone repositories and the working
1530 In some cases, you can clone repositories and the working
1531 directory using full hardlinks with ::
1531 directory using full hardlinks with ::
1532
1532
1533 $ cp -al REPO REPOCLONE
1533 $ cp -al REPO REPOCLONE
1534
1534
1535 This is the fastest way to clone, but it is not always safe. The
1535 This is the fastest way to clone, but it is not always safe. The
1536 operation is not atomic (making sure REPO is not modified during
1536 operation is not atomic (making sure REPO is not modified during
1537 the operation is up to you) and you have to make sure your
1537 the operation is up to you) and you have to make sure your
1538 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1538 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1539 so). Also, this is not compatible with certain extensions that
1539 so). Also, this is not compatible with certain extensions that
1540 place their metadata under the .hg directory, such as mq.
1540 place their metadata under the .hg directory, such as mq.
1541
1541
1542 Mercurial will update the working directory to the first applicable
1542 Mercurial will update the working directory to the first applicable
1543 revision from this list:
1543 revision from this list:
1544
1544
1545 a) null if -U or the source repository has no changesets
1545 a) null if -U or the source repository has no changesets
1546 b) if -u . and the source repository is local, the first parent of
1546 b) if -u . and the source repository is local, the first parent of
1547 the source repository's working directory
1547 the source repository's working directory
1548 c) the changeset specified with -u (if a branch name, this means the
1548 c) the changeset specified with -u (if a branch name, this means the
1549 latest head of that branch)
1549 latest head of that branch)
1550 d) the changeset specified with -r
1550 d) the changeset specified with -r
1551 e) the tipmost head specified with -b
1551 e) the tipmost head specified with -b
1552 f) the tipmost head specified with the url#branch source syntax
1552 f) the tipmost head specified with the url#branch source syntax
1553 g) the revision marked with the '@' bookmark, if present
1553 g) the revision marked with the '@' bookmark, if present
1554 h) the tipmost head of the default branch
1554 h) the tipmost head of the default branch
1555 i) tip
1555 i) tip
1556
1556
1557 When cloning from servers that support it, Mercurial may fetch
1557 When cloning from servers that support it, Mercurial may fetch
1558 pre-generated data from a server-advertised URL. When this is done,
1558 pre-generated data from a server-advertised URL. When this is done,
1559 hooks operating on incoming changesets and changegroups may fire twice,
1559 hooks operating on incoming changesets and changegroups may fire twice,
1560 once for the bundle fetched from the URL and another for any additional
1560 once for the bundle fetched from the URL and another for any additional
1561 data not fetched from this URL. In addition, if an error occurs, the
1561 data not fetched from this URL. In addition, if an error occurs, the
1562 repository may be rolled back to a partial clone. This behavior may
1562 repository may be rolled back to a partial clone. This behavior may
1563 change in future releases. See :hg:`help -e clonebundles` for more.
1563 change in future releases. See :hg:`help -e clonebundles` for more.
1564
1564
1565 Examples:
1565 Examples:
1566
1566
1567 - clone a remote repository to a new directory named hg/::
1567 - clone a remote repository to a new directory named hg/::
1568
1568
1569 hg clone http://selenic.com/hg
1569 hg clone http://selenic.com/hg
1570
1570
1571 - create a lightweight local clone::
1571 - create a lightweight local clone::
1572
1572
1573 hg clone project/ project-feature/
1573 hg clone project/ project-feature/
1574
1574
1575 - clone from an absolute path on an ssh server (note double-slash)::
1575 - clone from an absolute path on an ssh server (note double-slash)::
1576
1576
1577 hg clone ssh://user@server//home/projects/alpha/
1577 hg clone ssh://user@server//home/projects/alpha/
1578
1578
1579 - do a high-speed clone over a LAN while checking out a
1579 - do a high-speed clone over a LAN while checking out a
1580 specified version::
1580 specified version::
1581
1581
1582 hg clone --uncompressed http://server/repo -u 1.5
1582 hg clone --uncompressed http://server/repo -u 1.5
1583
1583
1584 - create a repository without changesets after a particular revision::
1584 - create a repository without changesets after a particular revision::
1585
1585
1586 hg clone -r 04e544 experimental/ good/
1586 hg clone -r 04e544 experimental/ good/
1587
1587
1588 - clone (and track) a particular named branch::
1588 - clone (and track) a particular named branch::
1589
1589
1590 hg clone http://selenic.com/hg#stable
1590 hg clone http://selenic.com/hg#stable
1591
1591
1592 See :hg:`help urls` for details on specifying URLs.
1592 See :hg:`help urls` for details on specifying URLs.
1593
1593
1594 Returns 0 on success.
1594 Returns 0 on success.
1595 """
1595 """
1596 if opts.get('noupdate') and opts.get('updaterev'):
1596 if opts.get('noupdate') and opts.get('updaterev'):
1597 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1597 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1598
1598
1599 r = hg.clone(ui, opts, source, dest,
1599 r = hg.clone(ui, opts, source, dest,
1600 pull=opts.get('pull'),
1600 pull=opts.get('pull'),
1601 stream=opts.get('uncompressed'),
1601 stream=opts.get('uncompressed'),
1602 rev=opts.get('rev'),
1602 rev=opts.get('rev'),
1603 update=opts.get('updaterev') or not opts.get('noupdate'),
1603 update=opts.get('updaterev') or not opts.get('noupdate'),
1604 branch=opts.get('branch'),
1604 branch=opts.get('branch'),
1605 shareopts=opts.get('shareopts'))
1605 shareopts=opts.get('shareopts'))
1606
1606
1607 return r is None
1607 return r is None
1608
1608
1609 @command('^commit|ci',
1609 @command('^commit|ci',
1610 [('A', 'addremove', None,
1610 [('A', 'addremove', None,
1611 _('mark new/missing files as added/removed before committing')),
1611 _('mark new/missing files as added/removed before committing')),
1612 ('', 'close-branch', None,
1612 ('', 'close-branch', None,
1613 _('mark a branch head as closed')),
1613 _('mark a branch head as closed')),
1614 ('', 'amend', None, _('amend the parent of the working directory')),
1614 ('', 'amend', None, _('amend the parent of the working directory')),
1615 ('s', 'secret', None, _('use the secret phase for committing')),
1615 ('s', 'secret', None, _('use the secret phase for committing')),
1616 ('e', 'edit', None, _('invoke editor on commit messages')),
1616 ('e', 'edit', None, _('invoke editor on commit messages')),
1617 ('i', 'interactive', None, _('use interactive mode')),
1617 ('i', 'interactive', None, _('use interactive mode')),
1618 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1618 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1619 _('[OPTION]... [FILE]...'),
1619 _('[OPTION]... [FILE]...'),
1620 inferrepo=True)
1620 inferrepo=True)
1621 def commit(ui, repo, *pats, **opts):
1621 def commit(ui, repo, *pats, **opts):
1622 """commit the specified files or all outstanding changes
1622 """commit the specified files or all outstanding changes
1623
1623
1624 Commit changes to the given files into the repository. Unlike a
1624 Commit changes to the given files into the repository. Unlike a
1625 centralized SCM, this operation is a local operation. See
1625 centralized SCM, this operation is a local operation. See
1626 :hg:`push` for a way to actively distribute your changes.
1626 :hg:`push` for a way to actively distribute your changes.
1627
1627
1628 If a list of files is omitted, all changes reported by :hg:`status`
1628 If a list of files is omitted, all changes reported by :hg:`status`
1629 will be committed.
1629 will be committed.
1630
1630
1631 If you are committing the result of a merge, do not provide any
1631 If you are committing the result of a merge, do not provide any
1632 filenames or -I/-X filters.
1632 filenames or -I/-X filters.
1633
1633
1634 If no commit message is specified, Mercurial starts your
1634 If no commit message is specified, Mercurial starts your
1635 configured editor where you can enter a message. In case your
1635 configured editor where you can enter a message. In case your
1636 commit fails, you will find a backup of your message in
1636 commit fails, you will find a backup of your message in
1637 ``.hg/last-message.txt``.
1637 ``.hg/last-message.txt``.
1638
1638
1639 The --close-branch flag can be used to mark the current branch
1639 The --close-branch flag can be used to mark the current branch
1640 head closed. When all heads of a branch are closed, the branch
1640 head closed. When all heads of a branch are closed, the branch
1641 will be considered closed and no longer listed.
1641 will be considered closed and no longer listed.
1642
1642
1643 The --amend flag can be used to amend the parent of the
1643 The --amend flag can be used to amend the parent of the
1644 working directory with a new commit that contains the changes
1644 working directory with a new commit that contains the changes
1645 in the parent in addition to those currently reported by :hg:`status`,
1645 in the parent in addition to those currently reported by :hg:`status`,
1646 if there are any. The old commit is stored in a backup bundle in
1646 if there are any. The old commit is stored in a backup bundle in
1647 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1647 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1648 on how to restore it).
1648 on how to restore it).
1649
1649
1650 Message, user and date are taken from the amended commit unless
1650 Message, user and date are taken from the amended commit unless
1651 specified. When a message isn't specified on the command line,
1651 specified. When a message isn't specified on the command line,
1652 the editor will open with the message of the amended commit.
1652 the editor will open with the message of the amended commit.
1653
1653
1654 It is not possible to amend public changesets (see :hg:`help phases`)
1654 It is not possible to amend public changesets (see :hg:`help phases`)
1655 or changesets that have children.
1655 or changesets that have children.
1656
1656
1657 See :hg:`help dates` for a list of formats valid for -d/--date.
1657 See :hg:`help dates` for a list of formats valid for -d/--date.
1658
1658
1659 Returns 0 on success, 1 if nothing changed.
1659 Returns 0 on success, 1 if nothing changed.
1660
1660
1661 .. container:: verbose
1661 .. container:: verbose
1662
1662
1663 Examples:
1663 Examples:
1664
1664
1665 - commit all files ending in .py::
1665 - commit all files ending in .py::
1666
1666
1667 hg commit --include "set:**.py"
1667 hg commit --include "set:**.py"
1668
1668
1669 - commit all non-binary files::
1669 - commit all non-binary files::
1670
1670
1671 hg commit --exclude "set:binary()"
1671 hg commit --exclude "set:binary()"
1672
1672
1673 - amend the current commit and set the date to now::
1673 - amend the current commit and set the date to now::
1674
1674
1675 hg commit --amend --date now
1675 hg commit --amend --date now
1676 """
1676 """
1677 wlock = lock = None
1677 wlock = lock = None
1678 try:
1678 try:
1679 wlock = repo.wlock()
1679 wlock = repo.wlock()
1680 lock = repo.lock()
1680 lock = repo.lock()
1681 return _docommit(ui, repo, *pats, **opts)
1681 return _docommit(ui, repo, *pats, **opts)
1682 finally:
1682 finally:
1683 release(lock, wlock)
1683 release(lock, wlock)
1684
1684
1685 def _docommit(ui, repo, *pats, **opts):
1685 def _docommit(ui, repo, *pats, **opts):
1686 if opts.get('interactive'):
1686 if opts.get('interactive'):
1687 opts.pop('interactive')
1687 opts.pop('interactive')
1688 cmdutil.dorecord(ui, repo, commit, None, False,
1688 cmdutil.dorecord(ui, repo, commit, None, False,
1689 cmdutil.recordfilter, *pats, **opts)
1689 cmdutil.recordfilter, *pats, **opts)
1690 return
1690 return
1691
1691
1692 if opts.get('subrepos'):
1692 if opts.get('subrepos'):
1693 if opts.get('amend'):
1693 if opts.get('amend'):
1694 raise error.Abort(_('cannot amend with --subrepos'))
1694 raise error.Abort(_('cannot amend with --subrepos'))
1695 # Let --subrepos on the command line override config setting.
1695 # Let --subrepos on the command line override config setting.
1696 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1696 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1697
1697
1698 cmdutil.checkunfinished(repo, commit=True)
1698 cmdutil.checkunfinished(repo, commit=True)
1699
1699
1700 branch = repo[None].branch()
1700 branch = repo[None].branch()
1701 bheads = repo.branchheads(branch)
1701 bheads = repo.branchheads(branch)
1702
1702
1703 extra = {}
1703 extra = {}
1704 if opts.get('close_branch'):
1704 if opts.get('close_branch'):
1705 extra['close'] = 1
1705 extra['close'] = 1
1706
1706
1707 if not bheads:
1707 if not bheads:
1708 raise error.Abort(_('can only close branch heads'))
1708 raise error.Abort(_('can only close branch heads'))
1709 elif opts.get('amend'):
1709 elif opts.get('amend'):
1710 if repo[None].parents()[0].p1().branch() != branch and \
1710 if repo[None].parents()[0].p1().branch() != branch and \
1711 repo[None].parents()[0].p2().branch() != branch:
1711 repo[None].parents()[0].p2().branch() != branch:
1712 raise error.Abort(_('can only close branch heads'))
1712 raise error.Abort(_('can only close branch heads'))
1713
1713
1714 if opts.get('amend'):
1714 if opts.get('amend'):
1715 if ui.configbool('ui', 'commitsubrepos'):
1715 if ui.configbool('ui', 'commitsubrepos'):
1716 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1716 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1717
1717
1718 old = repo['.']
1718 old = repo['.']
1719 if not old.mutable():
1719 if not old.mutable():
1720 raise error.Abort(_('cannot amend public changesets'))
1720 raise error.Abort(_('cannot amend public changesets'))
1721 if len(repo[None].parents()) > 1:
1721 if len(repo[None].parents()) > 1:
1722 raise error.Abort(_('cannot amend while merging'))
1722 raise error.Abort(_('cannot amend while merging'))
1723 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1723 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1724 if not allowunstable and old.children():
1724 if not allowunstable and old.children():
1725 raise error.Abort(_('cannot amend changeset with children'))
1725 raise error.Abort(_('cannot amend changeset with children'))
1726
1726
1727 # Currently histedit gets confused if an amend happens while histedit
1727 # Currently histedit gets confused if an amend happens while histedit
1728 # is in progress. Since we have a checkunfinished command, we are
1728 # is in progress. Since we have a checkunfinished command, we are
1729 # temporarily honoring it.
1729 # temporarily honoring it.
1730 #
1730 #
1731 # Note: eventually this guard will be removed. Please do not expect
1731 # Note: eventually this guard will be removed. Please do not expect
1732 # this behavior to remain.
1732 # this behavior to remain.
1733 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1733 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1734 cmdutil.checkunfinished(repo)
1734 cmdutil.checkunfinished(repo)
1735
1735
1736 # commitfunc is used only for temporary amend commit by cmdutil.amend
1736 # commitfunc is used only for temporary amend commit by cmdutil.amend
1737 def commitfunc(ui, repo, message, match, opts):
1737 def commitfunc(ui, repo, message, match, opts):
1738 return repo.commit(message,
1738 return repo.commit(message,
1739 opts.get('user') or old.user(),
1739 opts.get('user') or old.user(),
1740 opts.get('date') or old.date(),
1740 opts.get('date') or old.date(),
1741 match,
1741 match,
1742 extra=extra)
1742 extra=extra)
1743
1743
1744 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1744 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1745 if node == old.node():
1745 if node == old.node():
1746 ui.status(_("nothing changed\n"))
1746 ui.status(_("nothing changed\n"))
1747 return 1
1747 return 1
1748 else:
1748 else:
1749 def commitfunc(ui, repo, message, match, opts):
1749 def commitfunc(ui, repo, message, match, opts):
1750 backup = ui.backupconfig('phases', 'new-commit')
1750 backup = ui.backupconfig('phases', 'new-commit')
1751 baseui = repo.baseui
1751 baseui = repo.baseui
1752 basebackup = baseui.backupconfig('phases', 'new-commit')
1752 basebackup = baseui.backupconfig('phases', 'new-commit')
1753 try:
1753 try:
1754 if opts.get('secret'):
1754 if opts.get('secret'):
1755 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1756 # Propagate to subrepos
1756 # Propagate to subrepos
1757 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1758
1758
1759 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1759 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1761 return repo.commit(message, opts.get('user'), opts.get('date'),
1761 return repo.commit(message, opts.get('user'), opts.get('date'),
1762 match,
1762 match,
1763 editor=editor,
1763 editor=editor,
1764 extra=extra)
1764 extra=extra)
1765 finally:
1765 finally:
1766 ui.restoreconfig(backup)
1766 ui.restoreconfig(backup)
1767 repo.baseui.restoreconfig(basebackup)
1767 repo.baseui.restoreconfig(basebackup)
1768
1768
1769
1769
1770 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1770 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1771
1771
1772 if not node:
1772 if not node:
1773 stat = cmdutil.postcommitstatus(repo, pats, opts)
1773 stat = cmdutil.postcommitstatus(repo, pats, opts)
1774 if stat[3]:
1774 if stat[3]:
1775 ui.status(_("nothing changed (%d missing files, see "
1775 ui.status(_("nothing changed (%d missing files, see "
1776 "'hg status')\n") % len(stat[3]))
1776 "'hg status')\n") % len(stat[3]))
1777 else:
1777 else:
1778 ui.status(_("nothing changed\n"))
1778 ui.status(_("nothing changed\n"))
1779 return 1
1779 return 1
1780
1780
1781 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1781 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1782
1782
1783 @command('config|showconfig|debugconfig',
1783 @command('config|showconfig|debugconfig',
1784 [('u', 'untrusted', None, _('show untrusted configuration options')),
1784 [('u', 'untrusted', None, _('show untrusted configuration options')),
1785 ('e', 'edit', None, _('edit user config')),
1785 ('e', 'edit', None, _('edit user config')),
1786 ('l', 'local', None, _('edit repository config')),
1786 ('l', 'local', None, _('edit repository config')),
1787 ('g', 'global', None, _('edit global config'))],
1787 ('g', 'global', None, _('edit global config'))],
1788 _('[-u] [NAME]...'),
1788 _('[-u] [NAME]...'),
1789 optionalrepo=True)
1789 optionalrepo=True)
1790 def config(ui, repo, *values, **opts):
1790 def config(ui, repo, *values, **opts):
1791 """show combined config settings from all hgrc files
1791 """show combined config settings from all hgrc files
1792
1792
1793 With no arguments, print names and values of all config items.
1793 With no arguments, print names and values of all config items.
1794
1794
1795 With one argument of the form section.name, print just the value
1795 With one argument of the form section.name, print just the value
1796 of that config item.
1796 of that config item.
1797
1797
1798 With multiple arguments, print names and values of all config
1798 With multiple arguments, print names and values of all config
1799 items with matching section names.
1799 items with matching section names.
1800
1800
1801 With --edit, start an editor on the user-level config file. With
1801 With --edit, start an editor on the user-level config file. With
1802 --global, edit the system-wide config file. With --local, edit the
1802 --global, edit the system-wide config file. With --local, edit the
1803 repository-level config file.
1803 repository-level config file.
1804
1804
1805 With --debug, the source (filename and line number) is printed
1805 With --debug, the source (filename and line number) is printed
1806 for each config item.
1806 for each config item.
1807
1807
1808 See :hg:`help config` for more information about config files.
1808 See :hg:`help config` for more information about config files.
1809
1809
1810 Returns 0 on success, 1 if NAME does not exist.
1810 Returns 0 on success, 1 if NAME does not exist.
1811
1811
1812 """
1812 """
1813
1813
1814 if opts.get('edit') or opts.get('local') or opts.get('global'):
1814 if opts.get('edit') or opts.get('local') or opts.get('global'):
1815 if opts.get('local') and opts.get('global'):
1815 if opts.get('local') and opts.get('global'):
1816 raise error.Abort(_("can't use --local and --global together"))
1816 raise error.Abort(_("can't use --local and --global together"))
1817
1817
1818 if opts.get('local'):
1818 if opts.get('local'):
1819 if not repo:
1819 if not repo:
1820 raise error.Abort(_("can't use --local outside a repository"))
1820 raise error.Abort(_("can't use --local outside a repository"))
1821 paths = [repo.join('hgrc')]
1821 paths = [repo.join('hgrc')]
1822 elif opts.get('global'):
1822 elif opts.get('global'):
1823 paths = scmutil.systemrcpath()
1823 paths = scmutil.systemrcpath()
1824 else:
1824 else:
1825 paths = scmutil.userrcpath()
1825 paths = scmutil.userrcpath()
1826
1826
1827 for f in paths:
1827 for f in paths:
1828 if os.path.exists(f):
1828 if os.path.exists(f):
1829 break
1829 break
1830 else:
1830 else:
1831 if opts.get('global'):
1831 if opts.get('global'):
1832 samplehgrc = uimod.samplehgrcs['global']
1832 samplehgrc = uimod.samplehgrcs['global']
1833 elif opts.get('local'):
1833 elif opts.get('local'):
1834 samplehgrc = uimod.samplehgrcs['local']
1834 samplehgrc = uimod.samplehgrcs['local']
1835 else:
1835 else:
1836 samplehgrc = uimod.samplehgrcs['user']
1836 samplehgrc = uimod.samplehgrcs['user']
1837
1837
1838 f = paths[0]
1838 f = paths[0]
1839 fp = open(f, "w")
1839 fp = open(f, "w")
1840 fp.write(samplehgrc)
1840 fp.write(samplehgrc)
1841 fp.close()
1841 fp.close()
1842
1842
1843 editor = ui.geteditor()
1843 editor = ui.geteditor()
1844 ui.system("%s \"%s\"" % (editor, f),
1844 ui.system("%s \"%s\"" % (editor, f),
1845 onerr=error.Abort, errprefix=_("edit failed"))
1845 onerr=error.Abort, errprefix=_("edit failed"))
1846 return
1846 return
1847
1847
1848 for f in scmutil.rcpath():
1848 for f in scmutil.rcpath():
1849 ui.debug('read config from: %s\n' % f)
1849 ui.debug('read config from: %s\n' % f)
1850 untrusted = bool(opts.get('untrusted'))
1850 untrusted = bool(opts.get('untrusted'))
1851 if values:
1851 if values:
1852 sections = [v for v in values if '.' not in v]
1852 sections = [v for v in values if '.' not in v]
1853 items = [v for v in values if '.' in v]
1853 items = [v for v in values if '.' in v]
1854 if len(items) > 1 or items and sections:
1854 if len(items) > 1 or items and sections:
1855 raise error.Abort(_('only one config item permitted'))
1855 raise error.Abort(_('only one config item permitted'))
1856 matched = False
1856 matched = False
1857 for section, name, value in ui.walkconfig(untrusted=untrusted):
1857 for section, name, value in ui.walkconfig(untrusted=untrusted):
1858 value = str(value).replace('\n', '\\n')
1858 value = str(value).replace('\n', '\\n')
1859 sectname = section + '.' + name
1859 sectname = section + '.' + name
1860 if values:
1860 if values:
1861 for v in values:
1861 for v in values:
1862 if v == section:
1862 if v == section:
1863 ui.debug('%s: ' %
1863 ui.debug('%s: ' %
1864 ui.configsource(section, name, untrusted))
1864 ui.configsource(section, name, untrusted))
1865 ui.write('%s=%s\n' % (sectname, value))
1865 ui.write('%s=%s\n' % (sectname, value))
1866 matched = True
1866 matched = True
1867 elif v == sectname:
1867 elif v == sectname:
1868 ui.debug('%s: ' %
1868 ui.debug('%s: ' %
1869 ui.configsource(section, name, untrusted))
1869 ui.configsource(section, name, untrusted))
1870 ui.write(value, '\n')
1870 ui.write(value, '\n')
1871 matched = True
1871 matched = True
1872 else:
1872 else:
1873 ui.debug('%s: ' %
1873 ui.debug('%s: ' %
1874 ui.configsource(section, name, untrusted))
1874 ui.configsource(section, name, untrusted))
1875 ui.write('%s=%s\n' % (sectname, value))
1875 ui.write('%s=%s\n' % (sectname, value))
1876 matched = True
1876 matched = True
1877 if matched:
1877 if matched:
1878 return 0
1878 return 0
1879 return 1
1879 return 1
1880
1880
1881 @command('copy|cp',
1881 @command('copy|cp',
1882 [('A', 'after', None, _('record a copy that has already occurred')),
1882 [('A', 'after', None, _('record a copy that has already occurred')),
1883 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1883 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1884 ] + walkopts + dryrunopts,
1884 ] + walkopts + dryrunopts,
1885 _('[OPTION]... [SOURCE]... DEST'))
1885 _('[OPTION]... [SOURCE]... DEST'))
1886 def copy(ui, repo, *pats, **opts):
1886 def copy(ui, repo, *pats, **opts):
1887 """mark files as copied for the next commit
1887 """mark files as copied for the next commit
1888
1888
1889 Mark dest as having copies of source files. If dest is a
1889 Mark dest as having copies of source files. If dest is a
1890 directory, copies are put in that directory. If dest is a file,
1890 directory, copies are put in that directory. If dest is a file,
1891 the source must be a single file.
1891 the source must be a single file.
1892
1892
1893 By default, this command copies the contents of files as they
1893 By default, this command copies the contents of files as they
1894 exist in the working directory. If invoked with -A/--after, the
1894 exist in the working directory. If invoked with -A/--after, the
1895 operation is recorded, but no copying is performed.
1895 operation is recorded, but no copying is performed.
1896
1896
1897 This command takes effect with the next commit. To undo a copy
1897 This command takes effect with the next commit. To undo a copy
1898 before that, see :hg:`revert`.
1898 before that, see :hg:`revert`.
1899
1899
1900 Returns 0 on success, 1 if errors are encountered.
1900 Returns 0 on success, 1 if errors are encountered.
1901 """
1901 """
1902 with repo.wlock(False):
1902 with repo.wlock(False):
1903 return cmdutil.copy(ui, repo, pats, opts)
1903 return cmdutil.copy(ui, repo, pats, opts)
1904
1904
1905 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1905 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1906 def debugancestor(ui, repo, *args):
1906 def debugancestor(ui, repo, *args):
1907 """find the ancestor revision of two revisions in a given index"""
1907 """find the ancestor revision of two revisions in a given index"""
1908 if len(args) == 3:
1908 if len(args) == 3:
1909 index, rev1, rev2 = args
1909 index, rev1, rev2 = args
1910 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1910 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1911 lookup = r.lookup
1911 lookup = r.lookup
1912 elif len(args) == 2:
1912 elif len(args) == 2:
1913 if not repo:
1913 if not repo:
1914 raise error.Abort(_("there is no Mercurial repository here "
1914 raise error.Abort(_("there is no Mercurial repository here "
1915 "(.hg not found)"))
1915 "(.hg not found)"))
1916 rev1, rev2 = args
1916 rev1, rev2 = args
1917 r = repo.changelog
1917 r = repo.changelog
1918 lookup = repo.lookup
1918 lookup = repo.lookup
1919 else:
1919 else:
1920 raise error.Abort(_('either two or three arguments required'))
1920 raise error.Abort(_('either two or three arguments required'))
1921 a = r.ancestor(lookup(rev1), lookup(rev2))
1921 a = r.ancestor(lookup(rev1), lookup(rev2))
1922 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1922 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1923
1923
1924 @command('debugbuilddag',
1924 @command('debugbuilddag',
1925 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1925 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1926 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1926 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1927 ('n', 'new-file', None, _('add new file at each rev'))],
1927 ('n', 'new-file', None, _('add new file at each rev'))],
1928 _('[OPTION]... [TEXT]'))
1928 _('[OPTION]... [TEXT]'))
1929 def debugbuilddag(ui, repo, text=None,
1929 def debugbuilddag(ui, repo, text=None,
1930 mergeable_file=False,
1930 mergeable_file=False,
1931 overwritten_file=False,
1931 overwritten_file=False,
1932 new_file=False):
1932 new_file=False):
1933 """builds a repo with a given DAG from scratch in the current empty repo
1933 """builds a repo with a given DAG from scratch in the current empty repo
1934
1934
1935 The description of the DAG is read from stdin if not given on the
1935 The description of the DAG is read from stdin if not given on the
1936 command line.
1936 command line.
1937
1937
1938 Elements:
1938 Elements:
1939
1939
1940 - "+n" is a linear run of n nodes based on the current default parent
1940 - "+n" is a linear run of n nodes based on the current default parent
1941 - "." is a single node based on the current default parent
1941 - "." is a single node based on the current default parent
1942 - "$" resets the default parent to null (implied at the start);
1942 - "$" resets the default parent to null (implied at the start);
1943 otherwise the default parent is always the last node created
1943 otherwise the default parent is always the last node created
1944 - "<p" sets the default parent to the backref p
1944 - "<p" sets the default parent to the backref p
1945 - "*p" is a fork at parent p, which is a backref
1945 - "*p" is a fork at parent p, which is a backref
1946 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1946 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1947 - "/p2" is a merge of the preceding node and p2
1947 - "/p2" is a merge of the preceding node and p2
1948 - ":tag" defines a local tag for the preceding node
1948 - ":tag" defines a local tag for the preceding node
1949 - "@branch" sets the named branch for subsequent nodes
1949 - "@branch" sets the named branch for subsequent nodes
1950 - "#...\\n" is a comment up to the end of the line
1950 - "#...\\n" is a comment up to the end of the line
1951
1951
1952 Whitespace between the above elements is ignored.
1952 Whitespace between the above elements is ignored.
1953
1953
1954 A backref is either
1954 A backref is either
1955
1955
1956 - a number n, which references the node curr-n, where curr is the current
1956 - a number n, which references the node curr-n, where curr is the current
1957 node, or
1957 node, or
1958 - the name of a local tag you placed earlier using ":tag", or
1958 - the name of a local tag you placed earlier using ":tag", or
1959 - empty to denote the default parent.
1959 - empty to denote the default parent.
1960
1960
1961 All string valued-elements are either strictly alphanumeric, or must
1961 All string valued-elements are either strictly alphanumeric, or must
1962 be enclosed in double quotes ("..."), with "\\" as escape character.
1962 be enclosed in double quotes ("..."), with "\\" as escape character.
1963 """
1963 """
1964
1964
1965 if text is None:
1965 if text is None:
1966 ui.status(_("reading DAG from stdin\n"))
1966 ui.status(_("reading DAG from stdin\n"))
1967 text = ui.fin.read()
1967 text = ui.fin.read()
1968
1968
1969 cl = repo.changelog
1969 cl = repo.changelog
1970 if len(cl) > 0:
1970 if len(cl) > 0:
1971 raise error.Abort(_('repository is not empty'))
1971 raise error.Abort(_('repository is not empty'))
1972
1972
1973 # determine number of revs in DAG
1973 # determine number of revs in DAG
1974 total = 0
1974 total = 0
1975 for type, data in dagparser.parsedag(text):
1975 for type, data in dagparser.parsedag(text):
1976 if type == 'n':
1976 if type == 'n':
1977 total += 1
1977 total += 1
1978
1978
1979 if mergeable_file:
1979 if mergeable_file:
1980 linesperrev = 2
1980 linesperrev = 2
1981 # make a file with k lines per rev
1981 # make a file with k lines per rev
1982 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1982 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1983 initialmergedlines.append("")
1983 initialmergedlines.append("")
1984
1984
1985 tags = []
1985 tags = []
1986
1986
1987 lock = tr = None
1987 lock = tr = None
1988 try:
1988 try:
1989 lock = repo.lock()
1989 lock = repo.lock()
1990 tr = repo.transaction("builddag")
1990 tr = repo.transaction("builddag")
1991
1991
1992 at = -1
1992 at = -1
1993 atbranch = 'default'
1993 atbranch = 'default'
1994 nodeids = []
1994 nodeids = []
1995 id = 0
1995 id = 0
1996 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1996 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1997 for type, data in dagparser.parsedag(text):
1997 for type, data in dagparser.parsedag(text):
1998 if type == 'n':
1998 if type == 'n':
1999 ui.note(('node %s\n' % str(data)))
1999 ui.note(('node %s\n' % str(data)))
2000 id, ps = data
2000 id, ps = data
2001
2001
2002 files = []
2002 files = []
2003 fctxs = {}
2003 fctxs = {}
2004
2004
2005 p2 = None
2005 p2 = None
2006 if mergeable_file:
2006 if mergeable_file:
2007 fn = "mf"
2007 fn = "mf"
2008 p1 = repo[ps[0]]
2008 p1 = repo[ps[0]]
2009 if len(ps) > 1:
2009 if len(ps) > 1:
2010 p2 = repo[ps[1]]
2010 p2 = repo[ps[1]]
2011 pa = p1.ancestor(p2)
2011 pa = p1.ancestor(p2)
2012 base, local, other = [x[fn].data() for x in (pa, p1,
2012 base, local, other = [x[fn].data() for x in (pa, p1,
2013 p2)]
2013 p2)]
2014 m3 = simplemerge.Merge3Text(base, local, other)
2014 m3 = simplemerge.Merge3Text(base, local, other)
2015 ml = [l.strip() for l in m3.merge_lines()]
2015 ml = [l.strip() for l in m3.merge_lines()]
2016 ml.append("")
2016 ml.append("")
2017 elif at > 0:
2017 elif at > 0:
2018 ml = p1[fn].data().split("\n")
2018 ml = p1[fn].data().split("\n")
2019 else:
2019 else:
2020 ml = initialmergedlines
2020 ml = initialmergedlines
2021 ml[id * linesperrev] += " r%i" % id
2021 ml[id * linesperrev] += " r%i" % id
2022 mergedtext = "\n".join(ml)
2022 mergedtext = "\n".join(ml)
2023 files.append(fn)
2023 files.append(fn)
2024 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2024 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2025
2025
2026 if overwritten_file:
2026 if overwritten_file:
2027 fn = "of"
2027 fn = "of"
2028 files.append(fn)
2028 files.append(fn)
2029 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2029 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2030
2030
2031 if new_file:
2031 if new_file:
2032 fn = "nf%i" % id
2032 fn = "nf%i" % id
2033 files.append(fn)
2033 files.append(fn)
2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2035 if len(ps) > 1:
2035 if len(ps) > 1:
2036 if not p2:
2036 if not p2:
2037 p2 = repo[ps[1]]
2037 p2 = repo[ps[1]]
2038 for fn in p2:
2038 for fn in p2:
2039 if fn.startswith("nf"):
2039 if fn.startswith("nf"):
2040 files.append(fn)
2040 files.append(fn)
2041 fctxs[fn] = p2[fn]
2041 fctxs[fn] = p2[fn]
2042
2042
2043 def fctxfn(repo, cx, path):
2043 def fctxfn(repo, cx, path):
2044 return fctxs.get(path)
2044 return fctxs.get(path)
2045
2045
2046 if len(ps) == 0 or ps[0] < 0:
2046 if len(ps) == 0 or ps[0] < 0:
2047 pars = [None, None]
2047 pars = [None, None]
2048 elif len(ps) == 1:
2048 elif len(ps) == 1:
2049 pars = [nodeids[ps[0]], None]
2049 pars = [nodeids[ps[0]], None]
2050 else:
2050 else:
2051 pars = [nodeids[p] for p in ps]
2051 pars = [nodeids[p] for p in ps]
2052 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2052 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2053 date=(id, 0),
2053 date=(id, 0),
2054 user="debugbuilddag",
2054 user="debugbuilddag",
2055 extra={'branch': atbranch})
2055 extra={'branch': atbranch})
2056 nodeid = repo.commitctx(cx)
2056 nodeid = repo.commitctx(cx)
2057 nodeids.append(nodeid)
2057 nodeids.append(nodeid)
2058 at = id
2058 at = id
2059 elif type == 'l':
2059 elif type == 'l':
2060 id, name = data
2060 id, name = data
2061 ui.note(('tag %s\n' % name))
2061 ui.note(('tag %s\n' % name))
2062 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2062 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2063 elif type == 'a':
2063 elif type == 'a':
2064 ui.note(('branch %s\n' % data))
2064 ui.note(('branch %s\n' % data))
2065 atbranch = data
2065 atbranch = data
2066 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2066 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2067 tr.close()
2067 tr.close()
2068
2068
2069 if tags:
2069 if tags:
2070 repo.vfs.write("localtags", "".join(tags))
2070 repo.vfs.write("localtags", "".join(tags))
2071 finally:
2071 finally:
2072 ui.progress(_('building'), None)
2072 ui.progress(_('building'), None)
2073 release(tr, lock)
2073 release(tr, lock)
2074
2074
2075 @command('debugbundle',
2075 @command('debugbundle',
2076 [('a', 'all', None, _('show all details')),
2076 [('a', 'all', None, _('show all details')),
2077 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2077 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2078 _('FILE'),
2078 _('FILE'),
2079 norepo=True)
2079 norepo=True)
2080 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2080 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2081 """lists the contents of a bundle"""
2081 """lists the contents of a bundle"""
2082 with hg.openpath(ui, bundlepath) as f:
2082 with hg.openpath(ui, bundlepath) as f:
2083 if spec:
2083 if spec:
2084 spec = exchange.getbundlespec(ui, f)
2084 spec = exchange.getbundlespec(ui, f)
2085 ui.write('%s\n' % spec)
2085 ui.write('%s\n' % spec)
2086 return
2086 return
2087
2087
2088 gen = exchange.readbundle(ui, f, bundlepath)
2088 gen = exchange.readbundle(ui, f, bundlepath)
2089 if isinstance(gen, bundle2.unbundle20):
2089 if isinstance(gen, bundle2.unbundle20):
2090 return _debugbundle2(ui, gen, all=all, **opts)
2090 return _debugbundle2(ui, gen, all=all, **opts)
2091 if all:
2091 if all:
2092 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2092 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2093
2093
2094 def showchunks(named):
2094 def showchunks(named):
2095 ui.write("\n%s\n" % named)
2095 ui.write("\n%s\n" % named)
2096 chain = None
2096 chain = None
2097 while True:
2097 while True:
2098 chunkdata = gen.deltachunk(chain)
2098 chunkdata = gen.deltachunk(chain)
2099 if not chunkdata:
2099 if not chunkdata:
2100 break
2100 break
2101 node = chunkdata['node']
2101 node = chunkdata['node']
2102 p1 = chunkdata['p1']
2102 p1 = chunkdata['p1']
2103 p2 = chunkdata['p2']
2103 p2 = chunkdata['p2']
2104 cs = chunkdata['cs']
2104 cs = chunkdata['cs']
2105 deltabase = chunkdata['deltabase']
2105 deltabase = chunkdata['deltabase']
2106 delta = chunkdata['delta']
2106 delta = chunkdata['delta']
2107 ui.write("%s %s %s %s %s %s\n" %
2107 ui.write("%s %s %s %s %s %s\n" %
2108 (hex(node), hex(p1), hex(p2),
2108 (hex(node), hex(p1), hex(p2),
2109 hex(cs), hex(deltabase), len(delta)))
2109 hex(cs), hex(deltabase), len(delta)))
2110 chain = node
2110 chain = node
2111
2111
2112 chunkdata = gen.changelogheader()
2112 chunkdata = gen.changelogheader()
2113 showchunks("changelog")
2113 showchunks("changelog")
2114 chunkdata = gen.manifestheader()
2114 chunkdata = gen.manifestheader()
2115 showchunks("manifest")
2115 showchunks("manifest")
2116 while True:
2116 while True:
2117 chunkdata = gen.filelogheader()
2117 chunkdata = gen.filelogheader()
2118 if not chunkdata:
2118 if not chunkdata:
2119 break
2119 break
2120 fname = chunkdata['filename']
2120 fname = chunkdata['filename']
2121 showchunks(fname)
2121 showchunks(fname)
2122 else:
2122 else:
2123 if isinstance(gen, bundle2.unbundle20):
2123 if isinstance(gen, bundle2.unbundle20):
2124 raise error.Abort(_('use debugbundle2 for this file'))
2124 raise error.Abort(_('use debugbundle2 for this file'))
2125 chunkdata = gen.changelogheader()
2125 chunkdata = gen.changelogheader()
2126 chain = None
2126 chain = None
2127 while True:
2127 while True:
2128 chunkdata = gen.deltachunk(chain)
2128 chunkdata = gen.deltachunk(chain)
2129 if not chunkdata:
2129 if not chunkdata:
2130 break
2130 break
2131 node = chunkdata['node']
2131 node = chunkdata['node']
2132 ui.write("%s\n" % hex(node))
2132 ui.write("%s\n" % hex(node))
2133 chain = node
2133 chain = node
2134
2134
2135 def _debugbundle2(ui, gen, **opts):
2135 def _debugbundle2(ui, gen, **opts):
2136 """lists the contents of a bundle2"""
2136 """lists the contents of a bundle2"""
2137 if not isinstance(gen, bundle2.unbundle20):
2137 if not isinstance(gen, bundle2.unbundle20):
2138 raise error.Abort(_('not a bundle2 file'))
2138 raise error.Abort(_('not a bundle2 file'))
2139 ui.write(('Stream params: %s\n' % repr(gen.params)))
2139 ui.write(('Stream params: %s\n' % repr(gen.params)))
2140 for part in gen.iterparts():
2140 for part in gen.iterparts():
2141 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2141 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2142 if part.type == 'changegroup':
2142 if part.type == 'changegroup':
2143 version = part.params.get('version', '01')
2143 version = part.params.get('version', '01')
2144 cg = changegroup.getunbundler(version, part, 'UN')
2144 cg = changegroup.getunbundler(version, part, 'UN')
2145 chunkdata = cg.changelogheader()
2145 chunkdata = cg.changelogheader()
2146 chain = None
2146 chain = None
2147 while True:
2147 while True:
2148 chunkdata = cg.deltachunk(chain)
2148 chunkdata = cg.deltachunk(chain)
2149 if not chunkdata:
2149 if not chunkdata:
2150 break
2150 break
2151 node = chunkdata['node']
2151 node = chunkdata['node']
2152 ui.write(" %s\n" % hex(node))
2152 ui.write(" %s\n" % hex(node))
2153 chain = node
2153 chain = node
2154
2154
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2157 """create a stream clone bundle file
2157 """create a stream clone bundle file
2158
2158
2159 Stream bundles are special bundles that are essentially archives of
2159 Stream bundles are special bundles that are essentially archives of
2160 revlog files. They are commonly used for cloning very quickly.
2160 revlog files. They are commonly used for cloning very quickly.
2161 """
2161 """
2162 requirements, gen = streamclone.generatebundlev1(repo)
2162 requirements, gen = streamclone.generatebundlev1(repo)
2163 changegroup.writechunks(ui, gen, fname)
2163 changegroup.writechunks(ui, gen, fname)
2164
2164
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2166
2166
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2168 def debugapplystreamclonebundle(ui, repo, fname):
2168 def debugapplystreamclonebundle(ui, repo, fname):
2169 """apply a stream clone bundle file"""
2169 """apply a stream clone bundle file"""
2170 f = hg.openpath(ui, fname)
2170 f = hg.openpath(ui, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2172 gen.apply(repo)
2172 gen.apply(repo)
2173
2173
2174 @command('debugcheckstate', [], '')
2174 @command('debugcheckstate', [], '')
2175 def debugcheckstate(ui, repo):
2175 def debugcheckstate(ui, repo):
2176 """validate the correctness of the current dirstate"""
2176 """validate the correctness of the current dirstate"""
2177 parent1, parent2 = repo.dirstate.parents()
2177 parent1, parent2 = repo.dirstate.parents()
2178 m1 = repo[parent1].manifest()
2178 m1 = repo[parent1].manifest()
2179 m2 = repo[parent2].manifest()
2179 m2 = repo[parent2].manifest()
2180 errors = 0
2180 errors = 0
2181 for f in repo.dirstate:
2181 for f in repo.dirstate:
2182 state = repo.dirstate[f]
2182 state = repo.dirstate[f]
2183 if state in "nr" and f not in m1:
2183 if state in "nr" and f not in m1:
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2184 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2185 errors += 1
2185 errors += 1
2186 if state in "a" and f in m1:
2186 if state in "a" and f in m1:
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2187 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2188 errors += 1
2188 errors += 1
2189 if state in "m" and f not in m1 and f not in m2:
2189 if state in "m" and f not in m1 and f not in m2:
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2190 ui.warn(_("%s in state %s, but not in either manifest\n") %
2191 (f, state))
2191 (f, state))
2192 errors += 1
2192 errors += 1
2193 for f in m1:
2193 for f in m1:
2194 state = repo.dirstate[f]
2194 state = repo.dirstate[f]
2195 if state not in "nrm":
2195 if state not in "nrm":
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2196 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2197 errors += 1
2197 errors += 1
2198 if errors:
2198 if errors:
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2200 raise error.Abort(error)
2200 raise error.Abort(error)
2201
2201
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2203 def debugcommands(ui, cmd='', *args):
2203 def debugcommands(ui, cmd='', *args):
2204 """list all available commands and options"""
2204 """list all available commands and options"""
2205 for cmd, vals in sorted(table.iteritems()):
2205 for cmd, vals in sorted(table.iteritems()):
2206 cmd = cmd.split('|')[0].strip('^')
2206 cmd = cmd.split('|')[0].strip('^')
2207 opts = ', '.join([i[1] for i in vals[1]])
2207 opts = ', '.join([i[1] for i in vals[1]])
2208 ui.write('%s: %s\n' % (cmd, opts))
2208 ui.write('%s: %s\n' % (cmd, opts))
2209
2209
2210 @command('debugcomplete',
2210 @command('debugcomplete',
2211 [('o', 'options', None, _('show the command options'))],
2211 [('o', 'options', None, _('show the command options'))],
2212 _('[-o] CMD'),
2212 _('[-o] CMD'),
2213 norepo=True)
2213 norepo=True)
2214 def debugcomplete(ui, cmd='', **opts):
2214 def debugcomplete(ui, cmd='', **opts):
2215 """returns the completion list associated with the given command"""
2215 """returns the completion list associated with the given command"""
2216
2216
2217 if opts.get('options'):
2217 if opts.get('options'):
2218 options = []
2218 options = []
2219 otables = [globalopts]
2219 otables = [globalopts]
2220 if cmd:
2220 if cmd:
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2222 otables.append(entry[1])
2222 otables.append(entry[1])
2223 for t in otables:
2223 for t in otables:
2224 for o in t:
2224 for o in t:
2225 if "(DEPRECATED)" in o[3]:
2225 if "(DEPRECATED)" in o[3]:
2226 continue
2226 continue
2227 if o[0]:
2227 if o[0]:
2228 options.append('-%s' % o[0])
2228 options.append('-%s' % o[0])
2229 options.append('--%s' % o[1])
2229 options.append('--%s' % o[1])
2230 ui.write("%s\n" % "\n".join(options))
2230 ui.write("%s\n" % "\n".join(options))
2231 return
2231 return
2232
2232
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2234 if ui.verbose:
2234 if ui.verbose:
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2237
2237
2238 @command('debugdag',
2238 @command('debugdag',
2239 [('t', 'tags', None, _('use tags as labels')),
2239 [('t', 'tags', None, _('use tags as labels')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2241 ('', 'dots', None, _('use dots for runs')),
2241 ('', 'dots', None, _('use dots for runs')),
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2243 _('[OPTION]... [FILE [REV]...]'),
2243 _('[OPTION]... [FILE [REV]...]'),
2244 optionalrepo=True)
2244 optionalrepo=True)
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2246 """format the changelog or an index DAG as a concise textual description
2246 """format the changelog or an index DAG as a concise textual description
2247
2247
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2248 If you pass a revlog index, the revlog's DAG is emitted. If you list
2249 revision numbers, they get labeled in the output as rN.
2249 revision numbers, they get labeled in the output as rN.
2250
2250
2251 Otherwise, the changelog DAG of the current repo is emitted.
2251 Otherwise, the changelog DAG of the current repo is emitted.
2252 """
2252 """
2253 spaces = opts.get('spaces')
2253 spaces = opts.get('spaces')
2254 dots = opts.get('dots')
2254 dots = opts.get('dots')
2255 if file_:
2255 if file_:
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2257 revs = set((int(r) for r in revs))
2257 revs = set((int(r) for r in revs))
2258 def events():
2258 def events():
2259 for r in rlog:
2259 for r in rlog:
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2261 if p != -1))
2261 if p != -1))
2262 if r in revs:
2262 if r in revs:
2263 yield 'l', (r, "r%i" % r)
2263 yield 'l', (r, "r%i" % r)
2264 elif repo:
2264 elif repo:
2265 cl = repo.changelog
2265 cl = repo.changelog
2266 tags = opts.get('tags')
2266 tags = opts.get('tags')
2267 branches = opts.get('branches')
2267 branches = opts.get('branches')
2268 if tags:
2268 if tags:
2269 labels = {}
2269 labels = {}
2270 for l, n in repo.tags().items():
2270 for l, n in repo.tags().items():
2271 labels.setdefault(cl.rev(n), []).append(l)
2271 labels.setdefault(cl.rev(n), []).append(l)
2272 def events():
2272 def events():
2273 b = "default"
2273 b = "default"
2274 for r in cl:
2274 for r in cl:
2275 if branches:
2275 if branches:
2276 newb = cl.read(cl.node(r))[5]['branch']
2276 newb = cl.read(cl.node(r))[5]['branch']
2277 if newb != b:
2277 if newb != b:
2278 yield 'a', newb
2278 yield 'a', newb
2279 b = newb
2279 b = newb
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2281 if p != -1))
2281 if p != -1))
2282 if tags:
2282 if tags:
2283 ls = labels.get(r)
2283 ls = labels.get(r)
2284 if ls:
2284 if ls:
2285 for l in ls:
2285 for l in ls:
2286 yield 'l', (r, l)
2286 yield 'l', (r, l)
2287 else:
2287 else:
2288 raise error.Abort(_('need repo for changelog dag'))
2288 raise error.Abort(_('need repo for changelog dag'))
2289
2289
2290 for line in dagparser.dagtextlines(events(),
2290 for line in dagparser.dagtextlines(events(),
2291 addspaces=spaces,
2291 addspaces=spaces,
2292 wraplabels=True,
2292 wraplabels=True,
2293 wrapannotations=True,
2293 wrapannotations=True,
2294 wrapnonlinear=dots,
2294 wrapnonlinear=dots,
2295 usedots=dots,
2295 usedots=dots,
2296 maxlinewidth=70):
2296 maxlinewidth=70):
2297 ui.write(line)
2297 ui.write(line)
2298 ui.write("\n")
2298 ui.write("\n")
2299
2299
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2302 """dump the contents of a data file revision"""
2302 """dump the contents of a data file revision"""
2303 if opts.get('changelog') or opts.get('manifest'):
2303 if opts.get('changelog') or opts.get('manifest'):
2304 file_, rev = None, file_
2304 file_, rev = None, file_
2305 elif rev is None:
2305 elif rev is None:
2306 raise error.CommandError('debugdata', _('invalid arguments'))
2306 raise error.CommandError('debugdata', _('invalid arguments'))
2307 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2307 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2308 try:
2308 try:
2309 ui.write(r.revision(r.lookup(rev)))
2309 ui.write(r.revision(r.lookup(rev)))
2310 except KeyError:
2310 except KeyError:
2311 raise error.Abort(_('invalid revision identifier %s') % rev)
2311 raise error.Abort(_('invalid revision identifier %s') % rev)
2312
2312
2313 @command('debugdate',
2313 @command('debugdate',
2314 [('e', 'extended', None, _('try extended date formats'))],
2314 [('e', 'extended', None, _('try extended date formats'))],
2315 _('[-e] DATE [RANGE]'),
2315 _('[-e] DATE [RANGE]'),
2316 norepo=True, optionalrepo=True)
2316 norepo=True, optionalrepo=True)
2317 def debugdate(ui, date, range=None, **opts):
2317 def debugdate(ui, date, range=None, **opts):
2318 """parse and display a date"""
2318 """parse and display a date"""
2319 if opts["extended"]:
2319 if opts["extended"]:
2320 d = util.parsedate(date, util.extendeddateformats)
2320 d = util.parsedate(date, util.extendeddateformats)
2321 else:
2321 else:
2322 d = util.parsedate(date)
2322 d = util.parsedate(date)
2323 ui.write(("internal: %s %s\n") % d)
2323 ui.write(("internal: %s %s\n") % d)
2324 ui.write(("standard: %s\n") % util.datestr(d))
2324 ui.write(("standard: %s\n") % util.datestr(d))
2325 if range:
2325 if range:
2326 m = util.matchdate(range)
2326 m = util.matchdate(range)
2327 ui.write(("match: %s\n") % m(d[0]))
2327 ui.write(("match: %s\n") % m(d[0]))
2328
2328
2329 @command('debugdiscovery',
2329 @command('debugdiscovery',
2330 [('', 'old', None, _('use old-style discovery')),
2330 [('', 'old', None, _('use old-style discovery')),
2331 ('', 'nonheads', None,
2331 ('', 'nonheads', None,
2332 _('use old-style discovery with non-heads included')),
2332 _('use old-style discovery with non-heads included')),
2333 ] + remoteopts,
2333 ] + remoteopts,
2334 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2334 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2335 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2335 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2336 """runs the changeset discovery protocol in isolation"""
2336 """runs the changeset discovery protocol in isolation"""
2337 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2337 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2338 opts.get('branch'))
2338 opts.get('branch'))
2339 remote = hg.peer(repo, opts, remoteurl)
2339 remote = hg.peer(repo, opts, remoteurl)
2340 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2340 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2341
2341
2342 # make sure tests are repeatable
2342 # make sure tests are repeatable
2343 random.seed(12323)
2343 random.seed(12323)
2344
2344
2345 def doit(localheads, remoteheads, remote=remote):
2345 def doit(localheads, remoteheads, remote=remote):
2346 if opts.get('old'):
2346 if opts.get('old'):
2347 if localheads:
2347 if localheads:
2348 raise error.Abort('cannot use localheads with old style '
2348 raise error.Abort('cannot use localheads with old style '
2349 'discovery')
2349 'discovery')
2350 if not util.safehasattr(remote, 'branches'):
2350 if not util.safehasattr(remote, 'branches'):
2351 # enable in-client legacy support
2351 # enable in-client legacy support
2352 remote = localrepo.locallegacypeer(remote.local())
2352 remote = localrepo.locallegacypeer(remote.local())
2353 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2353 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2354 force=True)
2354 force=True)
2355 common = set(common)
2355 common = set(common)
2356 if not opts.get('nonheads'):
2356 if not opts.get('nonheads'):
2357 ui.write(("unpruned common: %s\n") %
2357 ui.write(("unpruned common: %s\n") %
2358 " ".join(sorted(short(n) for n in common)))
2358 " ".join(sorted(short(n) for n in common)))
2359 dag = dagutil.revlogdag(repo.changelog)
2359 dag = dagutil.revlogdag(repo.changelog)
2360 all = dag.ancestorset(dag.internalizeall(common))
2360 all = dag.ancestorset(dag.internalizeall(common))
2361 common = dag.externalizeall(dag.headsetofconnecteds(all))
2361 common = dag.externalizeall(dag.headsetofconnecteds(all))
2362 else:
2362 else:
2363 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2363 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2364 common = set(common)
2364 common = set(common)
2365 rheads = set(hds)
2365 rheads = set(hds)
2366 lheads = set(repo.heads())
2366 lheads = set(repo.heads())
2367 ui.write(("common heads: %s\n") %
2367 ui.write(("common heads: %s\n") %
2368 " ".join(sorted(short(n) for n in common)))
2368 " ".join(sorted(short(n) for n in common)))
2369 if lheads <= common:
2369 if lheads <= common:
2370 ui.write(("local is subset\n"))
2370 ui.write(("local is subset\n"))
2371 elif rheads <= common:
2371 elif rheads <= common:
2372 ui.write(("remote is subset\n"))
2372 ui.write(("remote is subset\n"))
2373
2373
2374 serverlogs = opts.get('serverlog')
2374 serverlogs = opts.get('serverlog')
2375 if serverlogs:
2375 if serverlogs:
2376 for filename in serverlogs:
2376 for filename in serverlogs:
2377 with open(filename, 'r') as logfile:
2377 with open(filename, 'r') as logfile:
2378 line = logfile.readline()
2378 line = logfile.readline()
2379 while line:
2379 while line:
2380 parts = line.strip().split(';')
2380 parts = line.strip().split(';')
2381 op = parts[1]
2381 op = parts[1]
2382 if op == 'cg':
2382 if op == 'cg':
2383 pass
2383 pass
2384 elif op == 'cgss':
2384 elif op == 'cgss':
2385 doit(parts[2].split(' '), parts[3].split(' '))
2385 doit(parts[2].split(' '), parts[3].split(' '))
2386 elif op == 'unb':
2386 elif op == 'unb':
2387 doit(parts[3].split(' '), parts[2].split(' '))
2387 doit(parts[3].split(' '), parts[2].split(' '))
2388 line = logfile.readline()
2388 line = logfile.readline()
2389 else:
2389 else:
2390 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2390 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2391 opts.get('remote_head'))
2391 opts.get('remote_head'))
2392 localrevs = opts.get('local_head')
2392 localrevs = opts.get('local_head')
2393 doit(localrevs, remoterevs)
2393 doit(localrevs, remoterevs)
2394
2394
2395 @command('debugextensions', formatteropts, [], norepo=True)
2395 @command('debugextensions', formatteropts, [], norepo=True)
2396 def debugextensions(ui, **opts):
2396 def debugextensions(ui, **opts):
2397 '''show information about active extensions'''
2397 '''show information about active extensions'''
2398 exts = extensions.extensions(ui)
2398 exts = extensions.extensions(ui)
2399 fm = ui.formatter('debugextensions', opts)
2399 fm = ui.formatter('debugextensions', opts)
2400 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2400 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2401 extsource = extmod.__file__
2401 extsource = extmod.__file__
2402 exttestedwith = getattr(extmod, 'testedwith', None)
2402 exttestedwith = getattr(extmod, 'testedwith', None)
2403 if exttestedwith is not None:
2403 if exttestedwith is not None:
2404 exttestedwith = exttestedwith.split()
2404 exttestedwith = exttestedwith.split()
2405 extbuglink = getattr(extmod, 'buglink', None)
2405 extbuglink = getattr(extmod, 'buglink', None)
2406
2406
2407 fm.startitem()
2407 fm.startitem()
2408
2408
2409 if ui.quiet or ui.verbose:
2409 if ui.quiet or ui.verbose:
2410 fm.write('name', '%s\n', extname)
2410 fm.write('name', '%s\n', extname)
2411 else:
2411 else:
2412 fm.write('name', '%s', extname)
2412 fm.write('name', '%s', extname)
2413 if not exttestedwith:
2413 if not exttestedwith:
2414 fm.plain(_(' (untested!)\n'))
2414 fm.plain(_(' (untested!)\n'))
2415 else:
2415 else:
2416 if exttestedwith == ['internal'] or \
2416 if exttestedwith == ['internal'] or \
2417 util.version() in exttestedwith:
2417 util.version() in exttestedwith:
2418 fm.plain('\n')
2418 fm.plain('\n')
2419 else:
2419 else:
2420 lasttestedversion = exttestedwith[-1]
2420 lasttestedversion = exttestedwith[-1]
2421 fm.plain(' (%s!)\n' % lasttestedversion)
2421 fm.plain(' (%s!)\n' % lasttestedversion)
2422
2422
2423 fm.condwrite(ui.verbose and extsource, 'source',
2423 fm.condwrite(ui.verbose and extsource, 'source',
2424 _(' location: %s\n'), extsource or "")
2424 _(' location: %s\n'), extsource or "")
2425
2425
2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2427 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2427 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2428
2428
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2430 _(' bug reporting: %s\n'), extbuglink or "")
2430 _(' bug reporting: %s\n'), extbuglink or "")
2431
2431
2432 fm.end()
2432 fm.end()
2433
2433
2434 @command('debugfileset',
2434 @command('debugfileset',
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2436 _('[-r REV] FILESPEC'))
2436 _('[-r REV] FILESPEC'))
2437 def debugfileset(ui, repo, expr, **opts):
2437 def debugfileset(ui, repo, expr, **opts):
2438 '''parse and apply a fileset specification'''
2438 '''parse and apply a fileset specification'''
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2440 if ui.verbose:
2440 if ui.verbose:
2441 tree = fileset.parse(expr)
2441 tree = fileset.parse(expr)
2442 ui.note(fileset.prettyformat(tree), "\n")
2442 ui.note(fileset.prettyformat(tree), "\n")
2443
2443
2444 for f in ctx.getfileset(expr):
2444 for f in ctx.getfileset(expr):
2445 ui.write("%s\n" % f)
2445 ui.write("%s\n" % f)
2446
2446
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2448 def debugfsinfo(ui, path="."):
2448 def debugfsinfo(ui, path="."):
2449 """show information detected about current filesystem"""
2449 """show information detected about current filesystem"""
2450 util.writefile('.debugfsinfo', '')
2450 util.writefile('.debugfsinfo', '')
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2451 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2452 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2453 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2455 and 'yes' or 'no'))
2455 and 'yes' or 'no'))
2456 os.unlink('.debugfsinfo')
2456 os.unlink('.debugfsinfo')
2457
2457
2458 @command('debuggetbundle',
2458 @command('debuggetbundle',
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2462 _('REPO FILE [-H|-C ID]...'),
2462 _('REPO FILE [-H|-C ID]...'),
2463 norepo=True)
2463 norepo=True)
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2465 """retrieves a bundle from a repo
2465 """retrieves a bundle from a repo
2466
2466
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2467 Every ID must be a full-length hex node id string. Saves the bundle to the
2468 given file.
2468 given file.
2469 """
2469 """
2470 repo = hg.peer(ui, opts, repopath)
2470 repo = hg.peer(ui, opts, repopath)
2471 if not repo.capable('getbundle'):
2471 if not repo.capable('getbundle'):
2472 raise error.Abort("getbundle() not supported by target repository")
2472 raise error.Abort("getbundle() not supported by target repository")
2473 args = {}
2473 args = {}
2474 if common:
2474 if common:
2475 args['common'] = [bin(s) for s in common]
2475 args['common'] = [bin(s) for s in common]
2476 if head:
2476 if head:
2477 args['heads'] = [bin(s) for s in head]
2477 args['heads'] = [bin(s) for s in head]
2478 # TODO: get desired bundlecaps from command line.
2478 # TODO: get desired bundlecaps from command line.
2479 args['bundlecaps'] = None
2479 args['bundlecaps'] = None
2480 bundle = repo.getbundle('debug', **args)
2480 bundle = repo.getbundle('debug', **args)
2481
2481
2482 bundletype = opts.get('type', 'bzip2').lower()
2482 bundletype = opts.get('type', 'bzip2').lower()
2483 btypes = {'none': 'HG10UN',
2483 btypes = {'none': 'HG10UN',
2484 'bzip2': 'HG10BZ',
2484 'bzip2': 'HG10BZ',
2485 'gzip': 'HG10GZ',
2485 'gzip': 'HG10GZ',
2486 'bundle2': 'HG20'}
2486 'bundle2': 'HG20'}
2487 bundletype = btypes.get(bundletype)
2487 bundletype = btypes.get(bundletype)
2488 if bundletype not in bundle2.bundletypes:
2488 if bundletype not in bundle2.bundletypes:
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2491
2491
2492 @command('debugignore', [], '[FILE]')
2492 @command('debugignore', [], '[FILE]')
2493 def debugignore(ui, repo, *files, **opts):
2493 def debugignore(ui, repo, *files, **opts):
2494 """display the combined ignore pattern and information about ignored files
2494 """display the combined ignore pattern and information about ignored files
2495
2495
2496 With no argument display the combined ignore pattern.
2496 With no argument display the combined ignore pattern.
2497
2497
2498 Given space separated file names, shows if the given file is ignored and
2498 Given space separated file names, shows if the given file is ignored and
2499 if so, show the ignore rule (file and line number) that matched it.
2499 if so, show the ignore rule (file and line number) that matched it.
2500 """
2500 """
2501 ignore = repo.dirstate._ignore
2501 ignore = repo.dirstate._ignore
2502 if not files:
2502 if not files:
2503 # Show all the patterns
2503 # Show all the patterns
2504 includepat = getattr(ignore, 'includepat', None)
2504 includepat = getattr(ignore, 'includepat', None)
2505 if includepat is not None:
2505 if includepat is not None:
2506 ui.write("%s\n" % includepat)
2506 ui.write("%s\n" % includepat)
2507 else:
2507 else:
2508 raise error.Abort(_("no ignore patterns found"))
2508 raise error.Abort(_("no ignore patterns found"))
2509 else:
2509 else:
2510 for f in files:
2510 for f in files:
2511 nf = util.normpath(f)
2511 nf = util.normpath(f)
2512 ignored = None
2512 ignored = None
2513 ignoredata = None
2513 ignoredata = None
2514 if nf != '.':
2514 if nf != '.':
2515 if ignore(nf):
2515 if ignore(nf):
2516 ignored = nf
2516 ignored = nf
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2518 else:
2518 else:
2519 for p in util.finddirs(nf):
2519 for p in util.finddirs(nf):
2520 if ignore(p):
2520 if ignore(p):
2521 ignored = p
2521 ignored = p
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2523 break
2523 break
2524 if ignored:
2524 if ignored:
2525 if ignored == nf:
2525 if ignored == nf:
2526 ui.write("%s is ignored\n" % f)
2526 ui.write("%s is ignored\n" % f)
2527 else:
2527 else:
2528 ui.write("%s is ignored because of containing folder %s\n"
2528 ui.write("%s is ignored because of containing folder %s\n"
2529 % (f, ignored))
2529 % (f, ignored))
2530 ignorefile, lineno, line = ignoredata
2530 ignorefile, lineno, line = ignoredata
2531 ui.write("(ignore rule in %s, line %d: '%s')\n"
2531 ui.write("(ignore rule in %s, line %d: '%s')\n"
2532 % (ignorefile, lineno, line))
2532 % (ignorefile, lineno, line))
2533 else:
2533 else:
2534 ui.write("%s is not ignored\n" % f)
2534 ui.write("%s is not ignored\n" % f)
2535
2535
2536 @command('debugindex', debugrevlogopts +
2536 @command('debugindex', debugrevlogopts +
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2538 _('[-f FORMAT] -c|-m|FILE'),
2538 _('[-f FORMAT] -c|-m|FILE'),
2539 optionalrepo=True)
2539 optionalrepo=True)
2540 def debugindex(ui, repo, file_=None, **opts):
2540 def debugindex(ui, repo, file_=None, **opts):
2541 """dump the contents of an index file"""
2541 """dump the contents of an index file"""
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2543 format = opts.get('format', 0)
2543 format = opts.get('format', 0)
2544 if format not in (0, 1):
2544 if format not in (0, 1):
2545 raise error.Abort(_("unknown format %d") % format)
2545 raise error.Abort(_("unknown format %d") % format)
2546
2546
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2548 if generaldelta:
2548 if generaldelta:
2549 basehdr = ' delta'
2549 basehdr = ' delta'
2550 else:
2550 else:
2551 basehdr = ' base'
2551 basehdr = ' base'
2552
2552
2553 if ui.debugflag:
2553 if ui.debugflag:
2554 shortfn = hex
2554 shortfn = hex
2555 else:
2555 else:
2556 shortfn = short
2556 shortfn = short
2557
2557
2558 # There might not be anything in r, so have a sane default
2558 # There might not be anything in r, so have a sane default
2559 idlen = 12
2559 idlen = 12
2560 for i in r:
2560 for i in r:
2561 idlen = len(shortfn(r.node(i)))
2561 idlen = len(shortfn(r.node(i)))
2562 break
2562 break
2563
2563
2564 if format == 0:
2564 if format == 0:
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2567 elif format == 1:
2567 elif format == 1:
2568 ui.write(" rev flag offset length"
2568 ui.write(" rev flag offset length"
2569 " size " + basehdr + " link p1 p2"
2569 " size " + basehdr + " link p1 p2"
2570 " %s\n" % "nodeid".rjust(idlen))
2570 " %s\n" % "nodeid".rjust(idlen))
2571
2571
2572 for i in r:
2572 for i in r:
2573 node = r.node(i)
2573 node = r.node(i)
2574 if generaldelta:
2574 if generaldelta:
2575 base = r.deltaparent(i)
2575 base = r.deltaparent(i)
2576 else:
2576 else:
2577 base = r.chainbase(i)
2577 base = r.chainbase(i)
2578 if format == 0:
2578 if format == 0:
2579 try:
2579 try:
2580 pp = r.parents(node)
2580 pp = r.parents(node)
2581 except Exception:
2581 except Exception:
2582 pp = [nullid, nullid]
2582 pp = [nullid, nullid]
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2586 elif format == 1:
2586 elif format == 1:
2587 pr = r.parentrevs(i)
2587 pr = r.parentrevs(i)
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2588 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2589 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2591
2591
2592 @command('debugindexdot', debugrevlogopts,
2592 @command('debugindexdot', debugrevlogopts,
2593 _('-c|-m|FILE'), optionalrepo=True)
2593 _('-c|-m|FILE'), optionalrepo=True)
2594 def debugindexdot(ui, repo, file_=None, **opts):
2594 def debugindexdot(ui, repo, file_=None, **opts):
2595 """dump an index DAG as a graphviz dot file"""
2595 """dump an index DAG as a graphviz dot file"""
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2597 ui.write(("digraph G {\n"))
2597 ui.write(("digraph G {\n"))
2598 for i in r:
2598 for i in r:
2599 node = r.node(i)
2599 node = r.node(i)
2600 pp = r.parents(node)
2600 pp = r.parents(node)
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2602 if pp[1] != nullid:
2602 if pp[1] != nullid:
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2604 ui.write("}\n")
2604 ui.write("}\n")
2605
2605
2606 @command('debugdeltachain',
2606 @command('debugdeltachain',
2607 debugrevlogopts + formatteropts,
2607 debugrevlogopts + formatteropts,
2608 _('-c|-m|FILE'),
2608 _('-c|-m|FILE'),
2609 optionalrepo=True)
2609 optionalrepo=True)
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2611 """dump information about delta chains in a revlog
2611 """dump information about delta chains in a revlog
2612
2612
2613 Output can be templatized. Available template keywords are:
2613 Output can be templatized. Available template keywords are:
2614
2614
2615 rev revision number
2615 rev revision number
2616 chainid delta chain identifier (numbered by unique base)
2616 chainid delta chain identifier (numbered by unique base)
2617 chainlen delta chain length to this revision
2617 chainlen delta chain length to this revision
2618 prevrev previous revision in delta chain
2618 prevrev previous revision in delta chain
2619 deltatype role of delta / how it was computed
2619 deltatype role of delta / how it was computed
2620 compsize compressed size of revision
2620 compsize compressed size of revision
2621 uncompsize uncompressed size of revision
2621 uncompsize uncompressed size of revision
2622 chainsize total size of compressed revisions in chain
2622 chainsize total size of compressed revisions in chain
2623 chainratio total chain size divided by uncompressed revision size
2623 chainratio total chain size divided by uncompressed revision size
2624 (new delta chains typically start at ratio 2.00)
2624 (new delta chains typically start at ratio 2.00)
2625 lindist linear distance from base revision in delta chain to end
2625 lindist linear distance from base revision in delta chain to end
2626 of this revision
2626 of this revision
2627 extradist total size of revisions not part of this delta chain from
2627 extradist total size of revisions not part of this delta chain from
2628 base of delta chain to end of this revision; a measurement
2628 base of delta chain to end of this revision; a measurement
2629 of how much extra data we need to read/seek across to read
2629 of how much extra data we need to read/seek across to read
2630 the delta chain for this revision
2630 the delta chain for this revision
2631 extraratio extradist divided by chainsize; another representation of
2631 extraratio extradist divided by chainsize; another representation of
2632 how much unrelated data is needed to load this delta chain
2632 how much unrelated data is needed to load this delta chain
2633 """
2633 """
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2635 index = r.index
2635 index = r.index
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2637
2637
2638 def revinfo(rev):
2638 def revinfo(rev):
2639 e = index[rev]
2639 e = index[rev]
2640 compsize = e[1]
2640 compsize = e[1]
2641 uncompsize = e[2]
2641 uncompsize = e[2]
2642 chainsize = 0
2642 chainsize = 0
2643
2643
2644 if generaldelta:
2644 if generaldelta:
2645 if e[3] == e[5]:
2645 if e[3] == e[5]:
2646 deltatype = 'p1'
2646 deltatype = 'p1'
2647 elif e[3] == e[6]:
2647 elif e[3] == e[6]:
2648 deltatype = 'p2'
2648 deltatype = 'p2'
2649 elif e[3] == rev - 1:
2649 elif e[3] == rev - 1:
2650 deltatype = 'prev'
2650 deltatype = 'prev'
2651 elif e[3] == rev:
2651 elif e[3] == rev:
2652 deltatype = 'base'
2652 deltatype = 'base'
2653 else:
2653 else:
2654 deltatype = 'other'
2654 deltatype = 'other'
2655 else:
2655 else:
2656 if e[3] == rev:
2656 if e[3] == rev:
2657 deltatype = 'base'
2657 deltatype = 'base'
2658 else:
2658 else:
2659 deltatype = 'prev'
2659 deltatype = 'prev'
2660
2660
2661 chain = r._deltachain(rev)[0]
2661 chain = r._deltachain(rev)[0]
2662 for iterrev in chain:
2662 for iterrev in chain:
2663 e = index[iterrev]
2663 e = index[iterrev]
2664 chainsize += e[1]
2664 chainsize += e[1]
2665
2665
2666 return compsize, uncompsize, deltatype, chain, chainsize
2666 return compsize, uncompsize, deltatype, chain, chainsize
2667
2667
2668 fm = ui.formatter('debugdeltachain', opts)
2668 fm = ui.formatter('debugdeltachain', opts)
2669
2669
2670 fm.plain(' rev chain# chainlen prev delta '
2670 fm.plain(' rev chain# chainlen prev delta '
2671 'size rawsize chainsize ratio lindist extradist '
2671 'size rawsize chainsize ratio lindist extradist '
2672 'extraratio\n')
2672 'extraratio\n')
2673
2673
2674 chainbases = {}
2674 chainbases = {}
2675 for rev in r:
2675 for rev in r:
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2677 chainbase = chain[0]
2677 chainbase = chain[0]
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2679 basestart = r.start(chainbase)
2679 basestart = r.start(chainbase)
2680 revstart = r.start(rev)
2680 revstart = r.start(rev)
2681 lineardist = revstart + comp - basestart
2681 lineardist = revstart + comp - basestart
2682 extradist = lineardist - chainsize
2682 extradist = lineardist - chainsize
2683 try:
2683 try:
2684 prevrev = chain[-2]
2684 prevrev = chain[-2]
2685 except IndexError:
2685 except IndexError:
2686 prevrev = -1
2686 prevrev = -1
2687
2687
2688 chainratio = float(chainsize) / float(uncomp)
2688 chainratio = float(chainsize) / float(uncomp)
2689 extraratio = float(extradist) / float(chainsize)
2689 extraratio = float(extradist) / float(chainsize)
2690
2690
2691 fm.startitem()
2691 fm.startitem()
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2693 'uncompsize chainsize chainratio lindist extradist '
2693 'uncompsize chainsize chainratio lindist extradist '
2694 'extraratio',
2694 'extraratio',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2695 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2698 extraratio,
2698 extraratio,
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2701 uncompsize=uncomp, chainsize=chainsize,
2701 uncompsize=uncomp, chainsize=chainsize,
2702 chainratio=chainratio, lindist=lineardist,
2702 chainratio=chainratio, lindist=lineardist,
2703 extradist=extradist, extraratio=extraratio)
2703 extradist=extradist, extraratio=extraratio)
2704
2704
2705 fm.end()
2705 fm.end()
2706
2706
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2708 def debuginstall(ui, **opts):
2708 def debuginstall(ui, **opts):
2709 '''test Mercurial installation
2709 '''test Mercurial installation
2710
2710
2711 Returns 0 on success.
2711 Returns 0 on success.
2712 '''
2712 '''
2713
2713
2714 def writetemp(contents):
2714 def writetemp(contents):
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2716 f = os.fdopen(fd, "wb")
2716 f = os.fdopen(fd, "wb")
2717 f.write(contents)
2717 f.write(contents)
2718 f.close()
2718 f.close()
2719 return name
2719 return name
2720
2720
2721 problems = 0
2721 problems = 0
2722
2722
2723 fm = ui.formatter('debuginstall', opts)
2723 fm = ui.formatter('debuginstall', opts)
2724 fm.startitem()
2724 fm.startitem()
2725
2725
2726 # encoding
2726 # encoding
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2728 err = None
2728 err = None
2729 try:
2729 try:
2730 encoding.fromlocal("test")
2730 encoding.fromlocal("test")
2731 except error.Abort as inst:
2731 except error.Abort as inst:
2732 err = inst
2732 err = inst
2733 problems += 1
2733 problems += 1
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2735 " (check that your locale is properly set)\n"), err)
2735 " (check that your locale is properly set)\n"), err)
2736
2736
2737 # Python
2737 # Python
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2739 sys.executable)
2739 sys.executable)
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2741 ("%s.%s.%s" % sys.version_info[:3]))
2741 ("%s.%s.%s" % sys.version_info[:3]))
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2743 os.path.dirname(os.__file__))
2743 os.path.dirname(os.__file__))
2744
2744
2745 # compiled modules
2745 # compiled modules
2746 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2746 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2747 os.path.dirname(__file__))
2747 os.path.dirname(__file__))
2748
2748
2749 err = None
2749 err = None
2750 try:
2750 try:
2751 from . import (
2751 from . import (
2752 base85,
2752 base85,
2753 bdiff,
2753 bdiff,
2754 mpatch,
2754 mpatch,
2755 osutil,
2755 osutil,
2756 )
2756 )
2757 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2757 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2758 except Exception as inst:
2758 except Exception as inst:
2759 err = inst
2759 err = inst
2760 problems += 1
2760 problems += 1
2761 fm.condwrite(err, 'extensionserror', " %s\n", err)
2761 fm.condwrite(err, 'extensionserror', " %s\n", err)
2762
2762
2763 # templates
2763 # templates
2764 p = templater.templatepaths()
2764 p = templater.templatepaths()
2765 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2765 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2766 fm.condwrite(not p, '', _(" no template directories found\n"))
2766 fm.condwrite(not p, '', _(" no template directories found\n"))
2767 if p:
2767 if p:
2768 m = templater.templatepath("map-cmdline.default")
2768 m = templater.templatepath("map-cmdline.default")
2769 if m:
2769 if m:
2770 # template found, check if it is working
2770 # template found, check if it is working
2771 err = None
2771 err = None
2772 try:
2772 try:
2773 templater.templater(m)
2773 templater.templater(m)
2774 except Exception as inst:
2774 except Exception as inst:
2775 err = inst
2775 err = inst
2776 p = None
2776 p = None
2777 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2777 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2778 else:
2778 else:
2779 p = None
2779 p = None
2780 fm.condwrite(p, 'defaulttemplate',
2780 fm.condwrite(p, 'defaulttemplate',
2781 _("checking default template (%s)\n"), m)
2781 _("checking default template (%s)\n"), m)
2782 fm.condwrite(not m, 'defaulttemplatenotfound',
2782 fm.condwrite(not m, 'defaulttemplatenotfound',
2783 _(" template '%s' not found\n"), "default")
2783 _(" template '%s' not found\n"), "default")
2784 if not p:
2784 if not p:
2785 problems += 1
2785 problems += 1
2786 fm.condwrite(not p, '',
2786 fm.condwrite(not p, '',
2787 _(" (templates seem to have been installed incorrectly)\n"))
2787 _(" (templates seem to have been installed incorrectly)\n"))
2788
2788
2789 # editor
2789 # editor
2790 editor = ui.geteditor()
2790 editor = ui.geteditor()
2791 editor = util.expandpath(editor)
2791 editor = util.expandpath(editor)
2792 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2792 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2793 cmdpath = util.findexe(shlex.split(editor)[0])
2793 cmdpath = util.findexe(shlex.split(editor)[0])
2794 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2794 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2795 _(" No commit editor set and can't find %s in PATH\n"
2795 _(" No commit editor set and can't find %s in PATH\n"
2796 " (specify a commit editor in your configuration"
2796 " (specify a commit editor in your configuration"
2797 " file)\n"), not cmdpath and editor == 'vi' and editor)
2797 " file)\n"), not cmdpath and editor == 'vi' and editor)
2798 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2798 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2799 _(" Can't find editor '%s' in PATH\n"
2799 _(" Can't find editor '%s' in PATH\n"
2800 " (specify a commit editor in your configuration"
2800 " (specify a commit editor in your configuration"
2801 " file)\n"), not cmdpath and editor)
2801 " file)\n"), not cmdpath and editor)
2802 if not cmdpath and editor != 'vi':
2802 if not cmdpath and editor != 'vi':
2803 problems += 1
2803 problems += 1
2804
2804
2805 # check username
2805 # check username
2806 username = None
2806 username = None
2807 err = None
2807 err = None
2808 try:
2808 try:
2809 username = ui.username()
2809 username = ui.username()
2810 except error.Abort as e:
2810 except error.Abort as e:
2811 err = e
2811 err = e
2812 problems += 1
2812 problems += 1
2813
2813
2814 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2814 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2815 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2815 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2816 " (specify a username in your configuration file)\n"), err)
2816 " (specify a username in your configuration file)\n"), err)
2817
2817
2818 fm.condwrite(not problems, '',
2818 fm.condwrite(not problems, '',
2819 _("no problems detected\n"))
2819 _("no problems detected\n"))
2820 if not problems:
2820 if not problems:
2821 fm.data(problems=problems)
2821 fm.data(problems=problems)
2822 fm.condwrite(problems, 'problems',
2822 fm.condwrite(problems, 'problems',
2823 _("%s problems detected,"
2823 _("%s problems detected,"
2824 " please check your install!\n"), problems)
2824 " please check your install!\n"), problems)
2825 fm.end()
2825 fm.end()
2826
2826
2827 return problems
2827 return problems
2828
2828
2829 @command('debugknown', [], _('REPO ID...'), norepo=True)
2829 @command('debugknown', [], _('REPO ID...'), norepo=True)
2830 def debugknown(ui, repopath, *ids, **opts):
2830 def debugknown(ui, repopath, *ids, **opts):
2831 """test whether node ids are known to a repo
2831 """test whether node ids are known to a repo
2832
2832
2833 Every ID must be a full-length hex node id string. Returns a list of 0s
2833 Every ID must be a full-length hex node id string. Returns a list of 0s
2834 and 1s indicating unknown/known.
2834 and 1s indicating unknown/known.
2835 """
2835 """
2836 repo = hg.peer(ui, opts, repopath)
2836 repo = hg.peer(ui, opts, repopath)
2837 if not repo.capable('known'):
2837 if not repo.capable('known'):
2838 raise error.Abort("known() not supported by target repository")
2838 raise error.Abort("known() not supported by target repository")
2839 flags = repo.known([bin(s) for s in ids])
2839 flags = repo.known([bin(s) for s in ids])
2840 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2840 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2841
2841
2842 @command('debuglabelcomplete', [], _('LABEL...'))
2842 @command('debuglabelcomplete', [], _('LABEL...'))
2843 def debuglabelcomplete(ui, repo, *args):
2843 def debuglabelcomplete(ui, repo, *args):
2844 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2844 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2845 debugnamecomplete(ui, repo, *args)
2845 debugnamecomplete(ui, repo, *args)
2846
2846
2847 @command('debugmergestate', [], '')
2847 @command('debugmergestate', [], '')
2848 def debugmergestate(ui, repo, *args):
2848 def debugmergestate(ui, repo, *args):
2849 """print merge state
2849 """print merge state
2850
2850
2851 Use --verbose to print out information about whether v1 or v2 merge state
2851 Use --verbose to print out information about whether v1 or v2 merge state
2852 was chosen."""
2852 was chosen."""
2853 def _hashornull(h):
2853 def _hashornull(h):
2854 if h == nullhex:
2854 if h == nullhex:
2855 return 'null'
2855 return 'null'
2856 else:
2856 else:
2857 return h
2857 return h
2858
2858
2859 def printrecords(version):
2859 def printrecords(version):
2860 ui.write(('* version %s records\n') % version)
2860 ui.write(('* version %s records\n') % version)
2861 if version == 1:
2861 if version == 1:
2862 records = v1records
2862 records = v1records
2863 else:
2863 else:
2864 records = v2records
2864 records = v2records
2865
2865
2866 for rtype, record in records:
2866 for rtype, record in records:
2867 # pretty print some record types
2867 # pretty print some record types
2868 if rtype == 'L':
2868 if rtype == 'L':
2869 ui.write(('local: %s\n') % record)
2869 ui.write(('local: %s\n') % record)
2870 elif rtype == 'O':
2870 elif rtype == 'O':
2871 ui.write(('other: %s\n') % record)
2871 ui.write(('other: %s\n') % record)
2872 elif rtype == 'm':
2872 elif rtype == 'm':
2873 driver, mdstate = record.split('\0', 1)
2873 driver, mdstate = record.split('\0', 1)
2874 ui.write(('merge driver: %s (state "%s")\n')
2874 ui.write(('merge driver: %s (state "%s")\n')
2875 % (driver, mdstate))
2875 % (driver, mdstate))
2876 elif rtype in 'FDC':
2876 elif rtype in 'FDC':
2877 r = record.split('\0')
2877 r = record.split('\0')
2878 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2878 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2879 if version == 1:
2879 if version == 1:
2880 onode = 'not stored in v1 format'
2880 onode = 'not stored in v1 format'
2881 flags = r[7]
2881 flags = r[7]
2882 else:
2882 else:
2883 onode, flags = r[7:9]
2883 onode, flags = r[7:9]
2884 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2884 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2885 % (f, rtype, state, _hashornull(hash)))
2885 % (f, rtype, state, _hashornull(hash)))
2886 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2886 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2887 ui.write((' ancestor path: %s (node %s)\n')
2887 ui.write((' ancestor path: %s (node %s)\n')
2888 % (afile, _hashornull(anode)))
2888 % (afile, _hashornull(anode)))
2889 ui.write((' other path: %s (node %s)\n')
2889 ui.write((' other path: %s (node %s)\n')
2890 % (ofile, _hashornull(onode)))
2890 % (ofile, _hashornull(onode)))
2891 elif rtype == 'f':
2891 elif rtype == 'f':
2892 filename, rawextras = record.split('\0', 1)
2892 filename, rawextras = record.split('\0', 1)
2893 extras = rawextras.split('\0')
2893 extras = rawextras.split('\0')
2894 i = 0
2894 i = 0
2895 extrastrings = []
2895 extrastrings = []
2896 while i < len(extras):
2896 while i < len(extras):
2897 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2897 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2898 i += 2
2898 i += 2
2899
2899
2900 ui.write(('file extras: %s (%s)\n')
2900 ui.write(('file extras: %s (%s)\n')
2901 % (filename, ', '.join(extrastrings)))
2901 % (filename, ', '.join(extrastrings)))
2902 elif rtype == 'l':
2902 elif rtype == 'l':
2903 labels = record.split('\0', 2)
2903 labels = record.split('\0', 2)
2904 labels = [l for l in labels if len(l) > 0]
2904 labels = [l for l in labels if len(l) > 0]
2905 ui.write(('labels:\n'))
2905 ui.write(('labels:\n'))
2906 ui.write((' local: %s\n' % labels[0]))
2906 ui.write((' local: %s\n' % labels[0]))
2907 ui.write((' other: %s\n' % labels[1]))
2907 ui.write((' other: %s\n' % labels[1]))
2908 if len(labels) > 2:
2908 if len(labels) > 2:
2909 ui.write((' base: %s\n' % labels[2]))
2909 ui.write((' base: %s\n' % labels[2]))
2910 else:
2910 else:
2911 ui.write(('unrecognized entry: %s\t%s\n')
2911 ui.write(('unrecognized entry: %s\t%s\n')
2912 % (rtype, record.replace('\0', '\t')))
2912 % (rtype, record.replace('\0', '\t')))
2913
2913
2914 # Avoid mergestate.read() since it may raise an exception for unsupported
2914 # Avoid mergestate.read() since it may raise an exception for unsupported
2915 # merge state records. We shouldn't be doing this, but this is OK since this
2915 # merge state records. We shouldn't be doing this, but this is OK since this
2916 # command is pretty low-level.
2916 # command is pretty low-level.
2917 ms = mergemod.mergestate(repo)
2917 ms = mergemod.mergestate(repo)
2918
2918
2919 # sort so that reasonable information is on top
2919 # sort so that reasonable information is on top
2920 v1records = ms._readrecordsv1()
2920 v1records = ms._readrecordsv1()
2921 v2records = ms._readrecordsv2()
2921 v2records = ms._readrecordsv2()
2922 order = 'LOml'
2922 order = 'LOml'
2923 def key(r):
2923 def key(r):
2924 idx = order.find(r[0])
2924 idx = order.find(r[0])
2925 if idx == -1:
2925 if idx == -1:
2926 return (1, r[1])
2926 return (1, r[1])
2927 else:
2927 else:
2928 return (0, idx)
2928 return (0, idx)
2929 v1records.sort(key=key)
2929 v1records.sort(key=key)
2930 v2records.sort(key=key)
2930 v2records.sort(key=key)
2931
2931
2932 if not v1records and not v2records:
2932 if not v1records and not v2records:
2933 ui.write(('no merge state found\n'))
2933 ui.write(('no merge state found\n'))
2934 elif not v2records:
2934 elif not v2records:
2935 ui.note(('no version 2 merge state\n'))
2935 ui.note(('no version 2 merge state\n'))
2936 printrecords(1)
2936 printrecords(1)
2937 elif ms._v1v2match(v1records, v2records):
2937 elif ms._v1v2match(v1records, v2records):
2938 ui.note(('v1 and v2 states match: using v2\n'))
2938 ui.note(('v1 and v2 states match: using v2\n'))
2939 printrecords(2)
2939 printrecords(2)
2940 else:
2940 else:
2941 ui.note(('v1 and v2 states mismatch: using v1\n'))
2941 ui.note(('v1 and v2 states mismatch: using v1\n'))
2942 printrecords(1)
2942 printrecords(1)
2943 if ui.verbose:
2943 if ui.verbose:
2944 printrecords(2)
2944 printrecords(2)
2945
2945
2946 @command('debugnamecomplete', [], _('NAME...'))
2946 @command('debugnamecomplete', [], _('NAME...'))
2947 def debugnamecomplete(ui, repo, *args):
2947 def debugnamecomplete(ui, repo, *args):
2948 '''complete "names" - tags, open branch names, bookmark names'''
2948 '''complete "names" - tags, open branch names, bookmark names'''
2949
2949
2950 names = set()
2950 names = set()
2951 # since we previously only listed open branches, we will handle that
2951 # since we previously only listed open branches, we will handle that
2952 # specially (after this for loop)
2952 # specially (after this for loop)
2953 for name, ns in repo.names.iteritems():
2953 for name, ns in repo.names.iteritems():
2954 if name != 'branches':
2954 if name != 'branches':
2955 names.update(ns.listnames(repo))
2955 names.update(ns.listnames(repo))
2956 names.update(tag for (tag, heads, tip, closed)
2956 names.update(tag for (tag, heads, tip, closed)
2957 in repo.branchmap().iterbranches() if not closed)
2957 in repo.branchmap().iterbranches() if not closed)
2958 completions = set()
2958 completions = set()
2959 if not args:
2959 if not args:
2960 args = ['']
2960 args = ['']
2961 for a in args:
2961 for a in args:
2962 completions.update(n for n in names if n.startswith(a))
2962 completions.update(n for n in names if n.startswith(a))
2963 ui.write('\n'.join(sorted(completions)))
2963 ui.write('\n'.join(sorted(completions)))
2964 ui.write('\n')
2964 ui.write('\n')
2965
2965
2966 @command('debuglocks',
2966 @command('debuglocks',
2967 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2967 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2968 ('W', 'force-wlock', None,
2968 ('W', 'force-wlock', None,
2969 _('free the working state lock (DANGEROUS)'))],
2969 _('free the working state lock (DANGEROUS)'))],
2970 _('[OPTION]...'))
2970 _('[OPTION]...'))
2971 def debuglocks(ui, repo, **opts):
2971 def debuglocks(ui, repo, **opts):
2972 """show or modify state of locks
2972 """show or modify state of locks
2973
2973
2974 By default, this command will show which locks are held. This
2974 By default, this command will show which locks are held. This
2975 includes the user and process holding the lock, the amount of time
2975 includes the user and process holding the lock, the amount of time
2976 the lock has been held, and the machine name where the process is
2976 the lock has been held, and the machine name where the process is
2977 running if it's not local.
2977 running if it's not local.
2978
2978
2979 Locks protect the integrity of Mercurial's data, so should be
2979 Locks protect the integrity of Mercurial's data, so should be
2980 treated with care. System crashes or other interruptions may cause
2980 treated with care. System crashes or other interruptions may cause
2981 locks to not be properly released, though Mercurial will usually
2981 locks to not be properly released, though Mercurial will usually
2982 detect and remove such stale locks automatically.
2982 detect and remove such stale locks automatically.
2983
2983
2984 However, detecting stale locks may not always be possible (for
2984 However, detecting stale locks may not always be possible (for
2985 instance, on a shared filesystem). Removing locks may also be
2985 instance, on a shared filesystem). Removing locks may also be
2986 blocked by filesystem permissions.
2986 blocked by filesystem permissions.
2987
2987
2988 Returns 0 if no locks are held.
2988 Returns 0 if no locks are held.
2989
2989
2990 """
2990 """
2991
2991
2992 if opts.get('force_lock'):
2992 if opts.get('force_lock'):
2993 repo.svfs.unlink('lock')
2993 repo.svfs.unlink('lock')
2994 if opts.get('force_wlock'):
2994 if opts.get('force_wlock'):
2995 repo.vfs.unlink('wlock')
2995 repo.vfs.unlink('wlock')
2996 if opts.get('force_lock') or opts.get('force_lock'):
2996 if opts.get('force_lock') or opts.get('force_lock'):
2997 return 0
2997 return 0
2998
2998
2999 now = time.time()
2999 now = time.time()
3000 held = 0
3000 held = 0
3001
3001
3002 def report(vfs, name, method):
3002 def report(vfs, name, method):
3003 # this causes stale locks to get reaped for more accurate reporting
3003 # this causes stale locks to get reaped for more accurate reporting
3004 try:
3004 try:
3005 l = method(False)
3005 l = method(False)
3006 except error.LockHeld:
3006 except error.LockHeld:
3007 l = None
3007 l = None
3008
3008
3009 if l:
3009 if l:
3010 l.release()
3010 l.release()
3011 else:
3011 else:
3012 try:
3012 try:
3013 stat = vfs.lstat(name)
3013 stat = vfs.lstat(name)
3014 age = now - stat.st_mtime
3014 age = now - stat.st_mtime
3015 user = util.username(stat.st_uid)
3015 user = util.username(stat.st_uid)
3016 locker = vfs.readlock(name)
3016 locker = vfs.readlock(name)
3017 if ":" in locker:
3017 if ":" in locker:
3018 host, pid = locker.split(':')
3018 host, pid = locker.split(':')
3019 if host == socket.gethostname():
3019 if host == socket.gethostname():
3020 locker = 'user %s, process %s' % (user, pid)
3020 locker = 'user %s, process %s' % (user, pid)
3021 else:
3021 else:
3022 locker = 'user %s, process %s, host %s' \
3022 locker = 'user %s, process %s, host %s' \
3023 % (user, pid, host)
3023 % (user, pid, host)
3024 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3024 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3025 return 1
3025 return 1
3026 except OSError as e:
3026 except OSError as e:
3027 if e.errno != errno.ENOENT:
3027 if e.errno != errno.ENOENT:
3028 raise
3028 raise
3029
3029
3030 ui.write("%-6s free\n" % (name + ":"))
3030 ui.write("%-6s free\n" % (name + ":"))
3031 return 0
3031 return 0
3032
3032
3033 held += report(repo.svfs, "lock", repo.lock)
3033 held += report(repo.svfs, "lock", repo.lock)
3034 held += report(repo.vfs, "wlock", repo.wlock)
3034 held += report(repo.vfs, "wlock", repo.wlock)
3035
3035
3036 return held
3036 return held
3037
3037
3038 @command('debugobsolete',
3038 @command('debugobsolete',
3039 [('', 'flags', 0, _('markers flag')),
3039 [('', 'flags', 0, _('markers flag')),
3040 ('', 'record-parents', False,
3040 ('', 'record-parents', False,
3041 _('record parent information for the precursor')),
3041 _('record parent information for the precursor')),
3042 ('r', 'rev', [], _('display markers relevant to REV')),
3042 ('r', 'rev', [], _('display markers relevant to REV')),
3043 ('', 'index', False, _('display index of the marker')),
3043 ('', 'index', False, _('display index of the marker')),
3044 ] + commitopts2,
3044 ] + commitopts2,
3045 _('[OBSOLETED [REPLACEMENT ...]]'))
3045 _('[OBSOLETED [REPLACEMENT ...]]'))
3046 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3046 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3047 """create arbitrary obsolete marker
3047 """create arbitrary obsolete marker
3048
3048
3049 With no arguments, displays the list of obsolescence markers."""
3049 With no arguments, displays the list of obsolescence markers."""
3050
3050
3051 def parsenodeid(s):
3051 def parsenodeid(s):
3052 try:
3052 try:
3053 # We do not use revsingle/revrange functions here to accept
3053 # We do not use revsingle/revrange functions here to accept
3054 # arbitrary node identifiers, possibly not present in the
3054 # arbitrary node identifiers, possibly not present in the
3055 # local repository.
3055 # local repository.
3056 n = bin(s)
3056 n = bin(s)
3057 if len(n) != len(nullid):
3057 if len(n) != len(nullid):
3058 raise TypeError()
3058 raise TypeError()
3059 return n
3059 return n
3060 except TypeError:
3060 except TypeError:
3061 raise error.Abort('changeset references must be full hexadecimal '
3061 raise error.Abort('changeset references must be full hexadecimal '
3062 'node identifiers')
3062 'node identifiers')
3063
3063
3064 if precursor is not None:
3064 if precursor is not None:
3065 if opts['rev']:
3065 if opts['rev']:
3066 raise error.Abort('cannot select revision when creating marker')
3066 raise error.Abort('cannot select revision when creating marker')
3067 metadata = {}
3067 metadata = {}
3068 metadata['user'] = opts['user'] or ui.username()
3068 metadata['user'] = opts['user'] or ui.username()
3069 succs = tuple(parsenodeid(succ) for succ in successors)
3069 succs = tuple(parsenodeid(succ) for succ in successors)
3070 l = repo.lock()
3070 l = repo.lock()
3071 try:
3071 try:
3072 tr = repo.transaction('debugobsolete')
3072 tr = repo.transaction('debugobsolete')
3073 try:
3073 try:
3074 date = opts.get('date')
3074 date = opts.get('date')
3075 if date:
3075 if date:
3076 date = util.parsedate(date)
3076 date = util.parsedate(date)
3077 else:
3077 else:
3078 date = None
3078 date = None
3079 prec = parsenodeid(precursor)
3079 prec = parsenodeid(precursor)
3080 parents = None
3080 parents = None
3081 if opts['record_parents']:
3081 if opts['record_parents']:
3082 if prec not in repo.unfiltered():
3082 if prec not in repo.unfiltered():
3083 raise error.Abort('cannot used --record-parents on '
3083 raise error.Abort('cannot used --record-parents on '
3084 'unknown changesets')
3084 'unknown changesets')
3085 parents = repo.unfiltered()[prec].parents()
3085 parents = repo.unfiltered()[prec].parents()
3086 parents = tuple(p.node() for p in parents)
3086 parents = tuple(p.node() for p in parents)
3087 repo.obsstore.create(tr, prec, succs, opts['flags'],
3087 repo.obsstore.create(tr, prec, succs, opts['flags'],
3088 parents=parents, date=date,
3088 parents=parents, date=date,
3089 metadata=metadata)
3089 metadata=metadata)
3090 tr.close()
3090 tr.close()
3091 except ValueError as exc:
3091 except ValueError as exc:
3092 raise error.Abort(_('bad obsmarker input: %s') % exc)
3092 raise error.Abort(_('bad obsmarker input: %s') % exc)
3093 finally:
3093 finally:
3094 tr.release()
3094 tr.release()
3095 finally:
3095 finally:
3096 l.release()
3096 l.release()
3097 else:
3097 else:
3098 if opts.get('rev') and opts.get('index'):
3099 hint = _("call 'hg debugobsolete --index' without other arguments")
3100 raise error.Abort(_("cannot use --index with --rev"), hint=hint)
3098 if opts['rev']:
3101 if opts['rev']:
3099 revs = scmutil.revrange(repo, opts['rev'])
3102 revs = scmutil.revrange(repo, opts['rev'])
3100 nodes = [repo[r].node() for r in revs]
3103 nodes = [repo[r].node() for r in revs]
3101 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3104 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3102 markers.sort(key=lambda x: x._data)
3105 markers.sort(key=lambda x: x._data)
3103 else:
3106 else:
3104 markers = obsolete.getmarkers(repo)
3107 markers = obsolete.getmarkers(repo)
3105
3108
3106 for i, m in enumerate(markers):
3109 for i, m in enumerate(markers):
3107 ind = i if opts.get('index') else None
3110 ind = i if opts.get('index') else None
3108 cmdutil.showmarker(ui, m, index=ind)
3111 cmdutil.showmarker(ui, m, index=ind)
3109
3112
3110 @command('debugpathcomplete',
3113 @command('debugpathcomplete',
3111 [('f', 'full', None, _('complete an entire path')),
3114 [('f', 'full', None, _('complete an entire path')),
3112 ('n', 'normal', None, _('show only normal files')),
3115 ('n', 'normal', None, _('show only normal files')),
3113 ('a', 'added', None, _('show only added files')),
3116 ('a', 'added', None, _('show only added files')),
3114 ('r', 'removed', None, _('show only removed files'))],
3117 ('r', 'removed', None, _('show only removed files'))],
3115 _('FILESPEC...'))
3118 _('FILESPEC...'))
3116 def debugpathcomplete(ui, repo, *specs, **opts):
3119 def debugpathcomplete(ui, repo, *specs, **opts):
3117 '''complete part or all of a tracked path
3120 '''complete part or all of a tracked path
3118
3121
3119 This command supports shells that offer path name completion. It
3122 This command supports shells that offer path name completion. It
3120 currently completes only files already known to the dirstate.
3123 currently completes only files already known to the dirstate.
3121
3124
3122 Completion extends only to the next path segment unless
3125 Completion extends only to the next path segment unless
3123 --full is specified, in which case entire paths are used.'''
3126 --full is specified, in which case entire paths are used.'''
3124
3127
3125 def complete(path, acceptable):
3128 def complete(path, acceptable):
3126 dirstate = repo.dirstate
3129 dirstate = repo.dirstate
3127 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3130 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3128 rootdir = repo.root + os.sep
3131 rootdir = repo.root + os.sep
3129 if spec != repo.root and not spec.startswith(rootdir):
3132 if spec != repo.root and not spec.startswith(rootdir):
3130 return [], []
3133 return [], []
3131 if os.path.isdir(spec):
3134 if os.path.isdir(spec):
3132 spec += '/'
3135 spec += '/'
3133 spec = spec[len(rootdir):]
3136 spec = spec[len(rootdir):]
3134 fixpaths = os.sep != '/'
3137 fixpaths = os.sep != '/'
3135 if fixpaths:
3138 if fixpaths:
3136 spec = spec.replace(os.sep, '/')
3139 spec = spec.replace(os.sep, '/')
3137 speclen = len(spec)
3140 speclen = len(spec)
3138 fullpaths = opts['full']
3141 fullpaths = opts['full']
3139 files, dirs = set(), set()
3142 files, dirs = set(), set()
3140 adddir, addfile = dirs.add, files.add
3143 adddir, addfile = dirs.add, files.add
3141 for f, st in dirstate.iteritems():
3144 for f, st in dirstate.iteritems():
3142 if f.startswith(spec) and st[0] in acceptable:
3145 if f.startswith(spec) and st[0] in acceptable:
3143 if fixpaths:
3146 if fixpaths:
3144 f = f.replace('/', os.sep)
3147 f = f.replace('/', os.sep)
3145 if fullpaths:
3148 if fullpaths:
3146 addfile(f)
3149 addfile(f)
3147 continue
3150 continue
3148 s = f.find(os.sep, speclen)
3151 s = f.find(os.sep, speclen)
3149 if s >= 0:
3152 if s >= 0:
3150 adddir(f[:s])
3153 adddir(f[:s])
3151 else:
3154 else:
3152 addfile(f)
3155 addfile(f)
3153 return files, dirs
3156 return files, dirs
3154
3157
3155 acceptable = ''
3158 acceptable = ''
3156 if opts['normal']:
3159 if opts['normal']:
3157 acceptable += 'nm'
3160 acceptable += 'nm'
3158 if opts['added']:
3161 if opts['added']:
3159 acceptable += 'a'
3162 acceptable += 'a'
3160 if opts['removed']:
3163 if opts['removed']:
3161 acceptable += 'r'
3164 acceptable += 'r'
3162 cwd = repo.getcwd()
3165 cwd = repo.getcwd()
3163 if not specs:
3166 if not specs:
3164 specs = ['.']
3167 specs = ['.']
3165
3168
3166 files, dirs = set(), set()
3169 files, dirs = set(), set()
3167 for spec in specs:
3170 for spec in specs:
3168 f, d = complete(spec, acceptable or 'nmar')
3171 f, d = complete(spec, acceptable or 'nmar')
3169 files.update(f)
3172 files.update(f)
3170 dirs.update(d)
3173 dirs.update(d)
3171 files.update(dirs)
3174 files.update(dirs)
3172 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3175 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3173 ui.write('\n')
3176 ui.write('\n')
3174
3177
3175 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3178 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3176 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3179 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3177 '''access the pushkey key/value protocol
3180 '''access the pushkey key/value protocol
3178
3181
3179 With two args, list the keys in the given namespace.
3182 With two args, list the keys in the given namespace.
3180
3183
3181 With five args, set a key to new if it currently is set to old.
3184 With five args, set a key to new if it currently is set to old.
3182 Reports success or failure.
3185 Reports success or failure.
3183 '''
3186 '''
3184
3187
3185 target = hg.peer(ui, {}, repopath)
3188 target = hg.peer(ui, {}, repopath)
3186 if keyinfo:
3189 if keyinfo:
3187 key, old, new = keyinfo
3190 key, old, new = keyinfo
3188 r = target.pushkey(namespace, key, old, new)
3191 r = target.pushkey(namespace, key, old, new)
3189 ui.status(str(r) + '\n')
3192 ui.status(str(r) + '\n')
3190 return not r
3193 return not r
3191 else:
3194 else:
3192 for k, v in sorted(target.listkeys(namespace).iteritems()):
3195 for k, v in sorted(target.listkeys(namespace).iteritems()):
3193 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3196 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3194 v.encode('string-escape')))
3197 v.encode('string-escape')))
3195
3198
3196 @command('debugpvec', [], _('A B'))
3199 @command('debugpvec', [], _('A B'))
3197 def debugpvec(ui, repo, a, b=None):
3200 def debugpvec(ui, repo, a, b=None):
3198 ca = scmutil.revsingle(repo, a)
3201 ca = scmutil.revsingle(repo, a)
3199 cb = scmutil.revsingle(repo, b)
3202 cb = scmutil.revsingle(repo, b)
3200 pa = pvec.ctxpvec(ca)
3203 pa = pvec.ctxpvec(ca)
3201 pb = pvec.ctxpvec(cb)
3204 pb = pvec.ctxpvec(cb)
3202 if pa == pb:
3205 if pa == pb:
3203 rel = "="
3206 rel = "="
3204 elif pa > pb:
3207 elif pa > pb:
3205 rel = ">"
3208 rel = ">"
3206 elif pa < pb:
3209 elif pa < pb:
3207 rel = "<"
3210 rel = "<"
3208 elif pa | pb:
3211 elif pa | pb:
3209 rel = "|"
3212 rel = "|"
3210 ui.write(_("a: %s\n") % pa)
3213 ui.write(_("a: %s\n") % pa)
3211 ui.write(_("b: %s\n") % pb)
3214 ui.write(_("b: %s\n") % pb)
3212 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3215 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3213 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3216 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3214 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3217 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3215 pa.distance(pb), rel))
3218 pa.distance(pb), rel))
3216
3219
3217 @command('debugrebuilddirstate|debugrebuildstate',
3220 @command('debugrebuilddirstate|debugrebuildstate',
3218 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3221 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3219 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3222 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3220 'the working copy parent')),
3223 'the working copy parent')),
3221 ],
3224 ],
3222 _('[-r REV]'))
3225 _('[-r REV]'))
3223 def debugrebuilddirstate(ui, repo, rev, **opts):
3226 def debugrebuilddirstate(ui, repo, rev, **opts):
3224 """rebuild the dirstate as it would look like for the given revision
3227 """rebuild the dirstate as it would look like for the given revision
3225
3228
3226 If no revision is specified the first current parent will be used.
3229 If no revision is specified the first current parent will be used.
3227
3230
3228 The dirstate will be set to the files of the given revision.
3231 The dirstate will be set to the files of the given revision.
3229 The actual working directory content or existing dirstate
3232 The actual working directory content or existing dirstate
3230 information such as adds or removes is not considered.
3233 information such as adds or removes is not considered.
3231
3234
3232 ``minimal`` will only rebuild the dirstate status for files that claim to be
3235 ``minimal`` will only rebuild the dirstate status for files that claim to be
3233 tracked but are not in the parent manifest, or that exist in the parent
3236 tracked but are not in the parent manifest, or that exist in the parent
3234 manifest but are not in the dirstate. It will not change adds, removes, or
3237 manifest but are not in the dirstate. It will not change adds, removes, or
3235 modified files that are in the working copy parent.
3238 modified files that are in the working copy parent.
3236
3239
3237 One use of this command is to make the next :hg:`status` invocation
3240 One use of this command is to make the next :hg:`status` invocation
3238 check the actual file content.
3241 check the actual file content.
3239 """
3242 """
3240 ctx = scmutil.revsingle(repo, rev)
3243 ctx = scmutil.revsingle(repo, rev)
3241 with repo.wlock():
3244 with repo.wlock():
3242 dirstate = repo.dirstate
3245 dirstate = repo.dirstate
3243 changedfiles = None
3246 changedfiles = None
3244 # See command doc for what minimal does.
3247 # See command doc for what minimal does.
3245 if opts.get('minimal'):
3248 if opts.get('minimal'):
3246 manifestfiles = set(ctx.manifest().keys())
3249 manifestfiles = set(ctx.manifest().keys())
3247 dirstatefiles = set(dirstate)
3250 dirstatefiles = set(dirstate)
3248 manifestonly = manifestfiles - dirstatefiles
3251 manifestonly = manifestfiles - dirstatefiles
3249 dsonly = dirstatefiles - manifestfiles
3252 dsonly = dirstatefiles - manifestfiles
3250 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3253 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3251 changedfiles = manifestonly | dsnotadded
3254 changedfiles = manifestonly | dsnotadded
3252
3255
3253 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3256 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3254
3257
3255 @command('debugrebuildfncache', [], '')
3258 @command('debugrebuildfncache', [], '')
3256 def debugrebuildfncache(ui, repo):
3259 def debugrebuildfncache(ui, repo):
3257 """rebuild the fncache file"""
3260 """rebuild the fncache file"""
3258 repair.rebuildfncache(ui, repo)
3261 repair.rebuildfncache(ui, repo)
3259
3262
3260 @command('debugrename',
3263 @command('debugrename',
3261 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3264 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3262 _('[-r REV] FILE'))
3265 _('[-r REV] FILE'))
3263 def debugrename(ui, repo, file1, *pats, **opts):
3266 def debugrename(ui, repo, file1, *pats, **opts):
3264 """dump rename information"""
3267 """dump rename information"""
3265
3268
3266 ctx = scmutil.revsingle(repo, opts.get('rev'))
3269 ctx = scmutil.revsingle(repo, opts.get('rev'))
3267 m = scmutil.match(ctx, (file1,) + pats, opts)
3270 m = scmutil.match(ctx, (file1,) + pats, opts)
3268 for abs in ctx.walk(m):
3271 for abs in ctx.walk(m):
3269 fctx = ctx[abs]
3272 fctx = ctx[abs]
3270 o = fctx.filelog().renamed(fctx.filenode())
3273 o = fctx.filelog().renamed(fctx.filenode())
3271 rel = m.rel(abs)
3274 rel = m.rel(abs)
3272 if o:
3275 if o:
3273 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3276 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3274 else:
3277 else:
3275 ui.write(_("%s not renamed\n") % rel)
3278 ui.write(_("%s not renamed\n") % rel)
3276
3279
3277 @command('debugrevlog', debugrevlogopts +
3280 @command('debugrevlog', debugrevlogopts +
3278 [('d', 'dump', False, _('dump index data'))],
3281 [('d', 'dump', False, _('dump index data'))],
3279 _('-c|-m|FILE'),
3282 _('-c|-m|FILE'),
3280 optionalrepo=True)
3283 optionalrepo=True)
3281 def debugrevlog(ui, repo, file_=None, **opts):
3284 def debugrevlog(ui, repo, file_=None, **opts):
3282 """show data and statistics about a revlog"""
3285 """show data and statistics about a revlog"""
3283 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3286 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3284
3287
3285 if opts.get("dump"):
3288 if opts.get("dump"):
3286 numrevs = len(r)
3289 numrevs = len(r)
3287 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3290 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3288 " rawsize totalsize compression heads chainlen\n")
3291 " rawsize totalsize compression heads chainlen\n")
3289 ts = 0
3292 ts = 0
3290 heads = set()
3293 heads = set()
3291
3294
3292 for rev in xrange(numrevs):
3295 for rev in xrange(numrevs):
3293 dbase = r.deltaparent(rev)
3296 dbase = r.deltaparent(rev)
3294 if dbase == -1:
3297 if dbase == -1:
3295 dbase = rev
3298 dbase = rev
3296 cbase = r.chainbase(rev)
3299 cbase = r.chainbase(rev)
3297 clen = r.chainlen(rev)
3300 clen = r.chainlen(rev)
3298 p1, p2 = r.parentrevs(rev)
3301 p1, p2 = r.parentrevs(rev)
3299 rs = r.rawsize(rev)
3302 rs = r.rawsize(rev)
3300 ts = ts + rs
3303 ts = ts + rs
3301 heads -= set(r.parentrevs(rev))
3304 heads -= set(r.parentrevs(rev))
3302 heads.add(rev)
3305 heads.add(rev)
3303 try:
3306 try:
3304 compression = ts / r.end(rev)
3307 compression = ts / r.end(rev)
3305 except ZeroDivisionError:
3308 except ZeroDivisionError:
3306 compression = 0
3309 compression = 0
3307 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3310 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3308 "%11d %5d %8d\n" %
3311 "%11d %5d %8d\n" %
3309 (rev, p1, p2, r.start(rev), r.end(rev),
3312 (rev, p1, p2, r.start(rev), r.end(rev),
3310 r.start(dbase), r.start(cbase),
3313 r.start(dbase), r.start(cbase),
3311 r.start(p1), r.start(p2),
3314 r.start(p1), r.start(p2),
3312 rs, ts, compression, len(heads), clen))
3315 rs, ts, compression, len(heads), clen))
3313 return 0
3316 return 0
3314
3317
3315 v = r.version
3318 v = r.version
3316 format = v & 0xFFFF
3319 format = v & 0xFFFF
3317 flags = []
3320 flags = []
3318 gdelta = False
3321 gdelta = False
3319 if v & revlog.REVLOGNGINLINEDATA:
3322 if v & revlog.REVLOGNGINLINEDATA:
3320 flags.append('inline')
3323 flags.append('inline')
3321 if v & revlog.REVLOGGENERALDELTA:
3324 if v & revlog.REVLOGGENERALDELTA:
3322 gdelta = True
3325 gdelta = True
3323 flags.append('generaldelta')
3326 flags.append('generaldelta')
3324 if not flags:
3327 if not flags:
3325 flags = ['(none)']
3328 flags = ['(none)']
3326
3329
3327 nummerges = 0
3330 nummerges = 0
3328 numfull = 0
3331 numfull = 0
3329 numprev = 0
3332 numprev = 0
3330 nump1 = 0
3333 nump1 = 0
3331 nump2 = 0
3334 nump2 = 0
3332 numother = 0
3335 numother = 0
3333 nump1prev = 0
3336 nump1prev = 0
3334 nump2prev = 0
3337 nump2prev = 0
3335 chainlengths = []
3338 chainlengths = []
3336
3339
3337 datasize = [None, 0, 0L]
3340 datasize = [None, 0, 0L]
3338 fullsize = [None, 0, 0L]
3341 fullsize = [None, 0, 0L]
3339 deltasize = [None, 0, 0L]
3342 deltasize = [None, 0, 0L]
3340
3343
3341 def addsize(size, l):
3344 def addsize(size, l):
3342 if l[0] is None or size < l[0]:
3345 if l[0] is None or size < l[0]:
3343 l[0] = size
3346 l[0] = size
3344 if size > l[1]:
3347 if size > l[1]:
3345 l[1] = size
3348 l[1] = size
3346 l[2] += size
3349 l[2] += size
3347
3350
3348 numrevs = len(r)
3351 numrevs = len(r)
3349 for rev in xrange(numrevs):
3352 for rev in xrange(numrevs):
3350 p1, p2 = r.parentrevs(rev)
3353 p1, p2 = r.parentrevs(rev)
3351 delta = r.deltaparent(rev)
3354 delta = r.deltaparent(rev)
3352 if format > 0:
3355 if format > 0:
3353 addsize(r.rawsize(rev), datasize)
3356 addsize(r.rawsize(rev), datasize)
3354 if p2 != nullrev:
3357 if p2 != nullrev:
3355 nummerges += 1
3358 nummerges += 1
3356 size = r.length(rev)
3359 size = r.length(rev)
3357 if delta == nullrev:
3360 if delta == nullrev:
3358 chainlengths.append(0)
3361 chainlengths.append(0)
3359 numfull += 1
3362 numfull += 1
3360 addsize(size, fullsize)
3363 addsize(size, fullsize)
3361 else:
3364 else:
3362 chainlengths.append(chainlengths[delta] + 1)
3365 chainlengths.append(chainlengths[delta] + 1)
3363 addsize(size, deltasize)
3366 addsize(size, deltasize)
3364 if delta == rev - 1:
3367 if delta == rev - 1:
3365 numprev += 1
3368 numprev += 1
3366 if delta == p1:
3369 if delta == p1:
3367 nump1prev += 1
3370 nump1prev += 1
3368 elif delta == p2:
3371 elif delta == p2:
3369 nump2prev += 1
3372 nump2prev += 1
3370 elif delta == p1:
3373 elif delta == p1:
3371 nump1 += 1
3374 nump1 += 1
3372 elif delta == p2:
3375 elif delta == p2:
3373 nump2 += 1
3376 nump2 += 1
3374 elif delta != nullrev:
3377 elif delta != nullrev:
3375 numother += 1
3378 numother += 1
3376
3379
3377 # Adjust size min value for empty cases
3380 # Adjust size min value for empty cases
3378 for size in (datasize, fullsize, deltasize):
3381 for size in (datasize, fullsize, deltasize):
3379 if size[0] is None:
3382 if size[0] is None:
3380 size[0] = 0
3383 size[0] = 0
3381
3384
3382 numdeltas = numrevs - numfull
3385 numdeltas = numrevs - numfull
3383 numoprev = numprev - nump1prev - nump2prev
3386 numoprev = numprev - nump1prev - nump2prev
3384 totalrawsize = datasize[2]
3387 totalrawsize = datasize[2]
3385 datasize[2] /= numrevs
3388 datasize[2] /= numrevs
3386 fulltotal = fullsize[2]
3389 fulltotal = fullsize[2]
3387 fullsize[2] /= numfull
3390 fullsize[2] /= numfull
3388 deltatotal = deltasize[2]
3391 deltatotal = deltasize[2]
3389 if numrevs - numfull > 0:
3392 if numrevs - numfull > 0:
3390 deltasize[2] /= numrevs - numfull
3393 deltasize[2] /= numrevs - numfull
3391 totalsize = fulltotal + deltatotal
3394 totalsize = fulltotal + deltatotal
3392 avgchainlen = sum(chainlengths) / numrevs
3395 avgchainlen = sum(chainlengths) / numrevs
3393 maxchainlen = max(chainlengths)
3396 maxchainlen = max(chainlengths)
3394 compratio = 1
3397 compratio = 1
3395 if totalsize:
3398 if totalsize:
3396 compratio = totalrawsize / totalsize
3399 compratio = totalrawsize / totalsize
3397
3400
3398 basedfmtstr = '%%%dd\n'
3401 basedfmtstr = '%%%dd\n'
3399 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3402 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3400
3403
3401 def dfmtstr(max):
3404 def dfmtstr(max):
3402 return basedfmtstr % len(str(max))
3405 return basedfmtstr % len(str(max))
3403 def pcfmtstr(max, padding=0):
3406 def pcfmtstr(max, padding=0):
3404 return basepcfmtstr % (len(str(max)), ' ' * padding)
3407 return basepcfmtstr % (len(str(max)), ' ' * padding)
3405
3408
3406 def pcfmt(value, total):
3409 def pcfmt(value, total):
3407 if total:
3410 if total:
3408 return (value, 100 * float(value) / total)
3411 return (value, 100 * float(value) / total)
3409 else:
3412 else:
3410 return value, 100.0
3413 return value, 100.0
3411
3414
3412 ui.write(('format : %d\n') % format)
3415 ui.write(('format : %d\n') % format)
3413 ui.write(('flags : %s\n') % ', '.join(flags))
3416 ui.write(('flags : %s\n') % ', '.join(flags))
3414
3417
3415 ui.write('\n')
3418 ui.write('\n')
3416 fmt = pcfmtstr(totalsize)
3419 fmt = pcfmtstr(totalsize)
3417 fmt2 = dfmtstr(totalsize)
3420 fmt2 = dfmtstr(totalsize)
3418 ui.write(('revisions : ') + fmt2 % numrevs)
3421 ui.write(('revisions : ') + fmt2 % numrevs)
3419 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3422 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3420 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3423 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3421 ui.write(('revisions : ') + fmt2 % numrevs)
3424 ui.write(('revisions : ') + fmt2 % numrevs)
3422 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3425 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3423 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3426 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3424 ui.write(('revision size : ') + fmt2 % totalsize)
3427 ui.write(('revision size : ') + fmt2 % totalsize)
3425 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3428 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3426 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3429 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3427
3430
3428 ui.write('\n')
3431 ui.write('\n')
3429 fmt = dfmtstr(max(avgchainlen, compratio))
3432 fmt = dfmtstr(max(avgchainlen, compratio))
3430 ui.write(('avg chain length : ') + fmt % avgchainlen)
3433 ui.write(('avg chain length : ') + fmt % avgchainlen)
3431 ui.write(('max chain length : ') + fmt % maxchainlen)
3434 ui.write(('max chain length : ') + fmt % maxchainlen)
3432 ui.write(('compression ratio : ') + fmt % compratio)
3435 ui.write(('compression ratio : ') + fmt % compratio)
3433
3436
3434 if format > 0:
3437 if format > 0:
3435 ui.write('\n')
3438 ui.write('\n')
3436 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3439 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3437 % tuple(datasize))
3440 % tuple(datasize))
3438 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3441 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3439 % tuple(fullsize))
3442 % tuple(fullsize))
3440 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3443 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3441 % tuple(deltasize))
3444 % tuple(deltasize))
3442
3445
3443 if numdeltas > 0:
3446 if numdeltas > 0:
3444 ui.write('\n')
3447 ui.write('\n')
3445 fmt = pcfmtstr(numdeltas)
3448 fmt = pcfmtstr(numdeltas)
3446 fmt2 = pcfmtstr(numdeltas, 4)
3449 fmt2 = pcfmtstr(numdeltas, 4)
3447 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3450 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3448 if numprev > 0:
3451 if numprev > 0:
3449 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3452 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3450 numprev))
3453 numprev))
3451 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3454 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3452 numprev))
3455 numprev))
3453 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3456 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3454 numprev))
3457 numprev))
3455 if gdelta:
3458 if gdelta:
3456 ui.write(('deltas against p1 : ')
3459 ui.write(('deltas against p1 : ')
3457 + fmt % pcfmt(nump1, numdeltas))
3460 + fmt % pcfmt(nump1, numdeltas))
3458 ui.write(('deltas against p2 : ')
3461 ui.write(('deltas against p2 : ')
3459 + fmt % pcfmt(nump2, numdeltas))
3462 + fmt % pcfmt(nump2, numdeltas))
3460 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3463 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3461 numdeltas))
3464 numdeltas))
3462
3465
3463 @command('debugrevspec',
3466 @command('debugrevspec',
3464 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3467 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3465 ('REVSPEC'))
3468 ('REVSPEC'))
3466 def debugrevspec(ui, repo, expr, **opts):
3469 def debugrevspec(ui, repo, expr, **opts):
3467 """parse and apply a revision specification
3470 """parse and apply a revision specification
3468
3471
3469 Use --verbose to print the parsed tree before and after aliases
3472 Use --verbose to print the parsed tree before and after aliases
3470 expansion.
3473 expansion.
3471 """
3474 """
3472 if ui.verbose:
3475 if ui.verbose:
3473 tree = revset.parse(expr, lookup=repo.__contains__)
3476 tree = revset.parse(expr, lookup=repo.__contains__)
3474 ui.note(revset.prettyformat(tree), "\n")
3477 ui.note(revset.prettyformat(tree), "\n")
3475 newtree = revset.findaliases(ui, tree)
3478 newtree = revset.findaliases(ui, tree)
3476 if newtree != tree:
3479 if newtree != tree:
3477 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3480 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3478 tree = newtree
3481 tree = newtree
3479 newtree = revset.foldconcat(tree)
3482 newtree = revset.foldconcat(tree)
3480 if newtree != tree:
3483 if newtree != tree:
3481 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3484 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3482 if opts["optimize"]:
3485 if opts["optimize"]:
3483 weight, optimizedtree = revset.optimize(newtree, True)
3486 weight, optimizedtree = revset.optimize(newtree, True)
3484 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3487 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3485 func = revset.match(ui, expr, repo)
3488 func = revset.match(ui, expr, repo)
3486 revs = func(repo)
3489 revs = func(repo)
3487 if ui.verbose:
3490 if ui.verbose:
3488 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3491 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3489 for c in revs:
3492 for c in revs:
3490 ui.write("%s\n" % c)
3493 ui.write("%s\n" % c)
3491
3494
3492 @command('debugsetparents', [], _('REV1 [REV2]'))
3495 @command('debugsetparents', [], _('REV1 [REV2]'))
3493 def debugsetparents(ui, repo, rev1, rev2=None):
3496 def debugsetparents(ui, repo, rev1, rev2=None):
3494 """manually set the parents of the current working directory
3497 """manually set the parents of the current working directory
3495
3498
3496 This is useful for writing repository conversion tools, but should
3499 This is useful for writing repository conversion tools, but should
3497 be used with care. For example, neither the working directory nor the
3500 be used with care. For example, neither the working directory nor the
3498 dirstate is updated, so file status may be incorrect after running this
3501 dirstate is updated, so file status may be incorrect after running this
3499 command.
3502 command.
3500
3503
3501 Returns 0 on success.
3504 Returns 0 on success.
3502 """
3505 """
3503
3506
3504 r1 = scmutil.revsingle(repo, rev1).node()
3507 r1 = scmutil.revsingle(repo, rev1).node()
3505 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3508 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3506
3509
3507 with repo.wlock():
3510 with repo.wlock():
3508 repo.setparents(r1, r2)
3511 repo.setparents(r1, r2)
3509
3512
3510 @command('debugdirstate|debugstate',
3513 @command('debugdirstate|debugstate',
3511 [('', 'nodates', None, _('do not display the saved mtime')),
3514 [('', 'nodates', None, _('do not display the saved mtime')),
3512 ('', 'datesort', None, _('sort by saved mtime'))],
3515 ('', 'datesort', None, _('sort by saved mtime'))],
3513 _('[OPTION]...'))
3516 _('[OPTION]...'))
3514 def debugstate(ui, repo, **opts):
3517 def debugstate(ui, repo, **opts):
3515 """show the contents of the current dirstate"""
3518 """show the contents of the current dirstate"""
3516
3519
3517 nodates = opts.get('nodates')
3520 nodates = opts.get('nodates')
3518 datesort = opts.get('datesort')
3521 datesort = opts.get('datesort')
3519
3522
3520 timestr = ""
3523 timestr = ""
3521 if datesort:
3524 if datesort:
3522 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3525 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3523 else:
3526 else:
3524 keyfunc = None # sort by filename
3527 keyfunc = None # sort by filename
3525 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3528 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3526 if ent[3] == -1:
3529 if ent[3] == -1:
3527 timestr = 'unset '
3530 timestr = 'unset '
3528 elif nodates:
3531 elif nodates:
3529 timestr = 'set '
3532 timestr = 'set '
3530 else:
3533 else:
3531 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3534 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3532 time.localtime(ent[3]))
3535 time.localtime(ent[3]))
3533 if ent[1] & 0o20000:
3536 if ent[1] & 0o20000:
3534 mode = 'lnk'
3537 mode = 'lnk'
3535 else:
3538 else:
3536 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3539 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3537 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3540 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3538 for f in repo.dirstate.copies():
3541 for f in repo.dirstate.copies():
3539 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3542 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3540
3543
3541 @command('debugsub',
3544 @command('debugsub',
3542 [('r', 'rev', '',
3545 [('r', 'rev', '',
3543 _('revision to check'), _('REV'))],
3546 _('revision to check'), _('REV'))],
3544 _('[-r REV] [REV]'))
3547 _('[-r REV] [REV]'))
3545 def debugsub(ui, repo, rev=None):
3548 def debugsub(ui, repo, rev=None):
3546 ctx = scmutil.revsingle(repo, rev, None)
3549 ctx = scmutil.revsingle(repo, rev, None)
3547 for k, v in sorted(ctx.substate.items()):
3550 for k, v in sorted(ctx.substate.items()):
3548 ui.write(('path %s\n') % k)
3551 ui.write(('path %s\n') % k)
3549 ui.write((' source %s\n') % v[0])
3552 ui.write((' source %s\n') % v[0])
3550 ui.write((' revision %s\n') % v[1])
3553 ui.write((' revision %s\n') % v[1])
3551
3554
3552 @command('debugsuccessorssets',
3555 @command('debugsuccessorssets',
3553 [],
3556 [],
3554 _('[REV]'))
3557 _('[REV]'))
3555 def debugsuccessorssets(ui, repo, *revs):
3558 def debugsuccessorssets(ui, repo, *revs):
3556 """show set of successors for revision
3559 """show set of successors for revision
3557
3560
3558 A successors set of changeset A is a consistent group of revisions that
3561 A successors set of changeset A is a consistent group of revisions that
3559 succeed A. It contains non-obsolete changesets only.
3562 succeed A. It contains non-obsolete changesets only.
3560
3563
3561 In most cases a changeset A has a single successors set containing a single
3564 In most cases a changeset A has a single successors set containing a single
3562 successor (changeset A replaced by A').
3565 successor (changeset A replaced by A').
3563
3566
3564 A changeset that is made obsolete with no successors are called "pruned".
3567 A changeset that is made obsolete with no successors are called "pruned".
3565 Such changesets have no successors sets at all.
3568 Such changesets have no successors sets at all.
3566
3569
3567 A changeset that has been "split" will have a successors set containing
3570 A changeset that has been "split" will have a successors set containing
3568 more than one successor.
3571 more than one successor.
3569
3572
3570 A changeset that has been rewritten in multiple different ways is called
3573 A changeset that has been rewritten in multiple different ways is called
3571 "divergent". Such changesets have multiple successor sets (each of which
3574 "divergent". Such changesets have multiple successor sets (each of which
3572 may also be split, i.e. have multiple successors).
3575 may also be split, i.e. have multiple successors).
3573
3576
3574 Results are displayed as follows::
3577 Results are displayed as follows::
3575
3578
3576 <rev1>
3579 <rev1>
3577 <successors-1A>
3580 <successors-1A>
3578 <rev2>
3581 <rev2>
3579 <successors-2A>
3582 <successors-2A>
3580 <successors-2B1> <successors-2B2> <successors-2B3>
3583 <successors-2B1> <successors-2B2> <successors-2B3>
3581
3584
3582 Here rev2 has two possible (i.e. divergent) successors sets. The first
3585 Here rev2 has two possible (i.e. divergent) successors sets. The first
3583 holds one element, whereas the second holds three (i.e. the changeset has
3586 holds one element, whereas the second holds three (i.e. the changeset has
3584 been split).
3587 been split).
3585 """
3588 """
3586 # passed to successorssets caching computation from one call to another
3589 # passed to successorssets caching computation from one call to another
3587 cache = {}
3590 cache = {}
3588 ctx2str = str
3591 ctx2str = str
3589 node2str = short
3592 node2str = short
3590 if ui.debug():
3593 if ui.debug():
3591 def ctx2str(ctx):
3594 def ctx2str(ctx):
3592 return ctx.hex()
3595 return ctx.hex()
3593 node2str = hex
3596 node2str = hex
3594 for rev in scmutil.revrange(repo, revs):
3597 for rev in scmutil.revrange(repo, revs):
3595 ctx = repo[rev]
3598 ctx = repo[rev]
3596 ui.write('%s\n'% ctx2str(ctx))
3599 ui.write('%s\n'% ctx2str(ctx))
3597 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3600 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3598 if succsset:
3601 if succsset:
3599 ui.write(' ')
3602 ui.write(' ')
3600 ui.write(node2str(succsset[0]))
3603 ui.write(node2str(succsset[0]))
3601 for node in succsset[1:]:
3604 for node in succsset[1:]:
3602 ui.write(' ')
3605 ui.write(' ')
3603 ui.write(node2str(node))
3606 ui.write(node2str(node))
3604 ui.write('\n')
3607 ui.write('\n')
3605
3608
3606 @command('debugtemplate',
3609 @command('debugtemplate',
3607 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3610 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3608 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3611 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3609 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3612 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3610 optionalrepo=True)
3613 optionalrepo=True)
3611 def debugtemplate(ui, repo, tmpl, **opts):
3614 def debugtemplate(ui, repo, tmpl, **opts):
3612 """parse and apply a template
3615 """parse and apply a template
3613
3616
3614 If -r/--rev is given, the template is processed as a log template and
3617 If -r/--rev is given, the template is processed as a log template and
3615 applied to the given changesets. Otherwise, it is processed as a generic
3618 applied to the given changesets. Otherwise, it is processed as a generic
3616 template.
3619 template.
3617
3620
3618 Use --verbose to print the parsed tree.
3621 Use --verbose to print the parsed tree.
3619 """
3622 """
3620 revs = None
3623 revs = None
3621 if opts['rev']:
3624 if opts['rev']:
3622 if repo is None:
3625 if repo is None:
3623 raise error.RepoError(_('there is no Mercurial repository here '
3626 raise error.RepoError(_('there is no Mercurial repository here '
3624 '(.hg not found)'))
3627 '(.hg not found)'))
3625 revs = scmutil.revrange(repo, opts['rev'])
3628 revs = scmutil.revrange(repo, opts['rev'])
3626
3629
3627 props = {}
3630 props = {}
3628 for d in opts['define']:
3631 for d in opts['define']:
3629 try:
3632 try:
3630 k, v = (e.strip() for e in d.split('=', 1))
3633 k, v = (e.strip() for e in d.split('=', 1))
3631 if not k:
3634 if not k:
3632 raise ValueError
3635 raise ValueError
3633 props[k] = v
3636 props[k] = v
3634 except ValueError:
3637 except ValueError:
3635 raise error.Abort(_('malformed keyword definition: %s') % d)
3638 raise error.Abort(_('malformed keyword definition: %s') % d)
3636
3639
3637 if ui.verbose:
3640 if ui.verbose:
3638 tree = templater.parse(tmpl)
3641 tree = templater.parse(tmpl)
3639 ui.note(templater.prettyformat(tree), '\n')
3642 ui.note(templater.prettyformat(tree), '\n')
3640
3643
3641 mapfile = None
3644 mapfile = None
3642 if revs is None:
3645 if revs is None:
3643 k = 'debugtemplate'
3646 k = 'debugtemplate'
3644 t = templater.templater(mapfile)
3647 t = templater.templater(mapfile)
3645 t.cache[k] = tmpl
3648 t.cache[k] = tmpl
3646 ui.write(templater.stringify(t(k, **props)))
3649 ui.write(templater.stringify(t(k, **props)))
3647 else:
3650 else:
3648 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3651 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3649 mapfile, buffered=False)
3652 mapfile, buffered=False)
3650 for r in revs:
3653 for r in revs:
3651 displayer.show(repo[r], **props)
3654 displayer.show(repo[r], **props)
3652 displayer.close()
3655 displayer.close()
3653
3656
3654 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3657 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3655 def debugwalk(ui, repo, *pats, **opts):
3658 def debugwalk(ui, repo, *pats, **opts):
3656 """show how files match on given patterns"""
3659 """show how files match on given patterns"""
3657 m = scmutil.match(repo[None], pats, opts)
3660 m = scmutil.match(repo[None], pats, opts)
3658 items = list(repo.walk(m))
3661 items = list(repo.walk(m))
3659 if not items:
3662 if not items:
3660 return
3663 return
3661 f = lambda fn: fn
3664 f = lambda fn: fn
3662 if ui.configbool('ui', 'slash') and os.sep != '/':
3665 if ui.configbool('ui', 'slash') and os.sep != '/':
3663 f = lambda fn: util.normpath(fn)
3666 f = lambda fn: util.normpath(fn)
3664 fmt = 'f %%-%ds %%-%ds %%s' % (
3667 fmt = 'f %%-%ds %%-%ds %%s' % (
3665 max([len(abs) for abs in items]),
3668 max([len(abs) for abs in items]),
3666 max([len(m.rel(abs)) for abs in items]))
3669 max([len(m.rel(abs)) for abs in items]))
3667 for abs in items:
3670 for abs in items:
3668 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3671 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3669 ui.write("%s\n" % line.rstrip())
3672 ui.write("%s\n" % line.rstrip())
3670
3673
3671 @command('debugwireargs',
3674 @command('debugwireargs',
3672 [('', 'three', '', 'three'),
3675 [('', 'three', '', 'three'),
3673 ('', 'four', '', 'four'),
3676 ('', 'four', '', 'four'),
3674 ('', 'five', '', 'five'),
3677 ('', 'five', '', 'five'),
3675 ] + remoteopts,
3678 ] + remoteopts,
3676 _('REPO [OPTIONS]... [ONE [TWO]]'),
3679 _('REPO [OPTIONS]... [ONE [TWO]]'),
3677 norepo=True)
3680 norepo=True)
3678 def debugwireargs(ui, repopath, *vals, **opts):
3681 def debugwireargs(ui, repopath, *vals, **opts):
3679 repo = hg.peer(ui, opts, repopath)
3682 repo = hg.peer(ui, opts, repopath)
3680 for opt in remoteopts:
3683 for opt in remoteopts:
3681 del opts[opt[1]]
3684 del opts[opt[1]]
3682 args = {}
3685 args = {}
3683 for k, v in opts.iteritems():
3686 for k, v in opts.iteritems():
3684 if v:
3687 if v:
3685 args[k] = v
3688 args[k] = v
3686 # run twice to check that we don't mess up the stream for the next command
3689 # run twice to check that we don't mess up the stream for the next command
3687 res1 = repo.debugwireargs(*vals, **args)
3690 res1 = repo.debugwireargs(*vals, **args)
3688 res2 = repo.debugwireargs(*vals, **args)
3691 res2 = repo.debugwireargs(*vals, **args)
3689 ui.write("%s\n" % res1)
3692 ui.write("%s\n" % res1)
3690 if res1 != res2:
3693 if res1 != res2:
3691 ui.warn("%s\n" % res2)
3694 ui.warn("%s\n" % res2)
3692
3695
3693 @command('^diff',
3696 @command('^diff',
3694 [('r', 'rev', [], _('revision'), _('REV')),
3697 [('r', 'rev', [], _('revision'), _('REV')),
3695 ('c', 'change', '', _('change made by revision'), _('REV'))
3698 ('c', 'change', '', _('change made by revision'), _('REV'))
3696 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3699 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3697 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3700 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3698 inferrepo=True)
3701 inferrepo=True)
3699 def diff(ui, repo, *pats, **opts):
3702 def diff(ui, repo, *pats, **opts):
3700 """diff repository (or selected files)
3703 """diff repository (or selected files)
3701
3704
3702 Show differences between revisions for the specified files.
3705 Show differences between revisions for the specified files.
3703
3706
3704 Differences between files are shown using the unified diff format.
3707 Differences between files are shown using the unified diff format.
3705
3708
3706 .. note::
3709 .. note::
3707
3710
3708 :hg:`diff` may generate unexpected results for merges, as it will
3711 :hg:`diff` may generate unexpected results for merges, as it will
3709 default to comparing against the working directory's first
3712 default to comparing against the working directory's first
3710 parent changeset if no revisions are specified.
3713 parent changeset if no revisions are specified.
3711
3714
3712 When two revision arguments are given, then changes are shown
3715 When two revision arguments are given, then changes are shown
3713 between those revisions. If only one revision is specified then
3716 between those revisions. If only one revision is specified then
3714 that revision is compared to the working directory, and, when no
3717 that revision is compared to the working directory, and, when no
3715 revisions are specified, the working directory files are compared
3718 revisions are specified, the working directory files are compared
3716 to its first parent.
3719 to its first parent.
3717
3720
3718 Alternatively you can specify -c/--change with a revision to see
3721 Alternatively you can specify -c/--change with a revision to see
3719 the changes in that changeset relative to its first parent.
3722 the changes in that changeset relative to its first parent.
3720
3723
3721 Without the -a/--text option, diff will avoid generating diffs of
3724 Without the -a/--text option, diff will avoid generating diffs of
3722 files it detects as binary. With -a, diff will generate a diff
3725 files it detects as binary. With -a, diff will generate a diff
3723 anyway, probably with undesirable results.
3726 anyway, probably with undesirable results.
3724
3727
3725 Use the -g/--git option to generate diffs in the git extended diff
3728 Use the -g/--git option to generate diffs in the git extended diff
3726 format. For more information, read :hg:`help diffs`.
3729 format. For more information, read :hg:`help diffs`.
3727
3730
3728 .. container:: verbose
3731 .. container:: verbose
3729
3732
3730 Examples:
3733 Examples:
3731
3734
3732 - compare a file in the current working directory to its parent::
3735 - compare a file in the current working directory to its parent::
3733
3736
3734 hg diff foo.c
3737 hg diff foo.c
3735
3738
3736 - compare two historical versions of a directory, with rename info::
3739 - compare two historical versions of a directory, with rename info::
3737
3740
3738 hg diff --git -r 1.0:1.2 lib/
3741 hg diff --git -r 1.0:1.2 lib/
3739
3742
3740 - get change stats relative to the last change on some date::
3743 - get change stats relative to the last change on some date::
3741
3744
3742 hg diff --stat -r "date('may 2')"
3745 hg diff --stat -r "date('may 2')"
3743
3746
3744 - diff all newly-added files that contain a keyword::
3747 - diff all newly-added files that contain a keyword::
3745
3748
3746 hg diff "set:added() and grep(GNU)"
3749 hg diff "set:added() and grep(GNU)"
3747
3750
3748 - compare a revision and its parents::
3751 - compare a revision and its parents::
3749
3752
3750 hg diff -c 9353 # compare against first parent
3753 hg diff -c 9353 # compare against first parent
3751 hg diff -r 9353^:9353 # same using revset syntax
3754 hg diff -r 9353^:9353 # same using revset syntax
3752 hg diff -r 9353^2:9353 # compare against the second parent
3755 hg diff -r 9353^2:9353 # compare against the second parent
3753
3756
3754 Returns 0 on success.
3757 Returns 0 on success.
3755 """
3758 """
3756
3759
3757 revs = opts.get('rev')
3760 revs = opts.get('rev')
3758 change = opts.get('change')
3761 change = opts.get('change')
3759 stat = opts.get('stat')
3762 stat = opts.get('stat')
3760 reverse = opts.get('reverse')
3763 reverse = opts.get('reverse')
3761
3764
3762 if revs and change:
3765 if revs and change:
3763 msg = _('cannot specify --rev and --change at the same time')
3766 msg = _('cannot specify --rev and --change at the same time')
3764 raise error.Abort(msg)
3767 raise error.Abort(msg)
3765 elif change:
3768 elif change:
3766 node2 = scmutil.revsingle(repo, change, None).node()
3769 node2 = scmutil.revsingle(repo, change, None).node()
3767 node1 = repo[node2].p1().node()
3770 node1 = repo[node2].p1().node()
3768 else:
3771 else:
3769 node1, node2 = scmutil.revpair(repo, revs)
3772 node1, node2 = scmutil.revpair(repo, revs)
3770
3773
3771 if reverse:
3774 if reverse:
3772 node1, node2 = node2, node1
3775 node1, node2 = node2, node1
3773
3776
3774 diffopts = patch.diffallopts(ui, opts)
3777 diffopts = patch.diffallopts(ui, opts)
3775 m = scmutil.match(repo[node2], pats, opts)
3778 m = scmutil.match(repo[node2], pats, opts)
3776 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3779 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3777 listsubrepos=opts.get('subrepos'),
3780 listsubrepos=opts.get('subrepos'),
3778 root=opts.get('root'))
3781 root=opts.get('root'))
3779
3782
3780 @command('^export',
3783 @command('^export',
3781 [('o', 'output', '',
3784 [('o', 'output', '',
3782 _('print output to file with formatted name'), _('FORMAT')),
3785 _('print output to file with formatted name'), _('FORMAT')),
3783 ('', 'switch-parent', None, _('diff against the second parent')),
3786 ('', 'switch-parent', None, _('diff against the second parent')),
3784 ('r', 'rev', [], _('revisions to export'), _('REV')),
3787 ('r', 'rev', [], _('revisions to export'), _('REV')),
3785 ] + diffopts,
3788 ] + diffopts,
3786 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3789 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3787 def export(ui, repo, *changesets, **opts):
3790 def export(ui, repo, *changesets, **opts):
3788 """dump the header and diffs for one or more changesets
3791 """dump the header and diffs for one or more changesets
3789
3792
3790 Print the changeset header and diffs for one or more revisions.
3793 Print the changeset header and diffs for one or more revisions.
3791 If no revision is given, the parent of the working directory is used.
3794 If no revision is given, the parent of the working directory is used.
3792
3795
3793 The information shown in the changeset header is: author, date,
3796 The information shown in the changeset header is: author, date,
3794 branch name (if non-default), changeset hash, parent(s) and commit
3797 branch name (if non-default), changeset hash, parent(s) and commit
3795 comment.
3798 comment.
3796
3799
3797 .. note::
3800 .. note::
3798
3801
3799 :hg:`export` may generate unexpected diff output for merge
3802 :hg:`export` may generate unexpected diff output for merge
3800 changesets, as it will compare the merge changeset against its
3803 changesets, as it will compare the merge changeset against its
3801 first parent only.
3804 first parent only.
3802
3805
3803 Output may be to a file, in which case the name of the file is
3806 Output may be to a file, in which case the name of the file is
3804 given using a format string. The formatting rules are as follows:
3807 given using a format string. The formatting rules are as follows:
3805
3808
3806 :``%%``: literal "%" character
3809 :``%%``: literal "%" character
3807 :``%H``: changeset hash (40 hexadecimal digits)
3810 :``%H``: changeset hash (40 hexadecimal digits)
3808 :``%N``: number of patches being generated
3811 :``%N``: number of patches being generated
3809 :``%R``: changeset revision number
3812 :``%R``: changeset revision number
3810 :``%b``: basename of the exporting repository
3813 :``%b``: basename of the exporting repository
3811 :``%h``: short-form changeset hash (12 hexadecimal digits)
3814 :``%h``: short-form changeset hash (12 hexadecimal digits)
3812 :``%m``: first line of the commit message (only alphanumeric characters)
3815 :``%m``: first line of the commit message (only alphanumeric characters)
3813 :``%n``: zero-padded sequence number, starting at 1
3816 :``%n``: zero-padded sequence number, starting at 1
3814 :``%r``: zero-padded changeset revision number
3817 :``%r``: zero-padded changeset revision number
3815
3818
3816 Without the -a/--text option, export will avoid generating diffs
3819 Without the -a/--text option, export will avoid generating diffs
3817 of files it detects as binary. With -a, export will generate a
3820 of files it detects as binary. With -a, export will generate a
3818 diff anyway, probably with undesirable results.
3821 diff anyway, probably with undesirable results.
3819
3822
3820 Use the -g/--git option to generate diffs in the git extended diff
3823 Use the -g/--git option to generate diffs in the git extended diff
3821 format. See :hg:`help diffs` for more information.
3824 format. See :hg:`help diffs` for more information.
3822
3825
3823 With the --switch-parent option, the diff will be against the
3826 With the --switch-parent option, the diff will be against the
3824 second parent. It can be useful to review a merge.
3827 second parent. It can be useful to review a merge.
3825
3828
3826 .. container:: verbose
3829 .. container:: verbose
3827
3830
3828 Examples:
3831 Examples:
3829
3832
3830 - use export and import to transplant a bugfix to the current
3833 - use export and import to transplant a bugfix to the current
3831 branch::
3834 branch::
3832
3835
3833 hg export -r 9353 | hg import -
3836 hg export -r 9353 | hg import -
3834
3837
3835 - export all the changesets between two revisions to a file with
3838 - export all the changesets between two revisions to a file with
3836 rename information::
3839 rename information::
3837
3840
3838 hg export --git -r 123:150 > changes.txt
3841 hg export --git -r 123:150 > changes.txt
3839
3842
3840 - split outgoing changes into a series of patches with
3843 - split outgoing changes into a series of patches with
3841 descriptive names::
3844 descriptive names::
3842
3845
3843 hg export -r "outgoing()" -o "%n-%m.patch"
3846 hg export -r "outgoing()" -o "%n-%m.patch"
3844
3847
3845 Returns 0 on success.
3848 Returns 0 on success.
3846 """
3849 """
3847 changesets += tuple(opts.get('rev', []))
3850 changesets += tuple(opts.get('rev', []))
3848 if not changesets:
3851 if not changesets:
3849 changesets = ['.']
3852 changesets = ['.']
3850 revs = scmutil.revrange(repo, changesets)
3853 revs = scmutil.revrange(repo, changesets)
3851 if not revs:
3854 if not revs:
3852 raise error.Abort(_("export requires at least one changeset"))
3855 raise error.Abort(_("export requires at least one changeset"))
3853 if len(revs) > 1:
3856 if len(revs) > 1:
3854 ui.note(_('exporting patches:\n'))
3857 ui.note(_('exporting patches:\n'))
3855 else:
3858 else:
3856 ui.note(_('exporting patch:\n'))
3859 ui.note(_('exporting patch:\n'))
3857 cmdutil.export(repo, revs, template=opts.get('output'),
3860 cmdutil.export(repo, revs, template=opts.get('output'),
3858 switch_parent=opts.get('switch_parent'),
3861 switch_parent=opts.get('switch_parent'),
3859 opts=patch.diffallopts(ui, opts))
3862 opts=patch.diffallopts(ui, opts))
3860
3863
3861 @command('files',
3864 @command('files',
3862 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3865 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3863 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3866 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3864 ] + walkopts + formatteropts + subrepoopts,
3867 ] + walkopts + formatteropts + subrepoopts,
3865 _('[OPTION]... [PATTERN]...'))
3868 _('[OPTION]... [PATTERN]...'))
3866 def files(ui, repo, *pats, **opts):
3869 def files(ui, repo, *pats, **opts):
3867 """list tracked files
3870 """list tracked files
3868
3871
3869 Print files under Mercurial control in the working directory or
3872 Print files under Mercurial control in the working directory or
3870 specified revision whose names match the given patterns (excluding
3873 specified revision whose names match the given patterns (excluding
3871 removed files).
3874 removed files).
3872
3875
3873 If no patterns are given to match, this command prints the names
3876 If no patterns are given to match, this command prints the names
3874 of all files under Mercurial control in the working directory.
3877 of all files under Mercurial control in the working directory.
3875
3878
3876 .. container:: verbose
3879 .. container:: verbose
3877
3880
3878 Examples:
3881 Examples:
3879
3882
3880 - list all files under the current directory::
3883 - list all files under the current directory::
3881
3884
3882 hg files .
3885 hg files .
3883
3886
3884 - shows sizes and flags for current revision::
3887 - shows sizes and flags for current revision::
3885
3888
3886 hg files -vr .
3889 hg files -vr .
3887
3890
3888 - list all files named README::
3891 - list all files named README::
3889
3892
3890 hg files -I "**/README"
3893 hg files -I "**/README"
3891
3894
3892 - list all binary files::
3895 - list all binary files::
3893
3896
3894 hg files "set:binary()"
3897 hg files "set:binary()"
3895
3898
3896 - find files containing a regular expression::
3899 - find files containing a regular expression::
3897
3900
3898 hg files "set:grep('bob')"
3901 hg files "set:grep('bob')"
3899
3902
3900 - search tracked file contents with xargs and grep::
3903 - search tracked file contents with xargs and grep::
3901
3904
3902 hg files -0 | xargs -0 grep foo
3905 hg files -0 | xargs -0 grep foo
3903
3906
3904 See :hg:`help patterns` and :hg:`help filesets` for more information
3907 See :hg:`help patterns` and :hg:`help filesets` for more information
3905 on specifying file patterns.
3908 on specifying file patterns.
3906
3909
3907 Returns 0 if a match is found, 1 otherwise.
3910 Returns 0 if a match is found, 1 otherwise.
3908
3911
3909 """
3912 """
3910 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3913 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3911
3914
3912 end = '\n'
3915 end = '\n'
3913 if opts.get('print0'):
3916 if opts.get('print0'):
3914 end = '\0'
3917 end = '\0'
3915 fm = ui.formatter('files', opts)
3918 fm = ui.formatter('files', opts)
3916 fmt = '%s' + end
3919 fmt = '%s' + end
3917
3920
3918 m = scmutil.match(ctx, pats, opts)
3921 m = scmutil.match(ctx, pats, opts)
3919 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3922 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3920
3923
3921 fm.end()
3924 fm.end()
3922
3925
3923 return ret
3926 return ret
3924
3927
3925 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3928 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3926 def forget(ui, repo, *pats, **opts):
3929 def forget(ui, repo, *pats, **opts):
3927 """forget the specified files on the next commit
3930 """forget the specified files on the next commit
3928
3931
3929 Mark the specified files so they will no longer be tracked
3932 Mark the specified files so they will no longer be tracked
3930 after the next commit.
3933 after the next commit.
3931
3934
3932 This only removes files from the current branch, not from the
3935 This only removes files from the current branch, not from the
3933 entire project history, and it does not delete them from the
3936 entire project history, and it does not delete them from the
3934 working directory.
3937 working directory.
3935
3938
3936 To delete the file from the working directory, see :hg:`remove`.
3939 To delete the file from the working directory, see :hg:`remove`.
3937
3940
3938 To undo a forget before the next commit, see :hg:`add`.
3941 To undo a forget before the next commit, see :hg:`add`.
3939
3942
3940 .. container:: verbose
3943 .. container:: verbose
3941
3944
3942 Examples:
3945 Examples:
3943
3946
3944 - forget newly-added binary files::
3947 - forget newly-added binary files::
3945
3948
3946 hg forget "set:added() and binary()"
3949 hg forget "set:added() and binary()"
3947
3950
3948 - forget files that would be excluded by .hgignore::
3951 - forget files that would be excluded by .hgignore::
3949
3952
3950 hg forget "set:hgignore()"
3953 hg forget "set:hgignore()"
3951
3954
3952 Returns 0 on success.
3955 Returns 0 on success.
3953 """
3956 """
3954
3957
3955 if not pats:
3958 if not pats:
3956 raise error.Abort(_('no files specified'))
3959 raise error.Abort(_('no files specified'))
3957
3960
3958 m = scmutil.match(repo[None], pats, opts)
3961 m = scmutil.match(repo[None], pats, opts)
3959 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3962 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3960 return rejected and 1 or 0
3963 return rejected and 1 or 0
3961
3964
3962 @command(
3965 @command(
3963 'graft',
3966 'graft',
3964 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3967 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3965 ('c', 'continue', False, _('resume interrupted graft')),
3968 ('c', 'continue', False, _('resume interrupted graft')),
3966 ('e', 'edit', False, _('invoke editor on commit messages')),
3969 ('e', 'edit', False, _('invoke editor on commit messages')),
3967 ('', 'log', None, _('append graft info to log message')),
3970 ('', 'log', None, _('append graft info to log message')),
3968 ('f', 'force', False, _('force graft')),
3971 ('f', 'force', False, _('force graft')),
3969 ('D', 'currentdate', False,
3972 ('D', 'currentdate', False,
3970 _('record the current date as commit date')),
3973 _('record the current date as commit date')),
3971 ('U', 'currentuser', False,
3974 ('U', 'currentuser', False,
3972 _('record the current user as committer'), _('DATE'))]
3975 _('record the current user as committer'), _('DATE'))]
3973 + commitopts2 + mergetoolopts + dryrunopts,
3976 + commitopts2 + mergetoolopts + dryrunopts,
3974 _('[OPTION]... [-r REV]... REV...'))
3977 _('[OPTION]... [-r REV]... REV...'))
3975 def graft(ui, repo, *revs, **opts):
3978 def graft(ui, repo, *revs, **opts):
3976 '''copy changes from other branches onto the current branch
3979 '''copy changes from other branches onto the current branch
3977
3980
3978 This command uses Mercurial's merge logic to copy individual
3981 This command uses Mercurial's merge logic to copy individual
3979 changes from other branches without merging branches in the
3982 changes from other branches without merging branches in the
3980 history graph. This is sometimes known as 'backporting' or
3983 history graph. This is sometimes known as 'backporting' or
3981 'cherry-picking'. By default, graft will copy user, date, and
3984 'cherry-picking'. By default, graft will copy user, date, and
3982 description from the source changesets.
3985 description from the source changesets.
3983
3986
3984 Changesets that are ancestors of the current revision, that have
3987 Changesets that are ancestors of the current revision, that have
3985 already been grafted, or that are merges will be skipped.
3988 already been grafted, or that are merges will be skipped.
3986
3989
3987 If --log is specified, log messages will have a comment appended
3990 If --log is specified, log messages will have a comment appended
3988 of the form::
3991 of the form::
3989
3992
3990 (grafted from CHANGESETHASH)
3993 (grafted from CHANGESETHASH)
3991
3994
3992 If --force is specified, revisions will be grafted even if they
3995 If --force is specified, revisions will be grafted even if they
3993 are already ancestors of or have been grafted to the destination.
3996 are already ancestors of or have been grafted to the destination.
3994 This is useful when the revisions have since been backed out.
3997 This is useful when the revisions have since been backed out.
3995
3998
3996 If a graft merge results in conflicts, the graft process is
3999 If a graft merge results in conflicts, the graft process is
3997 interrupted so that the current merge can be manually resolved.
4000 interrupted so that the current merge can be manually resolved.
3998 Once all conflicts are addressed, the graft process can be
4001 Once all conflicts are addressed, the graft process can be
3999 continued with the -c/--continue option.
4002 continued with the -c/--continue option.
4000
4003
4001 .. note::
4004 .. note::
4002
4005
4003 The -c/--continue option does not reapply earlier options, except
4006 The -c/--continue option does not reapply earlier options, except
4004 for --force.
4007 for --force.
4005
4008
4006 .. container:: verbose
4009 .. container:: verbose
4007
4010
4008 Examples:
4011 Examples:
4009
4012
4010 - copy a single change to the stable branch and edit its description::
4013 - copy a single change to the stable branch and edit its description::
4011
4014
4012 hg update stable
4015 hg update stable
4013 hg graft --edit 9393
4016 hg graft --edit 9393
4014
4017
4015 - graft a range of changesets with one exception, updating dates::
4018 - graft a range of changesets with one exception, updating dates::
4016
4019
4017 hg graft -D "2085::2093 and not 2091"
4020 hg graft -D "2085::2093 and not 2091"
4018
4021
4019 - continue a graft after resolving conflicts::
4022 - continue a graft after resolving conflicts::
4020
4023
4021 hg graft -c
4024 hg graft -c
4022
4025
4023 - show the source of a grafted changeset::
4026 - show the source of a grafted changeset::
4024
4027
4025 hg log --debug -r .
4028 hg log --debug -r .
4026
4029
4027 - show revisions sorted by date::
4030 - show revisions sorted by date::
4028
4031
4029 hg log -r 'sort(all(), date)'
4032 hg log -r 'sort(all(), date)'
4030
4033
4031 See :hg:`help revisions` and :hg:`help revsets` for more about
4034 See :hg:`help revisions` and :hg:`help revsets` for more about
4032 specifying revisions.
4035 specifying revisions.
4033
4036
4034 Returns 0 on successful completion.
4037 Returns 0 on successful completion.
4035 '''
4038 '''
4036 with repo.wlock():
4039 with repo.wlock():
4037 return _dograft(ui, repo, *revs, **opts)
4040 return _dograft(ui, repo, *revs, **opts)
4038
4041
4039 def _dograft(ui, repo, *revs, **opts):
4042 def _dograft(ui, repo, *revs, **opts):
4040 if revs and opts['rev']:
4043 if revs and opts['rev']:
4041 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4044 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4042 'revision ordering!\n'))
4045 'revision ordering!\n'))
4043
4046
4044 revs = list(revs)
4047 revs = list(revs)
4045 revs.extend(opts['rev'])
4048 revs.extend(opts['rev'])
4046
4049
4047 if not opts.get('user') and opts.get('currentuser'):
4050 if not opts.get('user') and opts.get('currentuser'):
4048 opts['user'] = ui.username()
4051 opts['user'] = ui.username()
4049 if not opts.get('date') and opts.get('currentdate'):
4052 if not opts.get('date') and opts.get('currentdate'):
4050 opts['date'] = "%d %d" % util.makedate()
4053 opts['date'] = "%d %d" % util.makedate()
4051
4054
4052 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4055 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4053
4056
4054 cont = False
4057 cont = False
4055 if opts['continue']:
4058 if opts['continue']:
4056 cont = True
4059 cont = True
4057 if revs:
4060 if revs:
4058 raise error.Abort(_("can't specify --continue and revisions"))
4061 raise error.Abort(_("can't specify --continue and revisions"))
4059 # read in unfinished revisions
4062 # read in unfinished revisions
4060 try:
4063 try:
4061 nodes = repo.vfs.read('graftstate').splitlines()
4064 nodes = repo.vfs.read('graftstate').splitlines()
4062 revs = [repo[node].rev() for node in nodes]
4065 revs = [repo[node].rev() for node in nodes]
4063 except IOError as inst:
4066 except IOError as inst:
4064 if inst.errno != errno.ENOENT:
4067 if inst.errno != errno.ENOENT:
4065 raise
4068 raise
4066 cmdutil.wrongtooltocontinue(repo, _('graft'))
4069 cmdutil.wrongtooltocontinue(repo, _('graft'))
4067 else:
4070 else:
4068 cmdutil.checkunfinished(repo)
4071 cmdutil.checkunfinished(repo)
4069 cmdutil.bailifchanged(repo)
4072 cmdutil.bailifchanged(repo)
4070 if not revs:
4073 if not revs:
4071 raise error.Abort(_('no revisions specified'))
4074 raise error.Abort(_('no revisions specified'))
4072 revs = scmutil.revrange(repo, revs)
4075 revs = scmutil.revrange(repo, revs)
4073
4076
4074 skipped = set()
4077 skipped = set()
4075 # check for merges
4078 # check for merges
4076 for rev in repo.revs('%ld and merge()', revs):
4079 for rev in repo.revs('%ld and merge()', revs):
4077 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4080 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4078 skipped.add(rev)
4081 skipped.add(rev)
4079 revs = [r for r in revs if r not in skipped]
4082 revs = [r for r in revs if r not in skipped]
4080 if not revs:
4083 if not revs:
4081 return -1
4084 return -1
4082
4085
4083 # Don't check in the --continue case, in effect retaining --force across
4086 # Don't check in the --continue case, in effect retaining --force across
4084 # --continues. That's because without --force, any revisions we decided to
4087 # --continues. That's because without --force, any revisions we decided to
4085 # skip would have been filtered out here, so they wouldn't have made their
4088 # skip would have been filtered out here, so they wouldn't have made their
4086 # way to the graftstate. With --force, any revisions we would have otherwise
4089 # way to the graftstate. With --force, any revisions we would have otherwise
4087 # skipped would not have been filtered out, and if they hadn't been applied
4090 # skipped would not have been filtered out, and if they hadn't been applied
4088 # already, they'd have been in the graftstate.
4091 # already, they'd have been in the graftstate.
4089 if not (cont or opts.get('force')):
4092 if not (cont or opts.get('force')):
4090 # check for ancestors of dest branch
4093 # check for ancestors of dest branch
4091 crev = repo['.'].rev()
4094 crev = repo['.'].rev()
4092 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4095 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4093 # Cannot use x.remove(y) on smart set, this has to be a list.
4096 # Cannot use x.remove(y) on smart set, this has to be a list.
4094 # XXX make this lazy in the future
4097 # XXX make this lazy in the future
4095 revs = list(revs)
4098 revs = list(revs)
4096 # don't mutate while iterating, create a copy
4099 # don't mutate while iterating, create a copy
4097 for rev in list(revs):
4100 for rev in list(revs):
4098 if rev in ancestors:
4101 if rev in ancestors:
4099 ui.warn(_('skipping ancestor revision %d:%s\n') %
4102 ui.warn(_('skipping ancestor revision %d:%s\n') %
4100 (rev, repo[rev]))
4103 (rev, repo[rev]))
4101 # XXX remove on list is slow
4104 # XXX remove on list is slow
4102 revs.remove(rev)
4105 revs.remove(rev)
4103 if not revs:
4106 if not revs:
4104 return -1
4107 return -1
4105
4108
4106 # analyze revs for earlier grafts
4109 # analyze revs for earlier grafts
4107 ids = {}
4110 ids = {}
4108 for ctx in repo.set("%ld", revs):
4111 for ctx in repo.set("%ld", revs):
4109 ids[ctx.hex()] = ctx.rev()
4112 ids[ctx.hex()] = ctx.rev()
4110 n = ctx.extra().get('source')
4113 n = ctx.extra().get('source')
4111 if n:
4114 if n:
4112 ids[n] = ctx.rev()
4115 ids[n] = ctx.rev()
4113
4116
4114 # check ancestors for earlier grafts
4117 # check ancestors for earlier grafts
4115 ui.debug('scanning for duplicate grafts\n')
4118 ui.debug('scanning for duplicate grafts\n')
4116
4119
4117 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4120 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4118 ctx = repo[rev]
4121 ctx = repo[rev]
4119 n = ctx.extra().get('source')
4122 n = ctx.extra().get('source')
4120 if n in ids:
4123 if n in ids:
4121 try:
4124 try:
4122 r = repo[n].rev()
4125 r = repo[n].rev()
4123 except error.RepoLookupError:
4126 except error.RepoLookupError:
4124 r = None
4127 r = None
4125 if r in revs:
4128 if r in revs:
4126 ui.warn(_('skipping revision %d:%s '
4129 ui.warn(_('skipping revision %d:%s '
4127 '(already grafted to %d:%s)\n')
4130 '(already grafted to %d:%s)\n')
4128 % (r, repo[r], rev, ctx))
4131 % (r, repo[r], rev, ctx))
4129 revs.remove(r)
4132 revs.remove(r)
4130 elif ids[n] in revs:
4133 elif ids[n] in revs:
4131 if r is None:
4134 if r is None:
4132 ui.warn(_('skipping already grafted revision %d:%s '
4135 ui.warn(_('skipping already grafted revision %d:%s '
4133 '(%d:%s also has unknown origin %s)\n')
4136 '(%d:%s also has unknown origin %s)\n')
4134 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4137 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4135 else:
4138 else:
4136 ui.warn(_('skipping already grafted revision %d:%s '
4139 ui.warn(_('skipping already grafted revision %d:%s '
4137 '(%d:%s also has origin %d:%s)\n')
4140 '(%d:%s also has origin %d:%s)\n')
4138 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4141 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4139 revs.remove(ids[n])
4142 revs.remove(ids[n])
4140 elif ctx.hex() in ids:
4143 elif ctx.hex() in ids:
4141 r = ids[ctx.hex()]
4144 r = ids[ctx.hex()]
4142 ui.warn(_('skipping already grafted revision %d:%s '
4145 ui.warn(_('skipping already grafted revision %d:%s '
4143 '(was grafted from %d:%s)\n') %
4146 '(was grafted from %d:%s)\n') %
4144 (r, repo[r], rev, ctx))
4147 (r, repo[r], rev, ctx))
4145 revs.remove(r)
4148 revs.remove(r)
4146 if not revs:
4149 if not revs:
4147 return -1
4150 return -1
4148
4151
4149 for pos, ctx in enumerate(repo.set("%ld", revs)):
4152 for pos, ctx in enumerate(repo.set("%ld", revs)):
4150 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4153 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4151 ctx.description().split('\n', 1)[0])
4154 ctx.description().split('\n', 1)[0])
4152 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4155 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4153 if names:
4156 if names:
4154 desc += ' (%s)' % ' '.join(names)
4157 desc += ' (%s)' % ' '.join(names)
4155 ui.status(_('grafting %s\n') % desc)
4158 ui.status(_('grafting %s\n') % desc)
4156 if opts.get('dry_run'):
4159 if opts.get('dry_run'):
4157 continue
4160 continue
4158
4161
4159 source = ctx.extra().get('source')
4162 source = ctx.extra().get('source')
4160 extra = {}
4163 extra = {}
4161 if source:
4164 if source:
4162 extra['source'] = source
4165 extra['source'] = source
4163 extra['intermediate-source'] = ctx.hex()
4166 extra['intermediate-source'] = ctx.hex()
4164 else:
4167 else:
4165 extra['source'] = ctx.hex()
4168 extra['source'] = ctx.hex()
4166 user = ctx.user()
4169 user = ctx.user()
4167 if opts.get('user'):
4170 if opts.get('user'):
4168 user = opts['user']
4171 user = opts['user']
4169 date = ctx.date()
4172 date = ctx.date()
4170 if opts.get('date'):
4173 if opts.get('date'):
4171 date = opts['date']
4174 date = opts['date']
4172 message = ctx.description()
4175 message = ctx.description()
4173 if opts.get('log'):
4176 if opts.get('log'):
4174 message += '\n(grafted from %s)' % ctx.hex()
4177 message += '\n(grafted from %s)' % ctx.hex()
4175
4178
4176 # we don't merge the first commit when continuing
4179 # we don't merge the first commit when continuing
4177 if not cont:
4180 if not cont:
4178 # perform the graft merge with p1(rev) as 'ancestor'
4181 # perform the graft merge with p1(rev) as 'ancestor'
4179 try:
4182 try:
4180 # ui.forcemerge is an internal variable, do not document
4183 # ui.forcemerge is an internal variable, do not document
4181 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4184 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4182 'graft')
4185 'graft')
4183 stats = mergemod.graft(repo, ctx, ctx.p1(),
4186 stats = mergemod.graft(repo, ctx, ctx.p1(),
4184 ['local', 'graft'])
4187 ['local', 'graft'])
4185 finally:
4188 finally:
4186 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4189 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4187 # report any conflicts
4190 # report any conflicts
4188 if stats and stats[3] > 0:
4191 if stats and stats[3] > 0:
4189 # write out state for --continue
4192 # write out state for --continue
4190 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4193 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4191 repo.vfs.write('graftstate', ''.join(nodelines))
4194 repo.vfs.write('graftstate', ''.join(nodelines))
4192 extra = ''
4195 extra = ''
4193 if opts.get('user'):
4196 if opts.get('user'):
4194 extra += ' --user %s' % opts['user']
4197 extra += ' --user %s' % opts['user']
4195 if opts.get('date'):
4198 if opts.get('date'):
4196 extra += ' --date %s' % opts['date']
4199 extra += ' --date %s' % opts['date']
4197 if opts.get('log'):
4200 if opts.get('log'):
4198 extra += ' --log'
4201 extra += ' --log'
4199 hint=_('use hg resolve and hg graft --continue%s') % extra
4202 hint=_('use hg resolve and hg graft --continue%s') % extra
4200 raise error.Abort(
4203 raise error.Abort(
4201 _("unresolved conflicts, can't continue"),
4204 _("unresolved conflicts, can't continue"),
4202 hint=hint)
4205 hint=hint)
4203 else:
4206 else:
4204 cont = False
4207 cont = False
4205
4208
4206 # commit
4209 # commit
4207 node = repo.commit(text=message, user=user,
4210 node = repo.commit(text=message, user=user,
4208 date=date, extra=extra, editor=editor)
4211 date=date, extra=extra, editor=editor)
4209 if node is None:
4212 if node is None:
4210 ui.warn(
4213 ui.warn(
4211 _('note: graft of %d:%s created no changes to commit\n') %
4214 _('note: graft of %d:%s created no changes to commit\n') %
4212 (ctx.rev(), ctx))
4215 (ctx.rev(), ctx))
4213
4216
4214 # remove state when we complete successfully
4217 # remove state when we complete successfully
4215 if not opts.get('dry_run'):
4218 if not opts.get('dry_run'):
4216 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4219 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4217
4220
4218 return 0
4221 return 0
4219
4222
4220 @command('grep',
4223 @command('grep',
4221 [('0', 'print0', None, _('end fields with NUL')),
4224 [('0', 'print0', None, _('end fields with NUL')),
4222 ('', 'all', None, _('print all revisions that match')),
4225 ('', 'all', None, _('print all revisions that match')),
4223 ('a', 'text', None, _('treat all files as text')),
4226 ('a', 'text', None, _('treat all files as text')),
4224 ('f', 'follow', None,
4227 ('f', 'follow', None,
4225 _('follow changeset history,'
4228 _('follow changeset history,'
4226 ' or file history across copies and renames')),
4229 ' or file history across copies and renames')),
4227 ('i', 'ignore-case', None, _('ignore case when matching')),
4230 ('i', 'ignore-case', None, _('ignore case when matching')),
4228 ('l', 'files-with-matches', None,
4231 ('l', 'files-with-matches', None,
4229 _('print only filenames and revisions that match')),
4232 _('print only filenames and revisions that match')),
4230 ('n', 'line-number', None, _('print matching line numbers')),
4233 ('n', 'line-number', None, _('print matching line numbers')),
4231 ('r', 'rev', [],
4234 ('r', 'rev', [],
4232 _('only search files changed within revision range'), _('REV')),
4235 _('only search files changed within revision range'), _('REV')),
4233 ('u', 'user', None, _('list the author (long with -v)')),
4236 ('u', 'user', None, _('list the author (long with -v)')),
4234 ('d', 'date', None, _('list the date (short with -q)')),
4237 ('d', 'date', None, _('list the date (short with -q)')),
4235 ] + walkopts,
4238 ] + walkopts,
4236 _('[OPTION]... PATTERN [FILE]...'),
4239 _('[OPTION]... PATTERN [FILE]...'),
4237 inferrepo=True)
4240 inferrepo=True)
4238 def grep(ui, repo, pattern, *pats, **opts):
4241 def grep(ui, repo, pattern, *pats, **opts):
4239 """search for a pattern in specified files and revisions
4242 """search for a pattern in specified files and revisions
4240
4243
4241 Search revisions of files for a regular expression.
4244 Search revisions of files for a regular expression.
4242
4245
4243 This command behaves differently than Unix grep. It only accepts
4246 This command behaves differently than Unix grep. It only accepts
4244 Python/Perl regexps. It searches repository history, not the
4247 Python/Perl regexps. It searches repository history, not the
4245 working directory. It always prints the revision number in which a
4248 working directory. It always prints the revision number in which a
4246 match appears.
4249 match appears.
4247
4250
4248 By default, grep only prints output for the first revision of a
4251 By default, grep only prints output for the first revision of a
4249 file in which it finds a match. To get it to print every revision
4252 file in which it finds a match. To get it to print every revision
4250 that contains a change in match status ("-" for a match that
4253 that contains a change in match status ("-" for a match that
4251 becomes a non-match, or "+" for a non-match that becomes a match),
4254 becomes a non-match, or "+" for a non-match that becomes a match),
4252 use the --all flag.
4255 use the --all flag.
4253
4256
4254 Returns 0 if a match is found, 1 otherwise.
4257 Returns 0 if a match is found, 1 otherwise.
4255 """
4258 """
4256 reflags = re.M
4259 reflags = re.M
4257 if opts.get('ignore_case'):
4260 if opts.get('ignore_case'):
4258 reflags |= re.I
4261 reflags |= re.I
4259 try:
4262 try:
4260 regexp = util.re.compile(pattern, reflags)
4263 regexp = util.re.compile(pattern, reflags)
4261 except re.error as inst:
4264 except re.error as inst:
4262 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4265 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4263 return 1
4266 return 1
4264 sep, eol = ':', '\n'
4267 sep, eol = ':', '\n'
4265 if opts.get('print0'):
4268 if opts.get('print0'):
4266 sep = eol = '\0'
4269 sep = eol = '\0'
4267
4270
4268 getfile = util.lrucachefunc(repo.file)
4271 getfile = util.lrucachefunc(repo.file)
4269
4272
4270 def matchlines(body):
4273 def matchlines(body):
4271 begin = 0
4274 begin = 0
4272 linenum = 0
4275 linenum = 0
4273 while begin < len(body):
4276 while begin < len(body):
4274 match = regexp.search(body, begin)
4277 match = regexp.search(body, begin)
4275 if not match:
4278 if not match:
4276 break
4279 break
4277 mstart, mend = match.span()
4280 mstart, mend = match.span()
4278 linenum += body.count('\n', begin, mstart) + 1
4281 linenum += body.count('\n', begin, mstart) + 1
4279 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4282 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4280 begin = body.find('\n', mend) + 1 or len(body) + 1
4283 begin = body.find('\n', mend) + 1 or len(body) + 1
4281 lend = begin - 1
4284 lend = begin - 1
4282 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4285 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4283
4286
4284 class linestate(object):
4287 class linestate(object):
4285 def __init__(self, line, linenum, colstart, colend):
4288 def __init__(self, line, linenum, colstart, colend):
4286 self.line = line
4289 self.line = line
4287 self.linenum = linenum
4290 self.linenum = linenum
4288 self.colstart = colstart
4291 self.colstart = colstart
4289 self.colend = colend
4292 self.colend = colend
4290
4293
4291 def __hash__(self):
4294 def __hash__(self):
4292 return hash((self.linenum, self.line))
4295 return hash((self.linenum, self.line))
4293
4296
4294 def __eq__(self, other):
4297 def __eq__(self, other):
4295 return self.line == other.line
4298 return self.line == other.line
4296
4299
4297 def __iter__(self):
4300 def __iter__(self):
4298 yield (self.line[:self.colstart], '')
4301 yield (self.line[:self.colstart], '')
4299 yield (self.line[self.colstart:self.colend], 'grep.match')
4302 yield (self.line[self.colstart:self.colend], 'grep.match')
4300 rest = self.line[self.colend:]
4303 rest = self.line[self.colend:]
4301 while rest != '':
4304 while rest != '':
4302 match = regexp.search(rest)
4305 match = regexp.search(rest)
4303 if not match:
4306 if not match:
4304 yield (rest, '')
4307 yield (rest, '')
4305 break
4308 break
4306 mstart, mend = match.span()
4309 mstart, mend = match.span()
4307 yield (rest[:mstart], '')
4310 yield (rest[:mstart], '')
4308 yield (rest[mstart:mend], 'grep.match')
4311 yield (rest[mstart:mend], 'grep.match')
4309 rest = rest[mend:]
4312 rest = rest[mend:]
4310
4313
4311 matches = {}
4314 matches = {}
4312 copies = {}
4315 copies = {}
4313 def grepbody(fn, rev, body):
4316 def grepbody(fn, rev, body):
4314 matches[rev].setdefault(fn, [])
4317 matches[rev].setdefault(fn, [])
4315 m = matches[rev][fn]
4318 m = matches[rev][fn]
4316 for lnum, cstart, cend, line in matchlines(body):
4319 for lnum, cstart, cend, line in matchlines(body):
4317 s = linestate(line, lnum, cstart, cend)
4320 s = linestate(line, lnum, cstart, cend)
4318 m.append(s)
4321 m.append(s)
4319
4322
4320 def difflinestates(a, b):
4323 def difflinestates(a, b):
4321 sm = difflib.SequenceMatcher(None, a, b)
4324 sm = difflib.SequenceMatcher(None, a, b)
4322 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4325 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4323 if tag == 'insert':
4326 if tag == 'insert':
4324 for i in xrange(blo, bhi):
4327 for i in xrange(blo, bhi):
4325 yield ('+', b[i])
4328 yield ('+', b[i])
4326 elif tag == 'delete':
4329 elif tag == 'delete':
4327 for i in xrange(alo, ahi):
4330 for i in xrange(alo, ahi):
4328 yield ('-', a[i])
4331 yield ('-', a[i])
4329 elif tag == 'replace':
4332 elif tag == 'replace':
4330 for i in xrange(alo, ahi):
4333 for i in xrange(alo, ahi):
4331 yield ('-', a[i])
4334 yield ('-', a[i])
4332 for i in xrange(blo, bhi):
4335 for i in xrange(blo, bhi):
4333 yield ('+', b[i])
4336 yield ('+', b[i])
4334
4337
4335 def display(fn, ctx, pstates, states):
4338 def display(fn, ctx, pstates, states):
4336 rev = ctx.rev()
4339 rev = ctx.rev()
4337 if ui.quiet:
4340 if ui.quiet:
4338 datefunc = util.shortdate
4341 datefunc = util.shortdate
4339 else:
4342 else:
4340 datefunc = util.datestr
4343 datefunc = util.datestr
4341 found = False
4344 found = False
4342 @util.cachefunc
4345 @util.cachefunc
4343 def binary():
4346 def binary():
4344 flog = getfile(fn)
4347 flog = getfile(fn)
4345 return util.binary(flog.read(ctx.filenode(fn)))
4348 return util.binary(flog.read(ctx.filenode(fn)))
4346
4349
4347 if opts.get('all'):
4350 if opts.get('all'):
4348 iter = difflinestates(pstates, states)
4351 iter = difflinestates(pstates, states)
4349 else:
4352 else:
4350 iter = [('', l) for l in states]
4353 iter = [('', l) for l in states]
4351 for change, l in iter:
4354 for change, l in iter:
4352 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4355 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4353
4356
4354 if opts.get('line_number'):
4357 if opts.get('line_number'):
4355 cols.append((str(l.linenum), 'grep.linenumber'))
4358 cols.append((str(l.linenum), 'grep.linenumber'))
4356 if opts.get('all'):
4359 if opts.get('all'):
4357 cols.append((change, 'grep.change'))
4360 cols.append((change, 'grep.change'))
4358 if opts.get('user'):
4361 if opts.get('user'):
4359 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4362 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4360 if opts.get('date'):
4363 if opts.get('date'):
4361 cols.append((datefunc(ctx.date()), 'grep.date'))
4364 cols.append((datefunc(ctx.date()), 'grep.date'))
4362 for col, label in cols[:-1]:
4365 for col, label in cols[:-1]:
4363 ui.write(col, label=label)
4366 ui.write(col, label=label)
4364 ui.write(sep, label='grep.sep')
4367 ui.write(sep, label='grep.sep')
4365 ui.write(cols[-1][0], label=cols[-1][1])
4368 ui.write(cols[-1][0], label=cols[-1][1])
4366 if not opts.get('files_with_matches'):
4369 if not opts.get('files_with_matches'):
4367 ui.write(sep, label='grep.sep')
4370 ui.write(sep, label='grep.sep')
4368 if not opts.get('text') and binary():
4371 if not opts.get('text') and binary():
4369 ui.write(" Binary file matches")
4372 ui.write(" Binary file matches")
4370 else:
4373 else:
4371 for s, label in l:
4374 for s, label in l:
4372 ui.write(s, label=label)
4375 ui.write(s, label=label)
4373 ui.write(eol)
4376 ui.write(eol)
4374 found = True
4377 found = True
4375 if opts.get('files_with_matches'):
4378 if opts.get('files_with_matches'):
4376 break
4379 break
4377 return found
4380 return found
4378
4381
4379 skip = {}
4382 skip = {}
4380 revfiles = {}
4383 revfiles = {}
4381 matchfn = scmutil.match(repo[None], pats, opts)
4384 matchfn = scmutil.match(repo[None], pats, opts)
4382 found = False
4385 found = False
4383 follow = opts.get('follow')
4386 follow = opts.get('follow')
4384
4387
4385 def prep(ctx, fns):
4388 def prep(ctx, fns):
4386 rev = ctx.rev()
4389 rev = ctx.rev()
4387 pctx = ctx.p1()
4390 pctx = ctx.p1()
4388 parent = pctx.rev()
4391 parent = pctx.rev()
4389 matches.setdefault(rev, {})
4392 matches.setdefault(rev, {})
4390 matches.setdefault(parent, {})
4393 matches.setdefault(parent, {})
4391 files = revfiles.setdefault(rev, [])
4394 files = revfiles.setdefault(rev, [])
4392 for fn in fns:
4395 for fn in fns:
4393 flog = getfile(fn)
4396 flog = getfile(fn)
4394 try:
4397 try:
4395 fnode = ctx.filenode(fn)
4398 fnode = ctx.filenode(fn)
4396 except error.LookupError:
4399 except error.LookupError:
4397 continue
4400 continue
4398
4401
4399 copied = flog.renamed(fnode)
4402 copied = flog.renamed(fnode)
4400 copy = follow and copied and copied[0]
4403 copy = follow and copied and copied[0]
4401 if copy:
4404 if copy:
4402 copies.setdefault(rev, {})[fn] = copy
4405 copies.setdefault(rev, {})[fn] = copy
4403 if fn in skip:
4406 if fn in skip:
4404 if copy:
4407 if copy:
4405 skip[copy] = True
4408 skip[copy] = True
4406 continue
4409 continue
4407 files.append(fn)
4410 files.append(fn)
4408
4411
4409 if fn not in matches[rev]:
4412 if fn not in matches[rev]:
4410 grepbody(fn, rev, flog.read(fnode))
4413 grepbody(fn, rev, flog.read(fnode))
4411
4414
4412 pfn = copy or fn
4415 pfn = copy or fn
4413 if pfn not in matches[parent]:
4416 if pfn not in matches[parent]:
4414 try:
4417 try:
4415 fnode = pctx.filenode(pfn)
4418 fnode = pctx.filenode(pfn)
4416 grepbody(pfn, parent, flog.read(fnode))
4419 grepbody(pfn, parent, flog.read(fnode))
4417 except error.LookupError:
4420 except error.LookupError:
4418 pass
4421 pass
4419
4422
4420 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4423 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4421 rev = ctx.rev()
4424 rev = ctx.rev()
4422 parent = ctx.p1().rev()
4425 parent = ctx.p1().rev()
4423 for fn in sorted(revfiles.get(rev, [])):
4426 for fn in sorted(revfiles.get(rev, [])):
4424 states = matches[rev][fn]
4427 states = matches[rev][fn]
4425 copy = copies.get(rev, {}).get(fn)
4428 copy = copies.get(rev, {}).get(fn)
4426 if fn in skip:
4429 if fn in skip:
4427 if copy:
4430 if copy:
4428 skip[copy] = True
4431 skip[copy] = True
4429 continue
4432 continue
4430 pstates = matches.get(parent, {}).get(copy or fn, [])
4433 pstates = matches.get(parent, {}).get(copy or fn, [])
4431 if pstates or states:
4434 if pstates or states:
4432 r = display(fn, ctx, pstates, states)
4435 r = display(fn, ctx, pstates, states)
4433 found = found or r
4436 found = found or r
4434 if r and not opts.get('all'):
4437 if r and not opts.get('all'):
4435 skip[fn] = True
4438 skip[fn] = True
4436 if copy:
4439 if copy:
4437 skip[copy] = True
4440 skip[copy] = True
4438 del matches[rev]
4441 del matches[rev]
4439 del revfiles[rev]
4442 del revfiles[rev]
4440
4443
4441 return not found
4444 return not found
4442
4445
4443 @command('heads',
4446 @command('heads',
4444 [('r', 'rev', '',
4447 [('r', 'rev', '',
4445 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4448 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4446 ('t', 'topo', False, _('show topological heads only')),
4449 ('t', 'topo', False, _('show topological heads only')),
4447 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4450 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4448 ('c', 'closed', False, _('show normal and closed branch heads')),
4451 ('c', 'closed', False, _('show normal and closed branch heads')),
4449 ] + templateopts,
4452 ] + templateopts,
4450 _('[-ct] [-r STARTREV] [REV]...'))
4453 _('[-ct] [-r STARTREV] [REV]...'))
4451 def heads(ui, repo, *branchrevs, **opts):
4454 def heads(ui, repo, *branchrevs, **opts):
4452 """show branch heads
4455 """show branch heads
4453
4456
4454 With no arguments, show all open branch heads in the repository.
4457 With no arguments, show all open branch heads in the repository.
4455 Branch heads are changesets that have no descendants on the
4458 Branch heads are changesets that have no descendants on the
4456 same branch. They are where development generally takes place and
4459 same branch. They are where development generally takes place and
4457 are the usual targets for update and merge operations.
4460 are the usual targets for update and merge operations.
4458
4461
4459 If one or more REVs are given, only open branch heads on the
4462 If one or more REVs are given, only open branch heads on the
4460 branches associated with the specified changesets are shown. This
4463 branches associated with the specified changesets are shown. This
4461 means that you can use :hg:`heads .` to see the heads on the
4464 means that you can use :hg:`heads .` to see the heads on the
4462 currently checked-out branch.
4465 currently checked-out branch.
4463
4466
4464 If -c/--closed is specified, also show branch heads marked closed
4467 If -c/--closed is specified, also show branch heads marked closed
4465 (see :hg:`commit --close-branch`).
4468 (see :hg:`commit --close-branch`).
4466
4469
4467 If STARTREV is specified, only those heads that are descendants of
4470 If STARTREV is specified, only those heads that are descendants of
4468 STARTREV will be displayed.
4471 STARTREV will be displayed.
4469
4472
4470 If -t/--topo is specified, named branch mechanics will be ignored and only
4473 If -t/--topo is specified, named branch mechanics will be ignored and only
4471 topological heads (changesets with no children) will be shown.
4474 topological heads (changesets with no children) will be shown.
4472
4475
4473 Returns 0 if matching heads are found, 1 if not.
4476 Returns 0 if matching heads are found, 1 if not.
4474 """
4477 """
4475
4478
4476 start = None
4479 start = None
4477 if 'rev' in opts:
4480 if 'rev' in opts:
4478 start = scmutil.revsingle(repo, opts['rev'], None).node()
4481 start = scmutil.revsingle(repo, opts['rev'], None).node()
4479
4482
4480 if opts.get('topo'):
4483 if opts.get('topo'):
4481 heads = [repo[h] for h in repo.heads(start)]
4484 heads = [repo[h] for h in repo.heads(start)]
4482 else:
4485 else:
4483 heads = []
4486 heads = []
4484 for branch in repo.branchmap():
4487 for branch in repo.branchmap():
4485 heads += repo.branchheads(branch, start, opts.get('closed'))
4488 heads += repo.branchheads(branch, start, opts.get('closed'))
4486 heads = [repo[h] for h in heads]
4489 heads = [repo[h] for h in heads]
4487
4490
4488 if branchrevs:
4491 if branchrevs:
4489 branches = set(repo[br].branch() for br in branchrevs)
4492 branches = set(repo[br].branch() for br in branchrevs)
4490 heads = [h for h in heads if h.branch() in branches]
4493 heads = [h for h in heads if h.branch() in branches]
4491
4494
4492 if opts.get('active') and branchrevs:
4495 if opts.get('active') and branchrevs:
4493 dagheads = repo.heads(start)
4496 dagheads = repo.heads(start)
4494 heads = [h for h in heads if h.node() in dagheads]
4497 heads = [h for h in heads if h.node() in dagheads]
4495
4498
4496 if branchrevs:
4499 if branchrevs:
4497 haveheads = set(h.branch() for h in heads)
4500 haveheads = set(h.branch() for h in heads)
4498 if branches - haveheads:
4501 if branches - haveheads:
4499 headless = ', '.join(b for b in branches - haveheads)
4502 headless = ', '.join(b for b in branches - haveheads)
4500 msg = _('no open branch heads found on branches %s')
4503 msg = _('no open branch heads found on branches %s')
4501 if opts.get('rev'):
4504 if opts.get('rev'):
4502 msg += _(' (started at %s)') % opts['rev']
4505 msg += _(' (started at %s)') % opts['rev']
4503 ui.warn((msg + '\n') % headless)
4506 ui.warn((msg + '\n') % headless)
4504
4507
4505 if not heads:
4508 if not heads:
4506 return 1
4509 return 1
4507
4510
4508 heads = sorted(heads, key=lambda x: -x.rev())
4511 heads = sorted(heads, key=lambda x: -x.rev())
4509 displayer = cmdutil.show_changeset(ui, repo, opts)
4512 displayer = cmdutil.show_changeset(ui, repo, opts)
4510 for ctx in heads:
4513 for ctx in heads:
4511 displayer.show(ctx)
4514 displayer.show(ctx)
4512 displayer.close()
4515 displayer.close()
4513
4516
4514 @command('help',
4517 @command('help',
4515 [('e', 'extension', None, _('show only help for extensions')),
4518 [('e', 'extension', None, _('show only help for extensions')),
4516 ('c', 'command', None, _('show only help for commands')),
4519 ('c', 'command', None, _('show only help for commands')),
4517 ('k', 'keyword', None, _('show topics matching keyword')),
4520 ('k', 'keyword', None, _('show topics matching keyword')),
4518 ('s', 'system', [], _('show help for specific platform(s)')),
4521 ('s', 'system', [], _('show help for specific platform(s)')),
4519 ],
4522 ],
4520 _('[-ecks] [TOPIC]'),
4523 _('[-ecks] [TOPIC]'),
4521 norepo=True)
4524 norepo=True)
4522 def help_(ui, name=None, **opts):
4525 def help_(ui, name=None, **opts):
4523 """show help for a given topic or a help overview
4526 """show help for a given topic or a help overview
4524
4527
4525 With no arguments, print a list of commands with short help messages.
4528 With no arguments, print a list of commands with short help messages.
4526
4529
4527 Given a topic, extension, or command name, print help for that
4530 Given a topic, extension, or command name, print help for that
4528 topic.
4531 topic.
4529
4532
4530 Returns 0 if successful.
4533 Returns 0 if successful.
4531 """
4534 """
4532
4535
4533 textwidth = min(ui.termwidth(), 80) - 2
4536 textwidth = min(ui.termwidth(), 80) - 2
4534
4537
4535 keep = opts.get('system') or []
4538 keep = opts.get('system') or []
4536 if len(keep) == 0:
4539 if len(keep) == 0:
4537 if sys.platform.startswith('win'):
4540 if sys.platform.startswith('win'):
4538 keep.append('windows')
4541 keep.append('windows')
4539 elif sys.platform == 'OpenVMS':
4542 elif sys.platform == 'OpenVMS':
4540 keep.append('vms')
4543 keep.append('vms')
4541 elif sys.platform == 'plan9':
4544 elif sys.platform == 'plan9':
4542 keep.append('plan9')
4545 keep.append('plan9')
4543 else:
4546 else:
4544 keep.append('unix')
4547 keep.append('unix')
4545 keep.append(sys.platform.lower())
4548 keep.append(sys.platform.lower())
4546 if ui.verbose:
4549 if ui.verbose:
4547 keep.append('verbose')
4550 keep.append('verbose')
4548
4551
4549 section = None
4552 section = None
4550 subtopic = None
4553 subtopic = None
4551 if name and '.' in name:
4554 if name and '.' in name:
4552 name, section = name.split('.', 1)
4555 name, section = name.split('.', 1)
4553 section = section.lower()
4556 section = section.lower()
4554 if '.' in section:
4557 if '.' in section:
4555 subtopic, section = section.split('.', 1)
4558 subtopic, section = section.split('.', 1)
4556 else:
4559 else:
4557 subtopic = section
4560 subtopic = section
4558
4561
4559 text = help.help_(ui, name, subtopic=subtopic, **opts)
4562 text = help.help_(ui, name, subtopic=subtopic, **opts)
4560
4563
4561 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4564 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4562 section=section)
4565 section=section)
4563
4566
4564 # We could have been given a weird ".foo" section without a name
4567 # We could have been given a weird ".foo" section without a name
4565 # to look for, or we could have simply failed to found "foo.bar"
4568 # to look for, or we could have simply failed to found "foo.bar"
4566 # because bar isn't a section of foo
4569 # because bar isn't a section of foo
4567 if section and not (formatted and name):
4570 if section and not (formatted and name):
4568 raise error.Abort(_("help section not found"))
4571 raise error.Abort(_("help section not found"))
4569
4572
4570 if 'verbose' in pruned:
4573 if 'verbose' in pruned:
4571 keep.append('omitted')
4574 keep.append('omitted')
4572 else:
4575 else:
4573 keep.append('notomitted')
4576 keep.append('notomitted')
4574 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4577 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4575 section=section)
4578 section=section)
4576 ui.write(formatted)
4579 ui.write(formatted)
4577
4580
4578
4581
4579 @command('identify|id',
4582 @command('identify|id',
4580 [('r', 'rev', '',
4583 [('r', 'rev', '',
4581 _('identify the specified revision'), _('REV')),
4584 _('identify the specified revision'), _('REV')),
4582 ('n', 'num', None, _('show local revision number')),
4585 ('n', 'num', None, _('show local revision number')),
4583 ('i', 'id', None, _('show global revision id')),
4586 ('i', 'id', None, _('show global revision id')),
4584 ('b', 'branch', None, _('show branch')),
4587 ('b', 'branch', None, _('show branch')),
4585 ('t', 'tags', None, _('show tags')),
4588 ('t', 'tags', None, _('show tags')),
4586 ('B', 'bookmarks', None, _('show bookmarks')),
4589 ('B', 'bookmarks', None, _('show bookmarks')),
4587 ] + remoteopts,
4590 ] + remoteopts,
4588 _('[-nibtB] [-r REV] [SOURCE]'),
4591 _('[-nibtB] [-r REV] [SOURCE]'),
4589 optionalrepo=True)
4592 optionalrepo=True)
4590 def identify(ui, repo, source=None, rev=None,
4593 def identify(ui, repo, source=None, rev=None,
4591 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4594 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4592 """identify the working directory or specified revision
4595 """identify the working directory or specified revision
4593
4596
4594 Print a summary identifying the repository state at REV using one or
4597 Print a summary identifying the repository state at REV using one or
4595 two parent hash identifiers, followed by a "+" if the working
4598 two parent hash identifiers, followed by a "+" if the working
4596 directory has uncommitted changes, the branch name (if not default),
4599 directory has uncommitted changes, the branch name (if not default),
4597 a list of tags, and a list of bookmarks.
4600 a list of tags, and a list of bookmarks.
4598
4601
4599 When REV is not given, print a summary of the current state of the
4602 When REV is not given, print a summary of the current state of the
4600 repository.
4603 repository.
4601
4604
4602 Specifying a path to a repository root or Mercurial bundle will
4605 Specifying a path to a repository root or Mercurial bundle will
4603 cause lookup to operate on that repository/bundle.
4606 cause lookup to operate on that repository/bundle.
4604
4607
4605 .. container:: verbose
4608 .. container:: verbose
4606
4609
4607 Examples:
4610 Examples:
4608
4611
4609 - generate a build identifier for the working directory::
4612 - generate a build identifier for the working directory::
4610
4613
4611 hg id --id > build-id.dat
4614 hg id --id > build-id.dat
4612
4615
4613 - find the revision corresponding to a tag::
4616 - find the revision corresponding to a tag::
4614
4617
4615 hg id -n -r 1.3
4618 hg id -n -r 1.3
4616
4619
4617 - check the most recent revision of a remote repository::
4620 - check the most recent revision of a remote repository::
4618
4621
4619 hg id -r tip http://selenic.com/hg/
4622 hg id -r tip http://selenic.com/hg/
4620
4623
4621 See :hg:`log` for generating more information about specific revisions,
4624 See :hg:`log` for generating more information about specific revisions,
4622 including full hash identifiers.
4625 including full hash identifiers.
4623
4626
4624 Returns 0 if successful.
4627 Returns 0 if successful.
4625 """
4628 """
4626
4629
4627 if not repo and not source:
4630 if not repo and not source:
4628 raise error.Abort(_("there is no Mercurial repository here "
4631 raise error.Abort(_("there is no Mercurial repository here "
4629 "(.hg not found)"))
4632 "(.hg not found)"))
4630
4633
4631 if ui.debugflag:
4634 if ui.debugflag:
4632 hexfunc = hex
4635 hexfunc = hex
4633 else:
4636 else:
4634 hexfunc = short
4637 hexfunc = short
4635 default = not (num or id or branch or tags or bookmarks)
4638 default = not (num or id or branch or tags or bookmarks)
4636 output = []
4639 output = []
4637 revs = []
4640 revs = []
4638
4641
4639 if source:
4642 if source:
4640 source, branches = hg.parseurl(ui.expandpath(source))
4643 source, branches = hg.parseurl(ui.expandpath(source))
4641 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4644 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4642 repo = peer.local()
4645 repo = peer.local()
4643 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4646 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4644
4647
4645 if not repo:
4648 if not repo:
4646 if num or branch or tags:
4649 if num or branch or tags:
4647 raise error.Abort(
4650 raise error.Abort(
4648 _("can't query remote revision number, branch, or tags"))
4651 _("can't query remote revision number, branch, or tags"))
4649 if not rev and revs:
4652 if not rev and revs:
4650 rev = revs[0]
4653 rev = revs[0]
4651 if not rev:
4654 if not rev:
4652 rev = "tip"
4655 rev = "tip"
4653
4656
4654 remoterev = peer.lookup(rev)
4657 remoterev = peer.lookup(rev)
4655 if default or id:
4658 if default or id:
4656 output = [hexfunc(remoterev)]
4659 output = [hexfunc(remoterev)]
4657
4660
4658 def getbms():
4661 def getbms():
4659 bms = []
4662 bms = []
4660
4663
4661 if 'bookmarks' in peer.listkeys('namespaces'):
4664 if 'bookmarks' in peer.listkeys('namespaces'):
4662 hexremoterev = hex(remoterev)
4665 hexremoterev = hex(remoterev)
4663 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4666 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4664 if bmr == hexremoterev]
4667 if bmr == hexremoterev]
4665
4668
4666 return sorted(bms)
4669 return sorted(bms)
4667
4670
4668 if bookmarks:
4671 if bookmarks:
4669 output.extend(getbms())
4672 output.extend(getbms())
4670 elif default and not ui.quiet:
4673 elif default and not ui.quiet:
4671 # multiple bookmarks for a single parent separated by '/'
4674 # multiple bookmarks for a single parent separated by '/'
4672 bm = '/'.join(getbms())
4675 bm = '/'.join(getbms())
4673 if bm:
4676 if bm:
4674 output.append(bm)
4677 output.append(bm)
4675 else:
4678 else:
4676 ctx = scmutil.revsingle(repo, rev, None)
4679 ctx = scmutil.revsingle(repo, rev, None)
4677
4680
4678 if ctx.rev() is None:
4681 if ctx.rev() is None:
4679 ctx = repo[None]
4682 ctx = repo[None]
4680 parents = ctx.parents()
4683 parents = ctx.parents()
4681 taglist = []
4684 taglist = []
4682 for p in parents:
4685 for p in parents:
4683 taglist.extend(p.tags())
4686 taglist.extend(p.tags())
4684
4687
4685 changed = ""
4688 changed = ""
4686 if default or id or num:
4689 if default or id or num:
4687 if (any(repo.status())
4690 if (any(repo.status())
4688 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4691 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4689 changed = '+'
4692 changed = '+'
4690 if default or id:
4693 if default or id:
4691 output = ["%s%s" %
4694 output = ["%s%s" %
4692 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4695 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4693 if num:
4696 if num:
4694 output.append("%s%s" %
4697 output.append("%s%s" %
4695 ('+'.join([str(p.rev()) for p in parents]), changed))
4698 ('+'.join([str(p.rev()) for p in parents]), changed))
4696 else:
4699 else:
4697 if default or id:
4700 if default or id:
4698 output = [hexfunc(ctx.node())]
4701 output = [hexfunc(ctx.node())]
4699 if num:
4702 if num:
4700 output.append(str(ctx.rev()))
4703 output.append(str(ctx.rev()))
4701 taglist = ctx.tags()
4704 taglist = ctx.tags()
4702
4705
4703 if default and not ui.quiet:
4706 if default and not ui.quiet:
4704 b = ctx.branch()
4707 b = ctx.branch()
4705 if b != 'default':
4708 if b != 'default':
4706 output.append("(%s)" % b)
4709 output.append("(%s)" % b)
4707
4710
4708 # multiple tags for a single parent separated by '/'
4711 # multiple tags for a single parent separated by '/'
4709 t = '/'.join(taglist)
4712 t = '/'.join(taglist)
4710 if t:
4713 if t:
4711 output.append(t)
4714 output.append(t)
4712
4715
4713 # multiple bookmarks for a single parent separated by '/'
4716 # multiple bookmarks for a single parent separated by '/'
4714 bm = '/'.join(ctx.bookmarks())
4717 bm = '/'.join(ctx.bookmarks())
4715 if bm:
4718 if bm:
4716 output.append(bm)
4719 output.append(bm)
4717 else:
4720 else:
4718 if branch:
4721 if branch:
4719 output.append(ctx.branch())
4722 output.append(ctx.branch())
4720
4723
4721 if tags:
4724 if tags:
4722 output.extend(taglist)
4725 output.extend(taglist)
4723
4726
4724 if bookmarks:
4727 if bookmarks:
4725 output.extend(ctx.bookmarks())
4728 output.extend(ctx.bookmarks())
4726
4729
4727 ui.write("%s\n" % ' '.join(output))
4730 ui.write("%s\n" % ' '.join(output))
4728
4731
4729 @command('import|patch',
4732 @command('import|patch',
4730 [('p', 'strip', 1,
4733 [('p', 'strip', 1,
4731 _('directory strip option for patch. This has the same '
4734 _('directory strip option for patch. This has the same '
4732 'meaning as the corresponding patch option'), _('NUM')),
4735 'meaning as the corresponding patch option'), _('NUM')),
4733 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4736 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4734 ('e', 'edit', False, _('invoke editor on commit messages')),
4737 ('e', 'edit', False, _('invoke editor on commit messages')),
4735 ('f', 'force', None,
4738 ('f', 'force', None,
4736 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4739 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4737 ('', 'no-commit', None,
4740 ('', 'no-commit', None,
4738 _("don't commit, just update the working directory")),
4741 _("don't commit, just update the working directory")),
4739 ('', 'bypass', None,
4742 ('', 'bypass', None,
4740 _("apply patch without touching the working directory")),
4743 _("apply patch without touching the working directory")),
4741 ('', 'partial', None,
4744 ('', 'partial', None,
4742 _('commit even if some hunks fail')),
4745 _('commit even if some hunks fail')),
4743 ('', 'exact', None,
4746 ('', 'exact', None,
4744 _('apply patch to the nodes from which it was generated')),
4747 _('apply patch to the nodes from which it was generated')),
4745 ('', 'prefix', '',
4748 ('', 'prefix', '',
4746 _('apply patch to subdirectory'), _('DIR')),
4749 _('apply patch to subdirectory'), _('DIR')),
4747 ('', 'import-branch', None,
4750 ('', 'import-branch', None,
4748 _('use any branch information in patch (implied by --exact)'))] +
4751 _('use any branch information in patch (implied by --exact)'))] +
4749 commitopts + commitopts2 + similarityopts,
4752 commitopts + commitopts2 + similarityopts,
4750 _('[OPTION]... PATCH...'))
4753 _('[OPTION]... PATCH...'))
4751 def import_(ui, repo, patch1=None, *patches, **opts):
4754 def import_(ui, repo, patch1=None, *patches, **opts):
4752 """import an ordered set of patches
4755 """import an ordered set of patches
4753
4756
4754 Import a list of patches and commit them individually (unless
4757 Import a list of patches and commit them individually (unless
4755 --no-commit is specified).
4758 --no-commit is specified).
4756
4759
4757 To read a patch from standard input, use "-" as the patch name. If
4760 To read a patch from standard input, use "-" as the patch name. If
4758 a URL is specified, the patch will be downloaded from there.
4761 a URL is specified, the patch will be downloaded from there.
4759
4762
4760 Import first applies changes to the working directory (unless
4763 Import first applies changes to the working directory (unless
4761 --bypass is specified), import will abort if there are outstanding
4764 --bypass is specified), import will abort if there are outstanding
4762 changes.
4765 changes.
4763
4766
4764 Use --bypass to apply and commit patches directly to the
4767 Use --bypass to apply and commit patches directly to the
4765 repository, without affecting the working directory. Without
4768 repository, without affecting the working directory. Without
4766 --exact, patches will be applied on top of the working directory
4769 --exact, patches will be applied on top of the working directory
4767 parent revision.
4770 parent revision.
4768
4771
4769 You can import a patch straight from a mail message. Even patches
4772 You can import a patch straight from a mail message. Even patches
4770 as attachments work (to use the body part, it must have type
4773 as attachments work (to use the body part, it must have type
4771 text/plain or text/x-patch). From and Subject headers of email
4774 text/plain or text/x-patch). From and Subject headers of email
4772 message are used as default committer and commit message. All
4775 message are used as default committer and commit message. All
4773 text/plain body parts before first diff are added to the commit
4776 text/plain body parts before first diff are added to the commit
4774 message.
4777 message.
4775
4778
4776 If the imported patch was generated by :hg:`export`, user and
4779 If the imported patch was generated by :hg:`export`, user and
4777 description from patch override values from message headers and
4780 description from patch override values from message headers and
4778 body. Values given on command line with -m/--message and -u/--user
4781 body. Values given on command line with -m/--message and -u/--user
4779 override these.
4782 override these.
4780
4783
4781 If --exact is specified, import will set the working directory to
4784 If --exact is specified, import will set the working directory to
4782 the parent of each patch before applying it, and will abort if the
4785 the parent of each patch before applying it, and will abort if the
4783 resulting changeset has a different ID than the one recorded in
4786 resulting changeset has a different ID than the one recorded in
4784 the patch. This may happen due to character set problems or other
4787 the patch. This may happen due to character set problems or other
4785 deficiencies in the text patch format.
4788 deficiencies in the text patch format.
4786
4789
4787 Use --partial to ensure a changeset will be created from the patch
4790 Use --partial to ensure a changeset will be created from the patch
4788 even if some hunks fail to apply. Hunks that fail to apply will be
4791 even if some hunks fail to apply. Hunks that fail to apply will be
4789 written to a <target-file>.rej file. Conflicts can then be resolved
4792 written to a <target-file>.rej file. Conflicts can then be resolved
4790 by hand before :hg:`commit --amend` is run to update the created
4793 by hand before :hg:`commit --amend` is run to update the created
4791 changeset. This flag exists to let people import patches that
4794 changeset. This flag exists to let people import patches that
4792 partially apply without losing the associated metadata (author,
4795 partially apply without losing the associated metadata (author,
4793 date, description, ...).
4796 date, description, ...).
4794
4797
4795 .. note::
4798 .. note::
4796
4799
4797 When no hunks apply cleanly, :hg:`import --partial` will create
4800 When no hunks apply cleanly, :hg:`import --partial` will create
4798 an empty changeset, importing only the patch metadata.
4801 an empty changeset, importing only the patch metadata.
4799
4802
4800 With -s/--similarity, hg will attempt to discover renames and
4803 With -s/--similarity, hg will attempt to discover renames and
4801 copies in the patch in the same way as :hg:`addremove`.
4804 copies in the patch in the same way as :hg:`addremove`.
4802
4805
4803 It is possible to use external patch programs to perform the patch
4806 It is possible to use external patch programs to perform the patch
4804 by setting the ``ui.patch`` configuration option. For the default
4807 by setting the ``ui.patch`` configuration option. For the default
4805 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4808 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4806 See :hg:`help config` for more information about configuration
4809 See :hg:`help config` for more information about configuration
4807 files and how to use these options.
4810 files and how to use these options.
4808
4811
4809 See :hg:`help dates` for a list of formats valid for -d/--date.
4812 See :hg:`help dates` for a list of formats valid for -d/--date.
4810
4813
4811 .. container:: verbose
4814 .. container:: verbose
4812
4815
4813 Examples:
4816 Examples:
4814
4817
4815 - import a traditional patch from a website and detect renames::
4818 - import a traditional patch from a website and detect renames::
4816
4819
4817 hg import -s 80 http://example.com/bugfix.patch
4820 hg import -s 80 http://example.com/bugfix.patch
4818
4821
4819 - import a changeset from an hgweb server::
4822 - import a changeset from an hgweb server::
4820
4823
4821 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4824 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4822
4825
4823 - import all the patches in an Unix-style mbox::
4826 - import all the patches in an Unix-style mbox::
4824
4827
4825 hg import incoming-patches.mbox
4828 hg import incoming-patches.mbox
4826
4829
4827 - attempt to exactly restore an exported changeset (not always
4830 - attempt to exactly restore an exported changeset (not always
4828 possible)::
4831 possible)::
4829
4832
4830 hg import --exact proposed-fix.patch
4833 hg import --exact proposed-fix.patch
4831
4834
4832 - use an external tool to apply a patch which is too fuzzy for
4835 - use an external tool to apply a patch which is too fuzzy for
4833 the default internal tool.
4836 the default internal tool.
4834
4837
4835 hg import --config ui.patch="patch --merge" fuzzy.patch
4838 hg import --config ui.patch="patch --merge" fuzzy.patch
4836
4839
4837 - change the default fuzzing from 2 to a less strict 7
4840 - change the default fuzzing from 2 to a less strict 7
4838
4841
4839 hg import --config ui.fuzz=7 fuzz.patch
4842 hg import --config ui.fuzz=7 fuzz.patch
4840
4843
4841 Returns 0 on success, 1 on partial success (see --partial).
4844 Returns 0 on success, 1 on partial success (see --partial).
4842 """
4845 """
4843
4846
4844 if not patch1:
4847 if not patch1:
4845 raise error.Abort(_('need at least one patch to import'))
4848 raise error.Abort(_('need at least one patch to import'))
4846
4849
4847 patches = (patch1,) + patches
4850 patches = (patch1,) + patches
4848
4851
4849 date = opts.get('date')
4852 date = opts.get('date')
4850 if date:
4853 if date:
4851 opts['date'] = util.parsedate(date)
4854 opts['date'] = util.parsedate(date)
4852
4855
4853 exact = opts.get('exact')
4856 exact = opts.get('exact')
4854 update = not opts.get('bypass')
4857 update = not opts.get('bypass')
4855 if not update and opts.get('no_commit'):
4858 if not update and opts.get('no_commit'):
4856 raise error.Abort(_('cannot use --no-commit with --bypass'))
4859 raise error.Abort(_('cannot use --no-commit with --bypass'))
4857 try:
4860 try:
4858 sim = float(opts.get('similarity') or 0)
4861 sim = float(opts.get('similarity') or 0)
4859 except ValueError:
4862 except ValueError:
4860 raise error.Abort(_('similarity must be a number'))
4863 raise error.Abort(_('similarity must be a number'))
4861 if sim < 0 or sim > 100:
4864 if sim < 0 or sim > 100:
4862 raise error.Abort(_('similarity must be between 0 and 100'))
4865 raise error.Abort(_('similarity must be between 0 and 100'))
4863 if sim and not update:
4866 if sim and not update:
4864 raise error.Abort(_('cannot use --similarity with --bypass'))
4867 raise error.Abort(_('cannot use --similarity with --bypass'))
4865 if exact:
4868 if exact:
4866 if opts.get('edit'):
4869 if opts.get('edit'):
4867 raise error.Abort(_('cannot use --exact with --edit'))
4870 raise error.Abort(_('cannot use --exact with --edit'))
4868 if opts.get('prefix'):
4871 if opts.get('prefix'):
4869 raise error.Abort(_('cannot use --exact with --prefix'))
4872 raise error.Abort(_('cannot use --exact with --prefix'))
4870
4873
4871 base = opts["base"]
4874 base = opts["base"]
4872 wlock = dsguard = lock = tr = None
4875 wlock = dsguard = lock = tr = None
4873 msgs = []
4876 msgs = []
4874 ret = 0
4877 ret = 0
4875
4878
4876
4879
4877 try:
4880 try:
4878 wlock = repo.wlock()
4881 wlock = repo.wlock()
4879
4882
4880 if update:
4883 if update:
4881 cmdutil.checkunfinished(repo)
4884 cmdutil.checkunfinished(repo)
4882 if (exact or not opts.get('force')):
4885 if (exact or not opts.get('force')):
4883 cmdutil.bailifchanged(repo)
4886 cmdutil.bailifchanged(repo)
4884
4887
4885 if not opts.get('no_commit'):
4888 if not opts.get('no_commit'):
4886 lock = repo.lock()
4889 lock = repo.lock()
4887 tr = repo.transaction('import')
4890 tr = repo.transaction('import')
4888 else:
4891 else:
4889 dsguard = cmdutil.dirstateguard(repo, 'import')
4892 dsguard = cmdutil.dirstateguard(repo, 'import')
4890 parents = repo[None].parents()
4893 parents = repo[None].parents()
4891 for patchurl in patches:
4894 for patchurl in patches:
4892 if patchurl == '-':
4895 if patchurl == '-':
4893 ui.status(_('applying patch from stdin\n'))
4896 ui.status(_('applying patch from stdin\n'))
4894 patchfile = ui.fin
4897 patchfile = ui.fin
4895 patchurl = 'stdin' # for error message
4898 patchurl = 'stdin' # for error message
4896 else:
4899 else:
4897 patchurl = os.path.join(base, patchurl)
4900 patchurl = os.path.join(base, patchurl)
4898 ui.status(_('applying %s\n') % patchurl)
4901 ui.status(_('applying %s\n') % patchurl)
4899 patchfile = hg.openpath(ui, patchurl)
4902 patchfile = hg.openpath(ui, patchurl)
4900
4903
4901 haspatch = False
4904 haspatch = False
4902 for hunk in patch.split(patchfile):
4905 for hunk in patch.split(patchfile):
4903 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4906 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4904 parents, opts,
4907 parents, opts,
4905 msgs, hg.clean)
4908 msgs, hg.clean)
4906 if msg:
4909 if msg:
4907 haspatch = True
4910 haspatch = True
4908 ui.note(msg + '\n')
4911 ui.note(msg + '\n')
4909 if update or exact:
4912 if update or exact:
4910 parents = repo[None].parents()
4913 parents = repo[None].parents()
4911 else:
4914 else:
4912 parents = [repo[node]]
4915 parents = [repo[node]]
4913 if rej:
4916 if rej:
4914 ui.write_err(_("patch applied partially\n"))
4917 ui.write_err(_("patch applied partially\n"))
4915 ui.write_err(_("(fix the .rej files and run "
4918 ui.write_err(_("(fix the .rej files and run "
4916 "`hg commit --amend`)\n"))
4919 "`hg commit --amend`)\n"))
4917 ret = 1
4920 ret = 1
4918 break
4921 break
4919
4922
4920 if not haspatch:
4923 if not haspatch:
4921 raise error.Abort(_('%s: no diffs found') % patchurl)
4924 raise error.Abort(_('%s: no diffs found') % patchurl)
4922
4925
4923 if tr:
4926 if tr:
4924 tr.close()
4927 tr.close()
4925 if msgs:
4928 if msgs:
4926 repo.savecommitmessage('\n* * *\n'.join(msgs))
4929 repo.savecommitmessage('\n* * *\n'.join(msgs))
4927 if dsguard:
4930 if dsguard:
4928 dsguard.close()
4931 dsguard.close()
4929 return ret
4932 return ret
4930 finally:
4933 finally:
4931 if tr:
4934 if tr:
4932 tr.release()
4935 tr.release()
4933 release(lock, dsguard, wlock)
4936 release(lock, dsguard, wlock)
4934
4937
4935 @command('incoming|in',
4938 @command('incoming|in',
4936 [('f', 'force', None,
4939 [('f', 'force', None,
4937 _('run even if remote repository is unrelated')),
4940 _('run even if remote repository is unrelated')),
4938 ('n', 'newest-first', None, _('show newest record first')),
4941 ('n', 'newest-first', None, _('show newest record first')),
4939 ('', 'bundle', '',
4942 ('', 'bundle', '',
4940 _('file to store the bundles into'), _('FILE')),
4943 _('file to store the bundles into'), _('FILE')),
4941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4944 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4942 ('B', 'bookmarks', False, _("compare bookmarks")),
4945 ('B', 'bookmarks', False, _("compare bookmarks")),
4943 ('b', 'branch', [],
4946 ('b', 'branch', [],
4944 _('a specific branch you would like to pull'), _('BRANCH')),
4947 _('a specific branch you would like to pull'), _('BRANCH')),
4945 ] + logopts + remoteopts + subrepoopts,
4948 ] + logopts + remoteopts + subrepoopts,
4946 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4949 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4947 def incoming(ui, repo, source="default", **opts):
4950 def incoming(ui, repo, source="default", **opts):
4948 """show new changesets found in source
4951 """show new changesets found in source
4949
4952
4950 Show new changesets found in the specified path/URL or the default
4953 Show new changesets found in the specified path/URL or the default
4951 pull location. These are the changesets that would have been pulled
4954 pull location. These are the changesets that would have been pulled
4952 if a pull at the time you issued this command.
4955 if a pull at the time you issued this command.
4953
4956
4954 See pull for valid source format details.
4957 See pull for valid source format details.
4955
4958
4956 .. container:: verbose
4959 .. container:: verbose
4957
4960
4958 With -B/--bookmarks, the result of bookmark comparison between
4961 With -B/--bookmarks, the result of bookmark comparison between
4959 local and remote repositories is displayed. With -v/--verbose,
4962 local and remote repositories is displayed. With -v/--verbose,
4960 status is also displayed for each bookmark like below::
4963 status is also displayed for each bookmark like below::
4961
4964
4962 BM1 01234567890a added
4965 BM1 01234567890a added
4963 BM2 1234567890ab advanced
4966 BM2 1234567890ab advanced
4964 BM3 234567890abc diverged
4967 BM3 234567890abc diverged
4965 BM4 34567890abcd changed
4968 BM4 34567890abcd changed
4966
4969
4967 The action taken locally when pulling depends on the
4970 The action taken locally when pulling depends on the
4968 status of each bookmark:
4971 status of each bookmark:
4969
4972
4970 :``added``: pull will create it
4973 :``added``: pull will create it
4971 :``advanced``: pull will update it
4974 :``advanced``: pull will update it
4972 :``diverged``: pull will create a divergent bookmark
4975 :``diverged``: pull will create a divergent bookmark
4973 :``changed``: result depends on remote changesets
4976 :``changed``: result depends on remote changesets
4974
4977
4975 From the point of view of pulling behavior, bookmark
4978 From the point of view of pulling behavior, bookmark
4976 existing only in the remote repository are treated as ``added``,
4979 existing only in the remote repository are treated as ``added``,
4977 even if it is in fact locally deleted.
4980 even if it is in fact locally deleted.
4978
4981
4979 .. container:: verbose
4982 .. container:: verbose
4980
4983
4981 For remote repository, using --bundle avoids downloading the
4984 For remote repository, using --bundle avoids downloading the
4982 changesets twice if the incoming is followed by a pull.
4985 changesets twice if the incoming is followed by a pull.
4983
4986
4984 Examples:
4987 Examples:
4985
4988
4986 - show incoming changes with patches and full description::
4989 - show incoming changes with patches and full description::
4987
4990
4988 hg incoming -vp
4991 hg incoming -vp
4989
4992
4990 - show incoming changes excluding merges, store a bundle::
4993 - show incoming changes excluding merges, store a bundle::
4991
4994
4992 hg in -vpM --bundle incoming.hg
4995 hg in -vpM --bundle incoming.hg
4993 hg pull incoming.hg
4996 hg pull incoming.hg
4994
4997
4995 - briefly list changes inside a bundle::
4998 - briefly list changes inside a bundle::
4996
4999
4997 hg in changes.hg -T "{desc|firstline}\\n"
5000 hg in changes.hg -T "{desc|firstline}\\n"
4998
5001
4999 Returns 0 if there are incoming changes, 1 otherwise.
5002 Returns 0 if there are incoming changes, 1 otherwise.
5000 """
5003 """
5001 if opts.get('graph'):
5004 if opts.get('graph'):
5002 cmdutil.checkunsupportedgraphflags([], opts)
5005 cmdutil.checkunsupportedgraphflags([], opts)
5003 def display(other, chlist, displayer):
5006 def display(other, chlist, displayer):
5004 revdag = cmdutil.graphrevs(other, chlist, opts)
5007 revdag = cmdutil.graphrevs(other, chlist, opts)
5005 cmdutil.displaygraph(ui, repo, revdag, displayer,
5008 cmdutil.displaygraph(ui, repo, revdag, displayer,
5006 graphmod.asciiedges)
5009 graphmod.asciiedges)
5007
5010
5008 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5011 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5009 return 0
5012 return 0
5010
5013
5011 if opts.get('bundle') and opts.get('subrepos'):
5014 if opts.get('bundle') and opts.get('subrepos'):
5012 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5015 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5013
5016
5014 if opts.get('bookmarks'):
5017 if opts.get('bookmarks'):
5015 source, branches = hg.parseurl(ui.expandpath(source),
5018 source, branches = hg.parseurl(ui.expandpath(source),
5016 opts.get('branch'))
5019 opts.get('branch'))
5017 other = hg.peer(repo, opts, source)
5020 other = hg.peer(repo, opts, source)
5018 if 'bookmarks' not in other.listkeys('namespaces'):
5021 if 'bookmarks' not in other.listkeys('namespaces'):
5019 ui.warn(_("remote doesn't support bookmarks\n"))
5022 ui.warn(_("remote doesn't support bookmarks\n"))
5020 return 0
5023 return 0
5021 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5024 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5022 return bookmarks.incoming(ui, repo, other)
5025 return bookmarks.incoming(ui, repo, other)
5023
5026
5024 repo._subtoppath = ui.expandpath(source)
5027 repo._subtoppath = ui.expandpath(source)
5025 try:
5028 try:
5026 return hg.incoming(ui, repo, source, opts)
5029 return hg.incoming(ui, repo, source, opts)
5027 finally:
5030 finally:
5028 del repo._subtoppath
5031 del repo._subtoppath
5029
5032
5030
5033
5031 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5034 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5032 norepo=True)
5035 norepo=True)
5033 def init(ui, dest=".", **opts):
5036 def init(ui, dest=".", **opts):
5034 """create a new repository in the given directory
5037 """create a new repository in the given directory
5035
5038
5036 Initialize a new repository in the given directory. If the given
5039 Initialize a new repository in the given directory. If the given
5037 directory does not exist, it will be created.
5040 directory does not exist, it will be created.
5038
5041
5039 If no directory is given, the current directory is used.
5042 If no directory is given, the current directory is used.
5040
5043
5041 It is possible to specify an ``ssh://`` URL as the destination.
5044 It is possible to specify an ``ssh://`` URL as the destination.
5042 See :hg:`help urls` for more information.
5045 See :hg:`help urls` for more information.
5043
5046
5044 Returns 0 on success.
5047 Returns 0 on success.
5045 """
5048 """
5046 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5049 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5047
5050
5048 @command('locate',
5051 @command('locate',
5049 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5052 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5050 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5053 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5051 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5054 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5052 ] + walkopts,
5055 ] + walkopts,
5053 _('[OPTION]... [PATTERN]...'))
5056 _('[OPTION]... [PATTERN]...'))
5054 def locate(ui, repo, *pats, **opts):
5057 def locate(ui, repo, *pats, **opts):
5055 """locate files matching specific patterns (DEPRECATED)
5058 """locate files matching specific patterns (DEPRECATED)
5056
5059
5057 Print files under Mercurial control in the working directory whose
5060 Print files under Mercurial control in the working directory whose
5058 names match the given patterns.
5061 names match the given patterns.
5059
5062
5060 By default, this command searches all directories in the working
5063 By default, this command searches all directories in the working
5061 directory. To search just the current directory and its
5064 directory. To search just the current directory and its
5062 subdirectories, use "--include .".
5065 subdirectories, use "--include .".
5063
5066
5064 If no patterns are given to match, this command prints the names
5067 If no patterns are given to match, this command prints the names
5065 of all files under Mercurial control in the working directory.
5068 of all files under Mercurial control in the working directory.
5066
5069
5067 If you want to feed the output of this command into the "xargs"
5070 If you want to feed the output of this command into the "xargs"
5068 command, use the -0 option to both this command and "xargs". This
5071 command, use the -0 option to both this command and "xargs". This
5069 will avoid the problem of "xargs" treating single filenames that
5072 will avoid the problem of "xargs" treating single filenames that
5070 contain whitespace as multiple filenames.
5073 contain whitespace as multiple filenames.
5071
5074
5072 See :hg:`help files` for a more versatile command.
5075 See :hg:`help files` for a more versatile command.
5073
5076
5074 Returns 0 if a match is found, 1 otherwise.
5077 Returns 0 if a match is found, 1 otherwise.
5075 """
5078 """
5076 if opts.get('print0'):
5079 if opts.get('print0'):
5077 end = '\0'
5080 end = '\0'
5078 else:
5081 else:
5079 end = '\n'
5082 end = '\n'
5080 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5083 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5081
5084
5082 ret = 1
5085 ret = 1
5083 ctx = repo[rev]
5086 ctx = repo[rev]
5084 m = scmutil.match(ctx, pats, opts, default='relglob',
5087 m = scmutil.match(ctx, pats, opts, default='relglob',
5085 badfn=lambda x, y: False)
5088 badfn=lambda x, y: False)
5086
5089
5087 for abs in ctx.matches(m):
5090 for abs in ctx.matches(m):
5088 if opts.get('fullpath'):
5091 if opts.get('fullpath'):
5089 ui.write(repo.wjoin(abs), end)
5092 ui.write(repo.wjoin(abs), end)
5090 else:
5093 else:
5091 ui.write(((pats and m.rel(abs)) or abs), end)
5094 ui.write(((pats and m.rel(abs)) or abs), end)
5092 ret = 0
5095 ret = 0
5093
5096
5094 return ret
5097 return ret
5095
5098
5096 @command('^log|history',
5099 @command('^log|history',
5097 [('f', 'follow', None,
5100 [('f', 'follow', None,
5098 _('follow changeset history, or file history across copies and renames')),
5101 _('follow changeset history, or file history across copies and renames')),
5099 ('', 'follow-first', None,
5102 ('', 'follow-first', None,
5100 _('only follow the first parent of merge changesets (DEPRECATED)')),
5103 _('only follow the first parent of merge changesets (DEPRECATED)')),
5101 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5104 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5102 ('C', 'copies', None, _('show copied files')),
5105 ('C', 'copies', None, _('show copied files')),
5103 ('k', 'keyword', [],
5106 ('k', 'keyword', [],
5104 _('do case-insensitive search for a given text'), _('TEXT')),
5107 _('do case-insensitive search for a given text'), _('TEXT')),
5105 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5108 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5106 ('', 'removed', None, _('include revisions where files were removed')),
5109 ('', 'removed', None, _('include revisions where files were removed')),
5107 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5110 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5108 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5111 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5109 ('', 'only-branch', [],
5112 ('', 'only-branch', [],
5110 _('show only changesets within the given named branch (DEPRECATED)'),
5113 _('show only changesets within the given named branch (DEPRECATED)'),
5111 _('BRANCH')),
5114 _('BRANCH')),
5112 ('b', 'branch', [],
5115 ('b', 'branch', [],
5113 _('show changesets within the given named branch'), _('BRANCH')),
5116 _('show changesets within the given named branch'), _('BRANCH')),
5114 ('P', 'prune', [],
5117 ('P', 'prune', [],
5115 _('do not display revision or any of its ancestors'), _('REV')),
5118 _('do not display revision or any of its ancestors'), _('REV')),
5116 ] + logopts + walkopts,
5119 ] + logopts + walkopts,
5117 _('[OPTION]... [FILE]'),
5120 _('[OPTION]... [FILE]'),
5118 inferrepo=True)
5121 inferrepo=True)
5119 def log(ui, repo, *pats, **opts):
5122 def log(ui, repo, *pats, **opts):
5120 """show revision history of entire repository or files
5123 """show revision history of entire repository or files
5121
5124
5122 Print the revision history of the specified files or the entire
5125 Print the revision history of the specified files or the entire
5123 project.
5126 project.
5124
5127
5125 If no revision range is specified, the default is ``tip:0`` unless
5128 If no revision range is specified, the default is ``tip:0`` unless
5126 --follow is set, in which case the working directory parent is
5129 --follow is set, in which case the working directory parent is
5127 used as the starting revision.
5130 used as the starting revision.
5128
5131
5129 File history is shown without following rename or copy history of
5132 File history is shown without following rename or copy history of
5130 files. Use -f/--follow with a filename to follow history across
5133 files. Use -f/--follow with a filename to follow history across
5131 renames and copies. --follow without a filename will only show
5134 renames and copies. --follow without a filename will only show
5132 ancestors or descendants of the starting revision.
5135 ancestors or descendants of the starting revision.
5133
5136
5134 By default this command prints revision number and changeset id,
5137 By default this command prints revision number and changeset id,
5135 tags, non-trivial parents, user, date and time, and a summary for
5138 tags, non-trivial parents, user, date and time, and a summary for
5136 each commit. When the -v/--verbose switch is used, the list of
5139 each commit. When the -v/--verbose switch is used, the list of
5137 changed files and full commit message are shown.
5140 changed files and full commit message are shown.
5138
5141
5139 With --graph the revisions are shown as an ASCII art DAG with the most
5142 With --graph the revisions are shown as an ASCII art DAG with the most
5140 recent changeset at the top.
5143 recent changeset at the top.
5141 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5144 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5142 and '+' represents a fork where the changeset from the lines below is a
5145 and '+' represents a fork where the changeset from the lines below is a
5143 parent of the 'o' merge on the same line.
5146 parent of the 'o' merge on the same line.
5144
5147
5145 .. note::
5148 .. note::
5146
5149
5147 :hg:`log --patch` may generate unexpected diff output for merge
5150 :hg:`log --patch` may generate unexpected diff output for merge
5148 changesets, as it will only compare the merge changeset against
5151 changesets, as it will only compare the merge changeset against
5149 its first parent. Also, only files different from BOTH parents
5152 its first parent. Also, only files different from BOTH parents
5150 will appear in files:.
5153 will appear in files:.
5151
5154
5152 .. note::
5155 .. note::
5153
5156
5154 For performance reasons, :hg:`log FILE` may omit duplicate changes
5157 For performance reasons, :hg:`log FILE` may omit duplicate changes
5155 made on branches and will not show removals or mode changes. To
5158 made on branches and will not show removals or mode changes. To
5156 see all such changes, use the --removed switch.
5159 see all such changes, use the --removed switch.
5157
5160
5158 .. container:: verbose
5161 .. container:: verbose
5159
5162
5160 Some examples:
5163 Some examples:
5161
5164
5162 - changesets with full descriptions and file lists::
5165 - changesets with full descriptions and file lists::
5163
5166
5164 hg log -v
5167 hg log -v
5165
5168
5166 - changesets ancestral to the working directory::
5169 - changesets ancestral to the working directory::
5167
5170
5168 hg log -f
5171 hg log -f
5169
5172
5170 - last 10 commits on the current branch::
5173 - last 10 commits on the current branch::
5171
5174
5172 hg log -l 10 -b .
5175 hg log -l 10 -b .
5173
5176
5174 - changesets showing all modifications of a file, including removals::
5177 - changesets showing all modifications of a file, including removals::
5175
5178
5176 hg log --removed file.c
5179 hg log --removed file.c
5177
5180
5178 - all changesets that touch a directory, with diffs, excluding merges::
5181 - all changesets that touch a directory, with diffs, excluding merges::
5179
5182
5180 hg log -Mp lib/
5183 hg log -Mp lib/
5181
5184
5182 - all revision numbers that match a keyword::
5185 - all revision numbers that match a keyword::
5183
5186
5184 hg log -k bug --template "{rev}\\n"
5187 hg log -k bug --template "{rev}\\n"
5185
5188
5186 - the full hash identifier of the working directory parent::
5189 - the full hash identifier of the working directory parent::
5187
5190
5188 hg log -r . --template "{node}\\n"
5191 hg log -r . --template "{node}\\n"
5189
5192
5190 - list available log templates::
5193 - list available log templates::
5191
5194
5192 hg log -T list
5195 hg log -T list
5193
5196
5194 - check if a given changeset is included in a tagged release::
5197 - check if a given changeset is included in a tagged release::
5195
5198
5196 hg log -r "a21ccf and ancestor(1.9)"
5199 hg log -r "a21ccf and ancestor(1.9)"
5197
5200
5198 - find all changesets by some user in a date range::
5201 - find all changesets by some user in a date range::
5199
5202
5200 hg log -k alice -d "may 2008 to jul 2008"
5203 hg log -k alice -d "may 2008 to jul 2008"
5201
5204
5202 - summary of all changesets after the last tag::
5205 - summary of all changesets after the last tag::
5203
5206
5204 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5207 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5205
5208
5206 See :hg:`help dates` for a list of formats valid for -d/--date.
5209 See :hg:`help dates` for a list of formats valid for -d/--date.
5207
5210
5208 See :hg:`help revisions` and :hg:`help revsets` for more about
5211 See :hg:`help revisions` and :hg:`help revsets` for more about
5209 specifying and ordering revisions.
5212 specifying and ordering revisions.
5210
5213
5211 See :hg:`help templates` for more about pre-packaged styles and
5214 See :hg:`help templates` for more about pre-packaged styles and
5212 specifying custom templates.
5215 specifying custom templates.
5213
5216
5214 Returns 0 on success.
5217 Returns 0 on success.
5215
5218
5216 """
5219 """
5217 if opts.get('follow') and opts.get('rev'):
5220 if opts.get('follow') and opts.get('rev'):
5218 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5221 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5219 del opts['follow']
5222 del opts['follow']
5220
5223
5221 if opts.get('graph'):
5224 if opts.get('graph'):
5222 return cmdutil.graphlog(ui, repo, *pats, **opts)
5225 return cmdutil.graphlog(ui, repo, *pats, **opts)
5223
5226
5224 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5227 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5225 limit = cmdutil.loglimit(opts)
5228 limit = cmdutil.loglimit(opts)
5226 count = 0
5229 count = 0
5227
5230
5228 getrenamed = None
5231 getrenamed = None
5229 if opts.get('copies'):
5232 if opts.get('copies'):
5230 endrev = None
5233 endrev = None
5231 if opts.get('rev'):
5234 if opts.get('rev'):
5232 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5235 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5233 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5236 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5234
5237
5235 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5238 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5236 for rev in revs:
5239 for rev in revs:
5237 if count == limit:
5240 if count == limit:
5238 break
5241 break
5239 ctx = repo[rev]
5242 ctx = repo[rev]
5240 copies = None
5243 copies = None
5241 if getrenamed is not None and rev:
5244 if getrenamed is not None and rev:
5242 copies = []
5245 copies = []
5243 for fn in ctx.files():
5246 for fn in ctx.files():
5244 rename = getrenamed(fn, rev)
5247 rename = getrenamed(fn, rev)
5245 if rename:
5248 if rename:
5246 copies.append((fn, rename[0]))
5249 copies.append((fn, rename[0]))
5247 if filematcher:
5250 if filematcher:
5248 revmatchfn = filematcher(ctx.rev())
5251 revmatchfn = filematcher(ctx.rev())
5249 else:
5252 else:
5250 revmatchfn = None
5253 revmatchfn = None
5251 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5254 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5252 if displayer.flush(ctx):
5255 if displayer.flush(ctx):
5253 count += 1
5256 count += 1
5254
5257
5255 displayer.close()
5258 displayer.close()
5256
5259
5257 @command('manifest',
5260 @command('manifest',
5258 [('r', 'rev', '', _('revision to display'), _('REV')),
5261 [('r', 'rev', '', _('revision to display'), _('REV')),
5259 ('', 'all', False, _("list files from all revisions"))]
5262 ('', 'all', False, _("list files from all revisions"))]
5260 + formatteropts,
5263 + formatteropts,
5261 _('[-r REV]'))
5264 _('[-r REV]'))
5262 def manifest(ui, repo, node=None, rev=None, **opts):
5265 def manifest(ui, repo, node=None, rev=None, **opts):
5263 """output the current or given revision of the project manifest
5266 """output the current or given revision of the project manifest
5264
5267
5265 Print a list of version controlled files for the given revision.
5268 Print a list of version controlled files for the given revision.
5266 If no revision is given, the first parent of the working directory
5269 If no revision is given, the first parent of the working directory
5267 is used, or the null revision if no revision is checked out.
5270 is used, or the null revision if no revision is checked out.
5268
5271
5269 With -v, print file permissions, symlink and executable bits.
5272 With -v, print file permissions, symlink and executable bits.
5270 With --debug, print file revision hashes.
5273 With --debug, print file revision hashes.
5271
5274
5272 If option --all is specified, the list of all files from all revisions
5275 If option --all is specified, the list of all files from all revisions
5273 is printed. This includes deleted and renamed files.
5276 is printed. This includes deleted and renamed files.
5274
5277
5275 Returns 0 on success.
5278 Returns 0 on success.
5276 """
5279 """
5277
5280
5278 fm = ui.formatter('manifest', opts)
5281 fm = ui.formatter('manifest', opts)
5279
5282
5280 if opts.get('all'):
5283 if opts.get('all'):
5281 if rev or node:
5284 if rev or node:
5282 raise error.Abort(_("can't specify a revision with --all"))
5285 raise error.Abort(_("can't specify a revision with --all"))
5283
5286
5284 res = []
5287 res = []
5285 prefix = "data/"
5288 prefix = "data/"
5286 suffix = ".i"
5289 suffix = ".i"
5287 plen = len(prefix)
5290 plen = len(prefix)
5288 slen = len(suffix)
5291 slen = len(suffix)
5289 with repo.lock():
5292 with repo.lock():
5290 for fn, b, size in repo.store.datafiles():
5293 for fn, b, size in repo.store.datafiles():
5291 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5294 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5292 res.append(fn[plen:-slen])
5295 res.append(fn[plen:-slen])
5293 for f in res:
5296 for f in res:
5294 fm.startitem()
5297 fm.startitem()
5295 fm.write("path", '%s\n', f)
5298 fm.write("path", '%s\n', f)
5296 fm.end()
5299 fm.end()
5297 return
5300 return
5298
5301
5299 if rev and node:
5302 if rev and node:
5300 raise error.Abort(_("please specify just one revision"))
5303 raise error.Abort(_("please specify just one revision"))
5301
5304
5302 if not node:
5305 if not node:
5303 node = rev
5306 node = rev
5304
5307
5305 char = {'l': '@', 'x': '*', '': ''}
5308 char = {'l': '@', 'x': '*', '': ''}
5306 mode = {'l': '644', 'x': '755', '': '644'}
5309 mode = {'l': '644', 'x': '755', '': '644'}
5307 ctx = scmutil.revsingle(repo, node)
5310 ctx = scmutil.revsingle(repo, node)
5308 mf = ctx.manifest()
5311 mf = ctx.manifest()
5309 for f in ctx:
5312 for f in ctx:
5310 fm.startitem()
5313 fm.startitem()
5311 fl = ctx[f].flags()
5314 fl = ctx[f].flags()
5312 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5315 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5313 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5316 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5314 fm.write('path', '%s\n', f)
5317 fm.write('path', '%s\n', f)
5315 fm.end()
5318 fm.end()
5316
5319
5317 @command('^merge',
5320 @command('^merge',
5318 [('f', 'force', None,
5321 [('f', 'force', None,
5319 _('force a merge including outstanding changes (DEPRECATED)')),
5322 _('force a merge including outstanding changes (DEPRECATED)')),
5320 ('r', 'rev', '', _('revision to merge'), _('REV')),
5323 ('r', 'rev', '', _('revision to merge'), _('REV')),
5321 ('P', 'preview', None,
5324 ('P', 'preview', None,
5322 _('review revisions to merge (no merge is performed)'))
5325 _('review revisions to merge (no merge is performed)'))
5323 ] + mergetoolopts,
5326 ] + mergetoolopts,
5324 _('[-P] [[-r] REV]'))
5327 _('[-P] [[-r] REV]'))
5325 def merge(ui, repo, node=None, **opts):
5328 def merge(ui, repo, node=None, **opts):
5326 """merge another revision into working directory
5329 """merge another revision into working directory
5327
5330
5328 The current working directory is updated with all changes made in
5331 The current working directory is updated with all changes made in
5329 the requested revision since the last common predecessor revision.
5332 the requested revision since the last common predecessor revision.
5330
5333
5331 Files that changed between either parent are marked as changed for
5334 Files that changed between either parent are marked as changed for
5332 the next commit and a commit must be performed before any further
5335 the next commit and a commit must be performed before any further
5333 updates to the repository are allowed. The next commit will have
5336 updates to the repository are allowed. The next commit will have
5334 two parents.
5337 two parents.
5335
5338
5336 ``--tool`` can be used to specify the merge tool used for file
5339 ``--tool`` can be used to specify the merge tool used for file
5337 merges. It overrides the HGMERGE environment variable and your
5340 merges. It overrides the HGMERGE environment variable and your
5338 configuration files. See :hg:`help merge-tools` for options.
5341 configuration files. See :hg:`help merge-tools` for options.
5339
5342
5340 If no revision is specified, the working directory's parent is a
5343 If no revision is specified, the working directory's parent is a
5341 head revision, and the current branch contains exactly one other
5344 head revision, and the current branch contains exactly one other
5342 head, the other head is merged with by default. Otherwise, an
5345 head, the other head is merged with by default. Otherwise, an
5343 explicit revision with which to merge with must be provided.
5346 explicit revision with which to merge with must be provided.
5344
5347
5345 See :hg:`help resolve` for information on handling file conflicts.
5348 See :hg:`help resolve` for information on handling file conflicts.
5346
5349
5347 To undo an uncommitted merge, use :hg:`update --clean .` which
5350 To undo an uncommitted merge, use :hg:`update --clean .` which
5348 will check out a clean copy of the original merge parent, losing
5351 will check out a clean copy of the original merge parent, losing
5349 all changes.
5352 all changes.
5350
5353
5351 Returns 0 on success, 1 if there are unresolved files.
5354 Returns 0 on success, 1 if there are unresolved files.
5352 """
5355 """
5353
5356
5354 if opts.get('rev') and node:
5357 if opts.get('rev') and node:
5355 raise error.Abort(_("please specify just one revision"))
5358 raise error.Abort(_("please specify just one revision"))
5356 if not node:
5359 if not node:
5357 node = opts.get('rev')
5360 node = opts.get('rev')
5358
5361
5359 if node:
5362 if node:
5360 node = scmutil.revsingle(repo, node).node()
5363 node = scmutil.revsingle(repo, node).node()
5361
5364
5362 if not node:
5365 if not node:
5363 node = repo[destutil.destmerge(repo)].node()
5366 node = repo[destutil.destmerge(repo)].node()
5364
5367
5365 if opts.get('preview'):
5368 if opts.get('preview'):
5366 # find nodes that are ancestors of p2 but not of p1
5369 # find nodes that are ancestors of p2 but not of p1
5367 p1 = repo.lookup('.')
5370 p1 = repo.lookup('.')
5368 p2 = repo.lookup(node)
5371 p2 = repo.lookup(node)
5369 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5372 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5370
5373
5371 displayer = cmdutil.show_changeset(ui, repo, opts)
5374 displayer = cmdutil.show_changeset(ui, repo, opts)
5372 for node in nodes:
5375 for node in nodes:
5373 displayer.show(repo[node])
5376 displayer.show(repo[node])
5374 displayer.close()
5377 displayer.close()
5375 return 0
5378 return 0
5376
5379
5377 try:
5380 try:
5378 # ui.forcemerge is an internal variable, do not document
5381 # ui.forcemerge is an internal variable, do not document
5379 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5382 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5380 force = opts.get('force')
5383 force = opts.get('force')
5381 return hg.merge(repo, node, force=force, mergeforce=force)
5384 return hg.merge(repo, node, force=force, mergeforce=force)
5382 finally:
5385 finally:
5383 ui.setconfig('ui', 'forcemerge', '', 'merge')
5386 ui.setconfig('ui', 'forcemerge', '', 'merge')
5384
5387
5385 @command('outgoing|out',
5388 @command('outgoing|out',
5386 [('f', 'force', None, _('run even when the destination is unrelated')),
5389 [('f', 'force', None, _('run even when the destination is unrelated')),
5387 ('r', 'rev', [],
5390 ('r', 'rev', [],
5388 _('a changeset intended to be included in the destination'), _('REV')),
5391 _('a changeset intended to be included in the destination'), _('REV')),
5389 ('n', 'newest-first', None, _('show newest record first')),
5392 ('n', 'newest-first', None, _('show newest record first')),
5390 ('B', 'bookmarks', False, _('compare bookmarks')),
5393 ('B', 'bookmarks', False, _('compare bookmarks')),
5391 ('b', 'branch', [], _('a specific branch you would like to push'),
5394 ('b', 'branch', [], _('a specific branch you would like to push'),
5392 _('BRANCH')),
5395 _('BRANCH')),
5393 ] + logopts + remoteopts + subrepoopts,
5396 ] + logopts + remoteopts + subrepoopts,
5394 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5397 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5395 def outgoing(ui, repo, dest=None, **opts):
5398 def outgoing(ui, repo, dest=None, **opts):
5396 """show changesets not found in the destination
5399 """show changesets not found in the destination
5397
5400
5398 Show changesets not found in the specified destination repository
5401 Show changesets not found in the specified destination repository
5399 or the default push location. These are the changesets that would
5402 or the default push location. These are the changesets that would
5400 be pushed if a push was requested.
5403 be pushed if a push was requested.
5401
5404
5402 See pull for details of valid destination formats.
5405 See pull for details of valid destination formats.
5403
5406
5404 .. container:: verbose
5407 .. container:: verbose
5405
5408
5406 With -B/--bookmarks, the result of bookmark comparison between
5409 With -B/--bookmarks, the result of bookmark comparison between
5407 local and remote repositories is displayed. With -v/--verbose,
5410 local and remote repositories is displayed. With -v/--verbose,
5408 status is also displayed for each bookmark like below::
5411 status is also displayed for each bookmark like below::
5409
5412
5410 BM1 01234567890a added
5413 BM1 01234567890a added
5411 BM2 deleted
5414 BM2 deleted
5412 BM3 234567890abc advanced
5415 BM3 234567890abc advanced
5413 BM4 34567890abcd diverged
5416 BM4 34567890abcd diverged
5414 BM5 4567890abcde changed
5417 BM5 4567890abcde changed
5415
5418
5416 The action taken when pushing depends on the
5419 The action taken when pushing depends on the
5417 status of each bookmark:
5420 status of each bookmark:
5418
5421
5419 :``added``: push with ``-B`` will create it
5422 :``added``: push with ``-B`` will create it
5420 :``deleted``: push with ``-B`` will delete it
5423 :``deleted``: push with ``-B`` will delete it
5421 :``advanced``: push will update it
5424 :``advanced``: push will update it
5422 :``diverged``: push with ``-B`` will update it
5425 :``diverged``: push with ``-B`` will update it
5423 :``changed``: push with ``-B`` will update it
5426 :``changed``: push with ``-B`` will update it
5424
5427
5425 From the point of view of pushing behavior, bookmarks
5428 From the point of view of pushing behavior, bookmarks
5426 existing only in the remote repository are treated as
5429 existing only in the remote repository are treated as
5427 ``deleted``, even if it is in fact added remotely.
5430 ``deleted``, even if it is in fact added remotely.
5428
5431
5429 Returns 0 if there are outgoing changes, 1 otherwise.
5432 Returns 0 if there are outgoing changes, 1 otherwise.
5430 """
5433 """
5431 if opts.get('graph'):
5434 if opts.get('graph'):
5432 cmdutil.checkunsupportedgraphflags([], opts)
5435 cmdutil.checkunsupportedgraphflags([], opts)
5433 o, other = hg._outgoing(ui, repo, dest, opts)
5436 o, other = hg._outgoing(ui, repo, dest, opts)
5434 if not o:
5437 if not o:
5435 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5438 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5436 return
5439 return
5437
5440
5438 revdag = cmdutil.graphrevs(repo, o, opts)
5441 revdag = cmdutil.graphrevs(repo, o, opts)
5439 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5442 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5440 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5443 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5441 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5444 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5442 return 0
5445 return 0
5443
5446
5444 if opts.get('bookmarks'):
5447 if opts.get('bookmarks'):
5445 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5448 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5446 dest, branches = hg.parseurl(dest, opts.get('branch'))
5449 dest, branches = hg.parseurl(dest, opts.get('branch'))
5447 other = hg.peer(repo, opts, dest)
5450 other = hg.peer(repo, opts, dest)
5448 if 'bookmarks' not in other.listkeys('namespaces'):
5451 if 'bookmarks' not in other.listkeys('namespaces'):
5449 ui.warn(_("remote doesn't support bookmarks\n"))
5452 ui.warn(_("remote doesn't support bookmarks\n"))
5450 return 0
5453 return 0
5451 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5454 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5452 return bookmarks.outgoing(ui, repo, other)
5455 return bookmarks.outgoing(ui, repo, other)
5453
5456
5454 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5457 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5455 try:
5458 try:
5456 return hg.outgoing(ui, repo, dest, opts)
5459 return hg.outgoing(ui, repo, dest, opts)
5457 finally:
5460 finally:
5458 del repo._subtoppath
5461 del repo._subtoppath
5459
5462
5460 @command('parents',
5463 @command('parents',
5461 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5464 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5462 ] + templateopts,
5465 ] + templateopts,
5463 _('[-r REV] [FILE]'),
5466 _('[-r REV] [FILE]'),
5464 inferrepo=True)
5467 inferrepo=True)
5465 def parents(ui, repo, file_=None, **opts):
5468 def parents(ui, repo, file_=None, **opts):
5466 """show the parents of the working directory or revision (DEPRECATED)
5469 """show the parents of the working directory or revision (DEPRECATED)
5467
5470
5468 Print the working directory's parent revisions. If a revision is
5471 Print the working directory's parent revisions. If a revision is
5469 given via -r/--rev, the parent of that revision will be printed.
5472 given via -r/--rev, the parent of that revision will be printed.
5470 If a file argument is given, the revision in which the file was
5473 If a file argument is given, the revision in which the file was
5471 last changed (before the working directory revision or the
5474 last changed (before the working directory revision or the
5472 argument to --rev if given) is printed.
5475 argument to --rev if given) is printed.
5473
5476
5474 This command is equivalent to::
5477 This command is equivalent to::
5475
5478
5476 hg log -r "p1()+p2()" or
5479 hg log -r "p1()+p2()" or
5477 hg log -r "p1(REV)+p2(REV)" or
5480 hg log -r "p1(REV)+p2(REV)" or
5478 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5481 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5479 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5482 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5480
5483
5481 See :hg:`summary` and :hg:`help revsets` for related information.
5484 See :hg:`summary` and :hg:`help revsets` for related information.
5482
5485
5483 Returns 0 on success.
5486 Returns 0 on success.
5484 """
5487 """
5485
5488
5486 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5489 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5487
5490
5488 if file_:
5491 if file_:
5489 m = scmutil.match(ctx, (file_,), opts)
5492 m = scmutil.match(ctx, (file_,), opts)
5490 if m.anypats() or len(m.files()) != 1:
5493 if m.anypats() or len(m.files()) != 1:
5491 raise error.Abort(_('can only specify an explicit filename'))
5494 raise error.Abort(_('can only specify an explicit filename'))
5492 file_ = m.files()[0]
5495 file_ = m.files()[0]
5493 filenodes = []
5496 filenodes = []
5494 for cp in ctx.parents():
5497 for cp in ctx.parents():
5495 if not cp:
5498 if not cp:
5496 continue
5499 continue
5497 try:
5500 try:
5498 filenodes.append(cp.filenode(file_))
5501 filenodes.append(cp.filenode(file_))
5499 except error.LookupError:
5502 except error.LookupError:
5500 pass
5503 pass
5501 if not filenodes:
5504 if not filenodes:
5502 raise error.Abort(_("'%s' not found in manifest!") % file_)
5505 raise error.Abort(_("'%s' not found in manifest!") % file_)
5503 p = []
5506 p = []
5504 for fn in filenodes:
5507 for fn in filenodes:
5505 fctx = repo.filectx(file_, fileid=fn)
5508 fctx = repo.filectx(file_, fileid=fn)
5506 p.append(fctx.node())
5509 p.append(fctx.node())
5507 else:
5510 else:
5508 p = [cp.node() for cp in ctx.parents()]
5511 p = [cp.node() for cp in ctx.parents()]
5509
5512
5510 displayer = cmdutil.show_changeset(ui, repo, opts)
5513 displayer = cmdutil.show_changeset(ui, repo, opts)
5511 for n in p:
5514 for n in p:
5512 if n != nullid:
5515 if n != nullid:
5513 displayer.show(repo[n])
5516 displayer.show(repo[n])
5514 displayer.close()
5517 displayer.close()
5515
5518
5516 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5519 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5517 def paths(ui, repo, search=None, **opts):
5520 def paths(ui, repo, search=None, **opts):
5518 """show aliases for remote repositories
5521 """show aliases for remote repositories
5519
5522
5520 Show definition of symbolic path name NAME. If no name is given,
5523 Show definition of symbolic path name NAME. If no name is given,
5521 show definition of all available names.
5524 show definition of all available names.
5522
5525
5523 Option -q/--quiet suppresses all output when searching for NAME
5526 Option -q/--quiet suppresses all output when searching for NAME
5524 and shows only the path names when listing all definitions.
5527 and shows only the path names when listing all definitions.
5525
5528
5526 Path names are defined in the [paths] section of your
5529 Path names are defined in the [paths] section of your
5527 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5530 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5528 repository, ``.hg/hgrc`` is used, too.
5531 repository, ``.hg/hgrc`` is used, too.
5529
5532
5530 The path names ``default`` and ``default-push`` have a special
5533 The path names ``default`` and ``default-push`` have a special
5531 meaning. When performing a push or pull operation, they are used
5534 meaning. When performing a push or pull operation, they are used
5532 as fallbacks if no location is specified on the command-line.
5535 as fallbacks if no location is specified on the command-line.
5533 When ``default-push`` is set, it will be used for push and
5536 When ``default-push`` is set, it will be used for push and
5534 ``default`` will be used for pull; otherwise ``default`` is used
5537 ``default`` will be used for pull; otherwise ``default`` is used
5535 as the fallback for both. When cloning a repository, the clone
5538 as the fallback for both. When cloning a repository, the clone
5536 source is written as ``default`` in ``.hg/hgrc``.
5539 source is written as ``default`` in ``.hg/hgrc``.
5537
5540
5538 .. note::
5541 .. note::
5539
5542
5540 ``default`` and ``default-push`` apply to all inbound (e.g.
5543 ``default`` and ``default-push`` apply to all inbound (e.g.
5541 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5544 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5542 and :hg:`bundle`) operations.
5545 and :hg:`bundle`) operations.
5543
5546
5544 See :hg:`help urls` for more information.
5547 See :hg:`help urls` for more information.
5545
5548
5546 Returns 0 on success.
5549 Returns 0 on success.
5547 """
5550 """
5548 if search:
5551 if search:
5549 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5552 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5550 if name == search]
5553 if name == search]
5551 else:
5554 else:
5552 pathitems = sorted(ui.paths.iteritems())
5555 pathitems = sorted(ui.paths.iteritems())
5553
5556
5554 fm = ui.formatter('paths', opts)
5557 fm = ui.formatter('paths', opts)
5555 if fm:
5558 if fm:
5556 hidepassword = str
5559 hidepassword = str
5557 else:
5560 else:
5558 hidepassword = util.hidepassword
5561 hidepassword = util.hidepassword
5559 if ui.quiet:
5562 if ui.quiet:
5560 namefmt = '%s\n'
5563 namefmt = '%s\n'
5561 else:
5564 else:
5562 namefmt = '%s = '
5565 namefmt = '%s = '
5563 showsubopts = not search and not ui.quiet
5566 showsubopts = not search and not ui.quiet
5564
5567
5565 for name, path in pathitems:
5568 for name, path in pathitems:
5566 fm.startitem()
5569 fm.startitem()
5567 fm.condwrite(not search, 'name', namefmt, name)
5570 fm.condwrite(not search, 'name', namefmt, name)
5568 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5571 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5569 for subopt, value in sorted(path.suboptions.items()):
5572 for subopt, value in sorted(path.suboptions.items()):
5570 assert subopt not in ('name', 'url')
5573 assert subopt not in ('name', 'url')
5571 if showsubopts:
5574 if showsubopts:
5572 fm.plain('%s:%s = ' % (name, subopt))
5575 fm.plain('%s:%s = ' % (name, subopt))
5573 fm.condwrite(showsubopts, subopt, '%s\n', value)
5576 fm.condwrite(showsubopts, subopt, '%s\n', value)
5574
5577
5575 fm.end()
5578 fm.end()
5576
5579
5577 if search and not pathitems:
5580 if search and not pathitems:
5578 if not ui.quiet:
5581 if not ui.quiet:
5579 ui.warn(_("not found!\n"))
5582 ui.warn(_("not found!\n"))
5580 return 1
5583 return 1
5581 else:
5584 else:
5582 return 0
5585 return 0
5583
5586
5584 @command('phase',
5587 @command('phase',
5585 [('p', 'public', False, _('set changeset phase to public')),
5588 [('p', 'public', False, _('set changeset phase to public')),
5586 ('d', 'draft', False, _('set changeset phase to draft')),
5589 ('d', 'draft', False, _('set changeset phase to draft')),
5587 ('s', 'secret', False, _('set changeset phase to secret')),
5590 ('s', 'secret', False, _('set changeset phase to secret')),
5588 ('f', 'force', False, _('allow to move boundary backward')),
5591 ('f', 'force', False, _('allow to move boundary backward')),
5589 ('r', 'rev', [], _('target revision'), _('REV')),
5592 ('r', 'rev', [], _('target revision'), _('REV')),
5590 ],
5593 ],
5591 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5594 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5592 def phase(ui, repo, *revs, **opts):
5595 def phase(ui, repo, *revs, **opts):
5593 """set or show the current phase name
5596 """set or show the current phase name
5594
5597
5595 With no argument, show the phase name of the current revision(s).
5598 With no argument, show the phase name of the current revision(s).
5596
5599
5597 With one of -p/--public, -d/--draft or -s/--secret, change the
5600 With one of -p/--public, -d/--draft or -s/--secret, change the
5598 phase value of the specified revisions.
5601 phase value of the specified revisions.
5599
5602
5600 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5603 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5601 lower phase to an higher phase. Phases are ordered as follows::
5604 lower phase to an higher phase. Phases are ordered as follows::
5602
5605
5603 public < draft < secret
5606 public < draft < secret
5604
5607
5605 Returns 0 on success, 1 if some phases could not be changed.
5608 Returns 0 on success, 1 if some phases could not be changed.
5606
5609
5607 (For more information about the phases concept, see :hg:`help phases`.)
5610 (For more information about the phases concept, see :hg:`help phases`.)
5608 """
5611 """
5609 # search for a unique phase argument
5612 # search for a unique phase argument
5610 targetphase = None
5613 targetphase = None
5611 for idx, name in enumerate(phases.phasenames):
5614 for idx, name in enumerate(phases.phasenames):
5612 if opts[name]:
5615 if opts[name]:
5613 if targetphase is not None:
5616 if targetphase is not None:
5614 raise error.Abort(_('only one phase can be specified'))
5617 raise error.Abort(_('only one phase can be specified'))
5615 targetphase = idx
5618 targetphase = idx
5616
5619
5617 # look for specified revision
5620 # look for specified revision
5618 revs = list(revs)
5621 revs = list(revs)
5619 revs.extend(opts['rev'])
5622 revs.extend(opts['rev'])
5620 if not revs:
5623 if not revs:
5621 # display both parents as the second parent phase can influence
5624 # display both parents as the second parent phase can influence
5622 # the phase of a merge commit
5625 # the phase of a merge commit
5623 revs = [c.rev() for c in repo[None].parents()]
5626 revs = [c.rev() for c in repo[None].parents()]
5624
5627
5625 revs = scmutil.revrange(repo, revs)
5628 revs = scmutil.revrange(repo, revs)
5626
5629
5627 lock = None
5630 lock = None
5628 ret = 0
5631 ret = 0
5629 if targetphase is None:
5632 if targetphase is None:
5630 # display
5633 # display
5631 for r in revs:
5634 for r in revs:
5632 ctx = repo[r]
5635 ctx = repo[r]
5633 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5636 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5634 else:
5637 else:
5635 tr = None
5638 tr = None
5636 lock = repo.lock()
5639 lock = repo.lock()
5637 try:
5640 try:
5638 tr = repo.transaction("phase")
5641 tr = repo.transaction("phase")
5639 # set phase
5642 # set phase
5640 if not revs:
5643 if not revs:
5641 raise error.Abort(_('empty revision set'))
5644 raise error.Abort(_('empty revision set'))
5642 nodes = [repo[r].node() for r in revs]
5645 nodes = [repo[r].node() for r in revs]
5643 # moving revision from public to draft may hide them
5646 # moving revision from public to draft may hide them
5644 # We have to check result on an unfiltered repository
5647 # We have to check result on an unfiltered repository
5645 unfi = repo.unfiltered()
5648 unfi = repo.unfiltered()
5646 getphase = unfi._phasecache.phase
5649 getphase = unfi._phasecache.phase
5647 olddata = [getphase(unfi, r) for r in unfi]
5650 olddata = [getphase(unfi, r) for r in unfi]
5648 phases.advanceboundary(repo, tr, targetphase, nodes)
5651 phases.advanceboundary(repo, tr, targetphase, nodes)
5649 if opts['force']:
5652 if opts['force']:
5650 phases.retractboundary(repo, tr, targetphase, nodes)
5653 phases.retractboundary(repo, tr, targetphase, nodes)
5651 tr.close()
5654 tr.close()
5652 finally:
5655 finally:
5653 if tr is not None:
5656 if tr is not None:
5654 tr.release()
5657 tr.release()
5655 lock.release()
5658 lock.release()
5656 getphase = unfi._phasecache.phase
5659 getphase = unfi._phasecache.phase
5657 newdata = [getphase(unfi, r) for r in unfi]
5660 newdata = [getphase(unfi, r) for r in unfi]
5658 changes = sum(newdata[r] != olddata[r] for r in unfi)
5661 changes = sum(newdata[r] != olddata[r] for r in unfi)
5659 cl = unfi.changelog
5662 cl = unfi.changelog
5660 rejected = [n for n in nodes
5663 rejected = [n for n in nodes
5661 if newdata[cl.rev(n)] < targetphase]
5664 if newdata[cl.rev(n)] < targetphase]
5662 if rejected:
5665 if rejected:
5663 ui.warn(_('cannot move %i changesets to a higher '
5666 ui.warn(_('cannot move %i changesets to a higher '
5664 'phase, use --force\n') % len(rejected))
5667 'phase, use --force\n') % len(rejected))
5665 ret = 1
5668 ret = 1
5666 if changes:
5669 if changes:
5667 msg = _('phase changed for %i changesets\n') % changes
5670 msg = _('phase changed for %i changesets\n') % changes
5668 if ret:
5671 if ret:
5669 ui.status(msg)
5672 ui.status(msg)
5670 else:
5673 else:
5671 ui.note(msg)
5674 ui.note(msg)
5672 else:
5675 else:
5673 ui.warn(_('no phases changed\n'))
5676 ui.warn(_('no phases changed\n'))
5674 return ret
5677 return ret
5675
5678
5676 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5679 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5677 """Run after a changegroup has been added via pull/unbundle
5680 """Run after a changegroup has been added via pull/unbundle
5678
5681
5679 This takes arguments below:
5682 This takes arguments below:
5680
5683
5681 :modheads: change of heads by pull/unbundle
5684 :modheads: change of heads by pull/unbundle
5682 :optupdate: updating working directory is needed or not
5685 :optupdate: updating working directory is needed or not
5683 :checkout: update destination revision (or None to default destination)
5686 :checkout: update destination revision (or None to default destination)
5684 :brev: a name, which might be a bookmark to be activated after updating
5687 :brev: a name, which might be a bookmark to be activated after updating
5685 """
5688 """
5686 if modheads == 0:
5689 if modheads == 0:
5687 return
5690 return
5688 if optupdate:
5691 if optupdate:
5689 try:
5692 try:
5690 return hg.updatetotally(ui, repo, checkout, brev)
5693 return hg.updatetotally(ui, repo, checkout, brev)
5691 except error.UpdateAbort as inst:
5694 except error.UpdateAbort as inst:
5692 msg = _("not updating: %s") % str(inst)
5695 msg = _("not updating: %s") % str(inst)
5693 hint = inst.hint
5696 hint = inst.hint
5694 raise error.UpdateAbort(msg, hint=hint)
5697 raise error.UpdateAbort(msg, hint=hint)
5695 if modheads > 1:
5698 if modheads > 1:
5696 currentbranchheads = len(repo.branchheads())
5699 currentbranchheads = len(repo.branchheads())
5697 if currentbranchheads == modheads:
5700 if currentbranchheads == modheads:
5698 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5701 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5699 elif currentbranchheads > 1:
5702 elif currentbranchheads > 1:
5700 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5703 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5701 "merge)\n"))
5704 "merge)\n"))
5702 else:
5705 else:
5703 ui.status(_("(run 'hg heads' to see heads)\n"))
5706 ui.status(_("(run 'hg heads' to see heads)\n"))
5704 else:
5707 else:
5705 ui.status(_("(run 'hg update' to get a working copy)\n"))
5708 ui.status(_("(run 'hg update' to get a working copy)\n"))
5706
5709
5707 @command('^pull',
5710 @command('^pull',
5708 [('u', 'update', None,
5711 [('u', 'update', None,
5709 _('update to new branch head if changesets were pulled')),
5712 _('update to new branch head if changesets were pulled')),
5710 ('f', 'force', None, _('run even when remote repository is unrelated')),
5713 ('f', 'force', None, _('run even when remote repository is unrelated')),
5711 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5714 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5712 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5715 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5713 ('b', 'branch', [], _('a specific branch you would like to pull'),
5716 ('b', 'branch', [], _('a specific branch you would like to pull'),
5714 _('BRANCH')),
5717 _('BRANCH')),
5715 ] + remoteopts,
5718 ] + remoteopts,
5716 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5719 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5717 def pull(ui, repo, source="default", **opts):
5720 def pull(ui, repo, source="default", **opts):
5718 """pull changes from the specified source
5721 """pull changes from the specified source
5719
5722
5720 Pull changes from a remote repository to a local one.
5723 Pull changes from a remote repository to a local one.
5721
5724
5722 This finds all changes from the repository at the specified path
5725 This finds all changes from the repository at the specified path
5723 or URL and adds them to a local repository (the current one unless
5726 or URL and adds them to a local repository (the current one unless
5724 -R is specified). By default, this does not update the copy of the
5727 -R is specified). By default, this does not update the copy of the
5725 project in the working directory.
5728 project in the working directory.
5726
5729
5727 Use :hg:`incoming` if you want to see what would have been added
5730 Use :hg:`incoming` if you want to see what would have been added
5728 by a pull at the time you issued this command. If you then decide
5731 by a pull at the time you issued this command. If you then decide
5729 to add those changes to the repository, you should use :hg:`pull
5732 to add those changes to the repository, you should use :hg:`pull
5730 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5733 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5731
5734
5732 If SOURCE is omitted, the 'default' path will be used.
5735 If SOURCE is omitted, the 'default' path will be used.
5733 See :hg:`help urls` for more information.
5736 See :hg:`help urls` for more information.
5734
5737
5735 Returns 0 on success, 1 if an update had unresolved files.
5738 Returns 0 on success, 1 if an update had unresolved files.
5736 """
5739 """
5737 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5740 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5738 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5741 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5739 other = hg.peer(repo, opts, source)
5742 other = hg.peer(repo, opts, source)
5740 try:
5743 try:
5741 revs, checkout = hg.addbranchrevs(repo, other, branches,
5744 revs, checkout = hg.addbranchrevs(repo, other, branches,
5742 opts.get('rev'))
5745 opts.get('rev'))
5743
5746
5744
5747
5745 pullopargs = {}
5748 pullopargs = {}
5746 if opts.get('bookmark'):
5749 if opts.get('bookmark'):
5747 if not revs:
5750 if not revs:
5748 revs = []
5751 revs = []
5749 # The list of bookmark used here is not the one used to actually
5752 # The list of bookmark used here is not the one used to actually
5750 # update the bookmark name. This can result in the revision pulled
5753 # update the bookmark name. This can result in the revision pulled
5751 # not ending up with the name of the bookmark because of a race
5754 # not ending up with the name of the bookmark because of a race
5752 # condition on the server. (See issue 4689 for details)
5755 # condition on the server. (See issue 4689 for details)
5753 remotebookmarks = other.listkeys('bookmarks')
5756 remotebookmarks = other.listkeys('bookmarks')
5754 pullopargs['remotebookmarks'] = remotebookmarks
5757 pullopargs['remotebookmarks'] = remotebookmarks
5755 for b in opts['bookmark']:
5758 for b in opts['bookmark']:
5756 if b not in remotebookmarks:
5759 if b not in remotebookmarks:
5757 raise error.Abort(_('remote bookmark %s not found!') % b)
5760 raise error.Abort(_('remote bookmark %s not found!') % b)
5758 revs.append(remotebookmarks[b])
5761 revs.append(remotebookmarks[b])
5759
5762
5760 if revs:
5763 if revs:
5761 try:
5764 try:
5762 # When 'rev' is a bookmark name, we cannot guarantee that it
5765 # When 'rev' is a bookmark name, we cannot guarantee that it
5763 # will be updated with that name because of a race condition
5766 # will be updated with that name because of a race condition
5764 # server side. (See issue 4689 for details)
5767 # server side. (See issue 4689 for details)
5765 oldrevs = revs
5768 oldrevs = revs
5766 revs = [] # actually, nodes
5769 revs = [] # actually, nodes
5767 for r in oldrevs:
5770 for r in oldrevs:
5768 node = other.lookup(r)
5771 node = other.lookup(r)
5769 revs.append(node)
5772 revs.append(node)
5770 if r == checkout:
5773 if r == checkout:
5771 checkout = node
5774 checkout = node
5772 except error.CapabilityError:
5775 except error.CapabilityError:
5773 err = _("other repository doesn't support revision lookup, "
5776 err = _("other repository doesn't support revision lookup, "
5774 "so a rev cannot be specified.")
5777 "so a rev cannot be specified.")
5775 raise error.Abort(err)
5778 raise error.Abort(err)
5776
5779
5777 pullopargs.update(opts.get('opargs', {}))
5780 pullopargs.update(opts.get('opargs', {}))
5778 modheads = exchange.pull(repo, other, heads=revs,
5781 modheads = exchange.pull(repo, other, heads=revs,
5779 force=opts.get('force'),
5782 force=opts.get('force'),
5780 bookmarks=opts.get('bookmark', ()),
5783 bookmarks=opts.get('bookmark', ()),
5781 opargs=pullopargs).cgresult
5784 opargs=pullopargs).cgresult
5782
5785
5783 # brev is a name, which might be a bookmark to be activated at
5786 # brev is a name, which might be a bookmark to be activated at
5784 # the end of the update. In other words, it is an explicit
5787 # the end of the update. In other words, it is an explicit
5785 # destination of the update
5788 # destination of the update
5786 brev = None
5789 brev = None
5787
5790
5788 if checkout:
5791 if checkout:
5789 checkout = str(repo.changelog.rev(checkout))
5792 checkout = str(repo.changelog.rev(checkout))
5790
5793
5791 # order below depends on implementation of
5794 # order below depends on implementation of
5792 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5795 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5793 # because 'checkout' is determined without it.
5796 # because 'checkout' is determined without it.
5794 if opts.get('rev'):
5797 if opts.get('rev'):
5795 brev = opts['rev'][0]
5798 brev = opts['rev'][0]
5796 elif opts.get('branch'):
5799 elif opts.get('branch'):
5797 brev = opts['branch'][0]
5800 brev = opts['branch'][0]
5798 else:
5801 else:
5799 brev = branches[0]
5802 brev = branches[0]
5800 repo._subtoppath = source
5803 repo._subtoppath = source
5801 try:
5804 try:
5802 ret = postincoming(ui, repo, modheads, opts.get('update'),
5805 ret = postincoming(ui, repo, modheads, opts.get('update'),
5803 checkout, brev)
5806 checkout, brev)
5804
5807
5805 finally:
5808 finally:
5806 del repo._subtoppath
5809 del repo._subtoppath
5807
5810
5808 finally:
5811 finally:
5809 other.close()
5812 other.close()
5810 return ret
5813 return ret
5811
5814
5812 @command('^push',
5815 @command('^push',
5813 [('f', 'force', None, _('force push')),
5816 [('f', 'force', None, _('force push')),
5814 ('r', 'rev', [],
5817 ('r', 'rev', [],
5815 _('a changeset intended to be included in the destination'),
5818 _('a changeset intended to be included in the destination'),
5816 _('REV')),
5819 _('REV')),
5817 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5820 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5818 ('b', 'branch', [],
5821 ('b', 'branch', [],
5819 _('a specific branch you would like to push'), _('BRANCH')),
5822 _('a specific branch you would like to push'), _('BRANCH')),
5820 ('', 'new-branch', False, _('allow pushing a new branch')),
5823 ('', 'new-branch', False, _('allow pushing a new branch')),
5821 ] + remoteopts,
5824 ] + remoteopts,
5822 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5825 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5823 def push(ui, repo, dest=None, **opts):
5826 def push(ui, repo, dest=None, **opts):
5824 """push changes to the specified destination
5827 """push changes to the specified destination
5825
5828
5826 Push changesets from the local repository to the specified
5829 Push changesets from the local repository to the specified
5827 destination.
5830 destination.
5828
5831
5829 This operation is symmetrical to pull: it is identical to a pull
5832 This operation is symmetrical to pull: it is identical to a pull
5830 in the destination repository from the current one.
5833 in the destination repository from the current one.
5831
5834
5832 By default, push will not allow creation of new heads at the
5835 By default, push will not allow creation of new heads at the
5833 destination, since multiple heads would make it unclear which head
5836 destination, since multiple heads would make it unclear which head
5834 to use. In this situation, it is recommended to pull and merge
5837 to use. In this situation, it is recommended to pull and merge
5835 before pushing.
5838 before pushing.
5836
5839
5837 Use --new-branch if you want to allow push to create a new named
5840 Use --new-branch if you want to allow push to create a new named
5838 branch that is not present at the destination. This allows you to
5841 branch that is not present at the destination. This allows you to
5839 only create a new branch without forcing other changes.
5842 only create a new branch without forcing other changes.
5840
5843
5841 .. note::
5844 .. note::
5842
5845
5843 Extra care should be taken with the -f/--force option,
5846 Extra care should be taken with the -f/--force option,
5844 which will push all new heads on all branches, an action which will
5847 which will push all new heads on all branches, an action which will
5845 almost always cause confusion for collaborators.
5848 almost always cause confusion for collaborators.
5846
5849
5847 If -r/--rev is used, the specified revision and all its ancestors
5850 If -r/--rev is used, the specified revision and all its ancestors
5848 will be pushed to the remote repository.
5851 will be pushed to the remote repository.
5849
5852
5850 If -B/--bookmark is used, the specified bookmarked revision, its
5853 If -B/--bookmark is used, the specified bookmarked revision, its
5851 ancestors, and the bookmark will be pushed to the remote
5854 ancestors, and the bookmark will be pushed to the remote
5852 repository. Specifying ``.`` is equivalent to specifying the active
5855 repository. Specifying ``.`` is equivalent to specifying the active
5853 bookmark's name.
5856 bookmark's name.
5854
5857
5855 Please see :hg:`help urls` for important details about ``ssh://``
5858 Please see :hg:`help urls` for important details about ``ssh://``
5856 URLs. If DESTINATION is omitted, a default path will be used.
5859 URLs. If DESTINATION is omitted, a default path will be used.
5857
5860
5858 Returns 0 if push was successful, 1 if nothing to push.
5861 Returns 0 if push was successful, 1 if nothing to push.
5859 """
5862 """
5860
5863
5861 if opts.get('bookmark'):
5864 if opts.get('bookmark'):
5862 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5865 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5863 for b in opts['bookmark']:
5866 for b in opts['bookmark']:
5864 # translate -B options to -r so changesets get pushed
5867 # translate -B options to -r so changesets get pushed
5865 b = repo._bookmarks.expandname(b)
5868 b = repo._bookmarks.expandname(b)
5866 if b in repo._bookmarks:
5869 if b in repo._bookmarks:
5867 opts.setdefault('rev', []).append(b)
5870 opts.setdefault('rev', []).append(b)
5868 else:
5871 else:
5869 # if we try to push a deleted bookmark, translate it to null
5872 # if we try to push a deleted bookmark, translate it to null
5870 # this lets simultaneous -r, -b options continue working
5873 # this lets simultaneous -r, -b options continue working
5871 opts.setdefault('rev', []).append("null")
5874 opts.setdefault('rev', []).append("null")
5872
5875
5873 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5876 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5874 if not path:
5877 if not path:
5875 raise error.Abort(_('default repository not configured!'),
5878 raise error.Abort(_('default repository not configured!'),
5876 hint=_('see the "path" section in "hg help config"'))
5879 hint=_('see the "path" section in "hg help config"'))
5877 dest = path.pushloc or path.loc
5880 dest = path.pushloc or path.loc
5878 branches = (path.branch, opts.get('branch') or [])
5881 branches = (path.branch, opts.get('branch') or [])
5879 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5882 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5880 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5883 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5881 other = hg.peer(repo, opts, dest)
5884 other = hg.peer(repo, opts, dest)
5882
5885
5883 if revs:
5886 if revs:
5884 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5887 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5885 if not revs:
5888 if not revs:
5886 raise error.Abort(_("specified revisions evaluate to an empty set"),
5889 raise error.Abort(_("specified revisions evaluate to an empty set"),
5887 hint=_("use different revision arguments"))
5890 hint=_("use different revision arguments"))
5888
5891
5889 repo._subtoppath = dest
5892 repo._subtoppath = dest
5890 try:
5893 try:
5891 # push subrepos depth-first for coherent ordering
5894 # push subrepos depth-first for coherent ordering
5892 c = repo['']
5895 c = repo['']
5893 subs = c.substate # only repos that are committed
5896 subs = c.substate # only repos that are committed
5894 for s in sorted(subs):
5897 for s in sorted(subs):
5895 result = c.sub(s).push(opts)
5898 result = c.sub(s).push(opts)
5896 if result == 0:
5899 if result == 0:
5897 return not result
5900 return not result
5898 finally:
5901 finally:
5899 del repo._subtoppath
5902 del repo._subtoppath
5900 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5903 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5901 newbranch=opts.get('new_branch'),
5904 newbranch=opts.get('new_branch'),
5902 bookmarks=opts.get('bookmark', ()),
5905 bookmarks=opts.get('bookmark', ()),
5903 opargs=opts.get('opargs'))
5906 opargs=opts.get('opargs'))
5904
5907
5905 result = not pushop.cgresult
5908 result = not pushop.cgresult
5906
5909
5907 if pushop.bkresult is not None:
5910 if pushop.bkresult is not None:
5908 if pushop.bkresult == 2:
5911 if pushop.bkresult == 2:
5909 result = 2
5912 result = 2
5910 elif not result and pushop.bkresult:
5913 elif not result and pushop.bkresult:
5911 result = 2
5914 result = 2
5912
5915
5913 return result
5916 return result
5914
5917
5915 @command('recover', [])
5918 @command('recover', [])
5916 def recover(ui, repo):
5919 def recover(ui, repo):
5917 """roll back an interrupted transaction
5920 """roll back an interrupted transaction
5918
5921
5919 Recover from an interrupted commit or pull.
5922 Recover from an interrupted commit or pull.
5920
5923
5921 This command tries to fix the repository status after an
5924 This command tries to fix the repository status after an
5922 interrupted operation. It should only be necessary when Mercurial
5925 interrupted operation. It should only be necessary when Mercurial
5923 suggests it.
5926 suggests it.
5924
5927
5925 Returns 0 if successful, 1 if nothing to recover or verify fails.
5928 Returns 0 if successful, 1 if nothing to recover or verify fails.
5926 """
5929 """
5927 if repo.recover():
5930 if repo.recover():
5928 return hg.verify(repo)
5931 return hg.verify(repo)
5929 return 1
5932 return 1
5930
5933
5931 @command('^remove|rm',
5934 @command('^remove|rm',
5932 [('A', 'after', None, _('record delete for missing files')),
5935 [('A', 'after', None, _('record delete for missing files')),
5933 ('f', 'force', None,
5936 ('f', 'force', None,
5934 _('remove (and delete) file even if added or modified')),
5937 _('remove (and delete) file even if added or modified')),
5935 ] + subrepoopts + walkopts,
5938 ] + subrepoopts + walkopts,
5936 _('[OPTION]... FILE...'),
5939 _('[OPTION]... FILE...'),
5937 inferrepo=True)
5940 inferrepo=True)
5938 def remove(ui, repo, *pats, **opts):
5941 def remove(ui, repo, *pats, **opts):
5939 """remove the specified files on the next commit
5942 """remove the specified files on the next commit
5940
5943
5941 Schedule the indicated files for removal from the current branch.
5944 Schedule the indicated files for removal from the current branch.
5942
5945
5943 This command schedules the files to be removed at the next commit.
5946 This command schedules the files to be removed at the next commit.
5944 To undo a remove before that, see :hg:`revert`. To undo added
5947 To undo a remove before that, see :hg:`revert`. To undo added
5945 files, see :hg:`forget`.
5948 files, see :hg:`forget`.
5946
5949
5947 .. container:: verbose
5950 .. container:: verbose
5948
5951
5949 -A/--after can be used to remove only files that have already
5952 -A/--after can be used to remove only files that have already
5950 been deleted, -f/--force can be used to force deletion, and -Af
5953 been deleted, -f/--force can be used to force deletion, and -Af
5951 can be used to remove files from the next revision without
5954 can be used to remove files from the next revision without
5952 deleting them from the working directory.
5955 deleting them from the working directory.
5953
5956
5954 The following table details the behavior of remove for different
5957 The following table details the behavior of remove for different
5955 file states (columns) and option combinations (rows). The file
5958 file states (columns) and option combinations (rows). The file
5956 states are Added [A], Clean [C], Modified [M] and Missing [!]
5959 states are Added [A], Clean [C], Modified [M] and Missing [!]
5957 (as reported by :hg:`status`). The actions are Warn, Remove
5960 (as reported by :hg:`status`). The actions are Warn, Remove
5958 (from branch) and Delete (from disk):
5961 (from branch) and Delete (from disk):
5959
5962
5960 ========= == == == ==
5963 ========= == == == ==
5961 opt/state A C M !
5964 opt/state A C M !
5962 ========= == == == ==
5965 ========= == == == ==
5963 none W RD W R
5966 none W RD W R
5964 -f R RD RD R
5967 -f R RD RD R
5965 -A W W W R
5968 -A W W W R
5966 -Af R R R R
5969 -Af R R R R
5967 ========= == == == ==
5970 ========= == == == ==
5968
5971
5969 .. note::
5972 .. note::
5970
5973
5971 :hg:`remove` never deletes files in Added [A] state from the
5974 :hg:`remove` never deletes files in Added [A] state from the
5972 working directory, not even if ``--force`` is specified.
5975 working directory, not even if ``--force`` is specified.
5973
5976
5974 Returns 0 on success, 1 if any warnings encountered.
5977 Returns 0 on success, 1 if any warnings encountered.
5975 """
5978 """
5976
5979
5977 after, force = opts.get('after'), opts.get('force')
5980 after, force = opts.get('after'), opts.get('force')
5978 if not pats and not after:
5981 if not pats and not after:
5979 raise error.Abort(_('no files specified'))
5982 raise error.Abort(_('no files specified'))
5980
5983
5981 m = scmutil.match(repo[None], pats, opts)
5984 m = scmutil.match(repo[None], pats, opts)
5982 subrepos = opts.get('subrepos')
5985 subrepos = opts.get('subrepos')
5983 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5986 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5984
5987
5985 @command('rename|move|mv',
5988 @command('rename|move|mv',
5986 [('A', 'after', None, _('record a rename that has already occurred')),
5989 [('A', 'after', None, _('record a rename that has already occurred')),
5987 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5990 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5988 ] + walkopts + dryrunopts,
5991 ] + walkopts + dryrunopts,
5989 _('[OPTION]... SOURCE... DEST'))
5992 _('[OPTION]... SOURCE... DEST'))
5990 def rename(ui, repo, *pats, **opts):
5993 def rename(ui, repo, *pats, **opts):
5991 """rename files; equivalent of copy + remove
5994 """rename files; equivalent of copy + remove
5992
5995
5993 Mark dest as copies of sources; mark sources for deletion. If dest
5996 Mark dest as copies of sources; mark sources for deletion. If dest
5994 is a directory, copies are put in that directory. If dest is a
5997 is a directory, copies are put in that directory. If dest is a
5995 file, there can only be one source.
5998 file, there can only be one source.
5996
5999
5997 By default, this command copies the contents of files as they
6000 By default, this command copies the contents of files as they
5998 exist in the working directory. If invoked with -A/--after, the
6001 exist in the working directory. If invoked with -A/--after, the
5999 operation is recorded, but no copying is performed.
6002 operation is recorded, but no copying is performed.
6000
6003
6001 This command takes effect at the next commit. To undo a rename
6004 This command takes effect at the next commit. To undo a rename
6002 before that, see :hg:`revert`.
6005 before that, see :hg:`revert`.
6003
6006
6004 Returns 0 on success, 1 if errors are encountered.
6007 Returns 0 on success, 1 if errors are encountered.
6005 """
6008 """
6006 with repo.wlock(False):
6009 with repo.wlock(False):
6007 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6010 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6008
6011
6009 @command('resolve',
6012 @command('resolve',
6010 [('a', 'all', None, _('select all unresolved files')),
6013 [('a', 'all', None, _('select all unresolved files')),
6011 ('l', 'list', None, _('list state of files needing merge')),
6014 ('l', 'list', None, _('list state of files needing merge')),
6012 ('m', 'mark', None, _('mark files as resolved')),
6015 ('m', 'mark', None, _('mark files as resolved')),
6013 ('u', 'unmark', None, _('mark files as unresolved')),
6016 ('u', 'unmark', None, _('mark files as unresolved')),
6014 ('n', 'no-status', None, _('hide status prefix'))]
6017 ('n', 'no-status', None, _('hide status prefix'))]
6015 + mergetoolopts + walkopts + formatteropts,
6018 + mergetoolopts + walkopts + formatteropts,
6016 _('[OPTION]... [FILE]...'),
6019 _('[OPTION]... [FILE]...'),
6017 inferrepo=True)
6020 inferrepo=True)
6018 def resolve(ui, repo, *pats, **opts):
6021 def resolve(ui, repo, *pats, **opts):
6019 """redo merges or set/view the merge status of files
6022 """redo merges or set/view the merge status of files
6020
6023
6021 Merges with unresolved conflicts are often the result of
6024 Merges with unresolved conflicts are often the result of
6022 non-interactive merging using the ``internal:merge`` configuration
6025 non-interactive merging using the ``internal:merge`` configuration
6023 setting, or a command-line merge tool like ``diff3``. The resolve
6026 setting, or a command-line merge tool like ``diff3``. The resolve
6024 command is used to manage the files involved in a merge, after
6027 command is used to manage the files involved in a merge, after
6025 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6028 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6026 working directory must have two parents). See :hg:`help
6029 working directory must have two parents). See :hg:`help
6027 merge-tools` for information on configuring merge tools.
6030 merge-tools` for information on configuring merge tools.
6028
6031
6029 The resolve command can be used in the following ways:
6032 The resolve command can be used in the following ways:
6030
6033
6031 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6034 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6032 files, discarding any previous merge attempts. Re-merging is not
6035 files, discarding any previous merge attempts. Re-merging is not
6033 performed for files already marked as resolved. Use ``--all/-a``
6036 performed for files already marked as resolved. Use ``--all/-a``
6034 to select all unresolved files. ``--tool`` can be used to specify
6037 to select all unresolved files. ``--tool`` can be used to specify
6035 the merge tool used for the given files. It overrides the HGMERGE
6038 the merge tool used for the given files. It overrides the HGMERGE
6036 environment variable and your configuration files. Previous file
6039 environment variable and your configuration files. Previous file
6037 contents are saved with a ``.orig`` suffix.
6040 contents are saved with a ``.orig`` suffix.
6038
6041
6039 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6042 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6040 (e.g. after having manually fixed-up the files). The default is
6043 (e.g. after having manually fixed-up the files). The default is
6041 to mark all unresolved files.
6044 to mark all unresolved files.
6042
6045
6043 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6046 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6044 default is to mark all resolved files.
6047 default is to mark all resolved files.
6045
6048
6046 - :hg:`resolve -l`: list files which had or still have conflicts.
6049 - :hg:`resolve -l`: list files which had or still have conflicts.
6047 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6050 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6048
6051
6049 .. note::
6052 .. note::
6050
6053
6051 Mercurial will not let you commit files with unresolved merge
6054 Mercurial will not let you commit files with unresolved merge
6052 conflicts. You must use :hg:`resolve -m ...` before you can
6055 conflicts. You must use :hg:`resolve -m ...` before you can
6053 commit after a conflicting merge.
6056 commit after a conflicting merge.
6054
6057
6055 Returns 0 on success, 1 if any files fail a resolve attempt.
6058 Returns 0 on success, 1 if any files fail a resolve attempt.
6056 """
6059 """
6057
6060
6058 flaglist = 'all mark unmark list no_status'.split()
6061 flaglist = 'all mark unmark list no_status'.split()
6059 all, mark, unmark, show, nostatus = \
6062 all, mark, unmark, show, nostatus = \
6060 [opts.get(o) for o in flaglist]
6063 [opts.get(o) for o in flaglist]
6061
6064
6062 if (show and (mark or unmark)) or (mark and unmark):
6065 if (show and (mark or unmark)) or (mark and unmark):
6063 raise error.Abort(_("too many options specified"))
6066 raise error.Abort(_("too many options specified"))
6064 if pats and all:
6067 if pats and all:
6065 raise error.Abort(_("can't specify --all and patterns"))
6068 raise error.Abort(_("can't specify --all and patterns"))
6066 if not (all or pats or show or mark or unmark):
6069 if not (all or pats or show or mark or unmark):
6067 raise error.Abort(_('no files or directories specified'),
6070 raise error.Abort(_('no files or directories specified'),
6068 hint=('use --all to re-merge all unresolved files'))
6071 hint=('use --all to re-merge all unresolved files'))
6069
6072
6070 if show:
6073 if show:
6071 fm = ui.formatter('resolve', opts)
6074 fm = ui.formatter('resolve', opts)
6072 ms = mergemod.mergestate.read(repo)
6075 ms = mergemod.mergestate.read(repo)
6073 m = scmutil.match(repo[None], pats, opts)
6076 m = scmutil.match(repo[None], pats, opts)
6074 for f in ms:
6077 for f in ms:
6075 if not m(f):
6078 if not m(f):
6076 continue
6079 continue
6077 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6080 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6078 'd': 'driverresolved'}[ms[f]]
6081 'd': 'driverresolved'}[ms[f]]
6079 fm.startitem()
6082 fm.startitem()
6080 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6083 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6081 fm.write('path', '%s\n', f, label=l)
6084 fm.write('path', '%s\n', f, label=l)
6082 fm.end()
6085 fm.end()
6083 return 0
6086 return 0
6084
6087
6085 with repo.wlock():
6088 with repo.wlock():
6086 ms = mergemod.mergestate.read(repo)
6089 ms = mergemod.mergestate.read(repo)
6087
6090
6088 if not (ms.active() or repo.dirstate.p2() != nullid):
6091 if not (ms.active() or repo.dirstate.p2() != nullid):
6089 raise error.Abort(
6092 raise error.Abort(
6090 _('resolve command not applicable when not merging'))
6093 _('resolve command not applicable when not merging'))
6091
6094
6092 wctx = repo[None]
6095 wctx = repo[None]
6093
6096
6094 if ms.mergedriver and ms.mdstate() == 'u':
6097 if ms.mergedriver and ms.mdstate() == 'u':
6095 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6098 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6096 ms.commit()
6099 ms.commit()
6097 # allow mark and unmark to go through
6100 # allow mark and unmark to go through
6098 if not mark and not unmark and not proceed:
6101 if not mark and not unmark and not proceed:
6099 return 1
6102 return 1
6100
6103
6101 m = scmutil.match(wctx, pats, opts)
6104 m = scmutil.match(wctx, pats, opts)
6102 ret = 0
6105 ret = 0
6103 didwork = False
6106 didwork = False
6104 runconclude = False
6107 runconclude = False
6105
6108
6106 tocomplete = []
6109 tocomplete = []
6107 for f in ms:
6110 for f in ms:
6108 if not m(f):
6111 if not m(f):
6109 continue
6112 continue
6110
6113
6111 didwork = True
6114 didwork = True
6112
6115
6113 # don't let driver-resolved files be marked, and run the conclude
6116 # don't let driver-resolved files be marked, and run the conclude
6114 # step if asked to resolve
6117 # step if asked to resolve
6115 if ms[f] == "d":
6118 if ms[f] == "d":
6116 exact = m.exact(f)
6119 exact = m.exact(f)
6117 if mark:
6120 if mark:
6118 if exact:
6121 if exact:
6119 ui.warn(_('not marking %s as it is driver-resolved\n')
6122 ui.warn(_('not marking %s as it is driver-resolved\n')
6120 % f)
6123 % f)
6121 elif unmark:
6124 elif unmark:
6122 if exact:
6125 if exact:
6123 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6126 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6124 % f)
6127 % f)
6125 else:
6128 else:
6126 runconclude = True
6129 runconclude = True
6127 continue
6130 continue
6128
6131
6129 if mark:
6132 if mark:
6130 ms.mark(f, "r")
6133 ms.mark(f, "r")
6131 elif unmark:
6134 elif unmark:
6132 ms.mark(f, "u")
6135 ms.mark(f, "u")
6133 else:
6136 else:
6134 # backup pre-resolve (merge uses .orig for its own purposes)
6137 # backup pre-resolve (merge uses .orig for its own purposes)
6135 a = repo.wjoin(f)
6138 a = repo.wjoin(f)
6136 try:
6139 try:
6137 util.copyfile(a, a + ".resolve")
6140 util.copyfile(a, a + ".resolve")
6138 except (IOError, OSError) as inst:
6141 except (IOError, OSError) as inst:
6139 if inst.errno != errno.ENOENT:
6142 if inst.errno != errno.ENOENT:
6140 raise
6143 raise
6141
6144
6142 try:
6145 try:
6143 # preresolve file
6146 # preresolve file
6144 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6147 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6145 'resolve')
6148 'resolve')
6146 complete, r = ms.preresolve(f, wctx)
6149 complete, r = ms.preresolve(f, wctx)
6147 if not complete:
6150 if not complete:
6148 tocomplete.append(f)
6151 tocomplete.append(f)
6149 elif r:
6152 elif r:
6150 ret = 1
6153 ret = 1
6151 finally:
6154 finally:
6152 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6155 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6153 ms.commit()
6156 ms.commit()
6154
6157
6155 # replace filemerge's .orig file with our resolve file, but only
6158 # replace filemerge's .orig file with our resolve file, but only
6156 # for merges that are complete
6159 # for merges that are complete
6157 if complete:
6160 if complete:
6158 try:
6161 try:
6159 util.rename(a + ".resolve",
6162 util.rename(a + ".resolve",
6160 scmutil.origpath(ui, repo, a))
6163 scmutil.origpath(ui, repo, a))
6161 except OSError as inst:
6164 except OSError as inst:
6162 if inst.errno != errno.ENOENT:
6165 if inst.errno != errno.ENOENT:
6163 raise
6166 raise
6164
6167
6165 for f in tocomplete:
6168 for f in tocomplete:
6166 try:
6169 try:
6167 # resolve file
6170 # resolve file
6168 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6171 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6169 'resolve')
6172 'resolve')
6170 r = ms.resolve(f, wctx)
6173 r = ms.resolve(f, wctx)
6171 if r:
6174 if r:
6172 ret = 1
6175 ret = 1
6173 finally:
6176 finally:
6174 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6177 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6175 ms.commit()
6178 ms.commit()
6176
6179
6177 # replace filemerge's .orig file with our resolve file
6180 # replace filemerge's .orig file with our resolve file
6178 a = repo.wjoin(f)
6181 a = repo.wjoin(f)
6179 try:
6182 try:
6180 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6183 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6181 except OSError as inst:
6184 except OSError as inst:
6182 if inst.errno != errno.ENOENT:
6185 if inst.errno != errno.ENOENT:
6183 raise
6186 raise
6184
6187
6185 ms.commit()
6188 ms.commit()
6186 ms.recordactions()
6189 ms.recordactions()
6187
6190
6188 if not didwork and pats:
6191 if not didwork and pats:
6189 hint = None
6192 hint = None
6190 if not any([p for p in pats if p.find(':') >= 0]):
6193 if not any([p for p in pats if p.find(':') >= 0]):
6191 pats = ['path:%s' % p for p in pats]
6194 pats = ['path:%s' % p for p in pats]
6192 m = scmutil.match(wctx, pats, opts)
6195 m = scmutil.match(wctx, pats, opts)
6193 for f in ms:
6196 for f in ms:
6194 if not m(f):
6197 if not m(f):
6195 continue
6198 continue
6196 flags = ''.join(['-%s ' % o[0] for o in flaglist
6199 flags = ''.join(['-%s ' % o[0] for o in flaglist
6197 if opts.get(o)])
6200 if opts.get(o)])
6198 hint = _("(try: hg resolve %s%s)\n") % (
6201 hint = _("(try: hg resolve %s%s)\n") % (
6199 flags,
6202 flags,
6200 ' '.join(pats))
6203 ' '.join(pats))
6201 break
6204 break
6202 ui.warn(_("arguments do not match paths that need resolving\n"))
6205 ui.warn(_("arguments do not match paths that need resolving\n"))
6203 if hint:
6206 if hint:
6204 ui.warn(hint)
6207 ui.warn(hint)
6205 elif ms.mergedriver and ms.mdstate() != 's':
6208 elif ms.mergedriver and ms.mdstate() != 's':
6206 # run conclude step when either a driver-resolved file is requested
6209 # run conclude step when either a driver-resolved file is requested
6207 # or there are no driver-resolved files
6210 # or there are no driver-resolved files
6208 # we can't use 'ret' to determine whether any files are unresolved
6211 # we can't use 'ret' to determine whether any files are unresolved
6209 # because we might not have tried to resolve some
6212 # because we might not have tried to resolve some
6210 if ((runconclude or not list(ms.driverresolved()))
6213 if ((runconclude or not list(ms.driverresolved()))
6211 and not list(ms.unresolved())):
6214 and not list(ms.unresolved())):
6212 proceed = mergemod.driverconclude(repo, ms, wctx)
6215 proceed = mergemod.driverconclude(repo, ms, wctx)
6213 ms.commit()
6216 ms.commit()
6214 if not proceed:
6217 if not proceed:
6215 return 1
6218 return 1
6216
6219
6217 # Nudge users into finishing an unfinished operation
6220 # Nudge users into finishing an unfinished operation
6218 unresolvedf = list(ms.unresolved())
6221 unresolvedf = list(ms.unresolved())
6219 driverresolvedf = list(ms.driverresolved())
6222 driverresolvedf = list(ms.driverresolved())
6220 if not unresolvedf and not driverresolvedf:
6223 if not unresolvedf and not driverresolvedf:
6221 ui.status(_('(no more unresolved files)\n'))
6224 ui.status(_('(no more unresolved files)\n'))
6222 cmdutil.checkafterresolved(repo)
6225 cmdutil.checkafterresolved(repo)
6223 elif not unresolvedf:
6226 elif not unresolvedf:
6224 ui.status(_('(no more unresolved files -- '
6227 ui.status(_('(no more unresolved files -- '
6225 'run "hg resolve --all" to conclude)\n'))
6228 'run "hg resolve --all" to conclude)\n'))
6226
6229
6227 return ret
6230 return ret
6228
6231
6229 @command('revert',
6232 @command('revert',
6230 [('a', 'all', None, _('revert all changes when no arguments given')),
6233 [('a', 'all', None, _('revert all changes when no arguments given')),
6231 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6234 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6232 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6235 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6233 ('C', 'no-backup', None, _('do not save backup copies of files')),
6236 ('C', 'no-backup', None, _('do not save backup copies of files')),
6234 ('i', 'interactive', None,
6237 ('i', 'interactive', None,
6235 _('interactively select the changes (EXPERIMENTAL)')),
6238 _('interactively select the changes (EXPERIMENTAL)')),
6236 ] + walkopts + dryrunopts,
6239 ] + walkopts + dryrunopts,
6237 _('[OPTION]... [-r REV] [NAME]...'))
6240 _('[OPTION]... [-r REV] [NAME]...'))
6238 def revert(ui, repo, *pats, **opts):
6241 def revert(ui, repo, *pats, **opts):
6239 """restore files to their checkout state
6242 """restore files to their checkout state
6240
6243
6241 .. note::
6244 .. note::
6242
6245
6243 To check out earlier revisions, you should use :hg:`update REV`.
6246 To check out earlier revisions, you should use :hg:`update REV`.
6244 To cancel an uncommitted merge (and lose your changes),
6247 To cancel an uncommitted merge (and lose your changes),
6245 use :hg:`update --clean .`.
6248 use :hg:`update --clean .`.
6246
6249
6247 With no revision specified, revert the specified files or directories
6250 With no revision specified, revert the specified files or directories
6248 to the contents they had in the parent of the working directory.
6251 to the contents they had in the parent of the working directory.
6249 This restores the contents of files to an unmodified
6252 This restores the contents of files to an unmodified
6250 state and unschedules adds, removes, copies, and renames. If the
6253 state and unschedules adds, removes, copies, and renames. If the
6251 working directory has two parents, you must explicitly specify a
6254 working directory has two parents, you must explicitly specify a
6252 revision.
6255 revision.
6253
6256
6254 Using the -r/--rev or -d/--date options, revert the given files or
6257 Using the -r/--rev or -d/--date options, revert the given files or
6255 directories to their states as of a specific revision. Because
6258 directories to their states as of a specific revision. Because
6256 revert does not change the working directory parents, this will
6259 revert does not change the working directory parents, this will
6257 cause these files to appear modified. This can be helpful to "back
6260 cause these files to appear modified. This can be helpful to "back
6258 out" some or all of an earlier change. See :hg:`backout` for a
6261 out" some or all of an earlier change. See :hg:`backout` for a
6259 related method.
6262 related method.
6260
6263
6261 Modified files are saved with a .orig suffix before reverting.
6264 Modified files are saved with a .orig suffix before reverting.
6262 To disable these backups, use --no-backup.
6265 To disable these backups, use --no-backup.
6263
6266
6264 See :hg:`help dates` for a list of formats valid for -d/--date.
6267 See :hg:`help dates` for a list of formats valid for -d/--date.
6265
6268
6266 See :hg:`help backout` for a way to reverse the effect of an
6269 See :hg:`help backout` for a way to reverse the effect of an
6267 earlier changeset.
6270 earlier changeset.
6268
6271
6269 Returns 0 on success.
6272 Returns 0 on success.
6270 """
6273 """
6271
6274
6272 if opts.get("date"):
6275 if opts.get("date"):
6273 if opts.get("rev"):
6276 if opts.get("rev"):
6274 raise error.Abort(_("you can't specify a revision and a date"))
6277 raise error.Abort(_("you can't specify a revision and a date"))
6275 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6278 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6276
6279
6277 parent, p2 = repo.dirstate.parents()
6280 parent, p2 = repo.dirstate.parents()
6278 if not opts.get('rev') and p2 != nullid:
6281 if not opts.get('rev') and p2 != nullid:
6279 # revert after merge is a trap for new users (issue2915)
6282 # revert after merge is a trap for new users (issue2915)
6280 raise error.Abort(_('uncommitted merge with no revision specified'),
6283 raise error.Abort(_('uncommitted merge with no revision specified'),
6281 hint=_('use "hg update" or see "hg help revert"'))
6284 hint=_('use "hg update" or see "hg help revert"'))
6282
6285
6283 ctx = scmutil.revsingle(repo, opts.get('rev'))
6286 ctx = scmutil.revsingle(repo, opts.get('rev'))
6284
6287
6285 if (not (pats or opts.get('include') or opts.get('exclude') or
6288 if (not (pats or opts.get('include') or opts.get('exclude') or
6286 opts.get('all') or opts.get('interactive'))):
6289 opts.get('all') or opts.get('interactive'))):
6287 msg = _("no files or directories specified")
6290 msg = _("no files or directories specified")
6288 if p2 != nullid:
6291 if p2 != nullid:
6289 hint = _("uncommitted merge, use --all to discard all changes,"
6292 hint = _("uncommitted merge, use --all to discard all changes,"
6290 " or 'hg update -C .' to abort the merge")
6293 " or 'hg update -C .' to abort the merge")
6291 raise error.Abort(msg, hint=hint)
6294 raise error.Abort(msg, hint=hint)
6292 dirty = any(repo.status())
6295 dirty = any(repo.status())
6293 node = ctx.node()
6296 node = ctx.node()
6294 if node != parent:
6297 if node != parent:
6295 if dirty:
6298 if dirty:
6296 hint = _("uncommitted changes, use --all to discard all"
6299 hint = _("uncommitted changes, use --all to discard all"
6297 " changes, or 'hg update %s' to update") % ctx.rev()
6300 " changes, or 'hg update %s' to update") % ctx.rev()
6298 else:
6301 else:
6299 hint = _("use --all to revert all files,"
6302 hint = _("use --all to revert all files,"
6300 " or 'hg update %s' to update") % ctx.rev()
6303 " or 'hg update %s' to update") % ctx.rev()
6301 elif dirty:
6304 elif dirty:
6302 hint = _("uncommitted changes, use --all to discard all changes")
6305 hint = _("uncommitted changes, use --all to discard all changes")
6303 else:
6306 else:
6304 hint = _("use --all to revert all files")
6307 hint = _("use --all to revert all files")
6305 raise error.Abort(msg, hint=hint)
6308 raise error.Abort(msg, hint=hint)
6306
6309
6307 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6310 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6308
6311
6309 @command('rollback', dryrunopts +
6312 @command('rollback', dryrunopts +
6310 [('f', 'force', False, _('ignore safety measures'))])
6313 [('f', 'force', False, _('ignore safety measures'))])
6311 def rollback(ui, repo, **opts):
6314 def rollback(ui, repo, **opts):
6312 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6315 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6313
6316
6314 Please use :hg:`commit --amend` instead of rollback to correct
6317 Please use :hg:`commit --amend` instead of rollback to correct
6315 mistakes in the last commit.
6318 mistakes in the last commit.
6316
6319
6317 This command should be used with care. There is only one level of
6320 This command should be used with care. There is only one level of
6318 rollback, and there is no way to undo a rollback. It will also
6321 rollback, and there is no way to undo a rollback. It will also
6319 restore the dirstate at the time of the last transaction, losing
6322 restore the dirstate at the time of the last transaction, losing
6320 any dirstate changes since that time. This command does not alter
6323 any dirstate changes since that time. This command does not alter
6321 the working directory.
6324 the working directory.
6322
6325
6323 Transactions are used to encapsulate the effects of all commands
6326 Transactions are used to encapsulate the effects of all commands
6324 that create new changesets or propagate existing changesets into a
6327 that create new changesets or propagate existing changesets into a
6325 repository.
6328 repository.
6326
6329
6327 .. container:: verbose
6330 .. container:: verbose
6328
6331
6329 For example, the following commands are transactional, and their
6332 For example, the following commands are transactional, and their
6330 effects can be rolled back:
6333 effects can be rolled back:
6331
6334
6332 - commit
6335 - commit
6333 - import
6336 - import
6334 - pull
6337 - pull
6335 - push (with this repository as the destination)
6338 - push (with this repository as the destination)
6336 - unbundle
6339 - unbundle
6337
6340
6338 To avoid permanent data loss, rollback will refuse to rollback a
6341 To avoid permanent data loss, rollback will refuse to rollback a
6339 commit transaction if it isn't checked out. Use --force to
6342 commit transaction if it isn't checked out. Use --force to
6340 override this protection.
6343 override this protection.
6341
6344
6342 This command is not intended for use on public repositories. Once
6345 This command is not intended for use on public repositories. Once
6343 changes are visible for pull by other users, rolling a transaction
6346 changes are visible for pull by other users, rolling a transaction
6344 back locally is ineffective (someone else may already have pulled
6347 back locally is ineffective (someone else may already have pulled
6345 the changes). Furthermore, a race is possible with readers of the
6348 the changes). Furthermore, a race is possible with readers of the
6346 repository; for example an in-progress pull from the repository
6349 repository; for example an in-progress pull from the repository
6347 may fail if a rollback is performed.
6350 may fail if a rollback is performed.
6348
6351
6349 Returns 0 on success, 1 if no rollback data is available.
6352 Returns 0 on success, 1 if no rollback data is available.
6350 """
6353 """
6351 return repo.rollback(dryrun=opts.get('dry_run'),
6354 return repo.rollback(dryrun=opts.get('dry_run'),
6352 force=opts.get('force'))
6355 force=opts.get('force'))
6353
6356
6354 @command('root', [])
6357 @command('root', [])
6355 def root(ui, repo):
6358 def root(ui, repo):
6356 """print the root (top) of the current working directory
6359 """print the root (top) of the current working directory
6357
6360
6358 Print the root directory of the current repository.
6361 Print the root directory of the current repository.
6359
6362
6360 Returns 0 on success.
6363 Returns 0 on success.
6361 """
6364 """
6362 ui.write(repo.root + "\n")
6365 ui.write(repo.root + "\n")
6363
6366
6364 @command('^serve',
6367 @command('^serve',
6365 [('A', 'accesslog', '', _('name of access log file to write to'),
6368 [('A', 'accesslog', '', _('name of access log file to write to'),
6366 _('FILE')),
6369 _('FILE')),
6367 ('d', 'daemon', None, _('run server in background')),
6370 ('d', 'daemon', None, _('run server in background')),
6368 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6371 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6369 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6372 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6370 # use string type, then we can check if something was passed
6373 # use string type, then we can check if something was passed
6371 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6374 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6372 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6375 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6373 _('ADDR')),
6376 _('ADDR')),
6374 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6377 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6375 _('PREFIX')),
6378 _('PREFIX')),
6376 ('n', 'name', '',
6379 ('n', 'name', '',
6377 _('name to show in web pages (default: working directory)'), _('NAME')),
6380 _('name to show in web pages (default: working directory)'), _('NAME')),
6378 ('', 'web-conf', '',
6381 ('', 'web-conf', '',
6379 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6382 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6380 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6383 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6381 _('FILE')),
6384 _('FILE')),
6382 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6385 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6383 ('', 'stdio', None, _('for remote clients')),
6386 ('', 'stdio', None, _('for remote clients')),
6384 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6387 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6385 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6388 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6386 ('', 'style', '', _('template style to use'), _('STYLE')),
6389 ('', 'style', '', _('template style to use'), _('STYLE')),
6387 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6390 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6388 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6391 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6389 _('[OPTION]...'),
6392 _('[OPTION]...'),
6390 optionalrepo=True)
6393 optionalrepo=True)
6391 def serve(ui, repo, **opts):
6394 def serve(ui, repo, **opts):
6392 """start stand-alone webserver
6395 """start stand-alone webserver
6393
6396
6394 Start a local HTTP repository browser and pull server. You can use
6397 Start a local HTTP repository browser and pull server. You can use
6395 this for ad-hoc sharing and browsing of repositories. It is
6398 this for ad-hoc sharing and browsing of repositories. It is
6396 recommended to use a real web server to serve a repository for
6399 recommended to use a real web server to serve a repository for
6397 longer periods of time.
6400 longer periods of time.
6398
6401
6399 Please note that the server does not implement access control.
6402 Please note that the server does not implement access control.
6400 This means that, by default, anybody can read from the server and
6403 This means that, by default, anybody can read from the server and
6401 nobody can write to it by default. Set the ``web.allow_push``
6404 nobody can write to it by default. Set the ``web.allow_push``
6402 option to ``*`` to allow everybody to push to the server. You
6405 option to ``*`` to allow everybody to push to the server. You
6403 should use a real web server if you need to authenticate users.
6406 should use a real web server if you need to authenticate users.
6404
6407
6405 By default, the server logs accesses to stdout and errors to
6408 By default, the server logs accesses to stdout and errors to
6406 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6409 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6407 files.
6410 files.
6408
6411
6409 To have the server choose a free port number to listen on, specify
6412 To have the server choose a free port number to listen on, specify
6410 a port number of 0; in this case, the server will print the port
6413 a port number of 0; in this case, the server will print the port
6411 number it uses.
6414 number it uses.
6412
6415
6413 Returns 0 on success.
6416 Returns 0 on success.
6414 """
6417 """
6415
6418
6416 if opts["stdio"] and opts["cmdserver"]:
6419 if opts["stdio"] and opts["cmdserver"]:
6417 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6420 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6418
6421
6419 if opts["stdio"]:
6422 if opts["stdio"]:
6420 if repo is None:
6423 if repo is None:
6421 raise error.RepoError(_("there is no Mercurial repository here"
6424 raise error.RepoError(_("there is no Mercurial repository here"
6422 " (.hg not found)"))
6425 " (.hg not found)"))
6423 s = sshserver.sshserver(ui, repo)
6426 s = sshserver.sshserver(ui, repo)
6424 s.serve_forever()
6427 s.serve_forever()
6425
6428
6426 if opts["cmdserver"]:
6429 if opts["cmdserver"]:
6427 service = commandserver.createservice(ui, repo, opts)
6430 service = commandserver.createservice(ui, repo, opts)
6428 else:
6431 else:
6429 service = hgweb.createservice(ui, repo, opts)
6432 service = hgweb.createservice(ui, repo, opts)
6430 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6433 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6431
6434
6432 @command('^status|st',
6435 @command('^status|st',
6433 [('A', 'all', None, _('show status of all files')),
6436 [('A', 'all', None, _('show status of all files')),
6434 ('m', 'modified', None, _('show only modified files')),
6437 ('m', 'modified', None, _('show only modified files')),
6435 ('a', 'added', None, _('show only added files')),
6438 ('a', 'added', None, _('show only added files')),
6436 ('r', 'removed', None, _('show only removed files')),
6439 ('r', 'removed', None, _('show only removed files')),
6437 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6440 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6438 ('c', 'clean', None, _('show only files without changes')),
6441 ('c', 'clean', None, _('show only files without changes')),
6439 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6442 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6440 ('i', 'ignored', None, _('show only ignored files')),
6443 ('i', 'ignored', None, _('show only ignored files')),
6441 ('n', 'no-status', None, _('hide status prefix')),
6444 ('n', 'no-status', None, _('hide status prefix')),
6442 ('C', 'copies', None, _('show source of copied files')),
6445 ('C', 'copies', None, _('show source of copied files')),
6443 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6446 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6444 ('', 'rev', [], _('show difference from revision'), _('REV')),
6447 ('', 'rev', [], _('show difference from revision'), _('REV')),
6445 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6448 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6446 ] + walkopts + subrepoopts + formatteropts,
6449 ] + walkopts + subrepoopts + formatteropts,
6447 _('[OPTION]... [FILE]...'),
6450 _('[OPTION]... [FILE]...'),
6448 inferrepo=True)
6451 inferrepo=True)
6449 def status(ui, repo, *pats, **opts):
6452 def status(ui, repo, *pats, **opts):
6450 """show changed files in the working directory
6453 """show changed files in the working directory
6451
6454
6452 Show status of files in the repository. If names are given, only
6455 Show status of files in the repository. If names are given, only
6453 files that match are shown. Files that are clean or ignored or
6456 files that match are shown. Files that are clean or ignored or
6454 the source of a copy/move operation, are not listed unless
6457 the source of a copy/move operation, are not listed unless
6455 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6458 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6456 Unless options described with "show only ..." are given, the
6459 Unless options described with "show only ..." are given, the
6457 options -mardu are used.
6460 options -mardu are used.
6458
6461
6459 Option -q/--quiet hides untracked (unknown and ignored) files
6462 Option -q/--quiet hides untracked (unknown and ignored) files
6460 unless explicitly requested with -u/--unknown or -i/--ignored.
6463 unless explicitly requested with -u/--unknown or -i/--ignored.
6461
6464
6462 .. note::
6465 .. note::
6463
6466
6464 :hg:`status` may appear to disagree with diff if permissions have
6467 :hg:`status` may appear to disagree with diff if permissions have
6465 changed or a merge has occurred. The standard diff format does
6468 changed or a merge has occurred. The standard diff format does
6466 not report permission changes and diff only reports changes
6469 not report permission changes and diff only reports changes
6467 relative to one merge parent.
6470 relative to one merge parent.
6468
6471
6469 If one revision is given, it is used as the base revision.
6472 If one revision is given, it is used as the base revision.
6470 If two revisions are given, the differences between them are
6473 If two revisions are given, the differences between them are
6471 shown. The --change option can also be used as a shortcut to list
6474 shown. The --change option can also be used as a shortcut to list
6472 the changed files of a revision from its first parent.
6475 the changed files of a revision from its first parent.
6473
6476
6474 The codes used to show the status of files are::
6477 The codes used to show the status of files are::
6475
6478
6476 M = modified
6479 M = modified
6477 A = added
6480 A = added
6478 R = removed
6481 R = removed
6479 C = clean
6482 C = clean
6480 ! = missing (deleted by non-hg command, but still tracked)
6483 ! = missing (deleted by non-hg command, but still tracked)
6481 ? = not tracked
6484 ? = not tracked
6482 I = ignored
6485 I = ignored
6483 = origin of the previous file (with --copies)
6486 = origin of the previous file (with --copies)
6484
6487
6485 .. container:: verbose
6488 .. container:: verbose
6486
6489
6487 Examples:
6490 Examples:
6488
6491
6489 - show changes in the working directory relative to a
6492 - show changes in the working directory relative to a
6490 changeset::
6493 changeset::
6491
6494
6492 hg status --rev 9353
6495 hg status --rev 9353
6493
6496
6494 - show changes in the working directory relative to the
6497 - show changes in the working directory relative to the
6495 current directory (see :hg:`help patterns` for more information)::
6498 current directory (see :hg:`help patterns` for more information)::
6496
6499
6497 hg status re:
6500 hg status re:
6498
6501
6499 - show all changes including copies in an existing changeset::
6502 - show all changes including copies in an existing changeset::
6500
6503
6501 hg status --copies --change 9353
6504 hg status --copies --change 9353
6502
6505
6503 - get a NUL separated list of added files, suitable for xargs::
6506 - get a NUL separated list of added files, suitable for xargs::
6504
6507
6505 hg status -an0
6508 hg status -an0
6506
6509
6507 Returns 0 on success.
6510 Returns 0 on success.
6508 """
6511 """
6509
6512
6510 revs = opts.get('rev')
6513 revs = opts.get('rev')
6511 change = opts.get('change')
6514 change = opts.get('change')
6512
6515
6513 if revs and change:
6516 if revs and change:
6514 msg = _('cannot specify --rev and --change at the same time')
6517 msg = _('cannot specify --rev and --change at the same time')
6515 raise error.Abort(msg)
6518 raise error.Abort(msg)
6516 elif change:
6519 elif change:
6517 node2 = scmutil.revsingle(repo, change, None).node()
6520 node2 = scmutil.revsingle(repo, change, None).node()
6518 node1 = repo[node2].p1().node()
6521 node1 = repo[node2].p1().node()
6519 else:
6522 else:
6520 node1, node2 = scmutil.revpair(repo, revs)
6523 node1, node2 = scmutil.revpair(repo, revs)
6521
6524
6522 if pats:
6525 if pats:
6523 cwd = repo.getcwd()
6526 cwd = repo.getcwd()
6524 else:
6527 else:
6525 cwd = ''
6528 cwd = ''
6526
6529
6527 if opts.get('print0'):
6530 if opts.get('print0'):
6528 end = '\0'
6531 end = '\0'
6529 else:
6532 else:
6530 end = '\n'
6533 end = '\n'
6531 copy = {}
6534 copy = {}
6532 states = 'modified added removed deleted unknown ignored clean'.split()
6535 states = 'modified added removed deleted unknown ignored clean'.split()
6533 show = [k for k in states if opts.get(k)]
6536 show = [k for k in states if opts.get(k)]
6534 if opts.get('all'):
6537 if opts.get('all'):
6535 show += ui.quiet and (states[:4] + ['clean']) or states
6538 show += ui.quiet and (states[:4] + ['clean']) or states
6536 if not show:
6539 if not show:
6537 if ui.quiet:
6540 if ui.quiet:
6538 show = states[:4]
6541 show = states[:4]
6539 else:
6542 else:
6540 show = states[:5]
6543 show = states[:5]
6541
6544
6542 m = scmutil.match(repo[node2], pats, opts)
6545 m = scmutil.match(repo[node2], pats, opts)
6543 stat = repo.status(node1, node2, m,
6546 stat = repo.status(node1, node2, m,
6544 'ignored' in show, 'clean' in show, 'unknown' in show,
6547 'ignored' in show, 'clean' in show, 'unknown' in show,
6545 opts.get('subrepos'))
6548 opts.get('subrepos'))
6546 changestates = zip(states, 'MAR!?IC', stat)
6549 changestates = zip(states, 'MAR!?IC', stat)
6547
6550
6548 if (opts.get('all') or opts.get('copies')
6551 if (opts.get('all') or opts.get('copies')
6549 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6552 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6550 copy = copies.pathcopies(repo[node1], repo[node2], m)
6553 copy = copies.pathcopies(repo[node1], repo[node2], m)
6551
6554
6552 fm = ui.formatter('status', opts)
6555 fm = ui.formatter('status', opts)
6553 fmt = '%s' + end
6556 fmt = '%s' + end
6554 showchar = not opts.get('no_status')
6557 showchar = not opts.get('no_status')
6555
6558
6556 for state, char, files in changestates:
6559 for state, char, files in changestates:
6557 if state in show:
6560 if state in show:
6558 label = 'status.' + state
6561 label = 'status.' + state
6559 for f in files:
6562 for f in files:
6560 fm.startitem()
6563 fm.startitem()
6561 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6564 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6562 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6565 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6563 if f in copy:
6566 if f in copy:
6564 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6567 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6565 label='status.copied')
6568 label='status.copied')
6566 fm.end()
6569 fm.end()
6567
6570
6568 @command('^summary|sum',
6571 @command('^summary|sum',
6569 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6572 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6570 def summary(ui, repo, **opts):
6573 def summary(ui, repo, **opts):
6571 """summarize working directory state
6574 """summarize working directory state
6572
6575
6573 This generates a brief summary of the working directory state,
6576 This generates a brief summary of the working directory state,
6574 including parents, branch, commit status, phase and available updates.
6577 including parents, branch, commit status, phase and available updates.
6575
6578
6576 With the --remote option, this will check the default paths for
6579 With the --remote option, this will check the default paths for
6577 incoming and outgoing changes. This can be time-consuming.
6580 incoming and outgoing changes. This can be time-consuming.
6578
6581
6579 Returns 0 on success.
6582 Returns 0 on success.
6580 """
6583 """
6581
6584
6582 ctx = repo[None]
6585 ctx = repo[None]
6583 parents = ctx.parents()
6586 parents = ctx.parents()
6584 pnode = parents[0].node()
6587 pnode = parents[0].node()
6585 marks = []
6588 marks = []
6586
6589
6587 ms = None
6590 ms = None
6588 try:
6591 try:
6589 ms = mergemod.mergestate.read(repo)
6592 ms = mergemod.mergestate.read(repo)
6590 except error.UnsupportedMergeRecords as e:
6593 except error.UnsupportedMergeRecords as e:
6591 s = ' '.join(e.recordtypes)
6594 s = ' '.join(e.recordtypes)
6592 ui.warn(
6595 ui.warn(
6593 _('warning: merge state has unsupported record types: %s\n') % s)
6596 _('warning: merge state has unsupported record types: %s\n') % s)
6594 unresolved = 0
6597 unresolved = 0
6595 else:
6598 else:
6596 unresolved = [f for f in ms if ms[f] == 'u']
6599 unresolved = [f for f in ms if ms[f] == 'u']
6597
6600
6598 for p in parents:
6601 for p in parents:
6599 # label with log.changeset (instead of log.parent) since this
6602 # label with log.changeset (instead of log.parent) since this
6600 # shows a working directory parent *changeset*:
6603 # shows a working directory parent *changeset*:
6601 # i18n: column positioning for "hg summary"
6604 # i18n: column positioning for "hg summary"
6602 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6605 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6603 label='log.changeset changeset.%s' % p.phasestr())
6606 label='log.changeset changeset.%s' % p.phasestr())
6604 ui.write(' '.join(p.tags()), label='log.tag')
6607 ui.write(' '.join(p.tags()), label='log.tag')
6605 if p.bookmarks():
6608 if p.bookmarks():
6606 marks.extend(p.bookmarks())
6609 marks.extend(p.bookmarks())
6607 if p.rev() == -1:
6610 if p.rev() == -1:
6608 if not len(repo):
6611 if not len(repo):
6609 ui.write(_(' (empty repository)'))
6612 ui.write(_(' (empty repository)'))
6610 else:
6613 else:
6611 ui.write(_(' (no revision checked out)'))
6614 ui.write(_(' (no revision checked out)'))
6612 ui.write('\n')
6615 ui.write('\n')
6613 if p.description():
6616 if p.description():
6614 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6617 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6615 label='log.summary')
6618 label='log.summary')
6616
6619
6617 branch = ctx.branch()
6620 branch = ctx.branch()
6618 bheads = repo.branchheads(branch)
6621 bheads = repo.branchheads(branch)
6619 # i18n: column positioning for "hg summary"
6622 # i18n: column positioning for "hg summary"
6620 m = _('branch: %s\n') % branch
6623 m = _('branch: %s\n') % branch
6621 if branch != 'default':
6624 if branch != 'default':
6622 ui.write(m, label='log.branch')
6625 ui.write(m, label='log.branch')
6623 else:
6626 else:
6624 ui.status(m, label='log.branch')
6627 ui.status(m, label='log.branch')
6625
6628
6626 if marks:
6629 if marks:
6627 active = repo._activebookmark
6630 active = repo._activebookmark
6628 # i18n: column positioning for "hg summary"
6631 # i18n: column positioning for "hg summary"
6629 ui.write(_('bookmarks:'), label='log.bookmark')
6632 ui.write(_('bookmarks:'), label='log.bookmark')
6630 if active is not None:
6633 if active is not None:
6631 if active in marks:
6634 if active in marks:
6632 ui.write(' *' + active, label=activebookmarklabel)
6635 ui.write(' *' + active, label=activebookmarklabel)
6633 marks.remove(active)
6636 marks.remove(active)
6634 else:
6637 else:
6635 ui.write(' [%s]' % active, label=activebookmarklabel)
6638 ui.write(' [%s]' % active, label=activebookmarklabel)
6636 for m in marks:
6639 for m in marks:
6637 ui.write(' ' + m, label='log.bookmark')
6640 ui.write(' ' + m, label='log.bookmark')
6638 ui.write('\n', label='log.bookmark')
6641 ui.write('\n', label='log.bookmark')
6639
6642
6640 status = repo.status(unknown=True)
6643 status = repo.status(unknown=True)
6641
6644
6642 c = repo.dirstate.copies()
6645 c = repo.dirstate.copies()
6643 copied, renamed = [], []
6646 copied, renamed = [], []
6644 for d, s in c.iteritems():
6647 for d, s in c.iteritems():
6645 if s in status.removed:
6648 if s in status.removed:
6646 status.removed.remove(s)
6649 status.removed.remove(s)
6647 renamed.append(d)
6650 renamed.append(d)
6648 else:
6651 else:
6649 copied.append(d)
6652 copied.append(d)
6650 if d in status.added:
6653 if d in status.added:
6651 status.added.remove(d)
6654 status.added.remove(d)
6652
6655
6653 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6656 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6654
6657
6655 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6658 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6656 (ui.label(_('%d added'), 'status.added'), status.added),
6659 (ui.label(_('%d added'), 'status.added'), status.added),
6657 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6660 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6658 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6661 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6659 (ui.label(_('%d copied'), 'status.copied'), copied),
6662 (ui.label(_('%d copied'), 'status.copied'), copied),
6660 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6663 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6661 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6664 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6662 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6665 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6663 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6666 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6664 t = []
6667 t = []
6665 for l, s in labels:
6668 for l, s in labels:
6666 if s:
6669 if s:
6667 t.append(l % len(s))
6670 t.append(l % len(s))
6668
6671
6669 t = ', '.join(t)
6672 t = ', '.join(t)
6670 cleanworkdir = False
6673 cleanworkdir = False
6671
6674
6672 if repo.vfs.exists('graftstate'):
6675 if repo.vfs.exists('graftstate'):
6673 t += _(' (graft in progress)')
6676 t += _(' (graft in progress)')
6674 if repo.vfs.exists('updatestate'):
6677 if repo.vfs.exists('updatestate'):
6675 t += _(' (interrupted update)')
6678 t += _(' (interrupted update)')
6676 elif len(parents) > 1:
6679 elif len(parents) > 1:
6677 t += _(' (merge)')
6680 t += _(' (merge)')
6678 elif branch != parents[0].branch():
6681 elif branch != parents[0].branch():
6679 t += _(' (new branch)')
6682 t += _(' (new branch)')
6680 elif (parents[0].closesbranch() and
6683 elif (parents[0].closesbranch() and
6681 pnode in repo.branchheads(branch, closed=True)):
6684 pnode in repo.branchheads(branch, closed=True)):
6682 t += _(' (head closed)')
6685 t += _(' (head closed)')
6683 elif not (status.modified or status.added or status.removed or renamed or
6686 elif not (status.modified or status.added or status.removed or renamed or
6684 copied or subs):
6687 copied or subs):
6685 t += _(' (clean)')
6688 t += _(' (clean)')
6686 cleanworkdir = True
6689 cleanworkdir = True
6687 elif pnode not in bheads:
6690 elif pnode not in bheads:
6688 t += _(' (new branch head)')
6691 t += _(' (new branch head)')
6689
6692
6690 if parents:
6693 if parents:
6691 pendingphase = max(p.phase() for p in parents)
6694 pendingphase = max(p.phase() for p in parents)
6692 else:
6695 else:
6693 pendingphase = phases.public
6696 pendingphase = phases.public
6694
6697
6695 if pendingphase > phases.newcommitphase(ui):
6698 if pendingphase > phases.newcommitphase(ui):
6696 t += ' (%s)' % phases.phasenames[pendingphase]
6699 t += ' (%s)' % phases.phasenames[pendingphase]
6697
6700
6698 if cleanworkdir:
6701 if cleanworkdir:
6699 # i18n: column positioning for "hg summary"
6702 # i18n: column positioning for "hg summary"
6700 ui.status(_('commit: %s\n') % t.strip())
6703 ui.status(_('commit: %s\n') % t.strip())
6701 else:
6704 else:
6702 # i18n: column positioning for "hg summary"
6705 # i18n: column positioning for "hg summary"
6703 ui.write(_('commit: %s\n') % t.strip())
6706 ui.write(_('commit: %s\n') % t.strip())
6704
6707
6705 # all ancestors of branch heads - all ancestors of parent = new csets
6708 # all ancestors of branch heads - all ancestors of parent = new csets
6706 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6709 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6707 bheads))
6710 bheads))
6708
6711
6709 if new == 0:
6712 if new == 0:
6710 # i18n: column positioning for "hg summary"
6713 # i18n: column positioning for "hg summary"
6711 ui.status(_('update: (current)\n'))
6714 ui.status(_('update: (current)\n'))
6712 elif pnode not in bheads:
6715 elif pnode not in bheads:
6713 # i18n: column positioning for "hg summary"
6716 # i18n: column positioning for "hg summary"
6714 ui.write(_('update: %d new changesets (update)\n') % new)
6717 ui.write(_('update: %d new changesets (update)\n') % new)
6715 else:
6718 else:
6716 # i18n: column positioning for "hg summary"
6719 # i18n: column positioning for "hg summary"
6717 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6720 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6718 (new, len(bheads)))
6721 (new, len(bheads)))
6719
6722
6720 t = []
6723 t = []
6721 draft = len(repo.revs('draft()'))
6724 draft = len(repo.revs('draft()'))
6722 if draft:
6725 if draft:
6723 t.append(_('%d draft') % draft)
6726 t.append(_('%d draft') % draft)
6724 secret = len(repo.revs('secret()'))
6727 secret = len(repo.revs('secret()'))
6725 if secret:
6728 if secret:
6726 t.append(_('%d secret') % secret)
6729 t.append(_('%d secret') % secret)
6727
6730
6728 if draft or secret:
6731 if draft or secret:
6729 ui.status(_('phases: %s\n') % ', '.join(t))
6732 ui.status(_('phases: %s\n') % ', '.join(t))
6730
6733
6731 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6734 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6732 for trouble in ("unstable", "divergent", "bumped"):
6735 for trouble in ("unstable", "divergent", "bumped"):
6733 numtrouble = len(repo.revs(trouble + "()"))
6736 numtrouble = len(repo.revs(trouble + "()"))
6734 # We write all the possibilities to ease translation
6737 # We write all the possibilities to ease translation
6735 troublemsg = {
6738 troublemsg = {
6736 "unstable": _("unstable: %d changesets"),
6739 "unstable": _("unstable: %d changesets"),
6737 "divergent": _("divergent: %d changesets"),
6740 "divergent": _("divergent: %d changesets"),
6738 "bumped": _("bumped: %d changesets"),
6741 "bumped": _("bumped: %d changesets"),
6739 }
6742 }
6740 if numtrouble > 0:
6743 if numtrouble > 0:
6741 ui.status(troublemsg[trouble] % numtrouble + "\n")
6744 ui.status(troublemsg[trouble] % numtrouble + "\n")
6742
6745
6743 cmdutil.summaryhooks(ui, repo)
6746 cmdutil.summaryhooks(ui, repo)
6744
6747
6745 if opts.get('remote'):
6748 if opts.get('remote'):
6746 needsincoming, needsoutgoing = True, True
6749 needsincoming, needsoutgoing = True, True
6747 else:
6750 else:
6748 needsincoming, needsoutgoing = False, False
6751 needsincoming, needsoutgoing = False, False
6749 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6752 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6750 if i:
6753 if i:
6751 needsincoming = True
6754 needsincoming = True
6752 if o:
6755 if o:
6753 needsoutgoing = True
6756 needsoutgoing = True
6754 if not needsincoming and not needsoutgoing:
6757 if not needsincoming and not needsoutgoing:
6755 return
6758 return
6756
6759
6757 def getincoming():
6760 def getincoming():
6758 source, branches = hg.parseurl(ui.expandpath('default'))
6761 source, branches = hg.parseurl(ui.expandpath('default'))
6759 sbranch = branches[0]
6762 sbranch = branches[0]
6760 try:
6763 try:
6761 other = hg.peer(repo, {}, source)
6764 other = hg.peer(repo, {}, source)
6762 except error.RepoError:
6765 except error.RepoError:
6763 if opts.get('remote'):
6766 if opts.get('remote'):
6764 raise
6767 raise
6765 return source, sbranch, None, None, None
6768 return source, sbranch, None, None, None
6766 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6769 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6767 if revs:
6770 if revs:
6768 revs = [other.lookup(rev) for rev in revs]
6771 revs = [other.lookup(rev) for rev in revs]
6769 ui.debug('comparing with %s\n' % util.hidepassword(source))
6772 ui.debug('comparing with %s\n' % util.hidepassword(source))
6770 repo.ui.pushbuffer()
6773 repo.ui.pushbuffer()
6771 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6774 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6772 repo.ui.popbuffer()
6775 repo.ui.popbuffer()
6773 return source, sbranch, other, commoninc, commoninc[1]
6776 return source, sbranch, other, commoninc, commoninc[1]
6774
6777
6775 if needsincoming:
6778 if needsincoming:
6776 source, sbranch, sother, commoninc, incoming = getincoming()
6779 source, sbranch, sother, commoninc, incoming = getincoming()
6777 else:
6780 else:
6778 source = sbranch = sother = commoninc = incoming = None
6781 source = sbranch = sother = commoninc = incoming = None
6779
6782
6780 def getoutgoing():
6783 def getoutgoing():
6781 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6784 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6782 dbranch = branches[0]
6785 dbranch = branches[0]
6783 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6786 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6784 if source != dest:
6787 if source != dest:
6785 try:
6788 try:
6786 dother = hg.peer(repo, {}, dest)
6789 dother = hg.peer(repo, {}, dest)
6787 except error.RepoError:
6790 except error.RepoError:
6788 if opts.get('remote'):
6791 if opts.get('remote'):
6789 raise
6792 raise
6790 return dest, dbranch, None, None
6793 return dest, dbranch, None, None
6791 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6794 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6792 elif sother is None:
6795 elif sother is None:
6793 # there is no explicit destination peer, but source one is invalid
6796 # there is no explicit destination peer, but source one is invalid
6794 return dest, dbranch, None, None
6797 return dest, dbranch, None, None
6795 else:
6798 else:
6796 dother = sother
6799 dother = sother
6797 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6800 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6798 common = None
6801 common = None
6799 else:
6802 else:
6800 common = commoninc
6803 common = commoninc
6801 if revs:
6804 if revs:
6802 revs = [repo.lookup(rev) for rev in revs]
6805 revs = [repo.lookup(rev) for rev in revs]
6803 repo.ui.pushbuffer()
6806 repo.ui.pushbuffer()
6804 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6807 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6805 commoninc=common)
6808 commoninc=common)
6806 repo.ui.popbuffer()
6809 repo.ui.popbuffer()
6807 return dest, dbranch, dother, outgoing
6810 return dest, dbranch, dother, outgoing
6808
6811
6809 if needsoutgoing:
6812 if needsoutgoing:
6810 dest, dbranch, dother, outgoing = getoutgoing()
6813 dest, dbranch, dother, outgoing = getoutgoing()
6811 else:
6814 else:
6812 dest = dbranch = dother = outgoing = None
6815 dest = dbranch = dother = outgoing = None
6813
6816
6814 if opts.get('remote'):
6817 if opts.get('remote'):
6815 t = []
6818 t = []
6816 if incoming:
6819 if incoming:
6817 t.append(_('1 or more incoming'))
6820 t.append(_('1 or more incoming'))
6818 o = outgoing.missing
6821 o = outgoing.missing
6819 if o:
6822 if o:
6820 t.append(_('%d outgoing') % len(o))
6823 t.append(_('%d outgoing') % len(o))
6821 other = dother or sother
6824 other = dother or sother
6822 if 'bookmarks' in other.listkeys('namespaces'):
6825 if 'bookmarks' in other.listkeys('namespaces'):
6823 counts = bookmarks.summary(repo, other)
6826 counts = bookmarks.summary(repo, other)
6824 if counts[0] > 0:
6827 if counts[0] > 0:
6825 t.append(_('%d incoming bookmarks') % counts[0])
6828 t.append(_('%d incoming bookmarks') % counts[0])
6826 if counts[1] > 0:
6829 if counts[1] > 0:
6827 t.append(_('%d outgoing bookmarks') % counts[1])
6830 t.append(_('%d outgoing bookmarks') % counts[1])
6828
6831
6829 if t:
6832 if t:
6830 # i18n: column positioning for "hg summary"
6833 # i18n: column positioning for "hg summary"
6831 ui.write(_('remote: %s\n') % (', '.join(t)))
6834 ui.write(_('remote: %s\n') % (', '.join(t)))
6832 else:
6835 else:
6833 # i18n: column positioning for "hg summary"
6836 # i18n: column positioning for "hg summary"
6834 ui.status(_('remote: (synced)\n'))
6837 ui.status(_('remote: (synced)\n'))
6835
6838
6836 cmdutil.summaryremotehooks(ui, repo, opts,
6839 cmdutil.summaryremotehooks(ui, repo, opts,
6837 ((source, sbranch, sother, commoninc),
6840 ((source, sbranch, sother, commoninc),
6838 (dest, dbranch, dother, outgoing)))
6841 (dest, dbranch, dother, outgoing)))
6839
6842
6840 @command('tag',
6843 @command('tag',
6841 [('f', 'force', None, _('force tag')),
6844 [('f', 'force', None, _('force tag')),
6842 ('l', 'local', None, _('make the tag local')),
6845 ('l', 'local', None, _('make the tag local')),
6843 ('r', 'rev', '', _('revision to tag'), _('REV')),
6846 ('r', 'rev', '', _('revision to tag'), _('REV')),
6844 ('', 'remove', None, _('remove a tag')),
6847 ('', 'remove', None, _('remove a tag')),
6845 # -l/--local is already there, commitopts cannot be used
6848 # -l/--local is already there, commitopts cannot be used
6846 ('e', 'edit', None, _('invoke editor on commit messages')),
6849 ('e', 'edit', None, _('invoke editor on commit messages')),
6847 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6850 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6848 ] + commitopts2,
6851 ] + commitopts2,
6849 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6852 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6850 def tag(ui, repo, name1, *names, **opts):
6853 def tag(ui, repo, name1, *names, **opts):
6851 """add one or more tags for the current or given revision
6854 """add one or more tags for the current or given revision
6852
6855
6853 Name a particular revision using <name>.
6856 Name a particular revision using <name>.
6854
6857
6855 Tags are used to name particular revisions of the repository and are
6858 Tags are used to name particular revisions of the repository and are
6856 very useful to compare different revisions, to go back to significant
6859 very useful to compare different revisions, to go back to significant
6857 earlier versions or to mark branch points as releases, etc. Changing
6860 earlier versions or to mark branch points as releases, etc. Changing
6858 an existing tag is normally disallowed; use -f/--force to override.
6861 an existing tag is normally disallowed; use -f/--force to override.
6859
6862
6860 If no revision is given, the parent of the working directory is
6863 If no revision is given, the parent of the working directory is
6861 used.
6864 used.
6862
6865
6863 To facilitate version control, distribution, and merging of tags,
6866 To facilitate version control, distribution, and merging of tags,
6864 they are stored as a file named ".hgtags" which is managed similarly
6867 they are stored as a file named ".hgtags" which is managed similarly
6865 to other project files and can be hand-edited if necessary. This
6868 to other project files and can be hand-edited if necessary. This
6866 also means that tagging creates a new commit. The file
6869 also means that tagging creates a new commit. The file
6867 ".hg/localtags" is used for local tags (not shared among
6870 ".hg/localtags" is used for local tags (not shared among
6868 repositories).
6871 repositories).
6869
6872
6870 Tag commits are usually made at the head of a branch. If the parent
6873 Tag commits are usually made at the head of a branch. If the parent
6871 of the working directory is not a branch head, :hg:`tag` aborts; use
6874 of the working directory is not a branch head, :hg:`tag` aborts; use
6872 -f/--force to force the tag commit to be based on a non-head
6875 -f/--force to force the tag commit to be based on a non-head
6873 changeset.
6876 changeset.
6874
6877
6875 See :hg:`help dates` for a list of formats valid for -d/--date.
6878 See :hg:`help dates` for a list of formats valid for -d/--date.
6876
6879
6877 Since tag names have priority over branch names during revision
6880 Since tag names have priority over branch names during revision
6878 lookup, using an existing branch name as a tag name is discouraged.
6881 lookup, using an existing branch name as a tag name is discouraged.
6879
6882
6880 Returns 0 on success.
6883 Returns 0 on success.
6881 """
6884 """
6882 wlock = lock = None
6885 wlock = lock = None
6883 try:
6886 try:
6884 wlock = repo.wlock()
6887 wlock = repo.wlock()
6885 lock = repo.lock()
6888 lock = repo.lock()
6886 rev_ = "."
6889 rev_ = "."
6887 names = [t.strip() for t in (name1,) + names]
6890 names = [t.strip() for t in (name1,) + names]
6888 if len(names) != len(set(names)):
6891 if len(names) != len(set(names)):
6889 raise error.Abort(_('tag names must be unique'))
6892 raise error.Abort(_('tag names must be unique'))
6890 for n in names:
6893 for n in names:
6891 scmutil.checknewlabel(repo, n, 'tag')
6894 scmutil.checknewlabel(repo, n, 'tag')
6892 if not n:
6895 if not n:
6893 raise error.Abort(_('tag names cannot consist entirely of '
6896 raise error.Abort(_('tag names cannot consist entirely of '
6894 'whitespace'))
6897 'whitespace'))
6895 if opts.get('rev') and opts.get('remove'):
6898 if opts.get('rev') and opts.get('remove'):
6896 raise error.Abort(_("--rev and --remove are incompatible"))
6899 raise error.Abort(_("--rev and --remove are incompatible"))
6897 if opts.get('rev'):
6900 if opts.get('rev'):
6898 rev_ = opts['rev']
6901 rev_ = opts['rev']
6899 message = opts.get('message')
6902 message = opts.get('message')
6900 if opts.get('remove'):
6903 if opts.get('remove'):
6901 if opts.get('local'):
6904 if opts.get('local'):
6902 expectedtype = 'local'
6905 expectedtype = 'local'
6903 else:
6906 else:
6904 expectedtype = 'global'
6907 expectedtype = 'global'
6905
6908
6906 for n in names:
6909 for n in names:
6907 if not repo.tagtype(n):
6910 if not repo.tagtype(n):
6908 raise error.Abort(_("tag '%s' does not exist") % n)
6911 raise error.Abort(_("tag '%s' does not exist") % n)
6909 if repo.tagtype(n) != expectedtype:
6912 if repo.tagtype(n) != expectedtype:
6910 if expectedtype == 'global':
6913 if expectedtype == 'global':
6911 raise error.Abort(_("tag '%s' is not a global tag") % n)
6914 raise error.Abort(_("tag '%s' is not a global tag") % n)
6912 else:
6915 else:
6913 raise error.Abort(_("tag '%s' is not a local tag") % n)
6916 raise error.Abort(_("tag '%s' is not a local tag") % n)
6914 rev_ = 'null'
6917 rev_ = 'null'
6915 if not message:
6918 if not message:
6916 # we don't translate commit messages
6919 # we don't translate commit messages
6917 message = 'Removed tag %s' % ', '.join(names)
6920 message = 'Removed tag %s' % ', '.join(names)
6918 elif not opts.get('force'):
6921 elif not opts.get('force'):
6919 for n in names:
6922 for n in names:
6920 if n in repo.tags():
6923 if n in repo.tags():
6921 raise error.Abort(_("tag '%s' already exists "
6924 raise error.Abort(_("tag '%s' already exists "
6922 "(use -f to force)") % n)
6925 "(use -f to force)") % n)
6923 if not opts.get('local'):
6926 if not opts.get('local'):
6924 p1, p2 = repo.dirstate.parents()
6927 p1, p2 = repo.dirstate.parents()
6925 if p2 != nullid:
6928 if p2 != nullid:
6926 raise error.Abort(_('uncommitted merge'))
6929 raise error.Abort(_('uncommitted merge'))
6927 bheads = repo.branchheads()
6930 bheads = repo.branchheads()
6928 if not opts.get('force') and bheads and p1 not in bheads:
6931 if not opts.get('force') and bheads and p1 not in bheads:
6929 raise error.Abort(_('not at a branch head (use -f to force)'))
6932 raise error.Abort(_('not at a branch head (use -f to force)'))
6930 r = scmutil.revsingle(repo, rev_).node()
6933 r = scmutil.revsingle(repo, rev_).node()
6931
6934
6932 if not message:
6935 if not message:
6933 # we don't translate commit messages
6936 # we don't translate commit messages
6934 message = ('Added tag %s for changeset %s' %
6937 message = ('Added tag %s for changeset %s' %
6935 (', '.join(names), short(r)))
6938 (', '.join(names), short(r)))
6936
6939
6937 date = opts.get('date')
6940 date = opts.get('date')
6938 if date:
6941 if date:
6939 date = util.parsedate(date)
6942 date = util.parsedate(date)
6940
6943
6941 if opts.get('remove'):
6944 if opts.get('remove'):
6942 editform = 'tag.remove'
6945 editform = 'tag.remove'
6943 else:
6946 else:
6944 editform = 'tag.add'
6947 editform = 'tag.add'
6945 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6948 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6946
6949
6947 # don't allow tagging the null rev
6950 # don't allow tagging the null rev
6948 if (not opts.get('remove') and
6951 if (not opts.get('remove') and
6949 scmutil.revsingle(repo, rev_).rev() == nullrev):
6952 scmutil.revsingle(repo, rev_).rev() == nullrev):
6950 raise error.Abort(_("cannot tag null revision"))
6953 raise error.Abort(_("cannot tag null revision"))
6951
6954
6952 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6955 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6953 editor=editor)
6956 editor=editor)
6954 finally:
6957 finally:
6955 release(lock, wlock)
6958 release(lock, wlock)
6956
6959
6957 @command('tags', formatteropts, '')
6960 @command('tags', formatteropts, '')
6958 def tags(ui, repo, **opts):
6961 def tags(ui, repo, **opts):
6959 """list repository tags
6962 """list repository tags
6960
6963
6961 This lists both regular and local tags. When the -v/--verbose
6964 This lists both regular and local tags. When the -v/--verbose
6962 switch is used, a third column "local" is printed for local tags.
6965 switch is used, a third column "local" is printed for local tags.
6963 When the -q/--quiet switch is used, only the tag name is printed.
6966 When the -q/--quiet switch is used, only the tag name is printed.
6964
6967
6965 Returns 0 on success.
6968 Returns 0 on success.
6966 """
6969 """
6967
6970
6968 fm = ui.formatter('tags', opts)
6971 fm = ui.formatter('tags', opts)
6969 hexfunc = fm.hexfunc
6972 hexfunc = fm.hexfunc
6970 tagtype = ""
6973 tagtype = ""
6971
6974
6972 for t, n in reversed(repo.tagslist()):
6975 for t, n in reversed(repo.tagslist()):
6973 hn = hexfunc(n)
6976 hn = hexfunc(n)
6974 label = 'tags.normal'
6977 label = 'tags.normal'
6975 tagtype = ''
6978 tagtype = ''
6976 if repo.tagtype(t) == 'local':
6979 if repo.tagtype(t) == 'local':
6977 label = 'tags.local'
6980 label = 'tags.local'
6978 tagtype = 'local'
6981 tagtype = 'local'
6979
6982
6980 fm.startitem()
6983 fm.startitem()
6981 fm.write('tag', '%s', t, label=label)
6984 fm.write('tag', '%s', t, label=label)
6982 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6985 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6983 fm.condwrite(not ui.quiet, 'rev node', fmt,
6986 fm.condwrite(not ui.quiet, 'rev node', fmt,
6984 repo.changelog.rev(n), hn, label=label)
6987 repo.changelog.rev(n), hn, label=label)
6985 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6988 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6986 tagtype, label=label)
6989 tagtype, label=label)
6987 fm.plain('\n')
6990 fm.plain('\n')
6988 fm.end()
6991 fm.end()
6989
6992
6990 @command('tip',
6993 @command('tip',
6991 [('p', 'patch', None, _('show patch')),
6994 [('p', 'patch', None, _('show patch')),
6992 ('g', 'git', None, _('use git extended diff format')),
6995 ('g', 'git', None, _('use git extended diff format')),
6993 ] + templateopts,
6996 ] + templateopts,
6994 _('[-p] [-g]'))
6997 _('[-p] [-g]'))
6995 def tip(ui, repo, **opts):
6998 def tip(ui, repo, **opts):
6996 """show the tip revision (DEPRECATED)
6999 """show the tip revision (DEPRECATED)
6997
7000
6998 The tip revision (usually just called the tip) is the changeset
7001 The tip revision (usually just called the tip) is the changeset
6999 most recently added to the repository (and therefore the most
7002 most recently added to the repository (and therefore the most
7000 recently changed head).
7003 recently changed head).
7001
7004
7002 If you have just made a commit, that commit will be the tip. If
7005 If you have just made a commit, that commit will be the tip. If
7003 you have just pulled changes from another repository, the tip of
7006 you have just pulled changes from another repository, the tip of
7004 that repository becomes the current tip. The "tip" tag is special
7007 that repository becomes the current tip. The "tip" tag is special
7005 and cannot be renamed or assigned to a different changeset.
7008 and cannot be renamed or assigned to a different changeset.
7006
7009
7007 This command is deprecated, please use :hg:`heads` instead.
7010 This command is deprecated, please use :hg:`heads` instead.
7008
7011
7009 Returns 0 on success.
7012 Returns 0 on success.
7010 """
7013 """
7011 displayer = cmdutil.show_changeset(ui, repo, opts)
7014 displayer = cmdutil.show_changeset(ui, repo, opts)
7012 displayer.show(repo['tip'])
7015 displayer.show(repo['tip'])
7013 displayer.close()
7016 displayer.close()
7014
7017
7015 @command('unbundle',
7018 @command('unbundle',
7016 [('u', 'update', None,
7019 [('u', 'update', None,
7017 _('update to new branch head if changesets were unbundled'))],
7020 _('update to new branch head if changesets were unbundled'))],
7018 _('[-u] FILE...'))
7021 _('[-u] FILE...'))
7019 def unbundle(ui, repo, fname1, *fnames, **opts):
7022 def unbundle(ui, repo, fname1, *fnames, **opts):
7020 """apply one or more changegroup files
7023 """apply one or more changegroup files
7021
7024
7022 Apply one or more compressed changegroup files generated by the
7025 Apply one or more compressed changegroup files generated by the
7023 bundle command.
7026 bundle command.
7024
7027
7025 Returns 0 on success, 1 if an update has unresolved files.
7028 Returns 0 on success, 1 if an update has unresolved files.
7026 """
7029 """
7027 fnames = (fname1,) + fnames
7030 fnames = (fname1,) + fnames
7028
7031
7029 with repo.lock():
7032 with repo.lock():
7030 for fname in fnames:
7033 for fname in fnames:
7031 f = hg.openpath(ui, fname)
7034 f = hg.openpath(ui, fname)
7032 gen = exchange.readbundle(ui, f, fname)
7035 gen = exchange.readbundle(ui, f, fname)
7033 if isinstance(gen, bundle2.unbundle20):
7036 if isinstance(gen, bundle2.unbundle20):
7034 tr = repo.transaction('unbundle')
7037 tr = repo.transaction('unbundle')
7035 try:
7038 try:
7036 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7039 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7037 url='bundle:' + fname)
7040 url='bundle:' + fname)
7038 tr.close()
7041 tr.close()
7039 except error.BundleUnknownFeatureError as exc:
7042 except error.BundleUnknownFeatureError as exc:
7040 raise error.Abort(_('%s: unknown bundle feature, %s')
7043 raise error.Abort(_('%s: unknown bundle feature, %s')
7041 % (fname, exc),
7044 % (fname, exc),
7042 hint=_("see https://mercurial-scm.org/"
7045 hint=_("see https://mercurial-scm.org/"
7043 "wiki/BundleFeature for more "
7046 "wiki/BundleFeature for more "
7044 "information"))
7047 "information"))
7045 finally:
7048 finally:
7046 if tr:
7049 if tr:
7047 tr.release()
7050 tr.release()
7048 changes = [r.get('return', 0)
7051 changes = [r.get('return', 0)
7049 for r in op.records['changegroup']]
7052 for r in op.records['changegroup']]
7050 modheads = changegroup.combineresults(changes)
7053 modheads = changegroup.combineresults(changes)
7051 elif isinstance(gen, streamclone.streamcloneapplier):
7054 elif isinstance(gen, streamclone.streamcloneapplier):
7052 raise error.Abort(
7055 raise error.Abort(
7053 _('packed bundles cannot be applied with '
7056 _('packed bundles cannot be applied with '
7054 '"hg unbundle"'),
7057 '"hg unbundle"'),
7055 hint=_('use "hg debugapplystreamclonebundle"'))
7058 hint=_('use "hg debugapplystreamclonebundle"'))
7056 else:
7059 else:
7057 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7060 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7058
7061
7059 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7062 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7060
7063
7061 @command('^update|up|checkout|co',
7064 @command('^update|up|checkout|co',
7062 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7065 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7063 ('c', 'check', None,
7066 ('c', 'check', None,
7064 _('update across branches if no uncommitted changes')),
7067 _('update across branches if no uncommitted changes')),
7065 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7068 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7066 ('r', 'rev', '', _('revision'), _('REV'))
7069 ('r', 'rev', '', _('revision'), _('REV'))
7067 ] + mergetoolopts,
7070 ] + mergetoolopts,
7068 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7071 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7069 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7072 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7070 tool=None):
7073 tool=None):
7071 """update working directory (or switch revisions)
7074 """update working directory (or switch revisions)
7072
7075
7073 Update the repository's working directory to the specified
7076 Update the repository's working directory to the specified
7074 changeset. If no changeset is specified, update to the tip of the
7077 changeset. If no changeset is specified, update to the tip of the
7075 current named branch and move the active bookmark (see :hg:`help
7078 current named branch and move the active bookmark (see :hg:`help
7076 bookmarks`).
7079 bookmarks`).
7077
7080
7078 Update sets the working directory's parent revision to the specified
7081 Update sets the working directory's parent revision to the specified
7079 changeset (see :hg:`help parents`).
7082 changeset (see :hg:`help parents`).
7080
7083
7081 If the changeset is not a descendant or ancestor of the working
7084 If the changeset is not a descendant or ancestor of the working
7082 directory's parent, the update is aborted. With the -c/--check
7085 directory's parent, the update is aborted. With the -c/--check
7083 option, the working directory is checked for uncommitted changes; if
7086 option, the working directory is checked for uncommitted changes; if
7084 none are found, the working directory is updated to the specified
7087 none are found, the working directory is updated to the specified
7085 changeset.
7088 changeset.
7086
7089
7087 .. container:: verbose
7090 .. container:: verbose
7088
7091
7089 The following rules apply when the working directory contains
7092 The following rules apply when the working directory contains
7090 uncommitted changes:
7093 uncommitted changes:
7091
7094
7092 1. If neither -c/--check nor -C/--clean is specified, and if
7095 1. If neither -c/--check nor -C/--clean is specified, and if
7093 the requested changeset is an ancestor or descendant of
7096 the requested changeset is an ancestor or descendant of
7094 the working directory's parent, the uncommitted changes
7097 the working directory's parent, the uncommitted changes
7095 are merged into the requested changeset and the merged
7098 are merged into the requested changeset and the merged
7096 result is left uncommitted. If the requested changeset is
7099 result is left uncommitted. If the requested changeset is
7097 not an ancestor or descendant (that is, it is on another
7100 not an ancestor or descendant (that is, it is on another
7098 branch), the update is aborted and the uncommitted changes
7101 branch), the update is aborted and the uncommitted changes
7099 are preserved.
7102 are preserved.
7100
7103
7101 2. With the -c/--check option, the update is aborted and the
7104 2. With the -c/--check option, the update is aborted and the
7102 uncommitted changes are preserved.
7105 uncommitted changes are preserved.
7103
7106
7104 3. With the -C/--clean option, uncommitted changes are discarded and
7107 3. With the -C/--clean option, uncommitted changes are discarded and
7105 the working directory is updated to the requested changeset.
7108 the working directory is updated to the requested changeset.
7106
7109
7107 To cancel an uncommitted merge (and lose your changes), use
7110 To cancel an uncommitted merge (and lose your changes), use
7108 :hg:`update --clean .`.
7111 :hg:`update --clean .`.
7109
7112
7110 Use null as the changeset to remove the working directory (like
7113 Use null as the changeset to remove the working directory (like
7111 :hg:`clone -U`).
7114 :hg:`clone -U`).
7112
7115
7113 If you want to revert just one file to an older revision, use
7116 If you want to revert just one file to an older revision, use
7114 :hg:`revert [-r REV] NAME`.
7117 :hg:`revert [-r REV] NAME`.
7115
7118
7116 See :hg:`help dates` for a list of formats valid for -d/--date.
7119 See :hg:`help dates` for a list of formats valid for -d/--date.
7117
7120
7118 Returns 0 on success, 1 if there are unresolved files.
7121 Returns 0 on success, 1 if there are unresolved files.
7119 """
7122 """
7120 if rev and node:
7123 if rev and node:
7121 raise error.Abort(_("please specify just one revision"))
7124 raise error.Abort(_("please specify just one revision"))
7122
7125
7123 if rev is None or rev == '':
7126 if rev is None or rev == '':
7124 rev = node
7127 rev = node
7125
7128
7126 if date and rev is not None:
7129 if date and rev is not None:
7127 raise error.Abort(_("you can't specify a revision and a date"))
7130 raise error.Abort(_("you can't specify a revision and a date"))
7128
7131
7129 if check and clean:
7132 if check and clean:
7130 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7133 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7131
7134
7132 with repo.wlock():
7135 with repo.wlock():
7133 cmdutil.clearunfinished(repo)
7136 cmdutil.clearunfinished(repo)
7134
7137
7135 if date:
7138 if date:
7136 rev = cmdutil.finddate(ui, repo, date)
7139 rev = cmdutil.finddate(ui, repo, date)
7137
7140
7138 # if we defined a bookmark, we have to remember the original name
7141 # if we defined a bookmark, we have to remember the original name
7139 brev = rev
7142 brev = rev
7140 rev = scmutil.revsingle(repo, rev, rev).rev()
7143 rev = scmutil.revsingle(repo, rev, rev).rev()
7141
7144
7142 if check:
7145 if check:
7143 cmdutil.bailifchanged(repo, merge=False)
7146 cmdutil.bailifchanged(repo, merge=False)
7144
7147
7145 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7148 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7146
7149
7147 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7150 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7148
7151
7149 @command('verify', [])
7152 @command('verify', [])
7150 def verify(ui, repo):
7153 def verify(ui, repo):
7151 """verify the integrity of the repository
7154 """verify the integrity of the repository
7152
7155
7153 Verify the integrity of the current repository.
7156 Verify the integrity of the current repository.
7154
7157
7155 This will perform an extensive check of the repository's
7158 This will perform an extensive check of the repository's
7156 integrity, validating the hashes and checksums of each entry in
7159 integrity, validating the hashes and checksums of each entry in
7157 the changelog, manifest, and tracked files, as well as the
7160 the changelog, manifest, and tracked files, as well as the
7158 integrity of their crosslinks and indices.
7161 integrity of their crosslinks and indices.
7159
7162
7160 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7163 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7161 for more information about recovery from corruption of the
7164 for more information about recovery from corruption of the
7162 repository.
7165 repository.
7163
7166
7164 Returns 0 on success, 1 if errors are encountered.
7167 Returns 0 on success, 1 if errors are encountered.
7165 """
7168 """
7166 return hg.verify(repo)
7169 return hg.verify(repo)
7167
7170
7168 @command('version', [], norepo=True)
7171 @command('version', [], norepo=True)
7169 def version_(ui):
7172 def version_(ui):
7170 """output version and copyright information"""
7173 """output version and copyright information"""
7171 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7174 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7172 % util.version())
7175 % util.version())
7173 ui.status(_(
7176 ui.status(_(
7174 "(see https://mercurial-scm.org for more information)\n"
7177 "(see https://mercurial-scm.org for more information)\n"
7175 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7178 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7176 "This is free software; see the source for copying conditions. "
7179 "This is free software; see the source for copying conditions. "
7177 "There is NO\nwarranty; "
7180 "There is NO\nwarranty; "
7178 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7181 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7179 ))
7182 ))
7180
7183
7181 ui.note(_("\nEnabled extensions:\n\n"))
7184 ui.note(_("\nEnabled extensions:\n\n"))
7182 if ui.verbose:
7185 if ui.verbose:
7183 # format names and versions into columns
7186 # format names and versions into columns
7184 names = []
7187 names = []
7185 vers = []
7188 vers = []
7186 place = []
7189 place = []
7187 for name, module in extensions.extensions():
7190 for name, module in extensions.extensions():
7188 names.append(name)
7191 names.append(name)
7189 vers.append(extensions.moduleversion(module))
7192 vers.append(extensions.moduleversion(module))
7190 if extensions.ismoduleinternal(module):
7193 if extensions.ismoduleinternal(module):
7191 place.append(_("internal"))
7194 place.append(_("internal"))
7192 else:
7195 else:
7193 place.append(_("external"))
7196 place.append(_("external"))
7194 if names:
7197 if names:
7195 maxnamelen = max(len(n) for n in names)
7198 maxnamelen = max(len(n) for n in names)
7196 for i, name in enumerate(names):
7199 for i, name in enumerate(names):
7197 ui.write(" %-*s %s %s\n" %
7200 ui.write(" %-*s %s %s\n" %
7198 (maxnamelen, name, place[i], vers[i]))
7201 (maxnamelen, name, place[i], vers[i]))
7199
7202
7200 def loadcmdtable(ui, name, cmdtable):
7203 def loadcmdtable(ui, name, cmdtable):
7201 """Load command functions from specified cmdtable
7204 """Load command functions from specified cmdtable
7202 """
7205 """
7203 overrides = [cmd for cmd in cmdtable if cmd in table]
7206 overrides = [cmd for cmd in cmdtable if cmd in table]
7204 if overrides:
7207 if overrides:
7205 ui.warn(_("extension '%s' overrides commands: %s\n")
7208 ui.warn(_("extension '%s' overrides commands: %s\n")
7206 % (name, " ".join(overrides)))
7209 % (name, " ".join(overrides)))
7207 table.update(cmdtable)
7210 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now