##// END OF EJS Templates
bundle: avoid crash when no good changegroup version found...
Martin von Zweigbergk -
r28669:c4b72779 default
parent child Browse files
Show More
@@ -1,7203 +1,7207 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):
1403 raise error.Abort(_("repository does not support bundle version %s") %
1404 cgversion)
1405
1402 if base:
1406 if base:
1403 if dest:
1407 if dest:
1404 raise error.Abort(_("--base is incompatible with specifying "
1408 raise error.Abort(_("--base is incompatible with specifying "
1405 "a destination"))
1409 "a destination"))
1406 common = [repo.lookup(rev) for rev in base]
1410 common = [repo.lookup(rev) for rev in base]
1407 heads = revs and map(repo.lookup, revs) or revs
1411 heads = revs and map(repo.lookup, revs) or revs
1408 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1412 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1409 common=common, bundlecaps=bundlecaps,
1413 common=common, bundlecaps=bundlecaps,
1410 version=cgversion)
1414 version=cgversion)
1411 outgoing = None
1415 outgoing = None
1412 else:
1416 else:
1413 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1417 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1414 dest, branches = hg.parseurl(dest, opts.get('branch'))
1418 dest, branches = hg.parseurl(dest, opts.get('branch'))
1415 other = hg.peer(repo, opts, dest)
1419 other = hg.peer(repo, opts, dest)
1416 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1420 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1417 heads = revs and map(repo.lookup, revs) or revs
1421 heads = revs and map(repo.lookup, revs) or revs
1418 outgoing = discovery.findcommonoutgoing(repo, other,
1422 outgoing = discovery.findcommonoutgoing(repo, other,
1419 onlyheads=heads,
1423 onlyheads=heads,
1420 force=opts.get('force'),
1424 force=opts.get('force'),
1421 portable=True)
1425 portable=True)
1422 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1426 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1423 bundlecaps, version=cgversion)
1427 bundlecaps, version=cgversion)
1424 if not cg:
1428 if not cg:
1425 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1429 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1426 return 1
1430 return 1
1427
1431
1428 if cgversion == '01': #bundle1
1432 if cgversion == '01': #bundle1
1429 if bcompression is None:
1433 if bcompression is None:
1430 bcompression = 'UN'
1434 bcompression = 'UN'
1431 bversion = 'HG10' + bcompression
1435 bversion = 'HG10' + bcompression
1432 bcompression = None
1436 bcompression = None
1433 else:
1437 else:
1434 assert cgversion == '02'
1438 assert cgversion == '02'
1435 bversion = 'HG20'
1439 bversion = 'HG20'
1436
1440
1437 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1441 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression)
1438
1442
1439 @command('cat',
1443 @command('cat',
1440 [('o', 'output', '',
1444 [('o', 'output', '',
1441 _('print output to file with formatted name'), _('FORMAT')),
1445 _('print output to file with formatted name'), _('FORMAT')),
1442 ('r', 'rev', '', _('print the given revision'), _('REV')),
1446 ('r', 'rev', '', _('print the given revision'), _('REV')),
1443 ('', 'decode', None, _('apply any matching decode filter')),
1447 ('', 'decode', None, _('apply any matching decode filter')),
1444 ] + walkopts,
1448 ] + walkopts,
1445 _('[OPTION]... FILE...'),
1449 _('[OPTION]... FILE...'),
1446 inferrepo=True)
1450 inferrepo=True)
1447 def cat(ui, repo, file1, *pats, **opts):
1451 def cat(ui, repo, file1, *pats, **opts):
1448 """output the current or given revision of files
1452 """output the current or given revision of files
1449
1453
1450 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
1451 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.
1452
1456
1453 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
1454 given using a format string. The formatting rules as follows:
1458 given using a format string. The formatting rules as follows:
1455
1459
1456 :``%%``: literal "%" character
1460 :``%%``: literal "%" character
1457 :``%s``: basename of file being printed
1461 :``%s``: basename of file being printed
1458 :``%d``: dirname of file being printed, or '.' if in repository root
1462 :``%d``: dirname of file being printed, or '.' if in repository root
1459 :``%p``: root-relative path name of file being printed
1463 :``%p``: root-relative path name of file being printed
1460 :``%H``: changeset hash (40 hexadecimal digits)
1464 :``%H``: changeset hash (40 hexadecimal digits)
1461 :``%R``: changeset revision number
1465 :``%R``: changeset revision number
1462 :``%h``: short-form changeset hash (12 hexadecimal digits)
1466 :``%h``: short-form changeset hash (12 hexadecimal digits)
1463 :``%r``: zero-padded changeset revision number
1467 :``%r``: zero-padded changeset revision number
1464 :``%b``: basename of the exporting repository
1468 :``%b``: basename of the exporting repository
1465
1469
1466 Returns 0 on success.
1470 Returns 0 on success.
1467 """
1471 """
1468 ctx = scmutil.revsingle(repo, opts.get('rev'))
1472 ctx = scmutil.revsingle(repo, opts.get('rev'))
1469 m = scmutil.match(ctx, (file1,) + pats, opts)
1473 m = scmutil.match(ctx, (file1,) + pats, opts)
1470
1474
1471 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1475 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1472
1476
1473 @command('^clone',
1477 @command('^clone',
1474 [('U', 'noupdate', None, _('the clone will include an empty working '
1478 [('U', 'noupdate', None, _('the clone will include an empty working '
1475 'directory (only a repository)')),
1479 'directory (only a repository)')),
1476 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1480 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1477 _('REV')),
1481 _('REV')),
1478 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1482 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1479 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1483 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1480 ('', 'pull', None, _('use pull protocol to copy metadata')),
1484 ('', 'pull', None, _('use pull protocol to copy metadata')),
1481 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1485 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1482 ] + remoteopts,
1486 ] + remoteopts,
1483 _('[OPTION]... SOURCE [DEST]'),
1487 _('[OPTION]... SOURCE [DEST]'),
1484 norepo=True)
1488 norepo=True)
1485 def clone(ui, source, dest=None, **opts):
1489 def clone(ui, source, dest=None, **opts):
1486 """make a copy of an existing repository
1490 """make a copy of an existing repository
1487
1491
1488 Create a copy of an existing repository in a new directory.
1492 Create a copy of an existing repository in a new directory.
1489
1493
1490 If no destination directory name is specified, it defaults to the
1494 If no destination directory name is specified, it defaults to the
1491 basename of the source.
1495 basename of the source.
1492
1496
1493 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
1494 ``.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.
1495
1499
1496 Only local paths and ``ssh://`` URLs are supported as
1500 Only local paths and ``ssh://`` URLs are supported as
1497 destinations. For ``ssh://`` destinations, no working directory or
1501 destinations. For ``ssh://`` destinations, no working directory or
1498 ``.hg/hgrc`` will be created on the remote side.
1502 ``.hg/hgrc`` will be created on the remote side.
1499
1503
1500 If the source repository has a bookmark called '@' set, that
1504 If the source repository has a bookmark called '@' set, that
1501 revision will be checked out in the new repository by default.
1505 revision will be checked out in the new repository by default.
1502
1506
1503 To check out a particular version, use -u/--update, or
1507 To check out a particular version, use -u/--update, or
1504 -U/--noupdate to create a clone with no working directory.
1508 -U/--noupdate to create a clone with no working directory.
1505
1509
1506 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
1507 identifiers with -r/--rev or branches with -b/--branch. The
1511 identifiers with -r/--rev or branches with -b/--branch. The
1508 resulting clone will contain only the specified changesets and
1512 resulting clone will contain only the specified changesets and
1509 their ancestors. These options (or 'clone src#rev dest') imply
1513 their ancestors. These options (or 'clone src#rev dest') imply
1510 --pull, even for local source repositories.
1514 --pull, even for local source repositories.
1511
1515
1512 .. note::
1516 .. note::
1513
1517
1514 Specifying a tag will include the tagged changeset but not the
1518 Specifying a tag will include the tagged changeset but not the
1515 changeset containing the tag.
1519 changeset containing the tag.
1516
1520
1517 .. container:: verbose
1521 .. container:: verbose
1518
1522
1519 For efficiency, hardlinks are used for cloning whenever the
1523 For efficiency, hardlinks are used for cloning whenever the
1520 source and destination are on the same filesystem (note this
1524 source and destination are on the same filesystem (note this
1521 applies only to the repository data, not to the working
1525 applies only to the repository data, not to the working
1522 directory). Some filesystems, such as AFS, implement hardlinking
1526 directory). Some filesystems, such as AFS, implement hardlinking
1523 incorrectly, but do not report errors. In these cases, use the
1527 incorrectly, but do not report errors. In these cases, use the
1524 --pull option to avoid hardlinking.
1528 --pull option to avoid hardlinking.
1525
1529
1526 In some cases, you can clone repositories and the working
1530 In some cases, you can clone repositories and the working
1527 directory using full hardlinks with ::
1531 directory using full hardlinks with ::
1528
1532
1529 $ cp -al REPO REPOCLONE
1533 $ cp -al REPO REPOCLONE
1530
1534
1531 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
1532 operation is not atomic (making sure REPO is not modified during
1536 operation is not atomic (making sure REPO is not modified during
1533 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
1534 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1538 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1535 so). Also, this is not compatible with certain extensions that
1539 so). Also, this is not compatible with certain extensions that
1536 place their metadata under the .hg directory, such as mq.
1540 place their metadata under the .hg directory, such as mq.
1537
1541
1538 Mercurial will update the working directory to the first applicable
1542 Mercurial will update the working directory to the first applicable
1539 revision from this list:
1543 revision from this list:
1540
1544
1541 a) null if -U or the source repository has no changesets
1545 a) null if -U or the source repository has no changesets
1542 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
1543 the source repository's working directory
1547 the source repository's working directory
1544 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
1545 latest head of that branch)
1549 latest head of that branch)
1546 d) the changeset specified with -r
1550 d) the changeset specified with -r
1547 e) the tipmost head specified with -b
1551 e) the tipmost head specified with -b
1548 f) the tipmost head specified with the url#branch source syntax
1552 f) the tipmost head specified with the url#branch source syntax
1549 g) the revision marked with the '@' bookmark, if present
1553 g) the revision marked with the '@' bookmark, if present
1550 h) the tipmost head of the default branch
1554 h) the tipmost head of the default branch
1551 i) tip
1555 i) tip
1552
1556
1553 When cloning from servers that support it, Mercurial may fetch
1557 When cloning from servers that support it, Mercurial may fetch
1554 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,
1555 hooks operating on incoming changesets and changegroups may fire twice,
1559 hooks operating on incoming changesets and changegroups may fire twice,
1556 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
1557 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
1558 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
1559 change in future releases. See :hg:`help -e clonebundles` for more.
1563 change in future releases. See :hg:`help -e clonebundles` for more.
1560
1564
1561 Examples:
1565 Examples:
1562
1566
1563 - clone a remote repository to a new directory named hg/::
1567 - clone a remote repository to a new directory named hg/::
1564
1568
1565 hg clone http://selenic.com/hg
1569 hg clone http://selenic.com/hg
1566
1570
1567 - create a lightweight local clone::
1571 - create a lightweight local clone::
1568
1572
1569 hg clone project/ project-feature/
1573 hg clone project/ project-feature/
1570
1574
1571 - 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)::
1572
1576
1573 hg clone ssh://user@server//home/projects/alpha/
1577 hg clone ssh://user@server//home/projects/alpha/
1574
1578
1575 - 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
1576 specified version::
1580 specified version::
1577
1581
1578 hg clone --uncompressed http://server/repo -u 1.5
1582 hg clone --uncompressed http://server/repo -u 1.5
1579
1583
1580 - create a repository without changesets after a particular revision::
1584 - create a repository without changesets after a particular revision::
1581
1585
1582 hg clone -r 04e544 experimental/ good/
1586 hg clone -r 04e544 experimental/ good/
1583
1587
1584 - clone (and track) a particular named branch::
1588 - clone (and track) a particular named branch::
1585
1589
1586 hg clone http://selenic.com/hg#stable
1590 hg clone http://selenic.com/hg#stable
1587
1591
1588 See :hg:`help urls` for details on specifying URLs.
1592 See :hg:`help urls` for details on specifying URLs.
1589
1593
1590 Returns 0 on success.
1594 Returns 0 on success.
1591 """
1595 """
1592 if opts.get('noupdate') and opts.get('updaterev'):
1596 if opts.get('noupdate') and opts.get('updaterev'):
1593 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1597 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1594
1598
1595 r = hg.clone(ui, opts, source, dest,
1599 r = hg.clone(ui, opts, source, dest,
1596 pull=opts.get('pull'),
1600 pull=opts.get('pull'),
1597 stream=opts.get('uncompressed'),
1601 stream=opts.get('uncompressed'),
1598 rev=opts.get('rev'),
1602 rev=opts.get('rev'),
1599 update=opts.get('updaterev') or not opts.get('noupdate'),
1603 update=opts.get('updaterev') or not opts.get('noupdate'),
1600 branch=opts.get('branch'),
1604 branch=opts.get('branch'),
1601 shareopts=opts.get('shareopts'))
1605 shareopts=opts.get('shareopts'))
1602
1606
1603 return r is None
1607 return r is None
1604
1608
1605 @command('^commit|ci',
1609 @command('^commit|ci',
1606 [('A', 'addremove', None,
1610 [('A', 'addremove', None,
1607 _('mark new/missing files as added/removed before committing')),
1611 _('mark new/missing files as added/removed before committing')),
1608 ('', 'close-branch', None,
1612 ('', 'close-branch', None,
1609 _('mark a branch head as closed')),
1613 _('mark a branch head as closed')),
1610 ('', 'amend', None, _('amend the parent of the working directory')),
1614 ('', 'amend', None, _('amend the parent of the working directory')),
1611 ('s', 'secret', None, _('use the secret phase for committing')),
1615 ('s', 'secret', None, _('use the secret phase for committing')),
1612 ('e', 'edit', None, _('invoke editor on commit messages')),
1616 ('e', 'edit', None, _('invoke editor on commit messages')),
1613 ('i', 'interactive', None, _('use interactive mode')),
1617 ('i', 'interactive', None, _('use interactive mode')),
1614 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1618 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1615 _('[OPTION]... [FILE]...'),
1619 _('[OPTION]... [FILE]...'),
1616 inferrepo=True)
1620 inferrepo=True)
1617 def commit(ui, repo, *pats, **opts):
1621 def commit(ui, repo, *pats, **opts):
1618 """commit the specified files or all outstanding changes
1622 """commit the specified files or all outstanding changes
1619
1623
1620 Commit changes to the given files into the repository. Unlike a
1624 Commit changes to the given files into the repository. Unlike a
1621 centralized SCM, this operation is a local operation. See
1625 centralized SCM, this operation is a local operation. See
1622 :hg:`push` for a way to actively distribute your changes.
1626 :hg:`push` for a way to actively distribute your changes.
1623
1627
1624 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`
1625 will be committed.
1629 will be committed.
1626
1630
1627 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
1628 filenames or -I/-X filters.
1632 filenames or -I/-X filters.
1629
1633
1630 If no commit message is specified, Mercurial starts your
1634 If no commit message is specified, Mercurial starts your
1631 configured editor where you can enter a message. In case your
1635 configured editor where you can enter a message. In case your
1632 commit fails, you will find a backup of your message in
1636 commit fails, you will find a backup of your message in
1633 ``.hg/last-message.txt``.
1637 ``.hg/last-message.txt``.
1634
1638
1635 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
1636 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
1637 will be considered closed and no longer listed.
1641 will be considered closed and no longer listed.
1638
1642
1639 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
1640 working directory with a new commit that contains the changes
1644 working directory with a new commit that contains the changes
1641 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`,
1642 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
1643 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1647 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1644 on how to restore it).
1648 on how to restore it).
1645
1649
1646 Message, user and date are taken from the amended commit unless
1650 Message, user and date are taken from the amended commit unless
1647 specified. When a message isn't specified on the command line,
1651 specified. When a message isn't specified on the command line,
1648 the editor will open with the message of the amended commit.
1652 the editor will open with the message of the amended commit.
1649
1653
1650 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`)
1651 or changesets that have children.
1655 or changesets that have children.
1652
1656
1653 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.
1654
1658
1655 Returns 0 on success, 1 if nothing changed.
1659 Returns 0 on success, 1 if nothing changed.
1656
1660
1657 .. container:: verbose
1661 .. container:: verbose
1658
1662
1659 Examples:
1663 Examples:
1660
1664
1661 - commit all files ending in .py::
1665 - commit all files ending in .py::
1662
1666
1663 hg commit --include "set:**.py"
1667 hg commit --include "set:**.py"
1664
1668
1665 - commit all non-binary files::
1669 - commit all non-binary files::
1666
1670
1667 hg commit --exclude "set:binary()"
1671 hg commit --exclude "set:binary()"
1668
1672
1669 - amend the current commit and set the date to now::
1673 - amend the current commit and set the date to now::
1670
1674
1671 hg commit --amend --date now
1675 hg commit --amend --date now
1672 """
1676 """
1673 wlock = lock = None
1677 wlock = lock = None
1674 try:
1678 try:
1675 wlock = repo.wlock()
1679 wlock = repo.wlock()
1676 lock = repo.lock()
1680 lock = repo.lock()
1677 return _docommit(ui, repo, *pats, **opts)
1681 return _docommit(ui, repo, *pats, **opts)
1678 finally:
1682 finally:
1679 release(lock, wlock)
1683 release(lock, wlock)
1680
1684
1681 def _docommit(ui, repo, *pats, **opts):
1685 def _docommit(ui, repo, *pats, **opts):
1682 if opts.get('interactive'):
1686 if opts.get('interactive'):
1683 opts.pop('interactive')
1687 opts.pop('interactive')
1684 cmdutil.dorecord(ui, repo, commit, None, False,
1688 cmdutil.dorecord(ui, repo, commit, None, False,
1685 cmdutil.recordfilter, *pats, **opts)
1689 cmdutil.recordfilter, *pats, **opts)
1686 return
1690 return
1687
1691
1688 if opts.get('subrepos'):
1692 if opts.get('subrepos'):
1689 if opts.get('amend'):
1693 if opts.get('amend'):
1690 raise error.Abort(_('cannot amend with --subrepos'))
1694 raise error.Abort(_('cannot amend with --subrepos'))
1691 # Let --subrepos on the command line override config setting.
1695 # Let --subrepos on the command line override config setting.
1692 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1696 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1693
1697
1694 cmdutil.checkunfinished(repo, commit=True)
1698 cmdutil.checkunfinished(repo, commit=True)
1695
1699
1696 branch = repo[None].branch()
1700 branch = repo[None].branch()
1697 bheads = repo.branchheads(branch)
1701 bheads = repo.branchheads(branch)
1698
1702
1699 extra = {}
1703 extra = {}
1700 if opts.get('close_branch'):
1704 if opts.get('close_branch'):
1701 extra['close'] = 1
1705 extra['close'] = 1
1702
1706
1703 if not bheads:
1707 if not bheads:
1704 raise error.Abort(_('can only close branch heads'))
1708 raise error.Abort(_('can only close branch heads'))
1705 elif opts.get('amend'):
1709 elif opts.get('amend'):
1706 if repo[None].parents()[0].p1().branch() != branch and \
1710 if repo[None].parents()[0].p1().branch() != branch and \
1707 repo[None].parents()[0].p2().branch() != branch:
1711 repo[None].parents()[0].p2().branch() != branch:
1708 raise error.Abort(_('can only close branch heads'))
1712 raise error.Abort(_('can only close branch heads'))
1709
1713
1710 if opts.get('amend'):
1714 if opts.get('amend'):
1711 if ui.configbool('ui', 'commitsubrepos'):
1715 if ui.configbool('ui', 'commitsubrepos'):
1712 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1716 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1713
1717
1714 old = repo['.']
1718 old = repo['.']
1715 if not old.mutable():
1719 if not old.mutable():
1716 raise error.Abort(_('cannot amend public changesets'))
1720 raise error.Abort(_('cannot amend public changesets'))
1717 if len(repo[None].parents()) > 1:
1721 if len(repo[None].parents()) > 1:
1718 raise error.Abort(_('cannot amend while merging'))
1722 raise error.Abort(_('cannot amend while merging'))
1719 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1723 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1720 if not allowunstable and old.children():
1724 if not allowunstable and old.children():
1721 raise error.Abort(_('cannot amend changeset with children'))
1725 raise error.Abort(_('cannot amend changeset with children'))
1722
1726
1723 # Currently histedit gets confused if an amend happens while histedit
1727 # Currently histedit gets confused if an amend happens while histedit
1724 # is in progress. Since we have a checkunfinished command, we are
1728 # is in progress. Since we have a checkunfinished command, we are
1725 # temporarily honoring it.
1729 # temporarily honoring it.
1726 #
1730 #
1727 # Note: eventually this guard will be removed. Please do not expect
1731 # Note: eventually this guard will be removed. Please do not expect
1728 # this behavior to remain.
1732 # this behavior to remain.
1729 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1733 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1730 cmdutil.checkunfinished(repo)
1734 cmdutil.checkunfinished(repo)
1731
1735
1732 # commitfunc is used only for temporary amend commit by cmdutil.amend
1736 # commitfunc is used only for temporary amend commit by cmdutil.amend
1733 def commitfunc(ui, repo, message, match, opts):
1737 def commitfunc(ui, repo, message, match, opts):
1734 return repo.commit(message,
1738 return repo.commit(message,
1735 opts.get('user') or old.user(),
1739 opts.get('user') or old.user(),
1736 opts.get('date') or old.date(),
1740 opts.get('date') or old.date(),
1737 match,
1741 match,
1738 extra=extra)
1742 extra=extra)
1739
1743
1740 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1744 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1741 if node == old.node():
1745 if node == old.node():
1742 ui.status(_("nothing changed\n"))
1746 ui.status(_("nothing changed\n"))
1743 return 1
1747 return 1
1744 else:
1748 else:
1745 def commitfunc(ui, repo, message, match, opts):
1749 def commitfunc(ui, repo, message, match, opts):
1746 backup = ui.backupconfig('phases', 'new-commit')
1750 backup = ui.backupconfig('phases', 'new-commit')
1747 baseui = repo.baseui
1751 baseui = repo.baseui
1748 basebackup = baseui.backupconfig('phases', 'new-commit')
1752 basebackup = baseui.backupconfig('phases', 'new-commit')
1749 try:
1753 try:
1750 if opts.get('secret'):
1754 if opts.get('secret'):
1751 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1755 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1752 # Propagate to subrepos
1756 # Propagate to subrepos
1753 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1757 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1754
1758
1755 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1759 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1756 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1757 return repo.commit(message, opts.get('user'), opts.get('date'),
1761 return repo.commit(message, opts.get('user'), opts.get('date'),
1758 match,
1762 match,
1759 editor=editor,
1763 editor=editor,
1760 extra=extra)
1764 extra=extra)
1761 finally:
1765 finally:
1762 ui.restoreconfig(backup)
1766 ui.restoreconfig(backup)
1763 repo.baseui.restoreconfig(basebackup)
1767 repo.baseui.restoreconfig(basebackup)
1764
1768
1765
1769
1766 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1770 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1767
1771
1768 if not node:
1772 if not node:
1769 stat = cmdutil.postcommitstatus(repo, pats, opts)
1773 stat = cmdutil.postcommitstatus(repo, pats, opts)
1770 if stat[3]:
1774 if stat[3]:
1771 ui.status(_("nothing changed (%d missing files, see "
1775 ui.status(_("nothing changed (%d missing files, see "
1772 "'hg status')\n") % len(stat[3]))
1776 "'hg status')\n") % len(stat[3]))
1773 else:
1777 else:
1774 ui.status(_("nothing changed\n"))
1778 ui.status(_("nothing changed\n"))
1775 return 1
1779 return 1
1776
1780
1777 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1781 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1778
1782
1779 @command('config|showconfig|debugconfig',
1783 @command('config|showconfig|debugconfig',
1780 [('u', 'untrusted', None, _('show untrusted configuration options')),
1784 [('u', 'untrusted', None, _('show untrusted configuration options')),
1781 ('e', 'edit', None, _('edit user config')),
1785 ('e', 'edit', None, _('edit user config')),
1782 ('l', 'local', None, _('edit repository config')),
1786 ('l', 'local', None, _('edit repository config')),
1783 ('g', 'global', None, _('edit global config'))],
1787 ('g', 'global', None, _('edit global config'))],
1784 _('[-u] [NAME]...'),
1788 _('[-u] [NAME]...'),
1785 optionalrepo=True)
1789 optionalrepo=True)
1786 def config(ui, repo, *values, **opts):
1790 def config(ui, repo, *values, **opts):
1787 """show combined config settings from all hgrc files
1791 """show combined config settings from all hgrc files
1788
1792
1789 With no arguments, print names and values of all config items.
1793 With no arguments, print names and values of all config items.
1790
1794
1791 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
1792 of that config item.
1796 of that config item.
1793
1797
1794 With multiple arguments, print names and values of all config
1798 With multiple arguments, print names and values of all config
1795 items with matching section names.
1799 items with matching section names.
1796
1800
1797 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
1798 --global, edit the system-wide config file. With --local, edit the
1802 --global, edit the system-wide config file. With --local, edit the
1799 repository-level config file.
1803 repository-level config file.
1800
1804
1801 With --debug, the source (filename and line number) is printed
1805 With --debug, the source (filename and line number) is printed
1802 for each config item.
1806 for each config item.
1803
1807
1804 See :hg:`help config` for more information about config files.
1808 See :hg:`help config` for more information about config files.
1805
1809
1806 Returns 0 on success, 1 if NAME does not exist.
1810 Returns 0 on success, 1 if NAME does not exist.
1807
1811
1808 """
1812 """
1809
1813
1810 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'):
1811 if opts.get('local') and opts.get('global'):
1815 if opts.get('local') and opts.get('global'):
1812 raise error.Abort(_("can't use --local and --global together"))
1816 raise error.Abort(_("can't use --local and --global together"))
1813
1817
1814 if opts.get('local'):
1818 if opts.get('local'):
1815 if not repo:
1819 if not repo:
1816 raise error.Abort(_("can't use --local outside a repository"))
1820 raise error.Abort(_("can't use --local outside a repository"))
1817 paths = [repo.join('hgrc')]
1821 paths = [repo.join('hgrc')]
1818 elif opts.get('global'):
1822 elif opts.get('global'):
1819 paths = scmutil.systemrcpath()
1823 paths = scmutil.systemrcpath()
1820 else:
1824 else:
1821 paths = scmutil.userrcpath()
1825 paths = scmutil.userrcpath()
1822
1826
1823 for f in paths:
1827 for f in paths:
1824 if os.path.exists(f):
1828 if os.path.exists(f):
1825 break
1829 break
1826 else:
1830 else:
1827 if opts.get('global'):
1831 if opts.get('global'):
1828 samplehgrc = uimod.samplehgrcs['global']
1832 samplehgrc = uimod.samplehgrcs['global']
1829 elif opts.get('local'):
1833 elif opts.get('local'):
1830 samplehgrc = uimod.samplehgrcs['local']
1834 samplehgrc = uimod.samplehgrcs['local']
1831 else:
1835 else:
1832 samplehgrc = uimod.samplehgrcs['user']
1836 samplehgrc = uimod.samplehgrcs['user']
1833
1837
1834 f = paths[0]
1838 f = paths[0]
1835 fp = open(f, "w")
1839 fp = open(f, "w")
1836 fp.write(samplehgrc)
1840 fp.write(samplehgrc)
1837 fp.close()
1841 fp.close()
1838
1842
1839 editor = ui.geteditor()
1843 editor = ui.geteditor()
1840 ui.system("%s \"%s\"" % (editor, f),
1844 ui.system("%s \"%s\"" % (editor, f),
1841 onerr=error.Abort, errprefix=_("edit failed"))
1845 onerr=error.Abort, errprefix=_("edit failed"))
1842 return
1846 return
1843
1847
1844 for f in scmutil.rcpath():
1848 for f in scmutil.rcpath():
1845 ui.debug('read config from: %s\n' % f)
1849 ui.debug('read config from: %s\n' % f)
1846 untrusted = bool(opts.get('untrusted'))
1850 untrusted = bool(opts.get('untrusted'))
1847 if values:
1851 if values:
1848 sections = [v for v in values if '.' not in v]
1852 sections = [v for v in values if '.' not in v]
1849 items = [v for v in values if '.' in v]
1853 items = [v for v in values if '.' in v]
1850 if len(items) > 1 or items and sections:
1854 if len(items) > 1 or items and sections:
1851 raise error.Abort(_('only one config item permitted'))
1855 raise error.Abort(_('only one config item permitted'))
1852 matched = False
1856 matched = False
1853 for section, name, value in ui.walkconfig(untrusted=untrusted):
1857 for section, name, value in ui.walkconfig(untrusted=untrusted):
1854 value = str(value).replace('\n', '\\n')
1858 value = str(value).replace('\n', '\\n')
1855 sectname = section + '.' + name
1859 sectname = section + '.' + name
1856 if values:
1860 if values:
1857 for v in values:
1861 for v in values:
1858 if v == section:
1862 if v == section:
1859 ui.debug('%s: ' %
1863 ui.debug('%s: ' %
1860 ui.configsource(section, name, untrusted))
1864 ui.configsource(section, name, untrusted))
1861 ui.write('%s=%s\n' % (sectname, value))
1865 ui.write('%s=%s\n' % (sectname, value))
1862 matched = True
1866 matched = True
1863 elif v == sectname:
1867 elif v == sectname:
1864 ui.debug('%s: ' %
1868 ui.debug('%s: ' %
1865 ui.configsource(section, name, untrusted))
1869 ui.configsource(section, name, untrusted))
1866 ui.write(value, '\n')
1870 ui.write(value, '\n')
1867 matched = True
1871 matched = True
1868 else:
1872 else:
1869 ui.debug('%s: ' %
1873 ui.debug('%s: ' %
1870 ui.configsource(section, name, untrusted))
1874 ui.configsource(section, name, untrusted))
1871 ui.write('%s=%s\n' % (sectname, value))
1875 ui.write('%s=%s\n' % (sectname, value))
1872 matched = True
1876 matched = True
1873 if matched:
1877 if matched:
1874 return 0
1878 return 0
1875 return 1
1879 return 1
1876
1880
1877 @command('copy|cp',
1881 @command('copy|cp',
1878 [('A', 'after', None, _('record a copy that has already occurred')),
1882 [('A', 'after', None, _('record a copy that has already occurred')),
1879 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1883 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1880 ] + walkopts + dryrunopts,
1884 ] + walkopts + dryrunopts,
1881 _('[OPTION]... [SOURCE]... DEST'))
1885 _('[OPTION]... [SOURCE]... DEST'))
1882 def copy(ui, repo, *pats, **opts):
1886 def copy(ui, repo, *pats, **opts):
1883 """mark files as copied for the next commit
1887 """mark files as copied for the next commit
1884
1888
1885 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
1886 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,
1887 the source must be a single file.
1891 the source must be a single file.
1888
1892
1889 By default, this command copies the contents of files as they
1893 By default, this command copies the contents of files as they
1890 exist in the working directory. If invoked with -A/--after, the
1894 exist in the working directory. If invoked with -A/--after, the
1891 operation is recorded, but no copying is performed.
1895 operation is recorded, but no copying is performed.
1892
1896
1893 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
1894 before that, see :hg:`revert`.
1898 before that, see :hg:`revert`.
1895
1899
1896 Returns 0 on success, 1 if errors are encountered.
1900 Returns 0 on success, 1 if errors are encountered.
1897 """
1901 """
1898 with repo.wlock(False):
1902 with repo.wlock(False):
1899 return cmdutil.copy(ui, repo, pats, opts)
1903 return cmdutil.copy(ui, repo, pats, opts)
1900
1904
1901 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1905 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1902 def debugancestor(ui, repo, *args):
1906 def debugancestor(ui, repo, *args):
1903 """find the ancestor revision of two revisions in a given index"""
1907 """find the ancestor revision of two revisions in a given index"""
1904 if len(args) == 3:
1908 if len(args) == 3:
1905 index, rev1, rev2 = args
1909 index, rev1, rev2 = args
1906 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1910 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1907 lookup = r.lookup
1911 lookup = r.lookup
1908 elif len(args) == 2:
1912 elif len(args) == 2:
1909 if not repo:
1913 if not repo:
1910 raise error.Abort(_("there is no Mercurial repository here "
1914 raise error.Abort(_("there is no Mercurial repository here "
1911 "(.hg not found)"))
1915 "(.hg not found)"))
1912 rev1, rev2 = args
1916 rev1, rev2 = args
1913 r = repo.changelog
1917 r = repo.changelog
1914 lookup = repo.lookup
1918 lookup = repo.lookup
1915 else:
1919 else:
1916 raise error.Abort(_('either two or three arguments required'))
1920 raise error.Abort(_('either two or three arguments required'))
1917 a = r.ancestor(lookup(rev1), lookup(rev2))
1921 a = r.ancestor(lookup(rev1), lookup(rev2))
1918 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1922 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1919
1923
1920 @command('debugbuilddag',
1924 @command('debugbuilddag',
1921 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1925 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1922 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1926 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1923 ('n', 'new-file', None, _('add new file at each rev'))],
1927 ('n', 'new-file', None, _('add new file at each rev'))],
1924 _('[OPTION]... [TEXT]'))
1928 _('[OPTION]... [TEXT]'))
1925 def debugbuilddag(ui, repo, text=None,
1929 def debugbuilddag(ui, repo, text=None,
1926 mergeable_file=False,
1930 mergeable_file=False,
1927 overwritten_file=False,
1931 overwritten_file=False,
1928 new_file=False):
1932 new_file=False):
1929 """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
1930
1934
1931 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
1932 command line.
1936 command line.
1933
1937
1934 Elements:
1938 Elements:
1935
1939
1936 - "+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
1937 - "." is a single node based on the current default parent
1941 - "." is a single node based on the current default parent
1938 - "$" resets the default parent to null (implied at the start);
1942 - "$" resets the default parent to null (implied at the start);
1939 otherwise the default parent is always the last node created
1943 otherwise the default parent is always the last node created
1940 - "<p" sets the default parent to the backref p
1944 - "<p" sets the default parent to the backref p
1941 - "*p" is a fork at parent p, which is a backref
1945 - "*p" is a fork at parent p, which is a backref
1942 - "*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
1943 - "/p2" is a merge of the preceding node and p2
1947 - "/p2" is a merge of the preceding node and p2
1944 - ":tag" defines a local tag for the preceding node
1948 - ":tag" defines a local tag for the preceding node
1945 - "@branch" sets the named branch for subsequent nodes
1949 - "@branch" sets the named branch for subsequent nodes
1946 - "#...\\n" is a comment up to the end of the line
1950 - "#...\\n" is a comment up to the end of the line
1947
1951
1948 Whitespace between the above elements is ignored.
1952 Whitespace between the above elements is ignored.
1949
1953
1950 A backref is either
1954 A backref is either
1951
1955
1952 - 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
1953 node, or
1957 node, or
1954 - 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
1955 - empty to denote the default parent.
1959 - empty to denote the default parent.
1956
1960
1957 All string valued-elements are either strictly alphanumeric, or must
1961 All string valued-elements are either strictly alphanumeric, or must
1958 be enclosed in double quotes ("..."), with "\\" as escape character.
1962 be enclosed in double quotes ("..."), with "\\" as escape character.
1959 """
1963 """
1960
1964
1961 if text is None:
1965 if text is None:
1962 ui.status(_("reading DAG from stdin\n"))
1966 ui.status(_("reading DAG from stdin\n"))
1963 text = ui.fin.read()
1967 text = ui.fin.read()
1964
1968
1965 cl = repo.changelog
1969 cl = repo.changelog
1966 if len(cl) > 0:
1970 if len(cl) > 0:
1967 raise error.Abort(_('repository is not empty'))
1971 raise error.Abort(_('repository is not empty'))
1968
1972
1969 # determine number of revs in DAG
1973 # determine number of revs in DAG
1970 total = 0
1974 total = 0
1971 for type, data in dagparser.parsedag(text):
1975 for type, data in dagparser.parsedag(text):
1972 if type == 'n':
1976 if type == 'n':
1973 total += 1
1977 total += 1
1974
1978
1975 if mergeable_file:
1979 if mergeable_file:
1976 linesperrev = 2
1980 linesperrev = 2
1977 # make a file with k lines per rev
1981 # make a file with k lines per rev
1978 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1982 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1979 initialmergedlines.append("")
1983 initialmergedlines.append("")
1980
1984
1981 tags = []
1985 tags = []
1982
1986
1983 lock = tr = None
1987 lock = tr = None
1984 try:
1988 try:
1985 lock = repo.lock()
1989 lock = repo.lock()
1986 tr = repo.transaction("builddag")
1990 tr = repo.transaction("builddag")
1987
1991
1988 at = -1
1992 at = -1
1989 atbranch = 'default'
1993 atbranch = 'default'
1990 nodeids = []
1994 nodeids = []
1991 id = 0
1995 id = 0
1992 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1996 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1993 for type, data in dagparser.parsedag(text):
1997 for type, data in dagparser.parsedag(text):
1994 if type == 'n':
1998 if type == 'n':
1995 ui.note(('node %s\n' % str(data)))
1999 ui.note(('node %s\n' % str(data)))
1996 id, ps = data
2000 id, ps = data
1997
2001
1998 files = []
2002 files = []
1999 fctxs = {}
2003 fctxs = {}
2000
2004
2001 p2 = None
2005 p2 = None
2002 if mergeable_file:
2006 if mergeable_file:
2003 fn = "mf"
2007 fn = "mf"
2004 p1 = repo[ps[0]]
2008 p1 = repo[ps[0]]
2005 if len(ps) > 1:
2009 if len(ps) > 1:
2006 p2 = repo[ps[1]]
2010 p2 = repo[ps[1]]
2007 pa = p1.ancestor(p2)
2011 pa = p1.ancestor(p2)
2008 base, local, other = [x[fn].data() for x in (pa, p1,
2012 base, local, other = [x[fn].data() for x in (pa, p1,
2009 p2)]
2013 p2)]
2010 m3 = simplemerge.Merge3Text(base, local, other)
2014 m3 = simplemerge.Merge3Text(base, local, other)
2011 ml = [l.strip() for l in m3.merge_lines()]
2015 ml = [l.strip() for l in m3.merge_lines()]
2012 ml.append("")
2016 ml.append("")
2013 elif at > 0:
2017 elif at > 0:
2014 ml = p1[fn].data().split("\n")
2018 ml = p1[fn].data().split("\n")
2015 else:
2019 else:
2016 ml = initialmergedlines
2020 ml = initialmergedlines
2017 ml[id * linesperrev] += " r%i" % id
2021 ml[id * linesperrev] += " r%i" % id
2018 mergedtext = "\n".join(ml)
2022 mergedtext = "\n".join(ml)
2019 files.append(fn)
2023 files.append(fn)
2020 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2024 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
2021
2025
2022 if overwritten_file:
2026 if overwritten_file:
2023 fn = "of"
2027 fn = "of"
2024 files.append(fn)
2028 files.append(fn)
2025 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2029 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2026
2030
2027 if new_file:
2031 if new_file:
2028 fn = "nf%i" % id
2032 fn = "nf%i" % id
2029 files.append(fn)
2033 files.append(fn)
2030 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2034 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
2031 if len(ps) > 1:
2035 if len(ps) > 1:
2032 if not p2:
2036 if not p2:
2033 p2 = repo[ps[1]]
2037 p2 = repo[ps[1]]
2034 for fn in p2:
2038 for fn in p2:
2035 if fn.startswith("nf"):
2039 if fn.startswith("nf"):
2036 files.append(fn)
2040 files.append(fn)
2037 fctxs[fn] = p2[fn]
2041 fctxs[fn] = p2[fn]
2038
2042
2039 def fctxfn(repo, cx, path):
2043 def fctxfn(repo, cx, path):
2040 return fctxs.get(path)
2044 return fctxs.get(path)
2041
2045
2042 if len(ps) == 0 or ps[0] < 0:
2046 if len(ps) == 0 or ps[0] < 0:
2043 pars = [None, None]
2047 pars = [None, None]
2044 elif len(ps) == 1:
2048 elif len(ps) == 1:
2045 pars = [nodeids[ps[0]], None]
2049 pars = [nodeids[ps[0]], None]
2046 else:
2050 else:
2047 pars = [nodeids[p] for p in ps]
2051 pars = [nodeids[p] for p in ps]
2048 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2052 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
2049 date=(id, 0),
2053 date=(id, 0),
2050 user="debugbuilddag",
2054 user="debugbuilddag",
2051 extra={'branch': atbranch})
2055 extra={'branch': atbranch})
2052 nodeid = repo.commitctx(cx)
2056 nodeid = repo.commitctx(cx)
2053 nodeids.append(nodeid)
2057 nodeids.append(nodeid)
2054 at = id
2058 at = id
2055 elif type == 'l':
2059 elif type == 'l':
2056 id, name = data
2060 id, name = data
2057 ui.note(('tag %s\n' % name))
2061 ui.note(('tag %s\n' % name))
2058 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2062 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2059 elif type == 'a':
2063 elif type == 'a':
2060 ui.note(('branch %s\n' % data))
2064 ui.note(('branch %s\n' % data))
2061 atbranch = data
2065 atbranch = data
2062 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2066 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2063 tr.close()
2067 tr.close()
2064
2068
2065 if tags:
2069 if tags:
2066 repo.vfs.write("localtags", "".join(tags))
2070 repo.vfs.write("localtags", "".join(tags))
2067 finally:
2071 finally:
2068 ui.progress(_('building'), None)
2072 ui.progress(_('building'), None)
2069 release(tr, lock)
2073 release(tr, lock)
2070
2074
2071 @command('debugbundle',
2075 @command('debugbundle',
2072 [('a', 'all', None, _('show all details')),
2076 [('a', 'all', None, _('show all details')),
2073 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2077 ('', 'spec', None, _('print the bundlespec of the bundle'))],
2074 _('FILE'),
2078 _('FILE'),
2075 norepo=True)
2079 norepo=True)
2076 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2080 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
2077 """lists the contents of a bundle"""
2081 """lists the contents of a bundle"""
2078 with hg.openpath(ui, bundlepath) as f:
2082 with hg.openpath(ui, bundlepath) as f:
2079 if spec:
2083 if spec:
2080 spec = exchange.getbundlespec(ui, f)
2084 spec = exchange.getbundlespec(ui, f)
2081 ui.write('%s\n' % spec)
2085 ui.write('%s\n' % spec)
2082 return
2086 return
2083
2087
2084 gen = exchange.readbundle(ui, f, bundlepath)
2088 gen = exchange.readbundle(ui, f, bundlepath)
2085 if isinstance(gen, bundle2.unbundle20):
2089 if isinstance(gen, bundle2.unbundle20):
2086 return _debugbundle2(ui, gen, all=all, **opts)
2090 return _debugbundle2(ui, gen, all=all, **opts)
2087 if all:
2091 if all:
2088 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"))
2089
2093
2090 def showchunks(named):
2094 def showchunks(named):
2091 ui.write("\n%s\n" % named)
2095 ui.write("\n%s\n" % named)
2092 chain = None
2096 chain = None
2093 while True:
2097 while True:
2094 chunkdata = gen.deltachunk(chain)
2098 chunkdata = gen.deltachunk(chain)
2095 if not chunkdata:
2099 if not chunkdata:
2096 break
2100 break
2097 node = chunkdata['node']
2101 node = chunkdata['node']
2098 p1 = chunkdata['p1']
2102 p1 = chunkdata['p1']
2099 p2 = chunkdata['p2']
2103 p2 = chunkdata['p2']
2100 cs = chunkdata['cs']
2104 cs = chunkdata['cs']
2101 deltabase = chunkdata['deltabase']
2105 deltabase = chunkdata['deltabase']
2102 delta = chunkdata['delta']
2106 delta = chunkdata['delta']
2103 ui.write("%s %s %s %s %s %s\n" %
2107 ui.write("%s %s %s %s %s %s\n" %
2104 (hex(node), hex(p1), hex(p2),
2108 (hex(node), hex(p1), hex(p2),
2105 hex(cs), hex(deltabase), len(delta)))
2109 hex(cs), hex(deltabase), len(delta)))
2106 chain = node
2110 chain = node
2107
2111
2108 chunkdata = gen.changelogheader()
2112 chunkdata = gen.changelogheader()
2109 showchunks("changelog")
2113 showchunks("changelog")
2110 chunkdata = gen.manifestheader()
2114 chunkdata = gen.manifestheader()
2111 showchunks("manifest")
2115 showchunks("manifest")
2112 while True:
2116 while True:
2113 chunkdata = gen.filelogheader()
2117 chunkdata = gen.filelogheader()
2114 if not chunkdata:
2118 if not chunkdata:
2115 break
2119 break
2116 fname = chunkdata['filename']
2120 fname = chunkdata['filename']
2117 showchunks(fname)
2121 showchunks(fname)
2118 else:
2122 else:
2119 if isinstance(gen, bundle2.unbundle20):
2123 if isinstance(gen, bundle2.unbundle20):
2120 raise error.Abort(_('use debugbundle2 for this file'))
2124 raise error.Abort(_('use debugbundle2 for this file'))
2121 chunkdata = gen.changelogheader()
2125 chunkdata = gen.changelogheader()
2122 chain = None
2126 chain = None
2123 while True:
2127 while True:
2124 chunkdata = gen.deltachunk(chain)
2128 chunkdata = gen.deltachunk(chain)
2125 if not chunkdata:
2129 if not chunkdata:
2126 break
2130 break
2127 node = chunkdata['node']
2131 node = chunkdata['node']
2128 ui.write("%s\n" % hex(node))
2132 ui.write("%s\n" % hex(node))
2129 chain = node
2133 chain = node
2130
2134
2131 def _debugbundle2(ui, gen, **opts):
2135 def _debugbundle2(ui, gen, **opts):
2132 """lists the contents of a bundle2"""
2136 """lists the contents of a bundle2"""
2133 if not isinstance(gen, bundle2.unbundle20):
2137 if not isinstance(gen, bundle2.unbundle20):
2134 raise error.Abort(_('not a bundle2 file'))
2138 raise error.Abort(_('not a bundle2 file'))
2135 ui.write(('Stream params: %s\n' % repr(gen.params)))
2139 ui.write(('Stream params: %s\n' % repr(gen.params)))
2136 for part in gen.iterparts():
2140 for part in gen.iterparts():
2137 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2141 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2138 if part.type == 'changegroup':
2142 if part.type == 'changegroup':
2139 version = part.params.get('version', '01')
2143 version = part.params.get('version', '01')
2140 cg = changegroup.getunbundler(version, part, 'UN')
2144 cg = changegroup.getunbundler(version, part, 'UN')
2141 chunkdata = cg.changelogheader()
2145 chunkdata = cg.changelogheader()
2142 chain = None
2146 chain = None
2143 while True:
2147 while True:
2144 chunkdata = cg.deltachunk(chain)
2148 chunkdata = cg.deltachunk(chain)
2145 if not chunkdata:
2149 if not chunkdata:
2146 break
2150 break
2147 node = chunkdata['node']
2151 node = chunkdata['node']
2148 ui.write(" %s\n" % hex(node))
2152 ui.write(" %s\n" % hex(node))
2149 chain = node
2153 chain = node
2150
2154
2151 @command('debugcreatestreamclonebundle', [], 'FILE')
2155 @command('debugcreatestreamclonebundle', [], 'FILE')
2152 def debugcreatestreamclonebundle(ui, repo, fname):
2156 def debugcreatestreamclonebundle(ui, repo, fname):
2153 """create a stream clone bundle file
2157 """create a stream clone bundle file
2154
2158
2155 Stream bundles are special bundles that are essentially archives of
2159 Stream bundles are special bundles that are essentially archives of
2156 revlog files. They are commonly used for cloning very quickly.
2160 revlog files. They are commonly used for cloning very quickly.
2157 """
2161 """
2158 requirements, gen = streamclone.generatebundlev1(repo)
2162 requirements, gen = streamclone.generatebundlev1(repo)
2159 changegroup.writechunks(ui, gen, fname)
2163 changegroup.writechunks(ui, gen, fname)
2160
2164
2161 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2165 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2162
2166
2163 @command('debugapplystreamclonebundle', [], 'FILE')
2167 @command('debugapplystreamclonebundle', [], 'FILE')
2164 def debugapplystreamclonebundle(ui, repo, fname):
2168 def debugapplystreamclonebundle(ui, repo, fname):
2165 """apply a stream clone bundle file"""
2169 """apply a stream clone bundle file"""
2166 f = hg.openpath(ui, fname)
2170 f = hg.openpath(ui, fname)
2167 gen = exchange.readbundle(ui, f, fname)
2171 gen = exchange.readbundle(ui, f, fname)
2168 gen.apply(repo)
2172 gen.apply(repo)
2169
2173
2170 @command('debugcheckstate', [], '')
2174 @command('debugcheckstate', [], '')
2171 def debugcheckstate(ui, repo):
2175 def debugcheckstate(ui, repo):
2172 """validate the correctness of the current dirstate"""
2176 """validate the correctness of the current dirstate"""
2173 parent1, parent2 = repo.dirstate.parents()
2177 parent1, parent2 = repo.dirstate.parents()
2174 m1 = repo[parent1].manifest()
2178 m1 = repo[parent1].manifest()
2175 m2 = repo[parent2].manifest()
2179 m2 = repo[parent2].manifest()
2176 errors = 0
2180 errors = 0
2177 for f in repo.dirstate:
2181 for f in repo.dirstate:
2178 state = repo.dirstate[f]
2182 state = repo.dirstate[f]
2179 if state in "nr" and f not in m1:
2183 if state in "nr" and f not in m1:
2180 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))
2181 errors += 1
2185 errors += 1
2182 if state in "a" and f in m1:
2186 if state in "a" and f in m1:
2183 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))
2184 errors += 1
2188 errors += 1
2185 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:
2186 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") %
2187 (f, state))
2191 (f, state))
2188 errors += 1
2192 errors += 1
2189 for f in m1:
2193 for f in m1:
2190 state = repo.dirstate[f]
2194 state = repo.dirstate[f]
2191 if state not in "nrm":
2195 if state not in "nrm":
2192 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))
2193 errors += 1
2197 errors += 1
2194 if errors:
2198 if errors:
2195 error = _(".hg/dirstate inconsistent with current parent's manifest")
2199 error = _(".hg/dirstate inconsistent with current parent's manifest")
2196 raise error.Abort(error)
2200 raise error.Abort(error)
2197
2201
2198 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2202 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2199 def debugcommands(ui, cmd='', *args):
2203 def debugcommands(ui, cmd='', *args):
2200 """list all available commands and options"""
2204 """list all available commands and options"""
2201 for cmd, vals in sorted(table.iteritems()):
2205 for cmd, vals in sorted(table.iteritems()):
2202 cmd = cmd.split('|')[0].strip('^')
2206 cmd = cmd.split('|')[0].strip('^')
2203 opts = ', '.join([i[1] for i in vals[1]])
2207 opts = ', '.join([i[1] for i in vals[1]])
2204 ui.write('%s: %s\n' % (cmd, opts))
2208 ui.write('%s: %s\n' % (cmd, opts))
2205
2209
2206 @command('debugcomplete',
2210 @command('debugcomplete',
2207 [('o', 'options', None, _('show the command options'))],
2211 [('o', 'options', None, _('show the command options'))],
2208 _('[-o] CMD'),
2212 _('[-o] CMD'),
2209 norepo=True)
2213 norepo=True)
2210 def debugcomplete(ui, cmd='', **opts):
2214 def debugcomplete(ui, cmd='', **opts):
2211 """returns the completion list associated with the given command"""
2215 """returns the completion list associated with the given command"""
2212
2216
2213 if opts.get('options'):
2217 if opts.get('options'):
2214 options = []
2218 options = []
2215 otables = [globalopts]
2219 otables = [globalopts]
2216 if cmd:
2220 if cmd:
2217 aliases, entry = cmdutil.findcmd(cmd, table, False)
2221 aliases, entry = cmdutil.findcmd(cmd, table, False)
2218 otables.append(entry[1])
2222 otables.append(entry[1])
2219 for t in otables:
2223 for t in otables:
2220 for o in t:
2224 for o in t:
2221 if "(DEPRECATED)" in o[3]:
2225 if "(DEPRECATED)" in o[3]:
2222 continue
2226 continue
2223 if o[0]:
2227 if o[0]:
2224 options.append('-%s' % o[0])
2228 options.append('-%s' % o[0])
2225 options.append('--%s' % o[1])
2229 options.append('--%s' % o[1])
2226 ui.write("%s\n" % "\n".join(options))
2230 ui.write("%s\n" % "\n".join(options))
2227 return
2231 return
2228
2232
2229 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2233 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2230 if ui.verbose:
2234 if ui.verbose:
2231 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2235 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2232 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2236 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2233
2237
2234 @command('debugdag',
2238 @command('debugdag',
2235 [('t', 'tags', None, _('use tags as labels')),
2239 [('t', 'tags', None, _('use tags as labels')),
2236 ('b', 'branches', None, _('annotate with branch names')),
2240 ('b', 'branches', None, _('annotate with branch names')),
2237 ('', 'dots', None, _('use dots for runs')),
2241 ('', 'dots', None, _('use dots for runs')),
2238 ('s', 'spaces', None, _('separate elements by spaces'))],
2242 ('s', 'spaces', None, _('separate elements by spaces'))],
2239 _('[OPTION]... [FILE [REV]...]'),
2243 _('[OPTION]... [FILE [REV]...]'),
2240 optionalrepo=True)
2244 optionalrepo=True)
2241 def debugdag(ui, repo, file_=None, *revs, **opts):
2245 def debugdag(ui, repo, file_=None, *revs, **opts):
2242 """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
2243
2247
2244 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
2245 revision numbers, they get labeled in the output as rN.
2249 revision numbers, they get labeled in the output as rN.
2246
2250
2247 Otherwise, the changelog DAG of the current repo is emitted.
2251 Otherwise, the changelog DAG of the current repo is emitted.
2248 """
2252 """
2249 spaces = opts.get('spaces')
2253 spaces = opts.get('spaces')
2250 dots = opts.get('dots')
2254 dots = opts.get('dots')
2251 if file_:
2255 if file_:
2252 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2256 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 revs = set((int(r) for r in revs))
2257 revs = set((int(r) for r in revs))
2254 def events():
2258 def events():
2255 for r in rlog:
2259 for r in rlog:
2256 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2260 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2257 if p != -1))
2261 if p != -1))
2258 if r in revs:
2262 if r in revs:
2259 yield 'l', (r, "r%i" % r)
2263 yield 'l', (r, "r%i" % r)
2260 elif repo:
2264 elif repo:
2261 cl = repo.changelog
2265 cl = repo.changelog
2262 tags = opts.get('tags')
2266 tags = opts.get('tags')
2263 branches = opts.get('branches')
2267 branches = opts.get('branches')
2264 if tags:
2268 if tags:
2265 labels = {}
2269 labels = {}
2266 for l, n in repo.tags().items():
2270 for l, n in repo.tags().items():
2267 labels.setdefault(cl.rev(n), []).append(l)
2271 labels.setdefault(cl.rev(n), []).append(l)
2268 def events():
2272 def events():
2269 b = "default"
2273 b = "default"
2270 for r in cl:
2274 for r in cl:
2271 if branches:
2275 if branches:
2272 newb = cl.read(cl.node(r))[5]['branch']
2276 newb = cl.read(cl.node(r))[5]['branch']
2273 if newb != b:
2277 if newb != b:
2274 yield 'a', newb
2278 yield 'a', newb
2275 b = newb
2279 b = newb
2276 yield 'n', (r, list(p for p in cl.parentrevs(r)
2280 yield 'n', (r, list(p for p in cl.parentrevs(r)
2277 if p != -1))
2281 if p != -1))
2278 if tags:
2282 if tags:
2279 ls = labels.get(r)
2283 ls = labels.get(r)
2280 if ls:
2284 if ls:
2281 for l in ls:
2285 for l in ls:
2282 yield 'l', (r, l)
2286 yield 'l', (r, l)
2283 else:
2287 else:
2284 raise error.Abort(_('need repo for changelog dag'))
2288 raise error.Abort(_('need repo for changelog dag'))
2285
2289
2286 for line in dagparser.dagtextlines(events(),
2290 for line in dagparser.dagtextlines(events(),
2287 addspaces=spaces,
2291 addspaces=spaces,
2288 wraplabels=True,
2292 wraplabels=True,
2289 wrapannotations=True,
2293 wrapannotations=True,
2290 wrapnonlinear=dots,
2294 wrapnonlinear=dots,
2291 usedots=dots,
2295 usedots=dots,
2292 maxlinewidth=70):
2296 maxlinewidth=70):
2293 ui.write(line)
2297 ui.write(line)
2294 ui.write("\n")
2298 ui.write("\n")
2295
2299
2296 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2300 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2297 def debugdata(ui, repo, file_, rev=None, **opts):
2301 def debugdata(ui, repo, file_, rev=None, **opts):
2298 """dump the contents of a data file revision"""
2302 """dump the contents of a data file revision"""
2299 if opts.get('changelog') or opts.get('manifest'):
2303 if opts.get('changelog') or opts.get('manifest'):
2300 file_, rev = None, file_
2304 file_, rev = None, file_
2301 elif rev is None:
2305 elif rev is None:
2302 raise error.CommandError('debugdata', _('invalid arguments'))
2306 raise error.CommandError('debugdata', _('invalid arguments'))
2303 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2307 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2304 try:
2308 try:
2305 ui.write(r.revision(r.lookup(rev)))
2309 ui.write(r.revision(r.lookup(rev)))
2306 except KeyError:
2310 except KeyError:
2307 raise error.Abort(_('invalid revision identifier %s') % rev)
2311 raise error.Abort(_('invalid revision identifier %s') % rev)
2308
2312
2309 @command('debugdate',
2313 @command('debugdate',
2310 [('e', 'extended', None, _('try extended date formats'))],
2314 [('e', 'extended', None, _('try extended date formats'))],
2311 _('[-e] DATE [RANGE]'),
2315 _('[-e] DATE [RANGE]'),
2312 norepo=True, optionalrepo=True)
2316 norepo=True, optionalrepo=True)
2313 def debugdate(ui, date, range=None, **opts):
2317 def debugdate(ui, date, range=None, **opts):
2314 """parse and display a date"""
2318 """parse and display a date"""
2315 if opts["extended"]:
2319 if opts["extended"]:
2316 d = util.parsedate(date, util.extendeddateformats)
2320 d = util.parsedate(date, util.extendeddateformats)
2317 else:
2321 else:
2318 d = util.parsedate(date)
2322 d = util.parsedate(date)
2319 ui.write(("internal: %s %s\n") % d)
2323 ui.write(("internal: %s %s\n") % d)
2320 ui.write(("standard: %s\n") % util.datestr(d))
2324 ui.write(("standard: %s\n") % util.datestr(d))
2321 if range:
2325 if range:
2322 m = util.matchdate(range)
2326 m = util.matchdate(range)
2323 ui.write(("match: %s\n") % m(d[0]))
2327 ui.write(("match: %s\n") % m(d[0]))
2324
2328
2325 @command('debugdiscovery',
2329 @command('debugdiscovery',
2326 [('', 'old', None, _('use old-style discovery')),
2330 [('', 'old', None, _('use old-style discovery')),
2327 ('', 'nonheads', None,
2331 ('', 'nonheads', None,
2328 _('use old-style discovery with non-heads included')),
2332 _('use old-style discovery with non-heads included')),
2329 ] + remoteopts,
2333 ] + remoteopts,
2330 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2334 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2331 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2335 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2332 """runs the changeset discovery protocol in isolation"""
2336 """runs the changeset discovery protocol in isolation"""
2333 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2337 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2334 opts.get('branch'))
2338 opts.get('branch'))
2335 remote = hg.peer(repo, opts, remoteurl)
2339 remote = hg.peer(repo, opts, remoteurl)
2336 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2340 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2337
2341
2338 # make sure tests are repeatable
2342 # make sure tests are repeatable
2339 random.seed(12323)
2343 random.seed(12323)
2340
2344
2341 def doit(localheads, remoteheads, remote=remote):
2345 def doit(localheads, remoteheads, remote=remote):
2342 if opts.get('old'):
2346 if opts.get('old'):
2343 if localheads:
2347 if localheads:
2344 raise error.Abort('cannot use localheads with old style '
2348 raise error.Abort('cannot use localheads with old style '
2345 'discovery')
2349 'discovery')
2346 if not util.safehasattr(remote, 'branches'):
2350 if not util.safehasattr(remote, 'branches'):
2347 # enable in-client legacy support
2351 # enable in-client legacy support
2348 remote = localrepo.locallegacypeer(remote.local())
2352 remote = localrepo.locallegacypeer(remote.local())
2349 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2353 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2350 force=True)
2354 force=True)
2351 common = set(common)
2355 common = set(common)
2352 if not opts.get('nonheads'):
2356 if not opts.get('nonheads'):
2353 ui.write(("unpruned common: %s\n") %
2357 ui.write(("unpruned common: %s\n") %
2354 " ".join(sorted(short(n) for n in common)))
2358 " ".join(sorted(short(n) for n in common)))
2355 dag = dagutil.revlogdag(repo.changelog)
2359 dag = dagutil.revlogdag(repo.changelog)
2356 all = dag.ancestorset(dag.internalizeall(common))
2360 all = dag.ancestorset(dag.internalizeall(common))
2357 common = dag.externalizeall(dag.headsetofconnecteds(all))
2361 common = dag.externalizeall(dag.headsetofconnecteds(all))
2358 else:
2362 else:
2359 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2363 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2360 common = set(common)
2364 common = set(common)
2361 rheads = set(hds)
2365 rheads = set(hds)
2362 lheads = set(repo.heads())
2366 lheads = set(repo.heads())
2363 ui.write(("common heads: %s\n") %
2367 ui.write(("common heads: %s\n") %
2364 " ".join(sorted(short(n) for n in common)))
2368 " ".join(sorted(short(n) for n in common)))
2365 if lheads <= common:
2369 if lheads <= common:
2366 ui.write(("local is subset\n"))
2370 ui.write(("local is subset\n"))
2367 elif rheads <= common:
2371 elif rheads <= common:
2368 ui.write(("remote is subset\n"))
2372 ui.write(("remote is subset\n"))
2369
2373
2370 serverlogs = opts.get('serverlog')
2374 serverlogs = opts.get('serverlog')
2371 if serverlogs:
2375 if serverlogs:
2372 for filename in serverlogs:
2376 for filename in serverlogs:
2373 with open(filename, 'r') as logfile:
2377 with open(filename, 'r') as logfile:
2374 line = logfile.readline()
2378 line = logfile.readline()
2375 while line:
2379 while line:
2376 parts = line.strip().split(';')
2380 parts = line.strip().split(';')
2377 op = parts[1]
2381 op = parts[1]
2378 if op == 'cg':
2382 if op == 'cg':
2379 pass
2383 pass
2380 elif op == 'cgss':
2384 elif op == 'cgss':
2381 doit(parts[2].split(' '), parts[3].split(' '))
2385 doit(parts[2].split(' '), parts[3].split(' '))
2382 elif op == 'unb':
2386 elif op == 'unb':
2383 doit(parts[3].split(' '), parts[2].split(' '))
2387 doit(parts[3].split(' '), parts[2].split(' '))
2384 line = logfile.readline()
2388 line = logfile.readline()
2385 else:
2389 else:
2386 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2390 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2387 opts.get('remote_head'))
2391 opts.get('remote_head'))
2388 localrevs = opts.get('local_head')
2392 localrevs = opts.get('local_head')
2389 doit(localrevs, remoterevs)
2393 doit(localrevs, remoterevs)
2390
2394
2391 @command('debugextensions', formatteropts, [], norepo=True)
2395 @command('debugextensions', formatteropts, [], norepo=True)
2392 def debugextensions(ui, **opts):
2396 def debugextensions(ui, **opts):
2393 '''show information about active extensions'''
2397 '''show information about active extensions'''
2394 exts = extensions.extensions(ui)
2398 exts = extensions.extensions(ui)
2395 fm = ui.formatter('debugextensions', opts)
2399 fm = ui.formatter('debugextensions', opts)
2396 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2400 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2397 extsource = extmod.__file__
2401 extsource = extmod.__file__
2398 exttestedwith = getattr(extmod, 'testedwith', None)
2402 exttestedwith = getattr(extmod, 'testedwith', None)
2399 if exttestedwith is not None:
2403 if exttestedwith is not None:
2400 exttestedwith = exttestedwith.split()
2404 exttestedwith = exttestedwith.split()
2401 extbuglink = getattr(extmod, 'buglink', None)
2405 extbuglink = getattr(extmod, 'buglink', None)
2402
2406
2403 fm.startitem()
2407 fm.startitem()
2404
2408
2405 if ui.quiet or ui.verbose:
2409 if ui.quiet or ui.verbose:
2406 fm.write('name', '%s\n', extname)
2410 fm.write('name', '%s\n', extname)
2407 else:
2411 else:
2408 fm.write('name', '%s', extname)
2412 fm.write('name', '%s', extname)
2409 if not exttestedwith:
2413 if not exttestedwith:
2410 fm.plain(_(' (untested!)\n'))
2414 fm.plain(_(' (untested!)\n'))
2411 else:
2415 else:
2412 if exttestedwith == ['internal'] or \
2416 if exttestedwith == ['internal'] or \
2413 util.version() in exttestedwith:
2417 util.version() in exttestedwith:
2414 fm.plain('\n')
2418 fm.plain('\n')
2415 else:
2419 else:
2416 lasttestedversion = exttestedwith[-1]
2420 lasttestedversion = exttestedwith[-1]
2417 fm.plain(' (%s!)\n' % lasttestedversion)
2421 fm.plain(' (%s!)\n' % lasttestedversion)
2418
2422
2419 fm.condwrite(ui.verbose and extsource, 'source',
2423 fm.condwrite(ui.verbose and extsource, 'source',
2420 _(' location: %s\n'), extsource or "")
2424 _(' location: %s\n'), extsource or "")
2421
2425
2422 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2426 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2423 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2427 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2424
2428
2425 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2429 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2426 _(' bug reporting: %s\n'), extbuglink or "")
2430 _(' bug reporting: %s\n'), extbuglink or "")
2427
2431
2428 fm.end()
2432 fm.end()
2429
2433
2430 @command('debugfileset',
2434 @command('debugfileset',
2431 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2435 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2432 _('[-r REV] FILESPEC'))
2436 _('[-r REV] FILESPEC'))
2433 def debugfileset(ui, repo, expr, **opts):
2437 def debugfileset(ui, repo, expr, **opts):
2434 '''parse and apply a fileset specification'''
2438 '''parse and apply a fileset specification'''
2435 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2439 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2436 if ui.verbose:
2440 if ui.verbose:
2437 tree = fileset.parse(expr)
2441 tree = fileset.parse(expr)
2438 ui.note(fileset.prettyformat(tree), "\n")
2442 ui.note(fileset.prettyformat(tree), "\n")
2439
2443
2440 for f in ctx.getfileset(expr):
2444 for f in ctx.getfileset(expr):
2441 ui.write("%s\n" % f)
2445 ui.write("%s\n" % f)
2442
2446
2443 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2447 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2444 def debugfsinfo(ui, path="."):
2448 def debugfsinfo(ui, path="."):
2445 """show information detected about current filesystem"""
2449 """show information detected about current filesystem"""
2446 util.writefile('.debugfsinfo', '')
2450 util.writefile('.debugfsinfo', '')
2447 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'))
2448 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'))
2449 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'))
2450 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2454 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2451 and 'yes' or 'no'))
2455 and 'yes' or 'no'))
2452 os.unlink('.debugfsinfo')
2456 os.unlink('.debugfsinfo')
2453
2457
2454 @command('debuggetbundle',
2458 @command('debuggetbundle',
2455 [('H', 'head', [], _('id of head node'), _('ID')),
2459 [('H', 'head', [], _('id of head node'), _('ID')),
2456 ('C', 'common', [], _('id of common node'), _('ID')),
2460 ('C', 'common', [], _('id of common node'), _('ID')),
2457 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2461 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2458 _('REPO FILE [-H|-C ID]...'),
2462 _('REPO FILE [-H|-C ID]...'),
2459 norepo=True)
2463 norepo=True)
2460 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2464 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2461 """retrieves a bundle from a repo
2465 """retrieves a bundle from a repo
2462
2466
2463 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
2464 given file.
2468 given file.
2465 """
2469 """
2466 repo = hg.peer(ui, opts, repopath)
2470 repo = hg.peer(ui, opts, repopath)
2467 if not repo.capable('getbundle'):
2471 if not repo.capable('getbundle'):
2468 raise error.Abort("getbundle() not supported by target repository")
2472 raise error.Abort("getbundle() not supported by target repository")
2469 args = {}
2473 args = {}
2470 if common:
2474 if common:
2471 args['common'] = [bin(s) for s in common]
2475 args['common'] = [bin(s) for s in common]
2472 if head:
2476 if head:
2473 args['heads'] = [bin(s) for s in head]
2477 args['heads'] = [bin(s) for s in head]
2474 # TODO: get desired bundlecaps from command line.
2478 # TODO: get desired bundlecaps from command line.
2475 args['bundlecaps'] = None
2479 args['bundlecaps'] = None
2476 bundle = repo.getbundle('debug', **args)
2480 bundle = repo.getbundle('debug', **args)
2477
2481
2478 bundletype = opts.get('type', 'bzip2').lower()
2482 bundletype = opts.get('type', 'bzip2').lower()
2479 btypes = {'none': 'HG10UN',
2483 btypes = {'none': 'HG10UN',
2480 'bzip2': 'HG10BZ',
2484 'bzip2': 'HG10BZ',
2481 'gzip': 'HG10GZ',
2485 'gzip': 'HG10GZ',
2482 'bundle2': 'HG20'}
2486 'bundle2': 'HG20'}
2483 bundletype = btypes.get(bundletype)
2487 bundletype = btypes.get(bundletype)
2484 if bundletype not in bundle2.bundletypes:
2488 if bundletype not in bundle2.bundletypes:
2485 raise error.Abort(_('unknown bundle type specified with --type'))
2489 raise error.Abort(_('unknown bundle type specified with --type'))
2486 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2490 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
2487
2491
2488 @command('debugignore', [], '[FILE]')
2492 @command('debugignore', [], '[FILE]')
2489 def debugignore(ui, repo, *files, **opts):
2493 def debugignore(ui, repo, *files, **opts):
2490 """display the combined ignore pattern and information about ignored files
2494 """display the combined ignore pattern and information about ignored files
2491
2495
2492 With no argument display the combined ignore pattern.
2496 With no argument display the combined ignore pattern.
2493
2497
2494 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
2495 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.
2496 """
2500 """
2497 ignore = repo.dirstate._ignore
2501 ignore = repo.dirstate._ignore
2498 if not files:
2502 if not files:
2499 # Show all the patterns
2503 # Show all the patterns
2500 includepat = getattr(ignore, 'includepat', None)
2504 includepat = getattr(ignore, 'includepat', None)
2501 if includepat is not None:
2505 if includepat is not None:
2502 ui.write("%s\n" % includepat)
2506 ui.write("%s\n" % includepat)
2503 else:
2507 else:
2504 raise error.Abort(_("no ignore patterns found"))
2508 raise error.Abort(_("no ignore patterns found"))
2505 else:
2509 else:
2506 for f in files:
2510 for f in files:
2507 nf = util.normpath(f)
2511 nf = util.normpath(f)
2508 ignored = None
2512 ignored = None
2509 ignoredata = None
2513 ignoredata = None
2510 if nf != '.':
2514 if nf != '.':
2511 if ignore(nf):
2515 if ignore(nf):
2512 ignored = nf
2516 ignored = nf
2513 ignoredata = repo.dirstate._ignorefileandline(nf)
2517 ignoredata = repo.dirstate._ignorefileandline(nf)
2514 else:
2518 else:
2515 for p in util.finddirs(nf):
2519 for p in util.finddirs(nf):
2516 if ignore(p):
2520 if ignore(p):
2517 ignored = p
2521 ignored = p
2518 ignoredata = repo.dirstate._ignorefileandline(p)
2522 ignoredata = repo.dirstate._ignorefileandline(p)
2519 break
2523 break
2520 if ignored:
2524 if ignored:
2521 if ignored == nf:
2525 if ignored == nf:
2522 ui.write("%s is ignored\n" % f)
2526 ui.write("%s is ignored\n" % f)
2523 else:
2527 else:
2524 ui.write("%s is ignored because of containing folder %s\n"
2528 ui.write("%s is ignored because of containing folder %s\n"
2525 % (f, ignored))
2529 % (f, ignored))
2526 ignorefile, lineno, line = ignoredata
2530 ignorefile, lineno, line = ignoredata
2527 ui.write("(ignore rule in %s, line %d: '%s')\n"
2531 ui.write("(ignore rule in %s, line %d: '%s')\n"
2528 % (ignorefile, lineno, line))
2532 % (ignorefile, lineno, line))
2529 else:
2533 else:
2530 ui.write("%s is not ignored\n" % f)
2534 ui.write("%s is not ignored\n" % f)
2531
2535
2532 @command('debugindex', debugrevlogopts +
2536 @command('debugindex', debugrevlogopts +
2533 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2537 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2534 _('[-f FORMAT] -c|-m|FILE'),
2538 _('[-f FORMAT] -c|-m|FILE'),
2535 optionalrepo=True)
2539 optionalrepo=True)
2536 def debugindex(ui, repo, file_=None, **opts):
2540 def debugindex(ui, repo, file_=None, **opts):
2537 """dump the contents of an index file"""
2541 """dump the contents of an index file"""
2538 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2542 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2539 format = opts.get('format', 0)
2543 format = opts.get('format', 0)
2540 if format not in (0, 1):
2544 if format not in (0, 1):
2541 raise error.Abort(_("unknown format %d") % format)
2545 raise error.Abort(_("unknown format %d") % format)
2542
2546
2543 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2547 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2544 if generaldelta:
2548 if generaldelta:
2545 basehdr = ' delta'
2549 basehdr = ' delta'
2546 else:
2550 else:
2547 basehdr = ' base'
2551 basehdr = ' base'
2548
2552
2549 if ui.debugflag:
2553 if ui.debugflag:
2550 shortfn = hex
2554 shortfn = hex
2551 else:
2555 else:
2552 shortfn = short
2556 shortfn = short
2553
2557
2554 # 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
2555 idlen = 12
2559 idlen = 12
2556 for i in r:
2560 for i in r:
2557 idlen = len(shortfn(r.node(i)))
2561 idlen = len(shortfn(r.node(i)))
2558 break
2562 break
2559
2563
2560 if format == 0:
2564 if format == 0:
2561 ui.write(" rev offset length " + basehdr + " linkrev"
2565 ui.write(" rev offset length " + basehdr + " linkrev"
2562 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2566 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2563 elif format == 1:
2567 elif format == 1:
2564 ui.write(" rev flag offset length"
2568 ui.write(" rev flag offset length"
2565 " size " + basehdr + " link p1 p2"
2569 " size " + basehdr + " link p1 p2"
2566 " %s\n" % "nodeid".rjust(idlen))
2570 " %s\n" % "nodeid".rjust(idlen))
2567
2571
2568 for i in r:
2572 for i in r:
2569 node = r.node(i)
2573 node = r.node(i)
2570 if generaldelta:
2574 if generaldelta:
2571 base = r.deltaparent(i)
2575 base = r.deltaparent(i)
2572 else:
2576 else:
2573 base = r.chainbase(i)
2577 base = r.chainbase(i)
2574 if format == 0:
2578 if format == 0:
2575 try:
2579 try:
2576 pp = r.parents(node)
2580 pp = r.parents(node)
2577 except Exception:
2581 except Exception:
2578 pp = [nullid, nullid]
2582 pp = [nullid, nullid]
2579 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2583 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2580 i, r.start(i), r.length(i), base, r.linkrev(i),
2584 i, r.start(i), r.length(i), base, r.linkrev(i),
2581 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2585 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2582 elif format == 1:
2586 elif format == 1:
2583 pr = r.parentrevs(i)
2587 pr = r.parentrevs(i)
2584 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" % (
2585 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),
2586 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2590 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2587
2591
2588 @command('debugindexdot', debugrevlogopts,
2592 @command('debugindexdot', debugrevlogopts,
2589 _('-c|-m|FILE'), optionalrepo=True)
2593 _('-c|-m|FILE'), optionalrepo=True)
2590 def debugindexdot(ui, repo, file_=None, **opts):
2594 def debugindexdot(ui, repo, file_=None, **opts):
2591 """dump an index DAG as a graphviz dot file"""
2595 """dump an index DAG as a graphviz dot file"""
2592 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2596 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2593 ui.write(("digraph G {\n"))
2597 ui.write(("digraph G {\n"))
2594 for i in r:
2598 for i in r:
2595 node = r.node(i)
2599 node = r.node(i)
2596 pp = r.parents(node)
2600 pp = r.parents(node)
2597 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2601 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2598 if pp[1] != nullid:
2602 if pp[1] != nullid:
2599 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2603 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2600 ui.write("}\n")
2604 ui.write("}\n")
2601
2605
2602 @command('debugdeltachain',
2606 @command('debugdeltachain',
2603 debugrevlogopts + formatteropts,
2607 debugrevlogopts + formatteropts,
2604 _('-c|-m|FILE'),
2608 _('-c|-m|FILE'),
2605 optionalrepo=True)
2609 optionalrepo=True)
2606 def debugdeltachain(ui, repo, file_=None, **opts):
2610 def debugdeltachain(ui, repo, file_=None, **opts):
2607 """dump information about delta chains in a revlog
2611 """dump information about delta chains in a revlog
2608
2612
2609 Output can be templatized. Available template keywords are:
2613 Output can be templatized. Available template keywords are:
2610
2614
2611 rev revision number
2615 rev revision number
2612 chainid delta chain identifier (numbered by unique base)
2616 chainid delta chain identifier (numbered by unique base)
2613 chainlen delta chain length to this revision
2617 chainlen delta chain length to this revision
2614 prevrev previous revision in delta chain
2618 prevrev previous revision in delta chain
2615 deltatype role of delta / how it was computed
2619 deltatype role of delta / how it was computed
2616 compsize compressed size of revision
2620 compsize compressed size of revision
2617 uncompsize uncompressed size of revision
2621 uncompsize uncompressed size of revision
2618 chainsize total size of compressed revisions in chain
2622 chainsize total size of compressed revisions in chain
2619 chainratio total chain size divided by uncompressed revision size
2623 chainratio total chain size divided by uncompressed revision size
2620 (new delta chains typically start at ratio 2.00)
2624 (new delta chains typically start at ratio 2.00)
2621 lindist linear distance from base revision in delta chain to end
2625 lindist linear distance from base revision in delta chain to end
2622 of this revision
2626 of this revision
2623 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
2624 base of delta chain to end of this revision; a measurement
2628 base of delta chain to end of this revision; a measurement
2625 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
2626 the delta chain for this revision
2630 the delta chain for this revision
2627 extraratio extradist divided by chainsize; another representation of
2631 extraratio extradist divided by chainsize; another representation of
2628 how much unrelated data is needed to load this delta chain
2632 how much unrelated data is needed to load this delta chain
2629 """
2633 """
2630 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2634 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2631 index = r.index
2635 index = r.index
2632 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2636 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2633
2637
2634 def revinfo(rev):
2638 def revinfo(rev):
2635 e = index[rev]
2639 e = index[rev]
2636 compsize = e[1]
2640 compsize = e[1]
2637 uncompsize = e[2]
2641 uncompsize = e[2]
2638 chainsize = 0
2642 chainsize = 0
2639
2643
2640 if generaldelta:
2644 if generaldelta:
2641 if e[3] == e[5]:
2645 if e[3] == e[5]:
2642 deltatype = 'p1'
2646 deltatype = 'p1'
2643 elif e[3] == e[6]:
2647 elif e[3] == e[6]:
2644 deltatype = 'p2'
2648 deltatype = 'p2'
2645 elif e[3] == rev - 1:
2649 elif e[3] == rev - 1:
2646 deltatype = 'prev'
2650 deltatype = 'prev'
2647 elif e[3] == rev:
2651 elif e[3] == rev:
2648 deltatype = 'base'
2652 deltatype = 'base'
2649 else:
2653 else:
2650 deltatype = 'other'
2654 deltatype = 'other'
2651 else:
2655 else:
2652 if e[3] == rev:
2656 if e[3] == rev:
2653 deltatype = 'base'
2657 deltatype = 'base'
2654 else:
2658 else:
2655 deltatype = 'prev'
2659 deltatype = 'prev'
2656
2660
2657 chain = r._deltachain(rev)[0]
2661 chain = r._deltachain(rev)[0]
2658 for iterrev in chain:
2662 for iterrev in chain:
2659 e = index[iterrev]
2663 e = index[iterrev]
2660 chainsize += e[1]
2664 chainsize += e[1]
2661
2665
2662 return compsize, uncompsize, deltatype, chain, chainsize
2666 return compsize, uncompsize, deltatype, chain, chainsize
2663
2667
2664 fm = ui.formatter('debugdeltachain', opts)
2668 fm = ui.formatter('debugdeltachain', opts)
2665
2669
2666 fm.plain(' rev chain# chainlen prev delta '
2670 fm.plain(' rev chain# chainlen prev delta '
2667 'size rawsize chainsize ratio lindist extradist '
2671 'size rawsize chainsize ratio lindist extradist '
2668 'extraratio\n')
2672 'extraratio\n')
2669
2673
2670 chainbases = {}
2674 chainbases = {}
2671 for rev in r:
2675 for rev in r:
2672 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2676 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2673 chainbase = chain[0]
2677 chainbase = chain[0]
2674 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2678 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2675 basestart = r.start(chainbase)
2679 basestart = r.start(chainbase)
2676 revstart = r.start(rev)
2680 revstart = r.start(rev)
2677 lineardist = revstart + comp - basestart
2681 lineardist = revstart + comp - basestart
2678 extradist = lineardist - chainsize
2682 extradist = lineardist - chainsize
2679 try:
2683 try:
2680 prevrev = chain[-2]
2684 prevrev = chain[-2]
2681 except IndexError:
2685 except IndexError:
2682 prevrev = -1
2686 prevrev = -1
2683
2687
2684 chainratio = float(chainsize) / float(uncomp)
2688 chainratio = float(chainsize) / float(uncomp)
2685 extraratio = float(extradist) / float(chainsize)
2689 extraratio = float(extradist) / float(chainsize)
2686
2690
2687 fm.startitem()
2691 fm.startitem()
2688 fm.write('rev chainid chainlen prevrev deltatype compsize '
2692 fm.write('rev chainid chainlen prevrev deltatype compsize '
2689 'uncompsize chainsize chainratio lindist extradist '
2693 'uncompsize chainsize chainratio lindist extradist '
2690 'extraratio',
2694 'extraratio',
2691 '%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',
2692 rev, chainid, len(chain), prevrev, deltatype, comp,
2696 rev, chainid, len(chain), prevrev, deltatype, comp,
2693 uncomp, chainsize, chainratio, lineardist, extradist,
2697 uncomp, chainsize, chainratio, lineardist, extradist,
2694 extraratio,
2698 extraratio,
2695 rev=rev, chainid=chainid, chainlen=len(chain),
2699 rev=rev, chainid=chainid, chainlen=len(chain),
2696 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2700 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2697 uncompsize=uncomp, chainsize=chainsize,
2701 uncompsize=uncomp, chainsize=chainsize,
2698 chainratio=chainratio, lindist=lineardist,
2702 chainratio=chainratio, lindist=lineardist,
2699 extradist=extradist, extraratio=extraratio)
2703 extradist=extradist, extraratio=extraratio)
2700
2704
2701 fm.end()
2705 fm.end()
2702
2706
2703 @command('debuginstall', [] + formatteropts, '', norepo=True)
2707 @command('debuginstall', [] + formatteropts, '', norepo=True)
2704 def debuginstall(ui, **opts):
2708 def debuginstall(ui, **opts):
2705 '''test Mercurial installation
2709 '''test Mercurial installation
2706
2710
2707 Returns 0 on success.
2711 Returns 0 on success.
2708 '''
2712 '''
2709
2713
2710 def writetemp(contents):
2714 def writetemp(contents):
2711 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2715 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2712 f = os.fdopen(fd, "wb")
2716 f = os.fdopen(fd, "wb")
2713 f.write(contents)
2717 f.write(contents)
2714 f.close()
2718 f.close()
2715 return name
2719 return name
2716
2720
2717 problems = 0
2721 problems = 0
2718
2722
2719 fm = ui.formatter('debuginstall', opts)
2723 fm = ui.formatter('debuginstall', opts)
2720 fm.startitem()
2724 fm.startitem()
2721
2725
2722 # encoding
2726 # encoding
2723 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2727 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
2724 err = None
2728 err = None
2725 try:
2729 try:
2726 encoding.fromlocal("test")
2730 encoding.fromlocal("test")
2727 except error.Abort as inst:
2731 except error.Abort as inst:
2728 err = inst
2732 err = inst
2729 problems += 1
2733 problems += 1
2730 fm.condwrite(err, 'encodingerror', _(" %s\n"
2734 fm.condwrite(err, 'encodingerror', _(" %s\n"
2731 " (check that your locale is properly set)\n"), err)
2735 " (check that your locale is properly set)\n"), err)
2732
2736
2733 # Python
2737 # Python
2734 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2738 fm.write('pythonexe', _("checking Python executable (%s)\n"),
2735 sys.executable)
2739 sys.executable)
2736 fm.write('pythonver', _("checking Python version (%s)\n"),
2740 fm.write('pythonver', _("checking Python version (%s)\n"),
2737 ("%s.%s.%s" % sys.version_info[:3]))
2741 ("%s.%s.%s" % sys.version_info[:3]))
2738 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2742 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
2739 os.path.dirname(os.__file__))
2743 os.path.dirname(os.__file__))
2740
2744
2741 # compiled modules
2745 # compiled modules
2742 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2746 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
2743 os.path.dirname(__file__))
2747 os.path.dirname(__file__))
2744
2748
2745 err = None
2749 err = None
2746 try:
2750 try:
2747 from . import (
2751 from . import (
2748 base85,
2752 base85,
2749 bdiff,
2753 bdiff,
2750 mpatch,
2754 mpatch,
2751 osutil,
2755 osutil,
2752 )
2756 )
2753 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2757 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2754 except Exception as inst:
2758 except Exception as inst:
2755 err = inst
2759 err = inst
2756 problems += 1
2760 problems += 1
2757 fm.condwrite(err, 'extensionserror', " %s\n", err)
2761 fm.condwrite(err, 'extensionserror', " %s\n", err)
2758
2762
2759 # templates
2763 # templates
2760 p = templater.templatepaths()
2764 p = templater.templatepaths()
2761 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2765 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
2762 fm.condwrite(not p, '', _(" no template directories found\n"))
2766 fm.condwrite(not p, '', _(" no template directories found\n"))
2763 if p:
2767 if p:
2764 m = templater.templatepath("map-cmdline.default")
2768 m = templater.templatepath("map-cmdline.default")
2765 if m:
2769 if m:
2766 # template found, check if it is working
2770 # template found, check if it is working
2767 err = None
2771 err = None
2768 try:
2772 try:
2769 templater.templater(m)
2773 templater.templater(m)
2770 except Exception as inst:
2774 except Exception as inst:
2771 err = inst
2775 err = inst
2772 p = None
2776 p = None
2773 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2777 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
2774 else:
2778 else:
2775 p = None
2779 p = None
2776 fm.condwrite(p, 'defaulttemplate',
2780 fm.condwrite(p, 'defaulttemplate',
2777 _("checking default template (%s)\n"), m)
2781 _("checking default template (%s)\n"), m)
2778 fm.condwrite(not m, 'defaulttemplatenotfound',
2782 fm.condwrite(not m, 'defaulttemplatenotfound',
2779 _(" template '%s' not found\n"), "default")
2783 _(" template '%s' not found\n"), "default")
2780 if not p:
2784 if not p:
2781 problems += 1
2785 problems += 1
2782 fm.condwrite(not p, '',
2786 fm.condwrite(not p, '',
2783 _(" (templates seem to have been installed incorrectly)\n"))
2787 _(" (templates seem to have been installed incorrectly)\n"))
2784
2788
2785 # editor
2789 # editor
2786 editor = ui.geteditor()
2790 editor = ui.geteditor()
2787 editor = util.expandpath(editor)
2791 editor = util.expandpath(editor)
2788 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2792 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
2789 cmdpath = util.findexe(shlex.split(editor)[0])
2793 cmdpath = util.findexe(shlex.split(editor)[0])
2790 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2794 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
2791 _(" 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"
2792 " (specify a commit editor in your configuration"
2796 " (specify a commit editor in your configuration"
2793 " file)\n"), not cmdpath and editor == 'vi' and editor)
2797 " file)\n"), not cmdpath and editor == 'vi' and editor)
2794 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2798 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
2795 _(" Can't find editor '%s' in PATH\n"
2799 _(" Can't find editor '%s' in PATH\n"
2796 " (specify a commit editor in your configuration"
2800 " (specify a commit editor in your configuration"
2797 " file)\n"), not cmdpath and editor)
2801 " file)\n"), not cmdpath and editor)
2798 if not cmdpath and editor != 'vi':
2802 if not cmdpath and editor != 'vi':
2799 problems += 1
2803 problems += 1
2800
2804
2801 # check username
2805 # check username
2802 username = None
2806 username = None
2803 err = None
2807 err = None
2804 try:
2808 try:
2805 username = ui.username()
2809 username = ui.username()
2806 except error.Abort as e:
2810 except error.Abort as e:
2807 err = e
2811 err = e
2808 problems += 1
2812 problems += 1
2809
2813
2810 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2814 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
2811 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2815 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
2812 " (specify a username in your configuration file)\n"), err)
2816 " (specify a username in your configuration file)\n"), err)
2813
2817
2814 fm.condwrite(not problems, '',
2818 fm.condwrite(not problems, '',
2815 _("no problems detected\n"))
2819 _("no problems detected\n"))
2816 if not problems:
2820 if not problems:
2817 fm.data(problems=problems)
2821 fm.data(problems=problems)
2818 fm.condwrite(problems, 'problems',
2822 fm.condwrite(problems, 'problems',
2819 _("%s problems detected,"
2823 _("%s problems detected,"
2820 " please check your install!\n"), problems)
2824 " please check your install!\n"), problems)
2821 fm.end()
2825 fm.end()
2822
2826
2823 return problems
2827 return problems
2824
2828
2825 @command('debugknown', [], _('REPO ID...'), norepo=True)
2829 @command('debugknown', [], _('REPO ID...'), norepo=True)
2826 def debugknown(ui, repopath, *ids, **opts):
2830 def debugknown(ui, repopath, *ids, **opts):
2827 """test whether node ids are known to a repo
2831 """test whether node ids are known to a repo
2828
2832
2829 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
2830 and 1s indicating unknown/known.
2834 and 1s indicating unknown/known.
2831 """
2835 """
2832 repo = hg.peer(ui, opts, repopath)
2836 repo = hg.peer(ui, opts, repopath)
2833 if not repo.capable('known'):
2837 if not repo.capable('known'):
2834 raise error.Abort("known() not supported by target repository")
2838 raise error.Abort("known() not supported by target repository")
2835 flags = repo.known([bin(s) for s in ids])
2839 flags = repo.known([bin(s) for s in ids])
2836 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])))
2837
2841
2838 @command('debuglabelcomplete', [], _('LABEL...'))
2842 @command('debuglabelcomplete', [], _('LABEL...'))
2839 def debuglabelcomplete(ui, repo, *args):
2843 def debuglabelcomplete(ui, repo, *args):
2840 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2844 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2841 debugnamecomplete(ui, repo, *args)
2845 debugnamecomplete(ui, repo, *args)
2842
2846
2843 @command('debugmergestate', [], '')
2847 @command('debugmergestate', [], '')
2844 def debugmergestate(ui, repo, *args):
2848 def debugmergestate(ui, repo, *args):
2845 """print merge state
2849 """print merge state
2846
2850
2847 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
2848 was chosen."""
2852 was chosen."""
2849 def _hashornull(h):
2853 def _hashornull(h):
2850 if h == nullhex:
2854 if h == nullhex:
2851 return 'null'
2855 return 'null'
2852 else:
2856 else:
2853 return h
2857 return h
2854
2858
2855 def printrecords(version):
2859 def printrecords(version):
2856 ui.write(('* version %s records\n') % version)
2860 ui.write(('* version %s records\n') % version)
2857 if version == 1:
2861 if version == 1:
2858 records = v1records
2862 records = v1records
2859 else:
2863 else:
2860 records = v2records
2864 records = v2records
2861
2865
2862 for rtype, record in records:
2866 for rtype, record in records:
2863 # pretty print some record types
2867 # pretty print some record types
2864 if rtype == 'L':
2868 if rtype == 'L':
2865 ui.write(('local: %s\n') % record)
2869 ui.write(('local: %s\n') % record)
2866 elif rtype == 'O':
2870 elif rtype == 'O':
2867 ui.write(('other: %s\n') % record)
2871 ui.write(('other: %s\n') % record)
2868 elif rtype == 'm':
2872 elif rtype == 'm':
2869 driver, mdstate = record.split('\0', 1)
2873 driver, mdstate = record.split('\0', 1)
2870 ui.write(('merge driver: %s (state "%s")\n')
2874 ui.write(('merge driver: %s (state "%s")\n')
2871 % (driver, mdstate))
2875 % (driver, mdstate))
2872 elif rtype in 'FDC':
2876 elif rtype in 'FDC':
2873 r = record.split('\0')
2877 r = record.split('\0')
2874 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2878 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2875 if version == 1:
2879 if version == 1:
2876 onode = 'not stored in v1 format'
2880 onode = 'not stored in v1 format'
2877 flags = r[7]
2881 flags = r[7]
2878 else:
2882 else:
2879 onode, flags = r[7:9]
2883 onode, flags = r[7:9]
2880 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')
2881 % (f, rtype, state, _hashornull(hash)))
2885 % (f, rtype, state, _hashornull(hash)))
2882 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2886 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2883 ui.write((' ancestor path: %s (node %s)\n')
2887 ui.write((' ancestor path: %s (node %s)\n')
2884 % (afile, _hashornull(anode)))
2888 % (afile, _hashornull(anode)))
2885 ui.write((' other path: %s (node %s)\n')
2889 ui.write((' other path: %s (node %s)\n')
2886 % (ofile, _hashornull(onode)))
2890 % (ofile, _hashornull(onode)))
2887 elif rtype == 'f':
2891 elif rtype == 'f':
2888 filename, rawextras = record.split('\0', 1)
2892 filename, rawextras = record.split('\0', 1)
2889 extras = rawextras.split('\0')
2893 extras = rawextras.split('\0')
2890 i = 0
2894 i = 0
2891 extrastrings = []
2895 extrastrings = []
2892 while i < len(extras):
2896 while i < len(extras):
2893 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2897 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
2894 i += 2
2898 i += 2
2895
2899
2896 ui.write(('file extras: %s (%s)\n')
2900 ui.write(('file extras: %s (%s)\n')
2897 % (filename, ', '.join(extrastrings)))
2901 % (filename, ', '.join(extrastrings)))
2898 elif rtype == 'l':
2902 elif rtype == 'l':
2899 labels = record.split('\0', 2)
2903 labels = record.split('\0', 2)
2900 labels = [l for l in labels if len(l) > 0]
2904 labels = [l for l in labels if len(l) > 0]
2901 ui.write(('labels:\n'))
2905 ui.write(('labels:\n'))
2902 ui.write((' local: %s\n' % labels[0]))
2906 ui.write((' local: %s\n' % labels[0]))
2903 ui.write((' other: %s\n' % labels[1]))
2907 ui.write((' other: %s\n' % labels[1]))
2904 if len(labels) > 2:
2908 if len(labels) > 2:
2905 ui.write((' base: %s\n' % labels[2]))
2909 ui.write((' base: %s\n' % labels[2]))
2906 else:
2910 else:
2907 ui.write(('unrecognized entry: %s\t%s\n')
2911 ui.write(('unrecognized entry: %s\t%s\n')
2908 % (rtype, record.replace('\0', '\t')))
2912 % (rtype, record.replace('\0', '\t')))
2909
2913
2910 # Avoid mergestate.read() since it may raise an exception for unsupported
2914 # Avoid mergestate.read() since it may raise an exception for unsupported
2911 # 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
2912 # command is pretty low-level.
2916 # command is pretty low-level.
2913 ms = mergemod.mergestate(repo)
2917 ms = mergemod.mergestate(repo)
2914
2918
2915 # sort so that reasonable information is on top
2919 # sort so that reasonable information is on top
2916 v1records = ms._readrecordsv1()
2920 v1records = ms._readrecordsv1()
2917 v2records = ms._readrecordsv2()
2921 v2records = ms._readrecordsv2()
2918 order = 'LOml'
2922 order = 'LOml'
2919 def key(r):
2923 def key(r):
2920 idx = order.find(r[0])
2924 idx = order.find(r[0])
2921 if idx == -1:
2925 if idx == -1:
2922 return (1, r[1])
2926 return (1, r[1])
2923 else:
2927 else:
2924 return (0, idx)
2928 return (0, idx)
2925 v1records.sort(key=key)
2929 v1records.sort(key=key)
2926 v2records.sort(key=key)
2930 v2records.sort(key=key)
2927
2931
2928 if not v1records and not v2records:
2932 if not v1records and not v2records:
2929 ui.write(('no merge state found\n'))
2933 ui.write(('no merge state found\n'))
2930 elif not v2records:
2934 elif not v2records:
2931 ui.note(('no version 2 merge state\n'))
2935 ui.note(('no version 2 merge state\n'))
2932 printrecords(1)
2936 printrecords(1)
2933 elif ms._v1v2match(v1records, v2records):
2937 elif ms._v1v2match(v1records, v2records):
2934 ui.note(('v1 and v2 states match: using v2\n'))
2938 ui.note(('v1 and v2 states match: using v2\n'))
2935 printrecords(2)
2939 printrecords(2)
2936 else:
2940 else:
2937 ui.note(('v1 and v2 states mismatch: using v1\n'))
2941 ui.note(('v1 and v2 states mismatch: using v1\n'))
2938 printrecords(1)
2942 printrecords(1)
2939 if ui.verbose:
2943 if ui.verbose:
2940 printrecords(2)
2944 printrecords(2)
2941
2945
2942 @command('debugnamecomplete', [], _('NAME...'))
2946 @command('debugnamecomplete', [], _('NAME...'))
2943 def debugnamecomplete(ui, repo, *args):
2947 def debugnamecomplete(ui, repo, *args):
2944 '''complete "names" - tags, open branch names, bookmark names'''
2948 '''complete "names" - tags, open branch names, bookmark names'''
2945
2949
2946 names = set()
2950 names = set()
2947 # since we previously only listed open branches, we will handle that
2951 # since we previously only listed open branches, we will handle that
2948 # specially (after this for loop)
2952 # specially (after this for loop)
2949 for name, ns in repo.names.iteritems():
2953 for name, ns in repo.names.iteritems():
2950 if name != 'branches':
2954 if name != 'branches':
2951 names.update(ns.listnames(repo))
2955 names.update(ns.listnames(repo))
2952 names.update(tag for (tag, heads, tip, closed)
2956 names.update(tag for (tag, heads, tip, closed)
2953 in repo.branchmap().iterbranches() if not closed)
2957 in repo.branchmap().iterbranches() if not closed)
2954 completions = set()
2958 completions = set()
2955 if not args:
2959 if not args:
2956 args = ['']
2960 args = ['']
2957 for a in args:
2961 for a in args:
2958 completions.update(n for n in names if n.startswith(a))
2962 completions.update(n for n in names if n.startswith(a))
2959 ui.write('\n'.join(sorted(completions)))
2963 ui.write('\n'.join(sorted(completions)))
2960 ui.write('\n')
2964 ui.write('\n')
2961
2965
2962 @command('debuglocks',
2966 @command('debuglocks',
2963 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2967 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2964 ('W', 'force-wlock', None,
2968 ('W', 'force-wlock', None,
2965 _('free the working state lock (DANGEROUS)'))],
2969 _('free the working state lock (DANGEROUS)'))],
2966 _('[OPTION]...'))
2970 _('[OPTION]...'))
2967 def debuglocks(ui, repo, **opts):
2971 def debuglocks(ui, repo, **opts):
2968 """show or modify state of locks
2972 """show or modify state of locks
2969
2973
2970 By default, this command will show which locks are held. This
2974 By default, this command will show which locks are held. This
2971 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
2972 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
2973 running if it's not local.
2977 running if it's not local.
2974
2978
2975 Locks protect the integrity of Mercurial's data, so should be
2979 Locks protect the integrity of Mercurial's data, so should be
2976 treated with care. System crashes or other interruptions may cause
2980 treated with care. System crashes or other interruptions may cause
2977 locks to not be properly released, though Mercurial will usually
2981 locks to not be properly released, though Mercurial will usually
2978 detect and remove such stale locks automatically.
2982 detect and remove such stale locks automatically.
2979
2983
2980 However, detecting stale locks may not always be possible (for
2984 However, detecting stale locks may not always be possible (for
2981 instance, on a shared filesystem). Removing locks may also be
2985 instance, on a shared filesystem). Removing locks may also be
2982 blocked by filesystem permissions.
2986 blocked by filesystem permissions.
2983
2987
2984 Returns 0 if no locks are held.
2988 Returns 0 if no locks are held.
2985
2989
2986 """
2990 """
2987
2991
2988 if opts.get('force_lock'):
2992 if opts.get('force_lock'):
2989 repo.svfs.unlink('lock')
2993 repo.svfs.unlink('lock')
2990 if opts.get('force_wlock'):
2994 if opts.get('force_wlock'):
2991 repo.vfs.unlink('wlock')
2995 repo.vfs.unlink('wlock')
2992 if opts.get('force_lock') or opts.get('force_lock'):
2996 if opts.get('force_lock') or opts.get('force_lock'):
2993 return 0
2997 return 0
2994
2998
2995 now = time.time()
2999 now = time.time()
2996 held = 0
3000 held = 0
2997
3001
2998 def report(vfs, name, method):
3002 def report(vfs, name, method):
2999 # this causes stale locks to get reaped for more accurate reporting
3003 # this causes stale locks to get reaped for more accurate reporting
3000 try:
3004 try:
3001 l = method(False)
3005 l = method(False)
3002 except error.LockHeld:
3006 except error.LockHeld:
3003 l = None
3007 l = None
3004
3008
3005 if l:
3009 if l:
3006 l.release()
3010 l.release()
3007 else:
3011 else:
3008 try:
3012 try:
3009 stat = vfs.lstat(name)
3013 stat = vfs.lstat(name)
3010 age = now - stat.st_mtime
3014 age = now - stat.st_mtime
3011 user = util.username(stat.st_uid)
3015 user = util.username(stat.st_uid)
3012 locker = vfs.readlock(name)
3016 locker = vfs.readlock(name)
3013 if ":" in locker:
3017 if ":" in locker:
3014 host, pid = locker.split(':')
3018 host, pid = locker.split(':')
3015 if host == socket.gethostname():
3019 if host == socket.gethostname():
3016 locker = 'user %s, process %s' % (user, pid)
3020 locker = 'user %s, process %s' % (user, pid)
3017 else:
3021 else:
3018 locker = 'user %s, process %s, host %s' \
3022 locker = 'user %s, process %s, host %s' \
3019 % (user, pid, host)
3023 % (user, pid, host)
3020 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3024 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
3021 return 1
3025 return 1
3022 except OSError as e:
3026 except OSError as e:
3023 if e.errno != errno.ENOENT:
3027 if e.errno != errno.ENOENT:
3024 raise
3028 raise
3025
3029
3026 ui.write("%-6s free\n" % (name + ":"))
3030 ui.write("%-6s free\n" % (name + ":"))
3027 return 0
3031 return 0
3028
3032
3029 held += report(repo.svfs, "lock", repo.lock)
3033 held += report(repo.svfs, "lock", repo.lock)
3030 held += report(repo.vfs, "wlock", repo.wlock)
3034 held += report(repo.vfs, "wlock", repo.wlock)
3031
3035
3032 return held
3036 return held
3033
3037
3034 @command('debugobsolete',
3038 @command('debugobsolete',
3035 [('', 'flags', 0, _('markers flag')),
3039 [('', 'flags', 0, _('markers flag')),
3036 ('', 'record-parents', False,
3040 ('', 'record-parents', False,
3037 _('record parent information for the precursor')),
3041 _('record parent information for the precursor')),
3038 ('r', 'rev', [], _('display markers relevant to REV')),
3042 ('r', 'rev', [], _('display markers relevant to REV')),
3039 ('', 'index', False, _('display index of the marker')),
3043 ('', 'index', False, _('display index of the marker')),
3040 ] + commitopts2,
3044 ] + commitopts2,
3041 _('[OBSOLETED [REPLACEMENT ...]]'))
3045 _('[OBSOLETED [REPLACEMENT ...]]'))
3042 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3046 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
3043 """create arbitrary obsolete marker
3047 """create arbitrary obsolete marker
3044
3048
3045 With no arguments, displays the list of obsolescence markers."""
3049 With no arguments, displays the list of obsolescence markers."""
3046
3050
3047 def parsenodeid(s):
3051 def parsenodeid(s):
3048 try:
3052 try:
3049 # We do not use revsingle/revrange functions here to accept
3053 # We do not use revsingle/revrange functions here to accept
3050 # arbitrary node identifiers, possibly not present in the
3054 # arbitrary node identifiers, possibly not present in the
3051 # local repository.
3055 # local repository.
3052 n = bin(s)
3056 n = bin(s)
3053 if len(n) != len(nullid):
3057 if len(n) != len(nullid):
3054 raise TypeError()
3058 raise TypeError()
3055 return n
3059 return n
3056 except TypeError:
3060 except TypeError:
3057 raise error.Abort('changeset references must be full hexadecimal '
3061 raise error.Abort('changeset references must be full hexadecimal '
3058 'node identifiers')
3062 'node identifiers')
3059
3063
3060 if precursor is not None:
3064 if precursor is not None:
3061 if opts['rev']:
3065 if opts['rev']:
3062 raise error.Abort('cannot select revision when creating marker')
3066 raise error.Abort('cannot select revision when creating marker')
3063 metadata = {}
3067 metadata = {}
3064 metadata['user'] = opts['user'] or ui.username()
3068 metadata['user'] = opts['user'] or ui.username()
3065 succs = tuple(parsenodeid(succ) for succ in successors)
3069 succs = tuple(parsenodeid(succ) for succ in successors)
3066 l = repo.lock()
3070 l = repo.lock()
3067 try:
3071 try:
3068 tr = repo.transaction('debugobsolete')
3072 tr = repo.transaction('debugobsolete')
3069 try:
3073 try:
3070 date = opts.get('date')
3074 date = opts.get('date')
3071 if date:
3075 if date:
3072 date = util.parsedate(date)
3076 date = util.parsedate(date)
3073 else:
3077 else:
3074 date = None
3078 date = None
3075 prec = parsenodeid(precursor)
3079 prec = parsenodeid(precursor)
3076 parents = None
3080 parents = None
3077 if opts['record_parents']:
3081 if opts['record_parents']:
3078 if prec not in repo.unfiltered():
3082 if prec not in repo.unfiltered():
3079 raise error.Abort('cannot used --record-parents on '
3083 raise error.Abort('cannot used --record-parents on '
3080 'unknown changesets')
3084 'unknown changesets')
3081 parents = repo.unfiltered()[prec].parents()
3085 parents = repo.unfiltered()[prec].parents()
3082 parents = tuple(p.node() for p in parents)
3086 parents = tuple(p.node() for p in parents)
3083 repo.obsstore.create(tr, prec, succs, opts['flags'],
3087 repo.obsstore.create(tr, prec, succs, opts['flags'],
3084 parents=parents, date=date,
3088 parents=parents, date=date,
3085 metadata=metadata)
3089 metadata=metadata)
3086 tr.close()
3090 tr.close()
3087 except ValueError as exc:
3091 except ValueError as exc:
3088 raise error.Abort(_('bad obsmarker input: %s') % exc)
3092 raise error.Abort(_('bad obsmarker input: %s') % exc)
3089 finally:
3093 finally:
3090 tr.release()
3094 tr.release()
3091 finally:
3095 finally:
3092 l.release()
3096 l.release()
3093 else:
3097 else:
3094 if opts['rev']:
3098 if opts['rev']:
3095 revs = scmutil.revrange(repo, opts['rev'])
3099 revs = scmutil.revrange(repo, opts['rev'])
3096 nodes = [repo[r].node() for r in revs]
3100 nodes = [repo[r].node() for r in revs]
3097 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3101 markers = list(obsolete.getmarkers(repo, nodes=nodes))
3098 markers.sort(key=lambda x: x._data)
3102 markers.sort(key=lambda x: x._data)
3099 else:
3103 else:
3100 markers = obsolete.getmarkers(repo)
3104 markers = obsolete.getmarkers(repo)
3101
3105
3102 for i, m in enumerate(markers):
3106 for i, m in enumerate(markers):
3103 ind = i if opts.get('index') else None
3107 ind = i if opts.get('index') else None
3104 cmdutil.showmarker(ui, m, index=ind)
3108 cmdutil.showmarker(ui, m, index=ind)
3105
3109
3106 @command('debugpathcomplete',
3110 @command('debugpathcomplete',
3107 [('f', 'full', None, _('complete an entire path')),
3111 [('f', 'full', None, _('complete an entire path')),
3108 ('n', 'normal', None, _('show only normal files')),
3112 ('n', 'normal', None, _('show only normal files')),
3109 ('a', 'added', None, _('show only added files')),
3113 ('a', 'added', None, _('show only added files')),
3110 ('r', 'removed', None, _('show only removed files'))],
3114 ('r', 'removed', None, _('show only removed files'))],
3111 _('FILESPEC...'))
3115 _('FILESPEC...'))
3112 def debugpathcomplete(ui, repo, *specs, **opts):
3116 def debugpathcomplete(ui, repo, *specs, **opts):
3113 '''complete part or all of a tracked path
3117 '''complete part or all of a tracked path
3114
3118
3115 This command supports shells that offer path name completion. It
3119 This command supports shells that offer path name completion. It
3116 currently completes only files already known to the dirstate.
3120 currently completes only files already known to the dirstate.
3117
3121
3118 Completion extends only to the next path segment unless
3122 Completion extends only to the next path segment unless
3119 --full is specified, in which case entire paths are used.'''
3123 --full is specified, in which case entire paths are used.'''
3120
3124
3121 def complete(path, acceptable):
3125 def complete(path, acceptable):
3122 dirstate = repo.dirstate
3126 dirstate = repo.dirstate
3123 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3127 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3124 rootdir = repo.root + os.sep
3128 rootdir = repo.root + os.sep
3125 if spec != repo.root and not spec.startswith(rootdir):
3129 if spec != repo.root and not spec.startswith(rootdir):
3126 return [], []
3130 return [], []
3127 if os.path.isdir(spec):
3131 if os.path.isdir(spec):
3128 spec += '/'
3132 spec += '/'
3129 spec = spec[len(rootdir):]
3133 spec = spec[len(rootdir):]
3130 fixpaths = os.sep != '/'
3134 fixpaths = os.sep != '/'
3131 if fixpaths:
3135 if fixpaths:
3132 spec = spec.replace(os.sep, '/')
3136 spec = spec.replace(os.sep, '/')
3133 speclen = len(spec)
3137 speclen = len(spec)
3134 fullpaths = opts['full']
3138 fullpaths = opts['full']
3135 files, dirs = set(), set()
3139 files, dirs = set(), set()
3136 adddir, addfile = dirs.add, files.add
3140 adddir, addfile = dirs.add, files.add
3137 for f, st in dirstate.iteritems():
3141 for f, st in dirstate.iteritems():
3138 if f.startswith(spec) and st[0] in acceptable:
3142 if f.startswith(spec) and st[0] in acceptable:
3139 if fixpaths:
3143 if fixpaths:
3140 f = f.replace('/', os.sep)
3144 f = f.replace('/', os.sep)
3141 if fullpaths:
3145 if fullpaths:
3142 addfile(f)
3146 addfile(f)
3143 continue
3147 continue
3144 s = f.find(os.sep, speclen)
3148 s = f.find(os.sep, speclen)
3145 if s >= 0:
3149 if s >= 0:
3146 adddir(f[:s])
3150 adddir(f[:s])
3147 else:
3151 else:
3148 addfile(f)
3152 addfile(f)
3149 return files, dirs
3153 return files, dirs
3150
3154
3151 acceptable = ''
3155 acceptable = ''
3152 if opts['normal']:
3156 if opts['normal']:
3153 acceptable += 'nm'
3157 acceptable += 'nm'
3154 if opts['added']:
3158 if opts['added']:
3155 acceptable += 'a'
3159 acceptable += 'a'
3156 if opts['removed']:
3160 if opts['removed']:
3157 acceptable += 'r'
3161 acceptable += 'r'
3158 cwd = repo.getcwd()
3162 cwd = repo.getcwd()
3159 if not specs:
3163 if not specs:
3160 specs = ['.']
3164 specs = ['.']
3161
3165
3162 files, dirs = set(), set()
3166 files, dirs = set(), set()
3163 for spec in specs:
3167 for spec in specs:
3164 f, d = complete(spec, acceptable or 'nmar')
3168 f, d = complete(spec, acceptable or 'nmar')
3165 files.update(f)
3169 files.update(f)
3166 dirs.update(d)
3170 dirs.update(d)
3167 files.update(dirs)
3171 files.update(dirs)
3168 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3172 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3169 ui.write('\n')
3173 ui.write('\n')
3170
3174
3171 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3175 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3172 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3176 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3173 '''access the pushkey key/value protocol
3177 '''access the pushkey key/value protocol
3174
3178
3175 With two args, list the keys in the given namespace.
3179 With two args, list the keys in the given namespace.
3176
3180
3177 With five args, set a key to new if it currently is set to old.
3181 With five args, set a key to new if it currently is set to old.
3178 Reports success or failure.
3182 Reports success or failure.
3179 '''
3183 '''
3180
3184
3181 target = hg.peer(ui, {}, repopath)
3185 target = hg.peer(ui, {}, repopath)
3182 if keyinfo:
3186 if keyinfo:
3183 key, old, new = keyinfo
3187 key, old, new = keyinfo
3184 r = target.pushkey(namespace, key, old, new)
3188 r = target.pushkey(namespace, key, old, new)
3185 ui.status(str(r) + '\n')
3189 ui.status(str(r) + '\n')
3186 return not r
3190 return not r
3187 else:
3191 else:
3188 for k, v in sorted(target.listkeys(namespace).iteritems()):
3192 for k, v in sorted(target.listkeys(namespace).iteritems()):
3189 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3193 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3190 v.encode('string-escape')))
3194 v.encode('string-escape')))
3191
3195
3192 @command('debugpvec', [], _('A B'))
3196 @command('debugpvec', [], _('A B'))
3193 def debugpvec(ui, repo, a, b=None):
3197 def debugpvec(ui, repo, a, b=None):
3194 ca = scmutil.revsingle(repo, a)
3198 ca = scmutil.revsingle(repo, a)
3195 cb = scmutil.revsingle(repo, b)
3199 cb = scmutil.revsingle(repo, b)
3196 pa = pvec.ctxpvec(ca)
3200 pa = pvec.ctxpvec(ca)
3197 pb = pvec.ctxpvec(cb)
3201 pb = pvec.ctxpvec(cb)
3198 if pa == pb:
3202 if pa == pb:
3199 rel = "="
3203 rel = "="
3200 elif pa > pb:
3204 elif pa > pb:
3201 rel = ">"
3205 rel = ">"
3202 elif pa < pb:
3206 elif pa < pb:
3203 rel = "<"
3207 rel = "<"
3204 elif pa | pb:
3208 elif pa | pb:
3205 rel = "|"
3209 rel = "|"
3206 ui.write(_("a: %s\n") % pa)
3210 ui.write(_("a: %s\n") % pa)
3207 ui.write(_("b: %s\n") % pb)
3211 ui.write(_("b: %s\n") % pb)
3208 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3212 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3209 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3213 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3210 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3214 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3211 pa.distance(pb), rel))
3215 pa.distance(pb), rel))
3212
3216
3213 @command('debugrebuilddirstate|debugrebuildstate',
3217 @command('debugrebuilddirstate|debugrebuildstate',
3214 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3218 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3215 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3219 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3216 'the working copy parent')),
3220 'the working copy parent')),
3217 ],
3221 ],
3218 _('[-r REV]'))
3222 _('[-r REV]'))
3219 def debugrebuilddirstate(ui, repo, rev, **opts):
3223 def debugrebuilddirstate(ui, repo, rev, **opts):
3220 """rebuild the dirstate as it would look like for the given revision
3224 """rebuild the dirstate as it would look like for the given revision
3221
3225
3222 If no revision is specified the first current parent will be used.
3226 If no revision is specified the first current parent will be used.
3223
3227
3224 The dirstate will be set to the files of the given revision.
3228 The dirstate will be set to the files of the given revision.
3225 The actual working directory content or existing dirstate
3229 The actual working directory content or existing dirstate
3226 information such as adds or removes is not considered.
3230 information such as adds or removes is not considered.
3227
3231
3228 ``minimal`` will only rebuild the dirstate status for files that claim to be
3232 ``minimal`` will only rebuild the dirstate status for files that claim to be
3229 tracked but are not in the parent manifest, or that exist in the parent
3233 tracked but are not in the parent manifest, or that exist in the parent
3230 manifest but are not in the dirstate. It will not change adds, removes, or
3234 manifest but are not in the dirstate. It will not change adds, removes, or
3231 modified files that are in the working copy parent.
3235 modified files that are in the working copy parent.
3232
3236
3233 One use of this command is to make the next :hg:`status` invocation
3237 One use of this command is to make the next :hg:`status` invocation
3234 check the actual file content.
3238 check the actual file content.
3235 """
3239 """
3236 ctx = scmutil.revsingle(repo, rev)
3240 ctx = scmutil.revsingle(repo, rev)
3237 with repo.wlock():
3241 with repo.wlock():
3238 dirstate = repo.dirstate
3242 dirstate = repo.dirstate
3239 changedfiles = None
3243 changedfiles = None
3240 # See command doc for what minimal does.
3244 # See command doc for what minimal does.
3241 if opts.get('minimal'):
3245 if opts.get('minimal'):
3242 manifestfiles = set(ctx.manifest().keys())
3246 manifestfiles = set(ctx.manifest().keys())
3243 dirstatefiles = set(dirstate)
3247 dirstatefiles = set(dirstate)
3244 manifestonly = manifestfiles - dirstatefiles
3248 manifestonly = manifestfiles - dirstatefiles
3245 dsonly = dirstatefiles - manifestfiles
3249 dsonly = dirstatefiles - manifestfiles
3246 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3250 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3247 changedfiles = manifestonly | dsnotadded
3251 changedfiles = manifestonly | dsnotadded
3248
3252
3249 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3253 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3250
3254
3251 @command('debugrebuildfncache', [], '')
3255 @command('debugrebuildfncache', [], '')
3252 def debugrebuildfncache(ui, repo):
3256 def debugrebuildfncache(ui, repo):
3253 """rebuild the fncache file"""
3257 """rebuild the fncache file"""
3254 repair.rebuildfncache(ui, repo)
3258 repair.rebuildfncache(ui, repo)
3255
3259
3256 @command('debugrename',
3260 @command('debugrename',
3257 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3261 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3258 _('[-r REV] FILE'))
3262 _('[-r REV] FILE'))
3259 def debugrename(ui, repo, file1, *pats, **opts):
3263 def debugrename(ui, repo, file1, *pats, **opts):
3260 """dump rename information"""
3264 """dump rename information"""
3261
3265
3262 ctx = scmutil.revsingle(repo, opts.get('rev'))
3266 ctx = scmutil.revsingle(repo, opts.get('rev'))
3263 m = scmutil.match(ctx, (file1,) + pats, opts)
3267 m = scmutil.match(ctx, (file1,) + pats, opts)
3264 for abs in ctx.walk(m):
3268 for abs in ctx.walk(m):
3265 fctx = ctx[abs]
3269 fctx = ctx[abs]
3266 o = fctx.filelog().renamed(fctx.filenode())
3270 o = fctx.filelog().renamed(fctx.filenode())
3267 rel = m.rel(abs)
3271 rel = m.rel(abs)
3268 if o:
3272 if o:
3269 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3273 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3270 else:
3274 else:
3271 ui.write(_("%s not renamed\n") % rel)
3275 ui.write(_("%s not renamed\n") % rel)
3272
3276
3273 @command('debugrevlog', debugrevlogopts +
3277 @command('debugrevlog', debugrevlogopts +
3274 [('d', 'dump', False, _('dump index data'))],
3278 [('d', 'dump', False, _('dump index data'))],
3275 _('-c|-m|FILE'),
3279 _('-c|-m|FILE'),
3276 optionalrepo=True)
3280 optionalrepo=True)
3277 def debugrevlog(ui, repo, file_=None, **opts):
3281 def debugrevlog(ui, repo, file_=None, **opts):
3278 """show data and statistics about a revlog"""
3282 """show data and statistics about a revlog"""
3279 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3283 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3280
3284
3281 if opts.get("dump"):
3285 if opts.get("dump"):
3282 numrevs = len(r)
3286 numrevs = len(r)
3283 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3287 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3284 " rawsize totalsize compression heads chainlen\n")
3288 " rawsize totalsize compression heads chainlen\n")
3285 ts = 0
3289 ts = 0
3286 heads = set()
3290 heads = set()
3287
3291
3288 for rev in xrange(numrevs):
3292 for rev in xrange(numrevs):
3289 dbase = r.deltaparent(rev)
3293 dbase = r.deltaparent(rev)
3290 if dbase == -1:
3294 if dbase == -1:
3291 dbase = rev
3295 dbase = rev
3292 cbase = r.chainbase(rev)
3296 cbase = r.chainbase(rev)
3293 clen = r.chainlen(rev)
3297 clen = r.chainlen(rev)
3294 p1, p2 = r.parentrevs(rev)
3298 p1, p2 = r.parentrevs(rev)
3295 rs = r.rawsize(rev)
3299 rs = r.rawsize(rev)
3296 ts = ts + rs
3300 ts = ts + rs
3297 heads -= set(r.parentrevs(rev))
3301 heads -= set(r.parentrevs(rev))
3298 heads.add(rev)
3302 heads.add(rev)
3299 try:
3303 try:
3300 compression = ts / r.end(rev)
3304 compression = ts / r.end(rev)
3301 except ZeroDivisionError:
3305 except ZeroDivisionError:
3302 compression = 0
3306 compression = 0
3303 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3307 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3304 "%11d %5d %8d\n" %
3308 "%11d %5d %8d\n" %
3305 (rev, p1, p2, r.start(rev), r.end(rev),
3309 (rev, p1, p2, r.start(rev), r.end(rev),
3306 r.start(dbase), r.start(cbase),
3310 r.start(dbase), r.start(cbase),
3307 r.start(p1), r.start(p2),
3311 r.start(p1), r.start(p2),
3308 rs, ts, compression, len(heads), clen))
3312 rs, ts, compression, len(heads), clen))
3309 return 0
3313 return 0
3310
3314
3311 v = r.version
3315 v = r.version
3312 format = v & 0xFFFF
3316 format = v & 0xFFFF
3313 flags = []
3317 flags = []
3314 gdelta = False
3318 gdelta = False
3315 if v & revlog.REVLOGNGINLINEDATA:
3319 if v & revlog.REVLOGNGINLINEDATA:
3316 flags.append('inline')
3320 flags.append('inline')
3317 if v & revlog.REVLOGGENERALDELTA:
3321 if v & revlog.REVLOGGENERALDELTA:
3318 gdelta = True
3322 gdelta = True
3319 flags.append('generaldelta')
3323 flags.append('generaldelta')
3320 if not flags:
3324 if not flags:
3321 flags = ['(none)']
3325 flags = ['(none)']
3322
3326
3323 nummerges = 0
3327 nummerges = 0
3324 numfull = 0
3328 numfull = 0
3325 numprev = 0
3329 numprev = 0
3326 nump1 = 0
3330 nump1 = 0
3327 nump2 = 0
3331 nump2 = 0
3328 numother = 0
3332 numother = 0
3329 nump1prev = 0
3333 nump1prev = 0
3330 nump2prev = 0
3334 nump2prev = 0
3331 chainlengths = []
3335 chainlengths = []
3332
3336
3333 datasize = [None, 0, 0L]
3337 datasize = [None, 0, 0L]
3334 fullsize = [None, 0, 0L]
3338 fullsize = [None, 0, 0L]
3335 deltasize = [None, 0, 0L]
3339 deltasize = [None, 0, 0L]
3336
3340
3337 def addsize(size, l):
3341 def addsize(size, l):
3338 if l[0] is None or size < l[0]:
3342 if l[0] is None or size < l[0]:
3339 l[0] = size
3343 l[0] = size
3340 if size > l[1]:
3344 if size > l[1]:
3341 l[1] = size
3345 l[1] = size
3342 l[2] += size
3346 l[2] += size
3343
3347
3344 numrevs = len(r)
3348 numrevs = len(r)
3345 for rev in xrange(numrevs):
3349 for rev in xrange(numrevs):
3346 p1, p2 = r.parentrevs(rev)
3350 p1, p2 = r.parentrevs(rev)
3347 delta = r.deltaparent(rev)
3351 delta = r.deltaparent(rev)
3348 if format > 0:
3352 if format > 0:
3349 addsize(r.rawsize(rev), datasize)
3353 addsize(r.rawsize(rev), datasize)
3350 if p2 != nullrev:
3354 if p2 != nullrev:
3351 nummerges += 1
3355 nummerges += 1
3352 size = r.length(rev)
3356 size = r.length(rev)
3353 if delta == nullrev:
3357 if delta == nullrev:
3354 chainlengths.append(0)
3358 chainlengths.append(0)
3355 numfull += 1
3359 numfull += 1
3356 addsize(size, fullsize)
3360 addsize(size, fullsize)
3357 else:
3361 else:
3358 chainlengths.append(chainlengths[delta] + 1)
3362 chainlengths.append(chainlengths[delta] + 1)
3359 addsize(size, deltasize)
3363 addsize(size, deltasize)
3360 if delta == rev - 1:
3364 if delta == rev - 1:
3361 numprev += 1
3365 numprev += 1
3362 if delta == p1:
3366 if delta == p1:
3363 nump1prev += 1
3367 nump1prev += 1
3364 elif delta == p2:
3368 elif delta == p2:
3365 nump2prev += 1
3369 nump2prev += 1
3366 elif delta == p1:
3370 elif delta == p1:
3367 nump1 += 1
3371 nump1 += 1
3368 elif delta == p2:
3372 elif delta == p2:
3369 nump2 += 1
3373 nump2 += 1
3370 elif delta != nullrev:
3374 elif delta != nullrev:
3371 numother += 1
3375 numother += 1
3372
3376
3373 # Adjust size min value for empty cases
3377 # Adjust size min value for empty cases
3374 for size in (datasize, fullsize, deltasize):
3378 for size in (datasize, fullsize, deltasize):
3375 if size[0] is None:
3379 if size[0] is None:
3376 size[0] = 0
3380 size[0] = 0
3377
3381
3378 numdeltas = numrevs - numfull
3382 numdeltas = numrevs - numfull
3379 numoprev = numprev - nump1prev - nump2prev
3383 numoprev = numprev - nump1prev - nump2prev
3380 totalrawsize = datasize[2]
3384 totalrawsize = datasize[2]
3381 datasize[2] /= numrevs
3385 datasize[2] /= numrevs
3382 fulltotal = fullsize[2]
3386 fulltotal = fullsize[2]
3383 fullsize[2] /= numfull
3387 fullsize[2] /= numfull
3384 deltatotal = deltasize[2]
3388 deltatotal = deltasize[2]
3385 if numrevs - numfull > 0:
3389 if numrevs - numfull > 0:
3386 deltasize[2] /= numrevs - numfull
3390 deltasize[2] /= numrevs - numfull
3387 totalsize = fulltotal + deltatotal
3391 totalsize = fulltotal + deltatotal
3388 avgchainlen = sum(chainlengths) / numrevs
3392 avgchainlen = sum(chainlengths) / numrevs
3389 maxchainlen = max(chainlengths)
3393 maxchainlen = max(chainlengths)
3390 compratio = 1
3394 compratio = 1
3391 if totalsize:
3395 if totalsize:
3392 compratio = totalrawsize / totalsize
3396 compratio = totalrawsize / totalsize
3393
3397
3394 basedfmtstr = '%%%dd\n'
3398 basedfmtstr = '%%%dd\n'
3395 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3399 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3396
3400
3397 def dfmtstr(max):
3401 def dfmtstr(max):
3398 return basedfmtstr % len(str(max))
3402 return basedfmtstr % len(str(max))
3399 def pcfmtstr(max, padding=0):
3403 def pcfmtstr(max, padding=0):
3400 return basepcfmtstr % (len(str(max)), ' ' * padding)
3404 return basepcfmtstr % (len(str(max)), ' ' * padding)
3401
3405
3402 def pcfmt(value, total):
3406 def pcfmt(value, total):
3403 if total:
3407 if total:
3404 return (value, 100 * float(value) / total)
3408 return (value, 100 * float(value) / total)
3405 else:
3409 else:
3406 return value, 100.0
3410 return value, 100.0
3407
3411
3408 ui.write(('format : %d\n') % format)
3412 ui.write(('format : %d\n') % format)
3409 ui.write(('flags : %s\n') % ', '.join(flags))
3413 ui.write(('flags : %s\n') % ', '.join(flags))
3410
3414
3411 ui.write('\n')
3415 ui.write('\n')
3412 fmt = pcfmtstr(totalsize)
3416 fmt = pcfmtstr(totalsize)
3413 fmt2 = dfmtstr(totalsize)
3417 fmt2 = dfmtstr(totalsize)
3414 ui.write(('revisions : ') + fmt2 % numrevs)
3418 ui.write(('revisions : ') + fmt2 % numrevs)
3415 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3419 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3416 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3420 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3417 ui.write(('revisions : ') + fmt2 % numrevs)
3421 ui.write(('revisions : ') + fmt2 % numrevs)
3418 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3422 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3419 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3423 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3420 ui.write(('revision size : ') + fmt2 % totalsize)
3424 ui.write(('revision size : ') + fmt2 % totalsize)
3421 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3425 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3422 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3426 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3423
3427
3424 ui.write('\n')
3428 ui.write('\n')
3425 fmt = dfmtstr(max(avgchainlen, compratio))
3429 fmt = dfmtstr(max(avgchainlen, compratio))
3426 ui.write(('avg chain length : ') + fmt % avgchainlen)
3430 ui.write(('avg chain length : ') + fmt % avgchainlen)
3427 ui.write(('max chain length : ') + fmt % maxchainlen)
3431 ui.write(('max chain length : ') + fmt % maxchainlen)
3428 ui.write(('compression ratio : ') + fmt % compratio)
3432 ui.write(('compression ratio : ') + fmt % compratio)
3429
3433
3430 if format > 0:
3434 if format > 0:
3431 ui.write('\n')
3435 ui.write('\n')
3432 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3436 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3433 % tuple(datasize))
3437 % tuple(datasize))
3434 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3438 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3435 % tuple(fullsize))
3439 % tuple(fullsize))
3436 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3440 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3437 % tuple(deltasize))
3441 % tuple(deltasize))
3438
3442
3439 if numdeltas > 0:
3443 if numdeltas > 0:
3440 ui.write('\n')
3444 ui.write('\n')
3441 fmt = pcfmtstr(numdeltas)
3445 fmt = pcfmtstr(numdeltas)
3442 fmt2 = pcfmtstr(numdeltas, 4)
3446 fmt2 = pcfmtstr(numdeltas, 4)
3443 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3447 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3444 if numprev > 0:
3448 if numprev > 0:
3445 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3449 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3446 numprev))
3450 numprev))
3447 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3451 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3448 numprev))
3452 numprev))
3449 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3453 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3450 numprev))
3454 numprev))
3451 if gdelta:
3455 if gdelta:
3452 ui.write(('deltas against p1 : ')
3456 ui.write(('deltas against p1 : ')
3453 + fmt % pcfmt(nump1, numdeltas))
3457 + fmt % pcfmt(nump1, numdeltas))
3454 ui.write(('deltas against p2 : ')
3458 ui.write(('deltas against p2 : ')
3455 + fmt % pcfmt(nump2, numdeltas))
3459 + fmt % pcfmt(nump2, numdeltas))
3456 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3460 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3457 numdeltas))
3461 numdeltas))
3458
3462
3459 @command('debugrevspec',
3463 @command('debugrevspec',
3460 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3464 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3461 ('REVSPEC'))
3465 ('REVSPEC'))
3462 def debugrevspec(ui, repo, expr, **opts):
3466 def debugrevspec(ui, repo, expr, **opts):
3463 """parse and apply a revision specification
3467 """parse and apply a revision specification
3464
3468
3465 Use --verbose to print the parsed tree before and after aliases
3469 Use --verbose to print the parsed tree before and after aliases
3466 expansion.
3470 expansion.
3467 """
3471 """
3468 if ui.verbose:
3472 if ui.verbose:
3469 tree = revset.parse(expr, lookup=repo.__contains__)
3473 tree = revset.parse(expr, lookup=repo.__contains__)
3470 ui.note(revset.prettyformat(tree), "\n")
3474 ui.note(revset.prettyformat(tree), "\n")
3471 newtree = revset.findaliases(ui, tree)
3475 newtree = revset.findaliases(ui, tree)
3472 if newtree != tree:
3476 if newtree != tree:
3473 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3477 ui.note("* expanded:\n", revset.prettyformat(newtree), "\n")
3474 tree = newtree
3478 tree = newtree
3475 newtree = revset.foldconcat(tree)
3479 newtree = revset.foldconcat(tree)
3476 if newtree != tree:
3480 if newtree != tree:
3477 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3481 ui.note("* concatenated:\n", revset.prettyformat(newtree), "\n")
3478 if opts["optimize"]:
3482 if opts["optimize"]:
3479 weight, optimizedtree = revset.optimize(newtree, True)
3483 weight, optimizedtree = revset.optimize(newtree, True)
3480 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3484 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3481 func = revset.match(ui, expr, repo)
3485 func = revset.match(ui, expr, repo)
3482 revs = func(repo)
3486 revs = func(repo)
3483 if ui.verbose:
3487 if ui.verbose:
3484 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3488 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3485 for c in revs:
3489 for c in revs:
3486 ui.write("%s\n" % c)
3490 ui.write("%s\n" % c)
3487
3491
3488 @command('debugsetparents', [], _('REV1 [REV2]'))
3492 @command('debugsetparents', [], _('REV1 [REV2]'))
3489 def debugsetparents(ui, repo, rev1, rev2=None):
3493 def debugsetparents(ui, repo, rev1, rev2=None):
3490 """manually set the parents of the current working directory
3494 """manually set the parents of the current working directory
3491
3495
3492 This is useful for writing repository conversion tools, but should
3496 This is useful for writing repository conversion tools, but should
3493 be used with care. For example, neither the working directory nor the
3497 be used with care. For example, neither the working directory nor the
3494 dirstate is updated, so file status may be incorrect after running this
3498 dirstate is updated, so file status may be incorrect after running this
3495 command.
3499 command.
3496
3500
3497 Returns 0 on success.
3501 Returns 0 on success.
3498 """
3502 """
3499
3503
3500 r1 = scmutil.revsingle(repo, rev1).node()
3504 r1 = scmutil.revsingle(repo, rev1).node()
3501 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3505 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3502
3506
3503 with repo.wlock():
3507 with repo.wlock():
3504 repo.setparents(r1, r2)
3508 repo.setparents(r1, r2)
3505
3509
3506 @command('debugdirstate|debugstate',
3510 @command('debugdirstate|debugstate',
3507 [('', 'nodates', None, _('do not display the saved mtime')),
3511 [('', 'nodates', None, _('do not display the saved mtime')),
3508 ('', 'datesort', None, _('sort by saved mtime'))],
3512 ('', 'datesort', None, _('sort by saved mtime'))],
3509 _('[OPTION]...'))
3513 _('[OPTION]...'))
3510 def debugstate(ui, repo, **opts):
3514 def debugstate(ui, repo, **opts):
3511 """show the contents of the current dirstate"""
3515 """show the contents of the current dirstate"""
3512
3516
3513 nodates = opts.get('nodates')
3517 nodates = opts.get('nodates')
3514 datesort = opts.get('datesort')
3518 datesort = opts.get('datesort')
3515
3519
3516 timestr = ""
3520 timestr = ""
3517 if datesort:
3521 if datesort:
3518 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3522 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3519 else:
3523 else:
3520 keyfunc = None # sort by filename
3524 keyfunc = None # sort by filename
3521 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3525 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3522 if ent[3] == -1:
3526 if ent[3] == -1:
3523 timestr = 'unset '
3527 timestr = 'unset '
3524 elif nodates:
3528 elif nodates:
3525 timestr = 'set '
3529 timestr = 'set '
3526 else:
3530 else:
3527 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3531 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3528 time.localtime(ent[3]))
3532 time.localtime(ent[3]))
3529 if ent[1] & 0o20000:
3533 if ent[1] & 0o20000:
3530 mode = 'lnk'
3534 mode = 'lnk'
3531 else:
3535 else:
3532 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3536 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3533 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3537 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3534 for f in repo.dirstate.copies():
3538 for f in repo.dirstate.copies():
3535 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3539 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3536
3540
3537 @command('debugsub',
3541 @command('debugsub',
3538 [('r', 'rev', '',
3542 [('r', 'rev', '',
3539 _('revision to check'), _('REV'))],
3543 _('revision to check'), _('REV'))],
3540 _('[-r REV] [REV]'))
3544 _('[-r REV] [REV]'))
3541 def debugsub(ui, repo, rev=None):
3545 def debugsub(ui, repo, rev=None):
3542 ctx = scmutil.revsingle(repo, rev, None)
3546 ctx = scmutil.revsingle(repo, rev, None)
3543 for k, v in sorted(ctx.substate.items()):
3547 for k, v in sorted(ctx.substate.items()):
3544 ui.write(('path %s\n') % k)
3548 ui.write(('path %s\n') % k)
3545 ui.write((' source %s\n') % v[0])
3549 ui.write((' source %s\n') % v[0])
3546 ui.write((' revision %s\n') % v[1])
3550 ui.write((' revision %s\n') % v[1])
3547
3551
3548 @command('debugsuccessorssets',
3552 @command('debugsuccessorssets',
3549 [],
3553 [],
3550 _('[REV]'))
3554 _('[REV]'))
3551 def debugsuccessorssets(ui, repo, *revs):
3555 def debugsuccessorssets(ui, repo, *revs):
3552 """show set of successors for revision
3556 """show set of successors for revision
3553
3557
3554 A successors set of changeset A is a consistent group of revisions that
3558 A successors set of changeset A is a consistent group of revisions that
3555 succeed A. It contains non-obsolete changesets only.
3559 succeed A. It contains non-obsolete changesets only.
3556
3560
3557 In most cases a changeset A has a single successors set containing a single
3561 In most cases a changeset A has a single successors set containing a single
3558 successor (changeset A replaced by A').
3562 successor (changeset A replaced by A').
3559
3563
3560 A changeset that is made obsolete with no successors are called "pruned".
3564 A changeset that is made obsolete with no successors are called "pruned".
3561 Such changesets have no successors sets at all.
3565 Such changesets have no successors sets at all.
3562
3566
3563 A changeset that has been "split" will have a successors set containing
3567 A changeset that has been "split" will have a successors set containing
3564 more than one successor.
3568 more than one successor.
3565
3569
3566 A changeset that has been rewritten in multiple different ways is called
3570 A changeset that has been rewritten in multiple different ways is called
3567 "divergent". Such changesets have multiple successor sets (each of which
3571 "divergent". Such changesets have multiple successor sets (each of which
3568 may also be split, i.e. have multiple successors).
3572 may also be split, i.e. have multiple successors).
3569
3573
3570 Results are displayed as follows::
3574 Results are displayed as follows::
3571
3575
3572 <rev1>
3576 <rev1>
3573 <successors-1A>
3577 <successors-1A>
3574 <rev2>
3578 <rev2>
3575 <successors-2A>
3579 <successors-2A>
3576 <successors-2B1> <successors-2B2> <successors-2B3>
3580 <successors-2B1> <successors-2B2> <successors-2B3>
3577
3581
3578 Here rev2 has two possible (i.e. divergent) successors sets. The first
3582 Here rev2 has two possible (i.e. divergent) successors sets. The first
3579 holds one element, whereas the second holds three (i.e. the changeset has
3583 holds one element, whereas the second holds three (i.e. the changeset has
3580 been split).
3584 been split).
3581 """
3585 """
3582 # passed to successorssets caching computation from one call to another
3586 # passed to successorssets caching computation from one call to another
3583 cache = {}
3587 cache = {}
3584 ctx2str = str
3588 ctx2str = str
3585 node2str = short
3589 node2str = short
3586 if ui.debug():
3590 if ui.debug():
3587 def ctx2str(ctx):
3591 def ctx2str(ctx):
3588 return ctx.hex()
3592 return ctx.hex()
3589 node2str = hex
3593 node2str = hex
3590 for rev in scmutil.revrange(repo, revs):
3594 for rev in scmutil.revrange(repo, revs):
3591 ctx = repo[rev]
3595 ctx = repo[rev]
3592 ui.write('%s\n'% ctx2str(ctx))
3596 ui.write('%s\n'% ctx2str(ctx))
3593 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3597 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3594 if succsset:
3598 if succsset:
3595 ui.write(' ')
3599 ui.write(' ')
3596 ui.write(node2str(succsset[0]))
3600 ui.write(node2str(succsset[0]))
3597 for node in succsset[1:]:
3601 for node in succsset[1:]:
3598 ui.write(' ')
3602 ui.write(' ')
3599 ui.write(node2str(node))
3603 ui.write(node2str(node))
3600 ui.write('\n')
3604 ui.write('\n')
3601
3605
3602 @command('debugtemplate',
3606 @command('debugtemplate',
3603 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3607 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
3604 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3608 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
3605 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3609 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
3606 optionalrepo=True)
3610 optionalrepo=True)
3607 def debugtemplate(ui, repo, tmpl, **opts):
3611 def debugtemplate(ui, repo, tmpl, **opts):
3608 """parse and apply a template
3612 """parse and apply a template
3609
3613
3610 If -r/--rev is given, the template is processed as a log template and
3614 If -r/--rev is given, the template is processed as a log template and
3611 applied to the given changesets. Otherwise, it is processed as a generic
3615 applied to the given changesets. Otherwise, it is processed as a generic
3612 template.
3616 template.
3613
3617
3614 Use --verbose to print the parsed tree.
3618 Use --verbose to print the parsed tree.
3615 """
3619 """
3616 revs = None
3620 revs = None
3617 if opts['rev']:
3621 if opts['rev']:
3618 if repo is None:
3622 if repo is None:
3619 raise error.RepoError(_('there is no Mercurial repository here '
3623 raise error.RepoError(_('there is no Mercurial repository here '
3620 '(.hg not found)'))
3624 '(.hg not found)'))
3621 revs = scmutil.revrange(repo, opts['rev'])
3625 revs = scmutil.revrange(repo, opts['rev'])
3622
3626
3623 props = {}
3627 props = {}
3624 for d in opts['define']:
3628 for d in opts['define']:
3625 try:
3629 try:
3626 k, v = (e.strip() for e in d.split('=', 1))
3630 k, v = (e.strip() for e in d.split('=', 1))
3627 if not k:
3631 if not k:
3628 raise ValueError
3632 raise ValueError
3629 props[k] = v
3633 props[k] = v
3630 except ValueError:
3634 except ValueError:
3631 raise error.Abort(_('malformed keyword definition: %s') % d)
3635 raise error.Abort(_('malformed keyword definition: %s') % d)
3632
3636
3633 if ui.verbose:
3637 if ui.verbose:
3634 tree = templater.parse(tmpl)
3638 tree = templater.parse(tmpl)
3635 ui.note(templater.prettyformat(tree), '\n')
3639 ui.note(templater.prettyformat(tree), '\n')
3636
3640
3637 mapfile = None
3641 mapfile = None
3638 if revs is None:
3642 if revs is None:
3639 k = 'debugtemplate'
3643 k = 'debugtemplate'
3640 t = templater.templater(mapfile)
3644 t = templater.templater(mapfile)
3641 t.cache[k] = tmpl
3645 t.cache[k] = tmpl
3642 ui.write(templater.stringify(t(k, **props)))
3646 ui.write(templater.stringify(t(k, **props)))
3643 else:
3647 else:
3644 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3648 displayer = cmdutil.changeset_templater(ui, repo, None, opts, tmpl,
3645 mapfile, buffered=False)
3649 mapfile, buffered=False)
3646 for r in revs:
3650 for r in revs:
3647 displayer.show(repo[r], **props)
3651 displayer.show(repo[r], **props)
3648 displayer.close()
3652 displayer.close()
3649
3653
3650 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3654 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3651 def debugwalk(ui, repo, *pats, **opts):
3655 def debugwalk(ui, repo, *pats, **opts):
3652 """show how files match on given patterns"""
3656 """show how files match on given patterns"""
3653 m = scmutil.match(repo[None], pats, opts)
3657 m = scmutil.match(repo[None], pats, opts)
3654 items = list(repo.walk(m))
3658 items = list(repo.walk(m))
3655 if not items:
3659 if not items:
3656 return
3660 return
3657 f = lambda fn: fn
3661 f = lambda fn: fn
3658 if ui.configbool('ui', 'slash') and os.sep != '/':
3662 if ui.configbool('ui', 'slash') and os.sep != '/':
3659 f = lambda fn: util.normpath(fn)
3663 f = lambda fn: util.normpath(fn)
3660 fmt = 'f %%-%ds %%-%ds %%s' % (
3664 fmt = 'f %%-%ds %%-%ds %%s' % (
3661 max([len(abs) for abs in items]),
3665 max([len(abs) for abs in items]),
3662 max([len(m.rel(abs)) for abs in items]))
3666 max([len(m.rel(abs)) for abs in items]))
3663 for abs in items:
3667 for abs in items:
3664 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3668 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3665 ui.write("%s\n" % line.rstrip())
3669 ui.write("%s\n" % line.rstrip())
3666
3670
3667 @command('debugwireargs',
3671 @command('debugwireargs',
3668 [('', 'three', '', 'three'),
3672 [('', 'three', '', 'three'),
3669 ('', 'four', '', 'four'),
3673 ('', 'four', '', 'four'),
3670 ('', 'five', '', 'five'),
3674 ('', 'five', '', 'five'),
3671 ] + remoteopts,
3675 ] + remoteopts,
3672 _('REPO [OPTIONS]... [ONE [TWO]]'),
3676 _('REPO [OPTIONS]... [ONE [TWO]]'),
3673 norepo=True)
3677 norepo=True)
3674 def debugwireargs(ui, repopath, *vals, **opts):
3678 def debugwireargs(ui, repopath, *vals, **opts):
3675 repo = hg.peer(ui, opts, repopath)
3679 repo = hg.peer(ui, opts, repopath)
3676 for opt in remoteopts:
3680 for opt in remoteopts:
3677 del opts[opt[1]]
3681 del opts[opt[1]]
3678 args = {}
3682 args = {}
3679 for k, v in opts.iteritems():
3683 for k, v in opts.iteritems():
3680 if v:
3684 if v:
3681 args[k] = v
3685 args[k] = v
3682 # run twice to check that we don't mess up the stream for the next command
3686 # run twice to check that we don't mess up the stream for the next command
3683 res1 = repo.debugwireargs(*vals, **args)
3687 res1 = repo.debugwireargs(*vals, **args)
3684 res2 = repo.debugwireargs(*vals, **args)
3688 res2 = repo.debugwireargs(*vals, **args)
3685 ui.write("%s\n" % res1)
3689 ui.write("%s\n" % res1)
3686 if res1 != res2:
3690 if res1 != res2:
3687 ui.warn("%s\n" % res2)
3691 ui.warn("%s\n" % res2)
3688
3692
3689 @command('^diff',
3693 @command('^diff',
3690 [('r', 'rev', [], _('revision'), _('REV')),
3694 [('r', 'rev', [], _('revision'), _('REV')),
3691 ('c', 'change', '', _('change made by revision'), _('REV'))
3695 ('c', 'change', '', _('change made by revision'), _('REV'))
3692 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3696 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3693 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3697 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3694 inferrepo=True)
3698 inferrepo=True)
3695 def diff(ui, repo, *pats, **opts):
3699 def diff(ui, repo, *pats, **opts):
3696 """diff repository (or selected files)
3700 """diff repository (or selected files)
3697
3701
3698 Show differences between revisions for the specified files.
3702 Show differences between revisions for the specified files.
3699
3703
3700 Differences between files are shown using the unified diff format.
3704 Differences between files are shown using the unified diff format.
3701
3705
3702 .. note::
3706 .. note::
3703
3707
3704 :hg:`diff` may generate unexpected results for merges, as it will
3708 :hg:`diff` may generate unexpected results for merges, as it will
3705 default to comparing against the working directory's first
3709 default to comparing against the working directory's first
3706 parent changeset if no revisions are specified.
3710 parent changeset if no revisions are specified.
3707
3711
3708 When two revision arguments are given, then changes are shown
3712 When two revision arguments are given, then changes are shown
3709 between those revisions. If only one revision is specified then
3713 between those revisions. If only one revision is specified then
3710 that revision is compared to the working directory, and, when no
3714 that revision is compared to the working directory, and, when no
3711 revisions are specified, the working directory files are compared
3715 revisions are specified, the working directory files are compared
3712 to its first parent.
3716 to its first parent.
3713
3717
3714 Alternatively you can specify -c/--change with a revision to see
3718 Alternatively you can specify -c/--change with a revision to see
3715 the changes in that changeset relative to its first parent.
3719 the changes in that changeset relative to its first parent.
3716
3720
3717 Without the -a/--text option, diff will avoid generating diffs of
3721 Without the -a/--text option, diff will avoid generating diffs of
3718 files it detects as binary. With -a, diff will generate a diff
3722 files it detects as binary. With -a, diff will generate a diff
3719 anyway, probably with undesirable results.
3723 anyway, probably with undesirable results.
3720
3724
3721 Use the -g/--git option to generate diffs in the git extended diff
3725 Use the -g/--git option to generate diffs in the git extended diff
3722 format. For more information, read :hg:`help diffs`.
3726 format. For more information, read :hg:`help diffs`.
3723
3727
3724 .. container:: verbose
3728 .. container:: verbose
3725
3729
3726 Examples:
3730 Examples:
3727
3731
3728 - compare a file in the current working directory to its parent::
3732 - compare a file in the current working directory to its parent::
3729
3733
3730 hg diff foo.c
3734 hg diff foo.c
3731
3735
3732 - compare two historical versions of a directory, with rename info::
3736 - compare two historical versions of a directory, with rename info::
3733
3737
3734 hg diff --git -r 1.0:1.2 lib/
3738 hg diff --git -r 1.0:1.2 lib/
3735
3739
3736 - get change stats relative to the last change on some date::
3740 - get change stats relative to the last change on some date::
3737
3741
3738 hg diff --stat -r "date('may 2')"
3742 hg diff --stat -r "date('may 2')"
3739
3743
3740 - diff all newly-added files that contain a keyword::
3744 - diff all newly-added files that contain a keyword::
3741
3745
3742 hg diff "set:added() and grep(GNU)"
3746 hg diff "set:added() and grep(GNU)"
3743
3747
3744 - compare a revision and its parents::
3748 - compare a revision and its parents::
3745
3749
3746 hg diff -c 9353 # compare against first parent
3750 hg diff -c 9353 # compare against first parent
3747 hg diff -r 9353^:9353 # same using revset syntax
3751 hg diff -r 9353^:9353 # same using revset syntax
3748 hg diff -r 9353^2:9353 # compare against the second parent
3752 hg diff -r 9353^2:9353 # compare against the second parent
3749
3753
3750 Returns 0 on success.
3754 Returns 0 on success.
3751 """
3755 """
3752
3756
3753 revs = opts.get('rev')
3757 revs = opts.get('rev')
3754 change = opts.get('change')
3758 change = opts.get('change')
3755 stat = opts.get('stat')
3759 stat = opts.get('stat')
3756 reverse = opts.get('reverse')
3760 reverse = opts.get('reverse')
3757
3761
3758 if revs and change:
3762 if revs and change:
3759 msg = _('cannot specify --rev and --change at the same time')
3763 msg = _('cannot specify --rev and --change at the same time')
3760 raise error.Abort(msg)
3764 raise error.Abort(msg)
3761 elif change:
3765 elif change:
3762 node2 = scmutil.revsingle(repo, change, None).node()
3766 node2 = scmutil.revsingle(repo, change, None).node()
3763 node1 = repo[node2].p1().node()
3767 node1 = repo[node2].p1().node()
3764 else:
3768 else:
3765 node1, node2 = scmutil.revpair(repo, revs)
3769 node1, node2 = scmutil.revpair(repo, revs)
3766
3770
3767 if reverse:
3771 if reverse:
3768 node1, node2 = node2, node1
3772 node1, node2 = node2, node1
3769
3773
3770 diffopts = patch.diffallopts(ui, opts)
3774 diffopts = patch.diffallopts(ui, opts)
3771 m = scmutil.match(repo[node2], pats, opts)
3775 m = scmutil.match(repo[node2], pats, opts)
3772 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3776 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3773 listsubrepos=opts.get('subrepos'),
3777 listsubrepos=opts.get('subrepos'),
3774 root=opts.get('root'))
3778 root=opts.get('root'))
3775
3779
3776 @command('^export',
3780 @command('^export',
3777 [('o', 'output', '',
3781 [('o', 'output', '',
3778 _('print output to file with formatted name'), _('FORMAT')),
3782 _('print output to file with formatted name'), _('FORMAT')),
3779 ('', 'switch-parent', None, _('diff against the second parent')),
3783 ('', 'switch-parent', None, _('diff against the second parent')),
3780 ('r', 'rev', [], _('revisions to export'), _('REV')),
3784 ('r', 'rev', [], _('revisions to export'), _('REV')),
3781 ] + diffopts,
3785 ] + diffopts,
3782 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3786 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3783 def export(ui, repo, *changesets, **opts):
3787 def export(ui, repo, *changesets, **opts):
3784 """dump the header and diffs for one or more changesets
3788 """dump the header and diffs for one or more changesets
3785
3789
3786 Print the changeset header and diffs for one or more revisions.
3790 Print the changeset header and diffs for one or more revisions.
3787 If no revision is given, the parent of the working directory is used.
3791 If no revision is given, the parent of the working directory is used.
3788
3792
3789 The information shown in the changeset header is: author, date,
3793 The information shown in the changeset header is: author, date,
3790 branch name (if non-default), changeset hash, parent(s) and commit
3794 branch name (if non-default), changeset hash, parent(s) and commit
3791 comment.
3795 comment.
3792
3796
3793 .. note::
3797 .. note::
3794
3798
3795 :hg:`export` may generate unexpected diff output for merge
3799 :hg:`export` may generate unexpected diff output for merge
3796 changesets, as it will compare the merge changeset against its
3800 changesets, as it will compare the merge changeset against its
3797 first parent only.
3801 first parent only.
3798
3802
3799 Output may be to a file, in which case the name of the file is
3803 Output may be to a file, in which case the name of the file is
3800 given using a format string. The formatting rules are as follows:
3804 given using a format string. The formatting rules are as follows:
3801
3805
3802 :``%%``: literal "%" character
3806 :``%%``: literal "%" character
3803 :``%H``: changeset hash (40 hexadecimal digits)
3807 :``%H``: changeset hash (40 hexadecimal digits)
3804 :``%N``: number of patches being generated
3808 :``%N``: number of patches being generated
3805 :``%R``: changeset revision number
3809 :``%R``: changeset revision number
3806 :``%b``: basename of the exporting repository
3810 :``%b``: basename of the exporting repository
3807 :``%h``: short-form changeset hash (12 hexadecimal digits)
3811 :``%h``: short-form changeset hash (12 hexadecimal digits)
3808 :``%m``: first line of the commit message (only alphanumeric characters)
3812 :``%m``: first line of the commit message (only alphanumeric characters)
3809 :``%n``: zero-padded sequence number, starting at 1
3813 :``%n``: zero-padded sequence number, starting at 1
3810 :``%r``: zero-padded changeset revision number
3814 :``%r``: zero-padded changeset revision number
3811
3815
3812 Without the -a/--text option, export will avoid generating diffs
3816 Without the -a/--text option, export will avoid generating diffs
3813 of files it detects as binary. With -a, export will generate a
3817 of files it detects as binary. With -a, export will generate a
3814 diff anyway, probably with undesirable results.
3818 diff anyway, probably with undesirable results.
3815
3819
3816 Use the -g/--git option to generate diffs in the git extended diff
3820 Use the -g/--git option to generate diffs in the git extended diff
3817 format. See :hg:`help diffs` for more information.
3821 format. See :hg:`help diffs` for more information.
3818
3822
3819 With the --switch-parent option, the diff will be against the
3823 With the --switch-parent option, the diff will be against the
3820 second parent. It can be useful to review a merge.
3824 second parent. It can be useful to review a merge.
3821
3825
3822 .. container:: verbose
3826 .. container:: verbose
3823
3827
3824 Examples:
3828 Examples:
3825
3829
3826 - use export and import to transplant a bugfix to the current
3830 - use export and import to transplant a bugfix to the current
3827 branch::
3831 branch::
3828
3832
3829 hg export -r 9353 | hg import -
3833 hg export -r 9353 | hg import -
3830
3834
3831 - export all the changesets between two revisions to a file with
3835 - export all the changesets between two revisions to a file with
3832 rename information::
3836 rename information::
3833
3837
3834 hg export --git -r 123:150 > changes.txt
3838 hg export --git -r 123:150 > changes.txt
3835
3839
3836 - split outgoing changes into a series of patches with
3840 - split outgoing changes into a series of patches with
3837 descriptive names::
3841 descriptive names::
3838
3842
3839 hg export -r "outgoing()" -o "%n-%m.patch"
3843 hg export -r "outgoing()" -o "%n-%m.patch"
3840
3844
3841 Returns 0 on success.
3845 Returns 0 on success.
3842 """
3846 """
3843 changesets += tuple(opts.get('rev', []))
3847 changesets += tuple(opts.get('rev', []))
3844 if not changesets:
3848 if not changesets:
3845 changesets = ['.']
3849 changesets = ['.']
3846 revs = scmutil.revrange(repo, changesets)
3850 revs = scmutil.revrange(repo, changesets)
3847 if not revs:
3851 if not revs:
3848 raise error.Abort(_("export requires at least one changeset"))
3852 raise error.Abort(_("export requires at least one changeset"))
3849 if len(revs) > 1:
3853 if len(revs) > 1:
3850 ui.note(_('exporting patches:\n'))
3854 ui.note(_('exporting patches:\n'))
3851 else:
3855 else:
3852 ui.note(_('exporting patch:\n'))
3856 ui.note(_('exporting patch:\n'))
3853 cmdutil.export(repo, revs, template=opts.get('output'),
3857 cmdutil.export(repo, revs, template=opts.get('output'),
3854 switch_parent=opts.get('switch_parent'),
3858 switch_parent=opts.get('switch_parent'),
3855 opts=patch.diffallopts(ui, opts))
3859 opts=patch.diffallopts(ui, opts))
3856
3860
3857 @command('files',
3861 @command('files',
3858 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3862 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3859 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3863 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3860 ] + walkopts + formatteropts + subrepoopts,
3864 ] + walkopts + formatteropts + subrepoopts,
3861 _('[OPTION]... [PATTERN]...'))
3865 _('[OPTION]... [PATTERN]...'))
3862 def files(ui, repo, *pats, **opts):
3866 def files(ui, repo, *pats, **opts):
3863 """list tracked files
3867 """list tracked files
3864
3868
3865 Print files under Mercurial control in the working directory or
3869 Print files under Mercurial control in the working directory or
3866 specified revision whose names match the given patterns (excluding
3870 specified revision whose names match the given patterns (excluding
3867 removed files).
3871 removed files).
3868
3872
3869 If no patterns are given to match, this command prints the names
3873 If no patterns are given to match, this command prints the names
3870 of all files under Mercurial control in the working directory.
3874 of all files under Mercurial control in the working directory.
3871
3875
3872 .. container:: verbose
3876 .. container:: verbose
3873
3877
3874 Examples:
3878 Examples:
3875
3879
3876 - list all files under the current directory::
3880 - list all files under the current directory::
3877
3881
3878 hg files .
3882 hg files .
3879
3883
3880 - shows sizes and flags for current revision::
3884 - shows sizes and flags for current revision::
3881
3885
3882 hg files -vr .
3886 hg files -vr .
3883
3887
3884 - list all files named README::
3888 - list all files named README::
3885
3889
3886 hg files -I "**/README"
3890 hg files -I "**/README"
3887
3891
3888 - list all binary files::
3892 - list all binary files::
3889
3893
3890 hg files "set:binary()"
3894 hg files "set:binary()"
3891
3895
3892 - find files containing a regular expression::
3896 - find files containing a regular expression::
3893
3897
3894 hg files "set:grep('bob')"
3898 hg files "set:grep('bob')"
3895
3899
3896 - search tracked file contents with xargs and grep::
3900 - search tracked file contents with xargs and grep::
3897
3901
3898 hg files -0 | xargs -0 grep foo
3902 hg files -0 | xargs -0 grep foo
3899
3903
3900 See :hg:`help patterns` and :hg:`help filesets` for more information
3904 See :hg:`help patterns` and :hg:`help filesets` for more information
3901 on specifying file patterns.
3905 on specifying file patterns.
3902
3906
3903 Returns 0 if a match is found, 1 otherwise.
3907 Returns 0 if a match is found, 1 otherwise.
3904
3908
3905 """
3909 """
3906 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3910 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3907
3911
3908 end = '\n'
3912 end = '\n'
3909 if opts.get('print0'):
3913 if opts.get('print0'):
3910 end = '\0'
3914 end = '\0'
3911 fm = ui.formatter('files', opts)
3915 fm = ui.formatter('files', opts)
3912 fmt = '%s' + end
3916 fmt = '%s' + end
3913
3917
3914 m = scmutil.match(ctx, pats, opts)
3918 m = scmutil.match(ctx, pats, opts)
3915 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3919 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3916
3920
3917 fm.end()
3921 fm.end()
3918
3922
3919 return ret
3923 return ret
3920
3924
3921 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3925 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3922 def forget(ui, repo, *pats, **opts):
3926 def forget(ui, repo, *pats, **opts):
3923 """forget the specified files on the next commit
3927 """forget the specified files on the next commit
3924
3928
3925 Mark the specified files so they will no longer be tracked
3929 Mark the specified files so they will no longer be tracked
3926 after the next commit.
3930 after the next commit.
3927
3931
3928 This only removes files from the current branch, not from the
3932 This only removes files from the current branch, not from the
3929 entire project history, and it does not delete them from the
3933 entire project history, and it does not delete them from the
3930 working directory.
3934 working directory.
3931
3935
3932 To delete the file from the working directory, see :hg:`remove`.
3936 To delete the file from the working directory, see :hg:`remove`.
3933
3937
3934 To undo a forget before the next commit, see :hg:`add`.
3938 To undo a forget before the next commit, see :hg:`add`.
3935
3939
3936 .. container:: verbose
3940 .. container:: verbose
3937
3941
3938 Examples:
3942 Examples:
3939
3943
3940 - forget newly-added binary files::
3944 - forget newly-added binary files::
3941
3945
3942 hg forget "set:added() and binary()"
3946 hg forget "set:added() and binary()"
3943
3947
3944 - forget files that would be excluded by .hgignore::
3948 - forget files that would be excluded by .hgignore::
3945
3949
3946 hg forget "set:hgignore()"
3950 hg forget "set:hgignore()"
3947
3951
3948 Returns 0 on success.
3952 Returns 0 on success.
3949 """
3953 """
3950
3954
3951 if not pats:
3955 if not pats:
3952 raise error.Abort(_('no files specified'))
3956 raise error.Abort(_('no files specified'))
3953
3957
3954 m = scmutil.match(repo[None], pats, opts)
3958 m = scmutil.match(repo[None], pats, opts)
3955 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3959 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3956 return rejected and 1 or 0
3960 return rejected and 1 or 0
3957
3961
3958 @command(
3962 @command(
3959 'graft',
3963 'graft',
3960 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3964 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3961 ('c', 'continue', False, _('resume interrupted graft')),
3965 ('c', 'continue', False, _('resume interrupted graft')),
3962 ('e', 'edit', False, _('invoke editor on commit messages')),
3966 ('e', 'edit', False, _('invoke editor on commit messages')),
3963 ('', 'log', None, _('append graft info to log message')),
3967 ('', 'log', None, _('append graft info to log message')),
3964 ('f', 'force', False, _('force graft')),
3968 ('f', 'force', False, _('force graft')),
3965 ('D', 'currentdate', False,
3969 ('D', 'currentdate', False,
3966 _('record the current date as commit date')),
3970 _('record the current date as commit date')),
3967 ('U', 'currentuser', False,
3971 ('U', 'currentuser', False,
3968 _('record the current user as committer'), _('DATE'))]
3972 _('record the current user as committer'), _('DATE'))]
3969 + commitopts2 + mergetoolopts + dryrunopts,
3973 + commitopts2 + mergetoolopts + dryrunopts,
3970 _('[OPTION]... [-r REV]... REV...'))
3974 _('[OPTION]... [-r REV]... REV...'))
3971 def graft(ui, repo, *revs, **opts):
3975 def graft(ui, repo, *revs, **opts):
3972 '''copy changes from other branches onto the current branch
3976 '''copy changes from other branches onto the current branch
3973
3977
3974 This command uses Mercurial's merge logic to copy individual
3978 This command uses Mercurial's merge logic to copy individual
3975 changes from other branches without merging branches in the
3979 changes from other branches without merging branches in the
3976 history graph. This is sometimes known as 'backporting' or
3980 history graph. This is sometimes known as 'backporting' or
3977 'cherry-picking'. By default, graft will copy user, date, and
3981 'cherry-picking'. By default, graft will copy user, date, and
3978 description from the source changesets.
3982 description from the source changesets.
3979
3983
3980 Changesets that are ancestors of the current revision, that have
3984 Changesets that are ancestors of the current revision, that have
3981 already been grafted, or that are merges will be skipped.
3985 already been grafted, or that are merges will be skipped.
3982
3986
3983 If --log is specified, log messages will have a comment appended
3987 If --log is specified, log messages will have a comment appended
3984 of the form::
3988 of the form::
3985
3989
3986 (grafted from CHANGESETHASH)
3990 (grafted from CHANGESETHASH)
3987
3991
3988 If --force is specified, revisions will be grafted even if they
3992 If --force is specified, revisions will be grafted even if they
3989 are already ancestors of or have been grafted to the destination.
3993 are already ancestors of or have been grafted to the destination.
3990 This is useful when the revisions have since been backed out.
3994 This is useful when the revisions have since been backed out.
3991
3995
3992 If a graft merge results in conflicts, the graft process is
3996 If a graft merge results in conflicts, the graft process is
3993 interrupted so that the current merge can be manually resolved.
3997 interrupted so that the current merge can be manually resolved.
3994 Once all conflicts are addressed, the graft process can be
3998 Once all conflicts are addressed, the graft process can be
3995 continued with the -c/--continue option.
3999 continued with the -c/--continue option.
3996
4000
3997 .. note::
4001 .. note::
3998
4002
3999 The -c/--continue option does not reapply earlier options, except
4003 The -c/--continue option does not reapply earlier options, except
4000 for --force.
4004 for --force.
4001
4005
4002 .. container:: verbose
4006 .. container:: verbose
4003
4007
4004 Examples:
4008 Examples:
4005
4009
4006 - copy a single change to the stable branch and edit its description::
4010 - copy a single change to the stable branch and edit its description::
4007
4011
4008 hg update stable
4012 hg update stable
4009 hg graft --edit 9393
4013 hg graft --edit 9393
4010
4014
4011 - graft a range of changesets with one exception, updating dates::
4015 - graft a range of changesets with one exception, updating dates::
4012
4016
4013 hg graft -D "2085::2093 and not 2091"
4017 hg graft -D "2085::2093 and not 2091"
4014
4018
4015 - continue a graft after resolving conflicts::
4019 - continue a graft after resolving conflicts::
4016
4020
4017 hg graft -c
4021 hg graft -c
4018
4022
4019 - show the source of a grafted changeset::
4023 - show the source of a grafted changeset::
4020
4024
4021 hg log --debug -r .
4025 hg log --debug -r .
4022
4026
4023 - show revisions sorted by date::
4027 - show revisions sorted by date::
4024
4028
4025 hg log -r 'sort(all(), date)'
4029 hg log -r 'sort(all(), date)'
4026
4030
4027 See :hg:`help revisions` and :hg:`help revsets` for more about
4031 See :hg:`help revisions` and :hg:`help revsets` for more about
4028 specifying revisions.
4032 specifying revisions.
4029
4033
4030 Returns 0 on successful completion.
4034 Returns 0 on successful completion.
4031 '''
4035 '''
4032 with repo.wlock():
4036 with repo.wlock():
4033 return _dograft(ui, repo, *revs, **opts)
4037 return _dograft(ui, repo, *revs, **opts)
4034
4038
4035 def _dograft(ui, repo, *revs, **opts):
4039 def _dograft(ui, repo, *revs, **opts):
4036 if revs and opts['rev']:
4040 if revs and opts['rev']:
4037 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4041 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
4038 'revision ordering!\n'))
4042 'revision ordering!\n'))
4039
4043
4040 revs = list(revs)
4044 revs = list(revs)
4041 revs.extend(opts['rev'])
4045 revs.extend(opts['rev'])
4042
4046
4043 if not opts.get('user') and opts.get('currentuser'):
4047 if not opts.get('user') and opts.get('currentuser'):
4044 opts['user'] = ui.username()
4048 opts['user'] = ui.username()
4045 if not opts.get('date') and opts.get('currentdate'):
4049 if not opts.get('date') and opts.get('currentdate'):
4046 opts['date'] = "%d %d" % util.makedate()
4050 opts['date'] = "%d %d" % util.makedate()
4047
4051
4048 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4052 editor = cmdutil.getcommiteditor(editform='graft', **opts)
4049
4053
4050 cont = False
4054 cont = False
4051 if opts['continue']:
4055 if opts['continue']:
4052 cont = True
4056 cont = True
4053 if revs:
4057 if revs:
4054 raise error.Abort(_("can't specify --continue and revisions"))
4058 raise error.Abort(_("can't specify --continue and revisions"))
4055 # read in unfinished revisions
4059 # read in unfinished revisions
4056 try:
4060 try:
4057 nodes = repo.vfs.read('graftstate').splitlines()
4061 nodes = repo.vfs.read('graftstate').splitlines()
4058 revs = [repo[node].rev() for node in nodes]
4062 revs = [repo[node].rev() for node in nodes]
4059 except IOError as inst:
4063 except IOError as inst:
4060 if inst.errno != errno.ENOENT:
4064 if inst.errno != errno.ENOENT:
4061 raise
4065 raise
4062 cmdutil.wrongtooltocontinue(repo, _('graft'))
4066 cmdutil.wrongtooltocontinue(repo, _('graft'))
4063 else:
4067 else:
4064 cmdutil.checkunfinished(repo)
4068 cmdutil.checkunfinished(repo)
4065 cmdutil.bailifchanged(repo)
4069 cmdutil.bailifchanged(repo)
4066 if not revs:
4070 if not revs:
4067 raise error.Abort(_('no revisions specified'))
4071 raise error.Abort(_('no revisions specified'))
4068 revs = scmutil.revrange(repo, revs)
4072 revs = scmutil.revrange(repo, revs)
4069
4073
4070 skipped = set()
4074 skipped = set()
4071 # check for merges
4075 # check for merges
4072 for rev in repo.revs('%ld and merge()', revs):
4076 for rev in repo.revs('%ld and merge()', revs):
4073 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4077 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
4074 skipped.add(rev)
4078 skipped.add(rev)
4075 revs = [r for r in revs if r not in skipped]
4079 revs = [r for r in revs if r not in skipped]
4076 if not revs:
4080 if not revs:
4077 return -1
4081 return -1
4078
4082
4079 # Don't check in the --continue case, in effect retaining --force across
4083 # Don't check in the --continue case, in effect retaining --force across
4080 # --continues. That's because without --force, any revisions we decided to
4084 # --continues. That's because without --force, any revisions we decided to
4081 # skip would have been filtered out here, so they wouldn't have made their
4085 # skip would have been filtered out here, so they wouldn't have made their
4082 # way to the graftstate. With --force, any revisions we would have otherwise
4086 # way to the graftstate. With --force, any revisions we would have otherwise
4083 # skipped would not have been filtered out, and if they hadn't been applied
4087 # skipped would not have been filtered out, and if they hadn't been applied
4084 # already, they'd have been in the graftstate.
4088 # already, they'd have been in the graftstate.
4085 if not (cont or opts.get('force')):
4089 if not (cont or opts.get('force')):
4086 # check for ancestors of dest branch
4090 # check for ancestors of dest branch
4087 crev = repo['.'].rev()
4091 crev = repo['.'].rev()
4088 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4092 ancestors = repo.changelog.ancestors([crev], inclusive=True)
4089 # Cannot use x.remove(y) on smart set, this has to be a list.
4093 # Cannot use x.remove(y) on smart set, this has to be a list.
4090 # XXX make this lazy in the future
4094 # XXX make this lazy in the future
4091 revs = list(revs)
4095 revs = list(revs)
4092 # don't mutate while iterating, create a copy
4096 # don't mutate while iterating, create a copy
4093 for rev in list(revs):
4097 for rev in list(revs):
4094 if rev in ancestors:
4098 if rev in ancestors:
4095 ui.warn(_('skipping ancestor revision %d:%s\n') %
4099 ui.warn(_('skipping ancestor revision %d:%s\n') %
4096 (rev, repo[rev]))
4100 (rev, repo[rev]))
4097 # XXX remove on list is slow
4101 # XXX remove on list is slow
4098 revs.remove(rev)
4102 revs.remove(rev)
4099 if not revs:
4103 if not revs:
4100 return -1
4104 return -1
4101
4105
4102 # analyze revs for earlier grafts
4106 # analyze revs for earlier grafts
4103 ids = {}
4107 ids = {}
4104 for ctx in repo.set("%ld", revs):
4108 for ctx in repo.set("%ld", revs):
4105 ids[ctx.hex()] = ctx.rev()
4109 ids[ctx.hex()] = ctx.rev()
4106 n = ctx.extra().get('source')
4110 n = ctx.extra().get('source')
4107 if n:
4111 if n:
4108 ids[n] = ctx.rev()
4112 ids[n] = ctx.rev()
4109
4113
4110 # check ancestors for earlier grafts
4114 # check ancestors for earlier grafts
4111 ui.debug('scanning for duplicate grafts\n')
4115 ui.debug('scanning for duplicate grafts\n')
4112
4116
4113 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4117 for rev in repo.changelog.findmissingrevs(revs, [crev]):
4114 ctx = repo[rev]
4118 ctx = repo[rev]
4115 n = ctx.extra().get('source')
4119 n = ctx.extra().get('source')
4116 if n in ids:
4120 if n in ids:
4117 try:
4121 try:
4118 r = repo[n].rev()
4122 r = repo[n].rev()
4119 except error.RepoLookupError:
4123 except error.RepoLookupError:
4120 r = None
4124 r = None
4121 if r in revs:
4125 if r in revs:
4122 ui.warn(_('skipping revision %d:%s '
4126 ui.warn(_('skipping revision %d:%s '
4123 '(already grafted to %d:%s)\n')
4127 '(already grafted to %d:%s)\n')
4124 % (r, repo[r], rev, ctx))
4128 % (r, repo[r], rev, ctx))
4125 revs.remove(r)
4129 revs.remove(r)
4126 elif ids[n] in revs:
4130 elif ids[n] in revs:
4127 if r is None:
4131 if r is None:
4128 ui.warn(_('skipping already grafted revision %d:%s '
4132 ui.warn(_('skipping already grafted revision %d:%s '
4129 '(%d:%s also has unknown origin %s)\n')
4133 '(%d:%s also has unknown origin %s)\n')
4130 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4134 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
4131 else:
4135 else:
4132 ui.warn(_('skipping already grafted revision %d:%s '
4136 ui.warn(_('skipping already grafted revision %d:%s '
4133 '(%d:%s also has origin %d:%s)\n')
4137 '(%d:%s also has origin %d:%s)\n')
4134 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4138 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
4135 revs.remove(ids[n])
4139 revs.remove(ids[n])
4136 elif ctx.hex() in ids:
4140 elif ctx.hex() in ids:
4137 r = ids[ctx.hex()]
4141 r = ids[ctx.hex()]
4138 ui.warn(_('skipping already grafted revision %d:%s '
4142 ui.warn(_('skipping already grafted revision %d:%s '
4139 '(was grafted from %d:%s)\n') %
4143 '(was grafted from %d:%s)\n') %
4140 (r, repo[r], rev, ctx))
4144 (r, repo[r], rev, ctx))
4141 revs.remove(r)
4145 revs.remove(r)
4142 if not revs:
4146 if not revs:
4143 return -1
4147 return -1
4144
4148
4145 for pos, ctx in enumerate(repo.set("%ld", revs)):
4149 for pos, ctx in enumerate(repo.set("%ld", revs)):
4146 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4150 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4147 ctx.description().split('\n', 1)[0])
4151 ctx.description().split('\n', 1)[0])
4148 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4152 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4149 if names:
4153 if names:
4150 desc += ' (%s)' % ' '.join(names)
4154 desc += ' (%s)' % ' '.join(names)
4151 ui.status(_('grafting %s\n') % desc)
4155 ui.status(_('grafting %s\n') % desc)
4152 if opts.get('dry_run'):
4156 if opts.get('dry_run'):
4153 continue
4157 continue
4154
4158
4155 source = ctx.extra().get('source')
4159 source = ctx.extra().get('source')
4156 extra = {}
4160 extra = {}
4157 if source:
4161 if source:
4158 extra['source'] = source
4162 extra['source'] = source
4159 extra['intermediate-source'] = ctx.hex()
4163 extra['intermediate-source'] = ctx.hex()
4160 else:
4164 else:
4161 extra['source'] = ctx.hex()
4165 extra['source'] = ctx.hex()
4162 user = ctx.user()
4166 user = ctx.user()
4163 if opts.get('user'):
4167 if opts.get('user'):
4164 user = opts['user']
4168 user = opts['user']
4165 date = ctx.date()
4169 date = ctx.date()
4166 if opts.get('date'):
4170 if opts.get('date'):
4167 date = opts['date']
4171 date = opts['date']
4168 message = ctx.description()
4172 message = ctx.description()
4169 if opts.get('log'):
4173 if opts.get('log'):
4170 message += '\n(grafted from %s)' % ctx.hex()
4174 message += '\n(grafted from %s)' % ctx.hex()
4171
4175
4172 # we don't merge the first commit when continuing
4176 # we don't merge the first commit when continuing
4173 if not cont:
4177 if not cont:
4174 # perform the graft merge with p1(rev) as 'ancestor'
4178 # perform the graft merge with p1(rev) as 'ancestor'
4175 try:
4179 try:
4176 # ui.forcemerge is an internal variable, do not document
4180 # ui.forcemerge is an internal variable, do not document
4177 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4181 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4178 'graft')
4182 'graft')
4179 stats = mergemod.graft(repo, ctx, ctx.p1(),
4183 stats = mergemod.graft(repo, ctx, ctx.p1(),
4180 ['local', 'graft'])
4184 ['local', 'graft'])
4181 finally:
4185 finally:
4182 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4186 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4183 # report any conflicts
4187 # report any conflicts
4184 if stats and stats[3] > 0:
4188 if stats and stats[3] > 0:
4185 # write out state for --continue
4189 # write out state for --continue
4186 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4190 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4187 repo.vfs.write('graftstate', ''.join(nodelines))
4191 repo.vfs.write('graftstate', ''.join(nodelines))
4188 extra = ''
4192 extra = ''
4189 if opts.get('user'):
4193 if opts.get('user'):
4190 extra += ' --user %s' % opts['user']
4194 extra += ' --user %s' % opts['user']
4191 if opts.get('date'):
4195 if opts.get('date'):
4192 extra += ' --date %s' % opts['date']
4196 extra += ' --date %s' % opts['date']
4193 if opts.get('log'):
4197 if opts.get('log'):
4194 extra += ' --log'
4198 extra += ' --log'
4195 hint=_('use hg resolve and hg graft --continue%s') % extra
4199 hint=_('use hg resolve and hg graft --continue%s') % extra
4196 raise error.Abort(
4200 raise error.Abort(
4197 _("unresolved conflicts, can't continue"),
4201 _("unresolved conflicts, can't continue"),
4198 hint=hint)
4202 hint=hint)
4199 else:
4203 else:
4200 cont = False
4204 cont = False
4201
4205
4202 # commit
4206 # commit
4203 node = repo.commit(text=message, user=user,
4207 node = repo.commit(text=message, user=user,
4204 date=date, extra=extra, editor=editor)
4208 date=date, extra=extra, editor=editor)
4205 if node is None:
4209 if node is None:
4206 ui.warn(
4210 ui.warn(
4207 _('note: graft of %d:%s created no changes to commit\n') %
4211 _('note: graft of %d:%s created no changes to commit\n') %
4208 (ctx.rev(), ctx))
4212 (ctx.rev(), ctx))
4209
4213
4210 # remove state when we complete successfully
4214 # remove state when we complete successfully
4211 if not opts.get('dry_run'):
4215 if not opts.get('dry_run'):
4212 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4216 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4213
4217
4214 return 0
4218 return 0
4215
4219
4216 @command('grep',
4220 @command('grep',
4217 [('0', 'print0', None, _('end fields with NUL')),
4221 [('0', 'print0', None, _('end fields with NUL')),
4218 ('', 'all', None, _('print all revisions that match')),
4222 ('', 'all', None, _('print all revisions that match')),
4219 ('a', 'text', None, _('treat all files as text')),
4223 ('a', 'text', None, _('treat all files as text')),
4220 ('f', 'follow', None,
4224 ('f', 'follow', None,
4221 _('follow changeset history,'
4225 _('follow changeset history,'
4222 ' or file history across copies and renames')),
4226 ' or file history across copies and renames')),
4223 ('i', 'ignore-case', None, _('ignore case when matching')),
4227 ('i', 'ignore-case', None, _('ignore case when matching')),
4224 ('l', 'files-with-matches', None,
4228 ('l', 'files-with-matches', None,
4225 _('print only filenames and revisions that match')),
4229 _('print only filenames and revisions that match')),
4226 ('n', 'line-number', None, _('print matching line numbers')),
4230 ('n', 'line-number', None, _('print matching line numbers')),
4227 ('r', 'rev', [],
4231 ('r', 'rev', [],
4228 _('only search files changed within revision range'), _('REV')),
4232 _('only search files changed within revision range'), _('REV')),
4229 ('u', 'user', None, _('list the author (long with -v)')),
4233 ('u', 'user', None, _('list the author (long with -v)')),
4230 ('d', 'date', None, _('list the date (short with -q)')),
4234 ('d', 'date', None, _('list the date (short with -q)')),
4231 ] + walkopts,
4235 ] + walkopts,
4232 _('[OPTION]... PATTERN [FILE]...'),
4236 _('[OPTION]... PATTERN [FILE]...'),
4233 inferrepo=True)
4237 inferrepo=True)
4234 def grep(ui, repo, pattern, *pats, **opts):
4238 def grep(ui, repo, pattern, *pats, **opts):
4235 """search for a pattern in specified files and revisions
4239 """search for a pattern in specified files and revisions
4236
4240
4237 Search revisions of files for a regular expression.
4241 Search revisions of files for a regular expression.
4238
4242
4239 This command behaves differently than Unix grep. It only accepts
4243 This command behaves differently than Unix grep. It only accepts
4240 Python/Perl regexps. It searches repository history, not the
4244 Python/Perl regexps. It searches repository history, not the
4241 working directory. It always prints the revision number in which a
4245 working directory. It always prints the revision number in which a
4242 match appears.
4246 match appears.
4243
4247
4244 By default, grep only prints output for the first revision of a
4248 By default, grep only prints output for the first revision of a
4245 file in which it finds a match. To get it to print every revision
4249 file in which it finds a match. To get it to print every revision
4246 that contains a change in match status ("-" for a match that
4250 that contains a change in match status ("-" for a match that
4247 becomes a non-match, or "+" for a non-match that becomes a match),
4251 becomes a non-match, or "+" for a non-match that becomes a match),
4248 use the --all flag.
4252 use the --all flag.
4249
4253
4250 Returns 0 if a match is found, 1 otherwise.
4254 Returns 0 if a match is found, 1 otherwise.
4251 """
4255 """
4252 reflags = re.M
4256 reflags = re.M
4253 if opts.get('ignore_case'):
4257 if opts.get('ignore_case'):
4254 reflags |= re.I
4258 reflags |= re.I
4255 try:
4259 try:
4256 regexp = util.re.compile(pattern, reflags)
4260 regexp = util.re.compile(pattern, reflags)
4257 except re.error as inst:
4261 except re.error as inst:
4258 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4262 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4259 return 1
4263 return 1
4260 sep, eol = ':', '\n'
4264 sep, eol = ':', '\n'
4261 if opts.get('print0'):
4265 if opts.get('print0'):
4262 sep = eol = '\0'
4266 sep = eol = '\0'
4263
4267
4264 getfile = util.lrucachefunc(repo.file)
4268 getfile = util.lrucachefunc(repo.file)
4265
4269
4266 def matchlines(body):
4270 def matchlines(body):
4267 begin = 0
4271 begin = 0
4268 linenum = 0
4272 linenum = 0
4269 while begin < len(body):
4273 while begin < len(body):
4270 match = regexp.search(body, begin)
4274 match = regexp.search(body, begin)
4271 if not match:
4275 if not match:
4272 break
4276 break
4273 mstart, mend = match.span()
4277 mstart, mend = match.span()
4274 linenum += body.count('\n', begin, mstart) + 1
4278 linenum += body.count('\n', begin, mstart) + 1
4275 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4279 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4276 begin = body.find('\n', mend) + 1 or len(body) + 1
4280 begin = body.find('\n', mend) + 1 or len(body) + 1
4277 lend = begin - 1
4281 lend = begin - 1
4278 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4282 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4279
4283
4280 class linestate(object):
4284 class linestate(object):
4281 def __init__(self, line, linenum, colstart, colend):
4285 def __init__(self, line, linenum, colstart, colend):
4282 self.line = line
4286 self.line = line
4283 self.linenum = linenum
4287 self.linenum = linenum
4284 self.colstart = colstart
4288 self.colstart = colstart
4285 self.colend = colend
4289 self.colend = colend
4286
4290
4287 def __hash__(self):
4291 def __hash__(self):
4288 return hash((self.linenum, self.line))
4292 return hash((self.linenum, self.line))
4289
4293
4290 def __eq__(self, other):
4294 def __eq__(self, other):
4291 return self.line == other.line
4295 return self.line == other.line
4292
4296
4293 def __iter__(self):
4297 def __iter__(self):
4294 yield (self.line[:self.colstart], '')
4298 yield (self.line[:self.colstart], '')
4295 yield (self.line[self.colstart:self.colend], 'grep.match')
4299 yield (self.line[self.colstart:self.colend], 'grep.match')
4296 rest = self.line[self.colend:]
4300 rest = self.line[self.colend:]
4297 while rest != '':
4301 while rest != '':
4298 match = regexp.search(rest)
4302 match = regexp.search(rest)
4299 if not match:
4303 if not match:
4300 yield (rest, '')
4304 yield (rest, '')
4301 break
4305 break
4302 mstart, mend = match.span()
4306 mstart, mend = match.span()
4303 yield (rest[:mstart], '')
4307 yield (rest[:mstart], '')
4304 yield (rest[mstart:mend], 'grep.match')
4308 yield (rest[mstart:mend], 'grep.match')
4305 rest = rest[mend:]
4309 rest = rest[mend:]
4306
4310
4307 matches = {}
4311 matches = {}
4308 copies = {}
4312 copies = {}
4309 def grepbody(fn, rev, body):
4313 def grepbody(fn, rev, body):
4310 matches[rev].setdefault(fn, [])
4314 matches[rev].setdefault(fn, [])
4311 m = matches[rev][fn]
4315 m = matches[rev][fn]
4312 for lnum, cstart, cend, line in matchlines(body):
4316 for lnum, cstart, cend, line in matchlines(body):
4313 s = linestate(line, lnum, cstart, cend)
4317 s = linestate(line, lnum, cstart, cend)
4314 m.append(s)
4318 m.append(s)
4315
4319
4316 def difflinestates(a, b):
4320 def difflinestates(a, b):
4317 sm = difflib.SequenceMatcher(None, a, b)
4321 sm = difflib.SequenceMatcher(None, a, b)
4318 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4322 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4319 if tag == 'insert':
4323 if tag == 'insert':
4320 for i in xrange(blo, bhi):
4324 for i in xrange(blo, bhi):
4321 yield ('+', b[i])
4325 yield ('+', b[i])
4322 elif tag == 'delete':
4326 elif tag == 'delete':
4323 for i in xrange(alo, ahi):
4327 for i in xrange(alo, ahi):
4324 yield ('-', a[i])
4328 yield ('-', a[i])
4325 elif tag == 'replace':
4329 elif tag == 'replace':
4326 for i in xrange(alo, ahi):
4330 for i in xrange(alo, ahi):
4327 yield ('-', a[i])
4331 yield ('-', a[i])
4328 for i in xrange(blo, bhi):
4332 for i in xrange(blo, bhi):
4329 yield ('+', b[i])
4333 yield ('+', b[i])
4330
4334
4331 def display(fn, ctx, pstates, states):
4335 def display(fn, ctx, pstates, states):
4332 rev = ctx.rev()
4336 rev = ctx.rev()
4333 if ui.quiet:
4337 if ui.quiet:
4334 datefunc = util.shortdate
4338 datefunc = util.shortdate
4335 else:
4339 else:
4336 datefunc = util.datestr
4340 datefunc = util.datestr
4337 found = False
4341 found = False
4338 @util.cachefunc
4342 @util.cachefunc
4339 def binary():
4343 def binary():
4340 flog = getfile(fn)
4344 flog = getfile(fn)
4341 return util.binary(flog.read(ctx.filenode(fn)))
4345 return util.binary(flog.read(ctx.filenode(fn)))
4342
4346
4343 if opts.get('all'):
4347 if opts.get('all'):
4344 iter = difflinestates(pstates, states)
4348 iter = difflinestates(pstates, states)
4345 else:
4349 else:
4346 iter = [('', l) for l in states]
4350 iter = [('', l) for l in states]
4347 for change, l in iter:
4351 for change, l in iter:
4348 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4352 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4349
4353
4350 if opts.get('line_number'):
4354 if opts.get('line_number'):
4351 cols.append((str(l.linenum), 'grep.linenumber'))
4355 cols.append((str(l.linenum), 'grep.linenumber'))
4352 if opts.get('all'):
4356 if opts.get('all'):
4353 cols.append((change, 'grep.change'))
4357 cols.append((change, 'grep.change'))
4354 if opts.get('user'):
4358 if opts.get('user'):
4355 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4359 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4356 if opts.get('date'):
4360 if opts.get('date'):
4357 cols.append((datefunc(ctx.date()), 'grep.date'))
4361 cols.append((datefunc(ctx.date()), 'grep.date'))
4358 for col, label in cols[:-1]:
4362 for col, label in cols[:-1]:
4359 ui.write(col, label=label)
4363 ui.write(col, label=label)
4360 ui.write(sep, label='grep.sep')
4364 ui.write(sep, label='grep.sep')
4361 ui.write(cols[-1][0], label=cols[-1][1])
4365 ui.write(cols[-1][0], label=cols[-1][1])
4362 if not opts.get('files_with_matches'):
4366 if not opts.get('files_with_matches'):
4363 ui.write(sep, label='grep.sep')
4367 ui.write(sep, label='grep.sep')
4364 if not opts.get('text') and binary():
4368 if not opts.get('text') and binary():
4365 ui.write(" Binary file matches")
4369 ui.write(" Binary file matches")
4366 else:
4370 else:
4367 for s, label in l:
4371 for s, label in l:
4368 ui.write(s, label=label)
4372 ui.write(s, label=label)
4369 ui.write(eol)
4373 ui.write(eol)
4370 found = True
4374 found = True
4371 if opts.get('files_with_matches'):
4375 if opts.get('files_with_matches'):
4372 break
4376 break
4373 return found
4377 return found
4374
4378
4375 skip = {}
4379 skip = {}
4376 revfiles = {}
4380 revfiles = {}
4377 matchfn = scmutil.match(repo[None], pats, opts)
4381 matchfn = scmutil.match(repo[None], pats, opts)
4378 found = False
4382 found = False
4379 follow = opts.get('follow')
4383 follow = opts.get('follow')
4380
4384
4381 def prep(ctx, fns):
4385 def prep(ctx, fns):
4382 rev = ctx.rev()
4386 rev = ctx.rev()
4383 pctx = ctx.p1()
4387 pctx = ctx.p1()
4384 parent = pctx.rev()
4388 parent = pctx.rev()
4385 matches.setdefault(rev, {})
4389 matches.setdefault(rev, {})
4386 matches.setdefault(parent, {})
4390 matches.setdefault(parent, {})
4387 files = revfiles.setdefault(rev, [])
4391 files = revfiles.setdefault(rev, [])
4388 for fn in fns:
4392 for fn in fns:
4389 flog = getfile(fn)
4393 flog = getfile(fn)
4390 try:
4394 try:
4391 fnode = ctx.filenode(fn)
4395 fnode = ctx.filenode(fn)
4392 except error.LookupError:
4396 except error.LookupError:
4393 continue
4397 continue
4394
4398
4395 copied = flog.renamed(fnode)
4399 copied = flog.renamed(fnode)
4396 copy = follow and copied and copied[0]
4400 copy = follow and copied and copied[0]
4397 if copy:
4401 if copy:
4398 copies.setdefault(rev, {})[fn] = copy
4402 copies.setdefault(rev, {})[fn] = copy
4399 if fn in skip:
4403 if fn in skip:
4400 if copy:
4404 if copy:
4401 skip[copy] = True
4405 skip[copy] = True
4402 continue
4406 continue
4403 files.append(fn)
4407 files.append(fn)
4404
4408
4405 if fn not in matches[rev]:
4409 if fn not in matches[rev]:
4406 grepbody(fn, rev, flog.read(fnode))
4410 grepbody(fn, rev, flog.read(fnode))
4407
4411
4408 pfn = copy or fn
4412 pfn = copy or fn
4409 if pfn not in matches[parent]:
4413 if pfn not in matches[parent]:
4410 try:
4414 try:
4411 fnode = pctx.filenode(pfn)
4415 fnode = pctx.filenode(pfn)
4412 grepbody(pfn, parent, flog.read(fnode))
4416 grepbody(pfn, parent, flog.read(fnode))
4413 except error.LookupError:
4417 except error.LookupError:
4414 pass
4418 pass
4415
4419
4416 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4420 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4417 rev = ctx.rev()
4421 rev = ctx.rev()
4418 parent = ctx.p1().rev()
4422 parent = ctx.p1().rev()
4419 for fn in sorted(revfiles.get(rev, [])):
4423 for fn in sorted(revfiles.get(rev, [])):
4420 states = matches[rev][fn]
4424 states = matches[rev][fn]
4421 copy = copies.get(rev, {}).get(fn)
4425 copy = copies.get(rev, {}).get(fn)
4422 if fn in skip:
4426 if fn in skip:
4423 if copy:
4427 if copy:
4424 skip[copy] = True
4428 skip[copy] = True
4425 continue
4429 continue
4426 pstates = matches.get(parent, {}).get(copy or fn, [])
4430 pstates = matches.get(parent, {}).get(copy or fn, [])
4427 if pstates or states:
4431 if pstates or states:
4428 r = display(fn, ctx, pstates, states)
4432 r = display(fn, ctx, pstates, states)
4429 found = found or r
4433 found = found or r
4430 if r and not opts.get('all'):
4434 if r and not opts.get('all'):
4431 skip[fn] = True
4435 skip[fn] = True
4432 if copy:
4436 if copy:
4433 skip[copy] = True
4437 skip[copy] = True
4434 del matches[rev]
4438 del matches[rev]
4435 del revfiles[rev]
4439 del revfiles[rev]
4436
4440
4437 return not found
4441 return not found
4438
4442
4439 @command('heads',
4443 @command('heads',
4440 [('r', 'rev', '',
4444 [('r', 'rev', '',
4441 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4445 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4442 ('t', 'topo', False, _('show topological heads only')),
4446 ('t', 'topo', False, _('show topological heads only')),
4443 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4447 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4444 ('c', 'closed', False, _('show normal and closed branch heads')),
4448 ('c', 'closed', False, _('show normal and closed branch heads')),
4445 ] + templateopts,
4449 ] + templateopts,
4446 _('[-ct] [-r STARTREV] [REV]...'))
4450 _('[-ct] [-r STARTREV] [REV]...'))
4447 def heads(ui, repo, *branchrevs, **opts):
4451 def heads(ui, repo, *branchrevs, **opts):
4448 """show branch heads
4452 """show branch heads
4449
4453
4450 With no arguments, show all open branch heads in the repository.
4454 With no arguments, show all open branch heads in the repository.
4451 Branch heads are changesets that have no descendants on the
4455 Branch heads are changesets that have no descendants on the
4452 same branch. They are where development generally takes place and
4456 same branch. They are where development generally takes place and
4453 are the usual targets for update and merge operations.
4457 are the usual targets for update and merge operations.
4454
4458
4455 If one or more REVs are given, only open branch heads on the
4459 If one or more REVs are given, only open branch heads on the
4456 branches associated with the specified changesets are shown. This
4460 branches associated with the specified changesets are shown. This
4457 means that you can use :hg:`heads .` to see the heads on the
4461 means that you can use :hg:`heads .` to see the heads on the
4458 currently checked-out branch.
4462 currently checked-out branch.
4459
4463
4460 If -c/--closed is specified, also show branch heads marked closed
4464 If -c/--closed is specified, also show branch heads marked closed
4461 (see :hg:`commit --close-branch`).
4465 (see :hg:`commit --close-branch`).
4462
4466
4463 If STARTREV is specified, only those heads that are descendants of
4467 If STARTREV is specified, only those heads that are descendants of
4464 STARTREV will be displayed.
4468 STARTREV will be displayed.
4465
4469
4466 If -t/--topo is specified, named branch mechanics will be ignored and only
4470 If -t/--topo is specified, named branch mechanics will be ignored and only
4467 topological heads (changesets with no children) will be shown.
4471 topological heads (changesets with no children) will be shown.
4468
4472
4469 Returns 0 if matching heads are found, 1 if not.
4473 Returns 0 if matching heads are found, 1 if not.
4470 """
4474 """
4471
4475
4472 start = None
4476 start = None
4473 if 'rev' in opts:
4477 if 'rev' in opts:
4474 start = scmutil.revsingle(repo, opts['rev'], None).node()
4478 start = scmutil.revsingle(repo, opts['rev'], None).node()
4475
4479
4476 if opts.get('topo'):
4480 if opts.get('topo'):
4477 heads = [repo[h] for h in repo.heads(start)]
4481 heads = [repo[h] for h in repo.heads(start)]
4478 else:
4482 else:
4479 heads = []
4483 heads = []
4480 for branch in repo.branchmap():
4484 for branch in repo.branchmap():
4481 heads += repo.branchheads(branch, start, opts.get('closed'))
4485 heads += repo.branchheads(branch, start, opts.get('closed'))
4482 heads = [repo[h] for h in heads]
4486 heads = [repo[h] for h in heads]
4483
4487
4484 if branchrevs:
4488 if branchrevs:
4485 branches = set(repo[br].branch() for br in branchrevs)
4489 branches = set(repo[br].branch() for br in branchrevs)
4486 heads = [h for h in heads if h.branch() in branches]
4490 heads = [h for h in heads if h.branch() in branches]
4487
4491
4488 if opts.get('active') and branchrevs:
4492 if opts.get('active') and branchrevs:
4489 dagheads = repo.heads(start)
4493 dagheads = repo.heads(start)
4490 heads = [h for h in heads if h.node() in dagheads]
4494 heads = [h for h in heads if h.node() in dagheads]
4491
4495
4492 if branchrevs:
4496 if branchrevs:
4493 haveheads = set(h.branch() for h in heads)
4497 haveheads = set(h.branch() for h in heads)
4494 if branches - haveheads:
4498 if branches - haveheads:
4495 headless = ', '.join(b for b in branches - haveheads)
4499 headless = ', '.join(b for b in branches - haveheads)
4496 msg = _('no open branch heads found on branches %s')
4500 msg = _('no open branch heads found on branches %s')
4497 if opts.get('rev'):
4501 if opts.get('rev'):
4498 msg += _(' (started at %s)') % opts['rev']
4502 msg += _(' (started at %s)') % opts['rev']
4499 ui.warn((msg + '\n') % headless)
4503 ui.warn((msg + '\n') % headless)
4500
4504
4501 if not heads:
4505 if not heads:
4502 return 1
4506 return 1
4503
4507
4504 heads = sorted(heads, key=lambda x: -x.rev())
4508 heads = sorted(heads, key=lambda x: -x.rev())
4505 displayer = cmdutil.show_changeset(ui, repo, opts)
4509 displayer = cmdutil.show_changeset(ui, repo, opts)
4506 for ctx in heads:
4510 for ctx in heads:
4507 displayer.show(ctx)
4511 displayer.show(ctx)
4508 displayer.close()
4512 displayer.close()
4509
4513
4510 @command('help',
4514 @command('help',
4511 [('e', 'extension', None, _('show only help for extensions')),
4515 [('e', 'extension', None, _('show only help for extensions')),
4512 ('c', 'command', None, _('show only help for commands')),
4516 ('c', 'command', None, _('show only help for commands')),
4513 ('k', 'keyword', None, _('show topics matching keyword')),
4517 ('k', 'keyword', None, _('show topics matching keyword')),
4514 ('s', 'system', [], _('show help for specific platform(s)')),
4518 ('s', 'system', [], _('show help for specific platform(s)')),
4515 ],
4519 ],
4516 _('[-ecks] [TOPIC]'),
4520 _('[-ecks] [TOPIC]'),
4517 norepo=True)
4521 norepo=True)
4518 def help_(ui, name=None, **opts):
4522 def help_(ui, name=None, **opts):
4519 """show help for a given topic or a help overview
4523 """show help for a given topic or a help overview
4520
4524
4521 With no arguments, print a list of commands with short help messages.
4525 With no arguments, print a list of commands with short help messages.
4522
4526
4523 Given a topic, extension, or command name, print help for that
4527 Given a topic, extension, or command name, print help for that
4524 topic.
4528 topic.
4525
4529
4526 Returns 0 if successful.
4530 Returns 0 if successful.
4527 """
4531 """
4528
4532
4529 textwidth = min(ui.termwidth(), 80) - 2
4533 textwidth = min(ui.termwidth(), 80) - 2
4530
4534
4531 keep = opts.get('system') or []
4535 keep = opts.get('system') or []
4532 if len(keep) == 0:
4536 if len(keep) == 0:
4533 if sys.platform.startswith('win'):
4537 if sys.platform.startswith('win'):
4534 keep.append('windows')
4538 keep.append('windows')
4535 elif sys.platform == 'OpenVMS':
4539 elif sys.platform == 'OpenVMS':
4536 keep.append('vms')
4540 keep.append('vms')
4537 elif sys.platform == 'plan9':
4541 elif sys.platform == 'plan9':
4538 keep.append('plan9')
4542 keep.append('plan9')
4539 else:
4543 else:
4540 keep.append('unix')
4544 keep.append('unix')
4541 keep.append(sys.platform.lower())
4545 keep.append(sys.platform.lower())
4542 if ui.verbose:
4546 if ui.verbose:
4543 keep.append('verbose')
4547 keep.append('verbose')
4544
4548
4545 section = None
4549 section = None
4546 subtopic = None
4550 subtopic = None
4547 if name and '.' in name:
4551 if name and '.' in name:
4548 name, section = name.split('.', 1)
4552 name, section = name.split('.', 1)
4549 section = section.lower()
4553 section = section.lower()
4550 if '.' in section:
4554 if '.' in section:
4551 subtopic, section = section.split('.', 1)
4555 subtopic, section = section.split('.', 1)
4552 else:
4556 else:
4553 subtopic = section
4557 subtopic = section
4554
4558
4555 text = help.help_(ui, name, subtopic=subtopic, **opts)
4559 text = help.help_(ui, name, subtopic=subtopic, **opts)
4556
4560
4557 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4561 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4558 section=section)
4562 section=section)
4559
4563
4560 # We could have been given a weird ".foo" section without a name
4564 # We could have been given a weird ".foo" section without a name
4561 # to look for, or we could have simply failed to found "foo.bar"
4565 # to look for, or we could have simply failed to found "foo.bar"
4562 # because bar isn't a section of foo
4566 # because bar isn't a section of foo
4563 if section and not (formatted and name):
4567 if section and not (formatted and name):
4564 raise error.Abort(_("help section not found"))
4568 raise error.Abort(_("help section not found"))
4565
4569
4566 if 'verbose' in pruned:
4570 if 'verbose' in pruned:
4567 keep.append('omitted')
4571 keep.append('omitted')
4568 else:
4572 else:
4569 keep.append('notomitted')
4573 keep.append('notomitted')
4570 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4574 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4571 section=section)
4575 section=section)
4572 ui.write(formatted)
4576 ui.write(formatted)
4573
4577
4574
4578
4575 @command('identify|id',
4579 @command('identify|id',
4576 [('r', 'rev', '',
4580 [('r', 'rev', '',
4577 _('identify the specified revision'), _('REV')),
4581 _('identify the specified revision'), _('REV')),
4578 ('n', 'num', None, _('show local revision number')),
4582 ('n', 'num', None, _('show local revision number')),
4579 ('i', 'id', None, _('show global revision id')),
4583 ('i', 'id', None, _('show global revision id')),
4580 ('b', 'branch', None, _('show branch')),
4584 ('b', 'branch', None, _('show branch')),
4581 ('t', 'tags', None, _('show tags')),
4585 ('t', 'tags', None, _('show tags')),
4582 ('B', 'bookmarks', None, _('show bookmarks')),
4586 ('B', 'bookmarks', None, _('show bookmarks')),
4583 ] + remoteopts,
4587 ] + remoteopts,
4584 _('[-nibtB] [-r REV] [SOURCE]'),
4588 _('[-nibtB] [-r REV] [SOURCE]'),
4585 optionalrepo=True)
4589 optionalrepo=True)
4586 def identify(ui, repo, source=None, rev=None,
4590 def identify(ui, repo, source=None, rev=None,
4587 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4591 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4588 """identify the working directory or specified revision
4592 """identify the working directory or specified revision
4589
4593
4590 Print a summary identifying the repository state at REV using one or
4594 Print a summary identifying the repository state at REV using one or
4591 two parent hash identifiers, followed by a "+" if the working
4595 two parent hash identifiers, followed by a "+" if the working
4592 directory has uncommitted changes, the branch name (if not default),
4596 directory has uncommitted changes, the branch name (if not default),
4593 a list of tags, and a list of bookmarks.
4597 a list of tags, and a list of bookmarks.
4594
4598
4595 When REV is not given, print a summary of the current state of the
4599 When REV is not given, print a summary of the current state of the
4596 repository.
4600 repository.
4597
4601
4598 Specifying a path to a repository root or Mercurial bundle will
4602 Specifying a path to a repository root or Mercurial bundle will
4599 cause lookup to operate on that repository/bundle.
4603 cause lookup to operate on that repository/bundle.
4600
4604
4601 .. container:: verbose
4605 .. container:: verbose
4602
4606
4603 Examples:
4607 Examples:
4604
4608
4605 - generate a build identifier for the working directory::
4609 - generate a build identifier for the working directory::
4606
4610
4607 hg id --id > build-id.dat
4611 hg id --id > build-id.dat
4608
4612
4609 - find the revision corresponding to a tag::
4613 - find the revision corresponding to a tag::
4610
4614
4611 hg id -n -r 1.3
4615 hg id -n -r 1.3
4612
4616
4613 - check the most recent revision of a remote repository::
4617 - check the most recent revision of a remote repository::
4614
4618
4615 hg id -r tip http://selenic.com/hg/
4619 hg id -r tip http://selenic.com/hg/
4616
4620
4617 See :hg:`log` for generating more information about specific revisions,
4621 See :hg:`log` for generating more information about specific revisions,
4618 including full hash identifiers.
4622 including full hash identifiers.
4619
4623
4620 Returns 0 if successful.
4624 Returns 0 if successful.
4621 """
4625 """
4622
4626
4623 if not repo and not source:
4627 if not repo and not source:
4624 raise error.Abort(_("there is no Mercurial repository here "
4628 raise error.Abort(_("there is no Mercurial repository here "
4625 "(.hg not found)"))
4629 "(.hg not found)"))
4626
4630
4627 if ui.debugflag:
4631 if ui.debugflag:
4628 hexfunc = hex
4632 hexfunc = hex
4629 else:
4633 else:
4630 hexfunc = short
4634 hexfunc = short
4631 default = not (num or id or branch or tags or bookmarks)
4635 default = not (num or id or branch or tags or bookmarks)
4632 output = []
4636 output = []
4633 revs = []
4637 revs = []
4634
4638
4635 if source:
4639 if source:
4636 source, branches = hg.parseurl(ui.expandpath(source))
4640 source, branches = hg.parseurl(ui.expandpath(source))
4637 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4641 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4638 repo = peer.local()
4642 repo = peer.local()
4639 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4643 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4640
4644
4641 if not repo:
4645 if not repo:
4642 if num or branch or tags:
4646 if num or branch or tags:
4643 raise error.Abort(
4647 raise error.Abort(
4644 _("can't query remote revision number, branch, or tags"))
4648 _("can't query remote revision number, branch, or tags"))
4645 if not rev and revs:
4649 if not rev and revs:
4646 rev = revs[0]
4650 rev = revs[0]
4647 if not rev:
4651 if not rev:
4648 rev = "tip"
4652 rev = "tip"
4649
4653
4650 remoterev = peer.lookup(rev)
4654 remoterev = peer.lookup(rev)
4651 if default or id:
4655 if default or id:
4652 output = [hexfunc(remoterev)]
4656 output = [hexfunc(remoterev)]
4653
4657
4654 def getbms():
4658 def getbms():
4655 bms = []
4659 bms = []
4656
4660
4657 if 'bookmarks' in peer.listkeys('namespaces'):
4661 if 'bookmarks' in peer.listkeys('namespaces'):
4658 hexremoterev = hex(remoterev)
4662 hexremoterev = hex(remoterev)
4659 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4663 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4660 if bmr == hexremoterev]
4664 if bmr == hexremoterev]
4661
4665
4662 return sorted(bms)
4666 return sorted(bms)
4663
4667
4664 if bookmarks:
4668 if bookmarks:
4665 output.extend(getbms())
4669 output.extend(getbms())
4666 elif default and not ui.quiet:
4670 elif default and not ui.quiet:
4667 # multiple bookmarks for a single parent separated by '/'
4671 # multiple bookmarks for a single parent separated by '/'
4668 bm = '/'.join(getbms())
4672 bm = '/'.join(getbms())
4669 if bm:
4673 if bm:
4670 output.append(bm)
4674 output.append(bm)
4671 else:
4675 else:
4672 ctx = scmutil.revsingle(repo, rev, None)
4676 ctx = scmutil.revsingle(repo, rev, None)
4673
4677
4674 if ctx.rev() is None:
4678 if ctx.rev() is None:
4675 ctx = repo[None]
4679 ctx = repo[None]
4676 parents = ctx.parents()
4680 parents = ctx.parents()
4677 taglist = []
4681 taglist = []
4678 for p in parents:
4682 for p in parents:
4679 taglist.extend(p.tags())
4683 taglist.extend(p.tags())
4680
4684
4681 changed = ""
4685 changed = ""
4682 if default or id or num:
4686 if default or id or num:
4683 if (any(repo.status())
4687 if (any(repo.status())
4684 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4688 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4685 changed = '+'
4689 changed = '+'
4686 if default or id:
4690 if default or id:
4687 output = ["%s%s" %
4691 output = ["%s%s" %
4688 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4692 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4689 if num:
4693 if num:
4690 output.append("%s%s" %
4694 output.append("%s%s" %
4691 ('+'.join([str(p.rev()) for p in parents]), changed))
4695 ('+'.join([str(p.rev()) for p in parents]), changed))
4692 else:
4696 else:
4693 if default or id:
4697 if default or id:
4694 output = [hexfunc(ctx.node())]
4698 output = [hexfunc(ctx.node())]
4695 if num:
4699 if num:
4696 output.append(str(ctx.rev()))
4700 output.append(str(ctx.rev()))
4697 taglist = ctx.tags()
4701 taglist = ctx.tags()
4698
4702
4699 if default and not ui.quiet:
4703 if default and not ui.quiet:
4700 b = ctx.branch()
4704 b = ctx.branch()
4701 if b != 'default':
4705 if b != 'default':
4702 output.append("(%s)" % b)
4706 output.append("(%s)" % b)
4703
4707
4704 # multiple tags for a single parent separated by '/'
4708 # multiple tags for a single parent separated by '/'
4705 t = '/'.join(taglist)
4709 t = '/'.join(taglist)
4706 if t:
4710 if t:
4707 output.append(t)
4711 output.append(t)
4708
4712
4709 # multiple bookmarks for a single parent separated by '/'
4713 # multiple bookmarks for a single parent separated by '/'
4710 bm = '/'.join(ctx.bookmarks())
4714 bm = '/'.join(ctx.bookmarks())
4711 if bm:
4715 if bm:
4712 output.append(bm)
4716 output.append(bm)
4713 else:
4717 else:
4714 if branch:
4718 if branch:
4715 output.append(ctx.branch())
4719 output.append(ctx.branch())
4716
4720
4717 if tags:
4721 if tags:
4718 output.extend(taglist)
4722 output.extend(taglist)
4719
4723
4720 if bookmarks:
4724 if bookmarks:
4721 output.extend(ctx.bookmarks())
4725 output.extend(ctx.bookmarks())
4722
4726
4723 ui.write("%s\n" % ' '.join(output))
4727 ui.write("%s\n" % ' '.join(output))
4724
4728
4725 @command('import|patch',
4729 @command('import|patch',
4726 [('p', 'strip', 1,
4730 [('p', 'strip', 1,
4727 _('directory strip option for patch. This has the same '
4731 _('directory strip option for patch. This has the same '
4728 'meaning as the corresponding patch option'), _('NUM')),
4732 'meaning as the corresponding patch option'), _('NUM')),
4729 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4733 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4730 ('e', 'edit', False, _('invoke editor on commit messages')),
4734 ('e', 'edit', False, _('invoke editor on commit messages')),
4731 ('f', 'force', None,
4735 ('f', 'force', None,
4732 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4736 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4733 ('', 'no-commit', None,
4737 ('', 'no-commit', None,
4734 _("don't commit, just update the working directory")),
4738 _("don't commit, just update the working directory")),
4735 ('', 'bypass', None,
4739 ('', 'bypass', None,
4736 _("apply patch without touching the working directory")),
4740 _("apply patch without touching the working directory")),
4737 ('', 'partial', None,
4741 ('', 'partial', None,
4738 _('commit even if some hunks fail')),
4742 _('commit even if some hunks fail')),
4739 ('', 'exact', None,
4743 ('', 'exact', None,
4740 _('apply patch to the nodes from which it was generated')),
4744 _('apply patch to the nodes from which it was generated')),
4741 ('', 'prefix', '',
4745 ('', 'prefix', '',
4742 _('apply patch to subdirectory'), _('DIR')),
4746 _('apply patch to subdirectory'), _('DIR')),
4743 ('', 'import-branch', None,
4747 ('', 'import-branch', None,
4744 _('use any branch information in patch (implied by --exact)'))] +
4748 _('use any branch information in patch (implied by --exact)'))] +
4745 commitopts + commitopts2 + similarityopts,
4749 commitopts + commitopts2 + similarityopts,
4746 _('[OPTION]... PATCH...'))
4750 _('[OPTION]... PATCH...'))
4747 def import_(ui, repo, patch1=None, *patches, **opts):
4751 def import_(ui, repo, patch1=None, *patches, **opts):
4748 """import an ordered set of patches
4752 """import an ordered set of patches
4749
4753
4750 Import a list of patches and commit them individually (unless
4754 Import a list of patches and commit them individually (unless
4751 --no-commit is specified).
4755 --no-commit is specified).
4752
4756
4753 To read a patch from standard input, use "-" as the patch name. If
4757 To read a patch from standard input, use "-" as the patch name. If
4754 a URL is specified, the patch will be downloaded from there.
4758 a URL is specified, the patch will be downloaded from there.
4755
4759
4756 Import first applies changes to the working directory (unless
4760 Import first applies changes to the working directory (unless
4757 --bypass is specified), import will abort if there are outstanding
4761 --bypass is specified), import will abort if there are outstanding
4758 changes.
4762 changes.
4759
4763
4760 Use --bypass to apply and commit patches directly to the
4764 Use --bypass to apply and commit patches directly to the
4761 repository, without affecting the working directory. Without
4765 repository, without affecting the working directory. Without
4762 --exact, patches will be applied on top of the working directory
4766 --exact, patches will be applied on top of the working directory
4763 parent revision.
4767 parent revision.
4764
4768
4765 You can import a patch straight from a mail message. Even patches
4769 You can import a patch straight from a mail message. Even patches
4766 as attachments work (to use the body part, it must have type
4770 as attachments work (to use the body part, it must have type
4767 text/plain or text/x-patch). From and Subject headers of email
4771 text/plain or text/x-patch). From and Subject headers of email
4768 message are used as default committer and commit message. All
4772 message are used as default committer and commit message. All
4769 text/plain body parts before first diff are added to the commit
4773 text/plain body parts before first diff are added to the commit
4770 message.
4774 message.
4771
4775
4772 If the imported patch was generated by :hg:`export`, user and
4776 If the imported patch was generated by :hg:`export`, user and
4773 description from patch override values from message headers and
4777 description from patch override values from message headers and
4774 body. Values given on command line with -m/--message and -u/--user
4778 body. Values given on command line with -m/--message and -u/--user
4775 override these.
4779 override these.
4776
4780
4777 If --exact is specified, import will set the working directory to
4781 If --exact is specified, import will set the working directory to
4778 the parent of each patch before applying it, and will abort if the
4782 the parent of each patch before applying it, and will abort if the
4779 resulting changeset has a different ID than the one recorded in
4783 resulting changeset has a different ID than the one recorded in
4780 the patch. This may happen due to character set problems or other
4784 the patch. This may happen due to character set problems or other
4781 deficiencies in the text patch format.
4785 deficiencies in the text patch format.
4782
4786
4783 Use --partial to ensure a changeset will be created from the patch
4787 Use --partial to ensure a changeset will be created from the patch
4784 even if some hunks fail to apply. Hunks that fail to apply will be
4788 even if some hunks fail to apply. Hunks that fail to apply will be
4785 written to a <target-file>.rej file. Conflicts can then be resolved
4789 written to a <target-file>.rej file. Conflicts can then be resolved
4786 by hand before :hg:`commit --amend` is run to update the created
4790 by hand before :hg:`commit --amend` is run to update the created
4787 changeset. This flag exists to let people import patches that
4791 changeset. This flag exists to let people import patches that
4788 partially apply without losing the associated metadata (author,
4792 partially apply without losing the associated metadata (author,
4789 date, description, ...).
4793 date, description, ...).
4790
4794
4791 .. note::
4795 .. note::
4792
4796
4793 When no hunks apply cleanly, :hg:`import --partial` will create
4797 When no hunks apply cleanly, :hg:`import --partial` will create
4794 an empty changeset, importing only the patch metadata.
4798 an empty changeset, importing only the patch metadata.
4795
4799
4796 With -s/--similarity, hg will attempt to discover renames and
4800 With -s/--similarity, hg will attempt to discover renames and
4797 copies in the patch in the same way as :hg:`addremove`.
4801 copies in the patch in the same way as :hg:`addremove`.
4798
4802
4799 It is possible to use external patch programs to perform the patch
4803 It is possible to use external patch programs to perform the patch
4800 by setting the ``ui.patch`` configuration option. For the default
4804 by setting the ``ui.patch`` configuration option. For the default
4801 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4805 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4802 See :hg:`help config` for more information about configuration
4806 See :hg:`help config` for more information about configuration
4803 files and how to use these options.
4807 files and how to use these options.
4804
4808
4805 See :hg:`help dates` for a list of formats valid for -d/--date.
4809 See :hg:`help dates` for a list of formats valid for -d/--date.
4806
4810
4807 .. container:: verbose
4811 .. container:: verbose
4808
4812
4809 Examples:
4813 Examples:
4810
4814
4811 - import a traditional patch from a website and detect renames::
4815 - import a traditional patch from a website and detect renames::
4812
4816
4813 hg import -s 80 http://example.com/bugfix.patch
4817 hg import -s 80 http://example.com/bugfix.patch
4814
4818
4815 - import a changeset from an hgweb server::
4819 - import a changeset from an hgweb server::
4816
4820
4817 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4821 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4818
4822
4819 - import all the patches in an Unix-style mbox::
4823 - import all the patches in an Unix-style mbox::
4820
4824
4821 hg import incoming-patches.mbox
4825 hg import incoming-patches.mbox
4822
4826
4823 - attempt to exactly restore an exported changeset (not always
4827 - attempt to exactly restore an exported changeset (not always
4824 possible)::
4828 possible)::
4825
4829
4826 hg import --exact proposed-fix.patch
4830 hg import --exact proposed-fix.patch
4827
4831
4828 - use an external tool to apply a patch which is too fuzzy for
4832 - use an external tool to apply a patch which is too fuzzy for
4829 the default internal tool.
4833 the default internal tool.
4830
4834
4831 hg import --config ui.patch="patch --merge" fuzzy.patch
4835 hg import --config ui.patch="patch --merge" fuzzy.patch
4832
4836
4833 - change the default fuzzing from 2 to a less strict 7
4837 - change the default fuzzing from 2 to a less strict 7
4834
4838
4835 hg import --config ui.fuzz=7 fuzz.patch
4839 hg import --config ui.fuzz=7 fuzz.patch
4836
4840
4837 Returns 0 on success, 1 on partial success (see --partial).
4841 Returns 0 on success, 1 on partial success (see --partial).
4838 """
4842 """
4839
4843
4840 if not patch1:
4844 if not patch1:
4841 raise error.Abort(_('need at least one patch to import'))
4845 raise error.Abort(_('need at least one patch to import'))
4842
4846
4843 patches = (patch1,) + patches
4847 patches = (patch1,) + patches
4844
4848
4845 date = opts.get('date')
4849 date = opts.get('date')
4846 if date:
4850 if date:
4847 opts['date'] = util.parsedate(date)
4851 opts['date'] = util.parsedate(date)
4848
4852
4849 exact = opts.get('exact')
4853 exact = opts.get('exact')
4850 update = not opts.get('bypass')
4854 update = not opts.get('bypass')
4851 if not update and opts.get('no_commit'):
4855 if not update and opts.get('no_commit'):
4852 raise error.Abort(_('cannot use --no-commit with --bypass'))
4856 raise error.Abort(_('cannot use --no-commit with --bypass'))
4853 try:
4857 try:
4854 sim = float(opts.get('similarity') or 0)
4858 sim = float(opts.get('similarity') or 0)
4855 except ValueError:
4859 except ValueError:
4856 raise error.Abort(_('similarity must be a number'))
4860 raise error.Abort(_('similarity must be a number'))
4857 if sim < 0 or sim > 100:
4861 if sim < 0 or sim > 100:
4858 raise error.Abort(_('similarity must be between 0 and 100'))
4862 raise error.Abort(_('similarity must be between 0 and 100'))
4859 if sim and not update:
4863 if sim and not update:
4860 raise error.Abort(_('cannot use --similarity with --bypass'))
4864 raise error.Abort(_('cannot use --similarity with --bypass'))
4861 if exact:
4865 if exact:
4862 if opts.get('edit'):
4866 if opts.get('edit'):
4863 raise error.Abort(_('cannot use --exact with --edit'))
4867 raise error.Abort(_('cannot use --exact with --edit'))
4864 if opts.get('prefix'):
4868 if opts.get('prefix'):
4865 raise error.Abort(_('cannot use --exact with --prefix'))
4869 raise error.Abort(_('cannot use --exact with --prefix'))
4866
4870
4867 base = opts["base"]
4871 base = opts["base"]
4868 wlock = dsguard = lock = tr = None
4872 wlock = dsguard = lock = tr = None
4869 msgs = []
4873 msgs = []
4870 ret = 0
4874 ret = 0
4871
4875
4872
4876
4873 try:
4877 try:
4874 wlock = repo.wlock()
4878 wlock = repo.wlock()
4875
4879
4876 if update:
4880 if update:
4877 cmdutil.checkunfinished(repo)
4881 cmdutil.checkunfinished(repo)
4878 if (exact or not opts.get('force')):
4882 if (exact or not opts.get('force')):
4879 cmdutil.bailifchanged(repo)
4883 cmdutil.bailifchanged(repo)
4880
4884
4881 if not opts.get('no_commit'):
4885 if not opts.get('no_commit'):
4882 lock = repo.lock()
4886 lock = repo.lock()
4883 tr = repo.transaction('import')
4887 tr = repo.transaction('import')
4884 else:
4888 else:
4885 dsguard = cmdutil.dirstateguard(repo, 'import')
4889 dsguard = cmdutil.dirstateguard(repo, 'import')
4886 parents = repo[None].parents()
4890 parents = repo[None].parents()
4887 for patchurl in patches:
4891 for patchurl in patches:
4888 if patchurl == '-':
4892 if patchurl == '-':
4889 ui.status(_('applying patch from stdin\n'))
4893 ui.status(_('applying patch from stdin\n'))
4890 patchfile = ui.fin
4894 patchfile = ui.fin
4891 patchurl = 'stdin' # for error message
4895 patchurl = 'stdin' # for error message
4892 else:
4896 else:
4893 patchurl = os.path.join(base, patchurl)
4897 patchurl = os.path.join(base, patchurl)
4894 ui.status(_('applying %s\n') % patchurl)
4898 ui.status(_('applying %s\n') % patchurl)
4895 patchfile = hg.openpath(ui, patchurl)
4899 patchfile = hg.openpath(ui, patchurl)
4896
4900
4897 haspatch = False
4901 haspatch = False
4898 for hunk in patch.split(patchfile):
4902 for hunk in patch.split(patchfile):
4899 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4903 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4900 parents, opts,
4904 parents, opts,
4901 msgs, hg.clean)
4905 msgs, hg.clean)
4902 if msg:
4906 if msg:
4903 haspatch = True
4907 haspatch = True
4904 ui.note(msg + '\n')
4908 ui.note(msg + '\n')
4905 if update or exact:
4909 if update or exact:
4906 parents = repo[None].parents()
4910 parents = repo[None].parents()
4907 else:
4911 else:
4908 parents = [repo[node]]
4912 parents = [repo[node]]
4909 if rej:
4913 if rej:
4910 ui.write_err(_("patch applied partially\n"))
4914 ui.write_err(_("patch applied partially\n"))
4911 ui.write_err(_("(fix the .rej files and run "
4915 ui.write_err(_("(fix the .rej files and run "
4912 "`hg commit --amend`)\n"))
4916 "`hg commit --amend`)\n"))
4913 ret = 1
4917 ret = 1
4914 break
4918 break
4915
4919
4916 if not haspatch:
4920 if not haspatch:
4917 raise error.Abort(_('%s: no diffs found') % patchurl)
4921 raise error.Abort(_('%s: no diffs found') % patchurl)
4918
4922
4919 if tr:
4923 if tr:
4920 tr.close()
4924 tr.close()
4921 if msgs:
4925 if msgs:
4922 repo.savecommitmessage('\n* * *\n'.join(msgs))
4926 repo.savecommitmessage('\n* * *\n'.join(msgs))
4923 if dsguard:
4927 if dsguard:
4924 dsguard.close()
4928 dsguard.close()
4925 return ret
4929 return ret
4926 finally:
4930 finally:
4927 if tr:
4931 if tr:
4928 tr.release()
4932 tr.release()
4929 release(lock, dsguard, wlock)
4933 release(lock, dsguard, wlock)
4930
4934
4931 @command('incoming|in',
4935 @command('incoming|in',
4932 [('f', 'force', None,
4936 [('f', 'force', None,
4933 _('run even if remote repository is unrelated')),
4937 _('run even if remote repository is unrelated')),
4934 ('n', 'newest-first', None, _('show newest record first')),
4938 ('n', 'newest-first', None, _('show newest record first')),
4935 ('', 'bundle', '',
4939 ('', 'bundle', '',
4936 _('file to store the bundles into'), _('FILE')),
4940 _('file to store the bundles into'), _('FILE')),
4937 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4941 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4938 ('B', 'bookmarks', False, _("compare bookmarks")),
4942 ('B', 'bookmarks', False, _("compare bookmarks")),
4939 ('b', 'branch', [],
4943 ('b', 'branch', [],
4940 _('a specific branch you would like to pull'), _('BRANCH')),
4944 _('a specific branch you would like to pull'), _('BRANCH')),
4941 ] + logopts + remoteopts + subrepoopts,
4945 ] + logopts + remoteopts + subrepoopts,
4942 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4946 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4943 def incoming(ui, repo, source="default", **opts):
4947 def incoming(ui, repo, source="default", **opts):
4944 """show new changesets found in source
4948 """show new changesets found in source
4945
4949
4946 Show new changesets found in the specified path/URL or the default
4950 Show new changesets found in the specified path/URL or the default
4947 pull location. These are the changesets that would have been pulled
4951 pull location. These are the changesets that would have been pulled
4948 if a pull at the time you issued this command.
4952 if a pull at the time you issued this command.
4949
4953
4950 See pull for valid source format details.
4954 See pull for valid source format details.
4951
4955
4952 .. container:: verbose
4956 .. container:: verbose
4953
4957
4954 With -B/--bookmarks, the result of bookmark comparison between
4958 With -B/--bookmarks, the result of bookmark comparison between
4955 local and remote repositories is displayed. With -v/--verbose,
4959 local and remote repositories is displayed. With -v/--verbose,
4956 status is also displayed for each bookmark like below::
4960 status is also displayed for each bookmark like below::
4957
4961
4958 BM1 01234567890a added
4962 BM1 01234567890a added
4959 BM2 1234567890ab advanced
4963 BM2 1234567890ab advanced
4960 BM3 234567890abc diverged
4964 BM3 234567890abc diverged
4961 BM4 34567890abcd changed
4965 BM4 34567890abcd changed
4962
4966
4963 The action taken locally when pulling depends on the
4967 The action taken locally when pulling depends on the
4964 status of each bookmark:
4968 status of each bookmark:
4965
4969
4966 :``added``: pull will create it
4970 :``added``: pull will create it
4967 :``advanced``: pull will update it
4971 :``advanced``: pull will update it
4968 :``diverged``: pull will create a divergent bookmark
4972 :``diverged``: pull will create a divergent bookmark
4969 :``changed``: result depends on remote changesets
4973 :``changed``: result depends on remote changesets
4970
4974
4971 From the point of view of pulling behavior, bookmark
4975 From the point of view of pulling behavior, bookmark
4972 existing only in the remote repository are treated as ``added``,
4976 existing only in the remote repository are treated as ``added``,
4973 even if it is in fact locally deleted.
4977 even if it is in fact locally deleted.
4974
4978
4975 .. container:: verbose
4979 .. container:: verbose
4976
4980
4977 For remote repository, using --bundle avoids downloading the
4981 For remote repository, using --bundle avoids downloading the
4978 changesets twice if the incoming is followed by a pull.
4982 changesets twice if the incoming is followed by a pull.
4979
4983
4980 Examples:
4984 Examples:
4981
4985
4982 - show incoming changes with patches and full description::
4986 - show incoming changes with patches and full description::
4983
4987
4984 hg incoming -vp
4988 hg incoming -vp
4985
4989
4986 - show incoming changes excluding merges, store a bundle::
4990 - show incoming changes excluding merges, store a bundle::
4987
4991
4988 hg in -vpM --bundle incoming.hg
4992 hg in -vpM --bundle incoming.hg
4989 hg pull incoming.hg
4993 hg pull incoming.hg
4990
4994
4991 - briefly list changes inside a bundle::
4995 - briefly list changes inside a bundle::
4992
4996
4993 hg in changes.hg -T "{desc|firstline}\\n"
4997 hg in changes.hg -T "{desc|firstline}\\n"
4994
4998
4995 Returns 0 if there are incoming changes, 1 otherwise.
4999 Returns 0 if there are incoming changes, 1 otherwise.
4996 """
5000 """
4997 if opts.get('graph'):
5001 if opts.get('graph'):
4998 cmdutil.checkunsupportedgraphflags([], opts)
5002 cmdutil.checkunsupportedgraphflags([], opts)
4999 def display(other, chlist, displayer):
5003 def display(other, chlist, displayer):
5000 revdag = cmdutil.graphrevs(other, chlist, opts)
5004 revdag = cmdutil.graphrevs(other, chlist, opts)
5001 cmdutil.displaygraph(ui, repo, revdag, displayer,
5005 cmdutil.displaygraph(ui, repo, revdag, displayer,
5002 graphmod.asciiedges)
5006 graphmod.asciiedges)
5003
5007
5004 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5008 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
5005 return 0
5009 return 0
5006
5010
5007 if opts.get('bundle') and opts.get('subrepos'):
5011 if opts.get('bundle') and opts.get('subrepos'):
5008 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5012 raise error.Abort(_('cannot combine --bundle and --subrepos'))
5009
5013
5010 if opts.get('bookmarks'):
5014 if opts.get('bookmarks'):
5011 source, branches = hg.parseurl(ui.expandpath(source),
5015 source, branches = hg.parseurl(ui.expandpath(source),
5012 opts.get('branch'))
5016 opts.get('branch'))
5013 other = hg.peer(repo, opts, source)
5017 other = hg.peer(repo, opts, source)
5014 if 'bookmarks' not in other.listkeys('namespaces'):
5018 if 'bookmarks' not in other.listkeys('namespaces'):
5015 ui.warn(_("remote doesn't support bookmarks\n"))
5019 ui.warn(_("remote doesn't support bookmarks\n"))
5016 return 0
5020 return 0
5017 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5021 ui.status(_('comparing with %s\n') % util.hidepassword(source))
5018 return bookmarks.incoming(ui, repo, other)
5022 return bookmarks.incoming(ui, repo, other)
5019
5023
5020 repo._subtoppath = ui.expandpath(source)
5024 repo._subtoppath = ui.expandpath(source)
5021 try:
5025 try:
5022 return hg.incoming(ui, repo, source, opts)
5026 return hg.incoming(ui, repo, source, opts)
5023 finally:
5027 finally:
5024 del repo._subtoppath
5028 del repo._subtoppath
5025
5029
5026
5030
5027 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5031 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
5028 norepo=True)
5032 norepo=True)
5029 def init(ui, dest=".", **opts):
5033 def init(ui, dest=".", **opts):
5030 """create a new repository in the given directory
5034 """create a new repository in the given directory
5031
5035
5032 Initialize a new repository in the given directory. If the given
5036 Initialize a new repository in the given directory. If the given
5033 directory does not exist, it will be created.
5037 directory does not exist, it will be created.
5034
5038
5035 If no directory is given, the current directory is used.
5039 If no directory is given, the current directory is used.
5036
5040
5037 It is possible to specify an ``ssh://`` URL as the destination.
5041 It is possible to specify an ``ssh://`` URL as the destination.
5038 See :hg:`help urls` for more information.
5042 See :hg:`help urls` for more information.
5039
5043
5040 Returns 0 on success.
5044 Returns 0 on success.
5041 """
5045 """
5042 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5046 hg.peer(ui, opts, ui.expandpath(dest), create=True)
5043
5047
5044 @command('locate',
5048 @command('locate',
5045 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5049 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
5046 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5050 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5047 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5051 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
5048 ] + walkopts,
5052 ] + walkopts,
5049 _('[OPTION]... [PATTERN]...'))
5053 _('[OPTION]... [PATTERN]...'))
5050 def locate(ui, repo, *pats, **opts):
5054 def locate(ui, repo, *pats, **opts):
5051 """locate files matching specific patterns (DEPRECATED)
5055 """locate files matching specific patterns (DEPRECATED)
5052
5056
5053 Print files under Mercurial control in the working directory whose
5057 Print files under Mercurial control in the working directory whose
5054 names match the given patterns.
5058 names match the given patterns.
5055
5059
5056 By default, this command searches all directories in the working
5060 By default, this command searches all directories in the working
5057 directory. To search just the current directory and its
5061 directory. To search just the current directory and its
5058 subdirectories, use "--include .".
5062 subdirectories, use "--include .".
5059
5063
5060 If no patterns are given to match, this command prints the names
5064 If no patterns are given to match, this command prints the names
5061 of all files under Mercurial control in the working directory.
5065 of all files under Mercurial control in the working directory.
5062
5066
5063 If you want to feed the output of this command into the "xargs"
5067 If you want to feed the output of this command into the "xargs"
5064 command, use the -0 option to both this command and "xargs". This
5068 command, use the -0 option to both this command and "xargs". This
5065 will avoid the problem of "xargs" treating single filenames that
5069 will avoid the problem of "xargs" treating single filenames that
5066 contain whitespace as multiple filenames.
5070 contain whitespace as multiple filenames.
5067
5071
5068 See :hg:`help files` for a more versatile command.
5072 See :hg:`help files` for a more versatile command.
5069
5073
5070 Returns 0 if a match is found, 1 otherwise.
5074 Returns 0 if a match is found, 1 otherwise.
5071 """
5075 """
5072 if opts.get('print0'):
5076 if opts.get('print0'):
5073 end = '\0'
5077 end = '\0'
5074 else:
5078 else:
5075 end = '\n'
5079 end = '\n'
5076 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5080 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
5077
5081
5078 ret = 1
5082 ret = 1
5079 ctx = repo[rev]
5083 ctx = repo[rev]
5080 m = scmutil.match(ctx, pats, opts, default='relglob',
5084 m = scmutil.match(ctx, pats, opts, default='relglob',
5081 badfn=lambda x, y: False)
5085 badfn=lambda x, y: False)
5082
5086
5083 for abs in ctx.matches(m):
5087 for abs in ctx.matches(m):
5084 if opts.get('fullpath'):
5088 if opts.get('fullpath'):
5085 ui.write(repo.wjoin(abs), end)
5089 ui.write(repo.wjoin(abs), end)
5086 else:
5090 else:
5087 ui.write(((pats and m.rel(abs)) or abs), end)
5091 ui.write(((pats and m.rel(abs)) or abs), end)
5088 ret = 0
5092 ret = 0
5089
5093
5090 return ret
5094 return ret
5091
5095
5092 @command('^log|history',
5096 @command('^log|history',
5093 [('f', 'follow', None,
5097 [('f', 'follow', None,
5094 _('follow changeset history, or file history across copies and renames')),
5098 _('follow changeset history, or file history across copies and renames')),
5095 ('', 'follow-first', None,
5099 ('', 'follow-first', None,
5096 _('only follow the first parent of merge changesets (DEPRECATED)')),
5100 _('only follow the first parent of merge changesets (DEPRECATED)')),
5097 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5101 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
5098 ('C', 'copies', None, _('show copied files')),
5102 ('C', 'copies', None, _('show copied files')),
5099 ('k', 'keyword', [],
5103 ('k', 'keyword', [],
5100 _('do case-insensitive search for a given text'), _('TEXT')),
5104 _('do case-insensitive search for a given text'), _('TEXT')),
5101 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5105 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
5102 ('', 'removed', None, _('include revisions where files were removed')),
5106 ('', 'removed', None, _('include revisions where files were removed')),
5103 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5107 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
5104 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5108 ('u', 'user', [], _('revisions committed by user'), _('USER')),
5105 ('', 'only-branch', [],
5109 ('', 'only-branch', [],
5106 _('show only changesets within the given named branch (DEPRECATED)'),
5110 _('show only changesets within the given named branch (DEPRECATED)'),
5107 _('BRANCH')),
5111 _('BRANCH')),
5108 ('b', 'branch', [],
5112 ('b', 'branch', [],
5109 _('show changesets within the given named branch'), _('BRANCH')),
5113 _('show changesets within the given named branch'), _('BRANCH')),
5110 ('P', 'prune', [],
5114 ('P', 'prune', [],
5111 _('do not display revision or any of its ancestors'), _('REV')),
5115 _('do not display revision or any of its ancestors'), _('REV')),
5112 ] + logopts + walkopts,
5116 ] + logopts + walkopts,
5113 _('[OPTION]... [FILE]'),
5117 _('[OPTION]... [FILE]'),
5114 inferrepo=True)
5118 inferrepo=True)
5115 def log(ui, repo, *pats, **opts):
5119 def log(ui, repo, *pats, **opts):
5116 """show revision history of entire repository or files
5120 """show revision history of entire repository or files
5117
5121
5118 Print the revision history of the specified files or the entire
5122 Print the revision history of the specified files or the entire
5119 project.
5123 project.
5120
5124
5121 If no revision range is specified, the default is ``tip:0`` unless
5125 If no revision range is specified, the default is ``tip:0`` unless
5122 --follow is set, in which case the working directory parent is
5126 --follow is set, in which case the working directory parent is
5123 used as the starting revision.
5127 used as the starting revision.
5124
5128
5125 File history is shown without following rename or copy history of
5129 File history is shown without following rename or copy history of
5126 files. Use -f/--follow with a filename to follow history across
5130 files. Use -f/--follow with a filename to follow history across
5127 renames and copies. --follow without a filename will only show
5131 renames and copies. --follow without a filename will only show
5128 ancestors or descendants of the starting revision.
5132 ancestors or descendants of the starting revision.
5129
5133
5130 By default this command prints revision number and changeset id,
5134 By default this command prints revision number and changeset id,
5131 tags, non-trivial parents, user, date and time, and a summary for
5135 tags, non-trivial parents, user, date and time, and a summary for
5132 each commit. When the -v/--verbose switch is used, the list of
5136 each commit. When the -v/--verbose switch is used, the list of
5133 changed files and full commit message are shown.
5137 changed files and full commit message are shown.
5134
5138
5135 With --graph the revisions are shown as an ASCII art DAG with the most
5139 With --graph the revisions are shown as an ASCII art DAG with the most
5136 recent changeset at the top.
5140 recent changeset at the top.
5137 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5141 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
5138 and '+' represents a fork where the changeset from the lines below is a
5142 and '+' represents a fork where the changeset from the lines below is a
5139 parent of the 'o' merge on the same line.
5143 parent of the 'o' merge on the same line.
5140
5144
5141 .. note::
5145 .. note::
5142
5146
5143 :hg:`log --patch` may generate unexpected diff output for merge
5147 :hg:`log --patch` may generate unexpected diff output for merge
5144 changesets, as it will only compare the merge changeset against
5148 changesets, as it will only compare the merge changeset against
5145 its first parent. Also, only files different from BOTH parents
5149 its first parent. Also, only files different from BOTH parents
5146 will appear in files:.
5150 will appear in files:.
5147
5151
5148 .. note::
5152 .. note::
5149
5153
5150 For performance reasons, :hg:`log FILE` may omit duplicate changes
5154 For performance reasons, :hg:`log FILE` may omit duplicate changes
5151 made on branches and will not show removals or mode changes. To
5155 made on branches and will not show removals or mode changes. To
5152 see all such changes, use the --removed switch.
5156 see all such changes, use the --removed switch.
5153
5157
5154 .. container:: verbose
5158 .. container:: verbose
5155
5159
5156 Some examples:
5160 Some examples:
5157
5161
5158 - changesets with full descriptions and file lists::
5162 - changesets with full descriptions and file lists::
5159
5163
5160 hg log -v
5164 hg log -v
5161
5165
5162 - changesets ancestral to the working directory::
5166 - changesets ancestral to the working directory::
5163
5167
5164 hg log -f
5168 hg log -f
5165
5169
5166 - last 10 commits on the current branch::
5170 - last 10 commits on the current branch::
5167
5171
5168 hg log -l 10 -b .
5172 hg log -l 10 -b .
5169
5173
5170 - changesets showing all modifications of a file, including removals::
5174 - changesets showing all modifications of a file, including removals::
5171
5175
5172 hg log --removed file.c
5176 hg log --removed file.c
5173
5177
5174 - all changesets that touch a directory, with diffs, excluding merges::
5178 - all changesets that touch a directory, with diffs, excluding merges::
5175
5179
5176 hg log -Mp lib/
5180 hg log -Mp lib/
5177
5181
5178 - all revision numbers that match a keyword::
5182 - all revision numbers that match a keyword::
5179
5183
5180 hg log -k bug --template "{rev}\\n"
5184 hg log -k bug --template "{rev}\\n"
5181
5185
5182 - the full hash identifier of the working directory parent::
5186 - the full hash identifier of the working directory parent::
5183
5187
5184 hg log -r . --template "{node}\\n"
5188 hg log -r . --template "{node}\\n"
5185
5189
5186 - list available log templates::
5190 - list available log templates::
5187
5191
5188 hg log -T list
5192 hg log -T list
5189
5193
5190 - check if a given changeset is included in a tagged release::
5194 - check if a given changeset is included in a tagged release::
5191
5195
5192 hg log -r "a21ccf and ancestor(1.9)"
5196 hg log -r "a21ccf and ancestor(1.9)"
5193
5197
5194 - find all changesets by some user in a date range::
5198 - find all changesets by some user in a date range::
5195
5199
5196 hg log -k alice -d "may 2008 to jul 2008"
5200 hg log -k alice -d "may 2008 to jul 2008"
5197
5201
5198 - summary of all changesets after the last tag::
5202 - summary of all changesets after the last tag::
5199
5203
5200 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5204 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5201
5205
5202 See :hg:`help dates` for a list of formats valid for -d/--date.
5206 See :hg:`help dates` for a list of formats valid for -d/--date.
5203
5207
5204 See :hg:`help revisions` and :hg:`help revsets` for more about
5208 See :hg:`help revisions` and :hg:`help revsets` for more about
5205 specifying and ordering revisions.
5209 specifying and ordering revisions.
5206
5210
5207 See :hg:`help templates` for more about pre-packaged styles and
5211 See :hg:`help templates` for more about pre-packaged styles and
5208 specifying custom templates.
5212 specifying custom templates.
5209
5213
5210 Returns 0 on success.
5214 Returns 0 on success.
5211
5215
5212 """
5216 """
5213 if opts.get('follow') and opts.get('rev'):
5217 if opts.get('follow') and opts.get('rev'):
5214 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5218 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5215 del opts['follow']
5219 del opts['follow']
5216
5220
5217 if opts.get('graph'):
5221 if opts.get('graph'):
5218 return cmdutil.graphlog(ui, repo, *pats, **opts)
5222 return cmdutil.graphlog(ui, repo, *pats, **opts)
5219
5223
5220 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5224 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5221 limit = cmdutil.loglimit(opts)
5225 limit = cmdutil.loglimit(opts)
5222 count = 0
5226 count = 0
5223
5227
5224 getrenamed = None
5228 getrenamed = None
5225 if opts.get('copies'):
5229 if opts.get('copies'):
5226 endrev = None
5230 endrev = None
5227 if opts.get('rev'):
5231 if opts.get('rev'):
5228 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5232 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5229 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5233 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5230
5234
5231 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5235 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5232 for rev in revs:
5236 for rev in revs:
5233 if count == limit:
5237 if count == limit:
5234 break
5238 break
5235 ctx = repo[rev]
5239 ctx = repo[rev]
5236 copies = None
5240 copies = None
5237 if getrenamed is not None and rev:
5241 if getrenamed is not None and rev:
5238 copies = []
5242 copies = []
5239 for fn in ctx.files():
5243 for fn in ctx.files():
5240 rename = getrenamed(fn, rev)
5244 rename = getrenamed(fn, rev)
5241 if rename:
5245 if rename:
5242 copies.append((fn, rename[0]))
5246 copies.append((fn, rename[0]))
5243 if filematcher:
5247 if filematcher:
5244 revmatchfn = filematcher(ctx.rev())
5248 revmatchfn = filematcher(ctx.rev())
5245 else:
5249 else:
5246 revmatchfn = None
5250 revmatchfn = None
5247 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5251 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5248 if displayer.flush(ctx):
5252 if displayer.flush(ctx):
5249 count += 1
5253 count += 1
5250
5254
5251 displayer.close()
5255 displayer.close()
5252
5256
5253 @command('manifest',
5257 @command('manifest',
5254 [('r', 'rev', '', _('revision to display'), _('REV')),
5258 [('r', 'rev', '', _('revision to display'), _('REV')),
5255 ('', 'all', False, _("list files from all revisions"))]
5259 ('', 'all', False, _("list files from all revisions"))]
5256 + formatteropts,
5260 + formatteropts,
5257 _('[-r REV]'))
5261 _('[-r REV]'))
5258 def manifest(ui, repo, node=None, rev=None, **opts):
5262 def manifest(ui, repo, node=None, rev=None, **opts):
5259 """output the current or given revision of the project manifest
5263 """output the current or given revision of the project manifest
5260
5264
5261 Print a list of version controlled files for the given revision.
5265 Print a list of version controlled files for the given revision.
5262 If no revision is given, the first parent of the working directory
5266 If no revision is given, the first parent of the working directory
5263 is used, or the null revision if no revision is checked out.
5267 is used, or the null revision if no revision is checked out.
5264
5268
5265 With -v, print file permissions, symlink and executable bits.
5269 With -v, print file permissions, symlink and executable bits.
5266 With --debug, print file revision hashes.
5270 With --debug, print file revision hashes.
5267
5271
5268 If option --all is specified, the list of all files from all revisions
5272 If option --all is specified, the list of all files from all revisions
5269 is printed. This includes deleted and renamed files.
5273 is printed. This includes deleted and renamed files.
5270
5274
5271 Returns 0 on success.
5275 Returns 0 on success.
5272 """
5276 """
5273
5277
5274 fm = ui.formatter('manifest', opts)
5278 fm = ui.formatter('manifest', opts)
5275
5279
5276 if opts.get('all'):
5280 if opts.get('all'):
5277 if rev or node:
5281 if rev or node:
5278 raise error.Abort(_("can't specify a revision with --all"))
5282 raise error.Abort(_("can't specify a revision with --all"))
5279
5283
5280 res = []
5284 res = []
5281 prefix = "data/"
5285 prefix = "data/"
5282 suffix = ".i"
5286 suffix = ".i"
5283 plen = len(prefix)
5287 plen = len(prefix)
5284 slen = len(suffix)
5288 slen = len(suffix)
5285 with repo.lock():
5289 with repo.lock():
5286 for fn, b, size in repo.store.datafiles():
5290 for fn, b, size in repo.store.datafiles():
5287 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5291 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5288 res.append(fn[plen:-slen])
5292 res.append(fn[plen:-slen])
5289 for f in res:
5293 for f in res:
5290 fm.startitem()
5294 fm.startitem()
5291 fm.write("path", '%s\n', f)
5295 fm.write("path", '%s\n', f)
5292 fm.end()
5296 fm.end()
5293 return
5297 return
5294
5298
5295 if rev and node:
5299 if rev and node:
5296 raise error.Abort(_("please specify just one revision"))
5300 raise error.Abort(_("please specify just one revision"))
5297
5301
5298 if not node:
5302 if not node:
5299 node = rev
5303 node = rev
5300
5304
5301 char = {'l': '@', 'x': '*', '': ''}
5305 char = {'l': '@', 'x': '*', '': ''}
5302 mode = {'l': '644', 'x': '755', '': '644'}
5306 mode = {'l': '644', 'x': '755', '': '644'}
5303 ctx = scmutil.revsingle(repo, node)
5307 ctx = scmutil.revsingle(repo, node)
5304 mf = ctx.manifest()
5308 mf = ctx.manifest()
5305 for f in ctx:
5309 for f in ctx:
5306 fm.startitem()
5310 fm.startitem()
5307 fl = ctx[f].flags()
5311 fl = ctx[f].flags()
5308 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5312 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5309 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5313 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5310 fm.write('path', '%s\n', f)
5314 fm.write('path', '%s\n', f)
5311 fm.end()
5315 fm.end()
5312
5316
5313 @command('^merge',
5317 @command('^merge',
5314 [('f', 'force', None,
5318 [('f', 'force', None,
5315 _('force a merge including outstanding changes (DEPRECATED)')),
5319 _('force a merge including outstanding changes (DEPRECATED)')),
5316 ('r', 'rev', '', _('revision to merge'), _('REV')),
5320 ('r', 'rev', '', _('revision to merge'), _('REV')),
5317 ('P', 'preview', None,
5321 ('P', 'preview', None,
5318 _('review revisions to merge (no merge is performed)'))
5322 _('review revisions to merge (no merge is performed)'))
5319 ] + mergetoolopts,
5323 ] + mergetoolopts,
5320 _('[-P] [[-r] REV]'))
5324 _('[-P] [[-r] REV]'))
5321 def merge(ui, repo, node=None, **opts):
5325 def merge(ui, repo, node=None, **opts):
5322 """merge another revision into working directory
5326 """merge another revision into working directory
5323
5327
5324 The current working directory is updated with all changes made in
5328 The current working directory is updated with all changes made in
5325 the requested revision since the last common predecessor revision.
5329 the requested revision since the last common predecessor revision.
5326
5330
5327 Files that changed between either parent are marked as changed for
5331 Files that changed between either parent are marked as changed for
5328 the next commit and a commit must be performed before any further
5332 the next commit and a commit must be performed before any further
5329 updates to the repository are allowed. The next commit will have
5333 updates to the repository are allowed. The next commit will have
5330 two parents.
5334 two parents.
5331
5335
5332 ``--tool`` can be used to specify the merge tool used for file
5336 ``--tool`` can be used to specify the merge tool used for file
5333 merges. It overrides the HGMERGE environment variable and your
5337 merges. It overrides the HGMERGE environment variable and your
5334 configuration files. See :hg:`help merge-tools` for options.
5338 configuration files. See :hg:`help merge-tools` for options.
5335
5339
5336 If no revision is specified, the working directory's parent is a
5340 If no revision is specified, the working directory's parent is a
5337 head revision, and the current branch contains exactly one other
5341 head revision, and the current branch contains exactly one other
5338 head, the other head is merged with by default. Otherwise, an
5342 head, the other head is merged with by default. Otherwise, an
5339 explicit revision with which to merge with must be provided.
5343 explicit revision with which to merge with must be provided.
5340
5344
5341 See :hg:`help resolve` for information on handling file conflicts.
5345 See :hg:`help resolve` for information on handling file conflicts.
5342
5346
5343 To undo an uncommitted merge, use :hg:`update --clean .` which
5347 To undo an uncommitted merge, use :hg:`update --clean .` which
5344 will check out a clean copy of the original merge parent, losing
5348 will check out a clean copy of the original merge parent, losing
5345 all changes.
5349 all changes.
5346
5350
5347 Returns 0 on success, 1 if there are unresolved files.
5351 Returns 0 on success, 1 if there are unresolved files.
5348 """
5352 """
5349
5353
5350 if opts.get('rev') and node:
5354 if opts.get('rev') and node:
5351 raise error.Abort(_("please specify just one revision"))
5355 raise error.Abort(_("please specify just one revision"))
5352 if not node:
5356 if not node:
5353 node = opts.get('rev')
5357 node = opts.get('rev')
5354
5358
5355 if node:
5359 if node:
5356 node = scmutil.revsingle(repo, node).node()
5360 node = scmutil.revsingle(repo, node).node()
5357
5361
5358 if not node:
5362 if not node:
5359 node = repo[destutil.destmerge(repo)].node()
5363 node = repo[destutil.destmerge(repo)].node()
5360
5364
5361 if opts.get('preview'):
5365 if opts.get('preview'):
5362 # find nodes that are ancestors of p2 but not of p1
5366 # find nodes that are ancestors of p2 but not of p1
5363 p1 = repo.lookup('.')
5367 p1 = repo.lookup('.')
5364 p2 = repo.lookup(node)
5368 p2 = repo.lookup(node)
5365 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5369 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5366
5370
5367 displayer = cmdutil.show_changeset(ui, repo, opts)
5371 displayer = cmdutil.show_changeset(ui, repo, opts)
5368 for node in nodes:
5372 for node in nodes:
5369 displayer.show(repo[node])
5373 displayer.show(repo[node])
5370 displayer.close()
5374 displayer.close()
5371 return 0
5375 return 0
5372
5376
5373 try:
5377 try:
5374 # ui.forcemerge is an internal variable, do not document
5378 # ui.forcemerge is an internal variable, do not document
5375 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5379 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5376 force = opts.get('force')
5380 force = opts.get('force')
5377 return hg.merge(repo, node, force=force, mergeforce=force)
5381 return hg.merge(repo, node, force=force, mergeforce=force)
5378 finally:
5382 finally:
5379 ui.setconfig('ui', 'forcemerge', '', 'merge')
5383 ui.setconfig('ui', 'forcemerge', '', 'merge')
5380
5384
5381 @command('outgoing|out',
5385 @command('outgoing|out',
5382 [('f', 'force', None, _('run even when the destination is unrelated')),
5386 [('f', 'force', None, _('run even when the destination is unrelated')),
5383 ('r', 'rev', [],
5387 ('r', 'rev', [],
5384 _('a changeset intended to be included in the destination'), _('REV')),
5388 _('a changeset intended to be included in the destination'), _('REV')),
5385 ('n', 'newest-first', None, _('show newest record first')),
5389 ('n', 'newest-first', None, _('show newest record first')),
5386 ('B', 'bookmarks', False, _('compare bookmarks')),
5390 ('B', 'bookmarks', False, _('compare bookmarks')),
5387 ('b', 'branch', [], _('a specific branch you would like to push'),
5391 ('b', 'branch', [], _('a specific branch you would like to push'),
5388 _('BRANCH')),
5392 _('BRANCH')),
5389 ] + logopts + remoteopts + subrepoopts,
5393 ] + logopts + remoteopts + subrepoopts,
5390 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5394 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5391 def outgoing(ui, repo, dest=None, **opts):
5395 def outgoing(ui, repo, dest=None, **opts):
5392 """show changesets not found in the destination
5396 """show changesets not found in the destination
5393
5397
5394 Show changesets not found in the specified destination repository
5398 Show changesets not found in the specified destination repository
5395 or the default push location. These are the changesets that would
5399 or the default push location. These are the changesets that would
5396 be pushed if a push was requested.
5400 be pushed if a push was requested.
5397
5401
5398 See pull for details of valid destination formats.
5402 See pull for details of valid destination formats.
5399
5403
5400 .. container:: verbose
5404 .. container:: verbose
5401
5405
5402 With -B/--bookmarks, the result of bookmark comparison between
5406 With -B/--bookmarks, the result of bookmark comparison between
5403 local and remote repositories is displayed. With -v/--verbose,
5407 local and remote repositories is displayed. With -v/--verbose,
5404 status is also displayed for each bookmark like below::
5408 status is also displayed for each bookmark like below::
5405
5409
5406 BM1 01234567890a added
5410 BM1 01234567890a added
5407 BM2 deleted
5411 BM2 deleted
5408 BM3 234567890abc advanced
5412 BM3 234567890abc advanced
5409 BM4 34567890abcd diverged
5413 BM4 34567890abcd diverged
5410 BM5 4567890abcde changed
5414 BM5 4567890abcde changed
5411
5415
5412 The action taken when pushing depends on the
5416 The action taken when pushing depends on the
5413 status of each bookmark:
5417 status of each bookmark:
5414
5418
5415 :``added``: push with ``-B`` will create it
5419 :``added``: push with ``-B`` will create it
5416 :``deleted``: push with ``-B`` will delete it
5420 :``deleted``: push with ``-B`` will delete it
5417 :``advanced``: push will update it
5421 :``advanced``: push will update it
5418 :``diverged``: push with ``-B`` will update it
5422 :``diverged``: push with ``-B`` will update it
5419 :``changed``: push with ``-B`` will update it
5423 :``changed``: push with ``-B`` will update it
5420
5424
5421 From the point of view of pushing behavior, bookmarks
5425 From the point of view of pushing behavior, bookmarks
5422 existing only in the remote repository are treated as
5426 existing only in the remote repository are treated as
5423 ``deleted``, even if it is in fact added remotely.
5427 ``deleted``, even if it is in fact added remotely.
5424
5428
5425 Returns 0 if there are outgoing changes, 1 otherwise.
5429 Returns 0 if there are outgoing changes, 1 otherwise.
5426 """
5430 """
5427 if opts.get('graph'):
5431 if opts.get('graph'):
5428 cmdutil.checkunsupportedgraphflags([], opts)
5432 cmdutil.checkunsupportedgraphflags([], opts)
5429 o, other = hg._outgoing(ui, repo, dest, opts)
5433 o, other = hg._outgoing(ui, repo, dest, opts)
5430 if not o:
5434 if not o:
5431 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5435 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5432 return
5436 return
5433
5437
5434 revdag = cmdutil.graphrevs(repo, o, opts)
5438 revdag = cmdutil.graphrevs(repo, o, opts)
5435 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5439 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5436 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5440 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5437 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5441 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5438 return 0
5442 return 0
5439
5443
5440 if opts.get('bookmarks'):
5444 if opts.get('bookmarks'):
5441 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5445 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5442 dest, branches = hg.parseurl(dest, opts.get('branch'))
5446 dest, branches = hg.parseurl(dest, opts.get('branch'))
5443 other = hg.peer(repo, opts, dest)
5447 other = hg.peer(repo, opts, dest)
5444 if 'bookmarks' not in other.listkeys('namespaces'):
5448 if 'bookmarks' not in other.listkeys('namespaces'):
5445 ui.warn(_("remote doesn't support bookmarks\n"))
5449 ui.warn(_("remote doesn't support bookmarks\n"))
5446 return 0
5450 return 0
5447 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5451 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5448 return bookmarks.outgoing(ui, repo, other)
5452 return bookmarks.outgoing(ui, repo, other)
5449
5453
5450 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5454 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5451 try:
5455 try:
5452 return hg.outgoing(ui, repo, dest, opts)
5456 return hg.outgoing(ui, repo, dest, opts)
5453 finally:
5457 finally:
5454 del repo._subtoppath
5458 del repo._subtoppath
5455
5459
5456 @command('parents',
5460 @command('parents',
5457 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5461 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5458 ] + templateopts,
5462 ] + templateopts,
5459 _('[-r REV] [FILE]'),
5463 _('[-r REV] [FILE]'),
5460 inferrepo=True)
5464 inferrepo=True)
5461 def parents(ui, repo, file_=None, **opts):
5465 def parents(ui, repo, file_=None, **opts):
5462 """show the parents of the working directory or revision (DEPRECATED)
5466 """show the parents of the working directory or revision (DEPRECATED)
5463
5467
5464 Print the working directory's parent revisions. If a revision is
5468 Print the working directory's parent revisions. If a revision is
5465 given via -r/--rev, the parent of that revision will be printed.
5469 given via -r/--rev, the parent of that revision will be printed.
5466 If a file argument is given, the revision in which the file was
5470 If a file argument is given, the revision in which the file was
5467 last changed (before the working directory revision or the
5471 last changed (before the working directory revision or the
5468 argument to --rev if given) is printed.
5472 argument to --rev if given) is printed.
5469
5473
5470 This command is equivalent to::
5474 This command is equivalent to::
5471
5475
5472 hg log -r "p1()+p2()" or
5476 hg log -r "p1()+p2()" or
5473 hg log -r "p1(REV)+p2(REV)" or
5477 hg log -r "p1(REV)+p2(REV)" or
5474 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5478 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5475 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5479 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5476
5480
5477 See :hg:`summary` and :hg:`help revsets` for related information.
5481 See :hg:`summary` and :hg:`help revsets` for related information.
5478
5482
5479 Returns 0 on success.
5483 Returns 0 on success.
5480 """
5484 """
5481
5485
5482 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5486 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5483
5487
5484 if file_:
5488 if file_:
5485 m = scmutil.match(ctx, (file_,), opts)
5489 m = scmutil.match(ctx, (file_,), opts)
5486 if m.anypats() or len(m.files()) != 1:
5490 if m.anypats() or len(m.files()) != 1:
5487 raise error.Abort(_('can only specify an explicit filename'))
5491 raise error.Abort(_('can only specify an explicit filename'))
5488 file_ = m.files()[0]
5492 file_ = m.files()[0]
5489 filenodes = []
5493 filenodes = []
5490 for cp in ctx.parents():
5494 for cp in ctx.parents():
5491 if not cp:
5495 if not cp:
5492 continue
5496 continue
5493 try:
5497 try:
5494 filenodes.append(cp.filenode(file_))
5498 filenodes.append(cp.filenode(file_))
5495 except error.LookupError:
5499 except error.LookupError:
5496 pass
5500 pass
5497 if not filenodes:
5501 if not filenodes:
5498 raise error.Abort(_("'%s' not found in manifest!") % file_)
5502 raise error.Abort(_("'%s' not found in manifest!") % file_)
5499 p = []
5503 p = []
5500 for fn in filenodes:
5504 for fn in filenodes:
5501 fctx = repo.filectx(file_, fileid=fn)
5505 fctx = repo.filectx(file_, fileid=fn)
5502 p.append(fctx.node())
5506 p.append(fctx.node())
5503 else:
5507 else:
5504 p = [cp.node() for cp in ctx.parents()]
5508 p = [cp.node() for cp in ctx.parents()]
5505
5509
5506 displayer = cmdutil.show_changeset(ui, repo, opts)
5510 displayer = cmdutil.show_changeset(ui, repo, opts)
5507 for n in p:
5511 for n in p:
5508 if n != nullid:
5512 if n != nullid:
5509 displayer.show(repo[n])
5513 displayer.show(repo[n])
5510 displayer.close()
5514 displayer.close()
5511
5515
5512 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5516 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5513 def paths(ui, repo, search=None, **opts):
5517 def paths(ui, repo, search=None, **opts):
5514 """show aliases for remote repositories
5518 """show aliases for remote repositories
5515
5519
5516 Show definition of symbolic path name NAME. If no name is given,
5520 Show definition of symbolic path name NAME. If no name is given,
5517 show definition of all available names.
5521 show definition of all available names.
5518
5522
5519 Option -q/--quiet suppresses all output when searching for NAME
5523 Option -q/--quiet suppresses all output when searching for NAME
5520 and shows only the path names when listing all definitions.
5524 and shows only the path names when listing all definitions.
5521
5525
5522 Path names are defined in the [paths] section of your
5526 Path names are defined in the [paths] section of your
5523 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5527 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5524 repository, ``.hg/hgrc`` is used, too.
5528 repository, ``.hg/hgrc`` is used, too.
5525
5529
5526 The path names ``default`` and ``default-push`` have a special
5530 The path names ``default`` and ``default-push`` have a special
5527 meaning. When performing a push or pull operation, they are used
5531 meaning. When performing a push or pull operation, they are used
5528 as fallbacks if no location is specified on the command-line.
5532 as fallbacks if no location is specified on the command-line.
5529 When ``default-push`` is set, it will be used for push and
5533 When ``default-push`` is set, it will be used for push and
5530 ``default`` will be used for pull; otherwise ``default`` is used
5534 ``default`` will be used for pull; otherwise ``default`` is used
5531 as the fallback for both. When cloning a repository, the clone
5535 as the fallback for both. When cloning a repository, the clone
5532 source is written as ``default`` in ``.hg/hgrc``.
5536 source is written as ``default`` in ``.hg/hgrc``.
5533
5537
5534 .. note::
5538 .. note::
5535
5539
5536 ``default`` and ``default-push`` apply to all inbound (e.g.
5540 ``default`` and ``default-push`` apply to all inbound (e.g.
5537 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5541 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5538 and :hg:`bundle`) operations.
5542 and :hg:`bundle`) operations.
5539
5543
5540 See :hg:`help urls` for more information.
5544 See :hg:`help urls` for more information.
5541
5545
5542 Returns 0 on success.
5546 Returns 0 on success.
5543 """
5547 """
5544 if search:
5548 if search:
5545 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5549 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5546 if name == search]
5550 if name == search]
5547 else:
5551 else:
5548 pathitems = sorted(ui.paths.iteritems())
5552 pathitems = sorted(ui.paths.iteritems())
5549
5553
5550 fm = ui.formatter('paths', opts)
5554 fm = ui.formatter('paths', opts)
5551 if fm:
5555 if fm:
5552 hidepassword = str
5556 hidepassword = str
5553 else:
5557 else:
5554 hidepassword = util.hidepassword
5558 hidepassword = util.hidepassword
5555 if ui.quiet:
5559 if ui.quiet:
5556 namefmt = '%s\n'
5560 namefmt = '%s\n'
5557 else:
5561 else:
5558 namefmt = '%s = '
5562 namefmt = '%s = '
5559 showsubopts = not search and not ui.quiet
5563 showsubopts = not search and not ui.quiet
5560
5564
5561 for name, path in pathitems:
5565 for name, path in pathitems:
5562 fm.startitem()
5566 fm.startitem()
5563 fm.condwrite(not search, 'name', namefmt, name)
5567 fm.condwrite(not search, 'name', namefmt, name)
5564 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5568 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5565 for subopt, value in sorted(path.suboptions.items()):
5569 for subopt, value in sorted(path.suboptions.items()):
5566 assert subopt not in ('name', 'url')
5570 assert subopt not in ('name', 'url')
5567 if showsubopts:
5571 if showsubopts:
5568 fm.plain('%s:%s = ' % (name, subopt))
5572 fm.plain('%s:%s = ' % (name, subopt))
5569 fm.condwrite(showsubopts, subopt, '%s\n', value)
5573 fm.condwrite(showsubopts, subopt, '%s\n', value)
5570
5574
5571 fm.end()
5575 fm.end()
5572
5576
5573 if search and not pathitems:
5577 if search and not pathitems:
5574 if not ui.quiet:
5578 if not ui.quiet:
5575 ui.warn(_("not found!\n"))
5579 ui.warn(_("not found!\n"))
5576 return 1
5580 return 1
5577 else:
5581 else:
5578 return 0
5582 return 0
5579
5583
5580 @command('phase',
5584 @command('phase',
5581 [('p', 'public', False, _('set changeset phase to public')),
5585 [('p', 'public', False, _('set changeset phase to public')),
5582 ('d', 'draft', False, _('set changeset phase to draft')),
5586 ('d', 'draft', False, _('set changeset phase to draft')),
5583 ('s', 'secret', False, _('set changeset phase to secret')),
5587 ('s', 'secret', False, _('set changeset phase to secret')),
5584 ('f', 'force', False, _('allow to move boundary backward')),
5588 ('f', 'force', False, _('allow to move boundary backward')),
5585 ('r', 'rev', [], _('target revision'), _('REV')),
5589 ('r', 'rev', [], _('target revision'), _('REV')),
5586 ],
5590 ],
5587 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5591 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5588 def phase(ui, repo, *revs, **opts):
5592 def phase(ui, repo, *revs, **opts):
5589 """set or show the current phase name
5593 """set or show the current phase name
5590
5594
5591 With no argument, show the phase name of the current revision(s).
5595 With no argument, show the phase name of the current revision(s).
5592
5596
5593 With one of -p/--public, -d/--draft or -s/--secret, change the
5597 With one of -p/--public, -d/--draft or -s/--secret, change the
5594 phase value of the specified revisions.
5598 phase value of the specified revisions.
5595
5599
5596 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5600 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5597 lower phase to an higher phase. Phases are ordered as follows::
5601 lower phase to an higher phase. Phases are ordered as follows::
5598
5602
5599 public < draft < secret
5603 public < draft < secret
5600
5604
5601 Returns 0 on success, 1 if some phases could not be changed.
5605 Returns 0 on success, 1 if some phases could not be changed.
5602
5606
5603 (For more information about the phases concept, see :hg:`help phases`.)
5607 (For more information about the phases concept, see :hg:`help phases`.)
5604 """
5608 """
5605 # search for a unique phase argument
5609 # search for a unique phase argument
5606 targetphase = None
5610 targetphase = None
5607 for idx, name in enumerate(phases.phasenames):
5611 for idx, name in enumerate(phases.phasenames):
5608 if opts[name]:
5612 if opts[name]:
5609 if targetphase is not None:
5613 if targetphase is not None:
5610 raise error.Abort(_('only one phase can be specified'))
5614 raise error.Abort(_('only one phase can be specified'))
5611 targetphase = idx
5615 targetphase = idx
5612
5616
5613 # look for specified revision
5617 # look for specified revision
5614 revs = list(revs)
5618 revs = list(revs)
5615 revs.extend(opts['rev'])
5619 revs.extend(opts['rev'])
5616 if not revs:
5620 if not revs:
5617 # display both parents as the second parent phase can influence
5621 # display both parents as the second parent phase can influence
5618 # the phase of a merge commit
5622 # the phase of a merge commit
5619 revs = [c.rev() for c in repo[None].parents()]
5623 revs = [c.rev() for c in repo[None].parents()]
5620
5624
5621 revs = scmutil.revrange(repo, revs)
5625 revs = scmutil.revrange(repo, revs)
5622
5626
5623 lock = None
5627 lock = None
5624 ret = 0
5628 ret = 0
5625 if targetphase is None:
5629 if targetphase is None:
5626 # display
5630 # display
5627 for r in revs:
5631 for r in revs:
5628 ctx = repo[r]
5632 ctx = repo[r]
5629 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5633 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5630 else:
5634 else:
5631 tr = None
5635 tr = None
5632 lock = repo.lock()
5636 lock = repo.lock()
5633 try:
5637 try:
5634 tr = repo.transaction("phase")
5638 tr = repo.transaction("phase")
5635 # set phase
5639 # set phase
5636 if not revs:
5640 if not revs:
5637 raise error.Abort(_('empty revision set'))
5641 raise error.Abort(_('empty revision set'))
5638 nodes = [repo[r].node() for r in revs]
5642 nodes = [repo[r].node() for r in revs]
5639 # moving revision from public to draft may hide them
5643 # moving revision from public to draft may hide them
5640 # We have to check result on an unfiltered repository
5644 # We have to check result on an unfiltered repository
5641 unfi = repo.unfiltered()
5645 unfi = repo.unfiltered()
5642 getphase = unfi._phasecache.phase
5646 getphase = unfi._phasecache.phase
5643 olddata = [getphase(unfi, r) for r in unfi]
5647 olddata = [getphase(unfi, r) for r in unfi]
5644 phases.advanceboundary(repo, tr, targetphase, nodes)
5648 phases.advanceboundary(repo, tr, targetphase, nodes)
5645 if opts['force']:
5649 if opts['force']:
5646 phases.retractboundary(repo, tr, targetphase, nodes)
5650 phases.retractboundary(repo, tr, targetphase, nodes)
5647 tr.close()
5651 tr.close()
5648 finally:
5652 finally:
5649 if tr is not None:
5653 if tr is not None:
5650 tr.release()
5654 tr.release()
5651 lock.release()
5655 lock.release()
5652 getphase = unfi._phasecache.phase
5656 getphase = unfi._phasecache.phase
5653 newdata = [getphase(unfi, r) for r in unfi]
5657 newdata = [getphase(unfi, r) for r in unfi]
5654 changes = sum(newdata[r] != olddata[r] for r in unfi)
5658 changes = sum(newdata[r] != olddata[r] for r in unfi)
5655 cl = unfi.changelog
5659 cl = unfi.changelog
5656 rejected = [n for n in nodes
5660 rejected = [n for n in nodes
5657 if newdata[cl.rev(n)] < targetphase]
5661 if newdata[cl.rev(n)] < targetphase]
5658 if rejected:
5662 if rejected:
5659 ui.warn(_('cannot move %i changesets to a higher '
5663 ui.warn(_('cannot move %i changesets to a higher '
5660 'phase, use --force\n') % len(rejected))
5664 'phase, use --force\n') % len(rejected))
5661 ret = 1
5665 ret = 1
5662 if changes:
5666 if changes:
5663 msg = _('phase changed for %i changesets\n') % changes
5667 msg = _('phase changed for %i changesets\n') % changes
5664 if ret:
5668 if ret:
5665 ui.status(msg)
5669 ui.status(msg)
5666 else:
5670 else:
5667 ui.note(msg)
5671 ui.note(msg)
5668 else:
5672 else:
5669 ui.warn(_('no phases changed\n'))
5673 ui.warn(_('no phases changed\n'))
5670 return ret
5674 return ret
5671
5675
5672 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5676 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5673 """Run after a changegroup has been added via pull/unbundle
5677 """Run after a changegroup has been added via pull/unbundle
5674
5678
5675 This takes arguments below:
5679 This takes arguments below:
5676
5680
5677 :modheads: change of heads by pull/unbundle
5681 :modheads: change of heads by pull/unbundle
5678 :optupdate: updating working directory is needed or not
5682 :optupdate: updating working directory is needed or not
5679 :checkout: update destination revision (or None to default destination)
5683 :checkout: update destination revision (or None to default destination)
5680 :brev: a name, which might be a bookmark to be activated after updating
5684 :brev: a name, which might be a bookmark to be activated after updating
5681 """
5685 """
5682 if modheads == 0:
5686 if modheads == 0:
5683 return
5687 return
5684 if optupdate:
5688 if optupdate:
5685 try:
5689 try:
5686 return hg.updatetotally(ui, repo, checkout, brev)
5690 return hg.updatetotally(ui, repo, checkout, brev)
5687 except error.UpdateAbort as inst:
5691 except error.UpdateAbort as inst:
5688 msg = _("not updating: %s") % str(inst)
5692 msg = _("not updating: %s") % str(inst)
5689 hint = inst.hint
5693 hint = inst.hint
5690 raise error.UpdateAbort(msg, hint=hint)
5694 raise error.UpdateAbort(msg, hint=hint)
5691 if modheads > 1:
5695 if modheads > 1:
5692 currentbranchheads = len(repo.branchheads())
5696 currentbranchheads = len(repo.branchheads())
5693 if currentbranchheads == modheads:
5697 if currentbranchheads == modheads:
5694 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5698 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5695 elif currentbranchheads > 1:
5699 elif currentbranchheads > 1:
5696 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5700 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5697 "merge)\n"))
5701 "merge)\n"))
5698 else:
5702 else:
5699 ui.status(_("(run 'hg heads' to see heads)\n"))
5703 ui.status(_("(run 'hg heads' to see heads)\n"))
5700 else:
5704 else:
5701 ui.status(_("(run 'hg update' to get a working copy)\n"))
5705 ui.status(_("(run 'hg update' to get a working copy)\n"))
5702
5706
5703 @command('^pull',
5707 @command('^pull',
5704 [('u', 'update', None,
5708 [('u', 'update', None,
5705 _('update to new branch head if changesets were pulled')),
5709 _('update to new branch head if changesets were pulled')),
5706 ('f', 'force', None, _('run even when remote repository is unrelated')),
5710 ('f', 'force', None, _('run even when remote repository is unrelated')),
5707 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5711 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5708 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5712 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5709 ('b', 'branch', [], _('a specific branch you would like to pull'),
5713 ('b', 'branch', [], _('a specific branch you would like to pull'),
5710 _('BRANCH')),
5714 _('BRANCH')),
5711 ] + remoteopts,
5715 ] + remoteopts,
5712 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5716 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5713 def pull(ui, repo, source="default", **opts):
5717 def pull(ui, repo, source="default", **opts):
5714 """pull changes from the specified source
5718 """pull changes from the specified source
5715
5719
5716 Pull changes from a remote repository to a local one.
5720 Pull changes from a remote repository to a local one.
5717
5721
5718 This finds all changes from the repository at the specified path
5722 This finds all changes from the repository at the specified path
5719 or URL and adds them to a local repository (the current one unless
5723 or URL and adds them to a local repository (the current one unless
5720 -R is specified). By default, this does not update the copy of the
5724 -R is specified). By default, this does not update the copy of the
5721 project in the working directory.
5725 project in the working directory.
5722
5726
5723 Use :hg:`incoming` if you want to see what would have been added
5727 Use :hg:`incoming` if you want to see what would have been added
5724 by a pull at the time you issued this command. If you then decide
5728 by a pull at the time you issued this command. If you then decide
5725 to add those changes to the repository, you should use :hg:`pull
5729 to add those changes to the repository, you should use :hg:`pull
5726 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5730 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5727
5731
5728 If SOURCE is omitted, the 'default' path will be used.
5732 If SOURCE is omitted, the 'default' path will be used.
5729 See :hg:`help urls` for more information.
5733 See :hg:`help urls` for more information.
5730
5734
5731 Returns 0 on success, 1 if an update had unresolved files.
5735 Returns 0 on success, 1 if an update had unresolved files.
5732 """
5736 """
5733 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5737 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5734 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5738 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5735 other = hg.peer(repo, opts, source)
5739 other = hg.peer(repo, opts, source)
5736 try:
5740 try:
5737 revs, checkout = hg.addbranchrevs(repo, other, branches,
5741 revs, checkout = hg.addbranchrevs(repo, other, branches,
5738 opts.get('rev'))
5742 opts.get('rev'))
5739
5743
5740
5744
5741 pullopargs = {}
5745 pullopargs = {}
5742 if opts.get('bookmark'):
5746 if opts.get('bookmark'):
5743 if not revs:
5747 if not revs:
5744 revs = []
5748 revs = []
5745 # The list of bookmark used here is not the one used to actually
5749 # The list of bookmark used here is not the one used to actually
5746 # update the bookmark name. This can result in the revision pulled
5750 # update the bookmark name. This can result in the revision pulled
5747 # not ending up with the name of the bookmark because of a race
5751 # not ending up with the name of the bookmark because of a race
5748 # condition on the server. (See issue 4689 for details)
5752 # condition on the server. (See issue 4689 for details)
5749 remotebookmarks = other.listkeys('bookmarks')
5753 remotebookmarks = other.listkeys('bookmarks')
5750 pullopargs['remotebookmarks'] = remotebookmarks
5754 pullopargs['remotebookmarks'] = remotebookmarks
5751 for b in opts['bookmark']:
5755 for b in opts['bookmark']:
5752 if b not in remotebookmarks:
5756 if b not in remotebookmarks:
5753 raise error.Abort(_('remote bookmark %s not found!') % b)
5757 raise error.Abort(_('remote bookmark %s not found!') % b)
5754 revs.append(remotebookmarks[b])
5758 revs.append(remotebookmarks[b])
5755
5759
5756 if revs:
5760 if revs:
5757 try:
5761 try:
5758 # When 'rev' is a bookmark name, we cannot guarantee that it
5762 # When 'rev' is a bookmark name, we cannot guarantee that it
5759 # will be updated with that name because of a race condition
5763 # will be updated with that name because of a race condition
5760 # server side. (See issue 4689 for details)
5764 # server side. (See issue 4689 for details)
5761 oldrevs = revs
5765 oldrevs = revs
5762 revs = [] # actually, nodes
5766 revs = [] # actually, nodes
5763 for r in oldrevs:
5767 for r in oldrevs:
5764 node = other.lookup(r)
5768 node = other.lookup(r)
5765 revs.append(node)
5769 revs.append(node)
5766 if r == checkout:
5770 if r == checkout:
5767 checkout = node
5771 checkout = node
5768 except error.CapabilityError:
5772 except error.CapabilityError:
5769 err = _("other repository doesn't support revision lookup, "
5773 err = _("other repository doesn't support revision lookup, "
5770 "so a rev cannot be specified.")
5774 "so a rev cannot be specified.")
5771 raise error.Abort(err)
5775 raise error.Abort(err)
5772
5776
5773 pullopargs.update(opts.get('opargs', {}))
5777 pullopargs.update(opts.get('opargs', {}))
5774 modheads = exchange.pull(repo, other, heads=revs,
5778 modheads = exchange.pull(repo, other, heads=revs,
5775 force=opts.get('force'),
5779 force=opts.get('force'),
5776 bookmarks=opts.get('bookmark', ()),
5780 bookmarks=opts.get('bookmark', ()),
5777 opargs=pullopargs).cgresult
5781 opargs=pullopargs).cgresult
5778
5782
5779 # brev is a name, which might be a bookmark to be activated at
5783 # brev is a name, which might be a bookmark to be activated at
5780 # the end of the update. In other words, it is an explicit
5784 # the end of the update. In other words, it is an explicit
5781 # destination of the update
5785 # destination of the update
5782 brev = None
5786 brev = None
5783
5787
5784 if checkout:
5788 if checkout:
5785 checkout = str(repo.changelog.rev(checkout))
5789 checkout = str(repo.changelog.rev(checkout))
5786
5790
5787 # order below depends on implementation of
5791 # order below depends on implementation of
5788 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5792 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5789 # because 'checkout' is determined without it.
5793 # because 'checkout' is determined without it.
5790 if opts.get('rev'):
5794 if opts.get('rev'):
5791 brev = opts['rev'][0]
5795 brev = opts['rev'][0]
5792 elif opts.get('branch'):
5796 elif opts.get('branch'):
5793 brev = opts['branch'][0]
5797 brev = opts['branch'][0]
5794 else:
5798 else:
5795 brev = branches[0]
5799 brev = branches[0]
5796 repo._subtoppath = source
5800 repo._subtoppath = source
5797 try:
5801 try:
5798 ret = postincoming(ui, repo, modheads, opts.get('update'),
5802 ret = postincoming(ui, repo, modheads, opts.get('update'),
5799 checkout, brev)
5803 checkout, brev)
5800
5804
5801 finally:
5805 finally:
5802 del repo._subtoppath
5806 del repo._subtoppath
5803
5807
5804 finally:
5808 finally:
5805 other.close()
5809 other.close()
5806 return ret
5810 return ret
5807
5811
5808 @command('^push',
5812 @command('^push',
5809 [('f', 'force', None, _('force push')),
5813 [('f', 'force', None, _('force push')),
5810 ('r', 'rev', [],
5814 ('r', 'rev', [],
5811 _('a changeset intended to be included in the destination'),
5815 _('a changeset intended to be included in the destination'),
5812 _('REV')),
5816 _('REV')),
5813 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5817 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5814 ('b', 'branch', [],
5818 ('b', 'branch', [],
5815 _('a specific branch you would like to push'), _('BRANCH')),
5819 _('a specific branch you would like to push'), _('BRANCH')),
5816 ('', 'new-branch', False, _('allow pushing a new branch')),
5820 ('', 'new-branch', False, _('allow pushing a new branch')),
5817 ] + remoteopts,
5821 ] + remoteopts,
5818 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5822 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5819 def push(ui, repo, dest=None, **opts):
5823 def push(ui, repo, dest=None, **opts):
5820 """push changes to the specified destination
5824 """push changes to the specified destination
5821
5825
5822 Push changesets from the local repository to the specified
5826 Push changesets from the local repository to the specified
5823 destination.
5827 destination.
5824
5828
5825 This operation is symmetrical to pull: it is identical to a pull
5829 This operation is symmetrical to pull: it is identical to a pull
5826 in the destination repository from the current one.
5830 in the destination repository from the current one.
5827
5831
5828 By default, push will not allow creation of new heads at the
5832 By default, push will not allow creation of new heads at the
5829 destination, since multiple heads would make it unclear which head
5833 destination, since multiple heads would make it unclear which head
5830 to use. In this situation, it is recommended to pull and merge
5834 to use. In this situation, it is recommended to pull and merge
5831 before pushing.
5835 before pushing.
5832
5836
5833 Use --new-branch if you want to allow push to create a new named
5837 Use --new-branch if you want to allow push to create a new named
5834 branch that is not present at the destination. This allows you to
5838 branch that is not present at the destination. This allows you to
5835 only create a new branch without forcing other changes.
5839 only create a new branch without forcing other changes.
5836
5840
5837 .. note::
5841 .. note::
5838
5842
5839 Extra care should be taken with the -f/--force option,
5843 Extra care should be taken with the -f/--force option,
5840 which will push all new heads on all branches, an action which will
5844 which will push all new heads on all branches, an action which will
5841 almost always cause confusion for collaborators.
5845 almost always cause confusion for collaborators.
5842
5846
5843 If -r/--rev is used, the specified revision and all its ancestors
5847 If -r/--rev is used, the specified revision and all its ancestors
5844 will be pushed to the remote repository.
5848 will be pushed to the remote repository.
5845
5849
5846 If -B/--bookmark is used, the specified bookmarked revision, its
5850 If -B/--bookmark is used, the specified bookmarked revision, its
5847 ancestors, and the bookmark will be pushed to the remote
5851 ancestors, and the bookmark will be pushed to the remote
5848 repository. Specifying ``.`` is equivalent to specifying the active
5852 repository. Specifying ``.`` is equivalent to specifying the active
5849 bookmark's name.
5853 bookmark's name.
5850
5854
5851 Please see :hg:`help urls` for important details about ``ssh://``
5855 Please see :hg:`help urls` for important details about ``ssh://``
5852 URLs. If DESTINATION is omitted, a default path will be used.
5856 URLs. If DESTINATION is omitted, a default path will be used.
5853
5857
5854 Returns 0 if push was successful, 1 if nothing to push.
5858 Returns 0 if push was successful, 1 if nothing to push.
5855 """
5859 """
5856
5860
5857 if opts.get('bookmark'):
5861 if opts.get('bookmark'):
5858 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5862 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5859 for b in opts['bookmark']:
5863 for b in opts['bookmark']:
5860 # translate -B options to -r so changesets get pushed
5864 # translate -B options to -r so changesets get pushed
5861 b = repo._bookmarks.expandname(b)
5865 b = repo._bookmarks.expandname(b)
5862 if b in repo._bookmarks:
5866 if b in repo._bookmarks:
5863 opts.setdefault('rev', []).append(b)
5867 opts.setdefault('rev', []).append(b)
5864 else:
5868 else:
5865 # if we try to push a deleted bookmark, translate it to null
5869 # if we try to push a deleted bookmark, translate it to null
5866 # this lets simultaneous -r, -b options continue working
5870 # this lets simultaneous -r, -b options continue working
5867 opts.setdefault('rev', []).append("null")
5871 opts.setdefault('rev', []).append("null")
5868
5872
5869 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5873 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5870 if not path:
5874 if not path:
5871 raise error.Abort(_('default repository not configured!'),
5875 raise error.Abort(_('default repository not configured!'),
5872 hint=_('see the "path" section in "hg help config"'))
5876 hint=_('see the "path" section in "hg help config"'))
5873 dest = path.pushloc or path.loc
5877 dest = path.pushloc or path.loc
5874 branches = (path.branch, opts.get('branch') or [])
5878 branches = (path.branch, opts.get('branch') or [])
5875 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5879 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5876 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5880 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5877 other = hg.peer(repo, opts, dest)
5881 other = hg.peer(repo, opts, dest)
5878
5882
5879 if revs:
5883 if revs:
5880 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5884 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5881 if not revs:
5885 if not revs:
5882 raise error.Abort(_("specified revisions evaluate to an empty set"),
5886 raise error.Abort(_("specified revisions evaluate to an empty set"),
5883 hint=_("use different revision arguments"))
5887 hint=_("use different revision arguments"))
5884
5888
5885 repo._subtoppath = dest
5889 repo._subtoppath = dest
5886 try:
5890 try:
5887 # push subrepos depth-first for coherent ordering
5891 # push subrepos depth-first for coherent ordering
5888 c = repo['']
5892 c = repo['']
5889 subs = c.substate # only repos that are committed
5893 subs = c.substate # only repos that are committed
5890 for s in sorted(subs):
5894 for s in sorted(subs):
5891 result = c.sub(s).push(opts)
5895 result = c.sub(s).push(opts)
5892 if result == 0:
5896 if result == 0:
5893 return not result
5897 return not result
5894 finally:
5898 finally:
5895 del repo._subtoppath
5899 del repo._subtoppath
5896 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5900 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5897 newbranch=opts.get('new_branch'),
5901 newbranch=opts.get('new_branch'),
5898 bookmarks=opts.get('bookmark', ()),
5902 bookmarks=opts.get('bookmark', ()),
5899 opargs=opts.get('opargs'))
5903 opargs=opts.get('opargs'))
5900
5904
5901 result = not pushop.cgresult
5905 result = not pushop.cgresult
5902
5906
5903 if pushop.bkresult is not None:
5907 if pushop.bkresult is not None:
5904 if pushop.bkresult == 2:
5908 if pushop.bkresult == 2:
5905 result = 2
5909 result = 2
5906 elif not result and pushop.bkresult:
5910 elif not result and pushop.bkresult:
5907 result = 2
5911 result = 2
5908
5912
5909 return result
5913 return result
5910
5914
5911 @command('recover', [])
5915 @command('recover', [])
5912 def recover(ui, repo):
5916 def recover(ui, repo):
5913 """roll back an interrupted transaction
5917 """roll back an interrupted transaction
5914
5918
5915 Recover from an interrupted commit or pull.
5919 Recover from an interrupted commit or pull.
5916
5920
5917 This command tries to fix the repository status after an
5921 This command tries to fix the repository status after an
5918 interrupted operation. It should only be necessary when Mercurial
5922 interrupted operation. It should only be necessary when Mercurial
5919 suggests it.
5923 suggests it.
5920
5924
5921 Returns 0 if successful, 1 if nothing to recover or verify fails.
5925 Returns 0 if successful, 1 if nothing to recover or verify fails.
5922 """
5926 """
5923 if repo.recover():
5927 if repo.recover():
5924 return hg.verify(repo)
5928 return hg.verify(repo)
5925 return 1
5929 return 1
5926
5930
5927 @command('^remove|rm',
5931 @command('^remove|rm',
5928 [('A', 'after', None, _('record delete for missing files')),
5932 [('A', 'after', None, _('record delete for missing files')),
5929 ('f', 'force', None,
5933 ('f', 'force', None,
5930 _('remove (and delete) file even if added or modified')),
5934 _('remove (and delete) file even if added or modified')),
5931 ] + subrepoopts + walkopts,
5935 ] + subrepoopts + walkopts,
5932 _('[OPTION]... FILE...'),
5936 _('[OPTION]... FILE...'),
5933 inferrepo=True)
5937 inferrepo=True)
5934 def remove(ui, repo, *pats, **opts):
5938 def remove(ui, repo, *pats, **opts):
5935 """remove the specified files on the next commit
5939 """remove the specified files on the next commit
5936
5940
5937 Schedule the indicated files for removal from the current branch.
5941 Schedule the indicated files for removal from the current branch.
5938
5942
5939 This command schedules the files to be removed at the next commit.
5943 This command schedules the files to be removed at the next commit.
5940 To undo a remove before that, see :hg:`revert`. To undo added
5944 To undo a remove before that, see :hg:`revert`. To undo added
5941 files, see :hg:`forget`.
5945 files, see :hg:`forget`.
5942
5946
5943 .. container:: verbose
5947 .. container:: verbose
5944
5948
5945 -A/--after can be used to remove only files that have already
5949 -A/--after can be used to remove only files that have already
5946 been deleted, -f/--force can be used to force deletion, and -Af
5950 been deleted, -f/--force can be used to force deletion, and -Af
5947 can be used to remove files from the next revision without
5951 can be used to remove files from the next revision without
5948 deleting them from the working directory.
5952 deleting them from the working directory.
5949
5953
5950 The following table details the behavior of remove for different
5954 The following table details the behavior of remove for different
5951 file states (columns) and option combinations (rows). The file
5955 file states (columns) and option combinations (rows). The file
5952 states are Added [A], Clean [C], Modified [M] and Missing [!]
5956 states are Added [A], Clean [C], Modified [M] and Missing [!]
5953 (as reported by :hg:`status`). The actions are Warn, Remove
5957 (as reported by :hg:`status`). The actions are Warn, Remove
5954 (from branch) and Delete (from disk):
5958 (from branch) and Delete (from disk):
5955
5959
5956 ========= == == == ==
5960 ========= == == == ==
5957 opt/state A C M !
5961 opt/state A C M !
5958 ========= == == == ==
5962 ========= == == == ==
5959 none W RD W R
5963 none W RD W R
5960 -f R RD RD R
5964 -f R RD RD R
5961 -A W W W R
5965 -A W W W R
5962 -Af R R R R
5966 -Af R R R R
5963 ========= == == == ==
5967 ========= == == == ==
5964
5968
5965 .. note::
5969 .. note::
5966
5970
5967 :hg:`remove` never deletes files in Added [A] state from the
5971 :hg:`remove` never deletes files in Added [A] state from the
5968 working directory, not even if ``--force`` is specified.
5972 working directory, not even if ``--force`` is specified.
5969
5973
5970 Returns 0 on success, 1 if any warnings encountered.
5974 Returns 0 on success, 1 if any warnings encountered.
5971 """
5975 """
5972
5976
5973 after, force = opts.get('after'), opts.get('force')
5977 after, force = opts.get('after'), opts.get('force')
5974 if not pats and not after:
5978 if not pats and not after:
5975 raise error.Abort(_('no files specified'))
5979 raise error.Abort(_('no files specified'))
5976
5980
5977 m = scmutil.match(repo[None], pats, opts)
5981 m = scmutil.match(repo[None], pats, opts)
5978 subrepos = opts.get('subrepos')
5982 subrepos = opts.get('subrepos')
5979 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5983 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5980
5984
5981 @command('rename|move|mv',
5985 @command('rename|move|mv',
5982 [('A', 'after', None, _('record a rename that has already occurred')),
5986 [('A', 'after', None, _('record a rename that has already occurred')),
5983 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5987 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5984 ] + walkopts + dryrunopts,
5988 ] + walkopts + dryrunopts,
5985 _('[OPTION]... SOURCE... DEST'))
5989 _('[OPTION]... SOURCE... DEST'))
5986 def rename(ui, repo, *pats, **opts):
5990 def rename(ui, repo, *pats, **opts):
5987 """rename files; equivalent of copy + remove
5991 """rename files; equivalent of copy + remove
5988
5992
5989 Mark dest as copies of sources; mark sources for deletion. If dest
5993 Mark dest as copies of sources; mark sources for deletion. If dest
5990 is a directory, copies are put in that directory. If dest is a
5994 is a directory, copies are put in that directory. If dest is a
5991 file, there can only be one source.
5995 file, there can only be one source.
5992
5996
5993 By default, this command copies the contents of files as they
5997 By default, this command copies the contents of files as they
5994 exist in the working directory. If invoked with -A/--after, the
5998 exist in the working directory. If invoked with -A/--after, the
5995 operation is recorded, but no copying is performed.
5999 operation is recorded, but no copying is performed.
5996
6000
5997 This command takes effect at the next commit. To undo a rename
6001 This command takes effect at the next commit. To undo a rename
5998 before that, see :hg:`revert`.
6002 before that, see :hg:`revert`.
5999
6003
6000 Returns 0 on success, 1 if errors are encountered.
6004 Returns 0 on success, 1 if errors are encountered.
6001 """
6005 """
6002 with repo.wlock(False):
6006 with repo.wlock(False):
6003 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6007 return cmdutil.copy(ui, repo, pats, opts, rename=True)
6004
6008
6005 @command('resolve',
6009 @command('resolve',
6006 [('a', 'all', None, _('select all unresolved files')),
6010 [('a', 'all', None, _('select all unresolved files')),
6007 ('l', 'list', None, _('list state of files needing merge')),
6011 ('l', 'list', None, _('list state of files needing merge')),
6008 ('m', 'mark', None, _('mark files as resolved')),
6012 ('m', 'mark', None, _('mark files as resolved')),
6009 ('u', 'unmark', None, _('mark files as unresolved')),
6013 ('u', 'unmark', None, _('mark files as unresolved')),
6010 ('n', 'no-status', None, _('hide status prefix'))]
6014 ('n', 'no-status', None, _('hide status prefix'))]
6011 + mergetoolopts + walkopts + formatteropts,
6015 + mergetoolopts + walkopts + formatteropts,
6012 _('[OPTION]... [FILE]...'),
6016 _('[OPTION]... [FILE]...'),
6013 inferrepo=True)
6017 inferrepo=True)
6014 def resolve(ui, repo, *pats, **opts):
6018 def resolve(ui, repo, *pats, **opts):
6015 """redo merges or set/view the merge status of files
6019 """redo merges or set/view the merge status of files
6016
6020
6017 Merges with unresolved conflicts are often the result of
6021 Merges with unresolved conflicts are often the result of
6018 non-interactive merging using the ``internal:merge`` configuration
6022 non-interactive merging using the ``internal:merge`` configuration
6019 setting, or a command-line merge tool like ``diff3``. The resolve
6023 setting, or a command-line merge tool like ``diff3``. The resolve
6020 command is used to manage the files involved in a merge, after
6024 command is used to manage the files involved in a merge, after
6021 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6025 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
6022 working directory must have two parents). See :hg:`help
6026 working directory must have two parents). See :hg:`help
6023 merge-tools` for information on configuring merge tools.
6027 merge-tools` for information on configuring merge tools.
6024
6028
6025 The resolve command can be used in the following ways:
6029 The resolve command can be used in the following ways:
6026
6030
6027 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6031 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
6028 files, discarding any previous merge attempts. Re-merging is not
6032 files, discarding any previous merge attempts. Re-merging is not
6029 performed for files already marked as resolved. Use ``--all/-a``
6033 performed for files already marked as resolved. Use ``--all/-a``
6030 to select all unresolved files. ``--tool`` can be used to specify
6034 to select all unresolved files. ``--tool`` can be used to specify
6031 the merge tool used for the given files. It overrides the HGMERGE
6035 the merge tool used for the given files. It overrides the HGMERGE
6032 environment variable and your configuration files. Previous file
6036 environment variable and your configuration files. Previous file
6033 contents are saved with a ``.orig`` suffix.
6037 contents are saved with a ``.orig`` suffix.
6034
6038
6035 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6039 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
6036 (e.g. after having manually fixed-up the files). The default is
6040 (e.g. after having manually fixed-up the files). The default is
6037 to mark all unresolved files.
6041 to mark all unresolved files.
6038
6042
6039 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6043 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
6040 default is to mark all resolved files.
6044 default is to mark all resolved files.
6041
6045
6042 - :hg:`resolve -l`: list files which had or still have conflicts.
6046 - :hg:`resolve -l`: list files which had or still have conflicts.
6043 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6047 In the printed list, ``U`` = unresolved and ``R`` = resolved.
6044
6048
6045 .. note::
6049 .. note::
6046
6050
6047 Mercurial will not let you commit files with unresolved merge
6051 Mercurial will not let you commit files with unresolved merge
6048 conflicts. You must use :hg:`resolve -m ...` before you can
6052 conflicts. You must use :hg:`resolve -m ...` before you can
6049 commit after a conflicting merge.
6053 commit after a conflicting merge.
6050
6054
6051 Returns 0 on success, 1 if any files fail a resolve attempt.
6055 Returns 0 on success, 1 if any files fail a resolve attempt.
6052 """
6056 """
6053
6057
6054 flaglist = 'all mark unmark list no_status'.split()
6058 flaglist = 'all mark unmark list no_status'.split()
6055 all, mark, unmark, show, nostatus = \
6059 all, mark, unmark, show, nostatus = \
6056 [opts.get(o) for o in flaglist]
6060 [opts.get(o) for o in flaglist]
6057
6061
6058 if (show and (mark or unmark)) or (mark and unmark):
6062 if (show and (mark or unmark)) or (mark and unmark):
6059 raise error.Abort(_("too many options specified"))
6063 raise error.Abort(_("too many options specified"))
6060 if pats and all:
6064 if pats and all:
6061 raise error.Abort(_("can't specify --all and patterns"))
6065 raise error.Abort(_("can't specify --all and patterns"))
6062 if not (all or pats or show or mark or unmark):
6066 if not (all or pats or show or mark or unmark):
6063 raise error.Abort(_('no files or directories specified'),
6067 raise error.Abort(_('no files or directories specified'),
6064 hint=('use --all to re-merge all unresolved files'))
6068 hint=('use --all to re-merge all unresolved files'))
6065
6069
6066 if show:
6070 if show:
6067 fm = ui.formatter('resolve', opts)
6071 fm = ui.formatter('resolve', opts)
6068 ms = mergemod.mergestate.read(repo)
6072 ms = mergemod.mergestate.read(repo)
6069 m = scmutil.match(repo[None], pats, opts)
6073 m = scmutil.match(repo[None], pats, opts)
6070 for f in ms:
6074 for f in ms:
6071 if not m(f):
6075 if not m(f):
6072 continue
6076 continue
6073 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6077 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
6074 'd': 'driverresolved'}[ms[f]]
6078 'd': 'driverresolved'}[ms[f]]
6075 fm.startitem()
6079 fm.startitem()
6076 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6080 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
6077 fm.write('path', '%s\n', f, label=l)
6081 fm.write('path', '%s\n', f, label=l)
6078 fm.end()
6082 fm.end()
6079 return 0
6083 return 0
6080
6084
6081 with repo.wlock():
6085 with repo.wlock():
6082 ms = mergemod.mergestate.read(repo)
6086 ms = mergemod.mergestate.read(repo)
6083
6087
6084 if not (ms.active() or repo.dirstate.p2() != nullid):
6088 if not (ms.active() or repo.dirstate.p2() != nullid):
6085 raise error.Abort(
6089 raise error.Abort(
6086 _('resolve command not applicable when not merging'))
6090 _('resolve command not applicable when not merging'))
6087
6091
6088 wctx = repo[None]
6092 wctx = repo[None]
6089
6093
6090 if ms.mergedriver and ms.mdstate() == 'u':
6094 if ms.mergedriver and ms.mdstate() == 'u':
6091 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6095 proceed = mergemod.driverpreprocess(repo, ms, wctx)
6092 ms.commit()
6096 ms.commit()
6093 # allow mark and unmark to go through
6097 # allow mark and unmark to go through
6094 if not mark and not unmark and not proceed:
6098 if not mark and not unmark and not proceed:
6095 return 1
6099 return 1
6096
6100
6097 m = scmutil.match(wctx, pats, opts)
6101 m = scmutil.match(wctx, pats, opts)
6098 ret = 0
6102 ret = 0
6099 didwork = False
6103 didwork = False
6100 runconclude = False
6104 runconclude = False
6101
6105
6102 tocomplete = []
6106 tocomplete = []
6103 for f in ms:
6107 for f in ms:
6104 if not m(f):
6108 if not m(f):
6105 continue
6109 continue
6106
6110
6107 didwork = True
6111 didwork = True
6108
6112
6109 # don't let driver-resolved files be marked, and run the conclude
6113 # don't let driver-resolved files be marked, and run the conclude
6110 # step if asked to resolve
6114 # step if asked to resolve
6111 if ms[f] == "d":
6115 if ms[f] == "d":
6112 exact = m.exact(f)
6116 exact = m.exact(f)
6113 if mark:
6117 if mark:
6114 if exact:
6118 if exact:
6115 ui.warn(_('not marking %s as it is driver-resolved\n')
6119 ui.warn(_('not marking %s as it is driver-resolved\n')
6116 % f)
6120 % f)
6117 elif unmark:
6121 elif unmark:
6118 if exact:
6122 if exact:
6119 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6123 ui.warn(_('not unmarking %s as it is driver-resolved\n')
6120 % f)
6124 % f)
6121 else:
6125 else:
6122 runconclude = True
6126 runconclude = True
6123 continue
6127 continue
6124
6128
6125 if mark:
6129 if mark:
6126 ms.mark(f, "r")
6130 ms.mark(f, "r")
6127 elif unmark:
6131 elif unmark:
6128 ms.mark(f, "u")
6132 ms.mark(f, "u")
6129 else:
6133 else:
6130 # backup pre-resolve (merge uses .orig for its own purposes)
6134 # backup pre-resolve (merge uses .orig for its own purposes)
6131 a = repo.wjoin(f)
6135 a = repo.wjoin(f)
6132 try:
6136 try:
6133 util.copyfile(a, a + ".resolve")
6137 util.copyfile(a, a + ".resolve")
6134 except (IOError, OSError) as inst:
6138 except (IOError, OSError) as inst:
6135 if inst.errno != errno.ENOENT:
6139 if inst.errno != errno.ENOENT:
6136 raise
6140 raise
6137
6141
6138 try:
6142 try:
6139 # preresolve file
6143 # preresolve file
6140 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6144 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6141 'resolve')
6145 'resolve')
6142 complete, r = ms.preresolve(f, wctx)
6146 complete, r = ms.preresolve(f, wctx)
6143 if not complete:
6147 if not complete:
6144 tocomplete.append(f)
6148 tocomplete.append(f)
6145 elif r:
6149 elif r:
6146 ret = 1
6150 ret = 1
6147 finally:
6151 finally:
6148 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6152 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6149 ms.commit()
6153 ms.commit()
6150
6154
6151 # replace filemerge's .orig file with our resolve file, but only
6155 # replace filemerge's .orig file with our resolve file, but only
6152 # for merges that are complete
6156 # for merges that are complete
6153 if complete:
6157 if complete:
6154 try:
6158 try:
6155 util.rename(a + ".resolve",
6159 util.rename(a + ".resolve",
6156 scmutil.origpath(ui, repo, a))
6160 scmutil.origpath(ui, repo, a))
6157 except OSError as inst:
6161 except OSError as inst:
6158 if inst.errno != errno.ENOENT:
6162 if inst.errno != errno.ENOENT:
6159 raise
6163 raise
6160
6164
6161 for f in tocomplete:
6165 for f in tocomplete:
6162 try:
6166 try:
6163 # resolve file
6167 # resolve file
6164 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6168 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6165 'resolve')
6169 'resolve')
6166 r = ms.resolve(f, wctx)
6170 r = ms.resolve(f, wctx)
6167 if r:
6171 if r:
6168 ret = 1
6172 ret = 1
6169 finally:
6173 finally:
6170 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6174 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6171 ms.commit()
6175 ms.commit()
6172
6176
6173 # replace filemerge's .orig file with our resolve file
6177 # replace filemerge's .orig file with our resolve file
6174 a = repo.wjoin(f)
6178 a = repo.wjoin(f)
6175 try:
6179 try:
6176 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6180 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6177 except OSError as inst:
6181 except OSError as inst:
6178 if inst.errno != errno.ENOENT:
6182 if inst.errno != errno.ENOENT:
6179 raise
6183 raise
6180
6184
6181 ms.commit()
6185 ms.commit()
6182 ms.recordactions()
6186 ms.recordactions()
6183
6187
6184 if not didwork and pats:
6188 if not didwork and pats:
6185 hint = None
6189 hint = None
6186 if not any([p for p in pats if p.find(':') >= 0]):
6190 if not any([p for p in pats if p.find(':') >= 0]):
6187 pats = ['path:%s' % p for p in pats]
6191 pats = ['path:%s' % p for p in pats]
6188 m = scmutil.match(wctx, pats, opts)
6192 m = scmutil.match(wctx, pats, opts)
6189 for f in ms:
6193 for f in ms:
6190 if not m(f):
6194 if not m(f):
6191 continue
6195 continue
6192 flags = ''.join(['-%s ' % o[0] for o in flaglist
6196 flags = ''.join(['-%s ' % o[0] for o in flaglist
6193 if opts.get(o)])
6197 if opts.get(o)])
6194 hint = _("(try: hg resolve %s%s)\n") % (
6198 hint = _("(try: hg resolve %s%s)\n") % (
6195 flags,
6199 flags,
6196 ' '.join(pats))
6200 ' '.join(pats))
6197 break
6201 break
6198 ui.warn(_("arguments do not match paths that need resolving\n"))
6202 ui.warn(_("arguments do not match paths that need resolving\n"))
6199 if hint:
6203 if hint:
6200 ui.warn(hint)
6204 ui.warn(hint)
6201 elif ms.mergedriver and ms.mdstate() != 's':
6205 elif ms.mergedriver and ms.mdstate() != 's':
6202 # run conclude step when either a driver-resolved file is requested
6206 # run conclude step when either a driver-resolved file is requested
6203 # or there are no driver-resolved files
6207 # or there are no driver-resolved files
6204 # we can't use 'ret' to determine whether any files are unresolved
6208 # we can't use 'ret' to determine whether any files are unresolved
6205 # because we might not have tried to resolve some
6209 # because we might not have tried to resolve some
6206 if ((runconclude or not list(ms.driverresolved()))
6210 if ((runconclude or not list(ms.driverresolved()))
6207 and not list(ms.unresolved())):
6211 and not list(ms.unresolved())):
6208 proceed = mergemod.driverconclude(repo, ms, wctx)
6212 proceed = mergemod.driverconclude(repo, ms, wctx)
6209 ms.commit()
6213 ms.commit()
6210 if not proceed:
6214 if not proceed:
6211 return 1
6215 return 1
6212
6216
6213 # Nudge users into finishing an unfinished operation
6217 # Nudge users into finishing an unfinished operation
6214 unresolvedf = list(ms.unresolved())
6218 unresolvedf = list(ms.unresolved())
6215 driverresolvedf = list(ms.driverresolved())
6219 driverresolvedf = list(ms.driverresolved())
6216 if not unresolvedf and not driverresolvedf:
6220 if not unresolvedf and not driverresolvedf:
6217 ui.status(_('(no more unresolved files)\n'))
6221 ui.status(_('(no more unresolved files)\n'))
6218 cmdutil.checkafterresolved(repo)
6222 cmdutil.checkafterresolved(repo)
6219 elif not unresolvedf:
6223 elif not unresolvedf:
6220 ui.status(_('(no more unresolved files -- '
6224 ui.status(_('(no more unresolved files -- '
6221 'run "hg resolve --all" to conclude)\n'))
6225 'run "hg resolve --all" to conclude)\n'))
6222
6226
6223 return ret
6227 return ret
6224
6228
6225 @command('revert',
6229 @command('revert',
6226 [('a', 'all', None, _('revert all changes when no arguments given')),
6230 [('a', 'all', None, _('revert all changes when no arguments given')),
6227 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6231 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6228 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6232 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6229 ('C', 'no-backup', None, _('do not save backup copies of files')),
6233 ('C', 'no-backup', None, _('do not save backup copies of files')),
6230 ('i', 'interactive', None,
6234 ('i', 'interactive', None,
6231 _('interactively select the changes (EXPERIMENTAL)')),
6235 _('interactively select the changes (EXPERIMENTAL)')),
6232 ] + walkopts + dryrunopts,
6236 ] + walkopts + dryrunopts,
6233 _('[OPTION]... [-r REV] [NAME]...'))
6237 _('[OPTION]... [-r REV] [NAME]...'))
6234 def revert(ui, repo, *pats, **opts):
6238 def revert(ui, repo, *pats, **opts):
6235 """restore files to their checkout state
6239 """restore files to their checkout state
6236
6240
6237 .. note::
6241 .. note::
6238
6242
6239 To check out earlier revisions, you should use :hg:`update REV`.
6243 To check out earlier revisions, you should use :hg:`update REV`.
6240 To cancel an uncommitted merge (and lose your changes),
6244 To cancel an uncommitted merge (and lose your changes),
6241 use :hg:`update --clean .`.
6245 use :hg:`update --clean .`.
6242
6246
6243 With no revision specified, revert the specified files or directories
6247 With no revision specified, revert the specified files or directories
6244 to the contents they had in the parent of the working directory.
6248 to the contents they had in the parent of the working directory.
6245 This restores the contents of files to an unmodified
6249 This restores the contents of files to an unmodified
6246 state and unschedules adds, removes, copies, and renames. If the
6250 state and unschedules adds, removes, copies, and renames. If the
6247 working directory has two parents, you must explicitly specify a
6251 working directory has two parents, you must explicitly specify a
6248 revision.
6252 revision.
6249
6253
6250 Using the -r/--rev or -d/--date options, revert the given files or
6254 Using the -r/--rev or -d/--date options, revert the given files or
6251 directories to their states as of a specific revision. Because
6255 directories to their states as of a specific revision. Because
6252 revert does not change the working directory parents, this will
6256 revert does not change the working directory parents, this will
6253 cause these files to appear modified. This can be helpful to "back
6257 cause these files to appear modified. This can be helpful to "back
6254 out" some or all of an earlier change. See :hg:`backout` for a
6258 out" some or all of an earlier change. See :hg:`backout` for a
6255 related method.
6259 related method.
6256
6260
6257 Modified files are saved with a .orig suffix before reverting.
6261 Modified files are saved with a .orig suffix before reverting.
6258 To disable these backups, use --no-backup.
6262 To disable these backups, use --no-backup.
6259
6263
6260 See :hg:`help dates` for a list of formats valid for -d/--date.
6264 See :hg:`help dates` for a list of formats valid for -d/--date.
6261
6265
6262 See :hg:`help backout` for a way to reverse the effect of an
6266 See :hg:`help backout` for a way to reverse the effect of an
6263 earlier changeset.
6267 earlier changeset.
6264
6268
6265 Returns 0 on success.
6269 Returns 0 on success.
6266 """
6270 """
6267
6271
6268 if opts.get("date"):
6272 if opts.get("date"):
6269 if opts.get("rev"):
6273 if opts.get("rev"):
6270 raise error.Abort(_("you can't specify a revision and a date"))
6274 raise error.Abort(_("you can't specify a revision and a date"))
6271 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6275 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6272
6276
6273 parent, p2 = repo.dirstate.parents()
6277 parent, p2 = repo.dirstate.parents()
6274 if not opts.get('rev') and p2 != nullid:
6278 if not opts.get('rev') and p2 != nullid:
6275 # revert after merge is a trap for new users (issue2915)
6279 # revert after merge is a trap for new users (issue2915)
6276 raise error.Abort(_('uncommitted merge with no revision specified'),
6280 raise error.Abort(_('uncommitted merge with no revision specified'),
6277 hint=_('use "hg update" or see "hg help revert"'))
6281 hint=_('use "hg update" or see "hg help revert"'))
6278
6282
6279 ctx = scmutil.revsingle(repo, opts.get('rev'))
6283 ctx = scmutil.revsingle(repo, opts.get('rev'))
6280
6284
6281 if (not (pats or opts.get('include') or opts.get('exclude') or
6285 if (not (pats or opts.get('include') or opts.get('exclude') or
6282 opts.get('all') or opts.get('interactive'))):
6286 opts.get('all') or opts.get('interactive'))):
6283 msg = _("no files or directories specified")
6287 msg = _("no files or directories specified")
6284 if p2 != nullid:
6288 if p2 != nullid:
6285 hint = _("uncommitted merge, use --all to discard all changes,"
6289 hint = _("uncommitted merge, use --all to discard all changes,"
6286 " or 'hg update -C .' to abort the merge")
6290 " or 'hg update -C .' to abort the merge")
6287 raise error.Abort(msg, hint=hint)
6291 raise error.Abort(msg, hint=hint)
6288 dirty = any(repo.status())
6292 dirty = any(repo.status())
6289 node = ctx.node()
6293 node = ctx.node()
6290 if node != parent:
6294 if node != parent:
6291 if dirty:
6295 if dirty:
6292 hint = _("uncommitted changes, use --all to discard all"
6296 hint = _("uncommitted changes, use --all to discard all"
6293 " changes, or 'hg update %s' to update") % ctx.rev()
6297 " changes, or 'hg update %s' to update") % ctx.rev()
6294 else:
6298 else:
6295 hint = _("use --all to revert all files,"
6299 hint = _("use --all to revert all files,"
6296 " or 'hg update %s' to update") % ctx.rev()
6300 " or 'hg update %s' to update") % ctx.rev()
6297 elif dirty:
6301 elif dirty:
6298 hint = _("uncommitted changes, use --all to discard all changes")
6302 hint = _("uncommitted changes, use --all to discard all changes")
6299 else:
6303 else:
6300 hint = _("use --all to revert all files")
6304 hint = _("use --all to revert all files")
6301 raise error.Abort(msg, hint=hint)
6305 raise error.Abort(msg, hint=hint)
6302
6306
6303 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6307 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6304
6308
6305 @command('rollback', dryrunopts +
6309 @command('rollback', dryrunopts +
6306 [('f', 'force', False, _('ignore safety measures'))])
6310 [('f', 'force', False, _('ignore safety measures'))])
6307 def rollback(ui, repo, **opts):
6311 def rollback(ui, repo, **opts):
6308 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6312 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6309
6313
6310 Please use :hg:`commit --amend` instead of rollback to correct
6314 Please use :hg:`commit --amend` instead of rollback to correct
6311 mistakes in the last commit.
6315 mistakes in the last commit.
6312
6316
6313 This command should be used with care. There is only one level of
6317 This command should be used with care. There is only one level of
6314 rollback, and there is no way to undo a rollback. It will also
6318 rollback, and there is no way to undo a rollback. It will also
6315 restore the dirstate at the time of the last transaction, losing
6319 restore the dirstate at the time of the last transaction, losing
6316 any dirstate changes since that time. This command does not alter
6320 any dirstate changes since that time. This command does not alter
6317 the working directory.
6321 the working directory.
6318
6322
6319 Transactions are used to encapsulate the effects of all commands
6323 Transactions are used to encapsulate the effects of all commands
6320 that create new changesets or propagate existing changesets into a
6324 that create new changesets or propagate existing changesets into a
6321 repository.
6325 repository.
6322
6326
6323 .. container:: verbose
6327 .. container:: verbose
6324
6328
6325 For example, the following commands are transactional, and their
6329 For example, the following commands are transactional, and their
6326 effects can be rolled back:
6330 effects can be rolled back:
6327
6331
6328 - commit
6332 - commit
6329 - import
6333 - import
6330 - pull
6334 - pull
6331 - push (with this repository as the destination)
6335 - push (with this repository as the destination)
6332 - unbundle
6336 - unbundle
6333
6337
6334 To avoid permanent data loss, rollback will refuse to rollback a
6338 To avoid permanent data loss, rollback will refuse to rollback a
6335 commit transaction if it isn't checked out. Use --force to
6339 commit transaction if it isn't checked out. Use --force to
6336 override this protection.
6340 override this protection.
6337
6341
6338 This command is not intended for use on public repositories. Once
6342 This command is not intended for use on public repositories. Once
6339 changes are visible for pull by other users, rolling a transaction
6343 changes are visible for pull by other users, rolling a transaction
6340 back locally is ineffective (someone else may already have pulled
6344 back locally is ineffective (someone else may already have pulled
6341 the changes). Furthermore, a race is possible with readers of the
6345 the changes). Furthermore, a race is possible with readers of the
6342 repository; for example an in-progress pull from the repository
6346 repository; for example an in-progress pull from the repository
6343 may fail if a rollback is performed.
6347 may fail if a rollback is performed.
6344
6348
6345 Returns 0 on success, 1 if no rollback data is available.
6349 Returns 0 on success, 1 if no rollback data is available.
6346 """
6350 """
6347 return repo.rollback(dryrun=opts.get('dry_run'),
6351 return repo.rollback(dryrun=opts.get('dry_run'),
6348 force=opts.get('force'))
6352 force=opts.get('force'))
6349
6353
6350 @command('root', [])
6354 @command('root', [])
6351 def root(ui, repo):
6355 def root(ui, repo):
6352 """print the root (top) of the current working directory
6356 """print the root (top) of the current working directory
6353
6357
6354 Print the root directory of the current repository.
6358 Print the root directory of the current repository.
6355
6359
6356 Returns 0 on success.
6360 Returns 0 on success.
6357 """
6361 """
6358 ui.write(repo.root + "\n")
6362 ui.write(repo.root + "\n")
6359
6363
6360 @command('^serve',
6364 @command('^serve',
6361 [('A', 'accesslog', '', _('name of access log file to write to'),
6365 [('A', 'accesslog', '', _('name of access log file to write to'),
6362 _('FILE')),
6366 _('FILE')),
6363 ('d', 'daemon', None, _('run server in background')),
6367 ('d', 'daemon', None, _('run server in background')),
6364 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6368 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
6365 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6369 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6366 # use string type, then we can check if something was passed
6370 # use string type, then we can check if something was passed
6367 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6371 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6368 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6372 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6369 _('ADDR')),
6373 _('ADDR')),
6370 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6374 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6371 _('PREFIX')),
6375 _('PREFIX')),
6372 ('n', 'name', '',
6376 ('n', 'name', '',
6373 _('name to show in web pages (default: working directory)'), _('NAME')),
6377 _('name to show in web pages (default: working directory)'), _('NAME')),
6374 ('', 'web-conf', '',
6378 ('', 'web-conf', '',
6375 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6379 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6376 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6380 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6377 _('FILE')),
6381 _('FILE')),
6378 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6382 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6379 ('', 'stdio', None, _('for remote clients')),
6383 ('', 'stdio', None, _('for remote clients')),
6380 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6384 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6381 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6385 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6382 ('', 'style', '', _('template style to use'), _('STYLE')),
6386 ('', 'style', '', _('template style to use'), _('STYLE')),
6383 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6387 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6384 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6388 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6385 _('[OPTION]...'),
6389 _('[OPTION]...'),
6386 optionalrepo=True)
6390 optionalrepo=True)
6387 def serve(ui, repo, **opts):
6391 def serve(ui, repo, **opts):
6388 """start stand-alone webserver
6392 """start stand-alone webserver
6389
6393
6390 Start a local HTTP repository browser and pull server. You can use
6394 Start a local HTTP repository browser and pull server. You can use
6391 this for ad-hoc sharing and browsing of repositories. It is
6395 this for ad-hoc sharing and browsing of repositories. It is
6392 recommended to use a real web server to serve a repository for
6396 recommended to use a real web server to serve a repository for
6393 longer periods of time.
6397 longer periods of time.
6394
6398
6395 Please note that the server does not implement access control.
6399 Please note that the server does not implement access control.
6396 This means that, by default, anybody can read from the server and
6400 This means that, by default, anybody can read from the server and
6397 nobody can write to it by default. Set the ``web.allow_push``
6401 nobody can write to it by default. Set the ``web.allow_push``
6398 option to ``*`` to allow everybody to push to the server. You
6402 option to ``*`` to allow everybody to push to the server. You
6399 should use a real web server if you need to authenticate users.
6403 should use a real web server if you need to authenticate users.
6400
6404
6401 By default, the server logs accesses to stdout and errors to
6405 By default, the server logs accesses to stdout and errors to
6402 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6406 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6403 files.
6407 files.
6404
6408
6405 To have the server choose a free port number to listen on, specify
6409 To have the server choose a free port number to listen on, specify
6406 a port number of 0; in this case, the server will print the port
6410 a port number of 0; in this case, the server will print the port
6407 number it uses.
6411 number it uses.
6408
6412
6409 Returns 0 on success.
6413 Returns 0 on success.
6410 """
6414 """
6411
6415
6412 if opts["stdio"] and opts["cmdserver"]:
6416 if opts["stdio"] and opts["cmdserver"]:
6413 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6417 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6414
6418
6415 if opts["stdio"]:
6419 if opts["stdio"]:
6416 if repo is None:
6420 if repo is None:
6417 raise error.RepoError(_("there is no Mercurial repository here"
6421 raise error.RepoError(_("there is no Mercurial repository here"
6418 " (.hg not found)"))
6422 " (.hg not found)"))
6419 s = sshserver.sshserver(ui, repo)
6423 s = sshserver.sshserver(ui, repo)
6420 s.serve_forever()
6424 s.serve_forever()
6421
6425
6422 if opts["cmdserver"]:
6426 if opts["cmdserver"]:
6423 service = commandserver.createservice(ui, repo, opts)
6427 service = commandserver.createservice(ui, repo, opts)
6424 else:
6428 else:
6425 service = hgweb.createservice(ui, repo, opts)
6429 service = hgweb.createservice(ui, repo, opts)
6426 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6430 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6427
6431
6428 @command('^status|st',
6432 @command('^status|st',
6429 [('A', 'all', None, _('show status of all files')),
6433 [('A', 'all', None, _('show status of all files')),
6430 ('m', 'modified', None, _('show only modified files')),
6434 ('m', 'modified', None, _('show only modified files')),
6431 ('a', 'added', None, _('show only added files')),
6435 ('a', 'added', None, _('show only added files')),
6432 ('r', 'removed', None, _('show only removed files')),
6436 ('r', 'removed', None, _('show only removed files')),
6433 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6437 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6434 ('c', 'clean', None, _('show only files without changes')),
6438 ('c', 'clean', None, _('show only files without changes')),
6435 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6439 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6436 ('i', 'ignored', None, _('show only ignored files')),
6440 ('i', 'ignored', None, _('show only ignored files')),
6437 ('n', 'no-status', None, _('hide status prefix')),
6441 ('n', 'no-status', None, _('hide status prefix')),
6438 ('C', 'copies', None, _('show source of copied files')),
6442 ('C', 'copies', None, _('show source of copied files')),
6439 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6443 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6440 ('', 'rev', [], _('show difference from revision'), _('REV')),
6444 ('', 'rev', [], _('show difference from revision'), _('REV')),
6441 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6445 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6442 ] + walkopts + subrepoopts + formatteropts,
6446 ] + walkopts + subrepoopts + formatteropts,
6443 _('[OPTION]... [FILE]...'),
6447 _('[OPTION]... [FILE]...'),
6444 inferrepo=True)
6448 inferrepo=True)
6445 def status(ui, repo, *pats, **opts):
6449 def status(ui, repo, *pats, **opts):
6446 """show changed files in the working directory
6450 """show changed files in the working directory
6447
6451
6448 Show status of files in the repository. If names are given, only
6452 Show status of files in the repository. If names are given, only
6449 files that match are shown. Files that are clean or ignored or
6453 files that match are shown. Files that are clean or ignored or
6450 the source of a copy/move operation, are not listed unless
6454 the source of a copy/move operation, are not listed unless
6451 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6455 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6452 Unless options described with "show only ..." are given, the
6456 Unless options described with "show only ..." are given, the
6453 options -mardu are used.
6457 options -mardu are used.
6454
6458
6455 Option -q/--quiet hides untracked (unknown and ignored) files
6459 Option -q/--quiet hides untracked (unknown and ignored) files
6456 unless explicitly requested with -u/--unknown or -i/--ignored.
6460 unless explicitly requested with -u/--unknown or -i/--ignored.
6457
6461
6458 .. note::
6462 .. note::
6459
6463
6460 :hg:`status` may appear to disagree with diff if permissions have
6464 :hg:`status` may appear to disagree with diff if permissions have
6461 changed or a merge has occurred. The standard diff format does
6465 changed or a merge has occurred. The standard diff format does
6462 not report permission changes and diff only reports changes
6466 not report permission changes and diff only reports changes
6463 relative to one merge parent.
6467 relative to one merge parent.
6464
6468
6465 If one revision is given, it is used as the base revision.
6469 If one revision is given, it is used as the base revision.
6466 If two revisions are given, the differences between them are
6470 If two revisions are given, the differences between them are
6467 shown. The --change option can also be used as a shortcut to list
6471 shown. The --change option can also be used as a shortcut to list
6468 the changed files of a revision from its first parent.
6472 the changed files of a revision from its first parent.
6469
6473
6470 The codes used to show the status of files are::
6474 The codes used to show the status of files are::
6471
6475
6472 M = modified
6476 M = modified
6473 A = added
6477 A = added
6474 R = removed
6478 R = removed
6475 C = clean
6479 C = clean
6476 ! = missing (deleted by non-hg command, but still tracked)
6480 ! = missing (deleted by non-hg command, but still tracked)
6477 ? = not tracked
6481 ? = not tracked
6478 I = ignored
6482 I = ignored
6479 = origin of the previous file (with --copies)
6483 = origin of the previous file (with --copies)
6480
6484
6481 .. container:: verbose
6485 .. container:: verbose
6482
6486
6483 Examples:
6487 Examples:
6484
6488
6485 - show changes in the working directory relative to a
6489 - show changes in the working directory relative to a
6486 changeset::
6490 changeset::
6487
6491
6488 hg status --rev 9353
6492 hg status --rev 9353
6489
6493
6490 - show changes in the working directory relative to the
6494 - show changes in the working directory relative to the
6491 current directory (see :hg:`help patterns` for more information)::
6495 current directory (see :hg:`help patterns` for more information)::
6492
6496
6493 hg status re:
6497 hg status re:
6494
6498
6495 - show all changes including copies in an existing changeset::
6499 - show all changes including copies in an existing changeset::
6496
6500
6497 hg status --copies --change 9353
6501 hg status --copies --change 9353
6498
6502
6499 - get a NUL separated list of added files, suitable for xargs::
6503 - get a NUL separated list of added files, suitable for xargs::
6500
6504
6501 hg status -an0
6505 hg status -an0
6502
6506
6503 Returns 0 on success.
6507 Returns 0 on success.
6504 """
6508 """
6505
6509
6506 revs = opts.get('rev')
6510 revs = opts.get('rev')
6507 change = opts.get('change')
6511 change = opts.get('change')
6508
6512
6509 if revs and change:
6513 if revs and change:
6510 msg = _('cannot specify --rev and --change at the same time')
6514 msg = _('cannot specify --rev and --change at the same time')
6511 raise error.Abort(msg)
6515 raise error.Abort(msg)
6512 elif change:
6516 elif change:
6513 node2 = scmutil.revsingle(repo, change, None).node()
6517 node2 = scmutil.revsingle(repo, change, None).node()
6514 node1 = repo[node2].p1().node()
6518 node1 = repo[node2].p1().node()
6515 else:
6519 else:
6516 node1, node2 = scmutil.revpair(repo, revs)
6520 node1, node2 = scmutil.revpair(repo, revs)
6517
6521
6518 if pats:
6522 if pats:
6519 cwd = repo.getcwd()
6523 cwd = repo.getcwd()
6520 else:
6524 else:
6521 cwd = ''
6525 cwd = ''
6522
6526
6523 if opts.get('print0'):
6527 if opts.get('print0'):
6524 end = '\0'
6528 end = '\0'
6525 else:
6529 else:
6526 end = '\n'
6530 end = '\n'
6527 copy = {}
6531 copy = {}
6528 states = 'modified added removed deleted unknown ignored clean'.split()
6532 states = 'modified added removed deleted unknown ignored clean'.split()
6529 show = [k for k in states if opts.get(k)]
6533 show = [k for k in states if opts.get(k)]
6530 if opts.get('all'):
6534 if opts.get('all'):
6531 show += ui.quiet and (states[:4] + ['clean']) or states
6535 show += ui.quiet and (states[:4] + ['clean']) or states
6532 if not show:
6536 if not show:
6533 if ui.quiet:
6537 if ui.quiet:
6534 show = states[:4]
6538 show = states[:4]
6535 else:
6539 else:
6536 show = states[:5]
6540 show = states[:5]
6537
6541
6538 m = scmutil.match(repo[node2], pats, opts)
6542 m = scmutil.match(repo[node2], pats, opts)
6539 stat = repo.status(node1, node2, m,
6543 stat = repo.status(node1, node2, m,
6540 'ignored' in show, 'clean' in show, 'unknown' in show,
6544 'ignored' in show, 'clean' in show, 'unknown' in show,
6541 opts.get('subrepos'))
6545 opts.get('subrepos'))
6542 changestates = zip(states, 'MAR!?IC', stat)
6546 changestates = zip(states, 'MAR!?IC', stat)
6543
6547
6544 if (opts.get('all') or opts.get('copies')
6548 if (opts.get('all') or opts.get('copies')
6545 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6549 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6546 copy = copies.pathcopies(repo[node1], repo[node2], m)
6550 copy = copies.pathcopies(repo[node1], repo[node2], m)
6547
6551
6548 fm = ui.formatter('status', opts)
6552 fm = ui.formatter('status', opts)
6549 fmt = '%s' + end
6553 fmt = '%s' + end
6550 showchar = not opts.get('no_status')
6554 showchar = not opts.get('no_status')
6551
6555
6552 for state, char, files in changestates:
6556 for state, char, files in changestates:
6553 if state in show:
6557 if state in show:
6554 label = 'status.' + state
6558 label = 'status.' + state
6555 for f in files:
6559 for f in files:
6556 fm.startitem()
6560 fm.startitem()
6557 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6561 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6558 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6562 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6559 if f in copy:
6563 if f in copy:
6560 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6564 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6561 label='status.copied')
6565 label='status.copied')
6562 fm.end()
6566 fm.end()
6563
6567
6564 @command('^summary|sum',
6568 @command('^summary|sum',
6565 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6569 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6566 def summary(ui, repo, **opts):
6570 def summary(ui, repo, **opts):
6567 """summarize working directory state
6571 """summarize working directory state
6568
6572
6569 This generates a brief summary of the working directory state,
6573 This generates a brief summary of the working directory state,
6570 including parents, branch, commit status, phase and available updates.
6574 including parents, branch, commit status, phase and available updates.
6571
6575
6572 With the --remote option, this will check the default paths for
6576 With the --remote option, this will check the default paths for
6573 incoming and outgoing changes. This can be time-consuming.
6577 incoming and outgoing changes. This can be time-consuming.
6574
6578
6575 Returns 0 on success.
6579 Returns 0 on success.
6576 """
6580 """
6577
6581
6578 ctx = repo[None]
6582 ctx = repo[None]
6579 parents = ctx.parents()
6583 parents = ctx.parents()
6580 pnode = parents[0].node()
6584 pnode = parents[0].node()
6581 marks = []
6585 marks = []
6582
6586
6583 ms = None
6587 ms = None
6584 try:
6588 try:
6585 ms = mergemod.mergestate.read(repo)
6589 ms = mergemod.mergestate.read(repo)
6586 except error.UnsupportedMergeRecords as e:
6590 except error.UnsupportedMergeRecords as e:
6587 s = ' '.join(e.recordtypes)
6591 s = ' '.join(e.recordtypes)
6588 ui.warn(
6592 ui.warn(
6589 _('warning: merge state has unsupported record types: %s\n') % s)
6593 _('warning: merge state has unsupported record types: %s\n') % s)
6590 unresolved = 0
6594 unresolved = 0
6591 else:
6595 else:
6592 unresolved = [f for f in ms if ms[f] == 'u']
6596 unresolved = [f for f in ms if ms[f] == 'u']
6593
6597
6594 for p in parents:
6598 for p in parents:
6595 # label with log.changeset (instead of log.parent) since this
6599 # label with log.changeset (instead of log.parent) since this
6596 # shows a working directory parent *changeset*:
6600 # shows a working directory parent *changeset*:
6597 # i18n: column positioning for "hg summary"
6601 # i18n: column positioning for "hg summary"
6598 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6602 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6599 label='log.changeset changeset.%s' % p.phasestr())
6603 label='log.changeset changeset.%s' % p.phasestr())
6600 ui.write(' '.join(p.tags()), label='log.tag')
6604 ui.write(' '.join(p.tags()), label='log.tag')
6601 if p.bookmarks():
6605 if p.bookmarks():
6602 marks.extend(p.bookmarks())
6606 marks.extend(p.bookmarks())
6603 if p.rev() == -1:
6607 if p.rev() == -1:
6604 if not len(repo):
6608 if not len(repo):
6605 ui.write(_(' (empty repository)'))
6609 ui.write(_(' (empty repository)'))
6606 else:
6610 else:
6607 ui.write(_(' (no revision checked out)'))
6611 ui.write(_(' (no revision checked out)'))
6608 ui.write('\n')
6612 ui.write('\n')
6609 if p.description():
6613 if p.description():
6610 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6614 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6611 label='log.summary')
6615 label='log.summary')
6612
6616
6613 branch = ctx.branch()
6617 branch = ctx.branch()
6614 bheads = repo.branchheads(branch)
6618 bheads = repo.branchheads(branch)
6615 # i18n: column positioning for "hg summary"
6619 # i18n: column positioning for "hg summary"
6616 m = _('branch: %s\n') % branch
6620 m = _('branch: %s\n') % branch
6617 if branch != 'default':
6621 if branch != 'default':
6618 ui.write(m, label='log.branch')
6622 ui.write(m, label='log.branch')
6619 else:
6623 else:
6620 ui.status(m, label='log.branch')
6624 ui.status(m, label='log.branch')
6621
6625
6622 if marks:
6626 if marks:
6623 active = repo._activebookmark
6627 active = repo._activebookmark
6624 # i18n: column positioning for "hg summary"
6628 # i18n: column positioning for "hg summary"
6625 ui.write(_('bookmarks:'), label='log.bookmark')
6629 ui.write(_('bookmarks:'), label='log.bookmark')
6626 if active is not None:
6630 if active is not None:
6627 if active in marks:
6631 if active in marks:
6628 ui.write(' *' + active, label=activebookmarklabel)
6632 ui.write(' *' + active, label=activebookmarklabel)
6629 marks.remove(active)
6633 marks.remove(active)
6630 else:
6634 else:
6631 ui.write(' [%s]' % active, label=activebookmarklabel)
6635 ui.write(' [%s]' % active, label=activebookmarklabel)
6632 for m in marks:
6636 for m in marks:
6633 ui.write(' ' + m, label='log.bookmark')
6637 ui.write(' ' + m, label='log.bookmark')
6634 ui.write('\n', label='log.bookmark')
6638 ui.write('\n', label='log.bookmark')
6635
6639
6636 status = repo.status(unknown=True)
6640 status = repo.status(unknown=True)
6637
6641
6638 c = repo.dirstate.copies()
6642 c = repo.dirstate.copies()
6639 copied, renamed = [], []
6643 copied, renamed = [], []
6640 for d, s in c.iteritems():
6644 for d, s in c.iteritems():
6641 if s in status.removed:
6645 if s in status.removed:
6642 status.removed.remove(s)
6646 status.removed.remove(s)
6643 renamed.append(d)
6647 renamed.append(d)
6644 else:
6648 else:
6645 copied.append(d)
6649 copied.append(d)
6646 if d in status.added:
6650 if d in status.added:
6647 status.added.remove(d)
6651 status.added.remove(d)
6648
6652
6649 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6653 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6650
6654
6651 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6655 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6652 (ui.label(_('%d added'), 'status.added'), status.added),
6656 (ui.label(_('%d added'), 'status.added'), status.added),
6653 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6657 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6654 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6658 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6655 (ui.label(_('%d copied'), 'status.copied'), copied),
6659 (ui.label(_('%d copied'), 'status.copied'), copied),
6656 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6660 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6657 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6661 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6658 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6662 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6659 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6663 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6660 t = []
6664 t = []
6661 for l, s in labels:
6665 for l, s in labels:
6662 if s:
6666 if s:
6663 t.append(l % len(s))
6667 t.append(l % len(s))
6664
6668
6665 t = ', '.join(t)
6669 t = ', '.join(t)
6666 cleanworkdir = False
6670 cleanworkdir = False
6667
6671
6668 if repo.vfs.exists('graftstate'):
6672 if repo.vfs.exists('graftstate'):
6669 t += _(' (graft in progress)')
6673 t += _(' (graft in progress)')
6670 if repo.vfs.exists('updatestate'):
6674 if repo.vfs.exists('updatestate'):
6671 t += _(' (interrupted update)')
6675 t += _(' (interrupted update)')
6672 elif len(parents) > 1:
6676 elif len(parents) > 1:
6673 t += _(' (merge)')
6677 t += _(' (merge)')
6674 elif branch != parents[0].branch():
6678 elif branch != parents[0].branch():
6675 t += _(' (new branch)')
6679 t += _(' (new branch)')
6676 elif (parents[0].closesbranch() and
6680 elif (parents[0].closesbranch() and
6677 pnode in repo.branchheads(branch, closed=True)):
6681 pnode in repo.branchheads(branch, closed=True)):
6678 t += _(' (head closed)')
6682 t += _(' (head closed)')
6679 elif not (status.modified or status.added or status.removed or renamed or
6683 elif not (status.modified or status.added or status.removed or renamed or
6680 copied or subs):
6684 copied or subs):
6681 t += _(' (clean)')
6685 t += _(' (clean)')
6682 cleanworkdir = True
6686 cleanworkdir = True
6683 elif pnode not in bheads:
6687 elif pnode not in bheads:
6684 t += _(' (new branch head)')
6688 t += _(' (new branch head)')
6685
6689
6686 if parents:
6690 if parents:
6687 pendingphase = max(p.phase() for p in parents)
6691 pendingphase = max(p.phase() for p in parents)
6688 else:
6692 else:
6689 pendingphase = phases.public
6693 pendingphase = phases.public
6690
6694
6691 if pendingphase > phases.newcommitphase(ui):
6695 if pendingphase > phases.newcommitphase(ui):
6692 t += ' (%s)' % phases.phasenames[pendingphase]
6696 t += ' (%s)' % phases.phasenames[pendingphase]
6693
6697
6694 if cleanworkdir:
6698 if cleanworkdir:
6695 # i18n: column positioning for "hg summary"
6699 # i18n: column positioning for "hg summary"
6696 ui.status(_('commit: %s\n') % t.strip())
6700 ui.status(_('commit: %s\n') % t.strip())
6697 else:
6701 else:
6698 # i18n: column positioning for "hg summary"
6702 # i18n: column positioning for "hg summary"
6699 ui.write(_('commit: %s\n') % t.strip())
6703 ui.write(_('commit: %s\n') % t.strip())
6700
6704
6701 # all ancestors of branch heads - all ancestors of parent = new csets
6705 # all ancestors of branch heads - all ancestors of parent = new csets
6702 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6706 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6703 bheads))
6707 bheads))
6704
6708
6705 if new == 0:
6709 if new == 0:
6706 # i18n: column positioning for "hg summary"
6710 # i18n: column positioning for "hg summary"
6707 ui.status(_('update: (current)\n'))
6711 ui.status(_('update: (current)\n'))
6708 elif pnode not in bheads:
6712 elif pnode not in bheads:
6709 # i18n: column positioning for "hg summary"
6713 # i18n: column positioning for "hg summary"
6710 ui.write(_('update: %d new changesets (update)\n') % new)
6714 ui.write(_('update: %d new changesets (update)\n') % new)
6711 else:
6715 else:
6712 # i18n: column positioning for "hg summary"
6716 # i18n: column positioning for "hg summary"
6713 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6717 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6714 (new, len(bheads)))
6718 (new, len(bheads)))
6715
6719
6716 t = []
6720 t = []
6717 draft = len(repo.revs('draft()'))
6721 draft = len(repo.revs('draft()'))
6718 if draft:
6722 if draft:
6719 t.append(_('%d draft') % draft)
6723 t.append(_('%d draft') % draft)
6720 secret = len(repo.revs('secret()'))
6724 secret = len(repo.revs('secret()'))
6721 if secret:
6725 if secret:
6722 t.append(_('%d secret') % secret)
6726 t.append(_('%d secret') % secret)
6723
6727
6724 if draft or secret:
6728 if draft or secret:
6725 ui.status(_('phases: %s\n') % ', '.join(t))
6729 ui.status(_('phases: %s\n') % ', '.join(t))
6726
6730
6727 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6731 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6728 for trouble in ("unstable", "divergent", "bumped"):
6732 for trouble in ("unstable", "divergent", "bumped"):
6729 numtrouble = len(repo.revs(trouble + "()"))
6733 numtrouble = len(repo.revs(trouble + "()"))
6730 # We write all the possibilities to ease translation
6734 # We write all the possibilities to ease translation
6731 troublemsg = {
6735 troublemsg = {
6732 "unstable": _("unstable: %d changesets"),
6736 "unstable": _("unstable: %d changesets"),
6733 "divergent": _("divergent: %d changesets"),
6737 "divergent": _("divergent: %d changesets"),
6734 "bumped": _("bumped: %d changesets"),
6738 "bumped": _("bumped: %d changesets"),
6735 }
6739 }
6736 if numtrouble > 0:
6740 if numtrouble > 0:
6737 ui.status(troublemsg[trouble] % numtrouble + "\n")
6741 ui.status(troublemsg[trouble] % numtrouble + "\n")
6738
6742
6739 cmdutil.summaryhooks(ui, repo)
6743 cmdutil.summaryhooks(ui, repo)
6740
6744
6741 if opts.get('remote'):
6745 if opts.get('remote'):
6742 needsincoming, needsoutgoing = True, True
6746 needsincoming, needsoutgoing = True, True
6743 else:
6747 else:
6744 needsincoming, needsoutgoing = False, False
6748 needsincoming, needsoutgoing = False, False
6745 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6749 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6746 if i:
6750 if i:
6747 needsincoming = True
6751 needsincoming = True
6748 if o:
6752 if o:
6749 needsoutgoing = True
6753 needsoutgoing = True
6750 if not needsincoming and not needsoutgoing:
6754 if not needsincoming and not needsoutgoing:
6751 return
6755 return
6752
6756
6753 def getincoming():
6757 def getincoming():
6754 source, branches = hg.parseurl(ui.expandpath('default'))
6758 source, branches = hg.parseurl(ui.expandpath('default'))
6755 sbranch = branches[0]
6759 sbranch = branches[0]
6756 try:
6760 try:
6757 other = hg.peer(repo, {}, source)
6761 other = hg.peer(repo, {}, source)
6758 except error.RepoError:
6762 except error.RepoError:
6759 if opts.get('remote'):
6763 if opts.get('remote'):
6760 raise
6764 raise
6761 return source, sbranch, None, None, None
6765 return source, sbranch, None, None, None
6762 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6766 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6763 if revs:
6767 if revs:
6764 revs = [other.lookup(rev) for rev in revs]
6768 revs = [other.lookup(rev) for rev in revs]
6765 ui.debug('comparing with %s\n' % util.hidepassword(source))
6769 ui.debug('comparing with %s\n' % util.hidepassword(source))
6766 repo.ui.pushbuffer()
6770 repo.ui.pushbuffer()
6767 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6771 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6768 repo.ui.popbuffer()
6772 repo.ui.popbuffer()
6769 return source, sbranch, other, commoninc, commoninc[1]
6773 return source, sbranch, other, commoninc, commoninc[1]
6770
6774
6771 if needsincoming:
6775 if needsincoming:
6772 source, sbranch, sother, commoninc, incoming = getincoming()
6776 source, sbranch, sother, commoninc, incoming = getincoming()
6773 else:
6777 else:
6774 source = sbranch = sother = commoninc = incoming = None
6778 source = sbranch = sother = commoninc = incoming = None
6775
6779
6776 def getoutgoing():
6780 def getoutgoing():
6777 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6781 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6778 dbranch = branches[0]
6782 dbranch = branches[0]
6779 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6783 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6780 if source != dest:
6784 if source != dest:
6781 try:
6785 try:
6782 dother = hg.peer(repo, {}, dest)
6786 dother = hg.peer(repo, {}, dest)
6783 except error.RepoError:
6787 except error.RepoError:
6784 if opts.get('remote'):
6788 if opts.get('remote'):
6785 raise
6789 raise
6786 return dest, dbranch, None, None
6790 return dest, dbranch, None, None
6787 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6791 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6788 elif sother is None:
6792 elif sother is None:
6789 # there is no explicit destination peer, but source one is invalid
6793 # there is no explicit destination peer, but source one is invalid
6790 return dest, dbranch, None, None
6794 return dest, dbranch, None, None
6791 else:
6795 else:
6792 dother = sother
6796 dother = sother
6793 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6797 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6794 common = None
6798 common = None
6795 else:
6799 else:
6796 common = commoninc
6800 common = commoninc
6797 if revs:
6801 if revs:
6798 revs = [repo.lookup(rev) for rev in revs]
6802 revs = [repo.lookup(rev) for rev in revs]
6799 repo.ui.pushbuffer()
6803 repo.ui.pushbuffer()
6800 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6804 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6801 commoninc=common)
6805 commoninc=common)
6802 repo.ui.popbuffer()
6806 repo.ui.popbuffer()
6803 return dest, dbranch, dother, outgoing
6807 return dest, dbranch, dother, outgoing
6804
6808
6805 if needsoutgoing:
6809 if needsoutgoing:
6806 dest, dbranch, dother, outgoing = getoutgoing()
6810 dest, dbranch, dother, outgoing = getoutgoing()
6807 else:
6811 else:
6808 dest = dbranch = dother = outgoing = None
6812 dest = dbranch = dother = outgoing = None
6809
6813
6810 if opts.get('remote'):
6814 if opts.get('remote'):
6811 t = []
6815 t = []
6812 if incoming:
6816 if incoming:
6813 t.append(_('1 or more incoming'))
6817 t.append(_('1 or more incoming'))
6814 o = outgoing.missing
6818 o = outgoing.missing
6815 if o:
6819 if o:
6816 t.append(_('%d outgoing') % len(o))
6820 t.append(_('%d outgoing') % len(o))
6817 other = dother or sother
6821 other = dother or sother
6818 if 'bookmarks' in other.listkeys('namespaces'):
6822 if 'bookmarks' in other.listkeys('namespaces'):
6819 counts = bookmarks.summary(repo, other)
6823 counts = bookmarks.summary(repo, other)
6820 if counts[0] > 0:
6824 if counts[0] > 0:
6821 t.append(_('%d incoming bookmarks') % counts[0])
6825 t.append(_('%d incoming bookmarks') % counts[0])
6822 if counts[1] > 0:
6826 if counts[1] > 0:
6823 t.append(_('%d outgoing bookmarks') % counts[1])
6827 t.append(_('%d outgoing bookmarks') % counts[1])
6824
6828
6825 if t:
6829 if t:
6826 # i18n: column positioning for "hg summary"
6830 # i18n: column positioning for "hg summary"
6827 ui.write(_('remote: %s\n') % (', '.join(t)))
6831 ui.write(_('remote: %s\n') % (', '.join(t)))
6828 else:
6832 else:
6829 # i18n: column positioning for "hg summary"
6833 # i18n: column positioning for "hg summary"
6830 ui.status(_('remote: (synced)\n'))
6834 ui.status(_('remote: (synced)\n'))
6831
6835
6832 cmdutil.summaryremotehooks(ui, repo, opts,
6836 cmdutil.summaryremotehooks(ui, repo, opts,
6833 ((source, sbranch, sother, commoninc),
6837 ((source, sbranch, sother, commoninc),
6834 (dest, dbranch, dother, outgoing)))
6838 (dest, dbranch, dother, outgoing)))
6835
6839
6836 @command('tag',
6840 @command('tag',
6837 [('f', 'force', None, _('force tag')),
6841 [('f', 'force', None, _('force tag')),
6838 ('l', 'local', None, _('make the tag local')),
6842 ('l', 'local', None, _('make the tag local')),
6839 ('r', 'rev', '', _('revision to tag'), _('REV')),
6843 ('r', 'rev', '', _('revision to tag'), _('REV')),
6840 ('', 'remove', None, _('remove a tag')),
6844 ('', 'remove', None, _('remove a tag')),
6841 # -l/--local is already there, commitopts cannot be used
6845 # -l/--local is already there, commitopts cannot be used
6842 ('e', 'edit', None, _('invoke editor on commit messages')),
6846 ('e', 'edit', None, _('invoke editor on commit messages')),
6843 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6847 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6844 ] + commitopts2,
6848 ] + commitopts2,
6845 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6849 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6846 def tag(ui, repo, name1, *names, **opts):
6850 def tag(ui, repo, name1, *names, **opts):
6847 """add one or more tags for the current or given revision
6851 """add one or more tags for the current or given revision
6848
6852
6849 Name a particular revision using <name>.
6853 Name a particular revision using <name>.
6850
6854
6851 Tags are used to name particular revisions of the repository and are
6855 Tags are used to name particular revisions of the repository and are
6852 very useful to compare different revisions, to go back to significant
6856 very useful to compare different revisions, to go back to significant
6853 earlier versions or to mark branch points as releases, etc. Changing
6857 earlier versions or to mark branch points as releases, etc. Changing
6854 an existing tag is normally disallowed; use -f/--force to override.
6858 an existing tag is normally disallowed; use -f/--force to override.
6855
6859
6856 If no revision is given, the parent of the working directory is
6860 If no revision is given, the parent of the working directory is
6857 used.
6861 used.
6858
6862
6859 To facilitate version control, distribution, and merging of tags,
6863 To facilitate version control, distribution, and merging of tags,
6860 they are stored as a file named ".hgtags" which is managed similarly
6864 they are stored as a file named ".hgtags" which is managed similarly
6861 to other project files and can be hand-edited if necessary. This
6865 to other project files and can be hand-edited if necessary. This
6862 also means that tagging creates a new commit. The file
6866 also means that tagging creates a new commit. The file
6863 ".hg/localtags" is used for local tags (not shared among
6867 ".hg/localtags" is used for local tags (not shared among
6864 repositories).
6868 repositories).
6865
6869
6866 Tag commits are usually made at the head of a branch. If the parent
6870 Tag commits are usually made at the head of a branch. If the parent
6867 of the working directory is not a branch head, :hg:`tag` aborts; use
6871 of the working directory is not a branch head, :hg:`tag` aborts; use
6868 -f/--force to force the tag commit to be based on a non-head
6872 -f/--force to force the tag commit to be based on a non-head
6869 changeset.
6873 changeset.
6870
6874
6871 See :hg:`help dates` for a list of formats valid for -d/--date.
6875 See :hg:`help dates` for a list of formats valid for -d/--date.
6872
6876
6873 Since tag names have priority over branch names during revision
6877 Since tag names have priority over branch names during revision
6874 lookup, using an existing branch name as a tag name is discouraged.
6878 lookup, using an existing branch name as a tag name is discouraged.
6875
6879
6876 Returns 0 on success.
6880 Returns 0 on success.
6877 """
6881 """
6878 wlock = lock = None
6882 wlock = lock = None
6879 try:
6883 try:
6880 wlock = repo.wlock()
6884 wlock = repo.wlock()
6881 lock = repo.lock()
6885 lock = repo.lock()
6882 rev_ = "."
6886 rev_ = "."
6883 names = [t.strip() for t in (name1,) + names]
6887 names = [t.strip() for t in (name1,) + names]
6884 if len(names) != len(set(names)):
6888 if len(names) != len(set(names)):
6885 raise error.Abort(_('tag names must be unique'))
6889 raise error.Abort(_('tag names must be unique'))
6886 for n in names:
6890 for n in names:
6887 scmutil.checknewlabel(repo, n, 'tag')
6891 scmutil.checknewlabel(repo, n, 'tag')
6888 if not n:
6892 if not n:
6889 raise error.Abort(_('tag names cannot consist entirely of '
6893 raise error.Abort(_('tag names cannot consist entirely of '
6890 'whitespace'))
6894 'whitespace'))
6891 if opts.get('rev') and opts.get('remove'):
6895 if opts.get('rev') and opts.get('remove'):
6892 raise error.Abort(_("--rev and --remove are incompatible"))
6896 raise error.Abort(_("--rev and --remove are incompatible"))
6893 if opts.get('rev'):
6897 if opts.get('rev'):
6894 rev_ = opts['rev']
6898 rev_ = opts['rev']
6895 message = opts.get('message')
6899 message = opts.get('message')
6896 if opts.get('remove'):
6900 if opts.get('remove'):
6897 if opts.get('local'):
6901 if opts.get('local'):
6898 expectedtype = 'local'
6902 expectedtype = 'local'
6899 else:
6903 else:
6900 expectedtype = 'global'
6904 expectedtype = 'global'
6901
6905
6902 for n in names:
6906 for n in names:
6903 if not repo.tagtype(n):
6907 if not repo.tagtype(n):
6904 raise error.Abort(_("tag '%s' does not exist") % n)
6908 raise error.Abort(_("tag '%s' does not exist") % n)
6905 if repo.tagtype(n) != expectedtype:
6909 if repo.tagtype(n) != expectedtype:
6906 if expectedtype == 'global':
6910 if expectedtype == 'global':
6907 raise error.Abort(_("tag '%s' is not a global tag") % n)
6911 raise error.Abort(_("tag '%s' is not a global tag") % n)
6908 else:
6912 else:
6909 raise error.Abort(_("tag '%s' is not a local tag") % n)
6913 raise error.Abort(_("tag '%s' is not a local tag") % n)
6910 rev_ = 'null'
6914 rev_ = 'null'
6911 if not message:
6915 if not message:
6912 # we don't translate commit messages
6916 # we don't translate commit messages
6913 message = 'Removed tag %s' % ', '.join(names)
6917 message = 'Removed tag %s' % ', '.join(names)
6914 elif not opts.get('force'):
6918 elif not opts.get('force'):
6915 for n in names:
6919 for n in names:
6916 if n in repo.tags():
6920 if n in repo.tags():
6917 raise error.Abort(_("tag '%s' already exists "
6921 raise error.Abort(_("tag '%s' already exists "
6918 "(use -f to force)") % n)
6922 "(use -f to force)") % n)
6919 if not opts.get('local'):
6923 if not opts.get('local'):
6920 p1, p2 = repo.dirstate.parents()
6924 p1, p2 = repo.dirstate.parents()
6921 if p2 != nullid:
6925 if p2 != nullid:
6922 raise error.Abort(_('uncommitted merge'))
6926 raise error.Abort(_('uncommitted merge'))
6923 bheads = repo.branchheads()
6927 bheads = repo.branchheads()
6924 if not opts.get('force') and bheads and p1 not in bheads:
6928 if not opts.get('force') and bheads and p1 not in bheads:
6925 raise error.Abort(_('not at a branch head (use -f to force)'))
6929 raise error.Abort(_('not at a branch head (use -f to force)'))
6926 r = scmutil.revsingle(repo, rev_).node()
6930 r = scmutil.revsingle(repo, rev_).node()
6927
6931
6928 if not message:
6932 if not message:
6929 # we don't translate commit messages
6933 # we don't translate commit messages
6930 message = ('Added tag %s for changeset %s' %
6934 message = ('Added tag %s for changeset %s' %
6931 (', '.join(names), short(r)))
6935 (', '.join(names), short(r)))
6932
6936
6933 date = opts.get('date')
6937 date = opts.get('date')
6934 if date:
6938 if date:
6935 date = util.parsedate(date)
6939 date = util.parsedate(date)
6936
6940
6937 if opts.get('remove'):
6941 if opts.get('remove'):
6938 editform = 'tag.remove'
6942 editform = 'tag.remove'
6939 else:
6943 else:
6940 editform = 'tag.add'
6944 editform = 'tag.add'
6941 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6945 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6942
6946
6943 # don't allow tagging the null rev
6947 # don't allow tagging the null rev
6944 if (not opts.get('remove') and
6948 if (not opts.get('remove') and
6945 scmutil.revsingle(repo, rev_).rev() == nullrev):
6949 scmutil.revsingle(repo, rev_).rev() == nullrev):
6946 raise error.Abort(_("cannot tag null revision"))
6950 raise error.Abort(_("cannot tag null revision"))
6947
6951
6948 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6952 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6949 editor=editor)
6953 editor=editor)
6950 finally:
6954 finally:
6951 release(lock, wlock)
6955 release(lock, wlock)
6952
6956
6953 @command('tags', formatteropts, '')
6957 @command('tags', formatteropts, '')
6954 def tags(ui, repo, **opts):
6958 def tags(ui, repo, **opts):
6955 """list repository tags
6959 """list repository tags
6956
6960
6957 This lists both regular and local tags. When the -v/--verbose
6961 This lists both regular and local tags. When the -v/--verbose
6958 switch is used, a third column "local" is printed for local tags.
6962 switch is used, a third column "local" is printed for local tags.
6959 When the -q/--quiet switch is used, only the tag name is printed.
6963 When the -q/--quiet switch is used, only the tag name is printed.
6960
6964
6961 Returns 0 on success.
6965 Returns 0 on success.
6962 """
6966 """
6963
6967
6964 fm = ui.formatter('tags', opts)
6968 fm = ui.formatter('tags', opts)
6965 hexfunc = fm.hexfunc
6969 hexfunc = fm.hexfunc
6966 tagtype = ""
6970 tagtype = ""
6967
6971
6968 for t, n in reversed(repo.tagslist()):
6972 for t, n in reversed(repo.tagslist()):
6969 hn = hexfunc(n)
6973 hn = hexfunc(n)
6970 label = 'tags.normal'
6974 label = 'tags.normal'
6971 tagtype = ''
6975 tagtype = ''
6972 if repo.tagtype(t) == 'local':
6976 if repo.tagtype(t) == 'local':
6973 label = 'tags.local'
6977 label = 'tags.local'
6974 tagtype = 'local'
6978 tagtype = 'local'
6975
6979
6976 fm.startitem()
6980 fm.startitem()
6977 fm.write('tag', '%s', t, label=label)
6981 fm.write('tag', '%s', t, label=label)
6978 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6982 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6979 fm.condwrite(not ui.quiet, 'rev node', fmt,
6983 fm.condwrite(not ui.quiet, 'rev node', fmt,
6980 repo.changelog.rev(n), hn, label=label)
6984 repo.changelog.rev(n), hn, label=label)
6981 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6985 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6982 tagtype, label=label)
6986 tagtype, label=label)
6983 fm.plain('\n')
6987 fm.plain('\n')
6984 fm.end()
6988 fm.end()
6985
6989
6986 @command('tip',
6990 @command('tip',
6987 [('p', 'patch', None, _('show patch')),
6991 [('p', 'patch', None, _('show patch')),
6988 ('g', 'git', None, _('use git extended diff format')),
6992 ('g', 'git', None, _('use git extended diff format')),
6989 ] + templateopts,
6993 ] + templateopts,
6990 _('[-p] [-g]'))
6994 _('[-p] [-g]'))
6991 def tip(ui, repo, **opts):
6995 def tip(ui, repo, **opts):
6992 """show the tip revision (DEPRECATED)
6996 """show the tip revision (DEPRECATED)
6993
6997
6994 The tip revision (usually just called the tip) is the changeset
6998 The tip revision (usually just called the tip) is the changeset
6995 most recently added to the repository (and therefore the most
6999 most recently added to the repository (and therefore the most
6996 recently changed head).
7000 recently changed head).
6997
7001
6998 If you have just made a commit, that commit will be the tip. If
7002 If you have just made a commit, that commit will be the tip. If
6999 you have just pulled changes from another repository, the tip of
7003 you have just pulled changes from another repository, the tip of
7000 that repository becomes the current tip. The "tip" tag is special
7004 that repository becomes the current tip. The "tip" tag is special
7001 and cannot be renamed or assigned to a different changeset.
7005 and cannot be renamed or assigned to a different changeset.
7002
7006
7003 This command is deprecated, please use :hg:`heads` instead.
7007 This command is deprecated, please use :hg:`heads` instead.
7004
7008
7005 Returns 0 on success.
7009 Returns 0 on success.
7006 """
7010 """
7007 displayer = cmdutil.show_changeset(ui, repo, opts)
7011 displayer = cmdutil.show_changeset(ui, repo, opts)
7008 displayer.show(repo['tip'])
7012 displayer.show(repo['tip'])
7009 displayer.close()
7013 displayer.close()
7010
7014
7011 @command('unbundle',
7015 @command('unbundle',
7012 [('u', 'update', None,
7016 [('u', 'update', None,
7013 _('update to new branch head if changesets were unbundled'))],
7017 _('update to new branch head if changesets were unbundled'))],
7014 _('[-u] FILE...'))
7018 _('[-u] FILE...'))
7015 def unbundle(ui, repo, fname1, *fnames, **opts):
7019 def unbundle(ui, repo, fname1, *fnames, **opts):
7016 """apply one or more changegroup files
7020 """apply one or more changegroup files
7017
7021
7018 Apply one or more compressed changegroup files generated by the
7022 Apply one or more compressed changegroup files generated by the
7019 bundle command.
7023 bundle command.
7020
7024
7021 Returns 0 on success, 1 if an update has unresolved files.
7025 Returns 0 on success, 1 if an update has unresolved files.
7022 """
7026 """
7023 fnames = (fname1,) + fnames
7027 fnames = (fname1,) + fnames
7024
7028
7025 with repo.lock():
7029 with repo.lock():
7026 for fname in fnames:
7030 for fname in fnames:
7027 f = hg.openpath(ui, fname)
7031 f = hg.openpath(ui, fname)
7028 gen = exchange.readbundle(ui, f, fname)
7032 gen = exchange.readbundle(ui, f, fname)
7029 if isinstance(gen, bundle2.unbundle20):
7033 if isinstance(gen, bundle2.unbundle20):
7030 tr = repo.transaction('unbundle')
7034 tr = repo.transaction('unbundle')
7031 try:
7035 try:
7032 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7036 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
7033 url='bundle:' + fname)
7037 url='bundle:' + fname)
7034 tr.close()
7038 tr.close()
7035 except error.BundleUnknownFeatureError as exc:
7039 except error.BundleUnknownFeatureError as exc:
7036 raise error.Abort(_('%s: unknown bundle feature, %s')
7040 raise error.Abort(_('%s: unknown bundle feature, %s')
7037 % (fname, exc),
7041 % (fname, exc),
7038 hint=_("see https://mercurial-scm.org/"
7042 hint=_("see https://mercurial-scm.org/"
7039 "wiki/BundleFeature for more "
7043 "wiki/BundleFeature for more "
7040 "information"))
7044 "information"))
7041 finally:
7045 finally:
7042 if tr:
7046 if tr:
7043 tr.release()
7047 tr.release()
7044 changes = [r.get('return', 0)
7048 changes = [r.get('return', 0)
7045 for r in op.records['changegroup']]
7049 for r in op.records['changegroup']]
7046 modheads = changegroup.combineresults(changes)
7050 modheads = changegroup.combineresults(changes)
7047 elif isinstance(gen, streamclone.streamcloneapplier):
7051 elif isinstance(gen, streamclone.streamcloneapplier):
7048 raise error.Abort(
7052 raise error.Abort(
7049 _('packed bundles cannot be applied with '
7053 _('packed bundles cannot be applied with '
7050 '"hg unbundle"'),
7054 '"hg unbundle"'),
7051 hint=_('use "hg debugapplystreamclonebundle"'))
7055 hint=_('use "hg debugapplystreamclonebundle"'))
7052 else:
7056 else:
7053 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7057 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
7054
7058
7055 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7059 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7056
7060
7057 @command('^update|up|checkout|co',
7061 @command('^update|up|checkout|co',
7058 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7062 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
7059 ('c', 'check', None,
7063 ('c', 'check', None,
7060 _('update across branches if no uncommitted changes')),
7064 _('update across branches if no uncommitted changes')),
7061 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7065 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
7062 ('r', 'rev', '', _('revision'), _('REV'))
7066 ('r', 'rev', '', _('revision'), _('REV'))
7063 ] + mergetoolopts,
7067 ] + mergetoolopts,
7064 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7068 _('[-c] [-C] [-d DATE] [[-r] REV]'))
7065 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7069 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
7066 tool=None):
7070 tool=None):
7067 """update working directory (or switch revisions)
7071 """update working directory (or switch revisions)
7068
7072
7069 Update the repository's working directory to the specified
7073 Update the repository's working directory to the specified
7070 changeset. If no changeset is specified, update to the tip of the
7074 changeset. If no changeset is specified, update to the tip of the
7071 current named branch and move the active bookmark (see :hg:`help
7075 current named branch and move the active bookmark (see :hg:`help
7072 bookmarks`).
7076 bookmarks`).
7073
7077
7074 Update sets the working directory's parent revision to the specified
7078 Update sets the working directory's parent revision to the specified
7075 changeset (see :hg:`help parents`).
7079 changeset (see :hg:`help parents`).
7076
7080
7077 If the changeset is not a descendant or ancestor of the working
7081 If the changeset is not a descendant or ancestor of the working
7078 directory's parent, the update is aborted. With the -c/--check
7082 directory's parent, the update is aborted. With the -c/--check
7079 option, the working directory is checked for uncommitted changes; if
7083 option, the working directory is checked for uncommitted changes; if
7080 none are found, the working directory is updated to the specified
7084 none are found, the working directory is updated to the specified
7081 changeset.
7085 changeset.
7082
7086
7083 .. container:: verbose
7087 .. container:: verbose
7084
7088
7085 The following rules apply when the working directory contains
7089 The following rules apply when the working directory contains
7086 uncommitted changes:
7090 uncommitted changes:
7087
7091
7088 1. If neither -c/--check nor -C/--clean is specified, and if
7092 1. If neither -c/--check nor -C/--clean is specified, and if
7089 the requested changeset is an ancestor or descendant of
7093 the requested changeset is an ancestor or descendant of
7090 the working directory's parent, the uncommitted changes
7094 the working directory's parent, the uncommitted changes
7091 are merged into the requested changeset and the merged
7095 are merged into the requested changeset and the merged
7092 result is left uncommitted. If the requested changeset is
7096 result is left uncommitted. If the requested changeset is
7093 not an ancestor or descendant (that is, it is on another
7097 not an ancestor or descendant (that is, it is on another
7094 branch), the update is aborted and the uncommitted changes
7098 branch), the update is aborted and the uncommitted changes
7095 are preserved.
7099 are preserved.
7096
7100
7097 2. With the -c/--check option, the update is aborted and the
7101 2. With the -c/--check option, the update is aborted and the
7098 uncommitted changes are preserved.
7102 uncommitted changes are preserved.
7099
7103
7100 3. With the -C/--clean option, uncommitted changes are discarded and
7104 3. With the -C/--clean option, uncommitted changes are discarded and
7101 the working directory is updated to the requested changeset.
7105 the working directory is updated to the requested changeset.
7102
7106
7103 To cancel an uncommitted merge (and lose your changes), use
7107 To cancel an uncommitted merge (and lose your changes), use
7104 :hg:`update --clean .`.
7108 :hg:`update --clean .`.
7105
7109
7106 Use null as the changeset to remove the working directory (like
7110 Use null as the changeset to remove the working directory (like
7107 :hg:`clone -U`).
7111 :hg:`clone -U`).
7108
7112
7109 If you want to revert just one file to an older revision, use
7113 If you want to revert just one file to an older revision, use
7110 :hg:`revert [-r REV] NAME`.
7114 :hg:`revert [-r REV] NAME`.
7111
7115
7112 See :hg:`help dates` for a list of formats valid for -d/--date.
7116 See :hg:`help dates` for a list of formats valid for -d/--date.
7113
7117
7114 Returns 0 on success, 1 if there are unresolved files.
7118 Returns 0 on success, 1 if there are unresolved files.
7115 """
7119 """
7116 if rev and node:
7120 if rev and node:
7117 raise error.Abort(_("please specify just one revision"))
7121 raise error.Abort(_("please specify just one revision"))
7118
7122
7119 if rev is None or rev == '':
7123 if rev is None or rev == '':
7120 rev = node
7124 rev = node
7121
7125
7122 if date and rev is not None:
7126 if date and rev is not None:
7123 raise error.Abort(_("you can't specify a revision and a date"))
7127 raise error.Abort(_("you can't specify a revision and a date"))
7124
7128
7125 if check and clean:
7129 if check and clean:
7126 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7130 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
7127
7131
7128 with repo.wlock():
7132 with repo.wlock():
7129 cmdutil.clearunfinished(repo)
7133 cmdutil.clearunfinished(repo)
7130
7134
7131 if date:
7135 if date:
7132 rev = cmdutil.finddate(ui, repo, date)
7136 rev = cmdutil.finddate(ui, repo, date)
7133
7137
7134 # if we defined a bookmark, we have to remember the original name
7138 # if we defined a bookmark, we have to remember the original name
7135 brev = rev
7139 brev = rev
7136 rev = scmutil.revsingle(repo, rev, rev).rev()
7140 rev = scmutil.revsingle(repo, rev, rev).rev()
7137
7141
7138 if check:
7142 if check:
7139 cmdutil.bailifchanged(repo, merge=False)
7143 cmdutil.bailifchanged(repo, merge=False)
7140
7144
7141 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7145 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
7142
7146
7143 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7147 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
7144
7148
7145 @command('verify', [])
7149 @command('verify', [])
7146 def verify(ui, repo):
7150 def verify(ui, repo):
7147 """verify the integrity of the repository
7151 """verify the integrity of the repository
7148
7152
7149 Verify the integrity of the current repository.
7153 Verify the integrity of the current repository.
7150
7154
7151 This will perform an extensive check of the repository's
7155 This will perform an extensive check of the repository's
7152 integrity, validating the hashes and checksums of each entry in
7156 integrity, validating the hashes and checksums of each entry in
7153 the changelog, manifest, and tracked files, as well as the
7157 the changelog, manifest, and tracked files, as well as the
7154 integrity of their crosslinks and indices.
7158 integrity of their crosslinks and indices.
7155
7159
7156 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7160 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7157 for more information about recovery from corruption of the
7161 for more information about recovery from corruption of the
7158 repository.
7162 repository.
7159
7163
7160 Returns 0 on success, 1 if errors are encountered.
7164 Returns 0 on success, 1 if errors are encountered.
7161 """
7165 """
7162 return hg.verify(repo)
7166 return hg.verify(repo)
7163
7167
7164 @command('version', [], norepo=True)
7168 @command('version', [], norepo=True)
7165 def version_(ui):
7169 def version_(ui):
7166 """output version and copyright information"""
7170 """output version and copyright information"""
7167 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7171 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7168 % util.version())
7172 % util.version())
7169 ui.status(_(
7173 ui.status(_(
7170 "(see https://mercurial-scm.org for more information)\n"
7174 "(see https://mercurial-scm.org for more information)\n"
7171 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7175 "\nCopyright (C) 2005-2016 Matt Mackall and others\n"
7172 "This is free software; see the source for copying conditions. "
7176 "This is free software; see the source for copying conditions. "
7173 "There is NO\nwarranty; "
7177 "There is NO\nwarranty; "
7174 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7178 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7175 ))
7179 ))
7176
7180
7177 ui.note(_("\nEnabled extensions:\n\n"))
7181 ui.note(_("\nEnabled extensions:\n\n"))
7178 if ui.verbose:
7182 if ui.verbose:
7179 # format names and versions into columns
7183 # format names and versions into columns
7180 names = []
7184 names = []
7181 vers = []
7185 vers = []
7182 place = []
7186 place = []
7183 for name, module in extensions.extensions():
7187 for name, module in extensions.extensions():
7184 names.append(name)
7188 names.append(name)
7185 vers.append(extensions.moduleversion(module))
7189 vers.append(extensions.moduleversion(module))
7186 if extensions.ismoduleinternal(module):
7190 if extensions.ismoduleinternal(module):
7187 place.append(_("internal"))
7191 place.append(_("internal"))
7188 else:
7192 else:
7189 place.append(_("external"))
7193 place.append(_("external"))
7190 if names:
7194 if names:
7191 maxnamelen = max(len(n) for n in names)
7195 maxnamelen = max(len(n) for n in names)
7192 for i, name in enumerate(names):
7196 for i, name in enumerate(names):
7193 ui.write(" %-*s %s %s\n" %
7197 ui.write(" %-*s %s %s\n" %
7194 (maxnamelen, name, place[i], vers[i]))
7198 (maxnamelen, name, place[i], vers[i]))
7195
7199
7196 def loadcmdtable(ui, name, cmdtable):
7200 def loadcmdtable(ui, name, cmdtable):
7197 """Load command functions from specified cmdtable
7201 """Load command functions from specified cmdtable
7198 """
7202 """
7199 overrides = [cmd for cmd in cmdtable if cmd in table]
7203 overrides = [cmd for cmd in cmdtable if cmd in table]
7200 if overrides:
7204 if overrides:
7201 ui.warn(_("extension '%s' overrides commands: %s\n")
7205 ui.warn(_("extension '%s' overrides commands: %s\n")
7202 % (name, " ".join(overrides)))
7206 % (name, " ".join(overrides)))
7203 table.update(cmdtable)
7207 table.update(cmdtable)
@@ -1,738 +1,744 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
4 > [format]
4 > [format]
5 > usegeneraldelta=yes
5 > usegeneraldelta=yes
6 > [ui]
6 > [ui]
7 > ssh=python "$TESTDIR/dummyssh"
7 > ssh=python "$TESTDIR/dummyssh"
8 > EOF
8 > EOF
9
9
10 Set up repo
10 Set up repo
11
11
12 $ hg --config experimental.treemanifest=True init repo
12 $ hg --config experimental.treemanifest=True init repo
13 $ cd repo
13 $ cd repo
14
14
15 Requirements get set on init
15 Requirements get set on init
16
16
17 $ grep treemanifest .hg/requires
17 $ grep treemanifest .hg/requires
18 treemanifest
18 treemanifest
19
19
20 Without directories, looks like any other repo
20 Without directories, looks like any other repo
21
21
22 $ echo 0 > a
22 $ echo 0 > a
23 $ echo 0 > b
23 $ echo 0 > b
24 $ hg ci -Aqm initial
24 $ hg ci -Aqm initial
25 $ hg debugdata -m 0
25 $ hg debugdata -m 0
26 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
26 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
27 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
27 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
28
28
29 Submanifest is stored in separate revlog
29 Submanifest is stored in separate revlog
30
30
31 $ mkdir dir1
31 $ mkdir dir1
32 $ echo 1 > dir1/a
32 $ echo 1 > dir1/a
33 $ echo 1 > dir1/b
33 $ echo 1 > dir1/b
34 $ echo 1 > e
34 $ echo 1 > e
35 $ hg ci -Aqm 'add dir1'
35 $ hg ci -Aqm 'add dir1'
36 $ hg debugdata -m 1
36 $ hg debugdata -m 1
37 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
37 a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
38 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
38 b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
39 dir1\x008b3ffd73f901e83304c83d33132c8e774ceac44et (esc)
39 dir1\x008b3ffd73f901e83304c83d33132c8e774ceac44et (esc)
40 e\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
40 e\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
41 $ hg debugdata --dir dir1 0
41 $ hg debugdata --dir dir1 0
42 a\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
42 a\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
43 b\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
43 b\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
44
44
45 Can add nested directories
45 Can add nested directories
46
46
47 $ mkdir dir1/dir1
47 $ mkdir dir1/dir1
48 $ echo 2 > dir1/dir1/a
48 $ echo 2 > dir1/dir1/a
49 $ echo 2 > dir1/dir1/b
49 $ echo 2 > dir1/dir1/b
50 $ mkdir dir1/dir2
50 $ mkdir dir1/dir2
51 $ echo 2 > dir1/dir2/a
51 $ echo 2 > dir1/dir2/a
52 $ echo 2 > dir1/dir2/b
52 $ echo 2 > dir1/dir2/b
53 $ hg ci -Aqm 'add dir1/dir1'
53 $ hg ci -Aqm 'add dir1/dir1'
54 $ hg files -r .
54 $ hg files -r .
55 a
55 a
56 b
56 b
57 dir1/a (glob)
57 dir1/a (glob)
58 dir1/b (glob)
58 dir1/b (glob)
59 dir1/dir1/a (glob)
59 dir1/dir1/a (glob)
60 dir1/dir1/b (glob)
60 dir1/dir1/b (glob)
61 dir1/dir2/a (glob)
61 dir1/dir2/a (glob)
62 dir1/dir2/b (glob)
62 dir1/dir2/b (glob)
63 e
63 e
64
64
65 Revision is not created for unchanged directory
65 Revision is not created for unchanged directory
66
66
67 $ mkdir dir2
67 $ mkdir dir2
68 $ echo 3 > dir2/a
68 $ echo 3 > dir2/a
69 $ hg add dir2
69 $ hg add dir2
70 adding dir2/a (glob)
70 adding dir2/a (glob)
71 $ hg debugindex --dir dir1 > before
71 $ hg debugindex --dir dir1 > before
72 $ hg ci -qm 'add dir2'
72 $ hg ci -qm 'add dir2'
73 $ hg debugindex --dir dir1 > after
73 $ hg debugindex --dir dir1 > after
74 $ diff before after
74 $ diff before after
75 $ rm before after
75 $ rm before after
76
76
77 Removing directory does not create an revlog entry
77 Removing directory does not create an revlog entry
78
78
79 $ hg rm dir1/dir1
79 $ hg rm dir1/dir1
80 removing dir1/dir1/a (glob)
80 removing dir1/dir1/a (glob)
81 removing dir1/dir1/b (glob)
81 removing dir1/dir1/b (glob)
82 $ hg debugindex --dir dir1/dir1 > before
82 $ hg debugindex --dir dir1/dir1 > before
83 $ hg ci -qm 'remove dir1/dir1'
83 $ hg ci -qm 'remove dir1/dir1'
84 $ hg debugindex --dir dir1/dir1 > after
84 $ hg debugindex --dir dir1/dir1 > after
85 $ diff before after
85 $ diff before after
86 $ rm before after
86 $ rm before after
87
87
88 Check that hg files (calls treemanifest.walk()) works
88 Check that hg files (calls treemanifest.walk()) works
89 without loading all directory revlogs
89 without loading all directory revlogs
90
90
91 $ hg co 'desc("add dir2")'
91 $ hg co 'desc("add dir2")'
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup
93 $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup
94 $ hg files -r . dir1
94 $ hg files -r . dir1
95 dir1/a (glob)
95 dir1/a (glob)
96 dir1/b (glob)
96 dir1/b (glob)
97 dir1/dir1/a (glob)
97 dir1/dir1/a (glob)
98 dir1/dir1/b (glob)
98 dir1/dir1/b (glob)
99 dir1/dir2/a (glob)
99 dir1/dir2/a (glob)
100 dir1/dir2/b (glob)
100 dir1/dir2/b (glob)
101
101
102 Check that status between revisions works (calls treemanifest.matches())
102 Check that status between revisions works (calls treemanifest.matches())
103 without loading all directory revlogs
103 without loading all directory revlogs
104
104
105 $ hg status --rev 'desc("add dir1")' --rev . dir1
105 $ hg status --rev 'desc("add dir1")' --rev . dir1
106 A dir1/dir1/a
106 A dir1/dir1/a
107 A dir1/dir1/b
107 A dir1/dir1/b
108 A dir1/dir2/a
108 A dir1/dir2/a
109 A dir1/dir2/b
109 A dir1/dir2/b
110 $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2
110 $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2
111
111
112 Merge creates 2-parent revision of directory revlog
112 Merge creates 2-parent revision of directory revlog
113
113
114 $ echo 5 > dir1/a
114 $ echo 5 > dir1/a
115 $ hg ci -Aqm 'modify dir1/a'
115 $ hg ci -Aqm 'modify dir1/a'
116 $ hg co '.^'
116 $ hg co '.^'
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 $ echo 6 > dir1/b
118 $ echo 6 > dir1/b
119 $ hg ci -Aqm 'modify dir1/b'
119 $ hg ci -Aqm 'modify dir1/b'
120 $ hg merge 'desc("modify dir1/a")'
120 $ hg merge 'desc("modify dir1/a")'
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 (branch merge, don't forget to commit)
122 (branch merge, don't forget to commit)
123 $ hg ci -m 'conflict-free merge involving dir1/'
123 $ hg ci -m 'conflict-free merge involving dir1/'
124 $ cat dir1/a
124 $ cat dir1/a
125 5
125 5
126 $ cat dir1/b
126 $ cat dir1/b
127 6
127 6
128 $ hg debugindex --dir dir1
128 $ hg debugindex --dir dir1
129 rev offset length delta linkrev nodeid p1 p2
129 rev offset length delta linkrev nodeid p1 p2
130 0 0 54 -1 1 8b3ffd73f901 000000000000 000000000000
130 0 0 54 -1 1 8b3ffd73f901 000000000000 000000000000
131 1 54 68 0 2 68e9d057c5a8 8b3ffd73f901 000000000000
131 1 54 68 0 2 68e9d057c5a8 8b3ffd73f901 000000000000
132 2 122 12 1 4 4698198d2624 68e9d057c5a8 000000000000
132 2 122 12 1 4 4698198d2624 68e9d057c5a8 000000000000
133 3 134 55 1 5 44844058ccce 68e9d057c5a8 000000000000
133 3 134 55 1 5 44844058ccce 68e9d057c5a8 000000000000
134 4 189 55 1 6 bf3d9b744927 68e9d057c5a8 000000000000
134 4 189 55 1 6 bf3d9b744927 68e9d057c5a8 000000000000
135 5 244 55 4 7 dde7c0af2a03 bf3d9b744927 44844058ccce
135 5 244 55 4 7 dde7c0af2a03 bf3d9b744927 44844058ccce
136
136
137 Merge keeping directory from parent 1 does not create revlog entry. (Note that
137 Merge keeping directory from parent 1 does not create revlog entry. (Note that
138 dir1's manifest does change, but only because dir1/a's filelog changes.)
138 dir1's manifest does change, but only because dir1/a's filelog changes.)
139
139
140 $ hg co 'desc("add dir2")'
140 $ hg co 'desc("add dir2")'
141 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 $ echo 8 > dir2/a
142 $ echo 8 > dir2/a
143 $ hg ci -m 'modify dir2/a'
143 $ hg ci -m 'modify dir2/a'
144 created new head
144 created new head
145
145
146 $ hg debugindex --dir dir2 > before
146 $ hg debugindex --dir dir2 > before
147 $ hg merge 'desc("modify dir1/a")'
147 $ hg merge 'desc("modify dir1/a")'
148 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 (branch merge, don't forget to commit)
149 (branch merge, don't forget to commit)
150 $ hg revert -r 'desc("modify dir2/a")' .
150 $ hg revert -r 'desc("modify dir2/a")' .
151 reverting dir1/a (glob)
151 reverting dir1/a (glob)
152 $ hg ci -m 'merge, keeping parent 1'
152 $ hg ci -m 'merge, keeping parent 1'
153 $ hg debugindex --dir dir2 > after
153 $ hg debugindex --dir dir2 > after
154 $ diff before after
154 $ diff before after
155 $ rm before after
155 $ rm before after
156
156
157 Merge keeping directory from parent 2 does not create revlog entry. (Note that
157 Merge keeping directory from parent 2 does not create revlog entry. (Note that
158 dir2's manifest does change, but only because dir2/a's filelog changes.)
158 dir2's manifest does change, but only because dir2/a's filelog changes.)
159
159
160 $ hg co 'desc("modify dir2/a")'
160 $ hg co 'desc("modify dir2/a")'
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 $ hg debugindex --dir dir1 > before
162 $ hg debugindex --dir dir1 > before
163 $ hg merge 'desc("modify dir1/a")'
163 $ hg merge 'desc("modify dir1/a")'
164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
164 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
165 (branch merge, don't forget to commit)
165 (branch merge, don't forget to commit)
166 $ hg revert -r 'desc("modify dir1/a")' .
166 $ hg revert -r 'desc("modify dir1/a")' .
167 reverting dir2/a (glob)
167 reverting dir2/a (glob)
168 $ hg ci -m 'merge, keeping parent 2'
168 $ hg ci -m 'merge, keeping parent 2'
169 created new head
169 created new head
170 $ hg debugindex --dir dir1 > after
170 $ hg debugindex --dir dir1 > after
171 $ diff before after
171 $ diff before after
172 $ rm before after
172 $ rm before after
173
173
174 Create flat source repo for tests with mixed flat/tree manifests
174 Create flat source repo for tests with mixed flat/tree manifests
175
175
176 $ cd ..
176 $ cd ..
177 $ hg init repo-flat
177 $ hg init repo-flat
178 $ cd repo-flat
178 $ cd repo-flat
179
179
180 Create a few commits with flat manifest
180 Create a few commits with flat manifest
181
181
182 $ echo 0 > a
182 $ echo 0 > a
183 $ echo 0 > b
183 $ echo 0 > b
184 $ echo 0 > e
184 $ echo 0 > e
185 $ for d in dir1 dir1/dir1 dir1/dir2 dir2
185 $ for d in dir1 dir1/dir1 dir1/dir2 dir2
186 > do
186 > do
187 > mkdir $d
187 > mkdir $d
188 > echo 0 > $d/a
188 > echo 0 > $d/a
189 > echo 0 > $d/b
189 > echo 0 > $d/b
190 > done
190 > done
191 $ hg ci -Aqm initial
191 $ hg ci -Aqm initial
192
192
193 $ echo 1 > a
193 $ echo 1 > a
194 $ echo 1 > dir1/a
194 $ echo 1 > dir1/a
195 $ echo 1 > dir1/dir1/a
195 $ echo 1 > dir1/dir1/a
196 $ hg ci -Aqm 'modify on branch 1'
196 $ hg ci -Aqm 'modify on branch 1'
197
197
198 $ hg co 0
198 $ hg co 0
199 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
199 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 $ echo 2 > b
200 $ echo 2 > b
201 $ echo 2 > dir1/b
201 $ echo 2 > dir1/b
202 $ echo 2 > dir1/dir1/b
202 $ echo 2 > dir1/dir1/b
203 $ hg ci -Aqm 'modify on branch 2'
203 $ hg ci -Aqm 'modify on branch 2'
204
204
205 $ hg merge 1
205 $ hg merge 1
206 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
206 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
207 (branch merge, don't forget to commit)
207 (branch merge, don't forget to commit)
208 $ hg ci -m 'merge of flat manifests to new flat manifest'
208 $ hg ci -m 'merge of flat manifests to new flat manifest'
209
209
210 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
210 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
211 $ cat hg.pid >> $DAEMON_PIDS
211 $ cat hg.pid >> $DAEMON_PIDS
212
212
213 Create clone with tree manifests enabled
213 Create clone with tree manifests enabled
214
214
215 $ cd ..
215 $ cd ..
216 $ hg clone --config experimental.treemanifest=1 \
216 $ hg clone --config experimental.treemanifest=1 \
217 > http://localhost:$HGPORT repo-mixed -r 1
217 > http://localhost:$HGPORT repo-mixed -r 1
218 adding changesets
218 adding changesets
219 adding manifests
219 adding manifests
220 adding file changes
220 adding file changes
221 added 2 changesets with 14 changes to 11 files
221 added 2 changesets with 14 changes to 11 files
222 updating to branch default
222 updating to branch default
223 11 files updated, 0 files merged, 0 files removed, 0 files unresolved
223 11 files updated, 0 files merged, 0 files removed, 0 files unresolved
224 $ cd repo-mixed
224 $ cd repo-mixed
225 $ test -d .hg/store/meta
225 $ test -d .hg/store/meta
226 [1]
226 [1]
227 $ grep treemanifest .hg/requires
227 $ grep treemanifest .hg/requires
228 treemanifest
228 treemanifest
229
229
230 Should be possible to push updates from flat to tree manifest repo
230 Should be possible to push updates from flat to tree manifest repo
231
231
232 $ hg -R ../repo-flat push ssh://user@dummy/repo-mixed
232 $ hg -R ../repo-flat push ssh://user@dummy/repo-mixed
233 pushing to ssh://user@dummy/repo-mixed
233 pushing to ssh://user@dummy/repo-mixed
234 searching for changes
234 searching for changes
235 remote: adding changesets
235 remote: adding changesets
236 remote: adding manifests
236 remote: adding manifests
237 remote: adding file changes
237 remote: adding file changes
238 remote: added 2 changesets with 3 changes to 3 files
238 remote: added 2 changesets with 3 changes to 3 files
239
239
240 Commit should store revlog per directory
240 Commit should store revlog per directory
241
241
242 $ hg co 1
242 $ hg co 1
243 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
243 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
244 $ echo 3 > a
244 $ echo 3 > a
245 $ echo 3 > dir1/a
245 $ echo 3 > dir1/a
246 $ echo 3 > dir1/dir1/a
246 $ echo 3 > dir1/dir1/a
247 $ hg ci -m 'first tree'
247 $ hg ci -m 'first tree'
248 created new head
248 created new head
249 $ find .hg/store/meta | sort
249 $ find .hg/store/meta | sort
250 .hg/store/meta
250 .hg/store/meta
251 .hg/store/meta/dir1
251 .hg/store/meta/dir1
252 .hg/store/meta/dir1/00manifest.i
252 .hg/store/meta/dir1/00manifest.i
253 .hg/store/meta/dir1/dir1
253 .hg/store/meta/dir1/dir1
254 .hg/store/meta/dir1/dir1/00manifest.i
254 .hg/store/meta/dir1/dir1/00manifest.i
255 .hg/store/meta/dir1/dir2
255 .hg/store/meta/dir1/dir2
256 .hg/store/meta/dir1/dir2/00manifest.i
256 .hg/store/meta/dir1/dir2/00manifest.i
257 .hg/store/meta/dir2
257 .hg/store/meta/dir2
258 .hg/store/meta/dir2/00manifest.i
258 .hg/store/meta/dir2/00manifest.i
259
259
260 Merge of two trees
260 Merge of two trees
261
261
262 $ hg co 2
262 $ hg co 2
263 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 $ hg merge 1
264 $ hg merge 1
265 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
266 (branch merge, don't forget to commit)
266 (branch merge, don't forget to commit)
267 $ hg ci -m 'merge of flat manifests to new tree manifest'
267 $ hg ci -m 'merge of flat manifests to new tree manifest'
268 created new head
268 created new head
269 $ hg diff -r 3
269 $ hg diff -r 3
270
270
271 Parent of tree root manifest should be flat manifest, and two for merge
271 Parent of tree root manifest should be flat manifest, and two for merge
272
272
273 $ hg debugindex -m
273 $ hg debugindex -m
274 rev offset length delta linkrev nodeid p1 p2
274 rev offset length delta linkrev nodeid p1 p2
275 0 0 80 -1 0 40536115ed9e 000000000000 000000000000
275 0 0 80 -1 0 40536115ed9e 000000000000 000000000000
276 1 80 83 0 1 f3376063c255 40536115ed9e 000000000000
276 1 80 83 0 1 f3376063c255 40536115ed9e 000000000000
277 2 163 89 0 2 5d9b9da231a2 40536115ed9e 000000000000
277 2 163 89 0 2 5d9b9da231a2 40536115ed9e 000000000000
278 3 252 83 2 3 d17d663cbd8a 5d9b9da231a2 f3376063c255
278 3 252 83 2 3 d17d663cbd8a 5d9b9da231a2 f3376063c255
279 4 335 124 1 4 51e32a8c60ee f3376063c255 000000000000
279 4 335 124 1 4 51e32a8c60ee f3376063c255 000000000000
280 5 459 126 2 5 cc5baa78b230 5d9b9da231a2 f3376063c255
280 5 459 126 2 5 cc5baa78b230 5d9b9da231a2 f3376063c255
281
281
282
282
283 Status across flat/tree boundary should work
283 Status across flat/tree boundary should work
284
284
285 $ hg status --rev '.^' --rev .
285 $ hg status --rev '.^' --rev .
286 M a
286 M a
287 M dir1/a
287 M dir1/a
288 M dir1/dir1/a
288 M dir1/dir1/a
289
289
290
290
291 Turning off treemanifest config has no effect
291 Turning off treemanifest config has no effect
292
292
293 $ hg debugindex --dir dir1
293 $ hg debugindex --dir dir1
294 rev offset length delta linkrev nodeid p1 p2
294 rev offset length delta linkrev nodeid p1 p2
295 0 0 127 -1 4 064927a0648a 000000000000 000000000000
295 0 0 127 -1 4 064927a0648a 000000000000 000000000000
296 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
296 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
297 $ echo 2 > dir1/a
297 $ echo 2 > dir1/a
298 $ hg --config experimental.treemanifest=False ci -qm 'modify dir1/a'
298 $ hg --config experimental.treemanifest=False ci -qm 'modify dir1/a'
299 $ hg debugindex --dir dir1
299 $ hg debugindex --dir dir1
300 rev offset length delta linkrev nodeid p1 p2
300 rev offset length delta linkrev nodeid p1 p2
301 0 0 127 -1 4 064927a0648a 000000000000 000000000000
301 0 0 127 -1 4 064927a0648a 000000000000 000000000000
302 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
302 1 127 111 0 5 25ecb8cb8618 000000000000 000000000000
303 2 238 55 1 6 5b16163a30c6 25ecb8cb8618 000000000000
303 2 238 55 1 6 5b16163a30c6 25ecb8cb8618 000000000000
304
304
305 Stripping and recovering changes should work
305 Stripping and recovering changes should work
306
306
307 $ hg st --change tip
307 $ hg st --change tip
308 M dir1/a
308 M dir1/a
309 $ hg --config extensions.strip= strip tip
309 $ hg --config extensions.strip= strip tip
310 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
310 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
311 saved backup bundle to $TESTTMP/repo-mixed/.hg/strip-backup/51cfd7b1e13b-78a2f3ed-backup.hg (glob)
311 saved backup bundle to $TESTTMP/repo-mixed/.hg/strip-backup/51cfd7b1e13b-78a2f3ed-backup.hg (glob)
312 $ hg unbundle -q .hg/strip-backup/*
312 $ hg unbundle -q .hg/strip-backup/*
313 $ hg st --change tip
313 $ hg st --change tip
314 M dir1/a
314 M dir1/a
315
315
316 Shelving and unshelving should work
316 Shelving and unshelving should work
317
317
318 $ echo foo >> dir1/a
318 $ echo foo >> dir1/a
319 $ hg --config extensions.shelve= shelve
319 $ hg --config extensions.shelve= shelve
320 shelved as default
320 shelved as default
321 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 $ hg --config extensions.shelve= unshelve
322 $ hg --config extensions.shelve= unshelve
323 unshelving change 'default'
323 unshelving change 'default'
324 $ hg diff --nodates
324 $ hg diff --nodates
325 diff -r 708a273da119 dir1/a
325 diff -r 708a273da119 dir1/a
326 --- a/dir1/a
326 --- a/dir1/a
327 +++ b/dir1/a
327 +++ b/dir1/a
328 @@ -1,1 +1,2 @@
328 @@ -1,1 +1,2 @@
329 1
329 1
330 +foo
330 +foo
331
331
332 Pushing from treemanifest repo to an empty repo makes that a treemanifest repo
332 Pushing from treemanifest repo to an empty repo makes that a treemanifest repo
333
333
334 $ cd ..
334 $ cd ..
335 $ hg init empty-repo
335 $ hg init empty-repo
336 $ cat << EOF >> empty-repo/.hg/hgrc
336 $ cat << EOF >> empty-repo/.hg/hgrc
337 > [experimental]
337 > [experimental]
338 > changegroup3=yes
338 > changegroup3=yes
339 > EOF
339 > EOF
340 $ grep treemanifest empty-repo/.hg/requires
340 $ grep treemanifest empty-repo/.hg/requires
341 [1]
341 [1]
342 $ hg push -R repo -r 0 empty-repo
342 $ hg push -R repo -r 0 empty-repo
343 pushing to empty-repo
343 pushing to empty-repo
344 searching for changes
344 searching for changes
345 adding changesets
345 adding changesets
346 adding manifests
346 adding manifests
347 adding file changes
347 adding file changes
348 added 1 changesets with 2 changes to 2 files
348 added 1 changesets with 2 changes to 2 files
349 $ grep treemanifest empty-repo/.hg/requires
349 $ grep treemanifest empty-repo/.hg/requires
350 treemanifest
350 treemanifest
351
351
352 Pushing to an empty repo works
352 Pushing to an empty repo works
353
353
354 $ hg --config experimental.treemanifest=1 init clone
354 $ hg --config experimental.treemanifest=1 init clone
355 $ grep treemanifest clone/.hg/requires
355 $ grep treemanifest clone/.hg/requires
356 treemanifest
356 treemanifest
357 $ hg push -R repo clone
357 $ hg push -R repo clone
358 pushing to clone
358 pushing to clone
359 searching for changes
359 searching for changes
360 adding changesets
360 adding changesets
361 adding manifests
361 adding manifests
362 adding file changes
362 adding file changes
363 added 11 changesets with 15 changes to 10 files (+3 heads)
363 added 11 changesets with 15 changes to 10 files (+3 heads)
364 $ grep treemanifest clone/.hg/requires
364 $ grep treemanifest clone/.hg/requires
365 treemanifest
365 treemanifest
366 $ hg -R clone verify
366 $ hg -R clone verify
367 checking changesets
367 checking changesets
368 checking manifests
368 checking manifests
369 checking directory manifests
369 checking directory manifests
370 crosschecking files in changesets and manifests
370 crosschecking files in changesets and manifests
371 checking files
371 checking files
372 10 files, 11 changesets, 15 total revisions
372 10 files, 11 changesets, 15 total revisions
373
373
374 Create deeper repo with tree manifests.
374 Create deeper repo with tree manifests.
375
375
376 $ hg --config experimental.treemanifest=True init deeprepo
376 $ hg --config experimental.treemanifest=True init deeprepo
377 $ cd deeprepo
377 $ cd deeprepo
378
378
379 $ mkdir .A
379 $ mkdir .A
380 $ mkdir b
380 $ mkdir b
381 $ mkdir b/bar
381 $ mkdir b/bar
382 $ mkdir b/bar/orange
382 $ mkdir b/bar/orange
383 $ mkdir b/bar/orange/fly
383 $ mkdir b/bar/orange/fly
384 $ mkdir b/foo
384 $ mkdir b/foo
385 $ mkdir b/foo/apple
385 $ mkdir b/foo/apple
386 $ mkdir b/foo/apple/bees
386 $ mkdir b/foo/apple/bees
387
387
388 $ touch .A/one.txt
388 $ touch .A/one.txt
389 $ touch .A/two.txt
389 $ touch .A/two.txt
390 $ touch b/bar/fruits.txt
390 $ touch b/bar/fruits.txt
391 $ touch b/bar/orange/fly/gnat.py
391 $ touch b/bar/orange/fly/gnat.py
392 $ touch b/bar/orange/fly/housefly.txt
392 $ touch b/bar/orange/fly/housefly.txt
393 $ touch b/foo/apple/bees/flower.py
393 $ touch b/foo/apple/bees/flower.py
394 $ touch c.txt
394 $ touch c.txt
395 $ touch d.py
395 $ touch d.py
396
396
397 $ hg ci -Aqm 'initial'
397 $ hg ci -Aqm 'initial'
398
398
399 We'll see that visitdir works by removing some treemanifest revlogs and running
399 We'll see that visitdir works by removing some treemanifest revlogs and running
400 the files command with various parameters.
400 the files command with various parameters.
401
401
402 Test files from the root.
402 Test files from the root.
403
403
404 $ hg files -r .
404 $ hg files -r .
405 .A/one.txt (glob)
405 .A/one.txt (glob)
406 .A/two.txt (glob)
406 .A/two.txt (glob)
407 b/bar/fruits.txt (glob)
407 b/bar/fruits.txt (glob)
408 b/bar/orange/fly/gnat.py (glob)
408 b/bar/orange/fly/gnat.py (glob)
409 b/bar/orange/fly/housefly.txt (glob)
409 b/bar/orange/fly/housefly.txt (glob)
410 b/foo/apple/bees/flower.py (glob)
410 b/foo/apple/bees/flower.py (glob)
411 c.txt
411 c.txt
412 d.py
412 d.py
413
413
414 Excludes with a glob should not exclude everything from the glob's root
414 Excludes with a glob should not exclude everything from the glob's root
415
415
416 $ hg files -r . -X 'b/fo?' b
416 $ hg files -r . -X 'b/fo?' b
417 b/bar/fruits.txt (glob)
417 b/bar/fruits.txt (glob)
418 b/bar/orange/fly/gnat.py (glob)
418 b/bar/orange/fly/gnat.py (glob)
419 b/bar/orange/fly/housefly.txt (glob)
419 b/bar/orange/fly/housefly.txt (glob)
420 $ cp -r .hg/store .hg/store-copy
420 $ cp -r .hg/store .hg/store-copy
421
421
422 Test files for a subdirectory.
422 Test files for a subdirectory.
423
423
424 $ rm -r .hg/store/meta/~2e_a
424 $ rm -r .hg/store/meta/~2e_a
425 $ hg files -r . b
425 $ hg files -r . b
426 b/bar/fruits.txt (glob)
426 b/bar/fruits.txt (glob)
427 b/bar/orange/fly/gnat.py (glob)
427 b/bar/orange/fly/gnat.py (glob)
428 b/bar/orange/fly/housefly.txt (glob)
428 b/bar/orange/fly/housefly.txt (glob)
429 b/foo/apple/bees/flower.py (glob)
429 b/foo/apple/bees/flower.py (glob)
430 $ cp -r .hg/store-copy/. .hg/store
430 $ cp -r .hg/store-copy/. .hg/store
431
431
432 Test files with just includes and excludes.
432 Test files with just includes and excludes.
433
433
434 $ rm -r .hg/store/meta/~2e_a
434 $ rm -r .hg/store/meta/~2e_a
435 $ rm -r .hg/store/meta/b/bar/orange/fly
435 $ rm -r .hg/store/meta/b/bar/orange/fly
436 $ rm -r .hg/store/meta/b/foo/apple/bees
436 $ rm -r .hg/store/meta/b/foo/apple/bees
437 $ hg files -r . -I path:b/bar -X path:b/bar/orange/fly -I path:b/foo -X path:b/foo/apple/bees
437 $ hg files -r . -I path:b/bar -X path:b/bar/orange/fly -I path:b/foo -X path:b/foo/apple/bees
438 b/bar/fruits.txt (glob)
438 b/bar/fruits.txt (glob)
439 $ cp -r .hg/store-copy/. .hg/store
439 $ cp -r .hg/store-copy/. .hg/store
440
440
441 Test files for a subdirectory, excluding a directory within it.
441 Test files for a subdirectory, excluding a directory within it.
442
442
443 $ rm -r .hg/store/meta/~2e_a
443 $ rm -r .hg/store/meta/~2e_a
444 $ rm -r .hg/store/meta/b/foo
444 $ rm -r .hg/store/meta/b/foo
445 $ hg files -r . -X path:b/foo b
445 $ hg files -r . -X path:b/foo b
446 b/bar/fruits.txt (glob)
446 b/bar/fruits.txt (glob)
447 b/bar/orange/fly/gnat.py (glob)
447 b/bar/orange/fly/gnat.py (glob)
448 b/bar/orange/fly/housefly.txt (glob)
448 b/bar/orange/fly/housefly.txt (glob)
449 $ cp -r .hg/store-copy/. .hg/store
449 $ cp -r .hg/store-copy/. .hg/store
450
450
451 Test files for a sub directory, including only a directory within it, and
451 Test files for a sub directory, including only a directory within it, and
452 including an unrelated directory.
452 including an unrelated directory.
453
453
454 $ rm -r .hg/store/meta/~2e_a
454 $ rm -r .hg/store/meta/~2e_a
455 $ rm -r .hg/store/meta/b/foo
455 $ rm -r .hg/store/meta/b/foo
456 $ hg files -r . -I path:b/bar/orange -I path:a b
456 $ hg files -r . -I path:b/bar/orange -I path:a b
457 b/bar/orange/fly/gnat.py (glob)
457 b/bar/orange/fly/gnat.py (glob)
458 b/bar/orange/fly/housefly.txt (glob)
458 b/bar/orange/fly/housefly.txt (glob)
459 $ cp -r .hg/store-copy/. .hg/store
459 $ cp -r .hg/store-copy/. .hg/store
460
460
461 Test files for a pattern, including a directory, and excluding a directory
461 Test files for a pattern, including a directory, and excluding a directory
462 within that.
462 within that.
463
463
464 $ rm -r .hg/store/meta/~2e_a
464 $ rm -r .hg/store/meta/~2e_a
465 $ rm -r .hg/store/meta/b/foo
465 $ rm -r .hg/store/meta/b/foo
466 $ rm -r .hg/store/meta/b/bar/orange
466 $ rm -r .hg/store/meta/b/bar/orange
467 $ hg files -r . glob:**.txt -I path:b/bar -X path:b/bar/orange
467 $ hg files -r . glob:**.txt -I path:b/bar -X path:b/bar/orange
468 b/bar/fruits.txt (glob)
468 b/bar/fruits.txt (glob)
469 $ cp -r .hg/store-copy/. .hg/store
469 $ cp -r .hg/store-copy/. .hg/store
470
470
471 Add some more changes to the deep repo
471 Add some more changes to the deep repo
472 $ echo narf >> b/bar/fruits.txt
472 $ echo narf >> b/bar/fruits.txt
473 $ hg ci -m narf
473 $ hg ci -m narf
474 $ echo troz >> b/bar/orange/fly/gnat.py
474 $ echo troz >> b/bar/orange/fly/gnat.py
475 $ hg ci -m troz
475 $ hg ci -m troz
476
476
477 Verify works
477 Verify works
478 $ hg verify
478 $ hg verify
479 checking changesets
479 checking changesets
480 checking manifests
480 checking manifests
481 checking directory manifests
481 checking directory manifests
482 crosschecking files in changesets and manifests
482 crosschecking files in changesets and manifests
483 checking files
483 checking files
484 8 files, 3 changesets, 10 total revisions
484 8 files, 3 changesets, 10 total revisions
485
485
486 Dirlogs are included in fncache
486 Dirlogs are included in fncache
487 $ grep meta/.A/00manifest.i .hg/store/fncache
487 $ grep meta/.A/00manifest.i .hg/store/fncache
488 meta/.A/00manifest.i
488 meta/.A/00manifest.i
489
489
490 Rebuilt fncache includes dirlogs
490 Rebuilt fncache includes dirlogs
491 $ rm .hg/store/fncache
491 $ rm .hg/store/fncache
492 $ hg debugrebuildfncache
492 $ hg debugrebuildfncache
493 adding data/.A/one.txt.i
493 adding data/.A/one.txt.i
494 adding data/.A/two.txt.i
494 adding data/.A/two.txt.i
495 adding data/b/bar/fruits.txt.i
495 adding data/b/bar/fruits.txt.i
496 adding data/b/bar/orange/fly/gnat.py.i
496 adding data/b/bar/orange/fly/gnat.py.i
497 adding data/b/bar/orange/fly/housefly.txt.i
497 adding data/b/bar/orange/fly/housefly.txt.i
498 adding data/b/foo/apple/bees/flower.py.i
498 adding data/b/foo/apple/bees/flower.py.i
499 adding data/c.txt.i
499 adding data/c.txt.i
500 adding data/d.py.i
500 adding data/d.py.i
501 adding meta/.A/00manifest.i
501 adding meta/.A/00manifest.i
502 adding meta/b/00manifest.i
502 adding meta/b/00manifest.i
503 adding meta/b/bar/00manifest.i
503 adding meta/b/bar/00manifest.i
504 adding meta/b/bar/orange/00manifest.i
504 adding meta/b/bar/orange/00manifest.i
505 adding meta/b/bar/orange/fly/00manifest.i
505 adding meta/b/bar/orange/fly/00manifest.i
506 adding meta/b/foo/00manifest.i
506 adding meta/b/foo/00manifest.i
507 adding meta/b/foo/apple/00manifest.i
507 adding meta/b/foo/apple/00manifest.i
508 adding meta/b/foo/apple/bees/00manifest.i
508 adding meta/b/foo/apple/bees/00manifest.i
509 16 items added, 0 removed from fncache
509 16 items added, 0 removed from fncache
510
510
511 Finish first server
511 Finish first server
512 $ killdaemons.py
512 $ killdaemons.py
513
513
514 Back up the recently added revlogs
514 Back up the recently added revlogs
515 $ cp -r .hg/store .hg/store-newcopy
515 $ cp -r .hg/store .hg/store-newcopy
516
516
517 Verify reports missing dirlog
517 Verify reports missing dirlog
518 $ rm .hg/store/meta/b/00manifest.*
518 $ rm .hg/store/meta/b/00manifest.*
519 $ hg verify
519 $ hg verify
520 checking changesets
520 checking changesets
521 checking manifests
521 checking manifests
522 checking directory manifests
522 checking directory manifests
523 0: empty or missing b/
523 0: empty or missing b/
524 b/@0: parent-directory manifest refers to unknown revision 67688a370455
524 b/@0: parent-directory manifest refers to unknown revision 67688a370455
525 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
525 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
526 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
526 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
527 warning: orphan revlog 'meta/b/bar/00manifest.i'
527 warning: orphan revlog 'meta/b/bar/00manifest.i'
528 warning: orphan revlog 'meta/b/bar/orange/00manifest.i'
528 warning: orphan revlog 'meta/b/bar/orange/00manifest.i'
529 warning: orphan revlog 'meta/b/bar/orange/fly/00manifest.i'
529 warning: orphan revlog 'meta/b/bar/orange/fly/00manifest.i'
530 warning: orphan revlog 'meta/b/foo/00manifest.i'
530 warning: orphan revlog 'meta/b/foo/00manifest.i'
531 warning: orphan revlog 'meta/b/foo/apple/00manifest.i'
531 warning: orphan revlog 'meta/b/foo/apple/00manifest.i'
532 warning: orphan revlog 'meta/b/foo/apple/bees/00manifest.i'
532 warning: orphan revlog 'meta/b/foo/apple/bees/00manifest.i'
533 crosschecking files in changesets and manifests
533 crosschecking files in changesets and manifests
534 b/bar/fruits.txt@0: in changeset but not in manifest
534 b/bar/fruits.txt@0: in changeset but not in manifest
535 b/bar/orange/fly/gnat.py@0: in changeset but not in manifest
535 b/bar/orange/fly/gnat.py@0: in changeset but not in manifest
536 b/bar/orange/fly/housefly.txt@0: in changeset but not in manifest
536 b/bar/orange/fly/housefly.txt@0: in changeset but not in manifest
537 b/foo/apple/bees/flower.py@0: in changeset but not in manifest
537 b/foo/apple/bees/flower.py@0: in changeset but not in manifest
538 checking files
538 checking files
539 8 files, 3 changesets, 10 total revisions
539 8 files, 3 changesets, 10 total revisions
540 6 warnings encountered!
540 6 warnings encountered!
541 8 integrity errors encountered!
541 8 integrity errors encountered!
542 (first damaged changeset appears to be 0)
542 (first damaged changeset appears to be 0)
543 [1]
543 [1]
544 $ cp -r .hg/store-newcopy/. .hg/store
544 $ cp -r .hg/store-newcopy/. .hg/store
545
545
546 Verify reports missing dirlog entry
546 Verify reports missing dirlog entry
547 $ mv -f .hg/store-copy/meta/b/00manifest.* .hg/store/meta/b/
547 $ mv -f .hg/store-copy/meta/b/00manifest.* .hg/store/meta/b/
548 $ hg verify
548 $ hg verify
549 checking changesets
549 checking changesets
550 checking manifests
550 checking manifests
551 checking directory manifests
551 checking directory manifests
552 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
552 b/@1: parent-directory manifest refers to unknown revision f38e85d334c5
553 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
553 b/@2: parent-directory manifest refers to unknown revision 99c9792fd4b0
554 b/bar/@?: rev 1 points to unexpected changeset 1
554 b/bar/@?: rev 1 points to unexpected changeset 1
555 b/bar/@?: 5e03c4ee5e4a not in parent-directory manifest
555 b/bar/@?: 5e03c4ee5e4a not in parent-directory manifest
556 b/bar/@?: rev 2 points to unexpected changeset 2
556 b/bar/@?: rev 2 points to unexpected changeset 2
557 b/bar/@?: 1b16940d66d6 not in parent-directory manifest
557 b/bar/@?: 1b16940d66d6 not in parent-directory manifest
558 b/bar/orange/@?: rev 1 points to unexpected changeset 2
558 b/bar/orange/@?: rev 1 points to unexpected changeset 2
559 (expected None)
559 (expected None)
560 b/bar/orange/fly/@?: rev 1 points to unexpected changeset 2
560 b/bar/orange/fly/@?: rev 1 points to unexpected changeset 2
561 (expected None)
561 (expected None)
562 crosschecking files in changesets and manifests
562 crosschecking files in changesets and manifests
563 checking files
563 checking files
564 8 files, 3 changesets, 10 total revisions
564 8 files, 3 changesets, 10 total revisions
565 2 warnings encountered!
565 2 warnings encountered!
566 8 integrity errors encountered!
566 8 integrity errors encountered!
567 (first damaged changeset appears to be 1)
567 (first damaged changeset appears to be 1)
568 [1]
568 [1]
569 $ cp -r .hg/store-newcopy/. .hg/store
569 $ cp -r .hg/store-newcopy/. .hg/store
570
570
571 Test cloning a treemanifest repo over http.
571 Test cloning a treemanifest repo over http.
572 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
572 $ hg serve -p $HGPORT -d --pid-file=hg.pid --errorlog=errors.log
573 $ cat hg.pid >> $DAEMON_PIDS
573 $ cat hg.pid >> $DAEMON_PIDS
574 $ cd ..
574 $ cd ..
575 We can clone even with the knob turned off and we'll get a treemanifest repo.
575 We can clone even with the knob turned off and we'll get a treemanifest repo.
576 $ hg clone --config experimental.treemanifest=False \
576 $ hg clone --config experimental.treemanifest=False \
577 > --config experimental.changegroup3=True \
577 > --config experimental.changegroup3=True \
578 > http://localhost:$HGPORT deepclone
578 > http://localhost:$HGPORT deepclone
579 requesting all changes
579 requesting all changes
580 adding changesets
580 adding changesets
581 adding manifests
581 adding manifests
582 adding file changes
582 adding file changes
583 added 3 changesets with 10 changes to 8 files
583 added 3 changesets with 10 changes to 8 files
584 updating to branch default
584 updating to branch default
585 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
585 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
586 No server errors.
586 No server errors.
587 $ cat deeprepo/errors.log
587 $ cat deeprepo/errors.log
588 requires got updated to include treemanifest
588 requires got updated to include treemanifest
589 $ cat deepclone/.hg/requires | grep treemanifest
589 $ cat deepclone/.hg/requires | grep treemanifest
590 treemanifest
590 treemanifest
591 Tree manifest revlogs exist.
591 Tree manifest revlogs exist.
592 $ find deepclone/.hg/store/meta | sort
592 $ find deepclone/.hg/store/meta | sort
593 deepclone/.hg/store/meta
593 deepclone/.hg/store/meta
594 deepclone/.hg/store/meta/b
594 deepclone/.hg/store/meta/b
595 deepclone/.hg/store/meta/b/00manifest.i
595 deepclone/.hg/store/meta/b/00manifest.i
596 deepclone/.hg/store/meta/b/bar
596 deepclone/.hg/store/meta/b/bar
597 deepclone/.hg/store/meta/b/bar/00manifest.i
597 deepclone/.hg/store/meta/b/bar/00manifest.i
598 deepclone/.hg/store/meta/b/bar/orange
598 deepclone/.hg/store/meta/b/bar/orange
599 deepclone/.hg/store/meta/b/bar/orange/00manifest.i
599 deepclone/.hg/store/meta/b/bar/orange/00manifest.i
600 deepclone/.hg/store/meta/b/bar/orange/fly
600 deepclone/.hg/store/meta/b/bar/orange/fly
601 deepclone/.hg/store/meta/b/bar/orange/fly/00manifest.i
601 deepclone/.hg/store/meta/b/bar/orange/fly/00manifest.i
602 deepclone/.hg/store/meta/b/foo
602 deepclone/.hg/store/meta/b/foo
603 deepclone/.hg/store/meta/b/foo/00manifest.i
603 deepclone/.hg/store/meta/b/foo/00manifest.i
604 deepclone/.hg/store/meta/b/foo/apple
604 deepclone/.hg/store/meta/b/foo/apple
605 deepclone/.hg/store/meta/b/foo/apple/00manifest.i
605 deepclone/.hg/store/meta/b/foo/apple/00manifest.i
606 deepclone/.hg/store/meta/b/foo/apple/bees
606 deepclone/.hg/store/meta/b/foo/apple/bees
607 deepclone/.hg/store/meta/b/foo/apple/bees/00manifest.i
607 deepclone/.hg/store/meta/b/foo/apple/bees/00manifest.i
608 deepclone/.hg/store/meta/~2e_a
608 deepclone/.hg/store/meta/~2e_a
609 deepclone/.hg/store/meta/~2e_a/00manifest.i
609 deepclone/.hg/store/meta/~2e_a/00manifest.i
610 Verify passes.
610 Verify passes.
611 $ cd deepclone
611 $ cd deepclone
612 $ hg verify
612 $ hg verify
613 checking changesets
613 checking changesets
614 checking manifests
614 checking manifests
615 checking directory manifests
615 checking directory manifests
616 crosschecking files in changesets and manifests
616 crosschecking files in changesets and manifests
617 checking files
617 checking files
618 8 files, 3 changesets, 10 total revisions
618 8 files, 3 changesets, 10 total revisions
619 $ cd ..
619 $ cd ..
620
620
621 Create clones using old repo formats to use in later tests
621 Create clones using old repo formats to use in later tests
622 $ hg clone --config format.usestore=False \
622 $ hg clone --config format.usestore=False \
623 > --config experimental.changegroup3=True \
623 > --config experimental.changegroup3=True \
624 > http://localhost:$HGPORT deeprepo-basicstore
624 > http://localhost:$HGPORT deeprepo-basicstore
625 requesting all changes
625 requesting all changes
626 adding changesets
626 adding changesets
627 adding manifests
627 adding manifests
628 adding file changes
628 adding file changes
629 added 3 changesets with 10 changes to 8 files
629 added 3 changesets with 10 changes to 8 files
630 updating to branch default
630 updating to branch default
631 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
631 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
632 $ cd deeprepo-basicstore
632 $ cd deeprepo-basicstore
633 $ grep store .hg/requires
633 $ grep store .hg/requires
634 [1]
634 [1]
635 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --errorlog=errors.log
635 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --errorlog=errors.log
636 $ cat hg.pid >> $DAEMON_PIDS
636 $ cat hg.pid >> $DAEMON_PIDS
637 $ cd ..
637 $ cd ..
638 $ hg clone --config format.usefncache=False \
638 $ hg clone --config format.usefncache=False \
639 > --config experimental.changegroup3=True \
639 > --config experimental.changegroup3=True \
640 > http://localhost:$HGPORT deeprepo-encodedstore
640 > http://localhost:$HGPORT deeprepo-encodedstore
641 requesting all changes
641 requesting all changes
642 adding changesets
642 adding changesets
643 adding manifests
643 adding manifests
644 adding file changes
644 adding file changes
645 added 3 changesets with 10 changes to 8 files
645 added 3 changesets with 10 changes to 8 files
646 updating to branch default
646 updating to branch default
647 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
647 8 files updated, 0 files merged, 0 files removed, 0 files unresolved
648 $ cd deeprepo-encodedstore
648 $ cd deeprepo-encodedstore
649 $ grep fncache .hg/requires
649 $ grep fncache .hg/requires
650 [1]
650 [1]
651 $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --errorlog=errors.log
651 $ hg serve -p $HGPORT2 -d --pid-file=hg.pid --errorlog=errors.log
652 $ cat hg.pid >> $DAEMON_PIDS
652 $ cat hg.pid >> $DAEMON_PIDS
653 $ cd ..
653 $ cd ..
654
654
655 Local clone with basicstore
655 Local clone with basicstore
656 $ hg clone -U deeprepo-basicstore local-clone-basicstore
656 $ hg clone -U deeprepo-basicstore local-clone-basicstore
657 $ hg -R local-clone-basicstore verify
657 $ hg -R local-clone-basicstore verify
658 checking changesets
658 checking changesets
659 checking manifests
659 checking manifests
660 checking directory manifests
660 checking directory manifests
661 crosschecking files in changesets and manifests
661 crosschecking files in changesets and manifests
662 checking files
662 checking files
663 8 files, 3 changesets, 10 total revisions
663 8 files, 3 changesets, 10 total revisions
664
664
665 Local clone with encodedstore
665 Local clone with encodedstore
666 $ hg clone -U deeprepo-encodedstore local-clone-encodedstore
666 $ hg clone -U deeprepo-encodedstore local-clone-encodedstore
667 $ hg -R local-clone-encodedstore verify
667 $ hg -R local-clone-encodedstore verify
668 checking changesets
668 checking changesets
669 checking manifests
669 checking manifests
670 checking directory manifests
670 checking directory manifests
671 crosschecking files in changesets and manifests
671 crosschecking files in changesets and manifests
672 checking files
672 checking files
673 8 files, 3 changesets, 10 total revisions
673 8 files, 3 changesets, 10 total revisions
674
674
675 Local clone with fncachestore
675 Local clone with fncachestore
676 $ hg clone -U deeprepo local-clone-fncachestore
676 $ hg clone -U deeprepo local-clone-fncachestore
677 $ hg -R local-clone-fncachestore verify
677 $ hg -R local-clone-fncachestore verify
678 checking changesets
678 checking changesets
679 checking manifests
679 checking manifests
680 checking directory manifests
680 checking directory manifests
681 crosschecking files in changesets and manifests
681 crosschecking files in changesets and manifests
682 checking files
682 checking files
683 8 files, 3 changesets, 10 total revisions
683 8 files, 3 changesets, 10 total revisions
684
684
685 Stream clone with basicstore
685 Stream clone with basicstore
686 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
686 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
687 > http://localhost:$HGPORT1 stream-clone-basicstore
687 > http://localhost:$HGPORT1 stream-clone-basicstore
688 streaming all changes
688 streaming all changes
689 18 files to transfer, * of data (glob)
689 18 files to transfer, * of data (glob)
690 transferred * in * seconds (*) (glob)
690 transferred * in * seconds (*) (glob)
691 searching for changes
691 searching for changes
692 no changes found
692 no changes found
693 $ hg -R stream-clone-basicstore verify
693 $ hg -R stream-clone-basicstore verify
694 checking changesets
694 checking changesets
695 checking manifests
695 checking manifests
696 checking directory manifests
696 checking directory manifests
697 crosschecking files in changesets and manifests
697 crosschecking files in changesets and manifests
698 checking files
698 checking files
699 8 files, 3 changesets, 10 total revisions
699 8 files, 3 changesets, 10 total revisions
700
700
701 Stream clone with encodedstore
701 Stream clone with encodedstore
702 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
702 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
703 > http://localhost:$HGPORT2 stream-clone-encodedstore
703 > http://localhost:$HGPORT2 stream-clone-encodedstore
704 streaming all changes
704 streaming all changes
705 18 files to transfer, * of data (glob)
705 18 files to transfer, * of data (glob)
706 transferred * in * seconds (*) (glob)
706 transferred * in * seconds (*) (glob)
707 searching for changes
707 searching for changes
708 no changes found
708 no changes found
709 $ hg -R stream-clone-encodedstore verify
709 $ hg -R stream-clone-encodedstore verify
710 checking changesets
710 checking changesets
711 checking manifests
711 checking manifests
712 checking directory manifests
712 checking directory manifests
713 crosschecking files in changesets and manifests
713 crosschecking files in changesets and manifests
714 checking files
714 checking files
715 8 files, 3 changesets, 10 total revisions
715 8 files, 3 changesets, 10 total revisions
716
716
717 Stream clone with fncachestore
717 Stream clone with fncachestore
718 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
718 $ hg clone --config experimental.changegroup3=True --uncompressed -U \
719 > http://localhost:$HGPORT stream-clone-fncachestore
719 > http://localhost:$HGPORT stream-clone-fncachestore
720 streaming all changes
720 streaming all changes
721 18 files to transfer, * of data (glob)
721 18 files to transfer, * of data (glob)
722 transferred * in * seconds (*) (glob)
722 transferred * in * seconds (*) (glob)
723 searching for changes
723 searching for changes
724 no changes found
724 no changes found
725 $ hg -R stream-clone-fncachestore verify
725 $ hg -R stream-clone-fncachestore verify
726 checking changesets
726 checking changesets
727 checking manifests
727 checking manifests
728 checking directory manifests
728 checking directory manifests
729 crosschecking files in changesets and manifests
729 crosschecking files in changesets and manifests
730 checking files
730 checking files
731 8 files, 3 changesets, 10 total revisions
731 8 files, 3 changesets, 10 total revisions
732
732
733 Packed bundle
733 Packed bundle
734 $ hg -R deeprepo debugcreatestreamclonebundle repo-packed.hg
734 $ hg -R deeprepo debugcreatestreamclonebundle repo-packed.hg
735 writing 3349 bytes for 18 files
735 writing 3349 bytes for 18 files
736 bundle requirements: generaldelta, revlogv1, treemanifest
736 bundle requirements: generaldelta, revlogv1, treemanifest
737 $ hg debugbundle --spec repo-packed.hg
737 $ hg debugbundle --spec repo-packed.hg
738 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Ctreemanifest
738 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1%2Ctreemanifest
739
740 Bundle with changegroup2 is not supported
741
742 $ hg -R deeprepo bundle --all -t v2 deeprepo.bundle
743 abort: repository does not support bundle version 02
744 [255]
General Comments 0
You need to be logged in to leave comments. Login now