##// END OF EJS Templates
branches: populate all template keywords in formatter...
Yuya Nishihara -
r31173:052e4f1f default
parent child Browse files
Show More
@@ -1,5447 +1,5448 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 os
12 import os
13 import re
13 import re
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 )
21 )
22 from . import (
22 from . import (
23 archival,
23 archival,
24 bookmarks,
24 bookmarks,
25 bundle2,
25 bundle2,
26 changegroup,
26 changegroup,
27 cmdutil,
27 cmdutil,
28 copies,
28 copies,
29 destutil,
29 destutil,
30 dirstateguard,
30 dirstateguard,
31 discovery,
31 discovery,
32 encoding,
32 encoding,
33 error,
33 error,
34 exchange,
34 exchange,
35 extensions,
35 extensions,
36 graphmod,
36 graphmod,
37 hbisect,
37 hbisect,
38 help,
38 help,
39 hg,
39 hg,
40 lock as lockmod,
40 lock as lockmod,
41 merge as mergemod,
41 merge as mergemod,
42 obsolete,
42 obsolete,
43 patch,
43 patch,
44 phases,
44 phases,
45 pycompat,
45 pycompat,
46 revsetlang,
46 revsetlang,
47 scmutil,
47 scmutil,
48 server,
48 server,
49 sshserver,
49 sshserver,
50 streamclone,
50 streamclone,
51 templatekw,
51 templatekw,
52 ui as uimod,
52 ui as uimod,
53 util,
53 util,
54 )
54 )
55
55
56 release = lockmod.release
56 release = lockmod.release
57
57
58 table = {}
58 table = {}
59
59
60 command = cmdutil.command(table)
60 command = cmdutil.command(table)
61
61
62 # label constants
62 # label constants
63 # until 3.5, bookmarks.current was the advertised name, not
63 # until 3.5, bookmarks.current was the advertised name, not
64 # bookmarks.active, so we must use both to avoid breaking old
64 # bookmarks.active, so we must use both to avoid breaking old
65 # custom styles
65 # custom styles
66 activebookmarklabel = 'bookmarks.active bookmarks.current'
66 activebookmarklabel = 'bookmarks.active bookmarks.current'
67
67
68 # common command options
68 # common command options
69
69
70 globalopts = [
70 globalopts = [
71 ('R', 'repository', '',
71 ('R', 'repository', '',
72 _('repository root directory or name of overlay bundle file'),
72 _('repository root directory or name of overlay bundle file'),
73 _('REPO')),
73 _('REPO')),
74 ('', 'cwd', '',
74 ('', 'cwd', '',
75 _('change working directory'), _('DIR')),
75 _('change working directory'), _('DIR')),
76 ('y', 'noninteractive', None,
76 ('y', 'noninteractive', None,
77 _('do not prompt, automatically pick the first choice for all prompts')),
77 _('do not prompt, automatically pick the first choice for all prompts')),
78 ('q', 'quiet', None, _('suppress output')),
78 ('q', 'quiet', None, _('suppress output')),
79 ('v', 'verbose', None, _('enable additional output')),
79 ('v', 'verbose', None, _('enable additional output')),
80 ('', 'color', '',
80 ('', 'color', '',
81 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
81 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
82 # and should not be translated
82 # and should not be translated
83 _("when to colorize (boolean, always, auto, never, or debug)"),
83 _("when to colorize (boolean, always, auto, never, or debug)"),
84 _('TYPE')),
84 _('TYPE')),
85 ('', 'config', [],
85 ('', 'config', [],
86 _('set/override config option (use \'section.name=value\')'),
86 _('set/override config option (use \'section.name=value\')'),
87 _('CONFIG')),
87 _('CONFIG')),
88 ('', 'debug', None, _('enable debugging output')),
88 ('', 'debug', None, _('enable debugging output')),
89 ('', 'debugger', None, _('start debugger')),
89 ('', 'debugger', None, _('start debugger')),
90 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
90 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
91 _('ENCODE')),
91 _('ENCODE')),
92 ('', 'encodingmode', encoding.encodingmode,
92 ('', 'encodingmode', encoding.encodingmode,
93 _('set the charset encoding mode'), _('MODE')),
93 _('set the charset encoding mode'), _('MODE')),
94 ('', 'traceback', None, _('always print a traceback on exception')),
94 ('', 'traceback', None, _('always print a traceback on exception')),
95 ('', 'time', None, _('time how long the command takes')),
95 ('', 'time', None, _('time how long the command takes')),
96 ('', 'profile', None, _('print command execution profile')),
96 ('', 'profile', None, _('print command execution profile')),
97 ('', 'version', None, _('output version information and exit')),
97 ('', 'version', None, _('output version information and exit')),
98 ('h', 'help', None, _('display help and exit')),
98 ('h', 'help', None, _('display help and exit')),
99 ('', 'hidden', False, _('consider hidden changesets')),
99 ('', 'hidden', False, _('consider hidden changesets')),
100 ('', 'pager', 'auto',
100 ('', 'pager', 'auto',
101 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
101 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
102 ]
102 ]
103
103
104 dryrunopts = [('n', 'dry-run', None,
104 dryrunopts = [('n', 'dry-run', None,
105 _('do not perform actions, just print output'))]
105 _('do not perform actions, just print output'))]
106
106
107 remoteopts = [
107 remoteopts = [
108 ('e', 'ssh', '',
108 ('e', 'ssh', '',
109 _('specify ssh command to use'), _('CMD')),
109 _('specify ssh command to use'), _('CMD')),
110 ('', 'remotecmd', '',
110 ('', 'remotecmd', '',
111 _('specify hg command to run on the remote side'), _('CMD')),
111 _('specify hg command to run on the remote side'), _('CMD')),
112 ('', 'insecure', None,
112 ('', 'insecure', None,
113 _('do not verify server certificate (ignoring web.cacerts config)')),
113 _('do not verify server certificate (ignoring web.cacerts config)')),
114 ]
114 ]
115
115
116 walkopts = [
116 walkopts = [
117 ('I', 'include', [],
117 ('I', 'include', [],
118 _('include names matching the given patterns'), _('PATTERN')),
118 _('include names matching the given patterns'), _('PATTERN')),
119 ('X', 'exclude', [],
119 ('X', 'exclude', [],
120 _('exclude names matching the given patterns'), _('PATTERN')),
120 _('exclude names matching the given patterns'), _('PATTERN')),
121 ]
121 ]
122
122
123 commitopts = [
123 commitopts = [
124 ('m', 'message', '',
124 ('m', 'message', '',
125 _('use text as commit message'), _('TEXT')),
125 _('use text as commit message'), _('TEXT')),
126 ('l', 'logfile', '',
126 ('l', 'logfile', '',
127 _('read commit message from file'), _('FILE')),
127 _('read commit message from file'), _('FILE')),
128 ]
128 ]
129
129
130 commitopts2 = [
130 commitopts2 = [
131 ('d', 'date', '',
131 ('d', 'date', '',
132 _('record the specified date as commit date'), _('DATE')),
132 _('record the specified date as commit date'), _('DATE')),
133 ('u', 'user', '',
133 ('u', 'user', '',
134 _('record the specified user as committer'), _('USER')),
134 _('record the specified user as committer'), _('USER')),
135 ]
135 ]
136
136
137 # hidden for now
137 # hidden for now
138 formatteropts = [
138 formatteropts = [
139 ('T', 'template', '',
139 ('T', 'template', '',
140 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
140 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
141 ]
141 ]
142
142
143 templateopts = [
143 templateopts = [
144 ('', 'style', '',
144 ('', 'style', '',
145 _('display using template map file (DEPRECATED)'), _('STYLE')),
145 _('display using template map file (DEPRECATED)'), _('STYLE')),
146 ('T', 'template', '',
146 ('T', 'template', '',
147 _('display with template'), _('TEMPLATE')),
147 _('display with template'), _('TEMPLATE')),
148 ]
148 ]
149
149
150 logopts = [
150 logopts = [
151 ('p', 'patch', None, _('show patch')),
151 ('p', 'patch', None, _('show patch')),
152 ('g', 'git', None, _('use git extended diff format')),
152 ('g', 'git', None, _('use git extended diff format')),
153 ('l', 'limit', '',
153 ('l', 'limit', '',
154 _('limit number of changes displayed'), _('NUM')),
154 _('limit number of changes displayed'), _('NUM')),
155 ('M', 'no-merges', None, _('do not show merges')),
155 ('M', 'no-merges', None, _('do not show merges')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('G', 'graph', None, _("show the revision DAG")),
157 ('G', 'graph', None, _("show the revision DAG")),
158 ] + templateopts
158 ] + templateopts
159
159
160 diffopts = [
160 diffopts = [
161 ('a', 'text', None, _('treat all files as text')),
161 ('a', 'text', None, _('treat all files as text')),
162 ('g', 'git', None, _('use git extended diff format')),
162 ('g', 'git', None, _('use git extended diff format')),
163 ('', 'nodates', None, _('omit dates from diff headers'))
163 ('', 'nodates', None, _('omit dates from diff headers'))
164 ]
164 ]
165
165
166 diffwsopts = [
166 diffwsopts = [
167 ('w', 'ignore-all-space', None,
167 ('w', 'ignore-all-space', None,
168 _('ignore white space when comparing lines')),
168 _('ignore white space when comparing lines')),
169 ('b', 'ignore-space-change', None,
169 ('b', 'ignore-space-change', None,
170 _('ignore changes in the amount of white space')),
170 _('ignore changes in the amount of white space')),
171 ('B', 'ignore-blank-lines', None,
171 ('B', 'ignore-blank-lines', None,
172 _('ignore changes whose lines are all blank')),
172 _('ignore changes whose lines are all blank')),
173 ]
173 ]
174
174
175 diffopts2 = [
175 diffopts2 = [
176 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
176 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
177 ('p', 'show-function', None, _('show which function each change is in')),
177 ('p', 'show-function', None, _('show which function each change is in')),
178 ('', 'reverse', None, _('produce a diff that undoes the changes')),
178 ('', 'reverse', None, _('produce a diff that undoes the changes')),
179 ] + diffwsopts + [
179 ] + diffwsopts + [
180 ('U', 'unified', '',
180 ('U', 'unified', '',
181 _('number of lines of context to show'), _('NUM')),
181 _('number of lines of context to show'), _('NUM')),
182 ('', 'stat', None, _('output diffstat-style summary of changes')),
182 ('', 'stat', None, _('output diffstat-style summary of changes')),
183 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
183 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
184 ]
184 ]
185
185
186 mergetoolopts = [
186 mergetoolopts = [
187 ('t', 'tool', '', _('specify merge tool')),
187 ('t', 'tool', '', _('specify merge tool')),
188 ]
188 ]
189
189
190 similarityopts = [
190 similarityopts = [
191 ('s', 'similarity', '',
191 ('s', 'similarity', '',
192 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
192 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
193 ]
193 ]
194
194
195 subrepoopts = [
195 subrepoopts = [
196 ('S', 'subrepos', None,
196 ('S', 'subrepos', None,
197 _('recurse into subrepositories'))
197 _('recurse into subrepositories'))
198 ]
198 ]
199
199
200 debugrevlogopts = [
200 debugrevlogopts = [
201 ('c', 'changelog', False, _('open changelog')),
201 ('c', 'changelog', False, _('open changelog')),
202 ('m', 'manifest', False, _('open manifest')),
202 ('m', 'manifest', False, _('open manifest')),
203 ('', 'dir', '', _('open directory manifest')),
203 ('', 'dir', '', _('open directory manifest')),
204 ]
204 ]
205
205
206 # Commands start here, listed alphabetically
206 # Commands start here, listed alphabetically
207
207
208 @command('^add',
208 @command('^add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _('[OPTION]... [FILE]...'),
210 _('[OPTION]... [FILE]...'),
211 inferrepo=True)
211 inferrepo=True)
212 def add(ui, repo, *pats, **opts):
212 def add(ui, repo, *pats, **opts):
213 """add the specified files on the next commit
213 """add the specified files on the next commit
214
214
215 Schedule files to be version controlled and added to the
215 Schedule files to be version controlled and added to the
216 repository.
216 repository.
217
217
218 The files will be added to the repository at the next commit. To
218 The files will be added to the repository at the next commit. To
219 undo an add before that, see :hg:`forget`.
219 undo an add before that, see :hg:`forget`.
220
220
221 If no names are given, add all files to the repository (except
221 If no names are given, add all files to the repository (except
222 files matching ``.hgignore``).
222 files matching ``.hgignore``).
223
223
224 .. container:: verbose
224 .. container:: verbose
225
225
226 Examples:
226 Examples:
227
227
228 - New (unknown) files are added
228 - New (unknown) files are added
229 automatically by :hg:`add`::
229 automatically by :hg:`add`::
230
230
231 $ ls
231 $ ls
232 foo.c
232 foo.c
233 $ hg status
233 $ hg status
234 ? foo.c
234 ? foo.c
235 $ hg add
235 $ hg add
236 adding foo.c
236 adding foo.c
237 $ hg status
237 $ hg status
238 A foo.c
238 A foo.c
239
239
240 - Specific files to be added can be specified::
240 - Specific files to be added can be specified::
241
241
242 $ ls
242 $ ls
243 bar.c foo.c
243 bar.c foo.c
244 $ hg status
244 $ hg status
245 ? bar.c
245 ? bar.c
246 ? foo.c
246 ? foo.c
247 $ hg add bar.c
247 $ hg add bar.c
248 $ hg status
248 $ hg status
249 A bar.c
249 A bar.c
250 ? foo.c
250 ? foo.c
251
251
252 Returns 0 if all files are successfully added.
252 Returns 0 if all files are successfully added.
253 """
253 """
254
254
255 m = scmutil.match(repo[None], pats, opts)
255 m = scmutil.match(repo[None], pats, opts)
256 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
256 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
257 return rejected and 1 or 0
257 return rejected and 1 or 0
258
258
259 @command('addremove',
259 @command('addremove',
260 similarityopts + subrepoopts + walkopts + dryrunopts,
260 similarityopts + subrepoopts + walkopts + dryrunopts,
261 _('[OPTION]... [FILE]...'),
261 _('[OPTION]... [FILE]...'),
262 inferrepo=True)
262 inferrepo=True)
263 def addremove(ui, repo, *pats, **opts):
263 def addremove(ui, repo, *pats, **opts):
264 """add all new files, delete all missing files
264 """add all new files, delete all missing files
265
265
266 Add all new files and remove all missing files from the
266 Add all new files and remove all missing files from the
267 repository.
267 repository.
268
268
269 Unless names are given, new files are ignored if they match any of
269 Unless names are given, new files are ignored if they match any of
270 the patterns in ``.hgignore``. As with add, these changes take
270 the patterns in ``.hgignore``. As with add, these changes take
271 effect at the next commit.
271 effect at the next commit.
272
272
273 Use the -s/--similarity option to detect renamed files. This
273 Use the -s/--similarity option to detect renamed files. This
274 option takes a percentage between 0 (disabled) and 100 (files must
274 option takes a percentage between 0 (disabled) and 100 (files must
275 be identical) as its parameter. With a parameter greater than 0,
275 be identical) as its parameter. With a parameter greater than 0,
276 this compares every removed file with every added file and records
276 this compares every removed file with every added file and records
277 those similar enough as renames. Detecting renamed files this way
277 those similar enough as renames. Detecting renamed files this way
278 can be expensive. After using this option, :hg:`status -C` can be
278 can be expensive. After using this option, :hg:`status -C` can be
279 used to check which files were identified as moved or renamed. If
279 used to check which files were identified as moved or renamed. If
280 not specified, -s/--similarity defaults to 100 and only renames of
280 not specified, -s/--similarity defaults to 100 and only renames of
281 identical files are detected.
281 identical files are detected.
282
282
283 .. container:: verbose
283 .. container:: verbose
284
284
285 Examples:
285 Examples:
286
286
287 - A number of files (bar.c and foo.c) are new,
287 - A number of files (bar.c and foo.c) are new,
288 while foobar.c has been removed (without using :hg:`remove`)
288 while foobar.c has been removed (without using :hg:`remove`)
289 from the repository::
289 from the repository::
290
290
291 $ ls
291 $ ls
292 bar.c foo.c
292 bar.c foo.c
293 $ hg status
293 $ hg status
294 ! foobar.c
294 ! foobar.c
295 ? bar.c
295 ? bar.c
296 ? foo.c
296 ? foo.c
297 $ hg addremove
297 $ hg addremove
298 adding bar.c
298 adding bar.c
299 adding foo.c
299 adding foo.c
300 removing foobar.c
300 removing foobar.c
301 $ hg status
301 $ hg status
302 A bar.c
302 A bar.c
303 A foo.c
303 A foo.c
304 R foobar.c
304 R foobar.c
305
305
306 - A file foobar.c was moved to foo.c without using :hg:`rename`.
306 - A file foobar.c was moved to foo.c without using :hg:`rename`.
307 Afterwards, it was edited slightly::
307 Afterwards, it was edited slightly::
308
308
309 $ ls
309 $ ls
310 foo.c
310 foo.c
311 $ hg status
311 $ hg status
312 ! foobar.c
312 ! foobar.c
313 ? foo.c
313 ? foo.c
314 $ hg addremove --similarity 90
314 $ hg addremove --similarity 90
315 removing foobar.c
315 removing foobar.c
316 adding foo.c
316 adding foo.c
317 recording removal of foobar.c as rename to foo.c (94% similar)
317 recording removal of foobar.c as rename to foo.c (94% similar)
318 $ hg status -C
318 $ hg status -C
319 A foo.c
319 A foo.c
320 foobar.c
320 foobar.c
321 R foobar.c
321 R foobar.c
322
322
323 Returns 0 if all files are successfully added.
323 Returns 0 if all files are successfully added.
324 """
324 """
325 try:
325 try:
326 sim = float(opts.get('similarity') or 100)
326 sim = float(opts.get('similarity') or 100)
327 except ValueError:
327 except ValueError:
328 raise error.Abort(_('similarity must be a number'))
328 raise error.Abort(_('similarity must be a number'))
329 if sim < 0 or sim > 100:
329 if sim < 0 or sim > 100:
330 raise error.Abort(_('similarity must be between 0 and 100'))
330 raise error.Abort(_('similarity must be between 0 and 100'))
331 matcher = scmutil.match(repo[None], pats, opts)
331 matcher = scmutil.match(repo[None], pats, opts)
332 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
332 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
333
333
334 @command('^annotate|blame',
334 @command('^annotate|blame',
335 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
335 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
336 ('', 'follow', None,
336 ('', 'follow', None,
337 _('follow copies/renames and list the filename (DEPRECATED)')),
337 _('follow copies/renames and list the filename (DEPRECATED)')),
338 ('', 'no-follow', None, _("don't follow copies and renames")),
338 ('', 'no-follow', None, _("don't follow copies and renames")),
339 ('a', 'text', None, _('treat all files as text')),
339 ('a', 'text', None, _('treat all files as text')),
340 ('u', 'user', None, _('list the author (long with -v)')),
340 ('u', 'user', None, _('list the author (long with -v)')),
341 ('f', 'file', None, _('list the filename')),
341 ('f', 'file', None, _('list the filename')),
342 ('d', 'date', None, _('list the date (short with -q)')),
342 ('d', 'date', None, _('list the date (short with -q)')),
343 ('n', 'number', None, _('list the revision number (default)')),
343 ('n', 'number', None, _('list the revision number (default)')),
344 ('c', 'changeset', None, _('list the changeset')),
344 ('c', 'changeset', None, _('list the changeset')),
345 ('l', 'line-number', None, _('show line number at the first appearance'))
345 ('l', 'line-number', None, _('show line number at the first appearance'))
346 ] + diffwsopts + walkopts + formatteropts,
346 ] + diffwsopts + walkopts + formatteropts,
347 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
347 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
348 inferrepo=True)
348 inferrepo=True)
349 def annotate(ui, repo, *pats, **opts):
349 def annotate(ui, repo, *pats, **opts):
350 """show changeset information by line for each file
350 """show changeset information by line for each file
351
351
352 List changes in files, showing the revision id responsible for
352 List changes in files, showing the revision id responsible for
353 each line.
353 each line.
354
354
355 This command is useful for discovering when a change was made and
355 This command is useful for discovering when a change was made and
356 by whom.
356 by whom.
357
357
358 If you include --file, --user, or --date, the revision number is
358 If you include --file, --user, or --date, the revision number is
359 suppressed unless you also include --number.
359 suppressed unless you also include --number.
360
360
361 Without the -a/--text option, annotate will avoid processing files
361 Without the -a/--text option, annotate will avoid processing files
362 it detects as binary. With -a, annotate will annotate the file
362 it detects as binary. With -a, annotate will annotate the file
363 anyway, although the results will probably be neither useful
363 anyway, although the results will probably be neither useful
364 nor desirable.
364 nor desirable.
365
365
366 Returns 0 on success.
366 Returns 0 on success.
367 """
367 """
368 if not pats:
368 if not pats:
369 raise error.Abort(_('at least one filename or pattern is required'))
369 raise error.Abort(_('at least one filename or pattern is required'))
370
370
371 if opts.get('follow'):
371 if opts.get('follow'):
372 # --follow is deprecated and now just an alias for -f/--file
372 # --follow is deprecated and now just an alias for -f/--file
373 # to mimic the behavior of Mercurial before version 1.5
373 # to mimic the behavior of Mercurial before version 1.5
374 opts['file'] = True
374 opts['file'] = True
375
375
376 ctx = scmutil.revsingle(repo, opts.get('rev'))
376 ctx = scmutil.revsingle(repo, opts.get('rev'))
377
377
378 fm = ui.formatter('annotate', opts)
378 fm = ui.formatter('annotate', opts)
379 if ui.quiet:
379 if ui.quiet:
380 datefunc = util.shortdate
380 datefunc = util.shortdate
381 else:
381 else:
382 datefunc = util.datestr
382 datefunc = util.datestr
383 if ctx.rev() is None:
383 if ctx.rev() is None:
384 def hexfn(node):
384 def hexfn(node):
385 if node is None:
385 if node is None:
386 return None
386 return None
387 else:
387 else:
388 return fm.hexfunc(node)
388 return fm.hexfunc(node)
389 if opts.get('changeset'):
389 if opts.get('changeset'):
390 # omit "+" suffix which is appended to node hex
390 # omit "+" suffix which is appended to node hex
391 def formatrev(rev):
391 def formatrev(rev):
392 if rev is None:
392 if rev is None:
393 return '%d' % ctx.p1().rev()
393 return '%d' % ctx.p1().rev()
394 else:
394 else:
395 return '%d' % rev
395 return '%d' % rev
396 else:
396 else:
397 def formatrev(rev):
397 def formatrev(rev):
398 if rev is None:
398 if rev is None:
399 return '%d+' % ctx.p1().rev()
399 return '%d+' % ctx.p1().rev()
400 else:
400 else:
401 return '%d ' % rev
401 return '%d ' % rev
402 def formathex(hex):
402 def formathex(hex):
403 if hex is None:
403 if hex is None:
404 return '%s+' % fm.hexfunc(ctx.p1().node())
404 return '%s+' % fm.hexfunc(ctx.p1().node())
405 else:
405 else:
406 return '%s ' % hex
406 return '%s ' % hex
407 else:
407 else:
408 hexfn = fm.hexfunc
408 hexfn = fm.hexfunc
409 formatrev = formathex = str
409 formatrev = formathex = str
410
410
411 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
411 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
412 ('number', ' ', lambda x: x[0].rev(), formatrev),
412 ('number', ' ', lambda x: x[0].rev(), formatrev),
413 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
413 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
414 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
414 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
415 ('file', ' ', lambda x: x[0].path(), str),
415 ('file', ' ', lambda x: x[0].path(), str),
416 ('line_number', ':', lambda x: x[1], str),
416 ('line_number', ':', lambda x: x[1], str),
417 ]
417 ]
418 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
418 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
419
419
420 if (not opts.get('user') and not opts.get('changeset')
420 if (not opts.get('user') and not opts.get('changeset')
421 and not opts.get('date') and not opts.get('file')):
421 and not opts.get('date') and not opts.get('file')):
422 opts['number'] = True
422 opts['number'] = True
423
423
424 linenumber = opts.get('line_number') is not None
424 linenumber = opts.get('line_number') is not None
425 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
425 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
426 raise error.Abort(_('at least one of -n/-c is required for -l'))
426 raise error.Abort(_('at least one of -n/-c is required for -l'))
427
427
428 ui.pager('annotate')
428 ui.pager('annotate')
429
429
430 if fm.isplain():
430 if fm.isplain():
431 def makefunc(get, fmt):
431 def makefunc(get, fmt):
432 return lambda x: fmt(get(x))
432 return lambda x: fmt(get(x))
433 else:
433 else:
434 def makefunc(get, fmt):
434 def makefunc(get, fmt):
435 return get
435 return get
436 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
436 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
437 if opts.get(op)]
437 if opts.get(op)]
438 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
438 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
439 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
439 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
440 if opts.get(op))
440 if opts.get(op))
441
441
442 def bad(x, y):
442 def bad(x, y):
443 raise error.Abort("%s: %s" % (x, y))
443 raise error.Abort("%s: %s" % (x, y))
444
444
445 m = scmutil.match(ctx, pats, opts, badfn=bad)
445 m = scmutil.match(ctx, pats, opts, badfn=bad)
446
446
447 follow = not opts.get('no_follow')
447 follow = not opts.get('no_follow')
448 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
448 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
449 whitespace=True)
449 whitespace=True)
450 for abs in ctx.walk(m):
450 for abs in ctx.walk(m):
451 fctx = ctx[abs]
451 fctx = ctx[abs]
452 if not opts.get('text') and util.binary(fctx.data()):
452 if not opts.get('text') and util.binary(fctx.data()):
453 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
453 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
454 continue
454 continue
455
455
456 lines = fctx.annotate(follow=follow, linenumber=linenumber,
456 lines = fctx.annotate(follow=follow, linenumber=linenumber,
457 diffopts=diffopts)
457 diffopts=diffopts)
458 if not lines:
458 if not lines:
459 continue
459 continue
460 formats = []
460 formats = []
461 pieces = []
461 pieces = []
462
462
463 for f, sep in funcmap:
463 for f, sep in funcmap:
464 l = [f(n) for n, dummy in lines]
464 l = [f(n) for n, dummy in lines]
465 if fm.isplain():
465 if fm.isplain():
466 sizes = [encoding.colwidth(x) for x in l]
466 sizes = [encoding.colwidth(x) for x in l]
467 ml = max(sizes)
467 ml = max(sizes)
468 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
468 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
469 else:
469 else:
470 formats.append(['%s' for x in l])
470 formats.append(['%s' for x in l])
471 pieces.append(l)
471 pieces.append(l)
472
472
473 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
473 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
474 fm.startitem()
474 fm.startitem()
475 fm.write(fields, "".join(f), *p)
475 fm.write(fields, "".join(f), *p)
476 fm.write('line', ": %s", l[1])
476 fm.write('line', ": %s", l[1])
477
477
478 if not lines[-1][1].endswith('\n'):
478 if not lines[-1][1].endswith('\n'):
479 fm.plain('\n')
479 fm.plain('\n')
480
480
481 fm.end()
481 fm.end()
482
482
483 @command('archive',
483 @command('archive',
484 [('', 'no-decode', None, _('do not pass files through decoders')),
484 [('', 'no-decode', None, _('do not pass files through decoders')),
485 ('p', 'prefix', '', _('directory prefix for files in archive'),
485 ('p', 'prefix', '', _('directory prefix for files in archive'),
486 _('PREFIX')),
486 _('PREFIX')),
487 ('r', 'rev', '', _('revision to distribute'), _('REV')),
487 ('r', 'rev', '', _('revision to distribute'), _('REV')),
488 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
488 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
489 ] + subrepoopts + walkopts,
489 ] + subrepoopts + walkopts,
490 _('[OPTION]... DEST'))
490 _('[OPTION]... DEST'))
491 def archive(ui, repo, dest, **opts):
491 def archive(ui, repo, dest, **opts):
492 '''create an unversioned archive of a repository revision
492 '''create an unversioned archive of a repository revision
493
493
494 By default, the revision used is the parent of the working
494 By default, the revision used is the parent of the working
495 directory; use -r/--rev to specify a different revision.
495 directory; use -r/--rev to specify a different revision.
496
496
497 The archive type is automatically detected based on file
497 The archive type is automatically detected based on file
498 extension (to override, use -t/--type).
498 extension (to override, use -t/--type).
499
499
500 .. container:: verbose
500 .. container:: verbose
501
501
502 Examples:
502 Examples:
503
503
504 - create a zip file containing the 1.0 release::
504 - create a zip file containing the 1.0 release::
505
505
506 hg archive -r 1.0 project-1.0.zip
506 hg archive -r 1.0 project-1.0.zip
507
507
508 - create a tarball excluding .hg files::
508 - create a tarball excluding .hg files::
509
509
510 hg archive project.tar.gz -X ".hg*"
510 hg archive project.tar.gz -X ".hg*"
511
511
512 Valid types are:
512 Valid types are:
513
513
514 :``files``: a directory full of files (default)
514 :``files``: a directory full of files (default)
515 :``tar``: tar archive, uncompressed
515 :``tar``: tar archive, uncompressed
516 :``tbz2``: tar archive, compressed using bzip2
516 :``tbz2``: tar archive, compressed using bzip2
517 :``tgz``: tar archive, compressed using gzip
517 :``tgz``: tar archive, compressed using gzip
518 :``uzip``: zip archive, uncompressed
518 :``uzip``: zip archive, uncompressed
519 :``zip``: zip archive, compressed using deflate
519 :``zip``: zip archive, compressed using deflate
520
520
521 The exact name of the destination archive or directory is given
521 The exact name of the destination archive or directory is given
522 using a format string; see :hg:`help export` for details.
522 using a format string; see :hg:`help export` for details.
523
523
524 Each member added to an archive file has a directory prefix
524 Each member added to an archive file has a directory prefix
525 prepended. Use -p/--prefix to specify a format string for the
525 prepended. Use -p/--prefix to specify a format string for the
526 prefix. The default is the basename of the archive, with suffixes
526 prefix. The default is the basename of the archive, with suffixes
527 removed.
527 removed.
528
528
529 Returns 0 on success.
529 Returns 0 on success.
530 '''
530 '''
531
531
532 ctx = scmutil.revsingle(repo, opts.get('rev'))
532 ctx = scmutil.revsingle(repo, opts.get('rev'))
533 if not ctx:
533 if not ctx:
534 raise error.Abort(_('no working directory: please specify a revision'))
534 raise error.Abort(_('no working directory: please specify a revision'))
535 node = ctx.node()
535 node = ctx.node()
536 dest = cmdutil.makefilename(repo, dest, node)
536 dest = cmdutil.makefilename(repo, dest, node)
537 if os.path.realpath(dest) == repo.root:
537 if os.path.realpath(dest) == repo.root:
538 raise error.Abort(_('repository root cannot be destination'))
538 raise error.Abort(_('repository root cannot be destination'))
539
539
540 kind = opts.get('type') or archival.guesskind(dest) or 'files'
540 kind = opts.get('type') or archival.guesskind(dest) or 'files'
541 prefix = opts.get('prefix')
541 prefix = opts.get('prefix')
542
542
543 if dest == '-':
543 if dest == '-':
544 if kind == 'files':
544 if kind == 'files':
545 raise error.Abort(_('cannot archive plain files to stdout'))
545 raise error.Abort(_('cannot archive plain files to stdout'))
546 dest = cmdutil.makefileobj(repo, dest)
546 dest = cmdutil.makefileobj(repo, dest)
547 if not prefix:
547 if not prefix:
548 prefix = os.path.basename(repo.root) + '-%h'
548 prefix = os.path.basename(repo.root) + '-%h'
549
549
550 prefix = cmdutil.makefilename(repo, prefix, node)
550 prefix = cmdutil.makefilename(repo, prefix, node)
551 matchfn = scmutil.match(ctx, [], opts)
551 matchfn = scmutil.match(ctx, [], opts)
552 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
552 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
553 matchfn, prefix, subrepos=opts.get('subrepos'))
553 matchfn, prefix, subrepos=opts.get('subrepos'))
554
554
555 @command('backout',
555 @command('backout',
556 [('', 'merge', None, _('merge with old dirstate parent after backout')),
556 [('', 'merge', None, _('merge with old dirstate parent after backout')),
557 ('', 'commit', None,
557 ('', 'commit', None,
558 _('commit if no conflicts were encountered (DEPRECATED)')),
558 _('commit if no conflicts were encountered (DEPRECATED)')),
559 ('', 'no-commit', None, _('do not commit')),
559 ('', 'no-commit', None, _('do not commit')),
560 ('', 'parent', '',
560 ('', 'parent', '',
561 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
561 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
562 ('r', 'rev', '', _('revision to backout'), _('REV')),
562 ('r', 'rev', '', _('revision to backout'), _('REV')),
563 ('e', 'edit', False, _('invoke editor on commit messages')),
563 ('e', 'edit', False, _('invoke editor on commit messages')),
564 ] + mergetoolopts + walkopts + commitopts + commitopts2,
564 ] + mergetoolopts + walkopts + commitopts + commitopts2,
565 _('[OPTION]... [-r] REV'))
565 _('[OPTION]... [-r] REV'))
566 def backout(ui, repo, node=None, rev=None, **opts):
566 def backout(ui, repo, node=None, rev=None, **opts):
567 '''reverse effect of earlier changeset
567 '''reverse effect of earlier changeset
568
568
569 Prepare a new changeset with the effect of REV undone in the
569 Prepare a new changeset with the effect of REV undone in the
570 current working directory. If no conflicts were encountered,
570 current working directory. If no conflicts were encountered,
571 it will be committed immediately.
571 it will be committed immediately.
572
572
573 If REV is the parent of the working directory, then this new changeset
573 If REV is the parent of the working directory, then this new changeset
574 is committed automatically (unless --no-commit is specified).
574 is committed automatically (unless --no-commit is specified).
575
575
576 .. note::
576 .. note::
577
577
578 :hg:`backout` cannot be used to fix either an unwanted or
578 :hg:`backout` cannot be used to fix either an unwanted or
579 incorrect merge.
579 incorrect merge.
580
580
581 .. container:: verbose
581 .. container:: verbose
582
582
583 Examples:
583 Examples:
584
584
585 - Reverse the effect of the parent of the working directory.
585 - Reverse the effect of the parent of the working directory.
586 This backout will be committed immediately::
586 This backout will be committed immediately::
587
587
588 hg backout -r .
588 hg backout -r .
589
589
590 - Reverse the effect of previous bad revision 23::
590 - Reverse the effect of previous bad revision 23::
591
591
592 hg backout -r 23
592 hg backout -r 23
593
593
594 - Reverse the effect of previous bad revision 23 and
594 - Reverse the effect of previous bad revision 23 and
595 leave changes uncommitted::
595 leave changes uncommitted::
596
596
597 hg backout -r 23 --no-commit
597 hg backout -r 23 --no-commit
598 hg commit -m "Backout revision 23"
598 hg commit -m "Backout revision 23"
599
599
600 By default, the pending changeset will have one parent,
600 By default, the pending changeset will have one parent,
601 maintaining a linear history. With --merge, the pending
601 maintaining a linear history. With --merge, the pending
602 changeset will instead have two parents: the old parent of the
602 changeset will instead have two parents: the old parent of the
603 working directory and a new child of REV that simply undoes REV.
603 working directory and a new child of REV that simply undoes REV.
604
604
605 Before version 1.7, the behavior without --merge was equivalent
605 Before version 1.7, the behavior without --merge was equivalent
606 to specifying --merge followed by :hg:`update --clean .` to
606 to specifying --merge followed by :hg:`update --clean .` to
607 cancel the merge and leave the child of REV as a head to be
607 cancel the merge and leave the child of REV as a head to be
608 merged separately.
608 merged separately.
609
609
610 See :hg:`help dates` for a list of formats valid for -d/--date.
610 See :hg:`help dates` for a list of formats valid for -d/--date.
611
611
612 See :hg:`help revert` for a way to restore files to the state
612 See :hg:`help revert` for a way to restore files to the state
613 of another revision.
613 of another revision.
614
614
615 Returns 0 on success, 1 if nothing to backout or there are unresolved
615 Returns 0 on success, 1 if nothing to backout or there are unresolved
616 files.
616 files.
617 '''
617 '''
618 wlock = lock = None
618 wlock = lock = None
619 try:
619 try:
620 wlock = repo.wlock()
620 wlock = repo.wlock()
621 lock = repo.lock()
621 lock = repo.lock()
622 return _dobackout(ui, repo, node, rev, **opts)
622 return _dobackout(ui, repo, node, rev, **opts)
623 finally:
623 finally:
624 release(lock, wlock)
624 release(lock, wlock)
625
625
626 def _dobackout(ui, repo, node=None, rev=None, **opts):
626 def _dobackout(ui, repo, node=None, rev=None, **opts):
627 if opts.get('commit') and opts.get('no_commit'):
627 if opts.get('commit') and opts.get('no_commit'):
628 raise error.Abort(_("cannot use --commit with --no-commit"))
628 raise error.Abort(_("cannot use --commit with --no-commit"))
629 if opts.get('merge') and opts.get('no_commit'):
629 if opts.get('merge') and opts.get('no_commit'):
630 raise error.Abort(_("cannot use --merge with --no-commit"))
630 raise error.Abort(_("cannot use --merge with --no-commit"))
631
631
632 if rev and node:
632 if rev and node:
633 raise error.Abort(_("please specify just one revision"))
633 raise error.Abort(_("please specify just one revision"))
634
634
635 if not rev:
635 if not rev:
636 rev = node
636 rev = node
637
637
638 if not rev:
638 if not rev:
639 raise error.Abort(_("please specify a revision to backout"))
639 raise error.Abort(_("please specify a revision to backout"))
640
640
641 date = opts.get('date')
641 date = opts.get('date')
642 if date:
642 if date:
643 opts['date'] = util.parsedate(date)
643 opts['date'] = util.parsedate(date)
644
644
645 cmdutil.checkunfinished(repo)
645 cmdutil.checkunfinished(repo)
646 cmdutil.bailifchanged(repo)
646 cmdutil.bailifchanged(repo)
647 node = scmutil.revsingle(repo, rev).node()
647 node = scmutil.revsingle(repo, rev).node()
648
648
649 op1, op2 = repo.dirstate.parents()
649 op1, op2 = repo.dirstate.parents()
650 if not repo.changelog.isancestor(node, op1):
650 if not repo.changelog.isancestor(node, op1):
651 raise error.Abort(_('cannot backout change that is not an ancestor'))
651 raise error.Abort(_('cannot backout change that is not an ancestor'))
652
652
653 p1, p2 = repo.changelog.parents(node)
653 p1, p2 = repo.changelog.parents(node)
654 if p1 == nullid:
654 if p1 == nullid:
655 raise error.Abort(_('cannot backout a change with no parents'))
655 raise error.Abort(_('cannot backout a change with no parents'))
656 if p2 != nullid:
656 if p2 != nullid:
657 if not opts.get('parent'):
657 if not opts.get('parent'):
658 raise error.Abort(_('cannot backout a merge changeset'))
658 raise error.Abort(_('cannot backout a merge changeset'))
659 p = repo.lookup(opts['parent'])
659 p = repo.lookup(opts['parent'])
660 if p not in (p1, p2):
660 if p not in (p1, p2):
661 raise error.Abort(_('%s is not a parent of %s') %
661 raise error.Abort(_('%s is not a parent of %s') %
662 (short(p), short(node)))
662 (short(p), short(node)))
663 parent = p
663 parent = p
664 else:
664 else:
665 if opts.get('parent'):
665 if opts.get('parent'):
666 raise error.Abort(_('cannot use --parent on non-merge changeset'))
666 raise error.Abort(_('cannot use --parent on non-merge changeset'))
667 parent = p1
667 parent = p1
668
668
669 # the backout should appear on the same branch
669 # the backout should appear on the same branch
670 branch = repo.dirstate.branch()
670 branch = repo.dirstate.branch()
671 bheads = repo.branchheads(branch)
671 bheads = repo.branchheads(branch)
672 rctx = scmutil.revsingle(repo, hex(parent))
672 rctx = scmutil.revsingle(repo, hex(parent))
673 if not opts.get('merge') and op1 != node:
673 if not opts.get('merge') and op1 != node:
674 dsguard = dirstateguard.dirstateguard(repo, 'backout')
674 dsguard = dirstateguard.dirstateguard(repo, 'backout')
675 try:
675 try:
676 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
676 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
677 'backout')
677 'backout')
678 stats = mergemod.update(repo, parent, True, True, node, False)
678 stats = mergemod.update(repo, parent, True, True, node, False)
679 repo.setparents(op1, op2)
679 repo.setparents(op1, op2)
680 dsguard.close()
680 dsguard.close()
681 hg._showstats(repo, stats)
681 hg._showstats(repo, stats)
682 if stats[3]:
682 if stats[3]:
683 repo.ui.status(_("use 'hg resolve' to retry unresolved "
683 repo.ui.status(_("use 'hg resolve' to retry unresolved "
684 "file merges\n"))
684 "file merges\n"))
685 return 1
685 return 1
686 finally:
686 finally:
687 ui.setconfig('ui', 'forcemerge', '', '')
687 ui.setconfig('ui', 'forcemerge', '', '')
688 lockmod.release(dsguard)
688 lockmod.release(dsguard)
689 else:
689 else:
690 hg.clean(repo, node, show_stats=False)
690 hg.clean(repo, node, show_stats=False)
691 repo.dirstate.setbranch(branch)
691 repo.dirstate.setbranch(branch)
692 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
692 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
693
693
694 if opts.get('no_commit'):
694 if opts.get('no_commit'):
695 msg = _("changeset %s backed out, "
695 msg = _("changeset %s backed out, "
696 "don't forget to commit.\n")
696 "don't forget to commit.\n")
697 ui.status(msg % short(node))
697 ui.status(msg % short(node))
698 return 0
698 return 0
699
699
700 def commitfunc(ui, repo, message, match, opts):
700 def commitfunc(ui, repo, message, match, opts):
701 editform = 'backout'
701 editform = 'backout'
702 e = cmdutil.getcommiteditor(editform=editform, **opts)
702 e = cmdutil.getcommiteditor(editform=editform, **opts)
703 if not message:
703 if not message:
704 # we don't translate commit messages
704 # we don't translate commit messages
705 message = "Backed out changeset %s" % short(node)
705 message = "Backed out changeset %s" % short(node)
706 e = cmdutil.getcommiteditor(edit=True, editform=editform)
706 e = cmdutil.getcommiteditor(edit=True, editform=editform)
707 return repo.commit(message, opts.get('user'), opts.get('date'),
707 return repo.commit(message, opts.get('user'), opts.get('date'),
708 match, editor=e)
708 match, editor=e)
709 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
709 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
710 if not newnode:
710 if not newnode:
711 ui.status(_("nothing changed\n"))
711 ui.status(_("nothing changed\n"))
712 return 1
712 return 1
713 cmdutil.commitstatus(repo, newnode, branch, bheads)
713 cmdutil.commitstatus(repo, newnode, branch, bheads)
714
714
715 def nice(node):
715 def nice(node):
716 return '%d:%s' % (repo.changelog.rev(node), short(node))
716 return '%d:%s' % (repo.changelog.rev(node), short(node))
717 ui.status(_('changeset %s backs out changeset %s\n') %
717 ui.status(_('changeset %s backs out changeset %s\n') %
718 (nice(repo.changelog.tip()), nice(node)))
718 (nice(repo.changelog.tip()), nice(node)))
719 if opts.get('merge') and op1 != node:
719 if opts.get('merge') and op1 != node:
720 hg.clean(repo, op1, show_stats=False)
720 hg.clean(repo, op1, show_stats=False)
721 ui.status(_('merging with changeset %s\n')
721 ui.status(_('merging with changeset %s\n')
722 % nice(repo.changelog.tip()))
722 % nice(repo.changelog.tip()))
723 try:
723 try:
724 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
724 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
725 'backout')
725 'backout')
726 return hg.merge(repo, hex(repo.changelog.tip()))
726 return hg.merge(repo, hex(repo.changelog.tip()))
727 finally:
727 finally:
728 ui.setconfig('ui', 'forcemerge', '', '')
728 ui.setconfig('ui', 'forcemerge', '', '')
729 return 0
729 return 0
730
730
731 @command('bisect',
731 @command('bisect',
732 [('r', 'reset', False, _('reset bisect state')),
732 [('r', 'reset', False, _('reset bisect state')),
733 ('g', 'good', False, _('mark changeset good')),
733 ('g', 'good', False, _('mark changeset good')),
734 ('b', 'bad', False, _('mark changeset bad')),
734 ('b', 'bad', False, _('mark changeset bad')),
735 ('s', 'skip', False, _('skip testing changeset')),
735 ('s', 'skip', False, _('skip testing changeset')),
736 ('e', 'extend', False, _('extend the bisect range')),
736 ('e', 'extend', False, _('extend the bisect range')),
737 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
737 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
738 ('U', 'noupdate', False, _('do not update to target'))],
738 ('U', 'noupdate', False, _('do not update to target'))],
739 _("[-gbsr] [-U] [-c CMD] [REV]"))
739 _("[-gbsr] [-U] [-c CMD] [REV]"))
740 def bisect(ui, repo, rev=None, extra=None, command=None,
740 def bisect(ui, repo, rev=None, extra=None, command=None,
741 reset=None, good=None, bad=None, skip=None, extend=None,
741 reset=None, good=None, bad=None, skip=None, extend=None,
742 noupdate=None):
742 noupdate=None):
743 """subdivision search of changesets
743 """subdivision search of changesets
744
744
745 This command helps to find changesets which introduce problems. To
745 This command helps to find changesets which introduce problems. To
746 use, mark the earliest changeset you know exhibits the problem as
746 use, mark the earliest changeset you know exhibits the problem as
747 bad, then mark the latest changeset which is free from the problem
747 bad, then mark the latest changeset which is free from the problem
748 as good. Bisect will update your working directory to a revision
748 as good. Bisect will update your working directory to a revision
749 for testing (unless the -U/--noupdate option is specified). Once
749 for testing (unless the -U/--noupdate option is specified). Once
750 you have performed tests, mark the working directory as good or
750 you have performed tests, mark the working directory as good or
751 bad, and bisect will either update to another candidate changeset
751 bad, and bisect will either update to another candidate changeset
752 or announce that it has found the bad revision.
752 or announce that it has found the bad revision.
753
753
754 As a shortcut, you can also use the revision argument to mark a
754 As a shortcut, you can also use the revision argument to mark a
755 revision as good or bad without checking it out first.
755 revision as good or bad without checking it out first.
756
756
757 If you supply a command, it will be used for automatic bisection.
757 If you supply a command, it will be used for automatic bisection.
758 The environment variable HG_NODE will contain the ID of the
758 The environment variable HG_NODE will contain the ID of the
759 changeset being tested. The exit status of the command will be
759 changeset being tested. The exit status of the command will be
760 used to mark revisions as good or bad: status 0 means good, 125
760 used to mark revisions as good or bad: status 0 means good, 125
761 means to skip the revision, 127 (command not found) will abort the
761 means to skip the revision, 127 (command not found) will abort the
762 bisection, and any other non-zero exit status means the revision
762 bisection, and any other non-zero exit status means the revision
763 is bad.
763 is bad.
764
764
765 .. container:: verbose
765 .. container:: verbose
766
766
767 Some examples:
767 Some examples:
768
768
769 - start a bisection with known bad revision 34, and good revision 12::
769 - start a bisection with known bad revision 34, and good revision 12::
770
770
771 hg bisect --bad 34
771 hg bisect --bad 34
772 hg bisect --good 12
772 hg bisect --good 12
773
773
774 - advance the current bisection by marking current revision as good or
774 - advance the current bisection by marking current revision as good or
775 bad::
775 bad::
776
776
777 hg bisect --good
777 hg bisect --good
778 hg bisect --bad
778 hg bisect --bad
779
779
780 - mark the current revision, or a known revision, to be skipped (e.g. if
780 - mark the current revision, or a known revision, to be skipped (e.g. if
781 that revision is not usable because of another issue)::
781 that revision is not usable because of another issue)::
782
782
783 hg bisect --skip
783 hg bisect --skip
784 hg bisect --skip 23
784 hg bisect --skip 23
785
785
786 - skip all revisions that do not touch directories ``foo`` or ``bar``::
786 - skip all revisions that do not touch directories ``foo`` or ``bar``::
787
787
788 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
788 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
789
789
790 - forget the current bisection::
790 - forget the current bisection::
791
791
792 hg bisect --reset
792 hg bisect --reset
793
793
794 - use 'make && make tests' to automatically find the first broken
794 - use 'make && make tests' to automatically find the first broken
795 revision::
795 revision::
796
796
797 hg bisect --reset
797 hg bisect --reset
798 hg bisect --bad 34
798 hg bisect --bad 34
799 hg bisect --good 12
799 hg bisect --good 12
800 hg bisect --command "make && make tests"
800 hg bisect --command "make && make tests"
801
801
802 - see all changesets whose states are already known in the current
802 - see all changesets whose states are already known in the current
803 bisection::
803 bisection::
804
804
805 hg log -r "bisect(pruned)"
805 hg log -r "bisect(pruned)"
806
806
807 - see the changeset currently being bisected (especially useful
807 - see the changeset currently being bisected (especially useful
808 if running with -U/--noupdate)::
808 if running with -U/--noupdate)::
809
809
810 hg log -r "bisect(current)"
810 hg log -r "bisect(current)"
811
811
812 - see all changesets that took part in the current bisection::
812 - see all changesets that took part in the current bisection::
813
813
814 hg log -r "bisect(range)"
814 hg log -r "bisect(range)"
815
815
816 - you can even get a nice graph::
816 - you can even get a nice graph::
817
817
818 hg log --graph -r "bisect(range)"
818 hg log --graph -r "bisect(range)"
819
819
820 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
820 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
821
821
822 Returns 0 on success.
822 Returns 0 on success.
823 """
823 """
824 # backward compatibility
824 # backward compatibility
825 if rev in "good bad reset init".split():
825 if rev in "good bad reset init".split():
826 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
826 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
827 cmd, rev, extra = rev, extra, None
827 cmd, rev, extra = rev, extra, None
828 if cmd == "good":
828 if cmd == "good":
829 good = True
829 good = True
830 elif cmd == "bad":
830 elif cmd == "bad":
831 bad = True
831 bad = True
832 else:
832 else:
833 reset = True
833 reset = True
834 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
834 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
835 raise error.Abort(_('incompatible arguments'))
835 raise error.Abort(_('incompatible arguments'))
836
836
837 cmdutil.checkunfinished(repo)
837 cmdutil.checkunfinished(repo)
838
838
839 if reset:
839 if reset:
840 hbisect.resetstate(repo)
840 hbisect.resetstate(repo)
841 return
841 return
842
842
843 state = hbisect.load_state(repo)
843 state = hbisect.load_state(repo)
844
844
845 # update state
845 # update state
846 if good or bad or skip:
846 if good or bad or skip:
847 if rev:
847 if rev:
848 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
848 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
849 else:
849 else:
850 nodes = [repo.lookup('.')]
850 nodes = [repo.lookup('.')]
851 if good:
851 if good:
852 state['good'] += nodes
852 state['good'] += nodes
853 elif bad:
853 elif bad:
854 state['bad'] += nodes
854 state['bad'] += nodes
855 elif skip:
855 elif skip:
856 state['skip'] += nodes
856 state['skip'] += nodes
857 hbisect.save_state(repo, state)
857 hbisect.save_state(repo, state)
858 if not (state['good'] and state['bad']):
858 if not (state['good'] and state['bad']):
859 return
859 return
860
860
861 def mayupdate(repo, node, show_stats=True):
861 def mayupdate(repo, node, show_stats=True):
862 """common used update sequence"""
862 """common used update sequence"""
863 if noupdate:
863 if noupdate:
864 return
864 return
865 cmdutil.bailifchanged(repo)
865 cmdutil.bailifchanged(repo)
866 return hg.clean(repo, node, show_stats=show_stats)
866 return hg.clean(repo, node, show_stats=show_stats)
867
867
868 displayer = cmdutil.show_changeset(ui, repo, {})
868 displayer = cmdutil.show_changeset(ui, repo, {})
869
869
870 if command:
870 if command:
871 changesets = 1
871 changesets = 1
872 if noupdate:
872 if noupdate:
873 try:
873 try:
874 node = state['current'][0]
874 node = state['current'][0]
875 except LookupError:
875 except LookupError:
876 raise error.Abort(_('current bisect revision is unknown - '
876 raise error.Abort(_('current bisect revision is unknown - '
877 'start a new bisect to fix'))
877 'start a new bisect to fix'))
878 else:
878 else:
879 node, p2 = repo.dirstate.parents()
879 node, p2 = repo.dirstate.parents()
880 if p2 != nullid:
880 if p2 != nullid:
881 raise error.Abort(_('current bisect revision is a merge'))
881 raise error.Abort(_('current bisect revision is a merge'))
882 if rev:
882 if rev:
883 node = repo[scmutil.revsingle(repo, rev, node)].node()
883 node = repo[scmutil.revsingle(repo, rev, node)].node()
884 try:
884 try:
885 while changesets:
885 while changesets:
886 # update state
886 # update state
887 state['current'] = [node]
887 state['current'] = [node]
888 hbisect.save_state(repo, state)
888 hbisect.save_state(repo, state)
889 status = ui.system(command, environ={'HG_NODE': hex(node)})
889 status = ui.system(command, environ={'HG_NODE': hex(node)})
890 if status == 125:
890 if status == 125:
891 transition = "skip"
891 transition = "skip"
892 elif status == 0:
892 elif status == 0:
893 transition = "good"
893 transition = "good"
894 # status < 0 means process was killed
894 # status < 0 means process was killed
895 elif status == 127:
895 elif status == 127:
896 raise error.Abort(_("failed to execute %s") % command)
896 raise error.Abort(_("failed to execute %s") % command)
897 elif status < 0:
897 elif status < 0:
898 raise error.Abort(_("%s killed") % command)
898 raise error.Abort(_("%s killed") % command)
899 else:
899 else:
900 transition = "bad"
900 transition = "bad"
901 state[transition].append(node)
901 state[transition].append(node)
902 ctx = repo[node]
902 ctx = repo[node]
903 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
903 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
904 hbisect.checkstate(state)
904 hbisect.checkstate(state)
905 # bisect
905 # bisect
906 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
906 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
907 # update to next check
907 # update to next check
908 node = nodes[0]
908 node = nodes[0]
909 mayupdate(repo, node, show_stats=False)
909 mayupdate(repo, node, show_stats=False)
910 finally:
910 finally:
911 state['current'] = [node]
911 state['current'] = [node]
912 hbisect.save_state(repo, state)
912 hbisect.save_state(repo, state)
913 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
913 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
914 return
914 return
915
915
916 hbisect.checkstate(state)
916 hbisect.checkstate(state)
917
917
918 # actually bisect
918 # actually bisect
919 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
919 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
920 if extend:
920 if extend:
921 if not changesets:
921 if not changesets:
922 extendnode = hbisect.extendrange(repo, state, nodes, good)
922 extendnode = hbisect.extendrange(repo, state, nodes, good)
923 if extendnode is not None:
923 if extendnode is not None:
924 ui.write(_("Extending search to changeset %d:%s\n")
924 ui.write(_("Extending search to changeset %d:%s\n")
925 % (extendnode.rev(), extendnode))
925 % (extendnode.rev(), extendnode))
926 state['current'] = [extendnode.node()]
926 state['current'] = [extendnode.node()]
927 hbisect.save_state(repo, state)
927 hbisect.save_state(repo, state)
928 return mayupdate(repo, extendnode.node())
928 return mayupdate(repo, extendnode.node())
929 raise error.Abort(_("nothing to extend"))
929 raise error.Abort(_("nothing to extend"))
930
930
931 if changesets == 0:
931 if changesets == 0:
932 hbisect.printresult(ui, repo, state, displayer, nodes, good)
932 hbisect.printresult(ui, repo, state, displayer, nodes, good)
933 else:
933 else:
934 assert len(nodes) == 1 # only a single node can be tested next
934 assert len(nodes) == 1 # only a single node can be tested next
935 node = nodes[0]
935 node = nodes[0]
936 # compute the approximate number of remaining tests
936 # compute the approximate number of remaining tests
937 tests, size = 0, 2
937 tests, size = 0, 2
938 while size <= changesets:
938 while size <= changesets:
939 tests, size = tests + 1, size * 2
939 tests, size = tests + 1, size * 2
940 rev = repo.changelog.rev(node)
940 rev = repo.changelog.rev(node)
941 ui.write(_("Testing changeset %d:%s "
941 ui.write(_("Testing changeset %d:%s "
942 "(%d changesets remaining, ~%d tests)\n")
942 "(%d changesets remaining, ~%d tests)\n")
943 % (rev, short(node), changesets, tests))
943 % (rev, short(node), changesets, tests))
944 state['current'] = [node]
944 state['current'] = [node]
945 hbisect.save_state(repo, state)
945 hbisect.save_state(repo, state)
946 return mayupdate(repo, node)
946 return mayupdate(repo, node)
947
947
948 @command('bookmarks|bookmark',
948 @command('bookmarks|bookmark',
949 [('f', 'force', False, _('force')),
949 [('f', 'force', False, _('force')),
950 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
950 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
951 ('d', 'delete', False, _('delete a given bookmark')),
951 ('d', 'delete', False, _('delete a given bookmark')),
952 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
952 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
953 ('i', 'inactive', False, _('mark a bookmark inactive')),
953 ('i', 'inactive', False, _('mark a bookmark inactive')),
954 ] + formatteropts,
954 ] + formatteropts,
955 _('hg bookmarks [OPTIONS]... [NAME]...'))
955 _('hg bookmarks [OPTIONS]... [NAME]...'))
956 def bookmark(ui, repo, *names, **opts):
956 def bookmark(ui, repo, *names, **opts):
957 '''create a new bookmark or list existing bookmarks
957 '''create a new bookmark or list existing bookmarks
958
958
959 Bookmarks are labels on changesets to help track lines of development.
959 Bookmarks are labels on changesets to help track lines of development.
960 Bookmarks are unversioned and can be moved, renamed and deleted.
960 Bookmarks are unversioned and can be moved, renamed and deleted.
961 Deleting or moving a bookmark has no effect on the associated changesets.
961 Deleting or moving a bookmark has no effect on the associated changesets.
962
962
963 Creating or updating to a bookmark causes it to be marked as 'active'.
963 Creating or updating to a bookmark causes it to be marked as 'active'.
964 The active bookmark is indicated with a '*'.
964 The active bookmark is indicated with a '*'.
965 When a commit is made, the active bookmark will advance to the new commit.
965 When a commit is made, the active bookmark will advance to the new commit.
966 A plain :hg:`update` will also advance an active bookmark, if possible.
966 A plain :hg:`update` will also advance an active bookmark, if possible.
967 Updating away from a bookmark will cause it to be deactivated.
967 Updating away from a bookmark will cause it to be deactivated.
968
968
969 Bookmarks can be pushed and pulled between repositories (see
969 Bookmarks can be pushed and pulled between repositories (see
970 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
970 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
971 diverged, a new 'divergent bookmark' of the form 'name@path' will
971 diverged, a new 'divergent bookmark' of the form 'name@path' will
972 be created. Using :hg:`merge` will resolve the divergence.
972 be created. Using :hg:`merge` will resolve the divergence.
973
973
974 A bookmark named '@' has the special property that :hg:`clone` will
974 A bookmark named '@' has the special property that :hg:`clone` will
975 check it out by default if it exists.
975 check it out by default if it exists.
976
976
977 .. container:: verbose
977 .. container:: verbose
978
978
979 Examples:
979 Examples:
980
980
981 - create an active bookmark for a new line of development::
981 - create an active bookmark for a new line of development::
982
982
983 hg book new-feature
983 hg book new-feature
984
984
985 - create an inactive bookmark as a place marker::
985 - create an inactive bookmark as a place marker::
986
986
987 hg book -i reviewed
987 hg book -i reviewed
988
988
989 - create an inactive bookmark on another changeset::
989 - create an inactive bookmark on another changeset::
990
990
991 hg book -r .^ tested
991 hg book -r .^ tested
992
992
993 - rename bookmark turkey to dinner::
993 - rename bookmark turkey to dinner::
994
994
995 hg book -m turkey dinner
995 hg book -m turkey dinner
996
996
997 - move the '@' bookmark from another branch::
997 - move the '@' bookmark from another branch::
998
998
999 hg book -f @
999 hg book -f @
1000 '''
1000 '''
1001 force = opts.get('force')
1001 force = opts.get('force')
1002 rev = opts.get('rev')
1002 rev = opts.get('rev')
1003 delete = opts.get('delete')
1003 delete = opts.get('delete')
1004 rename = opts.get('rename')
1004 rename = opts.get('rename')
1005 inactive = opts.get('inactive')
1005 inactive = opts.get('inactive')
1006
1006
1007 def checkformat(mark):
1007 def checkformat(mark):
1008 mark = mark.strip()
1008 mark = mark.strip()
1009 if not mark:
1009 if not mark:
1010 raise error.Abort(_("bookmark names cannot consist entirely of "
1010 raise error.Abort(_("bookmark names cannot consist entirely of "
1011 "whitespace"))
1011 "whitespace"))
1012 scmutil.checknewlabel(repo, mark, 'bookmark')
1012 scmutil.checknewlabel(repo, mark, 'bookmark')
1013 return mark
1013 return mark
1014
1014
1015 def checkconflict(repo, mark, cur, force=False, target=None):
1015 def checkconflict(repo, mark, cur, force=False, target=None):
1016 if mark in marks and not force:
1016 if mark in marks and not force:
1017 if target:
1017 if target:
1018 if marks[mark] == target and target == cur:
1018 if marks[mark] == target and target == cur:
1019 # re-activating a bookmark
1019 # re-activating a bookmark
1020 return
1020 return
1021 anc = repo.changelog.ancestors([repo[target].rev()])
1021 anc = repo.changelog.ancestors([repo[target].rev()])
1022 bmctx = repo[marks[mark]]
1022 bmctx = repo[marks[mark]]
1023 divs = [repo[b].node() for b in marks
1023 divs = [repo[b].node() for b in marks
1024 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1024 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1025
1025
1026 # allow resolving a single divergent bookmark even if moving
1026 # allow resolving a single divergent bookmark even if moving
1027 # the bookmark across branches when a revision is specified
1027 # the bookmark across branches when a revision is specified
1028 # that contains a divergent bookmark
1028 # that contains a divergent bookmark
1029 if bmctx.rev() not in anc and target in divs:
1029 if bmctx.rev() not in anc and target in divs:
1030 bookmarks.deletedivergent(repo, [target], mark)
1030 bookmarks.deletedivergent(repo, [target], mark)
1031 return
1031 return
1032
1032
1033 deletefrom = [b for b in divs
1033 deletefrom = [b for b in divs
1034 if repo[b].rev() in anc or b == target]
1034 if repo[b].rev() in anc or b == target]
1035 bookmarks.deletedivergent(repo, deletefrom, mark)
1035 bookmarks.deletedivergent(repo, deletefrom, mark)
1036 if bookmarks.validdest(repo, bmctx, repo[target]):
1036 if bookmarks.validdest(repo, bmctx, repo[target]):
1037 ui.status(_("moving bookmark '%s' forward from %s\n") %
1037 ui.status(_("moving bookmark '%s' forward from %s\n") %
1038 (mark, short(bmctx.node())))
1038 (mark, short(bmctx.node())))
1039 return
1039 return
1040 raise error.Abort(_("bookmark '%s' already exists "
1040 raise error.Abort(_("bookmark '%s' already exists "
1041 "(use -f to force)") % mark)
1041 "(use -f to force)") % mark)
1042 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1042 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1043 and not force):
1043 and not force):
1044 raise error.Abort(
1044 raise error.Abort(
1045 _("a bookmark cannot have the name of an existing branch"))
1045 _("a bookmark cannot have the name of an existing branch"))
1046
1046
1047 if delete and rename:
1047 if delete and rename:
1048 raise error.Abort(_("--delete and --rename are incompatible"))
1048 raise error.Abort(_("--delete and --rename are incompatible"))
1049 if delete and rev:
1049 if delete and rev:
1050 raise error.Abort(_("--rev is incompatible with --delete"))
1050 raise error.Abort(_("--rev is incompatible with --delete"))
1051 if rename and rev:
1051 if rename and rev:
1052 raise error.Abort(_("--rev is incompatible with --rename"))
1052 raise error.Abort(_("--rev is incompatible with --rename"))
1053 if not names and (delete or rev):
1053 if not names and (delete or rev):
1054 raise error.Abort(_("bookmark name required"))
1054 raise error.Abort(_("bookmark name required"))
1055
1055
1056 if delete or rename or names or inactive:
1056 if delete or rename or names or inactive:
1057 wlock = lock = tr = None
1057 wlock = lock = tr = None
1058 try:
1058 try:
1059 wlock = repo.wlock()
1059 wlock = repo.wlock()
1060 lock = repo.lock()
1060 lock = repo.lock()
1061 cur = repo.changectx('.').node()
1061 cur = repo.changectx('.').node()
1062 marks = repo._bookmarks
1062 marks = repo._bookmarks
1063 if delete:
1063 if delete:
1064 tr = repo.transaction('bookmark')
1064 tr = repo.transaction('bookmark')
1065 for mark in names:
1065 for mark in names:
1066 if mark not in marks:
1066 if mark not in marks:
1067 raise error.Abort(_("bookmark '%s' does not exist") %
1067 raise error.Abort(_("bookmark '%s' does not exist") %
1068 mark)
1068 mark)
1069 if mark == repo._activebookmark:
1069 if mark == repo._activebookmark:
1070 bookmarks.deactivate(repo)
1070 bookmarks.deactivate(repo)
1071 del marks[mark]
1071 del marks[mark]
1072
1072
1073 elif rename:
1073 elif rename:
1074 tr = repo.transaction('bookmark')
1074 tr = repo.transaction('bookmark')
1075 if not names:
1075 if not names:
1076 raise error.Abort(_("new bookmark name required"))
1076 raise error.Abort(_("new bookmark name required"))
1077 elif len(names) > 1:
1077 elif len(names) > 1:
1078 raise error.Abort(_("only one new bookmark name allowed"))
1078 raise error.Abort(_("only one new bookmark name allowed"))
1079 mark = checkformat(names[0])
1079 mark = checkformat(names[0])
1080 if rename not in marks:
1080 if rename not in marks:
1081 raise error.Abort(_("bookmark '%s' does not exist")
1081 raise error.Abort(_("bookmark '%s' does not exist")
1082 % rename)
1082 % rename)
1083 checkconflict(repo, mark, cur, force)
1083 checkconflict(repo, mark, cur, force)
1084 marks[mark] = marks[rename]
1084 marks[mark] = marks[rename]
1085 if repo._activebookmark == rename and not inactive:
1085 if repo._activebookmark == rename and not inactive:
1086 bookmarks.activate(repo, mark)
1086 bookmarks.activate(repo, mark)
1087 del marks[rename]
1087 del marks[rename]
1088 elif names:
1088 elif names:
1089 tr = repo.transaction('bookmark')
1089 tr = repo.transaction('bookmark')
1090 newact = None
1090 newact = None
1091 for mark in names:
1091 for mark in names:
1092 mark = checkformat(mark)
1092 mark = checkformat(mark)
1093 if newact is None:
1093 if newact is None:
1094 newact = mark
1094 newact = mark
1095 if inactive and mark == repo._activebookmark:
1095 if inactive and mark == repo._activebookmark:
1096 bookmarks.deactivate(repo)
1096 bookmarks.deactivate(repo)
1097 return
1097 return
1098 tgt = cur
1098 tgt = cur
1099 if rev:
1099 if rev:
1100 tgt = scmutil.revsingle(repo, rev).node()
1100 tgt = scmutil.revsingle(repo, rev).node()
1101 checkconflict(repo, mark, cur, force, tgt)
1101 checkconflict(repo, mark, cur, force, tgt)
1102 marks[mark] = tgt
1102 marks[mark] = tgt
1103 if not inactive and cur == marks[newact] and not rev:
1103 if not inactive and cur == marks[newact] and not rev:
1104 bookmarks.activate(repo, newact)
1104 bookmarks.activate(repo, newact)
1105 elif cur != tgt and newact == repo._activebookmark:
1105 elif cur != tgt and newact == repo._activebookmark:
1106 bookmarks.deactivate(repo)
1106 bookmarks.deactivate(repo)
1107 elif inactive:
1107 elif inactive:
1108 if len(marks) == 0:
1108 if len(marks) == 0:
1109 ui.status(_("no bookmarks set\n"))
1109 ui.status(_("no bookmarks set\n"))
1110 elif not repo._activebookmark:
1110 elif not repo._activebookmark:
1111 ui.status(_("no active bookmark\n"))
1111 ui.status(_("no active bookmark\n"))
1112 else:
1112 else:
1113 bookmarks.deactivate(repo)
1113 bookmarks.deactivate(repo)
1114 if tr is not None:
1114 if tr is not None:
1115 marks.recordchange(tr)
1115 marks.recordchange(tr)
1116 tr.close()
1116 tr.close()
1117 finally:
1117 finally:
1118 lockmod.release(tr, lock, wlock)
1118 lockmod.release(tr, lock, wlock)
1119 else: # show bookmarks
1119 else: # show bookmarks
1120 fm = ui.formatter('bookmarks', opts)
1120 fm = ui.formatter('bookmarks', opts)
1121 hexfn = fm.hexfunc
1121 hexfn = fm.hexfunc
1122 marks = repo._bookmarks
1122 marks = repo._bookmarks
1123 if len(marks) == 0 and fm.isplain():
1123 if len(marks) == 0 and fm.isplain():
1124 ui.status(_("no bookmarks set\n"))
1124 ui.status(_("no bookmarks set\n"))
1125 for bmark, n in sorted(marks.iteritems()):
1125 for bmark, n in sorted(marks.iteritems()):
1126 active = repo._activebookmark
1126 active = repo._activebookmark
1127 if bmark == active:
1127 if bmark == active:
1128 prefix, label = '*', activebookmarklabel
1128 prefix, label = '*', activebookmarklabel
1129 else:
1129 else:
1130 prefix, label = ' ', ''
1130 prefix, label = ' ', ''
1131
1131
1132 fm.startitem()
1132 fm.startitem()
1133 if not ui.quiet:
1133 if not ui.quiet:
1134 fm.plain(' %s ' % prefix, label=label)
1134 fm.plain(' %s ' % prefix, label=label)
1135 fm.write('bookmark', '%s', bmark, label=label)
1135 fm.write('bookmark', '%s', bmark, label=label)
1136 pad = " " * (25 - encoding.colwidth(bmark))
1136 pad = " " * (25 - encoding.colwidth(bmark))
1137 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1137 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1138 repo.changelog.rev(n), hexfn(n), label=label)
1138 repo.changelog.rev(n), hexfn(n), label=label)
1139 fm.data(active=(bmark == active))
1139 fm.data(active=(bmark == active))
1140 fm.plain('\n')
1140 fm.plain('\n')
1141 fm.end()
1141 fm.end()
1142
1142
1143 @command('branch',
1143 @command('branch',
1144 [('f', 'force', None,
1144 [('f', 'force', None,
1145 _('set branch name even if it shadows an existing branch')),
1145 _('set branch name even if it shadows an existing branch')),
1146 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1146 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1147 _('[-fC] [NAME]'))
1147 _('[-fC] [NAME]'))
1148 def branch(ui, repo, label=None, **opts):
1148 def branch(ui, repo, label=None, **opts):
1149 """set or show the current branch name
1149 """set or show the current branch name
1150
1150
1151 .. note::
1151 .. note::
1152
1152
1153 Branch names are permanent and global. Use :hg:`bookmark` to create a
1153 Branch names are permanent and global. Use :hg:`bookmark` to create a
1154 light-weight bookmark instead. See :hg:`help glossary` for more
1154 light-weight bookmark instead. See :hg:`help glossary` for more
1155 information about named branches and bookmarks.
1155 information about named branches and bookmarks.
1156
1156
1157 With no argument, show the current branch name. With one argument,
1157 With no argument, show the current branch name. With one argument,
1158 set the working directory branch name (the branch will not exist
1158 set the working directory branch name (the branch will not exist
1159 in the repository until the next commit). Standard practice
1159 in the repository until the next commit). Standard practice
1160 recommends that primary development take place on the 'default'
1160 recommends that primary development take place on the 'default'
1161 branch.
1161 branch.
1162
1162
1163 Unless -f/--force is specified, branch will not let you set a
1163 Unless -f/--force is specified, branch will not let you set a
1164 branch name that already exists.
1164 branch name that already exists.
1165
1165
1166 Use -C/--clean to reset the working directory branch to that of
1166 Use -C/--clean to reset the working directory branch to that of
1167 the parent of the working directory, negating a previous branch
1167 the parent of the working directory, negating a previous branch
1168 change.
1168 change.
1169
1169
1170 Use the command :hg:`update` to switch to an existing branch. Use
1170 Use the command :hg:`update` to switch to an existing branch. Use
1171 :hg:`commit --close-branch` to mark this branch head as closed.
1171 :hg:`commit --close-branch` to mark this branch head as closed.
1172 When all heads of a branch are closed, the branch will be
1172 When all heads of a branch are closed, the branch will be
1173 considered closed.
1173 considered closed.
1174
1174
1175 Returns 0 on success.
1175 Returns 0 on success.
1176 """
1176 """
1177 if label:
1177 if label:
1178 label = label.strip()
1178 label = label.strip()
1179
1179
1180 if not opts.get('clean') and not label:
1180 if not opts.get('clean') and not label:
1181 ui.write("%s\n" % repo.dirstate.branch())
1181 ui.write("%s\n" % repo.dirstate.branch())
1182 return
1182 return
1183
1183
1184 with repo.wlock():
1184 with repo.wlock():
1185 if opts.get('clean'):
1185 if opts.get('clean'):
1186 label = repo[None].p1().branch()
1186 label = repo[None].p1().branch()
1187 repo.dirstate.setbranch(label)
1187 repo.dirstate.setbranch(label)
1188 ui.status(_('reset working directory to branch %s\n') % label)
1188 ui.status(_('reset working directory to branch %s\n') % label)
1189 elif label:
1189 elif label:
1190 if not opts.get('force') and label in repo.branchmap():
1190 if not opts.get('force') and label in repo.branchmap():
1191 if label not in [p.branch() for p in repo[None].parents()]:
1191 if label not in [p.branch() for p in repo[None].parents()]:
1192 raise error.Abort(_('a branch of the same name already'
1192 raise error.Abort(_('a branch of the same name already'
1193 ' exists'),
1193 ' exists'),
1194 # i18n: "it" refers to an existing branch
1194 # i18n: "it" refers to an existing branch
1195 hint=_("use 'hg update' to switch to it"))
1195 hint=_("use 'hg update' to switch to it"))
1196 scmutil.checknewlabel(repo, label, 'branch')
1196 scmutil.checknewlabel(repo, label, 'branch')
1197 repo.dirstate.setbranch(label)
1197 repo.dirstate.setbranch(label)
1198 ui.status(_('marked working directory as branch %s\n') % label)
1198 ui.status(_('marked working directory as branch %s\n') % label)
1199
1199
1200 # find any open named branches aside from default
1200 # find any open named branches aside from default
1201 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1201 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1202 if n != "default" and not c]
1202 if n != "default" and not c]
1203 if not others:
1203 if not others:
1204 ui.status(_('(branches are permanent and global, '
1204 ui.status(_('(branches are permanent and global, '
1205 'did you want a bookmark?)\n'))
1205 'did you want a bookmark?)\n'))
1206
1206
1207 @command('branches',
1207 @command('branches',
1208 [('a', 'active', False,
1208 [('a', 'active', False,
1209 _('show only branches that have unmerged heads (DEPRECATED)')),
1209 _('show only branches that have unmerged heads (DEPRECATED)')),
1210 ('c', 'closed', False, _('show normal and closed branches')),
1210 ('c', 'closed', False, _('show normal and closed branches')),
1211 ] + formatteropts,
1211 ] + formatteropts,
1212 _('[-c]'))
1212 _('[-c]'))
1213 def branches(ui, repo, active=False, closed=False, **opts):
1213 def branches(ui, repo, active=False, closed=False, **opts):
1214 """list repository named branches
1214 """list repository named branches
1215
1215
1216 List the repository's named branches, indicating which ones are
1216 List the repository's named branches, indicating which ones are
1217 inactive. If -c/--closed is specified, also list branches which have
1217 inactive. If -c/--closed is specified, also list branches which have
1218 been marked closed (see :hg:`commit --close-branch`).
1218 been marked closed (see :hg:`commit --close-branch`).
1219
1219
1220 Use the command :hg:`update` to switch to an existing branch.
1220 Use the command :hg:`update` to switch to an existing branch.
1221
1221
1222 Returns 0.
1222 Returns 0.
1223 """
1223 """
1224
1224
1225 fm = ui.formatter('branches', opts)
1225 fm = ui.formatter('branches', opts)
1226 hexfunc = fm.hexfunc
1226 hexfunc = fm.hexfunc
1227
1227
1228 allheads = set(repo.heads())
1228 allheads = set(repo.heads())
1229 branches = []
1229 branches = []
1230 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1230 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1231 isactive = not isclosed and bool(set(heads) & allheads)
1231 isactive = not isclosed and bool(set(heads) & allheads)
1232 branches.append((tag, repo[tip], isactive, not isclosed))
1232 branches.append((tag, repo[tip], isactive, not isclosed))
1233 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1233 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1234 reverse=True)
1234 reverse=True)
1235
1235
1236 for tag, ctx, isactive, isopen in branches:
1236 for tag, ctx, isactive, isopen in branches:
1237 if active and not isactive:
1237 if active and not isactive:
1238 continue
1238 continue
1239 if isactive:
1239 if isactive:
1240 label = 'branches.active'
1240 label = 'branches.active'
1241 notice = ''
1241 notice = ''
1242 elif not isopen:
1242 elif not isopen:
1243 if not closed:
1243 if not closed:
1244 continue
1244 continue
1245 label = 'branches.closed'
1245 label = 'branches.closed'
1246 notice = _(' (closed)')
1246 notice = _(' (closed)')
1247 else:
1247 else:
1248 label = 'branches.inactive'
1248 label = 'branches.inactive'
1249 notice = _(' (inactive)')
1249 notice = _(' (inactive)')
1250 current = (tag == repo.dirstate.branch())
1250 current = (tag == repo.dirstate.branch())
1251 if current:
1251 if current:
1252 label = 'branches.current'
1252 label = 'branches.current'
1253
1253
1254 fm.startitem()
1254 fm.startitem()
1255 fm.write('branch', '%s', tag, label=label)
1255 fm.write('branch', '%s', tag, label=label)
1256 rev = ctx.rev()
1256 rev = ctx.rev()
1257 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1257 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1258 fmt = ' ' * padsize + ' %d:%s'
1258 fmt = ' ' * padsize + ' %d:%s'
1259 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1259 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1260 label='log.changeset changeset.%s' % ctx.phasestr())
1260 label='log.changeset changeset.%s' % ctx.phasestr())
1261 fm.context(ctx=ctx)
1261 fm.data(active=isactive, closed=not isopen, current=current)
1262 fm.data(active=isactive, closed=not isopen, current=current)
1262 if not ui.quiet:
1263 if not ui.quiet:
1263 fm.plain(notice)
1264 fm.plain(notice)
1264 fm.plain('\n')
1265 fm.plain('\n')
1265 fm.end()
1266 fm.end()
1266
1267
1267 @command('bundle',
1268 @command('bundle',
1268 [('f', 'force', None, _('run even when the destination is unrelated')),
1269 [('f', 'force', None, _('run even when the destination is unrelated')),
1269 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1270 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1270 _('REV')),
1271 _('REV')),
1271 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1272 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1272 _('BRANCH')),
1273 _('BRANCH')),
1273 ('', 'base', [],
1274 ('', 'base', [],
1274 _('a base changeset assumed to be available at the destination'),
1275 _('a base changeset assumed to be available at the destination'),
1275 _('REV')),
1276 _('REV')),
1276 ('a', 'all', None, _('bundle all changesets in the repository')),
1277 ('a', 'all', None, _('bundle all changesets in the repository')),
1277 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1278 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1278 ] + remoteopts,
1279 ] + remoteopts,
1279 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1280 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1280 def bundle(ui, repo, fname, dest=None, **opts):
1281 def bundle(ui, repo, fname, dest=None, **opts):
1281 """create a changegroup file
1282 """create a changegroup file
1282
1283
1283 Generate a changegroup file collecting changesets to be added
1284 Generate a changegroup file collecting changesets to be added
1284 to a repository.
1285 to a repository.
1285
1286
1286 To create a bundle containing all changesets, use -a/--all
1287 To create a bundle containing all changesets, use -a/--all
1287 (or --base null). Otherwise, hg assumes the destination will have
1288 (or --base null). Otherwise, hg assumes the destination will have
1288 all the nodes you specify with --base parameters. Otherwise, hg
1289 all the nodes you specify with --base parameters. Otherwise, hg
1289 will assume the repository has all the nodes in destination, or
1290 will assume the repository has all the nodes in destination, or
1290 default-push/default if no destination is specified.
1291 default-push/default if no destination is specified.
1291
1292
1292 You can change bundle format with the -t/--type option. You can
1293 You can change bundle format with the -t/--type option. You can
1293 specify a compression, a bundle version or both using a dash
1294 specify a compression, a bundle version or both using a dash
1294 (comp-version). The available compression methods are: none, bzip2,
1295 (comp-version). The available compression methods are: none, bzip2,
1295 and gzip (by default, bundles are compressed using bzip2). The
1296 and gzip (by default, bundles are compressed using bzip2). The
1296 available formats are: v1, v2 (default to most suitable).
1297 available formats are: v1, v2 (default to most suitable).
1297
1298
1298 The bundle file can then be transferred using conventional means
1299 The bundle file can then be transferred using conventional means
1299 and applied to another repository with the unbundle or pull
1300 and applied to another repository with the unbundle or pull
1300 command. This is useful when direct push and pull are not
1301 command. This is useful when direct push and pull are not
1301 available or when exporting an entire repository is undesirable.
1302 available or when exporting an entire repository is undesirable.
1302
1303
1303 Applying bundles preserves all changeset contents including
1304 Applying bundles preserves all changeset contents including
1304 permissions, copy/rename information, and revision history.
1305 permissions, copy/rename information, and revision history.
1305
1306
1306 Returns 0 on success, 1 if no changes found.
1307 Returns 0 on success, 1 if no changes found.
1307 """
1308 """
1308 revs = None
1309 revs = None
1309 if 'rev' in opts:
1310 if 'rev' in opts:
1310 revstrings = opts['rev']
1311 revstrings = opts['rev']
1311 revs = scmutil.revrange(repo, revstrings)
1312 revs = scmutil.revrange(repo, revstrings)
1312 if revstrings and not revs:
1313 if revstrings and not revs:
1313 raise error.Abort(_('no commits to bundle'))
1314 raise error.Abort(_('no commits to bundle'))
1314
1315
1315 bundletype = opts.get('type', 'bzip2').lower()
1316 bundletype = opts.get('type', 'bzip2').lower()
1316 try:
1317 try:
1317 bcompression, cgversion, params = exchange.parsebundlespec(
1318 bcompression, cgversion, params = exchange.parsebundlespec(
1318 repo, bundletype, strict=False)
1319 repo, bundletype, strict=False)
1319 except error.UnsupportedBundleSpecification as e:
1320 except error.UnsupportedBundleSpecification as e:
1320 raise error.Abort(str(e),
1321 raise error.Abort(str(e),
1321 hint=_("see 'hg help bundle' for supported "
1322 hint=_("see 'hg help bundle' for supported "
1322 "values for --type"))
1323 "values for --type"))
1323
1324
1324 # Packed bundles are a pseudo bundle format for now.
1325 # Packed bundles are a pseudo bundle format for now.
1325 if cgversion == 's1':
1326 if cgversion == 's1':
1326 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1327 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1327 hint=_("use 'hg debugcreatestreamclonebundle'"))
1328 hint=_("use 'hg debugcreatestreamclonebundle'"))
1328
1329
1329 if opts.get('all'):
1330 if opts.get('all'):
1330 if dest:
1331 if dest:
1331 raise error.Abort(_("--all is incompatible with specifying "
1332 raise error.Abort(_("--all is incompatible with specifying "
1332 "a destination"))
1333 "a destination"))
1333 if opts.get('base'):
1334 if opts.get('base'):
1334 ui.warn(_("ignoring --base because --all was specified\n"))
1335 ui.warn(_("ignoring --base because --all was specified\n"))
1335 base = ['null']
1336 base = ['null']
1336 else:
1337 else:
1337 base = scmutil.revrange(repo, opts.get('base'))
1338 base = scmutil.revrange(repo, opts.get('base'))
1338 # TODO: get desired bundlecaps from command line.
1339 # TODO: get desired bundlecaps from command line.
1339 bundlecaps = None
1340 bundlecaps = None
1340 if cgversion not in changegroup.supportedoutgoingversions(repo):
1341 if cgversion not in changegroup.supportedoutgoingversions(repo):
1341 raise error.Abort(_("repository does not support bundle version %s") %
1342 raise error.Abort(_("repository does not support bundle version %s") %
1342 cgversion)
1343 cgversion)
1343
1344
1344 if base:
1345 if base:
1345 if dest:
1346 if dest:
1346 raise error.Abort(_("--base is incompatible with specifying "
1347 raise error.Abort(_("--base is incompatible with specifying "
1347 "a destination"))
1348 "a destination"))
1348 common = [repo.lookup(rev) for rev in base]
1349 common = [repo.lookup(rev) for rev in base]
1349 heads = revs and map(repo.lookup, revs) or None
1350 heads = revs and map(repo.lookup, revs) or None
1350 outgoing = discovery.outgoing(repo, common, heads)
1351 outgoing = discovery.outgoing(repo, common, heads)
1351 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1352 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1352 bundlecaps=bundlecaps,
1353 bundlecaps=bundlecaps,
1353 version=cgversion)
1354 version=cgversion)
1354 outgoing = None
1355 outgoing = None
1355 else:
1356 else:
1356 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1357 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1357 dest, branches = hg.parseurl(dest, opts.get('branch'))
1358 dest, branches = hg.parseurl(dest, opts.get('branch'))
1358 other = hg.peer(repo, opts, dest)
1359 other = hg.peer(repo, opts, dest)
1359 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1360 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1360 heads = revs and map(repo.lookup, revs) or revs
1361 heads = revs and map(repo.lookup, revs) or revs
1361 outgoing = discovery.findcommonoutgoing(repo, other,
1362 outgoing = discovery.findcommonoutgoing(repo, other,
1362 onlyheads=heads,
1363 onlyheads=heads,
1363 force=opts.get('force'),
1364 force=opts.get('force'),
1364 portable=True)
1365 portable=True)
1365 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1366 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1366 bundlecaps, version=cgversion)
1367 bundlecaps, version=cgversion)
1367 if not cg:
1368 if not cg:
1368 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1369 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1369 return 1
1370 return 1
1370
1371
1371 if cgversion == '01': #bundle1
1372 if cgversion == '01': #bundle1
1372 if bcompression is None:
1373 if bcompression is None:
1373 bcompression = 'UN'
1374 bcompression = 'UN'
1374 bversion = 'HG10' + bcompression
1375 bversion = 'HG10' + bcompression
1375 bcompression = None
1376 bcompression = None
1376 else:
1377 else:
1377 assert cgversion == '02'
1378 assert cgversion == '02'
1378 bversion = 'HG20'
1379 bversion = 'HG20'
1379
1380
1380 # TODO compression options should be derived from bundlespec parsing.
1381 # TODO compression options should be derived from bundlespec parsing.
1381 # This is a temporary hack to allow adjusting bundle compression
1382 # This is a temporary hack to allow adjusting bundle compression
1382 # level without a) formalizing the bundlespec changes to declare it
1383 # level without a) formalizing the bundlespec changes to declare it
1383 # b) introducing a command flag.
1384 # b) introducing a command flag.
1384 compopts = {}
1385 compopts = {}
1385 complevel = ui.configint('experimental', 'bundlecomplevel')
1386 complevel = ui.configint('experimental', 'bundlecomplevel')
1386 if complevel is not None:
1387 if complevel is not None:
1387 compopts['level'] = complevel
1388 compopts['level'] = complevel
1388
1389
1389 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1390 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1390 compopts=compopts)
1391 compopts=compopts)
1391
1392
1392 @command('cat',
1393 @command('cat',
1393 [('o', 'output', '',
1394 [('o', 'output', '',
1394 _('print output to file with formatted name'), _('FORMAT')),
1395 _('print output to file with formatted name'), _('FORMAT')),
1395 ('r', 'rev', '', _('print the given revision'), _('REV')),
1396 ('r', 'rev', '', _('print the given revision'), _('REV')),
1396 ('', 'decode', None, _('apply any matching decode filter')),
1397 ('', 'decode', None, _('apply any matching decode filter')),
1397 ] + walkopts,
1398 ] + walkopts,
1398 _('[OPTION]... FILE...'),
1399 _('[OPTION]... FILE...'),
1399 inferrepo=True)
1400 inferrepo=True)
1400 def cat(ui, repo, file1, *pats, **opts):
1401 def cat(ui, repo, file1, *pats, **opts):
1401 """output the current or given revision of files
1402 """output the current or given revision of files
1402
1403
1403 Print the specified files as they were at the given revision. If
1404 Print the specified files as they were at the given revision. If
1404 no revision is given, the parent of the working directory is used.
1405 no revision is given, the parent of the working directory is used.
1405
1406
1406 Output may be to a file, in which case the name of the file is
1407 Output may be to a file, in which case the name of the file is
1407 given using a format string. The formatting rules as follows:
1408 given using a format string. The formatting rules as follows:
1408
1409
1409 :``%%``: literal "%" character
1410 :``%%``: literal "%" character
1410 :``%s``: basename of file being printed
1411 :``%s``: basename of file being printed
1411 :``%d``: dirname of file being printed, or '.' if in repository root
1412 :``%d``: dirname of file being printed, or '.' if in repository root
1412 :``%p``: root-relative path name of file being printed
1413 :``%p``: root-relative path name of file being printed
1413 :``%H``: changeset hash (40 hexadecimal digits)
1414 :``%H``: changeset hash (40 hexadecimal digits)
1414 :``%R``: changeset revision number
1415 :``%R``: changeset revision number
1415 :``%h``: short-form changeset hash (12 hexadecimal digits)
1416 :``%h``: short-form changeset hash (12 hexadecimal digits)
1416 :``%r``: zero-padded changeset revision number
1417 :``%r``: zero-padded changeset revision number
1417 :``%b``: basename of the exporting repository
1418 :``%b``: basename of the exporting repository
1418
1419
1419 Returns 0 on success.
1420 Returns 0 on success.
1420 """
1421 """
1421 ctx = scmutil.revsingle(repo, opts.get('rev'))
1422 ctx = scmutil.revsingle(repo, opts.get('rev'))
1422 m = scmutil.match(ctx, (file1,) + pats, opts)
1423 m = scmutil.match(ctx, (file1,) + pats, opts)
1423
1424
1424 ui.pager('cat')
1425 ui.pager('cat')
1425 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1426 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1426
1427
1427 @command('^clone',
1428 @command('^clone',
1428 [('U', 'noupdate', None, _('the clone will include an empty working '
1429 [('U', 'noupdate', None, _('the clone will include an empty working '
1429 'directory (only a repository)')),
1430 'directory (only a repository)')),
1430 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1431 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1431 _('REV')),
1432 _('REV')),
1432 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1433 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1433 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1434 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1434 ('', 'pull', None, _('use pull protocol to copy metadata')),
1435 ('', 'pull', None, _('use pull protocol to copy metadata')),
1435 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1436 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1436 ] + remoteopts,
1437 ] + remoteopts,
1437 _('[OPTION]... SOURCE [DEST]'),
1438 _('[OPTION]... SOURCE [DEST]'),
1438 norepo=True)
1439 norepo=True)
1439 def clone(ui, source, dest=None, **opts):
1440 def clone(ui, source, dest=None, **opts):
1440 """make a copy of an existing repository
1441 """make a copy of an existing repository
1441
1442
1442 Create a copy of an existing repository in a new directory.
1443 Create a copy of an existing repository in a new directory.
1443
1444
1444 If no destination directory name is specified, it defaults to the
1445 If no destination directory name is specified, it defaults to the
1445 basename of the source.
1446 basename of the source.
1446
1447
1447 The location of the source is added to the new repository's
1448 The location of the source is added to the new repository's
1448 ``.hg/hgrc`` file, as the default to be used for future pulls.
1449 ``.hg/hgrc`` file, as the default to be used for future pulls.
1449
1450
1450 Only local paths and ``ssh://`` URLs are supported as
1451 Only local paths and ``ssh://`` URLs are supported as
1451 destinations. For ``ssh://`` destinations, no working directory or
1452 destinations. For ``ssh://`` destinations, no working directory or
1452 ``.hg/hgrc`` will be created on the remote side.
1453 ``.hg/hgrc`` will be created on the remote side.
1453
1454
1454 If the source repository has a bookmark called '@' set, that
1455 If the source repository has a bookmark called '@' set, that
1455 revision will be checked out in the new repository by default.
1456 revision will be checked out in the new repository by default.
1456
1457
1457 To check out a particular version, use -u/--update, or
1458 To check out a particular version, use -u/--update, or
1458 -U/--noupdate to create a clone with no working directory.
1459 -U/--noupdate to create a clone with no working directory.
1459
1460
1460 To pull only a subset of changesets, specify one or more revisions
1461 To pull only a subset of changesets, specify one or more revisions
1461 identifiers with -r/--rev or branches with -b/--branch. The
1462 identifiers with -r/--rev or branches with -b/--branch. The
1462 resulting clone will contain only the specified changesets and
1463 resulting clone will contain only the specified changesets and
1463 their ancestors. These options (or 'clone src#rev dest') imply
1464 their ancestors. These options (or 'clone src#rev dest') imply
1464 --pull, even for local source repositories.
1465 --pull, even for local source repositories.
1465
1466
1466 .. note::
1467 .. note::
1467
1468
1468 Specifying a tag will include the tagged changeset but not the
1469 Specifying a tag will include the tagged changeset but not the
1469 changeset containing the tag.
1470 changeset containing the tag.
1470
1471
1471 .. container:: verbose
1472 .. container:: verbose
1472
1473
1473 For efficiency, hardlinks are used for cloning whenever the
1474 For efficiency, hardlinks are used for cloning whenever the
1474 source and destination are on the same filesystem (note this
1475 source and destination are on the same filesystem (note this
1475 applies only to the repository data, not to the working
1476 applies only to the repository data, not to the working
1476 directory). Some filesystems, such as AFS, implement hardlinking
1477 directory). Some filesystems, such as AFS, implement hardlinking
1477 incorrectly, but do not report errors. In these cases, use the
1478 incorrectly, but do not report errors. In these cases, use the
1478 --pull option to avoid hardlinking.
1479 --pull option to avoid hardlinking.
1479
1480
1480 In some cases, you can clone repositories and the working
1481 In some cases, you can clone repositories and the working
1481 directory using full hardlinks with ::
1482 directory using full hardlinks with ::
1482
1483
1483 $ cp -al REPO REPOCLONE
1484 $ cp -al REPO REPOCLONE
1484
1485
1485 This is the fastest way to clone, but it is not always safe. The
1486 This is the fastest way to clone, but it is not always safe. The
1486 operation is not atomic (making sure REPO is not modified during
1487 operation is not atomic (making sure REPO is not modified during
1487 the operation is up to you) and you have to make sure your
1488 the operation is up to you) and you have to make sure your
1488 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1489 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1489 so). Also, this is not compatible with certain extensions that
1490 so). Also, this is not compatible with certain extensions that
1490 place their metadata under the .hg directory, such as mq.
1491 place their metadata under the .hg directory, such as mq.
1491
1492
1492 Mercurial will update the working directory to the first applicable
1493 Mercurial will update the working directory to the first applicable
1493 revision from this list:
1494 revision from this list:
1494
1495
1495 a) null if -U or the source repository has no changesets
1496 a) null if -U or the source repository has no changesets
1496 b) if -u . and the source repository is local, the first parent of
1497 b) if -u . and the source repository is local, the first parent of
1497 the source repository's working directory
1498 the source repository's working directory
1498 c) the changeset specified with -u (if a branch name, this means the
1499 c) the changeset specified with -u (if a branch name, this means the
1499 latest head of that branch)
1500 latest head of that branch)
1500 d) the changeset specified with -r
1501 d) the changeset specified with -r
1501 e) the tipmost head specified with -b
1502 e) the tipmost head specified with -b
1502 f) the tipmost head specified with the url#branch source syntax
1503 f) the tipmost head specified with the url#branch source syntax
1503 g) the revision marked with the '@' bookmark, if present
1504 g) the revision marked with the '@' bookmark, if present
1504 h) the tipmost head of the default branch
1505 h) the tipmost head of the default branch
1505 i) tip
1506 i) tip
1506
1507
1507 When cloning from servers that support it, Mercurial may fetch
1508 When cloning from servers that support it, Mercurial may fetch
1508 pre-generated data from a server-advertised URL. When this is done,
1509 pre-generated data from a server-advertised URL. When this is done,
1509 hooks operating on incoming changesets and changegroups may fire twice,
1510 hooks operating on incoming changesets and changegroups may fire twice,
1510 once for the bundle fetched from the URL and another for any additional
1511 once for the bundle fetched from the URL and another for any additional
1511 data not fetched from this URL. In addition, if an error occurs, the
1512 data not fetched from this URL. In addition, if an error occurs, the
1512 repository may be rolled back to a partial clone. This behavior may
1513 repository may be rolled back to a partial clone. This behavior may
1513 change in future releases. See :hg:`help -e clonebundles` for more.
1514 change in future releases. See :hg:`help -e clonebundles` for more.
1514
1515
1515 Examples:
1516 Examples:
1516
1517
1517 - clone a remote repository to a new directory named hg/::
1518 - clone a remote repository to a new directory named hg/::
1518
1519
1519 hg clone https://www.mercurial-scm.org/repo/hg/
1520 hg clone https://www.mercurial-scm.org/repo/hg/
1520
1521
1521 - create a lightweight local clone::
1522 - create a lightweight local clone::
1522
1523
1523 hg clone project/ project-feature/
1524 hg clone project/ project-feature/
1524
1525
1525 - clone from an absolute path on an ssh server (note double-slash)::
1526 - clone from an absolute path on an ssh server (note double-slash)::
1526
1527
1527 hg clone ssh://user@server//home/projects/alpha/
1528 hg clone ssh://user@server//home/projects/alpha/
1528
1529
1529 - do a high-speed clone over a LAN while checking out a
1530 - do a high-speed clone over a LAN while checking out a
1530 specified version::
1531 specified version::
1531
1532
1532 hg clone --uncompressed http://server/repo -u 1.5
1533 hg clone --uncompressed http://server/repo -u 1.5
1533
1534
1534 - create a repository without changesets after a particular revision::
1535 - create a repository without changesets after a particular revision::
1535
1536
1536 hg clone -r 04e544 experimental/ good/
1537 hg clone -r 04e544 experimental/ good/
1537
1538
1538 - clone (and track) a particular named branch::
1539 - clone (and track) a particular named branch::
1539
1540
1540 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1541 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1541
1542
1542 See :hg:`help urls` for details on specifying URLs.
1543 See :hg:`help urls` for details on specifying URLs.
1543
1544
1544 Returns 0 on success.
1545 Returns 0 on success.
1545 """
1546 """
1546 if opts.get('noupdate') and opts.get('updaterev'):
1547 if opts.get('noupdate') and opts.get('updaterev'):
1547 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1548 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1548
1549
1549 r = hg.clone(ui, opts, source, dest,
1550 r = hg.clone(ui, opts, source, dest,
1550 pull=opts.get('pull'),
1551 pull=opts.get('pull'),
1551 stream=opts.get('uncompressed'),
1552 stream=opts.get('uncompressed'),
1552 rev=opts.get('rev'),
1553 rev=opts.get('rev'),
1553 update=opts.get('updaterev') or not opts.get('noupdate'),
1554 update=opts.get('updaterev') or not opts.get('noupdate'),
1554 branch=opts.get('branch'),
1555 branch=opts.get('branch'),
1555 shareopts=opts.get('shareopts'))
1556 shareopts=opts.get('shareopts'))
1556
1557
1557 return r is None
1558 return r is None
1558
1559
1559 @command('^commit|ci',
1560 @command('^commit|ci',
1560 [('A', 'addremove', None,
1561 [('A', 'addremove', None,
1561 _('mark new/missing files as added/removed before committing')),
1562 _('mark new/missing files as added/removed before committing')),
1562 ('', 'close-branch', None,
1563 ('', 'close-branch', None,
1563 _('mark a branch head as closed')),
1564 _('mark a branch head as closed')),
1564 ('', 'amend', None, _('amend the parent of the working directory')),
1565 ('', 'amend', None, _('amend the parent of the working directory')),
1565 ('s', 'secret', None, _('use the secret phase for committing')),
1566 ('s', 'secret', None, _('use the secret phase for committing')),
1566 ('e', 'edit', None, _('invoke editor on commit messages')),
1567 ('e', 'edit', None, _('invoke editor on commit messages')),
1567 ('i', 'interactive', None, _('use interactive mode')),
1568 ('i', 'interactive', None, _('use interactive mode')),
1568 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1569 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1569 _('[OPTION]... [FILE]...'),
1570 _('[OPTION]... [FILE]...'),
1570 inferrepo=True)
1571 inferrepo=True)
1571 def commit(ui, repo, *pats, **opts):
1572 def commit(ui, repo, *pats, **opts):
1572 """commit the specified files or all outstanding changes
1573 """commit the specified files or all outstanding changes
1573
1574
1574 Commit changes to the given files into the repository. Unlike a
1575 Commit changes to the given files into the repository. Unlike a
1575 centralized SCM, this operation is a local operation. See
1576 centralized SCM, this operation is a local operation. See
1576 :hg:`push` for a way to actively distribute your changes.
1577 :hg:`push` for a way to actively distribute your changes.
1577
1578
1578 If a list of files is omitted, all changes reported by :hg:`status`
1579 If a list of files is omitted, all changes reported by :hg:`status`
1579 will be committed.
1580 will be committed.
1580
1581
1581 If you are committing the result of a merge, do not provide any
1582 If you are committing the result of a merge, do not provide any
1582 filenames or -I/-X filters.
1583 filenames or -I/-X filters.
1583
1584
1584 If no commit message is specified, Mercurial starts your
1585 If no commit message is specified, Mercurial starts your
1585 configured editor where you can enter a message. In case your
1586 configured editor where you can enter a message. In case your
1586 commit fails, you will find a backup of your message in
1587 commit fails, you will find a backup of your message in
1587 ``.hg/last-message.txt``.
1588 ``.hg/last-message.txt``.
1588
1589
1589 The --close-branch flag can be used to mark the current branch
1590 The --close-branch flag can be used to mark the current branch
1590 head closed. When all heads of a branch are closed, the branch
1591 head closed. When all heads of a branch are closed, the branch
1591 will be considered closed and no longer listed.
1592 will be considered closed and no longer listed.
1592
1593
1593 The --amend flag can be used to amend the parent of the
1594 The --amend flag can be used to amend the parent of the
1594 working directory with a new commit that contains the changes
1595 working directory with a new commit that contains the changes
1595 in the parent in addition to those currently reported by :hg:`status`,
1596 in the parent in addition to those currently reported by :hg:`status`,
1596 if there are any. The old commit is stored in a backup bundle in
1597 if there are any. The old commit is stored in a backup bundle in
1597 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1598 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1598 on how to restore it).
1599 on how to restore it).
1599
1600
1600 Message, user and date are taken from the amended commit unless
1601 Message, user and date are taken from the amended commit unless
1601 specified. When a message isn't specified on the command line,
1602 specified. When a message isn't specified on the command line,
1602 the editor will open with the message of the amended commit.
1603 the editor will open with the message of the amended commit.
1603
1604
1604 It is not possible to amend public changesets (see :hg:`help phases`)
1605 It is not possible to amend public changesets (see :hg:`help phases`)
1605 or changesets that have children.
1606 or changesets that have children.
1606
1607
1607 See :hg:`help dates` for a list of formats valid for -d/--date.
1608 See :hg:`help dates` for a list of formats valid for -d/--date.
1608
1609
1609 Returns 0 on success, 1 if nothing changed.
1610 Returns 0 on success, 1 if nothing changed.
1610
1611
1611 .. container:: verbose
1612 .. container:: verbose
1612
1613
1613 Examples:
1614 Examples:
1614
1615
1615 - commit all files ending in .py::
1616 - commit all files ending in .py::
1616
1617
1617 hg commit --include "set:**.py"
1618 hg commit --include "set:**.py"
1618
1619
1619 - commit all non-binary files::
1620 - commit all non-binary files::
1620
1621
1621 hg commit --exclude "set:binary()"
1622 hg commit --exclude "set:binary()"
1622
1623
1623 - amend the current commit and set the date to now::
1624 - amend the current commit and set the date to now::
1624
1625
1625 hg commit --amend --date now
1626 hg commit --amend --date now
1626 """
1627 """
1627 wlock = lock = None
1628 wlock = lock = None
1628 try:
1629 try:
1629 wlock = repo.wlock()
1630 wlock = repo.wlock()
1630 lock = repo.lock()
1631 lock = repo.lock()
1631 return _docommit(ui, repo, *pats, **opts)
1632 return _docommit(ui, repo, *pats, **opts)
1632 finally:
1633 finally:
1633 release(lock, wlock)
1634 release(lock, wlock)
1634
1635
1635 def _docommit(ui, repo, *pats, **opts):
1636 def _docommit(ui, repo, *pats, **opts):
1636 if opts.get('interactive'):
1637 if opts.get('interactive'):
1637 opts.pop('interactive')
1638 opts.pop('interactive')
1638 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1639 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1639 cmdutil.recordfilter, *pats, **opts)
1640 cmdutil.recordfilter, *pats, **opts)
1640 # ret can be 0 (no changes to record) or the value returned by
1641 # ret can be 0 (no changes to record) or the value returned by
1641 # commit(), 1 if nothing changed or None on success.
1642 # commit(), 1 if nothing changed or None on success.
1642 return 1 if ret == 0 else ret
1643 return 1 if ret == 0 else ret
1643
1644
1644 if opts.get('subrepos'):
1645 if opts.get('subrepos'):
1645 if opts.get('amend'):
1646 if opts.get('amend'):
1646 raise error.Abort(_('cannot amend with --subrepos'))
1647 raise error.Abort(_('cannot amend with --subrepos'))
1647 # Let --subrepos on the command line override config setting.
1648 # Let --subrepos on the command line override config setting.
1648 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1649 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1649
1650
1650 cmdutil.checkunfinished(repo, commit=True)
1651 cmdutil.checkunfinished(repo, commit=True)
1651
1652
1652 branch = repo[None].branch()
1653 branch = repo[None].branch()
1653 bheads = repo.branchheads(branch)
1654 bheads = repo.branchheads(branch)
1654
1655
1655 extra = {}
1656 extra = {}
1656 if opts.get('close_branch'):
1657 if opts.get('close_branch'):
1657 extra['close'] = 1
1658 extra['close'] = 1
1658
1659
1659 if not bheads:
1660 if not bheads:
1660 raise error.Abort(_('can only close branch heads'))
1661 raise error.Abort(_('can only close branch heads'))
1661 elif opts.get('amend'):
1662 elif opts.get('amend'):
1662 if repo[None].parents()[0].p1().branch() != branch and \
1663 if repo[None].parents()[0].p1().branch() != branch and \
1663 repo[None].parents()[0].p2().branch() != branch:
1664 repo[None].parents()[0].p2().branch() != branch:
1664 raise error.Abort(_('can only close branch heads'))
1665 raise error.Abort(_('can only close branch heads'))
1665
1666
1666 if opts.get('amend'):
1667 if opts.get('amend'):
1667 if ui.configbool('ui', 'commitsubrepos'):
1668 if ui.configbool('ui', 'commitsubrepos'):
1668 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1669 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1669
1670
1670 old = repo['.']
1671 old = repo['.']
1671 if not old.mutable():
1672 if not old.mutable():
1672 raise error.Abort(_('cannot amend public changesets'))
1673 raise error.Abort(_('cannot amend public changesets'))
1673 if len(repo[None].parents()) > 1:
1674 if len(repo[None].parents()) > 1:
1674 raise error.Abort(_('cannot amend while merging'))
1675 raise error.Abort(_('cannot amend while merging'))
1675 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1676 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1676 if not allowunstable and old.children():
1677 if not allowunstable and old.children():
1677 raise error.Abort(_('cannot amend changeset with children'))
1678 raise error.Abort(_('cannot amend changeset with children'))
1678
1679
1679 # Currently histedit gets confused if an amend happens while histedit
1680 # Currently histedit gets confused if an amend happens while histedit
1680 # is in progress. Since we have a checkunfinished command, we are
1681 # is in progress. Since we have a checkunfinished command, we are
1681 # temporarily honoring it.
1682 # temporarily honoring it.
1682 #
1683 #
1683 # Note: eventually this guard will be removed. Please do not expect
1684 # Note: eventually this guard will be removed. Please do not expect
1684 # this behavior to remain.
1685 # this behavior to remain.
1685 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1686 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1686 cmdutil.checkunfinished(repo)
1687 cmdutil.checkunfinished(repo)
1687
1688
1688 # commitfunc is used only for temporary amend commit by cmdutil.amend
1689 # commitfunc is used only for temporary amend commit by cmdutil.amend
1689 def commitfunc(ui, repo, message, match, opts):
1690 def commitfunc(ui, repo, message, match, opts):
1690 return repo.commit(message,
1691 return repo.commit(message,
1691 opts.get('user') or old.user(),
1692 opts.get('user') or old.user(),
1692 opts.get('date') or old.date(),
1693 opts.get('date') or old.date(),
1693 match,
1694 match,
1694 extra=extra)
1695 extra=extra)
1695
1696
1696 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1697 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1697 if node == old.node():
1698 if node == old.node():
1698 ui.status(_("nothing changed\n"))
1699 ui.status(_("nothing changed\n"))
1699 return 1
1700 return 1
1700 else:
1701 else:
1701 def commitfunc(ui, repo, message, match, opts):
1702 def commitfunc(ui, repo, message, match, opts):
1702 backup = ui.backupconfig('phases', 'new-commit')
1703 backup = ui.backupconfig('phases', 'new-commit')
1703 baseui = repo.baseui
1704 baseui = repo.baseui
1704 basebackup = baseui.backupconfig('phases', 'new-commit')
1705 basebackup = baseui.backupconfig('phases', 'new-commit')
1705 try:
1706 try:
1706 if opts.get('secret'):
1707 if opts.get('secret'):
1707 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1708 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1708 # Propagate to subrepos
1709 # Propagate to subrepos
1709 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1710 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1710
1711
1711 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1712 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1712 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1713 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1713 return repo.commit(message, opts.get('user'), opts.get('date'),
1714 return repo.commit(message, opts.get('user'), opts.get('date'),
1714 match,
1715 match,
1715 editor=editor,
1716 editor=editor,
1716 extra=extra)
1717 extra=extra)
1717 finally:
1718 finally:
1718 ui.restoreconfig(backup)
1719 ui.restoreconfig(backup)
1719 repo.baseui.restoreconfig(basebackup)
1720 repo.baseui.restoreconfig(basebackup)
1720
1721
1721
1722
1722 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1723 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1723
1724
1724 if not node:
1725 if not node:
1725 stat = cmdutil.postcommitstatus(repo, pats, opts)
1726 stat = cmdutil.postcommitstatus(repo, pats, opts)
1726 if stat[3]:
1727 if stat[3]:
1727 ui.status(_("nothing changed (%d missing files, see "
1728 ui.status(_("nothing changed (%d missing files, see "
1728 "'hg status')\n") % len(stat[3]))
1729 "'hg status')\n") % len(stat[3]))
1729 else:
1730 else:
1730 ui.status(_("nothing changed\n"))
1731 ui.status(_("nothing changed\n"))
1731 return 1
1732 return 1
1732
1733
1733 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1734 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1734
1735
1735 @command('config|showconfig|debugconfig',
1736 @command('config|showconfig|debugconfig',
1736 [('u', 'untrusted', None, _('show untrusted configuration options')),
1737 [('u', 'untrusted', None, _('show untrusted configuration options')),
1737 ('e', 'edit', None, _('edit user config')),
1738 ('e', 'edit', None, _('edit user config')),
1738 ('l', 'local', None, _('edit repository config')),
1739 ('l', 'local', None, _('edit repository config')),
1739 ('g', 'global', None, _('edit global config'))] + formatteropts,
1740 ('g', 'global', None, _('edit global config'))] + formatteropts,
1740 _('[-u] [NAME]...'),
1741 _('[-u] [NAME]...'),
1741 optionalrepo=True)
1742 optionalrepo=True)
1742 def config(ui, repo, *values, **opts):
1743 def config(ui, repo, *values, **opts):
1743 """show combined config settings from all hgrc files
1744 """show combined config settings from all hgrc files
1744
1745
1745 With no arguments, print names and values of all config items.
1746 With no arguments, print names and values of all config items.
1746
1747
1747 With one argument of the form section.name, print just the value
1748 With one argument of the form section.name, print just the value
1748 of that config item.
1749 of that config item.
1749
1750
1750 With multiple arguments, print names and values of all config
1751 With multiple arguments, print names and values of all config
1751 items with matching section names.
1752 items with matching section names.
1752
1753
1753 With --edit, start an editor on the user-level config file. With
1754 With --edit, start an editor on the user-level config file. With
1754 --global, edit the system-wide config file. With --local, edit the
1755 --global, edit the system-wide config file. With --local, edit the
1755 repository-level config file.
1756 repository-level config file.
1756
1757
1757 With --debug, the source (filename and line number) is printed
1758 With --debug, the source (filename and line number) is printed
1758 for each config item.
1759 for each config item.
1759
1760
1760 See :hg:`help config` for more information about config files.
1761 See :hg:`help config` for more information about config files.
1761
1762
1762 Returns 0 on success, 1 if NAME does not exist.
1763 Returns 0 on success, 1 if NAME does not exist.
1763
1764
1764 """
1765 """
1765
1766
1766 if opts.get('edit') or opts.get('local') or opts.get('global'):
1767 if opts.get('edit') or opts.get('local') or opts.get('global'):
1767 if opts.get('local') and opts.get('global'):
1768 if opts.get('local') and opts.get('global'):
1768 raise error.Abort(_("can't use --local and --global together"))
1769 raise error.Abort(_("can't use --local and --global together"))
1769
1770
1770 if opts.get('local'):
1771 if opts.get('local'):
1771 if not repo:
1772 if not repo:
1772 raise error.Abort(_("can't use --local outside a repository"))
1773 raise error.Abort(_("can't use --local outside a repository"))
1773 paths = [repo.join('hgrc')]
1774 paths = [repo.join('hgrc')]
1774 elif opts.get('global'):
1775 elif opts.get('global'):
1775 paths = scmutil.systemrcpath()
1776 paths = scmutil.systemrcpath()
1776 else:
1777 else:
1777 paths = scmutil.userrcpath()
1778 paths = scmutil.userrcpath()
1778
1779
1779 for f in paths:
1780 for f in paths:
1780 if os.path.exists(f):
1781 if os.path.exists(f):
1781 break
1782 break
1782 else:
1783 else:
1783 if opts.get('global'):
1784 if opts.get('global'):
1784 samplehgrc = uimod.samplehgrcs['global']
1785 samplehgrc = uimod.samplehgrcs['global']
1785 elif opts.get('local'):
1786 elif opts.get('local'):
1786 samplehgrc = uimod.samplehgrcs['local']
1787 samplehgrc = uimod.samplehgrcs['local']
1787 else:
1788 else:
1788 samplehgrc = uimod.samplehgrcs['user']
1789 samplehgrc = uimod.samplehgrcs['user']
1789
1790
1790 f = paths[0]
1791 f = paths[0]
1791 fp = open(f, "w")
1792 fp = open(f, "w")
1792 fp.write(samplehgrc)
1793 fp.write(samplehgrc)
1793 fp.close()
1794 fp.close()
1794
1795
1795 editor = ui.geteditor()
1796 editor = ui.geteditor()
1796 ui.system("%s \"%s\"" % (editor, f),
1797 ui.system("%s \"%s\"" % (editor, f),
1797 onerr=error.Abort, errprefix=_("edit failed"))
1798 onerr=error.Abort, errprefix=_("edit failed"))
1798 return
1799 return
1799 ui.pager('config')
1800 ui.pager('config')
1800 fm = ui.formatter('config', opts)
1801 fm = ui.formatter('config', opts)
1801 for f in scmutil.rcpath():
1802 for f in scmutil.rcpath():
1802 ui.debug('read config from: %s\n' % f)
1803 ui.debug('read config from: %s\n' % f)
1803 untrusted = bool(opts.get('untrusted'))
1804 untrusted = bool(opts.get('untrusted'))
1804 if values:
1805 if values:
1805 sections = [v for v in values if '.' not in v]
1806 sections = [v for v in values if '.' not in v]
1806 items = [v for v in values if '.' in v]
1807 items = [v for v in values if '.' in v]
1807 if len(items) > 1 or items and sections:
1808 if len(items) > 1 or items and sections:
1808 raise error.Abort(_('only one config item permitted'))
1809 raise error.Abort(_('only one config item permitted'))
1809 matched = False
1810 matched = False
1810 for section, name, value in ui.walkconfig(untrusted=untrusted):
1811 for section, name, value in ui.walkconfig(untrusted=untrusted):
1811 source = ui.configsource(section, name, untrusted)
1812 source = ui.configsource(section, name, untrusted)
1812 value = str(value)
1813 value = str(value)
1813 if fm.isplain():
1814 if fm.isplain():
1814 source = source or 'none'
1815 source = source or 'none'
1815 value = value.replace('\n', '\\n')
1816 value = value.replace('\n', '\\n')
1816 entryname = section + '.' + name
1817 entryname = section + '.' + name
1817 if values:
1818 if values:
1818 for v in values:
1819 for v in values:
1819 if v == section:
1820 if v == section:
1820 fm.startitem()
1821 fm.startitem()
1821 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1822 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1822 fm.write('name value', '%s=%s\n', entryname, value)
1823 fm.write('name value', '%s=%s\n', entryname, value)
1823 matched = True
1824 matched = True
1824 elif v == entryname:
1825 elif v == entryname:
1825 fm.startitem()
1826 fm.startitem()
1826 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1827 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1827 fm.write('value', '%s\n', value)
1828 fm.write('value', '%s\n', value)
1828 fm.data(name=entryname)
1829 fm.data(name=entryname)
1829 matched = True
1830 matched = True
1830 else:
1831 else:
1831 fm.startitem()
1832 fm.startitem()
1832 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1833 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1833 fm.write('name value', '%s=%s\n', entryname, value)
1834 fm.write('name value', '%s=%s\n', entryname, value)
1834 matched = True
1835 matched = True
1835 fm.end()
1836 fm.end()
1836 if matched:
1837 if matched:
1837 return 0
1838 return 0
1838 return 1
1839 return 1
1839
1840
1840 @command('copy|cp',
1841 @command('copy|cp',
1841 [('A', 'after', None, _('record a copy that has already occurred')),
1842 [('A', 'after', None, _('record a copy that has already occurred')),
1842 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1843 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1843 ] + walkopts + dryrunopts,
1844 ] + walkopts + dryrunopts,
1844 _('[OPTION]... [SOURCE]... DEST'))
1845 _('[OPTION]... [SOURCE]... DEST'))
1845 def copy(ui, repo, *pats, **opts):
1846 def copy(ui, repo, *pats, **opts):
1846 """mark files as copied for the next commit
1847 """mark files as copied for the next commit
1847
1848
1848 Mark dest as having copies of source files. If dest is a
1849 Mark dest as having copies of source files. If dest is a
1849 directory, copies are put in that directory. If dest is a file,
1850 directory, copies are put in that directory. If dest is a file,
1850 the source must be a single file.
1851 the source must be a single file.
1851
1852
1852 By default, this command copies the contents of files as they
1853 By default, this command copies the contents of files as they
1853 exist in the working directory. If invoked with -A/--after, the
1854 exist in the working directory. If invoked with -A/--after, the
1854 operation is recorded, but no copying is performed.
1855 operation is recorded, but no copying is performed.
1855
1856
1856 This command takes effect with the next commit. To undo a copy
1857 This command takes effect with the next commit. To undo a copy
1857 before that, see :hg:`revert`.
1858 before that, see :hg:`revert`.
1858
1859
1859 Returns 0 on success, 1 if errors are encountered.
1860 Returns 0 on success, 1 if errors are encountered.
1860 """
1861 """
1861 with repo.wlock(False):
1862 with repo.wlock(False):
1862 return cmdutil.copy(ui, repo, pats, opts)
1863 return cmdutil.copy(ui, repo, pats, opts)
1863
1864
1864 @command('^diff',
1865 @command('^diff',
1865 [('r', 'rev', [], _('revision'), _('REV')),
1866 [('r', 'rev', [], _('revision'), _('REV')),
1866 ('c', 'change', '', _('change made by revision'), _('REV'))
1867 ('c', 'change', '', _('change made by revision'), _('REV'))
1867 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1868 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1868 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1869 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1869 inferrepo=True)
1870 inferrepo=True)
1870 def diff(ui, repo, *pats, **opts):
1871 def diff(ui, repo, *pats, **opts):
1871 """diff repository (or selected files)
1872 """diff repository (or selected files)
1872
1873
1873 Show differences between revisions for the specified files.
1874 Show differences between revisions for the specified files.
1874
1875
1875 Differences between files are shown using the unified diff format.
1876 Differences between files are shown using the unified diff format.
1876
1877
1877 .. note::
1878 .. note::
1878
1879
1879 :hg:`diff` may generate unexpected results for merges, as it will
1880 :hg:`diff` may generate unexpected results for merges, as it will
1880 default to comparing against the working directory's first
1881 default to comparing against the working directory's first
1881 parent changeset if no revisions are specified.
1882 parent changeset if no revisions are specified.
1882
1883
1883 When two revision arguments are given, then changes are shown
1884 When two revision arguments are given, then changes are shown
1884 between those revisions. If only one revision is specified then
1885 between those revisions. If only one revision is specified then
1885 that revision is compared to the working directory, and, when no
1886 that revision is compared to the working directory, and, when no
1886 revisions are specified, the working directory files are compared
1887 revisions are specified, the working directory files are compared
1887 to its first parent.
1888 to its first parent.
1888
1889
1889 Alternatively you can specify -c/--change with a revision to see
1890 Alternatively you can specify -c/--change with a revision to see
1890 the changes in that changeset relative to its first parent.
1891 the changes in that changeset relative to its first parent.
1891
1892
1892 Without the -a/--text option, diff will avoid generating diffs of
1893 Without the -a/--text option, diff will avoid generating diffs of
1893 files it detects as binary. With -a, diff will generate a diff
1894 files it detects as binary. With -a, diff will generate a diff
1894 anyway, probably with undesirable results.
1895 anyway, probably with undesirable results.
1895
1896
1896 Use the -g/--git option to generate diffs in the git extended diff
1897 Use the -g/--git option to generate diffs in the git extended diff
1897 format. For more information, read :hg:`help diffs`.
1898 format. For more information, read :hg:`help diffs`.
1898
1899
1899 .. container:: verbose
1900 .. container:: verbose
1900
1901
1901 Examples:
1902 Examples:
1902
1903
1903 - compare a file in the current working directory to its parent::
1904 - compare a file in the current working directory to its parent::
1904
1905
1905 hg diff foo.c
1906 hg diff foo.c
1906
1907
1907 - compare two historical versions of a directory, with rename info::
1908 - compare two historical versions of a directory, with rename info::
1908
1909
1909 hg diff --git -r 1.0:1.2 lib/
1910 hg diff --git -r 1.0:1.2 lib/
1910
1911
1911 - get change stats relative to the last change on some date::
1912 - get change stats relative to the last change on some date::
1912
1913
1913 hg diff --stat -r "date('may 2')"
1914 hg diff --stat -r "date('may 2')"
1914
1915
1915 - diff all newly-added files that contain a keyword::
1916 - diff all newly-added files that contain a keyword::
1916
1917
1917 hg diff "set:added() and grep(GNU)"
1918 hg diff "set:added() and grep(GNU)"
1918
1919
1919 - compare a revision and its parents::
1920 - compare a revision and its parents::
1920
1921
1921 hg diff -c 9353 # compare against first parent
1922 hg diff -c 9353 # compare against first parent
1922 hg diff -r 9353^:9353 # same using revset syntax
1923 hg diff -r 9353^:9353 # same using revset syntax
1923 hg diff -r 9353^2:9353 # compare against the second parent
1924 hg diff -r 9353^2:9353 # compare against the second parent
1924
1925
1925 Returns 0 on success.
1926 Returns 0 on success.
1926 """
1927 """
1927
1928
1928 revs = opts.get('rev')
1929 revs = opts.get('rev')
1929 change = opts.get('change')
1930 change = opts.get('change')
1930 stat = opts.get('stat')
1931 stat = opts.get('stat')
1931 reverse = opts.get('reverse')
1932 reverse = opts.get('reverse')
1932
1933
1933 if revs and change:
1934 if revs and change:
1934 msg = _('cannot specify --rev and --change at the same time')
1935 msg = _('cannot specify --rev and --change at the same time')
1935 raise error.Abort(msg)
1936 raise error.Abort(msg)
1936 elif change:
1937 elif change:
1937 node2 = scmutil.revsingle(repo, change, None).node()
1938 node2 = scmutil.revsingle(repo, change, None).node()
1938 node1 = repo[node2].p1().node()
1939 node1 = repo[node2].p1().node()
1939 else:
1940 else:
1940 node1, node2 = scmutil.revpair(repo, revs)
1941 node1, node2 = scmutil.revpair(repo, revs)
1941
1942
1942 if reverse:
1943 if reverse:
1943 node1, node2 = node2, node1
1944 node1, node2 = node2, node1
1944
1945
1945 diffopts = patch.diffallopts(ui, opts)
1946 diffopts = patch.diffallopts(ui, opts)
1946 m = scmutil.match(repo[node2], pats, opts)
1947 m = scmutil.match(repo[node2], pats, opts)
1947 ui.pager('diff')
1948 ui.pager('diff')
1948 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1949 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1949 listsubrepos=opts.get('subrepos'),
1950 listsubrepos=opts.get('subrepos'),
1950 root=opts.get('root'))
1951 root=opts.get('root'))
1951
1952
1952 @command('^export',
1953 @command('^export',
1953 [('o', 'output', '',
1954 [('o', 'output', '',
1954 _('print output to file with formatted name'), _('FORMAT')),
1955 _('print output to file with formatted name'), _('FORMAT')),
1955 ('', 'switch-parent', None, _('diff against the second parent')),
1956 ('', 'switch-parent', None, _('diff against the second parent')),
1956 ('r', 'rev', [], _('revisions to export'), _('REV')),
1957 ('r', 'rev', [], _('revisions to export'), _('REV')),
1957 ] + diffopts,
1958 ] + diffopts,
1958 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1959 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1959 def export(ui, repo, *changesets, **opts):
1960 def export(ui, repo, *changesets, **opts):
1960 """dump the header and diffs for one or more changesets
1961 """dump the header and diffs for one or more changesets
1961
1962
1962 Print the changeset header and diffs for one or more revisions.
1963 Print the changeset header and diffs for one or more revisions.
1963 If no revision is given, the parent of the working directory is used.
1964 If no revision is given, the parent of the working directory is used.
1964
1965
1965 The information shown in the changeset header is: author, date,
1966 The information shown in the changeset header is: author, date,
1966 branch name (if non-default), changeset hash, parent(s) and commit
1967 branch name (if non-default), changeset hash, parent(s) and commit
1967 comment.
1968 comment.
1968
1969
1969 .. note::
1970 .. note::
1970
1971
1971 :hg:`export` may generate unexpected diff output for merge
1972 :hg:`export` may generate unexpected diff output for merge
1972 changesets, as it will compare the merge changeset against its
1973 changesets, as it will compare the merge changeset against its
1973 first parent only.
1974 first parent only.
1974
1975
1975 Output may be to a file, in which case the name of the file is
1976 Output may be to a file, in which case the name of the file is
1976 given using a format string. The formatting rules are as follows:
1977 given using a format string. The formatting rules are as follows:
1977
1978
1978 :``%%``: literal "%" character
1979 :``%%``: literal "%" character
1979 :``%H``: changeset hash (40 hexadecimal digits)
1980 :``%H``: changeset hash (40 hexadecimal digits)
1980 :``%N``: number of patches being generated
1981 :``%N``: number of patches being generated
1981 :``%R``: changeset revision number
1982 :``%R``: changeset revision number
1982 :``%b``: basename of the exporting repository
1983 :``%b``: basename of the exporting repository
1983 :``%h``: short-form changeset hash (12 hexadecimal digits)
1984 :``%h``: short-form changeset hash (12 hexadecimal digits)
1984 :``%m``: first line of the commit message (only alphanumeric characters)
1985 :``%m``: first line of the commit message (only alphanumeric characters)
1985 :``%n``: zero-padded sequence number, starting at 1
1986 :``%n``: zero-padded sequence number, starting at 1
1986 :``%r``: zero-padded changeset revision number
1987 :``%r``: zero-padded changeset revision number
1987
1988
1988 Without the -a/--text option, export will avoid generating diffs
1989 Without the -a/--text option, export will avoid generating diffs
1989 of files it detects as binary. With -a, export will generate a
1990 of files it detects as binary. With -a, export will generate a
1990 diff anyway, probably with undesirable results.
1991 diff anyway, probably with undesirable results.
1991
1992
1992 Use the -g/--git option to generate diffs in the git extended diff
1993 Use the -g/--git option to generate diffs in the git extended diff
1993 format. See :hg:`help diffs` for more information.
1994 format. See :hg:`help diffs` for more information.
1994
1995
1995 With the --switch-parent option, the diff will be against the
1996 With the --switch-parent option, the diff will be against the
1996 second parent. It can be useful to review a merge.
1997 second parent. It can be useful to review a merge.
1997
1998
1998 .. container:: verbose
1999 .. container:: verbose
1999
2000
2000 Examples:
2001 Examples:
2001
2002
2002 - use export and import to transplant a bugfix to the current
2003 - use export and import to transplant a bugfix to the current
2003 branch::
2004 branch::
2004
2005
2005 hg export -r 9353 | hg import -
2006 hg export -r 9353 | hg import -
2006
2007
2007 - export all the changesets between two revisions to a file with
2008 - export all the changesets between two revisions to a file with
2008 rename information::
2009 rename information::
2009
2010
2010 hg export --git -r 123:150 > changes.txt
2011 hg export --git -r 123:150 > changes.txt
2011
2012
2012 - split outgoing changes into a series of patches with
2013 - split outgoing changes into a series of patches with
2013 descriptive names::
2014 descriptive names::
2014
2015
2015 hg export -r "outgoing()" -o "%n-%m.patch"
2016 hg export -r "outgoing()" -o "%n-%m.patch"
2016
2017
2017 Returns 0 on success.
2018 Returns 0 on success.
2018 """
2019 """
2019 changesets += tuple(opts.get('rev', []))
2020 changesets += tuple(opts.get('rev', []))
2020 if not changesets:
2021 if not changesets:
2021 changesets = ['.']
2022 changesets = ['.']
2022 revs = scmutil.revrange(repo, changesets)
2023 revs = scmutil.revrange(repo, changesets)
2023 if not revs:
2024 if not revs:
2024 raise error.Abort(_("export requires at least one changeset"))
2025 raise error.Abort(_("export requires at least one changeset"))
2025 if len(revs) > 1:
2026 if len(revs) > 1:
2026 ui.note(_('exporting patches:\n'))
2027 ui.note(_('exporting patches:\n'))
2027 else:
2028 else:
2028 ui.note(_('exporting patch:\n'))
2029 ui.note(_('exporting patch:\n'))
2029 ui.pager('export')
2030 ui.pager('export')
2030 cmdutil.export(repo, revs, template=opts.get('output'),
2031 cmdutil.export(repo, revs, template=opts.get('output'),
2031 switch_parent=opts.get('switch_parent'),
2032 switch_parent=opts.get('switch_parent'),
2032 opts=patch.diffallopts(ui, opts))
2033 opts=patch.diffallopts(ui, opts))
2033
2034
2034 @command('files',
2035 @command('files',
2035 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2036 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2036 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2037 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2037 ] + walkopts + formatteropts + subrepoopts,
2038 ] + walkopts + formatteropts + subrepoopts,
2038 _('[OPTION]... [FILE]...'))
2039 _('[OPTION]... [FILE]...'))
2039 def files(ui, repo, *pats, **opts):
2040 def files(ui, repo, *pats, **opts):
2040 """list tracked files
2041 """list tracked files
2041
2042
2042 Print files under Mercurial control in the working directory or
2043 Print files under Mercurial control in the working directory or
2043 specified revision for given files (excluding removed files).
2044 specified revision for given files (excluding removed files).
2044 Files can be specified as filenames or filesets.
2045 Files can be specified as filenames or filesets.
2045
2046
2046 If no files are given to match, this command prints the names
2047 If no files are given to match, this command prints the names
2047 of all files under Mercurial control.
2048 of all files under Mercurial control.
2048
2049
2049 .. container:: verbose
2050 .. container:: verbose
2050
2051
2051 Examples:
2052 Examples:
2052
2053
2053 - list all files under the current directory::
2054 - list all files under the current directory::
2054
2055
2055 hg files .
2056 hg files .
2056
2057
2057 - shows sizes and flags for current revision::
2058 - shows sizes and flags for current revision::
2058
2059
2059 hg files -vr .
2060 hg files -vr .
2060
2061
2061 - list all files named README::
2062 - list all files named README::
2062
2063
2063 hg files -I "**/README"
2064 hg files -I "**/README"
2064
2065
2065 - list all binary files::
2066 - list all binary files::
2066
2067
2067 hg files "set:binary()"
2068 hg files "set:binary()"
2068
2069
2069 - find files containing a regular expression::
2070 - find files containing a regular expression::
2070
2071
2071 hg files "set:grep('bob')"
2072 hg files "set:grep('bob')"
2072
2073
2073 - search tracked file contents with xargs and grep::
2074 - search tracked file contents with xargs and grep::
2074
2075
2075 hg files -0 | xargs -0 grep foo
2076 hg files -0 | xargs -0 grep foo
2076
2077
2077 See :hg:`help patterns` and :hg:`help filesets` for more information
2078 See :hg:`help patterns` and :hg:`help filesets` for more information
2078 on specifying file patterns.
2079 on specifying file patterns.
2079
2080
2080 Returns 0 if a match is found, 1 otherwise.
2081 Returns 0 if a match is found, 1 otherwise.
2081
2082
2082 """
2083 """
2083 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2084 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2084
2085
2085 end = '\n'
2086 end = '\n'
2086 if opts.get('print0'):
2087 if opts.get('print0'):
2087 end = '\0'
2088 end = '\0'
2088 fmt = '%s' + end
2089 fmt = '%s' + end
2089
2090
2090 m = scmutil.match(ctx, pats, opts)
2091 m = scmutil.match(ctx, pats, opts)
2091 ui.pager('files')
2092 ui.pager('files')
2092 with ui.formatter('files', opts) as fm:
2093 with ui.formatter('files', opts) as fm:
2093 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2094 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2094
2095
2095 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2096 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2096 def forget(ui, repo, *pats, **opts):
2097 def forget(ui, repo, *pats, **opts):
2097 """forget the specified files on the next commit
2098 """forget the specified files on the next commit
2098
2099
2099 Mark the specified files so they will no longer be tracked
2100 Mark the specified files so they will no longer be tracked
2100 after the next commit.
2101 after the next commit.
2101
2102
2102 This only removes files from the current branch, not from the
2103 This only removes files from the current branch, not from the
2103 entire project history, and it does not delete them from the
2104 entire project history, and it does not delete them from the
2104 working directory.
2105 working directory.
2105
2106
2106 To delete the file from the working directory, see :hg:`remove`.
2107 To delete the file from the working directory, see :hg:`remove`.
2107
2108
2108 To undo a forget before the next commit, see :hg:`add`.
2109 To undo a forget before the next commit, see :hg:`add`.
2109
2110
2110 .. container:: verbose
2111 .. container:: verbose
2111
2112
2112 Examples:
2113 Examples:
2113
2114
2114 - forget newly-added binary files::
2115 - forget newly-added binary files::
2115
2116
2116 hg forget "set:added() and binary()"
2117 hg forget "set:added() and binary()"
2117
2118
2118 - forget files that would be excluded by .hgignore::
2119 - forget files that would be excluded by .hgignore::
2119
2120
2120 hg forget "set:hgignore()"
2121 hg forget "set:hgignore()"
2121
2122
2122 Returns 0 on success.
2123 Returns 0 on success.
2123 """
2124 """
2124
2125
2125 if not pats:
2126 if not pats:
2126 raise error.Abort(_('no files specified'))
2127 raise error.Abort(_('no files specified'))
2127
2128
2128 m = scmutil.match(repo[None], pats, opts)
2129 m = scmutil.match(repo[None], pats, opts)
2129 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2130 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2130 return rejected and 1 or 0
2131 return rejected and 1 or 0
2131
2132
2132 @command(
2133 @command(
2133 'graft',
2134 'graft',
2134 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2135 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2135 ('c', 'continue', False, _('resume interrupted graft')),
2136 ('c', 'continue', False, _('resume interrupted graft')),
2136 ('e', 'edit', False, _('invoke editor on commit messages')),
2137 ('e', 'edit', False, _('invoke editor on commit messages')),
2137 ('', 'log', None, _('append graft info to log message')),
2138 ('', 'log', None, _('append graft info to log message')),
2138 ('f', 'force', False, _('force graft')),
2139 ('f', 'force', False, _('force graft')),
2139 ('D', 'currentdate', False,
2140 ('D', 'currentdate', False,
2140 _('record the current date as commit date')),
2141 _('record the current date as commit date')),
2141 ('U', 'currentuser', False,
2142 ('U', 'currentuser', False,
2142 _('record the current user as committer'), _('DATE'))]
2143 _('record the current user as committer'), _('DATE'))]
2143 + commitopts2 + mergetoolopts + dryrunopts,
2144 + commitopts2 + mergetoolopts + dryrunopts,
2144 _('[OPTION]... [-r REV]... REV...'))
2145 _('[OPTION]... [-r REV]... REV...'))
2145 def graft(ui, repo, *revs, **opts):
2146 def graft(ui, repo, *revs, **opts):
2146 '''copy changes from other branches onto the current branch
2147 '''copy changes from other branches onto the current branch
2147
2148
2148 This command uses Mercurial's merge logic to copy individual
2149 This command uses Mercurial's merge logic to copy individual
2149 changes from other branches without merging branches in the
2150 changes from other branches without merging branches in the
2150 history graph. This is sometimes known as 'backporting' or
2151 history graph. This is sometimes known as 'backporting' or
2151 'cherry-picking'. By default, graft will copy user, date, and
2152 'cherry-picking'. By default, graft will copy user, date, and
2152 description from the source changesets.
2153 description from the source changesets.
2153
2154
2154 Changesets that are ancestors of the current revision, that have
2155 Changesets that are ancestors of the current revision, that have
2155 already been grafted, or that are merges will be skipped.
2156 already been grafted, or that are merges will be skipped.
2156
2157
2157 If --log is specified, log messages will have a comment appended
2158 If --log is specified, log messages will have a comment appended
2158 of the form::
2159 of the form::
2159
2160
2160 (grafted from CHANGESETHASH)
2161 (grafted from CHANGESETHASH)
2161
2162
2162 If --force is specified, revisions will be grafted even if they
2163 If --force is specified, revisions will be grafted even if they
2163 are already ancestors of or have been grafted to the destination.
2164 are already ancestors of or have been grafted to the destination.
2164 This is useful when the revisions have since been backed out.
2165 This is useful when the revisions have since been backed out.
2165
2166
2166 If a graft merge results in conflicts, the graft process is
2167 If a graft merge results in conflicts, the graft process is
2167 interrupted so that the current merge can be manually resolved.
2168 interrupted so that the current merge can be manually resolved.
2168 Once all conflicts are addressed, the graft process can be
2169 Once all conflicts are addressed, the graft process can be
2169 continued with the -c/--continue option.
2170 continued with the -c/--continue option.
2170
2171
2171 .. note::
2172 .. note::
2172
2173
2173 The -c/--continue option does not reapply earlier options, except
2174 The -c/--continue option does not reapply earlier options, except
2174 for --force.
2175 for --force.
2175
2176
2176 .. container:: verbose
2177 .. container:: verbose
2177
2178
2178 Examples:
2179 Examples:
2179
2180
2180 - copy a single change to the stable branch and edit its description::
2181 - copy a single change to the stable branch and edit its description::
2181
2182
2182 hg update stable
2183 hg update stable
2183 hg graft --edit 9393
2184 hg graft --edit 9393
2184
2185
2185 - graft a range of changesets with one exception, updating dates::
2186 - graft a range of changesets with one exception, updating dates::
2186
2187
2187 hg graft -D "2085::2093 and not 2091"
2188 hg graft -D "2085::2093 and not 2091"
2188
2189
2189 - continue a graft after resolving conflicts::
2190 - continue a graft after resolving conflicts::
2190
2191
2191 hg graft -c
2192 hg graft -c
2192
2193
2193 - show the source of a grafted changeset::
2194 - show the source of a grafted changeset::
2194
2195
2195 hg log --debug -r .
2196 hg log --debug -r .
2196
2197
2197 - show revisions sorted by date::
2198 - show revisions sorted by date::
2198
2199
2199 hg log -r "sort(all(), date)"
2200 hg log -r "sort(all(), date)"
2200
2201
2201 See :hg:`help revisions` for more about specifying revisions.
2202 See :hg:`help revisions` for more about specifying revisions.
2202
2203
2203 Returns 0 on successful completion.
2204 Returns 0 on successful completion.
2204 '''
2205 '''
2205 with repo.wlock():
2206 with repo.wlock():
2206 return _dograft(ui, repo, *revs, **opts)
2207 return _dograft(ui, repo, *revs, **opts)
2207
2208
2208 def _dograft(ui, repo, *revs, **opts):
2209 def _dograft(ui, repo, *revs, **opts):
2209 if revs and opts.get('rev'):
2210 if revs and opts.get('rev'):
2210 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2211 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2211 'revision ordering!\n'))
2212 'revision ordering!\n'))
2212
2213
2213 revs = list(revs)
2214 revs = list(revs)
2214 revs.extend(opts.get('rev'))
2215 revs.extend(opts.get('rev'))
2215
2216
2216 if not opts.get('user') and opts.get('currentuser'):
2217 if not opts.get('user') and opts.get('currentuser'):
2217 opts['user'] = ui.username()
2218 opts['user'] = ui.username()
2218 if not opts.get('date') and opts.get('currentdate'):
2219 if not opts.get('date') and opts.get('currentdate'):
2219 opts['date'] = "%d %d" % util.makedate()
2220 opts['date'] = "%d %d" % util.makedate()
2220
2221
2221 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2222 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2222
2223
2223 cont = False
2224 cont = False
2224 if opts.get('continue'):
2225 if opts.get('continue'):
2225 cont = True
2226 cont = True
2226 if revs:
2227 if revs:
2227 raise error.Abort(_("can't specify --continue and revisions"))
2228 raise error.Abort(_("can't specify --continue and revisions"))
2228 # read in unfinished revisions
2229 # read in unfinished revisions
2229 try:
2230 try:
2230 nodes = repo.vfs.read('graftstate').splitlines()
2231 nodes = repo.vfs.read('graftstate').splitlines()
2231 revs = [repo[node].rev() for node in nodes]
2232 revs = [repo[node].rev() for node in nodes]
2232 except IOError as inst:
2233 except IOError as inst:
2233 if inst.errno != errno.ENOENT:
2234 if inst.errno != errno.ENOENT:
2234 raise
2235 raise
2235 cmdutil.wrongtooltocontinue(repo, _('graft'))
2236 cmdutil.wrongtooltocontinue(repo, _('graft'))
2236 else:
2237 else:
2237 cmdutil.checkunfinished(repo)
2238 cmdutil.checkunfinished(repo)
2238 cmdutil.bailifchanged(repo)
2239 cmdutil.bailifchanged(repo)
2239 if not revs:
2240 if not revs:
2240 raise error.Abort(_('no revisions specified'))
2241 raise error.Abort(_('no revisions specified'))
2241 revs = scmutil.revrange(repo, revs)
2242 revs = scmutil.revrange(repo, revs)
2242
2243
2243 skipped = set()
2244 skipped = set()
2244 # check for merges
2245 # check for merges
2245 for rev in repo.revs('%ld and merge()', revs):
2246 for rev in repo.revs('%ld and merge()', revs):
2246 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2247 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2247 skipped.add(rev)
2248 skipped.add(rev)
2248 revs = [r for r in revs if r not in skipped]
2249 revs = [r for r in revs if r not in skipped]
2249 if not revs:
2250 if not revs:
2250 return -1
2251 return -1
2251
2252
2252 # Don't check in the --continue case, in effect retaining --force across
2253 # Don't check in the --continue case, in effect retaining --force across
2253 # --continues. That's because without --force, any revisions we decided to
2254 # --continues. That's because without --force, any revisions we decided to
2254 # skip would have been filtered out here, so they wouldn't have made their
2255 # skip would have been filtered out here, so they wouldn't have made their
2255 # way to the graftstate. With --force, any revisions we would have otherwise
2256 # way to the graftstate. With --force, any revisions we would have otherwise
2256 # skipped would not have been filtered out, and if they hadn't been applied
2257 # skipped would not have been filtered out, and if they hadn't been applied
2257 # already, they'd have been in the graftstate.
2258 # already, they'd have been in the graftstate.
2258 if not (cont or opts.get('force')):
2259 if not (cont or opts.get('force')):
2259 # check for ancestors of dest branch
2260 # check for ancestors of dest branch
2260 crev = repo['.'].rev()
2261 crev = repo['.'].rev()
2261 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2262 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2262 # XXX make this lazy in the future
2263 # XXX make this lazy in the future
2263 # don't mutate while iterating, create a copy
2264 # don't mutate while iterating, create a copy
2264 for rev in list(revs):
2265 for rev in list(revs):
2265 if rev in ancestors:
2266 if rev in ancestors:
2266 ui.warn(_('skipping ancestor revision %d:%s\n') %
2267 ui.warn(_('skipping ancestor revision %d:%s\n') %
2267 (rev, repo[rev]))
2268 (rev, repo[rev]))
2268 # XXX remove on list is slow
2269 # XXX remove on list is slow
2269 revs.remove(rev)
2270 revs.remove(rev)
2270 if not revs:
2271 if not revs:
2271 return -1
2272 return -1
2272
2273
2273 # analyze revs for earlier grafts
2274 # analyze revs for earlier grafts
2274 ids = {}
2275 ids = {}
2275 for ctx in repo.set("%ld", revs):
2276 for ctx in repo.set("%ld", revs):
2276 ids[ctx.hex()] = ctx.rev()
2277 ids[ctx.hex()] = ctx.rev()
2277 n = ctx.extra().get('source')
2278 n = ctx.extra().get('source')
2278 if n:
2279 if n:
2279 ids[n] = ctx.rev()
2280 ids[n] = ctx.rev()
2280
2281
2281 # check ancestors for earlier grafts
2282 # check ancestors for earlier grafts
2282 ui.debug('scanning for duplicate grafts\n')
2283 ui.debug('scanning for duplicate grafts\n')
2283
2284
2284 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2285 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2285 ctx = repo[rev]
2286 ctx = repo[rev]
2286 n = ctx.extra().get('source')
2287 n = ctx.extra().get('source')
2287 if n in ids:
2288 if n in ids:
2288 try:
2289 try:
2289 r = repo[n].rev()
2290 r = repo[n].rev()
2290 except error.RepoLookupError:
2291 except error.RepoLookupError:
2291 r = None
2292 r = None
2292 if r in revs:
2293 if r in revs:
2293 ui.warn(_('skipping revision %d:%s '
2294 ui.warn(_('skipping revision %d:%s '
2294 '(already grafted to %d:%s)\n')
2295 '(already grafted to %d:%s)\n')
2295 % (r, repo[r], rev, ctx))
2296 % (r, repo[r], rev, ctx))
2296 revs.remove(r)
2297 revs.remove(r)
2297 elif ids[n] in revs:
2298 elif ids[n] in revs:
2298 if r is None:
2299 if r is None:
2299 ui.warn(_('skipping already grafted revision %d:%s '
2300 ui.warn(_('skipping already grafted revision %d:%s '
2300 '(%d:%s also has unknown origin %s)\n')
2301 '(%d:%s also has unknown origin %s)\n')
2301 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2302 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2302 else:
2303 else:
2303 ui.warn(_('skipping already grafted revision %d:%s '
2304 ui.warn(_('skipping already grafted revision %d:%s '
2304 '(%d:%s also has origin %d:%s)\n')
2305 '(%d:%s also has origin %d:%s)\n')
2305 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2306 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2306 revs.remove(ids[n])
2307 revs.remove(ids[n])
2307 elif ctx.hex() in ids:
2308 elif ctx.hex() in ids:
2308 r = ids[ctx.hex()]
2309 r = ids[ctx.hex()]
2309 ui.warn(_('skipping already grafted revision %d:%s '
2310 ui.warn(_('skipping already grafted revision %d:%s '
2310 '(was grafted from %d:%s)\n') %
2311 '(was grafted from %d:%s)\n') %
2311 (r, repo[r], rev, ctx))
2312 (r, repo[r], rev, ctx))
2312 revs.remove(r)
2313 revs.remove(r)
2313 if not revs:
2314 if not revs:
2314 return -1
2315 return -1
2315
2316
2316 for pos, ctx in enumerate(repo.set("%ld", revs)):
2317 for pos, ctx in enumerate(repo.set("%ld", revs)):
2317 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2318 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2318 ctx.description().split('\n', 1)[0])
2319 ctx.description().split('\n', 1)[0])
2319 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2320 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2320 if names:
2321 if names:
2321 desc += ' (%s)' % ' '.join(names)
2322 desc += ' (%s)' % ' '.join(names)
2322 ui.status(_('grafting %s\n') % desc)
2323 ui.status(_('grafting %s\n') % desc)
2323 if opts.get('dry_run'):
2324 if opts.get('dry_run'):
2324 continue
2325 continue
2325
2326
2326 source = ctx.extra().get('source')
2327 source = ctx.extra().get('source')
2327 extra = {}
2328 extra = {}
2328 if source:
2329 if source:
2329 extra['source'] = source
2330 extra['source'] = source
2330 extra['intermediate-source'] = ctx.hex()
2331 extra['intermediate-source'] = ctx.hex()
2331 else:
2332 else:
2332 extra['source'] = ctx.hex()
2333 extra['source'] = ctx.hex()
2333 user = ctx.user()
2334 user = ctx.user()
2334 if opts.get('user'):
2335 if opts.get('user'):
2335 user = opts['user']
2336 user = opts['user']
2336 date = ctx.date()
2337 date = ctx.date()
2337 if opts.get('date'):
2338 if opts.get('date'):
2338 date = opts['date']
2339 date = opts['date']
2339 message = ctx.description()
2340 message = ctx.description()
2340 if opts.get('log'):
2341 if opts.get('log'):
2341 message += '\n(grafted from %s)' % ctx.hex()
2342 message += '\n(grafted from %s)' % ctx.hex()
2342
2343
2343 # we don't merge the first commit when continuing
2344 # we don't merge the first commit when continuing
2344 if not cont:
2345 if not cont:
2345 # perform the graft merge with p1(rev) as 'ancestor'
2346 # perform the graft merge with p1(rev) as 'ancestor'
2346 try:
2347 try:
2347 # ui.forcemerge is an internal variable, do not document
2348 # ui.forcemerge is an internal variable, do not document
2348 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2349 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2349 'graft')
2350 'graft')
2350 stats = mergemod.graft(repo, ctx, ctx.p1(),
2351 stats = mergemod.graft(repo, ctx, ctx.p1(),
2351 ['local', 'graft'])
2352 ['local', 'graft'])
2352 finally:
2353 finally:
2353 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2354 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2354 # report any conflicts
2355 # report any conflicts
2355 if stats and stats[3] > 0:
2356 if stats and stats[3] > 0:
2356 # write out state for --continue
2357 # write out state for --continue
2357 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2358 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2358 repo.vfs.write('graftstate', ''.join(nodelines))
2359 repo.vfs.write('graftstate', ''.join(nodelines))
2359 extra = ''
2360 extra = ''
2360 if opts.get('user'):
2361 if opts.get('user'):
2361 extra += ' --user %s' % util.shellquote(opts['user'])
2362 extra += ' --user %s' % util.shellquote(opts['user'])
2362 if opts.get('date'):
2363 if opts.get('date'):
2363 extra += ' --date %s' % util.shellquote(opts['date'])
2364 extra += ' --date %s' % util.shellquote(opts['date'])
2364 if opts.get('log'):
2365 if opts.get('log'):
2365 extra += ' --log'
2366 extra += ' --log'
2366 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2367 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2367 raise error.Abort(
2368 raise error.Abort(
2368 _("unresolved conflicts, can't continue"),
2369 _("unresolved conflicts, can't continue"),
2369 hint=hint)
2370 hint=hint)
2370 else:
2371 else:
2371 cont = False
2372 cont = False
2372
2373
2373 # commit
2374 # commit
2374 node = repo.commit(text=message, user=user,
2375 node = repo.commit(text=message, user=user,
2375 date=date, extra=extra, editor=editor)
2376 date=date, extra=extra, editor=editor)
2376 if node is None:
2377 if node is None:
2377 ui.warn(
2378 ui.warn(
2378 _('note: graft of %d:%s created no changes to commit\n') %
2379 _('note: graft of %d:%s created no changes to commit\n') %
2379 (ctx.rev(), ctx))
2380 (ctx.rev(), ctx))
2380
2381
2381 # remove state when we complete successfully
2382 # remove state when we complete successfully
2382 if not opts.get('dry_run'):
2383 if not opts.get('dry_run'):
2383 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2384 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2384
2385
2385 return 0
2386 return 0
2386
2387
2387 @command('grep',
2388 @command('grep',
2388 [('0', 'print0', None, _('end fields with NUL')),
2389 [('0', 'print0', None, _('end fields with NUL')),
2389 ('', 'all', None, _('print all revisions that match')),
2390 ('', 'all', None, _('print all revisions that match')),
2390 ('a', 'text', None, _('treat all files as text')),
2391 ('a', 'text', None, _('treat all files as text')),
2391 ('f', 'follow', None,
2392 ('f', 'follow', None,
2392 _('follow changeset history,'
2393 _('follow changeset history,'
2393 ' or file history across copies and renames')),
2394 ' or file history across copies and renames')),
2394 ('i', 'ignore-case', None, _('ignore case when matching')),
2395 ('i', 'ignore-case', None, _('ignore case when matching')),
2395 ('l', 'files-with-matches', None,
2396 ('l', 'files-with-matches', None,
2396 _('print only filenames and revisions that match')),
2397 _('print only filenames and revisions that match')),
2397 ('n', 'line-number', None, _('print matching line numbers')),
2398 ('n', 'line-number', None, _('print matching line numbers')),
2398 ('r', 'rev', [],
2399 ('r', 'rev', [],
2399 _('only search files changed within revision range'), _('REV')),
2400 _('only search files changed within revision range'), _('REV')),
2400 ('u', 'user', None, _('list the author (long with -v)')),
2401 ('u', 'user', None, _('list the author (long with -v)')),
2401 ('d', 'date', None, _('list the date (short with -q)')),
2402 ('d', 'date', None, _('list the date (short with -q)')),
2402 ] + formatteropts + walkopts,
2403 ] + formatteropts + walkopts,
2403 _('[OPTION]... PATTERN [FILE]...'),
2404 _('[OPTION]... PATTERN [FILE]...'),
2404 inferrepo=True)
2405 inferrepo=True)
2405 def grep(ui, repo, pattern, *pats, **opts):
2406 def grep(ui, repo, pattern, *pats, **opts):
2406 """search revision history for a pattern in specified files
2407 """search revision history for a pattern in specified files
2407
2408
2408 Search revision history for a regular expression in the specified
2409 Search revision history for a regular expression in the specified
2409 files or the entire project.
2410 files or the entire project.
2410
2411
2411 By default, grep prints the most recent revision number for each
2412 By default, grep prints the most recent revision number for each
2412 file in which it finds a match. To get it to print every revision
2413 file in which it finds a match. To get it to print every revision
2413 that contains a change in match status ("-" for a match that becomes
2414 that contains a change in match status ("-" for a match that becomes
2414 a non-match, or "+" for a non-match that becomes a match), use the
2415 a non-match, or "+" for a non-match that becomes a match), use the
2415 --all flag.
2416 --all flag.
2416
2417
2417 PATTERN can be any Python (roughly Perl-compatible) regular
2418 PATTERN can be any Python (roughly Perl-compatible) regular
2418 expression.
2419 expression.
2419
2420
2420 If no FILEs are specified (and -f/--follow isn't set), all files in
2421 If no FILEs are specified (and -f/--follow isn't set), all files in
2421 the repository are searched, including those that don't exist in the
2422 the repository are searched, including those that don't exist in the
2422 current branch or have been deleted in a prior changeset.
2423 current branch or have been deleted in a prior changeset.
2423
2424
2424 Returns 0 if a match is found, 1 otherwise.
2425 Returns 0 if a match is found, 1 otherwise.
2425 """
2426 """
2426 reflags = re.M
2427 reflags = re.M
2427 if opts.get('ignore_case'):
2428 if opts.get('ignore_case'):
2428 reflags |= re.I
2429 reflags |= re.I
2429 try:
2430 try:
2430 regexp = util.re.compile(pattern, reflags)
2431 regexp = util.re.compile(pattern, reflags)
2431 except re.error as inst:
2432 except re.error as inst:
2432 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2433 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2433 return 1
2434 return 1
2434 sep, eol = ':', '\n'
2435 sep, eol = ':', '\n'
2435 if opts.get('print0'):
2436 if opts.get('print0'):
2436 sep = eol = '\0'
2437 sep = eol = '\0'
2437
2438
2438 getfile = util.lrucachefunc(repo.file)
2439 getfile = util.lrucachefunc(repo.file)
2439
2440
2440 def matchlines(body):
2441 def matchlines(body):
2441 begin = 0
2442 begin = 0
2442 linenum = 0
2443 linenum = 0
2443 while begin < len(body):
2444 while begin < len(body):
2444 match = regexp.search(body, begin)
2445 match = regexp.search(body, begin)
2445 if not match:
2446 if not match:
2446 break
2447 break
2447 mstart, mend = match.span()
2448 mstart, mend = match.span()
2448 linenum += body.count('\n', begin, mstart) + 1
2449 linenum += body.count('\n', begin, mstart) + 1
2449 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2450 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2450 begin = body.find('\n', mend) + 1 or len(body) + 1
2451 begin = body.find('\n', mend) + 1 or len(body) + 1
2451 lend = begin - 1
2452 lend = begin - 1
2452 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2453 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2453
2454
2454 class linestate(object):
2455 class linestate(object):
2455 def __init__(self, line, linenum, colstart, colend):
2456 def __init__(self, line, linenum, colstart, colend):
2456 self.line = line
2457 self.line = line
2457 self.linenum = linenum
2458 self.linenum = linenum
2458 self.colstart = colstart
2459 self.colstart = colstart
2459 self.colend = colend
2460 self.colend = colend
2460
2461
2461 def __hash__(self):
2462 def __hash__(self):
2462 return hash((self.linenum, self.line))
2463 return hash((self.linenum, self.line))
2463
2464
2464 def __eq__(self, other):
2465 def __eq__(self, other):
2465 return self.line == other.line
2466 return self.line == other.line
2466
2467
2467 def findpos(self):
2468 def findpos(self):
2468 """Iterate all (start, end) indices of matches"""
2469 """Iterate all (start, end) indices of matches"""
2469 yield self.colstart, self.colend
2470 yield self.colstart, self.colend
2470 p = self.colend
2471 p = self.colend
2471 while p < len(self.line):
2472 while p < len(self.line):
2472 m = regexp.search(self.line, p)
2473 m = regexp.search(self.line, p)
2473 if not m:
2474 if not m:
2474 break
2475 break
2475 yield m.span()
2476 yield m.span()
2476 p = m.end()
2477 p = m.end()
2477
2478
2478 matches = {}
2479 matches = {}
2479 copies = {}
2480 copies = {}
2480 def grepbody(fn, rev, body):
2481 def grepbody(fn, rev, body):
2481 matches[rev].setdefault(fn, [])
2482 matches[rev].setdefault(fn, [])
2482 m = matches[rev][fn]
2483 m = matches[rev][fn]
2483 for lnum, cstart, cend, line in matchlines(body):
2484 for lnum, cstart, cend, line in matchlines(body):
2484 s = linestate(line, lnum, cstart, cend)
2485 s = linestate(line, lnum, cstart, cend)
2485 m.append(s)
2486 m.append(s)
2486
2487
2487 def difflinestates(a, b):
2488 def difflinestates(a, b):
2488 sm = difflib.SequenceMatcher(None, a, b)
2489 sm = difflib.SequenceMatcher(None, a, b)
2489 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2490 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2490 if tag == 'insert':
2491 if tag == 'insert':
2491 for i in xrange(blo, bhi):
2492 for i in xrange(blo, bhi):
2492 yield ('+', b[i])
2493 yield ('+', b[i])
2493 elif tag == 'delete':
2494 elif tag == 'delete':
2494 for i in xrange(alo, ahi):
2495 for i in xrange(alo, ahi):
2495 yield ('-', a[i])
2496 yield ('-', a[i])
2496 elif tag == 'replace':
2497 elif tag == 'replace':
2497 for i in xrange(alo, ahi):
2498 for i in xrange(alo, ahi):
2498 yield ('-', a[i])
2499 yield ('-', a[i])
2499 for i in xrange(blo, bhi):
2500 for i in xrange(blo, bhi):
2500 yield ('+', b[i])
2501 yield ('+', b[i])
2501
2502
2502 def display(fm, fn, ctx, pstates, states):
2503 def display(fm, fn, ctx, pstates, states):
2503 rev = ctx.rev()
2504 rev = ctx.rev()
2504 if fm.isplain():
2505 if fm.isplain():
2505 formatuser = ui.shortuser
2506 formatuser = ui.shortuser
2506 else:
2507 else:
2507 formatuser = str
2508 formatuser = str
2508 if ui.quiet:
2509 if ui.quiet:
2509 datefmt = '%Y-%m-%d'
2510 datefmt = '%Y-%m-%d'
2510 else:
2511 else:
2511 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2512 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2512 found = False
2513 found = False
2513 @util.cachefunc
2514 @util.cachefunc
2514 def binary():
2515 def binary():
2515 flog = getfile(fn)
2516 flog = getfile(fn)
2516 return util.binary(flog.read(ctx.filenode(fn)))
2517 return util.binary(flog.read(ctx.filenode(fn)))
2517
2518
2518 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2519 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2519 if opts.get('all'):
2520 if opts.get('all'):
2520 iter = difflinestates(pstates, states)
2521 iter = difflinestates(pstates, states)
2521 else:
2522 else:
2522 iter = [('', l) for l in states]
2523 iter = [('', l) for l in states]
2523 for change, l in iter:
2524 for change, l in iter:
2524 fm.startitem()
2525 fm.startitem()
2525 fm.data(node=fm.hexfunc(ctx.node()))
2526 fm.data(node=fm.hexfunc(ctx.node()))
2526 cols = [
2527 cols = [
2527 ('filename', fn, True),
2528 ('filename', fn, True),
2528 ('rev', rev, True),
2529 ('rev', rev, True),
2529 ('linenumber', l.linenum, opts.get('line_number')),
2530 ('linenumber', l.linenum, opts.get('line_number')),
2530 ]
2531 ]
2531 if opts.get('all'):
2532 if opts.get('all'):
2532 cols.append(('change', change, True))
2533 cols.append(('change', change, True))
2533 cols.extend([
2534 cols.extend([
2534 ('user', formatuser(ctx.user()), opts.get('user')),
2535 ('user', formatuser(ctx.user()), opts.get('user')),
2535 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2536 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2536 ])
2537 ])
2537 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2538 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2538 for name, data, cond in cols:
2539 for name, data, cond in cols:
2539 field = fieldnamemap.get(name, name)
2540 field = fieldnamemap.get(name, name)
2540 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2541 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2541 if cond and name != lastcol:
2542 if cond and name != lastcol:
2542 fm.plain(sep, label='grep.sep')
2543 fm.plain(sep, label='grep.sep')
2543 if not opts.get('files_with_matches'):
2544 if not opts.get('files_with_matches'):
2544 fm.plain(sep, label='grep.sep')
2545 fm.plain(sep, label='grep.sep')
2545 if not opts.get('text') and binary():
2546 if not opts.get('text') and binary():
2546 fm.plain(_(" Binary file matches"))
2547 fm.plain(_(" Binary file matches"))
2547 else:
2548 else:
2548 displaymatches(fm.nested('texts'), l)
2549 displaymatches(fm.nested('texts'), l)
2549 fm.plain(eol)
2550 fm.plain(eol)
2550 found = True
2551 found = True
2551 if opts.get('files_with_matches'):
2552 if opts.get('files_with_matches'):
2552 break
2553 break
2553 return found
2554 return found
2554
2555
2555 def displaymatches(fm, l):
2556 def displaymatches(fm, l):
2556 p = 0
2557 p = 0
2557 for s, e in l.findpos():
2558 for s, e in l.findpos():
2558 if p < s:
2559 if p < s:
2559 fm.startitem()
2560 fm.startitem()
2560 fm.write('text', '%s', l.line[p:s])
2561 fm.write('text', '%s', l.line[p:s])
2561 fm.data(matched=False)
2562 fm.data(matched=False)
2562 fm.startitem()
2563 fm.startitem()
2563 fm.write('text', '%s', l.line[s:e], label='grep.match')
2564 fm.write('text', '%s', l.line[s:e], label='grep.match')
2564 fm.data(matched=True)
2565 fm.data(matched=True)
2565 p = e
2566 p = e
2566 if p < len(l.line):
2567 if p < len(l.line):
2567 fm.startitem()
2568 fm.startitem()
2568 fm.write('text', '%s', l.line[p:])
2569 fm.write('text', '%s', l.line[p:])
2569 fm.data(matched=False)
2570 fm.data(matched=False)
2570 fm.end()
2571 fm.end()
2571
2572
2572 skip = {}
2573 skip = {}
2573 revfiles = {}
2574 revfiles = {}
2574 matchfn = scmutil.match(repo[None], pats, opts)
2575 matchfn = scmutil.match(repo[None], pats, opts)
2575 found = False
2576 found = False
2576 follow = opts.get('follow')
2577 follow = opts.get('follow')
2577
2578
2578 def prep(ctx, fns):
2579 def prep(ctx, fns):
2579 rev = ctx.rev()
2580 rev = ctx.rev()
2580 pctx = ctx.p1()
2581 pctx = ctx.p1()
2581 parent = pctx.rev()
2582 parent = pctx.rev()
2582 matches.setdefault(rev, {})
2583 matches.setdefault(rev, {})
2583 matches.setdefault(parent, {})
2584 matches.setdefault(parent, {})
2584 files = revfiles.setdefault(rev, [])
2585 files = revfiles.setdefault(rev, [])
2585 for fn in fns:
2586 for fn in fns:
2586 flog = getfile(fn)
2587 flog = getfile(fn)
2587 try:
2588 try:
2588 fnode = ctx.filenode(fn)
2589 fnode = ctx.filenode(fn)
2589 except error.LookupError:
2590 except error.LookupError:
2590 continue
2591 continue
2591
2592
2592 copied = flog.renamed(fnode)
2593 copied = flog.renamed(fnode)
2593 copy = follow and copied and copied[0]
2594 copy = follow and copied and copied[0]
2594 if copy:
2595 if copy:
2595 copies.setdefault(rev, {})[fn] = copy
2596 copies.setdefault(rev, {})[fn] = copy
2596 if fn in skip:
2597 if fn in skip:
2597 if copy:
2598 if copy:
2598 skip[copy] = True
2599 skip[copy] = True
2599 continue
2600 continue
2600 files.append(fn)
2601 files.append(fn)
2601
2602
2602 if fn not in matches[rev]:
2603 if fn not in matches[rev]:
2603 grepbody(fn, rev, flog.read(fnode))
2604 grepbody(fn, rev, flog.read(fnode))
2604
2605
2605 pfn = copy or fn
2606 pfn = copy or fn
2606 if pfn not in matches[parent]:
2607 if pfn not in matches[parent]:
2607 try:
2608 try:
2608 fnode = pctx.filenode(pfn)
2609 fnode = pctx.filenode(pfn)
2609 grepbody(pfn, parent, flog.read(fnode))
2610 grepbody(pfn, parent, flog.read(fnode))
2610 except error.LookupError:
2611 except error.LookupError:
2611 pass
2612 pass
2612
2613
2613 ui.pager('grep')
2614 ui.pager('grep')
2614 fm = ui.formatter('grep', opts)
2615 fm = ui.formatter('grep', opts)
2615 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2616 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2616 rev = ctx.rev()
2617 rev = ctx.rev()
2617 parent = ctx.p1().rev()
2618 parent = ctx.p1().rev()
2618 for fn in sorted(revfiles.get(rev, [])):
2619 for fn in sorted(revfiles.get(rev, [])):
2619 states = matches[rev][fn]
2620 states = matches[rev][fn]
2620 copy = copies.get(rev, {}).get(fn)
2621 copy = copies.get(rev, {}).get(fn)
2621 if fn in skip:
2622 if fn in skip:
2622 if copy:
2623 if copy:
2623 skip[copy] = True
2624 skip[copy] = True
2624 continue
2625 continue
2625 pstates = matches.get(parent, {}).get(copy or fn, [])
2626 pstates = matches.get(parent, {}).get(copy or fn, [])
2626 if pstates or states:
2627 if pstates or states:
2627 r = display(fm, fn, ctx, pstates, states)
2628 r = display(fm, fn, ctx, pstates, states)
2628 found = found or r
2629 found = found or r
2629 if r and not opts.get('all'):
2630 if r and not opts.get('all'):
2630 skip[fn] = True
2631 skip[fn] = True
2631 if copy:
2632 if copy:
2632 skip[copy] = True
2633 skip[copy] = True
2633 del matches[rev]
2634 del matches[rev]
2634 del revfiles[rev]
2635 del revfiles[rev]
2635 fm.end()
2636 fm.end()
2636
2637
2637 return not found
2638 return not found
2638
2639
2639 @command('heads',
2640 @command('heads',
2640 [('r', 'rev', '',
2641 [('r', 'rev', '',
2641 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2642 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2642 ('t', 'topo', False, _('show topological heads only')),
2643 ('t', 'topo', False, _('show topological heads only')),
2643 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2644 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2644 ('c', 'closed', False, _('show normal and closed branch heads')),
2645 ('c', 'closed', False, _('show normal and closed branch heads')),
2645 ] + templateopts,
2646 ] + templateopts,
2646 _('[-ct] [-r STARTREV] [REV]...'))
2647 _('[-ct] [-r STARTREV] [REV]...'))
2647 def heads(ui, repo, *branchrevs, **opts):
2648 def heads(ui, repo, *branchrevs, **opts):
2648 """show branch heads
2649 """show branch heads
2649
2650
2650 With no arguments, show all open branch heads in the repository.
2651 With no arguments, show all open branch heads in the repository.
2651 Branch heads are changesets that have no descendants on the
2652 Branch heads are changesets that have no descendants on the
2652 same branch. They are where development generally takes place and
2653 same branch. They are where development generally takes place and
2653 are the usual targets for update and merge operations.
2654 are the usual targets for update and merge operations.
2654
2655
2655 If one or more REVs are given, only open branch heads on the
2656 If one or more REVs are given, only open branch heads on the
2656 branches associated with the specified changesets are shown. This
2657 branches associated with the specified changesets are shown. This
2657 means that you can use :hg:`heads .` to see the heads on the
2658 means that you can use :hg:`heads .` to see the heads on the
2658 currently checked-out branch.
2659 currently checked-out branch.
2659
2660
2660 If -c/--closed is specified, also show branch heads marked closed
2661 If -c/--closed is specified, also show branch heads marked closed
2661 (see :hg:`commit --close-branch`).
2662 (see :hg:`commit --close-branch`).
2662
2663
2663 If STARTREV is specified, only those heads that are descendants of
2664 If STARTREV is specified, only those heads that are descendants of
2664 STARTREV will be displayed.
2665 STARTREV will be displayed.
2665
2666
2666 If -t/--topo is specified, named branch mechanics will be ignored and only
2667 If -t/--topo is specified, named branch mechanics will be ignored and only
2667 topological heads (changesets with no children) will be shown.
2668 topological heads (changesets with no children) will be shown.
2668
2669
2669 Returns 0 if matching heads are found, 1 if not.
2670 Returns 0 if matching heads are found, 1 if not.
2670 """
2671 """
2671
2672
2672 start = None
2673 start = None
2673 if 'rev' in opts:
2674 if 'rev' in opts:
2674 start = scmutil.revsingle(repo, opts['rev'], None).node()
2675 start = scmutil.revsingle(repo, opts['rev'], None).node()
2675
2676
2676 if opts.get('topo'):
2677 if opts.get('topo'):
2677 heads = [repo[h] for h in repo.heads(start)]
2678 heads = [repo[h] for h in repo.heads(start)]
2678 else:
2679 else:
2679 heads = []
2680 heads = []
2680 for branch in repo.branchmap():
2681 for branch in repo.branchmap():
2681 heads += repo.branchheads(branch, start, opts.get('closed'))
2682 heads += repo.branchheads(branch, start, opts.get('closed'))
2682 heads = [repo[h] for h in heads]
2683 heads = [repo[h] for h in heads]
2683
2684
2684 if branchrevs:
2685 if branchrevs:
2685 branches = set(repo[br].branch() for br in branchrevs)
2686 branches = set(repo[br].branch() for br in branchrevs)
2686 heads = [h for h in heads if h.branch() in branches]
2687 heads = [h for h in heads if h.branch() in branches]
2687
2688
2688 if opts.get('active') and branchrevs:
2689 if opts.get('active') and branchrevs:
2689 dagheads = repo.heads(start)
2690 dagheads = repo.heads(start)
2690 heads = [h for h in heads if h.node() in dagheads]
2691 heads = [h for h in heads if h.node() in dagheads]
2691
2692
2692 if branchrevs:
2693 if branchrevs:
2693 haveheads = set(h.branch() for h in heads)
2694 haveheads = set(h.branch() for h in heads)
2694 if branches - haveheads:
2695 if branches - haveheads:
2695 headless = ', '.join(b for b in branches - haveheads)
2696 headless = ', '.join(b for b in branches - haveheads)
2696 msg = _('no open branch heads found on branches %s')
2697 msg = _('no open branch heads found on branches %s')
2697 if opts.get('rev'):
2698 if opts.get('rev'):
2698 msg += _(' (started at %s)') % opts['rev']
2699 msg += _(' (started at %s)') % opts['rev']
2699 ui.warn((msg + '\n') % headless)
2700 ui.warn((msg + '\n') % headless)
2700
2701
2701 if not heads:
2702 if not heads:
2702 return 1
2703 return 1
2703
2704
2704 heads = sorted(heads, key=lambda x: -x.rev())
2705 heads = sorted(heads, key=lambda x: -x.rev())
2705 displayer = cmdutil.show_changeset(ui, repo, opts)
2706 displayer = cmdutil.show_changeset(ui, repo, opts)
2706 for ctx in heads:
2707 for ctx in heads:
2707 displayer.show(ctx)
2708 displayer.show(ctx)
2708 displayer.close()
2709 displayer.close()
2709
2710
2710 @command('help',
2711 @command('help',
2711 [('e', 'extension', None, _('show only help for extensions')),
2712 [('e', 'extension', None, _('show only help for extensions')),
2712 ('c', 'command', None, _('show only help for commands')),
2713 ('c', 'command', None, _('show only help for commands')),
2713 ('k', 'keyword', None, _('show topics matching keyword')),
2714 ('k', 'keyword', None, _('show topics matching keyword')),
2714 ('s', 'system', [], _('show help for specific platform(s)')),
2715 ('s', 'system', [], _('show help for specific platform(s)')),
2715 ],
2716 ],
2716 _('[-ecks] [TOPIC]'),
2717 _('[-ecks] [TOPIC]'),
2717 norepo=True)
2718 norepo=True)
2718 def help_(ui, name=None, **opts):
2719 def help_(ui, name=None, **opts):
2719 """show help for a given topic or a help overview
2720 """show help for a given topic or a help overview
2720
2721
2721 With no arguments, print a list of commands with short help messages.
2722 With no arguments, print a list of commands with short help messages.
2722
2723
2723 Given a topic, extension, or command name, print help for that
2724 Given a topic, extension, or command name, print help for that
2724 topic.
2725 topic.
2725
2726
2726 Returns 0 if successful.
2727 Returns 0 if successful.
2727 """
2728 """
2728
2729
2729 keep = opts.get('system') or []
2730 keep = opts.get('system') or []
2730 if len(keep) == 0:
2731 if len(keep) == 0:
2731 if pycompat.sysplatform.startswith('win'):
2732 if pycompat.sysplatform.startswith('win'):
2732 keep.append('windows')
2733 keep.append('windows')
2733 elif pycompat.sysplatform == 'OpenVMS':
2734 elif pycompat.sysplatform == 'OpenVMS':
2734 keep.append('vms')
2735 keep.append('vms')
2735 elif pycompat.sysplatform == 'plan9':
2736 elif pycompat.sysplatform == 'plan9':
2736 keep.append('plan9')
2737 keep.append('plan9')
2737 else:
2738 else:
2738 keep.append('unix')
2739 keep.append('unix')
2739 keep.append(pycompat.sysplatform.lower())
2740 keep.append(pycompat.sysplatform.lower())
2740 if ui.verbose:
2741 if ui.verbose:
2741 keep.append('verbose')
2742 keep.append('verbose')
2742
2743
2743 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2744 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2744 ui.pager('help')
2745 ui.pager('help')
2745 ui.write(formatted)
2746 ui.write(formatted)
2746
2747
2747
2748
2748 @command('identify|id',
2749 @command('identify|id',
2749 [('r', 'rev', '',
2750 [('r', 'rev', '',
2750 _('identify the specified revision'), _('REV')),
2751 _('identify the specified revision'), _('REV')),
2751 ('n', 'num', None, _('show local revision number')),
2752 ('n', 'num', None, _('show local revision number')),
2752 ('i', 'id', None, _('show global revision id')),
2753 ('i', 'id', None, _('show global revision id')),
2753 ('b', 'branch', None, _('show branch')),
2754 ('b', 'branch', None, _('show branch')),
2754 ('t', 'tags', None, _('show tags')),
2755 ('t', 'tags', None, _('show tags')),
2755 ('B', 'bookmarks', None, _('show bookmarks')),
2756 ('B', 'bookmarks', None, _('show bookmarks')),
2756 ] + remoteopts,
2757 ] + remoteopts,
2757 _('[-nibtB] [-r REV] [SOURCE]'),
2758 _('[-nibtB] [-r REV] [SOURCE]'),
2758 optionalrepo=True)
2759 optionalrepo=True)
2759 def identify(ui, repo, source=None, rev=None,
2760 def identify(ui, repo, source=None, rev=None,
2760 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2761 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2761 """identify the working directory or specified revision
2762 """identify the working directory or specified revision
2762
2763
2763 Print a summary identifying the repository state at REV using one or
2764 Print a summary identifying the repository state at REV using one or
2764 two parent hash identifiers, followed by a "+" if the working
2765 two parent hash identifiers, followed by a "+" if the working
2765 directory has uncommitted changes, the branch name (if not default),
2766 directory has uncommitted changes, the branch name (if not default),
2766 a list of tags, and a list of bookmarks.
2767 a list of tags, and a list of bookmarks.
2767
2768
2768 When REV is not given, print a summary of the current state of the
2769 When REV is not given, print a summary of the current state of the
2769 repository.
2770 repository.
2770
2771
2771 Specifying a path to a repository root or Mercurial bundle will
2772 Specifying a path to a repository root or Mercurial bundle will
2772 cause lookup to operate on that repository/bundle.
2773 cause lookup to operate on that repository/bundle.
2773
2774
2774 .. container:: verbose
2775 .. container:: verbose
2775
2776
2776 Examples:
2777 Examples:
2777
2778
2778 - generate a build identifier for the working directory::
2779 - generate a build identifier for the working directory::
2779
2780
2780 hg id --id > build-id.dat
2781 hg id --id > build-id.dat
2781
2782
2782 - find the revision corresponding to a tag::
2783 - find the revision corresponding to a tag::
2783
2784
2784 hg id -n -r 1.3
2785 hg id -n -r 1.3
2785
2786
2786 - check the most recent revision of a remote repository::
2787 - check the most recent revision of a remote repository::
2787
2788
2788 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2789 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2789
2790
2790 See :hg:`log` for generating more information about specific revisions,
2791 See :hg:`log` for generating more information about specific revisions,
2791 including full hash identifiers.
2792 including full hash identifiers.
2792
2793
2793 Returns 0 if successful.
2794 Returns 0 if successful.
2794 """
2795 """
2795
2796
2796 if not repo and not source:
2797 if not repo and not source:
2797 raise error.Abort(_("there is no Mercurial repository here "
2798 raise error.Abort(_("there is no Mercurial repository here "
2798 "(.hg not found)"))
2799 "(.hg not found)"))
2799
2800
2800 if ui.debugflag:
2801 if ui.debugflag:
2801 hexfunc = hex
2802 hexfunc = hex
2802 else:
2803 else:
2803 hexfunc = short
2804 hexfunc = short
2804 default = not (num or id or branch or tags or bookmarks)
2805 default = not (num or id or branch or tags or bookmarks)
2805 output = []
2806 output = []
2806 revs = []
2807 revs = []
2807
2808
2808 if source:
2809 if source:
2809 source, branches = hg.parseurl(ui.expandpath(source))
2810 source, branches = hg.parseurl(ui.expandpath(source))
2810 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2811 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2811 repo = peer.local()
2812 repo = peer.local()
2812 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2813 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2813
2814
2814 if not repo:
2815 if not repo:
2815 if num or branch or tags:
2816 if num or branch or tags:
2816 raise error.Abort(
2817 raise error.Abort(
2817 _("can't query remote revision number, branch, or tags"))
2818 _("can't query remote revision number, branch, or tags"))
2818 if not rev and revs:
2819 if not rev and revs:
2819 rev = revs[0]
2820 rev = revs[0]
2820 if not rev:
2821 if not rev:
2821 rev = "tip"
2822 rev = "tip"
2822
2823
2823 remoterev = peer.lookup(rev)
2824 remoterev = peer.lookup(rev)
2824 if default or id:
2825 if default or id:
2825 output = [hexfunc(remoterev)]
2826 output = [hexfunc(remoterev)]
2826
2827
2827 def getbms():
2828 def getbms():
2828 bms = []
2829 bms = []
2829
2830
2830 if 'bookmarks' in peer.listkeys('namespaces'):
2831 if 'bookmarks' in peer.listkeys('namespaces'):
2831 hexremoterev = hex(remoterev)
2832 hexremoterev = hex(remoterev)
2832 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2833 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2833 if bmr == hexremoterev]
2834 if bmr == hexremoterev]
2834
2835
2835 return sorted(bms)
2836 return sorted(bms)
2836
2837
2837 if bookmarks:
2838 if bookmarks:
2838 output.extend(getbms())
2839 output.extend(getbms())
2839 elif default and not ui.quiet:
2840 elif default and not ui.quiet:
2840 # multiple bookmarks for a single parent separated by '/'
2841 # multiple bookmarks for a single parent separated by '/'
2841 bm = '/'.join(getbms())
2842 bm = '/'.join(getbms())
2842 if bm:
2843 if bm:
2843 output.append(bm)
2844 output.append(bm)
2844 else:
2845 else:
2845 ctx = scmutil.revsingle(repo, rev, None)
2846 ctx = scmutil.revsingle(repo, rev, None)
2846
2847
2847 if ctx.rev() is None:
2848 if ctx.rev() is None:
2848 ctx = repo[None]
2849 ctx = repo[None]
2849 parents = ctx.parents()
2850 parents = ctx.parents()
2850 taglist = []
2851 taglist = []
2851 for p in parents:
2852 for p in parents:
2852 taglist.extend(p.tags())
2853 taglist.extend(p.tags())
2853
2854
2854 changed = ""
2855 changed = ""
2855 if default or id or num:
2856 if default or id or num:
2856 if (any(repo.status())
2857 if (any(repo.status())
2857 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2858 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2858 changed = '+'
2859 changed = '+'
2859 if default or id:
2860 if default or id:
2860 output = ["%s%s" %
2861 output = ["%s%s" %
2861 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2862 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2862 if num:
2863 if num:
2863 output.append("%s%s" %
2864 output.append("%s%s" %
2864 ('+'.join([str(p.rev()) for p in parents]), changed))
2865 ('+'.join([str(p.rev()) for p in parents]), changed))
2865 else:
2866 else:
2866 if default or id:
2867 if default or id:
2867 output = [hexfunc(ctx.node())]
2868 output = [hexfunc(ctx.node())]
2868 if num:
2869 if num:
2869 output.append(str(ctx.rev()))
2870 output.append(str(ctx.rev()))
2870 taglist = ctx.tags()
2871 taglist = ctx.tags()
2871
2872
2872 if default and not ui.quiet:
2873 if default and not ui.quiet:
2873 b = ctx.branch()
2874 b = ctx.branch()
2874 if b != 'default':
2875 if b != 'default':
2875 output.append("(%s)" % b)
2876 output.append("(%s)" % b)
2876
2877
2877 # multiple tags for a single parent separated by '/'
2878 # multiple tags for a single parent separated by '/'
2878 t = '/'.join(taglist)
2879 t = '/'.join(taglist)
2879 if t:
2880 if t:
2880 output.append(t)
2881 output.append(t)
2881
2882
2882 # multiple bookmarks for a single parent separated by '/'
2883 # multiple bookmarks for a single parent separated by '/'
2883 bm = '/'.join(ctx.bookmarks())
2884 bm = '/'.join(ctx.bookmarks())
2884 if bm:
2885 if bm:
2885 output.append(bm)
2886 output.append(bm)
2886 else:
2887 else:
2887 if branch:
2888 if branch:
2888 output.append(ctx.branch())
2889 output.append(ctx.branch())
2889
2890
2890 if tags:
2891 if tags:
2891 output.extend(taglist)
2892 output.extend(taglist)
2892
2893
2893 if bookmarks:
2894 if bookmarks:
2894 output.extend(ctx.bookmarks())
2895 output.extend(ctx.bookmarks())
2895
2896
2896 ui.write("%s\n" % ' '.join(output))
2897 ui.write("%s\n" % ' '.join(output))
2897
2898
2898 @command('import|patch',
2899 @command('import|patch',
2899 [('p', 'strip', 1,
2900 [('p', 'strip', 1,
2900 _('directory strip option for patch. This has the same '
2901 _('directory strip option for patch. This has the same '
2901 'meaning as the corresponding patch option'), _('NUM')),
2902 'meaning as the corresponding patch option'), _('NUM')),
2902 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2903 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2903 ('e', 'edit', False, _('invoke editor on commit messages')),
2904 ('e', 'edit', False, _('invoke editor on commit messages')),
2904 ('f', 'force', None,
2905 ('f', 'force', None,
2905 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2906 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2906 ('', 'no-commit', None,
2907 ('', 'no-commit', None,
2907 _("don't commit, just update the working directory")),
2908 _("don't commit, just update the working directory")),
2908 ('', 'bypass', None,
2909 ('', 'bypass', None,
2909 _("apply patch without touching the working directory")),
2910 _("apply patch without touching the working directory")),
2910 ('', 'partial', None,
2911 ('', 'partial', None,
2911 _('commit even if some hunks fail')),
2912 _('commit even if some hunks fail')),
2912 ('', 'exact', None,
2913 ('', 'exact', None,
2913 _('abort if patch would apply lossily')),
2914 _('abort if patch would apply lossily')),
2914 ('', 'prefix', '',
2915 ('', 'prefix', '',
2915 _('apply patch to subdirectory'), _('DIR')),
2916 _('apply patch to subdirectory'), _('DIR')),
2916 ('', 'import-branch', None,
2917 ('', 'import-branch', None,
2917 _('use any branch information in patch (implied by --exact)'))] +
2918 _('use any branch information in patch (implied by --exact)'))] +
2918 commitopts + commitopts2 + similarityopts,
2919 commitopts + commitopts2 + similarityopts,
2919 _('[OPTION]... PATCH...'))
2920 _('[OPTION]... PATCH...'))
2920 def import_(ui, repo, patch1=None, *patches, **opts):
2921 def import_(ui, repo, patch1=None, *patches, **opts):
2921 """import an ordered set of patches
2922 """import an ordered set of patches
2922
2923
2923 Import a list of patches and commit them individually (unless
2924 Import a list of patches and commit them individually (unless
2924 --no-commit is specified).
2925 --no-commit is specified).
2925
2926
2926 To read a patch from standard input (stdin), use "-" as the patch
2927 To read a patch from standard input (stdin), use "-" as the patch
2927 name. If a URL is specified, the patch will be downloaded from
2928 name. If a URL is specified, the patch will be downloaded from
2928 there.
2929 there.
2929
2930
2930 Import first applies changes to the working directory (unless
2931 Import first applies changes to the working directory (unless
2931 --bypass is specified), import will abort if there are outstanding
2932 --bypass is specified), import will abort if there are outstanding
2932 changes.
2933 changes.
2933
2934
2934 Use --bypass to apply and commit patches directly to the
2935 Use --bypass to apply and commit patches directly to the
2935 repository, without affecting the working directory. Without
2936 repository, without affecting the working directory. Without
2936 --exact, patches will be applied on top of the working directory
2937 --exact, patches will be applied on top of the working directory
2937 parent revision.
2938 parent revision.
2938
2939
2939 You can import a patch straight from a mail message. Even patches
2940 You can import a patch straight from a mail message. Even patches
2940 as attachments work (to use the body part, it must have type
2941 as attachments work (to use the body part, it must have type
2941 text/plain or text/x-patch). From and Subject headers of email
2942 text/plain or text/x-patch). From and Subject headers of email
2942 message are used as default committer and commit message. All
2943 message are used as default committer and commit message. All
2943 text/plain body parts before first diff are added to the commit
2944 text/plain body parts before first diff are added to the commit
2944 message.
2945 message.
2945
2946
2946 If the imported patch was generated by :hg:`export`, user and
2947 If the imported patch was generated by :hg:`export`, user and
2947 description from patch override values from message headers and
2948 description from patch override values from message headers and
2948 body. Values given on command line with -m/--message and -u/--user
2949 body. Values given on command line with -m/--message and -u/--user
2949 override these.
2950 override these.
2950
2951
2951 If --exact is specified, import will set the working directory to
2952 If --exact is specified, import will set the working directory to
2952 the parent of each patch before applying it, and will abort if the
2953 the parent of each patch before applying it, and will abort if the
2953 resulting changeset has a different ID than the one recorded in
2954 resulting changeset has a different ID than the one recorded in
2954 the patch. This will guard against various ways that portable
2955 the patch. This will guard against various ways that portable
2955 patch formats and mail systems might fail to transfer Mercurial
2956 patch formats and mail systems might fail to transfer Mercurial
2956 data or metadata. See :hg:`bundle` for lossless transmission.
2957 data or metadata. See :hg:`bundle` for lossless transmission.
2957
2958
2958 Use --partial to ensure a changeset will be created from the patch
2959 Use --partial to ensure a changeset will be created from the patch
2959 even if some hunks fail to apply. Hunks that fail to apply will be
2960 even if some hunks fail to apply. Hunks that fail to apply will be
2960 written to a <target-file>.rej file. Conflicts can then be resolved
2961 written to a <target-file>.rej file. Conflicts can then be resolved
2961 by hand before :hg:`commit --amend` is run to update the created
2962 by hand before :hg:`commit --amend` is run to update the created
2962 changeset. This flag exists to let people import patches that
2963 changeset. This flag exists to let people import patches that
2963 partially apply without losing the associated metadata (author,
2964 partially apply without losing the associated metadata (author,
2964 date, description, ...).
2965 date, description, ...).
2965
2966
2966 .. note::
2967 .. note::
2967
2968
2968 When no hunks apply cleanly, :hg:`import --partial` will create
2969 When no hunks apply cleanly, :hg:`import --partial` will create
2969 an empty changeset, importing only the patch metadata.
2970 an empty changeset, importing only the patch metadata.
2970
2971
2971 With -s/--similarity, hg will attempt to discover renames and
2972 With -s/--similarity, hg will attempt to discover renames and
2972 copies in the patch in the same way as :hg:`addremove`.
2973 copies in the patch in the same way as :hg:`addremove`.
2973
2974
2974 It is possible to use external patch programs to perform the patch
2975 It is possible to use external patch programs to perform the patch
2975 by setting the ``ui.patch`` configuration option. For the default
2976 by setting the ``ui.patch`` configuration option. For the default
2976 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2977 internal tool, the fuzz can also be configured via ``patch.fuzz``.
2977 See :hg:`help config` for more information about configuration
2978 See :hg:`help config` for more information about configuration
2978 files and how to use these options.
2979 files and how to use these options.
2979
2980
2980 See :hg:`help dates` for a list of formats valid for -d/--date.
2981 See :hg:`help dates` for a list of formats valid for -d/--date.
2981
2982
2982 .. container:: verbose
2983 .. container:: verbose
2983
2984
2984 Examples:
2985 Examples:
2985
2986
2986 - import a traditional patch from a website and detect renames::
2987 - import a traditional patch from a website and detect renames::
2987
2988
2988 hg import -s 80 http://example.com/bugfix.patch
2989 hg import -s 80 http://example.com/bugfix.patch
2989
2990
2990 - import a changeset from an hgweb server::
2991 - import a changeset from an hgweb server::
2991
2992
2992 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2993 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
2993
2994
2994 - import all the patches in an Unix-style mbox::
2995 - import all the patches in an Unix-style mbox::
2995
2996
2996 hg import incoming-patches.mbox
2997 hg import incoming-patches.mbox
2997
2998
2998 - import patches from stdin::
2999 - import patches from stdin::
2999
3000
3000 hg import -
3001 hg import -
3001
3002
3002 - attempt to exactly restore an exported changeset (not always
3003 - attempt to exactly restore an exported changeset (not always
3003 possible)::
3004 possible)::
3004
3005
3005 hg import --exact proposed-fix.patch
3006 hg import --exact proposed-fix.patch
3006
3007
3007 - use an external tool to apply a patch which is too fuzzy for
3008 - use an external tool to apply a patch which is too fuzzy for
3008 the default internal tool.
3009 the default internal tool.
3009
3010
3010 hg import --config ui.patch="patch --merge" fuzzy.patch
3011 hg import --config ui.patch="patch --merge" fuzzy.patch
3011
3012
3012 - change the default fuzzing from 2 to a less strict 7
3013 - change the default fuzzing from 2 to a less strict 7
3013
3014
3014 hg import --config ui.fuzz=7 fuzz.patch
3015 hg import --config ui.fuzz=7 fuzz.patch
3015
3016
3016 Returns 0 on success, 1 on partial success (see --partial).
3017 Returns 0 on success, 1 on partial success (see --partial).
3017 """
3018 """
3018
3019
3019 if not patch1:
3020 if not patch1:
3020 raise error.Abort(_('need at least one patch to import'))
3021 raise error.Abort(_('need at least one patch to import'))
3021
3022
3022 patches = (patch1,) + patches
3023 patches = (patch1,) + patches
3023
3024
3024 date = opts.get('date')
3025 date = opts.get('date')
3025 if date:
3026 if date:
3026 opts['date'] = util.parsedate(date)
3027 opts['date'] = util.parsedate(date)
3027
3028
3028 exact = opts.get('exact')
3029 exact = opts.get('exact')
3029 update = not opts.get('bypass')
3030 update = not opts.get('bypass')
3030 if not update and opts.get('no_commit'):
3031 if not update and opts.get('no_commit'):
3031 raise error.Abort(_('cannot use --no-commit with --bypass'))
3032 raise error.Abort(_('cannot use --no-commit with --bypass'))
3032 try:
3033 try:
3033 sim = float(opts.get('similarity') or 0)
3034 sim = float(opts.get('similarity') or 0)
3034 except ValueError:
3035 except ValueError:
3035 raise error.Abort(_('similarity must be a number'))
3036 raise error.Abort(_('similarity must be a number'))
3036 if sim < 0 or sim > 100:
3037 if sim < 0 or sim > 100:
3037 raise error.Abort(_('similarity must be between 0 and 100'))
3038 raise error.Abort(_('similarity must be between 0 and 100'))
3038 if sim and not update:
3039 if sim and not update:
3039 raise error.Abort(_('cannot use --similarity with --bypass'))
3040 raise error.Abort(_('cannot use --similarity with --bypass'))
3040 if exact:
3041 if exact:
3041 if opts.get('edit'):
3042 if opts.get('edit'):
3042 raise error.Abort(_('cannot use --exact with --edit'))
3043 raise error.Abort(_('cannot use --exact with --edit'))
3043 if opts.get('prefix'):
3044 if opts.get('prefix'):
3044 raise error.Abort(_('cannot use --exact with --prefix'))
3045 raise error.Abort(_('cannot use --exact with --prefix'))
3045
3046
3046 base = opts["base"]
3047 base = opts["base"]
3047 wlock = dsguard = lock = tr = None
3048 wlock = dsguard = lock = tr = None
3048 msgs = []
3049 msgs = []
3049 ret = 0
3050 ret = 0
3050
3051
3051
3052
3052 try:
3053 try:
3053 wlock = repo.wlock()
3054 wlock = repo.wlock()
3054
3055
3055 if update:
3056 if update:
3056 cmdutil.checkunfinished(repo)
3057 cmdutil.checkunfinished(repo)
3057 if (exact or not opts.get('force')):
3058 if (exact or not opts.get('force')):
3058 cmdutil.bailifchanged(repo)
3059 cmdutil.bailifchanged(repo)
3059
3060
3060 if not opts.get('no_commit'):
3061 if not opts.get('no_commit'):
3061 lock = repo.lock()
3062 lock = repo.lock()
3062 tr = repo.transaction('import')
3063 tr = repo.transaction('import')
3063 else:
3064 else:
3064 dsguard = dirstateguard.dirstateguard(repo, 'import')
3065 dsguard = dirstateguard.dirstateguard(repo, 'import')
3065 parents = repo[None].parents()
3066 parents = repo[None].parents()
3066 for patchurl in patches:
3067 for patchurl in patches:
3067 if patchurl == '-':
3068 if patchurl == '-':
3068 ui.status(_('applying patch from stdin\n'))
3069 ui.status(_('applying patch from stdin\n'))
3069 patchfile = ui.fin
3070 patchfile = ui.fin
3070 patchurl = 'stdin' # for error message
3071 patchurl = 'stdin' # for error message
3071 else:
3072 else:
3072 patchurl = os.path.join(base, patchurl)
3073 patchurl = os.path.join(base, patchurl)
3073 ui.status(_('applying %s\n') % patchurl)
3074 ui.status(_('applying %s\n') % patchurl)
3074 patchfile = hg.openpath(ui, patchurl)
3075 patchfile = hg.openpath(ui, patchurl)
3075
3076
3076 haspatch = False
3077 haspatch = False
3077 for hunk in patch.split(patchfile):
3078 for hunk in patch.split(patchfile):
3078 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3079 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3079 parents, opts,
3080 parents, opts,
3080 msgs, hg.clean)
3081 msgs, hg.clean)
3081 if msg:
3082 if msg:
3082 haspatch = True
3083 haspatch = True
3083 ui.note(msg + '\n')
3084 ui.note(msg + '\n')
3084 if update or exact:
3085 if update or exact:
3085 parents = repo[None].parents()
3086 parents = repo[None].parents()
3086 else:
3087 else:
3087 parents = [repo[node]]
3088 parents = [repo[node]]
3088 if rej:
3089 if rej:
3089 ui.write_err(_("patch applied partially\n"))
3090 ui.write_err(_("patch applied partially\n"))
3090 ui.write_err(_("(fix the .rej files and run "
3091 ui.write_err(_("(fix the .rej files and run "
3091 "`hg commit --amend`)\n"))
3092 "`hg commit --amend`)\n"))
3092 ret = 1
3093 ret = 1
3093 break
3094 break
3094
3095
3095 if not haspatch:
3096 if not haspatch:
3096 raise error.Abort(_('%s: no diffs found') % patchurl)
3097 raise error.Abort(_('%s: no diffs found') % patchurl)
3097
3098
3098 if tr:
3099 if tr:
3099 tr.close()
3100 tr.close()
3100 if msgs:
3101 if msgs:
3101 repo.savecommitmessage('\n* * *\n'.join(msgs))
3102 repo.savecommitmessage('\n* * *\n'.join(msgs))
3102 if dsguard:
3103 if dsguard:
3103 dsguard.close()
3104 dsguard.close()
3104 return ret
3105 return ret
3105 finally:
3106 finally:
3106 if tr:
3107 if tr:
3107 tr.release()
3108 tr.release()
3108 release(lock, dsguard, wlock)
3109 release(lock, dsguard, wlock)
3109
3110
3110 @command('incoming|in',
3111 @command('incoming|in',
3111 [('f', 'force', None,
3112 [('f', 'force', None,
3112 _('run even if remote repository is unrelated')),
3113 _('run even if remote repository is unrelated')),
3113 ('n', 'newest-first', None, _('show newest record first')),
3114 ('n', 'newest-first', None, _('show newest record first')),
3114 ('', 'bundle', '',
3115 ('', 'bundle', '',
3115 _('file to store the bundles into'), _('FILE')),
3116 _('file to store the bundles into'), _('FILE')),
3116 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3117 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3117 ('B', 'bookmarks', False, _("compare bookmarks")),
3118 ('B', 'bookmarks', False, _("compare bookmarks")),
3118 ('b', 'branch', [],
3119 ('b', 'branch', [],
3119 _('a specific branch you would like to pull'), _('BRANCH')),
3120 _('a specific branch you would like to pull'), _('BRANCH')),
3120 ] + logopts + remoteopts + subrepoopts,
3121 ] + logopts + remoteopts + subrepoopts,
3121 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3122 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3122 def incoming(ui, repo, source="default", **opts):
3123 def incoming(ui, repo, source="default", **opts):
3123 """show new changesets found in source
3124 """show new changesets found in source
3124
3125
3125 Show new changesets found in the specified path/URL or the default
3126 Show new changesets found in the specified path/URL or the default
3126 pull location. These are the changesets that would have been pulled
3127 pull location. These are the changesets that would have been pulled
3127 if a pull at the time you issued this command.
3128 if a pull at the time you issued this command.
3128
3129
3129 See pull for valid source format details.
3130 See pull for valid source format details.
3130
3131
3131 .. container:: verbose
3132 .. container:: verbose
3132
3133
3133 With -B/--bookmarks, the result of bookmark comparison between
3134 With -B/--bookmarks, the result of bookmark comparison between
3134 local and remote repositories is displayed. With -v/--verbose,
3135 local and remote repositories is displayed. With -v/--verbose,
3135 status is also displayed for each bookmark like below::
3136 status is also displayed for each bookmark like below::
3136
3137
3137 BM1 01234567890a added
3138 BM1 01234567890a added
3138 BM2 1234567890ab advanced
3139 BM2 1234567890ab advanced
3139 BM3 234567890abc diverged
3140 BM3 234567890abc diverged
3140 BM4 34567890abcd changed
3141 BM4 34567890abcd changed
3141
3142
3142 The action taken locally when pulling depends on the
3143 The action taken locally when pulling depends on the
3143 status of each bookmark:
3144 status of each bookmark:
3144
3145
3145 :``added``: pull will create it
3146 :``added``: pull will create it
3146 :``advanced``: pull will update it
3147 :``advanced``: pull will update it
3147 :``diverged``: pull will create a divergent bookmark
3148 :``diverged``: pull will create a divergent bookmark
3148 :``changed``: result depends on remote changesets
3149 :``changed``: result depends on remote changesets
3149
3150
3150 From the point of view of pulling behavior, bookmark
3151 From the point of view of pulling behavior, bookmark
3151 existing only in the remote repository are treated as ``added``,
3152 existing only in the remote repository are treated as ``added``,
3152 even if it is in fact locally deleted.
3153 even if it is in fact locally deleted.
3153
3154
3154 .. container:: verbose
3155 .. container:: verbose
3155
3156
3156 For remote repository, using --bundle avoids downloading the
3157 For remote repository, using --bundle avoids downloading the
3157 changesets twice if the incoming is followed by a pull.
3158 changesets twice if the incoming is followed by a pull.
3158
3159
3159 Examples:
3160 Examples:
3160
3161
3161 - show incoming changes with patches and full description::
3162 - show incoming changes with patches and full description::
3162
3163
3163 hg incoming -vp
3164 hg incoming -vp
3164
3165
3165 - show incoming changes excluding merges, store a bundle::
3166 - show incoming changes excluding merges, store a bundle::
3166
3167
3167 hg in -vpM --bundle incoming.hg
3168 hg in -vpM --bundle incoming.hg
3168 hg pull incoming.hg
3169 hg pull incoming.hg
3169
3170
3170 - briefly list changes inside a bundle::
3171 - briefly list changes inside a bundle::
3171
3172
3172 hg in changes.hg -T "{desc|firstline}\\n"
3173 hg in changes.hg -T "{desc|firstline}\\n"
3173
3174
3174 Returns 0 if there are incoming changes, 1 otherwise.
3175 Returns 0 if there are incoming changes, 1 otherwise.
3175 """
3176 """
3176 if opts.get('graph'):
3177 if opts.get('graph'):
3177 cmdutil.checkunsupportedgraphflags([], opts)
3178 cmdutil.checkunsupportedgraphflags([], opts)
3178 def display(other, chlist, displayer):
3179 def display(other, chlist, displayer):
3179 revdag = cmdutil.graphrevs(other, chlist, opts)
3180 revdag = cmdutil.graphrevs(other, chlist, opts)
3180 cmdutil.displaygraph(ui, repo, revdag, displayer,
3181 cmdutil.displaygraph(ui, repo, revdag, displayer,
3181 graphmod.asciiedges)
3182 graphmod.asciiedges)
3182
3183
3183 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3184 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3184 return 0
3185 return 0
3185
3186
3186 if opts.get('bundle') and opts.get('subrepos'):
3187 if opts.get('bundle') and opts.get('subrepos'):
3187 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3188 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3188
3189
3189 if opts.get('bookmarks'):
3190 if opts.get('bookmarks'):
3190 source, branches = hg.parseurl(ui.expandpath(source),
3191 source, branches = hg.parseurl(ui.expandpath(source),
3191 opts.get('branch'))
3192 opts.get('branch'))
3192 other = hg.peer(repo, opts, source)
3193 other = hg.peer(repo, opts, source)
3193 if 'bookmarks' not in other.listkeys('namespaces'):
3194 if 'bookmarks' not in other.listkeys('namespaces'):
3194 ui.warn(_("remote doesn't support bookmarks\n"))
3195 ui.warn(_("remote doesn't support bookmarks\n"))
3195 return 0
3196 return 0
3196 ui.pager('incoming')
3197 ui.pager('incoming')
3197 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3198 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3198 return bookmarks.incoming(ui, repo, other)
3199 return bookmarks.incoming(ui, repo, other)
3199
3200
3200 repo._subtoppath = ui.expandpath(source)
3201 repo._subtoppath = ui.expandpath(source)
3201 try:
3202 try:
3202 return hg.incoming(ui, repo, source, opts)
3203 return hg.incoming(ui, repo, source, opts)
3203 finally:
3204 finally:
3204 del repo._subtoppath
3205 del repo._subtoppath
3205
3206
3206
3207
3207 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3208 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3208 norepo=True)
3209 norepo=True)
3209 def init(ui, dest=".", **opts):
3210 def init(ui, dest=".", **opts):
3210 """create a new repository in the given directory
3211 """create a new repository in the given directory
3211
3212
3212 Initialize a new repository in the given directory. If the given
3213 Initialize a new repository in the given directory. If the given
3213 directory does not exist, it will be created.
3214 directory does not exist, it will be created.
3214
3215
3215 If no directory is given, the current directory is used.
3216 If no directory is given, the current directory is used.
3216
3217
3217 It is possible to specify an ``ssh://`` URL as the destination.
3218 It is possible to specify an ``ssh://`` URL as the destination.
3218 See :hg:`help urls` for more information.
3219 See :hg:`help urls` for more information.
3219
3220
3220 Returns 0 on success.
3221 Returns 0 on success.
3221 """
3222 """
3222 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3223 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3223
3224
3224 @command('locate',
3225 @command('locate',
3225 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3226 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3226 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3227 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3227 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3228 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3228 ] + walkopts,
3229 ] + walkopts,
3229 _('[OPTION]... [PATTERN]...'))
3230 _('[OPTION]... [PATTERN]...'))
3230 def locate(ui, repo, *pats, **opts):
3231 def locate(ui, repo, *pats, **opts):
3231 """locate files matching specific patterns (DEPRECATED)
3232 """locate files matching specific patterns (DEPRECATED)
3232
3233
3233 Print files under Mercurial control in the working directory whose
3234 Print files under Mercurial control in the working directory whose
3234 names match the given patterns.
3235 names match the given patterns.
3235
3236
3236 By default, this command searches all directories in the working
3237 By default, this command searches all directories in the working
3237 directory. To search just the current directory and its
3238 directory. To search just the current directory and its
3238 subdirectories, use "--include .".
3239 subdirectories, use "--include .".
3239
3240
3240 If no patterns are given to match, this command prints the names
3241 If no patterns are given to match, this command prints the names
3241 of all files under Mercurial control in the working directory.
3242 of all files under Mercurial control in the working directory.
3242
3243
3243 If you want to feed the output of this command into the "xargs"
3244 If you want to feed the output of this command into the "xargs"
3244 command, use the -0 option to both this command and "xargs". This
3245 command, use the -0 option to both this command and "xargs". This
3245 will avoid the problem of "xargs" treating single filenames that
3246 will avoid the problem of "xargs" treating single filenames that
3246 contain whitespace as multiple filenames.
3247 contain whitespace as multiple filenames.
3247
3248
3248 See :hg:`help files` for a more versatile command.
3249 See :hg:`help files` for a more versatile command.
3249
3250
3250 Returns 0 if a match is found, 1 otherwise.
3251 Returns 0 if a match is found, 1 otherwise.
3251 """
3252 """
3252 if opts.get('print0'):
3253 if opts.get('print0'):
3253 end = '\0'
3254 end = '\0'
3254 else:
3255 else:
3255 end = '\n'
3256 end = '\n'
3256 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3257 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3257
3258
3258 ret = 1
3259 ret = 1
3259 ctx = repo[rev]
3260 ctx = repo[rev]
3260 m = scmutil.match(ctx, pats, opts, default='relglob',
3261 m = scmutil.match(ctx, pats, opts, default='relglob',
3261 badfn=lambda x, y: False)
3262 badfn=lambda x, y: False)
3262
3263
3263 ui.pager('locate')
3264 ui.pager('locate')
3264 for abs in ctx.matches(m):
3265 for abs in ctx.matches(m):
3265 if opts.get('fullpath'):
3266 if opts.get('fullpath'):
3266 ui.write(repo.wjoin(abs), end)
3267 ui.write(repo.wjoin(abs), end)
3267 else:
3268 else:
3268 ui.write(((pats and m.rel(abs)) or abs), end)
3269 ui.write(((pats and m.rel(abs)) or abs), end)
3269 ret = 0
3270 ret = 0
3270
3271
3271 return ret
3272 return ret
3272
3273
3273 @command('^log|history',
3274 @command('^log|history',
3274 [('f', 'follow', None,
3275 [('f', 'follow', None,
3275 _('follow changeset history, or file history across copies and renames')),
3276 _('follow changeset history, or file history across copies and renames')),
3276 ('', 'follow-first', None,
3277 ('', 'follow-first', None,
3277 _('only follow the first parent of merge changesets (DEPRECATED)')),
3278 _('only follow the first parent of merge changesets (DEPRECATED)')),
3278 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3279 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3279 ('C', 'copies', None, _('show copied files')),
3280 ('C', 'copies', None, _('show copied files')),
3280 ('k', 'keyword', [],
3281 ('k', 'keyword', [],
3281 _('do case-insensitive search for a given text'), _('TEXT')),
3282 _('do case-insensitive search for a given text'), _('TEXT')),
3282 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3283 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3283 ('', 'removed', None, _('include revisions where files were removed')),
3284 ('', 'removed', None, _('include revisions where files were removed')),
3284 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3285 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3285 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3286 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3286 ('', 'only-branch', [],
3287 ('', 'only-branch', [],
3287 _('show only changesets within the given named branch (DEPRECATED)'),
3288 _('show only changesets within the given named branch (DEPRECATED)'),
3288 _('BRANCH')),
3289 _('BRANCH')),
3289 ('b', 'branch', [],
3290 ('b', 'branch', [],
3290 _('show changesets within the given named branch'), _('BRANCH')),
3291 _('show changesets within the given named branch'), _('BRANCH')),
3291 ('P', 'prune', [],
3292 ('P', 'prune', [],
3292 _('do not display revision or any of its ancestors'), _('REV')),
3293 _('do not display revision or any of its ancestors'), _('REV')),
3293 ] + logopts + walkopts,
3294 ] + logopts + walkopts,
3294 _('[OPTION]... [FILE]'),
3295 _('[OPTION]... [FILE]'),
3295 inferrepo=True)
3296 inferrepo=True)
3296 def log(ui, repo, *pats, **opts):
3297 def log(ui, repo, *pats, **opts):
3297 """show revision history of entire repository or files
3298 """show revision history of entire repository or files
3298
3299
3299 Print the revision history of the specified files or the entire
3300 Print the revision history of the specified files or the entire
3300 project.
3301 project.
3301
3302
3302 If no revision range is specified, the default is ``tip:0`` unless
3303 If no revision range is specified, the default is ``tip:0`` unless
3303 --follow is set, in which case the working directory parent is
3304 --follow is set, in which case the working directory parent is
3304 used as the starting revision.
3305 used as the starting revision.
3305
3306
3306 File history is shown without following rename or copy history of
3307 File history is shown without following rename or copy history of
3307 files. Use -f/--follow with a filename to follow history across
3308 files. Use -f/--follow with a filename to follow history across
3308 renames and copies. --follow without a filename will only show
3309 renames and copies. --follow without a filename will only show
3309 ancestors or descendants of the starting revision.
3310 ancestors or descendants of the starting revision.
3310
3311
3311 By default this command prints revision number and changeset id,
3312 By default this command prints revision number and changeset id,
3312 tags, non-trivial parents, user, date and time, and a summary for
3313 tags, non-trivial parents, user, date and time, and a summary for
3313 each commit. When the -v/--verbose switch is used, the list of
3314 each commit. When the -v/--verbose switch is used, the list of
3314 changed files and full commit message are shown.
3315 changed files and full commit message are shown.
3315
3316
3316 With --graph the revisions are shown as an ASCII art DAG with the most
3317 With --graph the revisions are shown as an ASCII art DAG with the most
3317 recent changeset at the top.
3318 recent changeset at the top.
3318 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3319 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3319 and '+' represents a fork where the changeset from the lines below is a
3320 and '+' represents a fork where the changeset from the lines below is a
3320 parent of the 'o' merge on the same line.
3321 parent of the 'o' merge on the same line.
3321
3322
3322 .. note::
3323 .. note::
3323
3324
3324 :hg:`log --patch` may generate unexpected diff output for merge
3325 :hg:`log --patch` may generate unexpected diff output for merge
3325 changesets, as it will only compare the merge changeset against
3326 changesets, as it will only compare the merge changeset against
3326 its first parent. Also, only files different from BOTH parents
3327 its first parent. Also, only files different from BOTH parents
3327 will appear in files:.
3328 will appear in files:.
3328
3329
3329 .. note::
3330 .. note::
3330
3331
3331 For performance reasons, :hg:`log FILE` may omit duplicate changes
3332 For performance reasons, :hg:`log FILE` may omit duplicate changes
3332 made on branches and will not show removals or mode changes. To
3333 made on branches and will not show removals or mode changes. To
3333 see all such changes, use the --removed switch.
3334 see all such changes, use the --removed switch.
3334
3335
3335 .. container:: verbose
3336 .. container:: verbose
3336
3337
3337 Some examples:
3338 Some examples:
3338
3339
3339 - changesets with full descriptions and file lists::
3340 - changesets with full descriptions and file lists::
3340
3341
3341 hg log -v
3342 hg log -v
3342
3343
3343 - changesets ancestral to the working directory::
3344 - changesets ancestral to the working directory::
3344
3345
3345 hg log -f
3346 hg log -f
3346
3347
3347 - last 10 commits on the current branch::
3348 - last 10 commits on the current branch::
3348
3349
3349 hg log -l 10 -b .
3350 hg log -l 10 -b .
3350
3351
3351 - changesets showing all modifications of a file, including removals::
3352 - changesets showing all modifications of a file, including removals::
3352
3353
3353 hg log --removed file.c
3354 hg log --removed file.c
3354
3355
3355 - all changesets that touch a directory, with diffs, excluding merges::
3356 - all changesets that touch a directory, with diffs, excluding merges::
3356
3357
3357 hg log -Mp lib/
3358 hg log -Mp lib/
3358
3359
3359 - all revision numbers that match a keyword::
3360 - all revision numbers that match a keyword::
3360
3361
3361 hg log -k bug --template "{rev}\\n"
3362 hg log -k bug --template "{rev}\\n"
3362
3363
3363 - the full hash identifier of the working directory parent::
3364 - the full hash identifier of the working directory parent::
3364
3365
3365 hg log -r . --template "{node}\\n"
3366 hg log -r . --template "{node}\\n"
3366
3367
3367 - list available log templates::
3368 - list available log templates::
3368
3369
3369 hg log -T list
3370 hg log -T list
3370
3371
3371 - check if a given changeset is included in a tagged release::
3372 - check if a given changeset is included in a tagged release::
3372
3373
3373 hg log -r "a21ccf and ancestor(1.9)"
3374 hg log -r "a21ccf and ancestor(1.9)"
3374
3375
3375 - find all changesets by some user in a date range::
3376 - find all changesets by some user in a date range::
3376
3377
3377 hg log -k alice -d "may 2008 to jul 2008"
3378 hg log -k alice -d "may 2008 to jul 2008"
3378
3379
3379 - summary of all changesets after the last tag::
3380 - summary of all changesets after the last tag::
3380
3381
3381 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3382 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3382
3383
3383 See :hg:`help dates` for a list of formats valid for -d/--date.
3384 See :hg:`help dates` for a list of formats valid for -d/--date.
3384
3385
3385 See :hg:`help revisions` for more about specifying and ordering
3386 See :hg:`help revisions` for more about specifying and ordering
3386 revisions.
3387 revisions.
3387
3388
3388 See :hg:`help templates` for more about pre-packaged styles and
3389 See :hg:`help templates` for more about pre-packaged styles and
3389 specifying custom templates.
3390 specifying custom templates.
3390
3391
3391 Returns 0 on success.
3392 Returns 0 on success.
3392
3393
3393 """
3394 """
3394 if opts.get('follow') and opts.get('rev'):
3395 if opts.get('follow') and opts.get('rev'):
3395 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3396 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3396 del opts['follow']
3397 del opts['follow']
3397
3398
3398 if opts.get('graph'):
3399 if opts.get('graph'):
3399 return cmdutil.graphlog(ui, repo, *pats, **opts)
3400 return cmdutil.graphlog(ui, repo, *pats, **opts)
3400
3401
3401 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3402 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3402 limit = cmdutil.loglimit(opts)
3403 limit = cmdutil.loglimit(opts)
3403 count = 0
3404 count = 0
3404
3405
3405 getrenamed = None
3406 getrenamed = None
3406 if opts.get('copies'):
3407 if opts.get('copies'):
3407 endrev = None
3408 endrev = None
3408 if opts.get('rev'):
3409 if opts.get('rev'):
3409 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3410 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3410 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3411 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3411
3412
3412 ui.pager('log')
3413 ui.pager('log')
3413 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3414 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3414 for rev in revs:
3415 for rev in revs:
3415 if count == limit:
3416 if count == limit:
3416 break
3417 break
3417 ctx = repo[rev]
3418 ctx = repo[rev]
3418 copies = None
3419 copies = None
3419 if getrenamed is not None and rev:
3420 if getrenamed is not None and rev:
3420 copies = []
3421 copies = []
3421 for fn in ctx.files():
3422 for fn in ctx.files():
3422 rename = getrenamed(fn, rev)
3423 rename = getrenamed(fn, rev)
3423 if rename:
3424 if rename:
3424 copies.append((fn, rename[0]))
3425 copies.append((fn, rename[0]))
3425 if filematcher:
3426 if filematcher:
3426 revmatchfn = filematcher(ctx.rev())
3427 revmatchfn = filematcher(ctx.rev())
3427 else:
3428 else:
3428 revmatchfn = None
3429 revmatchfn = None
3429 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3430 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3430 if displayer.flush(ctx):
3431 if displayer.flush(ctx):
3431 count += 1
3432 count += 1
3432
3433
3433 displayer.close()
3434 displayer.close()
3434
3435
3435 @command('manifest',
3436 @command('manifest',
3436 [('r', 'rev', '', _('revision to display'), _('REV')),
3437 [('r', 'rev', '', _('revision to display'), _('REV')),
3437 ('', 'all', False, _("list files from all revisions"))]
3438 ('', 'all', False, _("list files from all revisions"))]
3438 + formatteropts,
3439 + formatteropts,
3439 _('[-r REV]'))
3440 _('[-r REV]'))
3440 def manifest(ui, repo, node=None, rev=None, **opts):
3441 def manifest(ui, repo, node=None, rev=None, **opts):
3441 """output the current or given revision of the project manifest
3442 """output the current or given revision of the project manifest
3442
3443
3443 Print a list of version controlled files for the given revision.
3444 Print a list of version controlled files for the given revision.
3444 If no revision is given, the first parent of the working directory
3445 If no revision is given, the first parent of the working directory
3445 is used, or the null revision if no revision is checked out.
3446 is used, or the null revision if no revision is checked out.
3446
3447
3447 With -v, print file permissions, symlink and executable bits.
3448 With -v, print file permissions, symlink and executable bits.
3448 With --debug, print file revision hashes.
3449 With --debug, print file revision hashes.
3449
3450
3450 If option --all is specified, the list of all files from all revisions
3451 If option --all is specified, the list of all files from all revisions
3451 is printed. This includes deleted and renamed files.
3452 is printed. This includes deleted and renamed files.
3452
3453
3453 Returns 0 on success.
3454 Returns 0 on success.
3454 """
3455 """
3455 fm = ui.formatter('manifest', opts)
3456 fm = ui.formatter('manifest', opts)
3456
3457
3457 if opts.get('all'):
3458 if opts.get('all'):
3458 if rev or node:
3459 if rev or node:
3459 raise error.Abort(_("can't specify a revision with --all"))
3460 raise error.Abort(_("can't specify a revision with --all"))
3460
3461
3461 res = []
3462 res = []
3462 prefix = "data/"
3463 prefix = "data/"
3463 suffix = ".i"
3464 suffix = ".i"
3464 plen = len(prefix)
3465 plen = len(prefix)
3465 slen = len(suffix)
3466 slen = len(suffix)
3466 with repo.lock():
3467 with repo.lock():
3467 for fn, b, size in repo.store.datafiles():
3468 for fn, b, size in repo.store.datafiles():
3468 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3469 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3469 res.append(fn[plen:-slen])
3470 res.append(fn[plen:-slen])
3470 ui.pager('manifest')
3471 ui.pager('manifest')
3471 for f in res:
3472 for f in res:
3472 fm.startitem()
3473 fm.startitem()
3473 fm.write("path", '%s\n', f)
3474 fm.write("path", '%s\n', f)
3474 fm.end()
3475 fm.end()
3475 return
3476 return
3476
3477
3477 if rev and node:
3478 if rev and node:
3478 raise error.Abort(_("please specify just one revision"))
3479 raise error.Abort(_("please specify just one revision"))
3479
3480
3480 if not node:
3481 if not node:
3481 node = rev
3482 node = rev
3482
3483
3483 char = {'l': '@', 'x': '*', '': ''}
3484 char = {'l': '@', 'x': '*', '': ''}
3484 mode = {'l': '644', 'x': '755', '': '644'}
3485 mode = {'l': '644', 'x': '755', '': '644'}
3485 ctx = scmutil.revsingle(repo, node)
3486 ctx = scmutil.revsingle(repo, node)
3486 mf = ctx.manifest()
3487 mf = ctx.manifest()
3487 ui.pager('manifest')
3488 ui.pager('manifest')
3488 for f in ctx:
3489 for f in ctx:
3489 fm.startitem()
3490 fm.startitem()
3490 fl = ctx[f].flags()
3491 fl = ctx[f].flags()
3491 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3492 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3492 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3493 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3493 fm.write('path', '%s\n', f)
3494 fm.write('path', '%s\n', f)
3494 fm.end()
3495 fm.end()
3495
3496
3496 @command('^merge',
3497 @command('^merge',
3497 [('f', 'force', None,
3498 [('f', 'force', None,
3498 _('force a merge including outstanding changes (DEPRECATED)')),
3499 _('force a merge including outstanding changes (DEPRECATED)')),
3499 ('r', 'rev', '', _('revision to merge'), _('REV')),
3500 ('r', 'rev', '', _('revision to merge'), _('REV')),
3500 ('P', 'preview', None,
3501 ('P', 'preview', None,
3501 _('review revisions to merge (no merge is performed)'))
3502 _('review revisions to merge (no merge is performed)'))
3502 ] + mergetoolopts,
3503 ] + mergetoolopts,
3503 _('[-P] [[-r] REV]'))
3504 _('[-P] [[-r] REV]'))
3504 def merge(ui, repo, node=None, **opts):
3505 def merge(ui, repo, node=None, **opts):
3505 """merge another revision into working directory
3506 """merge another revision into working directory
3506
3507
3507 The current working directory is updated with all changes made in
3508 The current working directory is updated with all changes made in
3508 the requested revision since the last common predecessor revision.
3509 the requested revision since the last common predecessor revision.
3509
3510
3510 Files that changed between either parent are marked as changed for
3511 Files that changed between either parent are marked as changed for
3511 the next commit and a commit must be performed before any further
3512 the next commit and a commit must be performed before any further
3512 updates to the repository are allowed. The next commit will have
3513 updates to the repository are allowed. The next commit will have
3513 two parents.
3514 two parents.
3514
3515
3515 ``--tool`` can be used to specify the merge tool used for file
3516 ``--tool`` can be used to specify the merge tool used for file
3516 merges. It overrides the HGMERGE environment variable and your
3517 merges. It overrides the HGMERGE environment variable and your
3517 configuration files. See :hg:`help merge-tools` for options.
3518 configuration files. See :hg:`help merge-tools` for options.
3518
3519
3519 If no revision is specified, the working directory's parent is a
3520 If no revision is specified, the working directory's parent is a
3520 head revision, and the current branch contains exactly one other
3521 head revision, and the current branch contains exactly one other
3521 head, the other head is merged with by default. Otherwise, an
3522 head, the other head is merged with by default. Otherwise, an
3522 explicit revision with which to merge with must be provided.
3523 explicit revision with which to merge with must be provided.
3523
3524
3524 See :hg:`help resolve` for information on handling file conflicts.
3525 See :hg:`help resolve` for information on handling file conflicts.
3525
3526
3526 To undo an uncommitted merge, use :hg:`update --clean .` which
3527 To undo an uncommitted merge, use :hg:`update --clean .` which
3527 will check out a clean copy of the original merge parent, losing
3528 will check out a clean copy of the original merge parent, losing
3528 all changes.
3529 all changes.
3529
3530
3530 Returns 0 on success, 1 if there are unresolved files.
3531 Returns 0 on success, 1 if there are unresolved files.
3531 """
3532 """
3532
3533
3533 if opts.get('rev') and node:
3534 if opts.get('rev') and node:
3534 raise error.Abort(_("please specify just one revision"))
3535 raise error.Abort(_("please specify just one revision"))
3535 if not node:
3536 if not node:
3536 node = opts.get('rev')
3537 node = opts.get('rev')
3537
3538
3538 if node:
3539 if node:
3539 node = scmutil.revsingle(repo, node).node()
3540 node = scmutil.revsingle(repo, node).node()
3540
3541
3541 if not node:
3542 if not node:
3542 node = repo[destutil.destmerge(repo)].node()
3543 node = repo[destutil.destmerge(repo)].node()
3543
3544
3544 if opts.get('preview'):
3545 if opts.get('preview'):
3545 # find nodes that are ancestors of p2 but not of p1
3546 # find nodes that are ancestors of p2 but not of p1
3546 p1 = repo.lookup('.')
3547 p1 = repo.lookup('.')
3547 p2 = repo.lookup(node)
3548 p2 = repo.lookup(node)
3548 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3549 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3549
3550
3550 displayer = cmdutil.show_changeset(ui, repo, opts)
3551 displayer = cmdutil.show_changeset(ui, repo, opts)
3551 for node in nodes:
3552 for node in nodes:
3552 displayer.show(repo[node])
3553 displayer.show(repo[node])
3553 displayer.close()
3554 displayer.close()
3554 return 0
3555 return 0
3555
3556
3556 try:
3557 try:
3557 # ui.forcemerge is an internal variable, do not document
3558 # ui.forcemerge is an internal variable, do not document
3558 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3559 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3559 force = opts.get('force')
3560 force = opts.get('force')
3560 labels = ['working copy', 'merge rev']
3561 labels = ['working copy', 'merge rev']
3561 return hg.merge(repo, node, force=force, mergeforce=force,
3562 return hg.merge(repo, node, force=force, mergeforce=force,
3562 labels=labels)
3563 labels=labels)
3563 finally:
3564 finally:
3564 ui.setconfig('ui', 'forcemerge', '', 'merge')
3565 ui.setconfig('ui', 'forcemerge', '', 'merge')
3565
3566
3566 @command('outgoing|out',
3567 @command('outgoing|out',
3567 [('f', 'force', None, _('run even when the destination is unrelated')),
3568 [('f', 'force', None, _('run even when the destination is unrelated')),
3568 ('r', 'rev', [],
3569 ('r', 'rev', [],
3569 _('a changeset intended to be included in the destination'), _('REV')),
3570 _('a changeset intended to be included in the destination'), _('REV')),
3570 ('n', 'newest-first', None, _('show newest record first')),
3571 ('n', 'newest-first', None, _('show newest record first')),
3571 ('B', 'bookmarks', False, _('compare bookmarks')),
3572 ('B', 'bookmarks', False, _('compare bookmarks')),
3572 ('b', 'branch', [], _('a specific branch you would like to push'),
3573 ('b', 'branch', [], _('a specific branch you would like to push'),
3573 _('BRANCH')),
3574 _('BRANCH')),
3574 ] + logopts + remoteopts + subrepoopts,
3575 ] + logopts + remoteopts + subrepoopts,
3575 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3576 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3576 def outgoing(ui, repo, dest=None, **opts):
3577 def outgoing(ui, repo, dest=None, **opts):
3577 """show changesets not found in the destination
3578 """show changesets not found in the destination
3578
3579
3579 Show changesets not found in the specified destination repository
3580 Show changesets not found in the specified destination repository
3580 or the default push location. These are the changesets that would
3581 or the default push location. These are the changesets that would
3581 be pushed if a push was requested.
3582 be pushed if a push was requested.
3582
3583
3583 See pull for details of valid destination formats.
3584 See pull for details of valid destination formats.
3584
3585
3585 .. container:: verbose
3586 .. container:: verbose
3586
3587
3587 With -B/--bookmarks, the result of bookmark comparison between
3588 With -B/--bookmarks, the result of bookmark comparison between
3588 local and remote repositories is displayed. With -v/--verbose,
3589 local and remote repositories is displayed. With -v/--verbose,
3589 status is also displayed for each bookmark like below::
3590 status is also displayed for each bookmark like below::
3590
3591
3591 BM1 01234567890a added
3592 BM1 01234567890a added
3592 BM2 deleted
3593 BM2 deleted
3593 BM3 234567890abc advanced
3594 BM3 234567890abc advanced
3594 BM4 34567890abcd diverged
3595 BM4 34567890abcd diverged
3595 BM5 4567890abcde changed
3596 BM5 4567890abcde changed
3596
3597
3597 The action taken when pushing depends on the
3598 The action taken when pushing depends on the
3598 status of each bookmark:
3599 status of each bookmark:
3599
3600
3600 :``added``: push with ``-B`` will create it
3601 :``added``: push with ``-B`` will create it
3601 :``deleted``: push with ``-B`` will delete it
3602 :``deleted``: push with ``-B`` will delete it
3602 :``advanced``: push will update it
3603 :``advanced``: push will update it
3603 :``diverged``: push with ``-B`` will update it
3604 :``diverged``: push with ``-B`` will update it
3604 :``changed``: push with ``-B`` will update it
3605 :``changed``: push with ``-B`` will update it
3605
3606
3606 From the point of view of pushing behavior, bookmarks
3607 From the point of view of pushing behavior, bookmarks
3607 existing only in the remote repository are treated as
3608 existing only in the remote repository are treated as
3608 ``deleted``, even if it is in fact added remotely.
3609 ``deleted``, even if it is in fact added remotely.
3609
3610
3610 Returns 0 if there are outgoing changes, 1 otherwise.
3611 Returns 0 if there are outgoing changes, 1 otherwise.
3611 """
3612 """
3612 if opts.get('graph'):
3613 if opts.get('graph'):
3613 cmdutil.checkunsupportedgraphflags([], opts)
3614 cmdutil.checkunsupportedgraphflags([], opts)
3614 o, other = hg._outgoing(ui, repo, dest, opts)
3615 o, other = hg._outgoing(ui, repo, dest, opts)
3615 if not o:
3616 if not o:
3616 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3617 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3617 return
3618 return
3618
3619
3619 revdag = cmdutil.graphrevs(repo, o, opts)
3620 revdag = cmdutil.graphrevs(repo, o, opts)
3620 ui.pager('outgoing')
3621 ui.pager('outgoing')
3621 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3622 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3622 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3623 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3623 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3624 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3624 return 0
3625 return 0
3625
3626
3626 if opts.get('bookmarks'):
3627 if opts.get('bookmarks'):
3627 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3628 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3628 dest, branches = hg.parseurl(dest, opts.get('branch'))
3629 dest, branches = hg.parseurl(dest, opts.get('branch'))
3629 other = hg.peer(repo, opts, dest)
3630 other = hg.peer(repo, opts, dest)
3630 if 'bookmarks' not in other.listkeys('namespaces'):
3631 if 'bookmarks' not in other.listkeys('namespaces'):
3631 ui.warn(_("remote doesn't support bookmarks\n"))
3632 ui.warn(_("remote doesn't support bookmarks\n"))
3632 return 0
3633 return 0
3633 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3634 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3634 ui.pager('outgoing')
3635 ui.pager('outgoing')
3635 return bookmarks.outgoing(ui, repo, other)
3636 return bookmarks.outgoing(ui, repo, other)
3636
3637
3637 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3638 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3638 try:
3639 try:
3639 return hg.outgoing(ui, repo, dest, opts)
3640 return hg.outgoing(ui, repo, dest, opts)
3640 finally:
3641 finally:
3641 del repo._subtoppath
3642 del repo._subtoppath
3642
3643
3643 @command('parents',
3644 @command('parents',
3644 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3645 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3645 ] + templateopts,
3646 ] + templateopts,
3646 _('[-r REV] [FILE]'),
3647 _('[-r REV] [FILE]'),
3647 inferrepo=True)
3648 inferrepo=True)
3648 def parents(ui, repo, file_=None, **opts):
3649 def parents(ui, repo, file_=None, **opts):
3649 """show the parents of the working directory or revision (DEPRECATED)
3650 """show the parents of the working directory or revision (DEPRECATED)
3650
3651
3651 Print the working directory's parent revisions. If a revision is
3652 Print the working directory's parent revisions. If a revision is
3652 given via -r/--rev, the parent of that revision will be printed.
3653 given via -r/--rev, the parent of that revision will be printed.
3653 If a file argument is given, the revision in which the file was
3654 If a file argument is given, the revision in which the file was
3654 last changed (before the working directory revision or the
3655 last changed (before the working directory revision or the
3655 argument to --rev if given) is printed.
3656 argument to --rev if given) is printed.
3656
3657
3657 This command is equivalent to::
3658 This command is equivalent to::
3658
3659
3659 hg log -r "p1()+p2()" or
3660 hg log -r "p1()+p2()" or
3660 hg log -r "p1(REV)+p2(REV)" or
3661 hg log -r "p1(REV)+p2(REV)" or
3661 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3662 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3662 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3663 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3663
3664
3664 See :hg:`summary` and :hg:`help revsets` for related information.
3665 See :hg:`summary` and :hg:`help revsets` for related information.
3665
3666
3666 Returns 0 on success.
3667 Returns 0 on success.
3667 """
3668 """
3668
3669
3669 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3670 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3670
3671
3671 if file_:
3672 if file_:
3672 m = scmutil.match(ctx, (file_,), opts)
3673 m = scmutil.match(ctx, (file_,), opts)
3673 if m.anypats() or len(m.files()) != 1:
3674 if m.anypats() or len(m.files()) != 1:
3674 raise error.Abort(_('can only specify an explicit filename'))
3675 raise error.Abort(_('can only specify an explicit filename'))
3675 file_ = m.files()[0]
3676 file_ = m.files()[0]
3676 filenodes = []
3677 filenodes = []
3677 for cp in ctx.parents():
3678 for cp in ctx.parents():
3678 if not cp:
3679 if not cp:
3679 continue
3680 continue
3680 try:
3681 try:
3681 filenodes.append(cp.filenode(file_))
3682 filenodes.append(cp.filenode(file_))
3682 except error.LookupError:
3683 except error.LookupError:
3683 pass
3684 pass
3684 if not filenodes:
3685 if not filenodes:
3685 raise error.Abort(_("'%s' not found in manifest!") % file_)
3686 raise error.Abort(_("'%s' not found in manifest!") % file_)
3686 p = []
3687 p = []
3687 for fn in filenodes:
3688 for fn in filenodes:
3688 fctx = repo.filectx(file_, fileid=fn)
3689 fctx = repo.filectx(file_, fileid=fn)
3689 p.append(fctx.node())
3690 p.append(fctx.node())
3690 else:
3691 else:
3691 p = [cp.node() for cp in ctx.parents()]
3692 p = [cp.node() for cp in ctx.parents()]
3692
3693
3693 displayer = cmdutil.show_changeset(ui, repo, opts)
3694 displayer = cmdutil.show_changeset(ui, repo, opts)
3694 for n in p:
3695 for n in p:
3695 if n != nullid:
3696 if n != nullid:
3696 displayer.show(repo[n])
3697 displayer.show(repo[n])
3697 displayer.close()
3698 displayer.close()
3698
3699
3699 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3700 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3700 def paths(ui, repo, search=None, **opts):
3701 def paths(ui, repo, search=None, **opts):
3701 """show aliases for remote repositories
3702 """show aliases for remote repositories
3702
3703
3703 Show definition of symbolic path name NAME. If no name is given,
3704 Show definition of symbolic path name NAME. If no name is given,
3704 show definition of all available names.
3705 show definition of all available names.
3705
3706
3706 Option -q/--quiet suppresses all output when searching for NAME
3707 Option -q/--quiet suppresses all output when searching for NAME
3707 and shows only the path names when listing all definitions.
3708 and shows only the path names when listing all definitions.
3708
3709
3709 Path names are defined in the [paths] section of your
3710 Path names are defined in the [paths] section of your
3710 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3711 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3711 repository, ``.hg/hgrc`` is used, too.
3712 repository, ``.hg/hgrc`` is used, too.
3712
3713
3713 The path names ``default`` and ``default-push`` have a special
3714 The path names ``default`` and ``default-push`` have a special
3714 meaning. When performing a push or pull operation, they are used
3715 meaning. When performing a push or pull operation, they are used
3715 as fallbacks if no location is specified on the command-line.
3716 as fallbacks if no location is specified on the command-line.
3716 When ``default-push`` is set, it will be used for push and
3717 When ``default-push`` is set, it will be used for push and
3717 ``default`` will be used for pull; otherwise ``default`` is used
3718 ``default`` will be used for pull; otherwise ``default`` is used
3718 as the fallback for both. When cloning a repository, the clone
3719 as the fallback for both. When cloning a repository, the clone
3719 source is written as ``default`` in ``.hg/hgrc``.
3720 source is written as ``default`` in ``.hg/hgrc``.
3720
3721
3721 .. note::
3722 .. note::
3722
3723
3723 ``default`` and ``default-push`` apply to all inbound (e.g.
3724 ``default`` and ``default-push`` apply to all inbound (e.g.
3724 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3725 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3725 and :hg:`bundle`) operations.
3726 and :hg:`bundle`) operations.
3726
3727
3727 See :hg:`help urls` for more information.
3728 See :hg:`help urls` for more information.
3728
3729
3729 Returns 0 on success.
3730 Returns 0 on success.
3730 """
3731 """
3731 ui.pager('paths')
3732 ui.pager('paths')
3732 if search:
3733 if search:
3733 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3734 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3734 if name == search]
3735 if name == search]
3735 else:
3736 else:
3736 pathitems = sorted(ui.paths.iteritems())
3737 pathitems = sorted(ui.paths.iteritems())
3737
3738
3738 fm = ui.formatter('paths', opts)
3739 fm = ui.formatter('paths', opts)
3739 if fm.isplain():
3740 if fm.isplain():
3740 hidepassword = util.hidepassword
3741 hidepassword = util.hidepassword
3741 else:
3742 else:
3742 hidepassword = str
3743 hidepassword = str
3743 if ui.quiet:
3744 if ui.quiet:
3744 namefmt = '%s\n'
3745 namefmt = '%s\n'
3745 else:
3746 else:
3746 namefmt = '%s = '
3747 namefmt = '%s = '
3747 showsubopts = not search and not ui.quiet
3748 showsubopts = not search and not ui.quiet
3748
3749
3749 for name, path in pathitems:
3750 for name, path in pathitems:
3750 fm.startitem()
3751 fm.startitem()
3751 fm.condwrite(not search, 'name', namefmt, name)
3752 fm.condwrite(not search, 'name', namefmt, name)
3752 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3753 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3753 for subopt, value in sorted(path.suboptions.items()):
3754 for subopt, value in sorted(path.suboptions.items()):
3754 assert subopt not in ('name', 'url')
3755 assert subopt not in ('name', 'url')
3755 if showsubopts:
3756 if showsubopts:
3756 fm.plain('%s:%s = ' % (name, subopt))
3757 fm.plain('%s:%s = ' % (name, subopt))
3757 fm.condwrite(showsubopts, subopt, '%s\n', value)
3758 fm.condwrite(showsubopts, subopt, '%s\n', value)
3758
3759
3759 fm.end()
3760 fm.end()
3760
3761
3761 if search and not pathitems:
3762 if search and not pathitems:
3762 if not ui.quiet:
3763 if not ui.quiet:
3763 ui.warn(_("not found!\n"))
3764 ui.warn(_("not found!\n"))
3764 return 1
3765 return 1
3765 else:
3766 else:
3766 return 0
3767 return 0
3767
3768
3768 @command('phase',
3769 @command('phase',
3769 [('p', 'public', False, _('set changeset phase to public')),
3770 [('p', 'public', False, _('set changeset phase to public')),
3770 ('d', 'draft', False, _('set changeset phase to draft')),
3771 ('d', 'draft', False, _('set changeset phase to draft')),
3771 ('s', 'secret', False, _('set changeset phase to secret')),
3772 ('s', 'secret', False, _('set changeset phase to secret')),
3772 ('f', 'force', False, _('allow to move boundary backward')),
3773 ('f', 'force', False, _('allow to move boundary backward')),
3773 ('r', 'rev', [], _('target revision'), _('REV')),
3774 ('r', 'rev', [], _('target revision'), _('REV')),
3774 ],
3775 ],
3775 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3776 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3776 def phase(ui, repo, *revs, **opts):
3777 def phase(ui, repo, *revs, **opts):
3777 """set or show the current phase name
3778 """set or show the current phase name
3778
3779
3779 With no argument, show the phase name of the current revision(s).
3780 With no argument, show the phase name of the current revision(s).
3780
3781
3781 With one of -p/--public, -d/--draft or -s/--secret, change the
3782 With one of -p/--public, -d/--draft or -s/--secret, change the
3782 phase value of the specified revisions.
3783 phase value of the specified revisions.
3783
3784
3784 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3785 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3785 lower phase to an higher phase. Phases are ordered as follows::
3786 lower phase to an higher phase. Phases are ordered as follows::
3786
3787
3787 public < draft < secret
3788 public < draft < secret
3788
3789
3789 Returns 0 on success, 1 if some phases could not be changed.
3790 Returns 0 on success, 1 if some phases could not be changed.
3790
3791
3791 (For more information about the phases concept, see :hg:`help phases`.)
3792 (For more information about the phases concept, see :hg:`help phases`.)
3792 """
3793 """
3793 # search for a unique phase argument
3794 # search for a unique phase argument
3794 targetphase = None
3795 targetphase = None
3795 for idx, name in enumerate(phases.phasenames):
3796 for idx, name in enumerate(phases.phasenames):
3796 if opts[name]:
3797 if opts[name]:
3797 if targetphase is not None:
3798 if targetphase is not None:
3798 raise error.Abort(_('only one phase can be specified'))
3799 raise error.Abort(_('only one phase can be specified'))
3799 targetphase = idx
3800 targetphase = idx
3800
3801
3801 # look for specified revision
3802 # look for specified revision
3802 revs = list(revs)
3803 revs = list(revs)
3803 revs.extend(opts['rev'])
3804 revs.extend(opts['rev'])
3804 if not revs:
3805 if not revs:
3805 # display both parents as the second parent phase can influence
3806 # display both parents as the second parent phase can influence
3806 # the phase of a merge commit
3807 # the phase of a merge commit
3807 revs = [c.rev() for c in repo[None].parents()]
3808 revs = [c.rev() for c in repo[None].parents()]
3808
3809
3809 revs = scmutil.revrange(repo, revs)
3810 revs = scmutil.revrange(repo, revs)
3810
3811
3811 lock = None
3812 lock = None
3812 ret = 0
3813 ret = 0
3813 if targetphase is None:
3814 if targetphase is None:
3814 # display
3815 # display
3815 for r in revs:
3816 for r in revs:
3816 ctx = repo[r]
3817 ctx = repo[r]
3817 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3818 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3818 else:
3819 else:
3819 tr = None
3820 tr = None
3820 lock = repo.lock()
3821 lock = repo.lock()
3821 try:
3822 try:
3822 tr = repo.transaction("phase")
3823 tr = repo.transaction("phase")
3823 # set phase
3824 # set phase
3824 if not revs:
3825 if not revs:
3825 raise error.Abort(_('empty revision set'))
3826 raise error.Abort(_('empty revision set'))
3826 nodes = [repo[r].node() for r in revs]
3827 nodes = [repo[r].node() for r in revs]
3827 # moving revision from public to draft may hide them
3828 # moving revision from public to draft may hide them
3828 # We have to check result on an unfiltered repository
3829 # We have to check result on an unfiltered repository
3829 unfi = repo.unfiltered()
3830 unfi = repo.unfiltered()
3830 getphase = unfi._phasecache.phase
3831 getphase = unfi._phasecache.phase
3831 olddata = [getphase(unfi, r) for r in unfi]
3832 olddata = [getphase(unfi, r) for r in unfi]
3832 phases.advanceboundary(repo, tr, targetphase, nodes)
3833 phases.advanceboundary(repo, tr, targetphase, nodes)
3833 if opts['force']:
3834 if opts['force']:
3834 phases.retractboundary(repo, tr, targetphase, nodes)
3835 phases.retractboundary(repo, tr, targetphase, nodes)
3835 tr.close()
3836 tr.close()
3836 finally:
3837 finally:
3837 if tr is not None:
3838 if tr is not None:
3838 tr.release()
3839 tr.release()
3839 lock.release()
3840 lock.release()
3840 getphase = unfi._phasecache.phase
3841 getphase = unfi._phasecache.phase
3841 newdata = [getphase(unfi, r) for r in unfi]
3842 newdata = [getphase(unfi, r) for r in unfi]
3842 changes = sum(newdata[r] != olddata[r] for r in unfi)
3843 changes = sum(newdata[r] != olddata[r] for r in unfi)
3843 cl = unfi.changelog
3844 cl = unfi.changelog
3844 rejected = [n for n in nodes
3845 rejected = [n for n in nodes
3845 if newdata[cl.rev(n)] < targetphase]
3846 if newdata[cl.rev(n)] < targetphase]
3846 if rejected:
3847 if rejected:
3847 ui.warn(_('cannot move %i changesets to a higher '
3848 ui.warn(_('cannot move %i changesets to a higher '
3848 'phase, use --force\n') % len(rejected))
3849 'phase, use --force\n') % len(rejected))
3849 ret = 1
3850 ret = 1
3850 if changes:
3851 if changes:
3851 msg = _('phase changed for %i changesets\n') % changes
3852 msg = _('phase changed for %i changesets\n') % changes
3852 if ret:
3853 if ret:
3853 ui.status(msg)
3854 ui.status(msg)
3854 else:
3855 else:
3855 ui.note(msg)
3856 ui.note(msg)
3856 else:
3857 else:
3857 ui.warn(_('no phases changed\n'))
3858 ui.warn(_('no phases changed\n'))
3858 return ret
3859 return ret
3859
3860
3860 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3861 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3861 """Run after a changegroup has been added via pull/unbundle
3862 """Run after a changegroup has been added via pull/unbundle
3862
3863
3863 This takes arguments below:
3864 This takes arguments below:
3864
3865
3865 :modheads: change of heads by pull/unbundle
3866 :modheads: change of heads by pull/unbundle
3866 :optupdate: updating working directory is needed or not
3867 :optupdate: updating working directory is needed or not
3867 :checkout: update destination revision (or None to default destination)
3868 :checkout: update destination revision (or None to default destination)
3868 :brev: a name, which might be a bookmark to be activated after updating
3869 :brev: a name, which might be a bookmark to be activated after updating
3869 """
3870 """
3870 if modheads == 0:
3871 if modheads == 0:
3871 return
3872 return
3872 if optupdate:
3873 if optupdate:
3873 try:
3874 try:
3874 return hg.updatetotally(ui, repo, checkout, brev)
3875 return hg.updatetotally(ui, repo, checkout, brev)
3875 except error.UpdateAbort as inst:
3876 except error.UpdateAbort as inst:
3876 msg = _("not updating: %s") % str(inst)
3877 msg = _("not updating: %s") % str(inst)
3877 hint = inst.hint
3878 hint = inst.hint
3878 raise error.UpdateAbort(msg, hint=hint)
3879 raise error.UpdateAbort(msg, hint=hint)
3879 if modheads > 1:
3880 if modheads > 1:
3880 currentbranchheads = len(repo.branchheads())
3881 currentbranchheads = len(repo.branchheads())
3881 if currentbranchheads == modheads:
3882 if currentbranchheads == modheads:
3882 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3883 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3883 elif currentbranchheads > 1:
3884 elif currentbranchheads > 1:
3884 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3885 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3885 "merge)\n"))
3886 "merge)\n"))
3886 else:
3887 else:
3887 ui.status(_("(run 'hg heads' to see heads)\n"))
3888 ui.status(_("(run 'hg heads' to see heads)\n"))
3888 else:
3889 else:
3889 ui.status(_("(run 'hg update' to get a working copy)\n"))
3890 ui.status(_("(run 'hg update' to get a working copy)\n"))
3890
3891
3891 @command('^pull',
3892 @command('^pull',
3892 [('u', 'update', None,
3893 [('u', 'update', None,
3893 _('update to new branch head if changesets were pulled')),
3894 _('update to new branch head if changesets were pulled')),
3894 ('f', 'force', None, _('run even when remote repository is unrelated')),
3895 ('f', 'force', None, _('run even when remote repository is unrelated')),
3895 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3896 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3896 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3897 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3897 ('b', 'branch', [], _('a specific branch you would like to pull'),
3898 ('b', 'branch', [], _('a specific branch you would like to pull'),
3898 _('BRANCH')),
3899 _('BRANCH')),
3899 ] + remoteopts,
3900 ] + remoteopts,
3900 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3901 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3901 def pull(ui, repo, source="default", **opts):
3902 def pull(ui, repo, source="default", **opts):
3902 """pull changes from the specified source
3903 """pull changes from the specified source
3903
3904
3904 Pull changes from a remote repository to a local one.
3905 Pull changes from a remote repository to a local one.
3905
3906
3906 This finds all changes from the repository at the specified path
3907 This finds all changes from the repository at the specified path
3907 or URL and adds them to a local repository (the current one unless
3908 or URL and adds them to a local repository (the current one unless
3908 -R is specified). By default, this does not update the copy of the
3909 -R is specified). By default, this does not update the copy of the
3909 project in the working directory.
3910 project in the working directory.
3910
3911
3911 Use :hg:`incoming` if you want to see what would have been added
3912 Use :hg:`incoming` if you want to see what would have been added
3912 by a pull at the time you issued this command. If you then decide
3913 by a pull at the time you issued this command. If you then decide
3913 to add those changes to the repository, you should use :hg:`pull
3914 to add those changes to the repository, you should use :hg:`pull
3914 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3915 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3915
3916
3916 If SOURCE is omitted, the 'default' path will be used.
3917 If SOURCE is omitted, the 'default' path will be used.
3917 See :hg:`help urls` for more information.
3918 See :hg:`help urls` for more information.
3918
3919
3919 Specifying bookmark as ``.`` is equivalent to specifying the active
3920 Specifying bookmark as ``.`` is equivalent to specifying the active
3920 bookmark's name.
3921 bookmark's name.
3921
3922
3922 Returns 0 on success, 1 if an update had unresolved files.
3923 Returns 0 on success, 1 if an update had unresolved files.
3923 """
3924 """
3924 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3925 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3925 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3926 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3926 other = hg.peer(repo, opts, source)
3927 other = hg.peer(repo, opts, source)
3927 try:
3928 try:
3928 revs, checkout = hg.addbranchrevs(repo, other, branches,
3929 revs, checkout = hg.addbranchrevs(repo, other, branches,
3929 opts.get('rev'))
3930 opts.get('rev'))
3930
3931
3931
3932
3932 pullopargs = {}
3933 pullopargs = {}
3933 if opts.get('bookmark'):
3934 if opts.get('bookmark'):
3934 if not revs:
3935 if not revs:
3935 revs = []
3936 revs = []
3936 # The list of bookmark used here is not the one used to actually
3937 # The list of bookmark used here is not the one used to actually
3937 # update the bookmark name. This can result in the revision pulled
3938 # update the bookmark name. This can result in the revision pulled
3938 # not ending up with the name of the bookmark because of a race
3939 # not ending up with the name of the bookmark because of a race
3939 # condition on the server. (See issue 4689 for details)
3940 # condition on the server. (See issue 4689 for details)
3940 remotebookmarks = other.listkeys('bookmarks')
3941 remotebookmarks = other.listkeys('bookmarks')
3941 pullopargs['remotebookmarks'] = remotebookmarks
3942 pullopargs['remotebookmarks'] = remotebookmarks
3942 for b in opts['bookmark']:
3943 for b in opts['bookmark']:
3943 b = repo._bookmarks.expandname(b)
3944 b = repo._bookmarks.expandname(b)
3944 if b not in remotebookmarks:
3945 if b not in remotebookmarks:
3945 raise error.Abort(_('remote bookmark %s not found!') % b)
3946 raise error.Abort(_('remote bookmark %s not found!') % b)
3946 revs.append(remotebookmarks[b])
3947 revs.append(remotebookmarks[b])
3947
3948
3948 if revs:
3949 if revs:
3949 try:
3950 try:
3950 # When 'rev' is a bookmark name, we cannot guarantee that it
3951 # When 'rev' is a bookmark name, we cannot guarantee that it
3951 # will be updated with that name because of a race condition
3952 # will be updated with that name because of a race condition
3952 # server side. (See issue 4689 for details)
3953 # server side. (See issue 4689 for details)
3953 oldrevs = revs
3954 oldrevs = revs
3954 revs = [] # actually, nodes
3955 revs = [] # actually, nodes
3955 for r in oldrevs:
3956 for r in oldrevs:
3956 node = other.lookup(r)
3957 node = other.lookup(r)
3957 revs.append(node)
3958 revs.append(node)
3958 if r == checkout:
3959 if r == checkout:
3959 checkout = node
3960 checkout = node
3960 except error.CapabilityError:
3961 except error.CapabilityError:
3961 err = _("other repository doesn't support revision lookup, "
3962 err = _("other repository doesn't support revision lookup, "
3962 "so a rev cannot be specified.")
3963 "so a rev cannot be specified.")
3963 raise error.Abort(err)
3964 raise error.Abort(err)
3964
3965
3965 pullopargs.update(opts.get('opargs', {}))
3966 pullopargs.update(opts.get('opargs', {}))
3966 modheads = exchange.pull(repo, other, heads=revs,
3967 modheads = exchange.pull(repo, other, heads=revs,
3967 force=opts.get('force'),
3968 force=opts.get('force'),
3968 bookmarks=opts.get('bookmark', ()),
3969 bookmarks=opts.get('bookmark', ()),
3969 opargs=pullopargs).cgresult
3970 opargs=pullopargs).cgresult
3970
3971
3971 # brev is a name, which might be a bookmark to be activated at
3972 # brev is a name, which might be a bookmark to be activated at
3972 # the end of the update. In other words, it is an explicit
3973 # the end of the update. In other words, it is an explicit
3973 # destination of the update
3974 # destination of the update
3974 brev = None
3975 brev = None
3975
3976
3976 if checkout:
3977 if checkout:
3977 checkout = str(repo.changelog.rev(checkout))
3978 checkout = str(repo.changelog.rev(checkout))
3978
3979
3979 # order below depends on implementation of
3980 # order below depends on implementation of
3980 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3981 # hg.addbranchrevs(). opts['bookmark'] is ignored,
3981 # because 'checkout' is determined without it.
3982 # because 'checkout' is determined without it.
3982 if opts.get('rev'):
3983 if opts.get('rev'):
3983 brev = opts['rev'][0]
3984 brev = opts['rev'][0]
3984 elif opts.get('branch'):
3985 elif opts.get('branch'):
3985 brev = opts['branch'][0]
3986 brev = opts['branch'][0]
3986 else:
3987 else:
3987 brev = branches[0]
3988 brev = branches[0]
3988 repo._subtoppath = source
3989 repo._subtoppath = source
3989 try:
3990 try:
3990 ret = postincoming(ui, repo, modheads, opts.get('update'),
3991 ret = postincoming(ui, repo, modheads, opts.get('update'),
3991 checkout, brev)
3992 checkout, brev)
3992
3993
3993 finally:
3994 finally:
3994 del repo._subtoppath
3995 del repo._subtoppath
3995
3996
3996 finally:
3997 finally:
3997 other.close()
3998 other.close()
3998 return ret
3999 return ret
3999
4000
4000 @command('^push',
4001 @command('^push',
4001 [('f', 'force', None, _('force push')),
4002 [('f', 'force', None, _('force push')),
4002 ('r', 'rev', [],
4003 ('r', 'rev', [],
4003 _('a changeset intended to be included in the destination'),
4004 _('a changeset intended to be included in the destination'),
4004 _('REV')),
4005 _('REV')),
4005 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4006 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4006 ('b', 'branch', [],
4007 ('b', 'branch', [],
4007 _('a specific branch you would like to push'), _('BRANCH')),
4008 _('a specific branch you would like to push'), _('BRANCH')),
4008 ('', 'new-branch', False, _('allow pushing a new branch')),
4009 ('', 'new-branch', False, _('allow pushing a new branch')),
4009 ] + remoteopts,
4010 ] + remoteopts,
4010 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4011 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4011 def push(ui, repo, dest=None, **opts):
4012 def push(ui, repo, dest=None, **opts):
4012 """push changes to the specified destination
4013 """push changes to the specified destination
4013
4014
4014 Push changesets from the local repository to the specified
4015 Push changesets from the local repository to the specified
4015 destination.
4016 destination.
4016
4017
4017 This operation is symmetrical to pull: it is identical to a pull
4018 This operation is symmetrical to pull: it is identical to a pull
4018 in the destination repository from the current one.
4019 in the destination repository from the current one.
4019
4020
4020 By default, push will not allow creation of new heads at the
4021 By default, push will not allow creation of new heads at the
4021 destination, since multiple heads would make it unclear which head
4022 destination, since multiple heads would make it unclear which head
4022 to use. In this situation, it is recommended to pull and merge
4023 to use. In this situation, it is recommended to pull and merge
4023 before pushing.
4024 before pushing.
4024
4025
4025 Use --new-branch if you want to allow push to create a new named
4026 Use --new-branch if you want to allow push to create a new named
4026 branch that is not present at the destination. This allows you to
4027 branch that is not present at the destination. This allows you to
4027 only create a new branch without forcing other changes.
4028 only create a new branch without forcing other changes.
4028
4029
4029 .. note::
4030 .. note::
4030
4031
4031 Extra care should be taken with the -f/--force option,
4032 Extra care should be taken with the -f/--force option,
4032 which will push all new heads on all branches, an action which will
4033 which will push all new heads on all branches, an action which will
4033 almost always cause confusion for collaborators.
4034 almost always cause confusion for collaborators.
4034
4035
4035 If -r/--rev is used, the specified revision and all its ancestors
4036 If -r/--rev is used, the specified revision and all its ancestors
4036 will be pushed to the remote repository.
4037 will be pushed to the remote repository.
4037
4038
4038 If -B/--bookmark is used, the specified bookmarked revision, its
4039 If -B/--bookmark is used, the specified bookmarked revision, its
4039 ancestors, and the bookmark will be pushed to the remote
4040 ancestors, and the bookmark will be pushed to the remote
4040 repository. Specifying ``.`` is equivalent to specifying the active
4041 repository. Specifying ``.`` is equivalent to specifying the active
4041 bookmark's name.
4042 bookmark's name.
4042
4043
4043 Please see :hg:`help urls` for important details about ``ssh://``
4044 Please see :hg:`help urls` for important details about ``ssh://``
4044 URLs. If DESTINATION is omitted, a default path will be used.
4045 URLs. If DESTINATION is omitted, a default path will be used.
4045
4046
4046 Returns 0 if push was successful, 1 if nothing to push.
4047 Returns 0 if push was successful, 1 if nothing to push.
4047 """
4048 """
4048
4049
4049 if opts.get('bookmark'):
4050 if opts.get('bookmark'):
4050 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4051 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4051 for b in opts['bookmark']:
4052 for b in opts['bookmark']:
4052 # translate -B options to -r so changesets get pushed
4053 # translate -B options to -r so changesets get pushed
4053 b = repo._bookmarks.expandname(b)
4054 b = repo._bookmarks.expandname(b)
4054 if b in repo._bookmarks:
4055 if b in repo._bookmarks:
4055 opts.setdefault('rev', []).append(b)
4056 opts.setdefault('rev', []).append(b)
4056 else:
4057 else:
4057 # if we try to push a deleted bookmark, translate it to null
4058 # if we try to push a deleted bookmark, translate it to null
4058 # this lets simultaneous -r, -b options continue working
4059 # this lets simultaneous -r, -b options continue working
4059 opts.setdefault('rev', []).append("null")
4060 opts.setdefault('rev', []).append("null")
4060
4061
4061 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4062 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4062 if not path:
4063 if not path:
4063 raise error.Abort(_('default repository not configured!'),
4064 raise error.Abort(_('default repository not configured!'),
4064 hint=_("see 'hg help config.paths'"))
4065 hint=_("see 'hg help config.paths'"))
4065 dest = path.pushloc or path.loc
4066 dest = path.pushloc or path.loc
4066 branches = (path.branch, opts.get('branch') or [])
4067 branches = (path.branch, opts.get('branch') or [])
4067 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4068 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4068 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4069 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4069 other = hg.peer(repo, opts, dest)
4070 other = hg.peer(repo, opts, dest)
4070
4071
4071 if revs:
4072 if revs:
4072 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4073 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4073 if not revs:
4074 if not revs:
4074 raise error.Abort(_("specified revisions evaluate to an empty set"),
4075 raise error.Abort(_("specified revisions evaluate to an empty set"),
4075 hint=_("use different revision arguments"))
4076 hint=_("use different revision arguments"))
4076 elif path.pushrev:
4077 elif path.pushrev:
4077 # It doesn't make any sense to specify ancestor revisions. So limit
4078 # It doesn't make any sense to specify ancestor revisions. So limit
4078 # to DAG heads to make discovery simpler.
4079 # to DAG heads to make discovery simpler.
4079 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4080 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4080 revs = scmutil.revrange(repo, [expr])
4081 revs = scmutil.revrange(repo, [expr])
4081 revs = [repo[rev].node() for rev in revs]
4082 revs = [repo[rev].node() for rev in revs]
4082 if not revs:
4083 if not revs:
4083 raise error.Abort(_('default push revset for path evaluates to an '
4084 raise error.Abort(_('default push revset for path evaluates to an '
4084 'empty set'))
4085 'empty set'))
4085
4086
4086 repo._subtoppath = dest
4087 repo._subtoppath = dest
4087 try:
4088 try:
4088 # push subrepos depth-first for coherent ordering
4089 # push subrepos depth-first for coherent ordering
4089 c = repo['']
4090 c = repo['']
4090 subs = c.substate # only repos that are committed
4091 subs = c.substate # only repos that are committed
4091 for s in sorted(subs):
4092 for s in sorted(subs):
4092 result = c.sub(s).push(opts)
4093 result = c.sub(s).push(opts)
4093 if result == 0:
4094 if result == 0:
4094 return not result
4095 return not result
4095 finally:
4096 finally:
4096 del repo._subtoppath
4097 del repo._subtoppath
4097 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4098 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4098 newbranch=opts.get('new_branch'),
4099 newbranch=opts.get('new_branch'),
4099 bookmarks=opts.get('bookmark', ()),
4100 bookmarks=opts.get('bookmark', ()),
4100 opargs=opts.get('opargs'))
4101 opargs=opts.get('opargs'))
4101
4102
4102 result = not pushop.cgresult
4103 result = not pushop.cgresult
4103
4104
4104 if pushop.bkresult is not None:
4105 if pushop.bkresult is not None:
4105 if pushop.bkresult == 2:
4106 if pushop.bkresult == 2:
4106 result = 2
4107 result = 2
4107 elif not result and pushop.bkresult:
4108 elif not result and pushop.bkresult:
4108 result = 2
4109 result = 2
4109
4110
4110 return result
4111 return result
4111
4112
4112 @command('recover', [])
4113 @command('recover', [])
4113 def recover(ui, repo):
4114 def recover(ui, repo):
4114 """roll back an interrupted transaction
4115 """roll back an interrupted transaction
4115
4116
4116 Recover from an interrupted commit or pull.
4117 Recover from an interrupted commit or pull.
4117
4118
4118 This command tries to fix the repository status after an
4119 This command tries to fix the repository status after an
4119 interrupted operation. It should only be necessary when Mercurial
4120 interrupted operation. It should only be necessary when Mercurial
4120 suggests it.
4121 suggests it.
4121
4122
4122 Returns 0 if successful, 1 if nothing to recover or verify fails.
4123 Returns 0 if successful, 1 if nothing to recover or verify fails.
4123 """
4124 """
4124 if repo.recover():
4125 if repo.recover():
4125 return hg.verify(repo)
4126 return hg.verify(repo)
4126 return 1
4127 return 1
4127
4128
4128 @command('^remove|rm',
4129 @command('^remove|rm',
4129 [('A', 'after', None, _('record delete for missing files')),
4130 [('A', 'after', None, _('record delete for missing files')),
4130 ('f', 'force', None,
4131 ('f', 'force', None,
4131 _('forget added files, delete modified files')),
4132 _('forget added files, delete modified files')),
4132 ] + subrepoopts + walkopts,
4133 ] + subrepoopts + walkopts,
4133 _('[OPTION]... FILE...'),
4134 _('[OPTION]... FILE...'),
4134 inferrepo=True)
4135 inferrepo=True)
4135 def remove(ui, repo, *pats, **opts):
4136 def remove(ui, repo, *pats, **opts):
4136 """remove the specified files on the next commit
4137 """remove the specified files on the next commit
4137
4138
4138 Schedule the indicated files for removal from the current branch.
4139 Schedule the indicated files for removal from the current branch.
4139
4140
4140 This command schedules the files to be removed at the next commit.
4141 This command schedules the files to be removed at the next commit.
4141 To undo a remove before that, see :hg:`revert`. To undo added
4142 To undo a remove before that, see :hg:`revert`. To undo added
4142 files, see :hg:`forget`.
4143 files, see :hg:`forget`.
4143
4144
4144 .. container:: verbose
4145 .. container:: verbose
4145
4146
4146 -A/--after can be used to remove only files that have already
4147 -A/--after can be used to remove only files that have already
4147 been deleted, -f/--force can be used to force deletion, and -Af
4148 been deleted, -f/--force can be used to force deletion, and -Af
4148 can be used to remove files from the next revision without
4149 can be used to remove files from the next revision without
4149 deleting them from the working directory.
4150 deleting them from the working directory.
4150
4151
4151 The following table details the behavior of remove for different
4152 The following table details the behavior of remove for different
4152 file states (columns) and option combinations (rows). The file
4153 file states (columns) and option combinations (rows). The file
4153 states are Added [A], Clean [C], Modified [M] and Missing [!]
4154 states are Added [A], Clean [C], Modified [M] and Missing [!]
4154 (as reported by :hg:`status`). The actions are Warn, Remove
4155 (as reported by :hg:`status`). The actions are Warn, Remove
4155 (from branch) and Delete (from disk):
4156 (from branch) and Delete (from disk):
4156
4157
4157 ========= == == == ==
4158 ========= == == == ==
4158 opt/state A C M !
4159 opt/state A C M !
4159 ========= == == == ==
4160 ========= == == == ==
4160 none W RD W R
4161 none W RD W R
4161 -f R RD RD R
4162 -f R RD RD R
4162 -A W W W R
4163 -A W W W R
4163 -Af R R R R
4164 -Af R R R R
4164 ========= == == == ==
4165 ========= == == == ==
4165
4166
4166 .. note::
4167 .. note::
4167
4168
4168 :hg:`remove` never deletes files in Added [A] state from the
4169 :hg:`remove` never deletes files in Added [A] state from the
4169 working directory, not even if ``--force`` is specified.
4170 working directory, not even if ``--force`` is specified.
4170
4171
4171 Returns 0 on success, 1 if any warnings encountered.
4172 Returns 0 on success, 1 if any warnings encountered.
4172 """
4173 """
4173
4174
4174 after, force = opts.get('after'), opts.get('force')
4175 after, force = opts.get('after'), opts.get('force')
4175 if not pats and not after:
4176 if not pats and not after:
4176 raise error.Abort(_('no files specified'))
4177 raise error.Abort(_('no files specified'))
4177
4178
4178 m = scmutil.match(repo[None], pats, opts)
4179 m = scmutil.match(repo[None], pats, opts)
4179 subrepos = opts.get('subrepos')
4180 subrepos = opts.get('subrepos')
4180 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4181 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4181
4182
4182 @command('rename|move|mv',
4183 @command('rename|move|mv',
4183 [('A', 'after', None, _('record a rename that has already occurred')),
4184 [('A', 'after', None, _('record a rename that has already occurred')),
4184 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4185 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4185 ] + walkopts + dryrunopts,
4186 ] + walkopts + dryrunopts,
4186 _('[OPTION]... SOURCE... DEST'))
4187 _('[OPTION]... SOURCE... DEST'))
4187 def rename(ui, repo, *pats, **opts):
4188 def rename(ui, repo, *pats, **opts):
4188 """rename files; equivalent of copy + remove
4189 """rename files; equivalent of copy + remove
4189
4190
4190 Mark dest as copies of sources; mark sources for deletion. If dest
4191 Mark dest as copies of sources; mark sources for deletion. If dest
4191 is a directory, copies are put in that directory. If dest is a
4192 is a directory, copies are put in that directory. If dest is a
4192 file, there can only be one source.
4193 file, there can only be one source.
4193
4194
4194 By default, this command copies the contents of files as they
4195 By default, this command copies the contents of files as they
4195 exist in the working directory. If invoked with -A/--after, the
4196 exist in the working directory. If invoked with -A/--after, the
4196 operation is recorded, but no copying is performed.
4197 operation is recorded, but no copying is performed.
4197
4198
4198 This command takes effect at the next commit. To undo a rename
4199 This command takes effect at the next commit. To undo a rename
4199 before that, see :hg:`revert`.
4200 before that, see :hg:`revert`.
4200
4201
4201 Returns 0 on success, 1 if errors are encountered.
4202 Returns 0 on success, 1 if errors are encountered.
4202 """
4203 """
4203 with repo.wlock(False):
4204 with repo.wlock(False):
4204 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4205 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4205
4206
4206 @command('resolve',
4207 @command('resolve',
4207 [('a', 'all', None, _('select all unresolved files')),
4208 [('a', 'all', None, _('select all unresolved files')),
4208 ('l', 'list', None, _('list state of files needing merge')),
4209 ('l', 'list', None, _('list state of files needing merge')),
4209 ('m', 'mark', None, _('mark files as resolved')),
4210 ('m', 'mark', None, _('mark files as resolved')),
4210 ('u', 'unmark', None, _('mark files as unresolved')),
4211 ('u', 'unmark', None, _('mark files as unresolved')),
4211 ('n', 'no-status', None, _('hide status prefix'))]
4212 ('n', 'no-status', None, _('hide status prefix'))]
4212 + mergetoolopts + walkopts + formatteropts,
4213 + mergetoolopts + walkopts + formatteropts,
4213 _('[OPTION]... [FILE]...'),
4214 _('[OPTION]... [FILE]...'),
4214 inferrepo=True)
4215 inferrepo=True)
4215 def resolve(ui, repo, *pats, **opts):
4216 def resolve(ui, repo, *pats, **opts):
4216 """redo merges or set/view the merge status of files
4217 """redo merges or set/view the merge status of files
4217
4218
4218 Merges with unresolved conflicts are often the result of
4219 Merges with unresolved conflicts are often the result of
4219 non-interactive merging using the ``internal:merge`` configuration
4220 non-interactive merging using the ``internal:merge`` configuration
4220 setting, or a command-line merge tool like ``diff3``. The resolve
4221 setting, or a command-line merge tool like ``diff3``. The resolve
4221 command is used to manage the files involved in a merge, after
4222 command is used to manage the files involved in a merge, after
4222 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4223 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4223 working directory must have two parents). See :hg:`help
4224 working directory must have two parents). See :hg:`help
4224 merge-tools` for information on configuring merge tools.
4225 merge-tools` for information on configuring merge tools.
4225
4226
4226 The resolve command can be used in the following ways:
4227 The resolve command can be used in the following ways:
4227
4228
4228 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4229 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4229 files, discarding any previous merge attempts. Re-merging is not
4230 files, discarding any previous merge attempts. Re-merging is not
4230 performed for files already marked as resolved. Use ``--all/-a``
4231 performed for files already marked as resolved. Use ``--all/-a``
4231 to select all unresolved files. ``--tool`` can be used to specify
4232 to select all unresolved files. ``--tool`` can be used to specify
4232 the merge tool used for the given files. It overrides the HGMERGE
4233 the merge tool used for the given files. It overrides the HGMERGE
4233 environment variable and your configuration files. Previous file
4234 environment variable and your configuration files. Previous file
4234 contents are saved with a ``.orig`` suffix.
4235 contents are saved with a ``.orig`` suffix.
4235
4236
4236 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4237 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4237 (e.g. after having manually fixed-up the files). The default is
4238 (e.g. after having manually fixed-up the files). The default is
4238 to mark all unresolved files.
4239 to mark all unresolved files.
4239
4240
4240 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4241 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4241 default is to mark all resolved files.
4242 default is to mark all resolved files.
4242
4243
4243 - :hg:`resolve -l`: list files which had or still have conflicts.
4244 - :hg:`resolve -l`: list files which had or still have conflicts.
4244 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4245 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4245 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4246 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4246 the list. See :hg:`help filesets` for details.
4247 the list. See :hg:`help filesets` for details.
4247
4248
4248 .. note::
4249 .. note::
4249
4250
4250 Mercurial will not let you commit files with unresolved merge
4251 Mercurial will not let you commit files with unresolved merge
4251 conflicts. You must use :hg:`resolve -m ...` before you can
4252 conflicts. You must use :hg:`resolve -m ...` before you can
4252 commit after a conflicting merge.
4253 commit after a conflicting merge.
4253
4254
4254 Returns 0 on success, 1 if any files fail a resolve attempt.
4255 Returns 0 on success, 1 if any files fail a resolve attempt.
4255 """
4256 """
4256
4257
4257 flaglist = 'all mark unmark list no_status'.split()
4258 flaglist = 'all mark unmark list no_status'.split()
4258 all, mark, unmark, show, nostatus = \
4259 all, mark, unmark, show, nostatus = \
4259 [opts.get(o) for o in flaglist]
4260 [opts.get(o) for o in flaglist]
4260
4261
4261 if (show and (mark or unmark)) or (mark and unmark):
4262 if (show and (mark or unmark)) or (mark and unmark):
4262 raise error.Abort(_("too many options specified"))
4263 raise error.Abort(_("too many options specified"))
4263 if pats and all:
4264 if pats and all:
4264 raise error.Abort(_("can't specify --all and patterns"))
4265 raise error.Abort(_("can't specify --all and patterns"))
4265 if not (all or pats or show or mark or unmark):
4266 if not (all or pats or show or mark or unmark):
4266 raise error.Abort(_('no files or directories specified'),
4267 raise error.Abort(_('no files or directories specified'),
4267 hint=('use --all to re-merge all unresolved files'))
4268 hint=('use --all to re-merge all unresolved files'))
4268
4269
4269 if show:
4270 if show:
4270 ui.pager('resolve')
4271 ui.pager('resolve')
4271 fm = ui.formatter('resolve', opts)
4272 fm = ui.formatter('resolve', opts)
4272 ms = mergemod.mergestate.read(repo)
4273 ms = mergemod.mergestate.read(repo)
4273 m = scmutil.match(repo[None], pats, opts)
4274 m = scmutil.match(repo[None], pats, opts)
4274 for f in ms:
4275 for f in ms:
4275 if not m(f):
4276 if not m(f):
4276 continue
4277 continue
4277 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4278 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4278 'd': 'driverresolved'}[ms[f]]
4279 'd': 'driverresolved'}[ms[f]]
4279 fm.startitem()
4280 fm.startitem()
4280 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4281 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4281 fm.write('path', '%s\n', f, label=l)
4282 fm.write('path', '%s\n', f, label=l)
4282 fm.end()
4283 fm.end()
4283 return 0
4284 return 0
4284
4285
4285 with repo.wlock():
4286 with repo.wlock():
4286 ms = mergemod.mergestate.read(repo)
4287 ms = mergemod.mergestate.read(repo)
4287
4288
4288 if not (ms.active() or repo.dirstate.p2() != nullid):
4289 if not (ms.active() or repo.dirstate.p2() != nullid):
4289 raise error.Abort(
4290 raise error.Abort(
4290 _('resolve command not applicable when not merging'))
4291 _('resolve command not applicable when not merging'))
4291
4292
4292 wctx = repo[None]
4293 wctx = repo[None]
4293
4294
4294 if ms.mergedriver and ms.mdstate() == 'u':
4295 if ms.mergedriver and ms.mdstate() == 'u':
4295 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4296 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4296 ms.commit()
4297 ms.commit()
4297 # allow mark and unmark to go through
4298 # allow mark and unmark to go through
4298 if not mark and not unmark and not proceed:
4299 if not mark and not unmark and not proceed:
4299 return 1
4300 return 1
4300
4301
4301 m = scmutil.match(wctx, pats, opts)
4302 m = scmutil.match(wctx, pats, opts)
4302 ret = 0
4303 ret = 0
4303 didwork = False
4304 didwork = False
4304 runconclude = False
4305 runconclude = False
4305
4306
4306 tocomplete = []
4307 tocomplete = []
4307 for f in ms:
4308 for f in ms:
4308 if not m(f):
4309 if not m(f):
4309 continue
4310 continue
4310
4311
4311 didwork = True
4312 didwork = True
4312
4313
4313 # don't let driver-resolved files be marked, and run the conclude
4314 # don't let driver-resolved files be marked, and run the conclude
4314 # step if asked to resolve
4315 # step if asked to resolve
4315 if ms[f] == "d":
4316 if ms[f] == "d":
4316 exact = m.exact(f)
4317 exact = m.exact(f)
4317 if mark:
4318 if mark:
4318 if exact:
4319 if exact:
4319 ui.warn(_('not marking %s as it is driver-resolved\n')
4320 ui.warn(_('not marking %s as it is driver-resolved\n')
4320 % f)
4321 % f)
4321 elif unmark:
4322 elif unmark:
4322 if exact:
4323 if exact:
4323 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4324 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4324 % f)
4325 % f)
4325 else:
4326 else:
4326 runconclude = True
4327 runconclude = True
4327 continue
4328 continue
4328
4329
4329 if mark:
4330 if mark:
4330 ms.mark(f, "r")
4331 ms.mark(f, "r")
4331 elif unmark:
4332 elif unmark:
4332 ms.mark(f, "u")
4333 ms.mark(f, "u")
4333 else:
4334 else:
4334 # backup pre-resolve (merge uses .orig for its own purposes)
4335 # backup pre-resolve (merge uses .orig for its own purposes)
4335 a = repo.wjoin(f)
4336 a = repo.wjoin(f)
4336 try:
4337 try:
4337 util.copyfile(a, a + ".resolve")
4338 util.copyfile(a, a + ".resolve")
4338 except (IOError, OSError) as inst:
4339 except (IOError, OSError) as inst:
4339 if inst.errno != errno.ENOENT:
4340 if inst.errno != errno.ENOENT:
4340 raise
4341 raise
4341
4342
4342 try:
4343 try:
4343 # preresolve file
4344 # preresolve file
4344 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4345 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4345 'resolve')
4346 'resolve')
4346 complete, r = ms.preresolve(f, wctx)
4347 complete, r = ms.preresolve(f, wctx)
4347 if not complete:
4348 if not complete:
4348 tocomplete.append(f)
4349 tocomplete.append(f)
4349 elif r:
4350 elif r:
4350 ret = 1
4351 ret = 1
4351 finally:
4352 finally:
4352 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4353 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4353 ms.commit()
4354 ms.commit()
4354
4355
4355 # replace filemerge's .orig file with our resolve file, but only
4356 # replace filemerge's .orig file with our resolve file, but only
4356 # for merges that are complete
4357 # for merges that are complete
4357 if complete:
4358 if complete:
4358 try:
4359 try:
4359 util.rename(a + ".resolve",
4360 util.rename(a + ".resolve",
4360 scmutil.origpath(ui, repo, a))
4361 scmutil.origpath(ui, repo, a))
4361 except OSError as inst:
4362 except OSError as inst:
4362 if inst.errno != errno.ENOENT:
4363 if inst.errno != errno.ENOENT:
4363 raise
4364 raise
4364
4365
4365 for f in tocomplete:
4366 for f in tocomplete:
4366 try:
4367 try:
4367 # resolve file
4368 # resolve file
4368 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4369 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4369 'resolve')
4370 'resolve')
4370 r = ms.resolve(f, wctx)
4371 r = ms.resolve(f, wctx)
4371 if r:
4372 if r:
4372 ret = 1
4373 ret = 1
4373 finally:
4374 finally:
4374 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4375 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4375 ms.commit()
4376 ms.commit()
4376
4377
4377 # replace filemerge's .orig file with our resolve file
4378 # replace filemerge's .orig file with our resolve file
4378 a = repo.wjoin(f)
4379 a = repo.wjoin(f)
4379 try:
4380 try:
4380 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4381 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4381 except OSError as inst:
4382 except OSError as inst:
4382 if inst.errno != errno.ENOENT:
4383 if inst.errno != errno.ENOENT:
4383 raise
4384 raise
4384
4385
4385 ms.commit()
4386 ms.commit()
4386 ms.recordactions()
4387 ms.recordactions()
4387
4388
4388 if not didwork and pats:
4389 if not didwork and pats:
4389 hint = None
4390 hint = None
4390 if not any([p for p in pats if p.find(':') >= 0]):
4391 if not any([p for p in pats if p.find(':') >= 0]):
4391 pats = ['path:%s' % p for p in pats]
4392 pats = ['path:%s' % p for p in pats]
4392 m = scmutil.match(wctx, pats, opts)
4393 m = scmutil.match(wctx, pats, opts)
4393 for f in ms:
4394 for f in ms:
4394 if not m(f):
4395 if not m(f):
4395 continue
4396 continue
4396 flags = ''.join(['-%s ' % o[0] for o in flaglist
4397 flags = ''.join(['-%s ' % o[0] for o in flaglist
4397 if opts.get(o)])
4398 if opts.get(o)])
4398 hint = _("(try: hg resolve %s%s)\n") % (
4399 hint = _("(try: hg resolve %s%s)\n") % (
4399 flags,
4400 flags,
4400 ' '.join(pats))
4401 ' '.join(pats))
4401 break
4402 break
4402 ui.warn(_("arguments do not match paths that need resolving\n"))
4403 ui.warn(_("arguments do not match paths that need resolving\n"))
4403 if hint:
4404 if hint:
4404 ui.warn(hint)
4405 ui.warn(hint)
4405 elif ms.mergedriver and ms.mdstate() != 's':
4406 elif ms.mergedriver and ms.mdstate() != 's':
4406 # run conclude step when either a driver-resolved file is requested
4407 # run conclude step when either a driver-resolved file is requested
4407 # or there are no driver-resolved files
4408 # or there are no driver-resolved files
4408 # we can't use 'ret' to determine whether any files are unresolved
4409 # we can't use 'ret' to determine whether any files are unresolved
4409 # because we might not have tried to resolve some
4410 # because we might not have tried to resolve some
4410 if ((runconclude or not list(ms.driverresolved()))
4411 if ((runconclude or not list(ms.driverresolved()))
4411 and not list(ms.unresolved())):
4412 and not list(ms.unresolved())):
4412 proceed = mergemod.driverconclude(repo, ms, wctx)
4413 proceed = mergemod.driverconclude(repo, ms, wctx)
4413 ms.commit()
4414 ms.commit()
4414 if not proceed:
4415 if not proceed:
4415 return 1
4416 return 1
4416
4417
4417 # Nudge users into finishing an unfinished operation
4418 # Nudge users into finishing an unfinished operation
4418 unresolvedf = list(ms.unresolved())
4419 unresolvedf = list(ms.unresolved())
4419 driverresolvedf = list(ms.driverresolved())
4420 driverresolvedf = list(ms.driverresolved())
4420 if not unresolvedf and not driverresolvedf:
4421 if not unresolvedf and not driverresolvedf:
4421 ui.status(_('(no more unresolved files)\n'))
4422 ui.status(_('(no more unresolved files)\n'))
4422 cmdutil.checkafterresolved(repo)
4423 cmdutil.checkafterresolved(repo)
4423 elif not unresolvedf:
4424 elif not unresolvedf:
4424 ui.status(_('(no more unresolved files -- '
4425 ui.status(_('(no more unresolved files -- '
4425 'run "hg resolve --all" to conclude)\n'))
4426 'run "hg resolve --all" to conclude)\n'))
4426
4427
4427 return ret
4428 return ret
4428
4429
4429 @command('revert',
4430 @command('revert',
4430 [('a', 'all', None, _('revert all changes when no arguments given')),
4431 [('a', 'all', None, _('revert all changes when no arguments given')),
4431 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4432 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4432 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4433 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4433 ('C', 'no-backup', None, _('do not save backup copies of files')),
4434 ('C', 'no-backup', None, _('do not save backup copies of files')),
4434 ('i', 'interactive', None,
4435 ('i', 'interactive', None,
4435 _('interactively select the changes (EXPERIMENTAL)')),
4436 _('interactively select the changes (EXPERIMENTAL)')),
4436 ] + walkopts + dryrunopts,
4437 ] + walkopts + dryrunopts,
4437 _('[OPTION]... [-r REV] [NAME]...'))
4438 _('[OPTION]... [-r REV] [NAME]...'))
4438 def revert(ui, repo, *pats, **opts):
4439 def revert(ui, repo, *pats, **opts):
4439 """restore files to their checkout state
4440 """restore files to their checkout state
4440
4441
4441 .. note::
4442 .. note::
4442
4443
4443 To check out earlier revisions, you should use :hg:`update REV`.
4444 To check out earlier revisions, you should use :hg:`update REV`.
4444 To cancel an uncommitted merge (and lose your changes),
4445 To cancel an uncommitted merge (and lose your changes),
4445 use :hg:`update --clean .`.
4446 use :hg:`update --clean .`.
4446
4447
4447 With no revision specified, revert the specified files or directories
4448 With no revision specified, revert the specified files or directories
4448 to the contents they had in the parent of the working directory.
4449 to the contents they had in the parent of the working directory.
4449 This restores the contents of files to an unmodified
4450 This restores the contents of files to an unmodified
4450 state and unschedules adds, removes, copies, and renames. If the
4451 state and unschedules adds, removes, copies, and renames. If the
4451 working directory has two parents, you must explicitly specify a
4452 working directory has two parents, you must explicitly specify a
4452 revision.
4453 revision.
4453
4454
4454 Using the -r/--rev or -d/--date options, revert the given files or
4455 Using the -r/--rev or -d/--date options, revert the given files or
4455 directories to their states as of a specific revision. Because
4456 directories to their states as of a specific revision. Because
4456 revert does not change the working directory parents, this will
4457 revert does not change the working directory parents, this will
4457 cause these files to appear modified. This can be helpful to "back
4458 cause these files to appear modified. This can be helpful to "back
4458 out" some or all of an earlier change. See :hg:`backout` for a
4459 out" some or all of an earlier change. See :hg:`backout` for a
4459 related method.
4460 related method.
4460
4461
4461 Modified files are saved with a .orig suffix before reverting.
4462 Modified files are saved with a .orig suffix before reverting.
4462 To disable these backups, use --no-backup. It is possible to store
4463 To disable these backups, use --no-backup. It is possible to store
4463 the backup files in a custom directory relative to the root of the
4464 the backup files in a custom directory relative to the root of the
4464 repository by setting the ``ui.origbackuppath`` configuration
4465 repository by setting the ``ui.origbackuppath`` configuration
4465 option.
4466 option.
4466
4467
4467 See :hg:`help dates` for a list of formats valid for -d/--date.
4468 See :hg:`help dates` for a list of formats valid for -d/--date.
4468
4469
4469 See :hg:`help backout` for a way to reverse the effect of an
4470 See :hg:`help backout` for a way to reverse the effect of an
4470 earlier changeset.
4471 earlier changeset.
4471
4472
4472 Returns 0 on success.
4473 Returns 0 on success.
4473 """
4474 """
4474
4475
4475 if opts.get("date"):
4476 if opts.get("date"):
4476 if opts.get("rev"):
4477 if opts.get("rev"):
4477 raise error.Abort(_("you can't specify a revision and a date"))
4478 raise error.Abort(_("you can't specify a revision and a date"))
4478 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4479 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4479
4480
4480 parent, p2 = repo.dirstate.parents()
4481 parent, p2 = repo.dirstate.parents()
4481 if not opts.get('rev') and p2 != nullid:
4482 if not opts.get('rev') and p2 != nullid:
4482 # revert after merge is a trap for new users (issue2915)
4483 # revert after merge is a trap for new users (issue2915)
4483 raise error.Abort(_('uncommitted merge with no revision specified'),
4484 raise error.Abort(_('uncommitted merge with no revision specified'),
4484 hint=_("use 'hg update' or see 'hg help revert'"))
4485 hint=_("use 'hg update' or see 'hg help revert'"))
4485
4486
4486 ctx = scmutil.revsingle(repo, opts.get('rev'))
4487 ctx = scmutil.revsingle(repo, opts.get('rev'))
4487
4488
4488 if (not (pats or opts.get('include') or opts.get('exclude') or
4489 if (not (pats or opts.get('include') or opts.get('exclude') or
4489 opts.get('all') or opts.get('interactive'))):
4490 opts.get('all') or opts.get('interactive'))):
4490 msg = _("no files or directories specified")
4491 msg = _("no files or directories specified")
4491 if p2 != nullid:
4492 if p2 != nullid:
4492 hint = _("uncommitted merge, use --all to discard all changes,"
4493 hint = _("uncommitted merge, use --all to discard all changes,"
4493 " or 'hg update -C .' to abort the merge")
4494 " or 'hg update -C .' to abort the merge")
4494 raise error.Abort(msg, hint=hint)
4495 raise error.Abort(msg, hint=hint)
4495 dirty = any(repo.status())
4496 dirty = any(repo.status())
4496 node = ctx.node()
4497 node = ctx.node()
4497 if node != parent:
4498 if node != parent:
4498 if dirty:
4499 if dirty:
4499 hint = _("uncommitted changes, use --all to discard all"
4500 hint = _("uncommitted changes, use --all to discard all"
4500 " changes, or 'hg update %s' to update") % ctx.rev()
4501 " changes, or 'hg update %s' to update") % ctx.rev()
4501 else:
4502 else:
4502 hint = _("use --all to revert all files,"
4503 hint = _("use --all to revert all files,"
4503 " or 'hg update %s' to update") % ctx.rev()
4504 " or 'hg update %s' to update") % ctx.rev()
4504 elif dirty:
4505 elif dirty:
4505 hint = _("uncommitted changes, use --all to discard all changes")
4506 hint = _("uncommitted changes, use --all to discard all changes")
4506 else:
4507 else:
4507 hint = _("use --all to revert all files")
4508 hint = _("use --all to revert all files")
4508 raise error.Abort(msg, hint=hint)
4509 raise error.Abort(msg, hint=hint)
4509
4510
4510 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4511 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4511
4512
4512 @command('rollback', dryrunopts +
4513 @command('rollback', dryrunopts +
4513 [('f', 'force', False, _('ignore safety measures'))])
4514 [('f', 'force', False, _('ignore safety measures'))])
4514 def rollback(ui, repo, **opts):
4515 def rollback(ui, repo, **opts):
4515 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4516 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4516
4517
4517 Please use :hg:`commit --amend` instead of rollback to correct
4518 Please use :hg:`commit --amend` instead of rollback to correct
4518 mistakes in the last commit.
4519 mistakes in the last commit.
4519
4520
4520 This command should be used with care. There is only one level of
4521 This command should be used with care. There is only one level of
4521 rollback, and there is no way to undo a rollback. It will also
4522 rollback, and there is no way to undo a rollback. It will also
4522 restore the dirstate at the time of the last transaction, losing
4523 restore the dirstate at the time of the last transaction, losing
4523 any dirstate changes since that time. This command does not alter
4524 any dirstate changes since that time. This command does not alter
4524 the working directory.
4525 the working directory.
4525
4526
4526 Transactions are used to encapsulate the effects of all commands
4527 Transactions are used to encapsulate the effects of all commands
4527 that create new changesets or propagate existing changesets into a
4528 that create new changesets or propagate existing changesets into a
4528 repository.
4529 repository.
4529
4530
4530 .. container:: verbose
4531 .. container:: verbose
4531
4532
4532 For example, the following commands are transactional, and their
4533 For example, the following commands are transactional, and their
4533 effects can be rolled back:
4534 effects can be rolled back:
4534
4535
4535 - commit
4536 - commit
4536 - import
4537 - import
4537 - pull
4538 - pull
4538 - push (with this repository as the destination)
4539 - push (with this repository as the destination)
4539 - unbundle
4540 - unbundle
4540
4541
4541 To avoid permanent data loss, rollback will refuse to rollback a
4542 To avoid permanent data loss, rollback will refuse to rollback a
4542 commit transaction if it isn't checked out. Use --force to
4543 commit transaction if it isn't checked out. Use --force to
4543 override this protection.
4544 override this protection.
4544
4545
4545 The rollback command can be entirely disabled by setting the
4546 The rollback command can be entirely disabled by setting the
4546 ``ui.rollback`` configuration setting to false. If you're here
4547 ``ui.rollback`` configuration setting to false. If you're here
4547 because you want to use rollback and it's disabled, you can
4548 because you want to use rollback and it's disabled, you can
4548 re-enable the command by setting ``ui.rollback`` to true.
4549 re-enable the command by setting ``ui.rollback`` to true.
4549
4550
4550 This command is not intended for use on public repositories. Once
4551 This command is not intended for use on public repositories. Once
4551 changes are visible for pull by other users, rolling a transaction
4552 changes are visible for pull by other users, rolling a transaction
4552 back locally is ineffective (someone else may already have pulled
4553 back locally is ineffective (someone else may already have pulled
4553 the changes). Furthermore, a race is possible with readers of the
4554 the changes). Furthermore, a race is possible with readers of the
4554 repository; for example an in-progress pull from the repository
4555 repository; for example an in-progress pull from the repository
4555 may fail if a rollback is performed.
4556 may fail if a rollback is performed.
4556
4557
4557 Returns 0 on success, 1 if no rollback data is available.
4558 Returns 0 on success, 1 if no rollback data is available.
4558 """
4559 """
4559 if not ui.configbool('ui', 'rollback', True):
4560 if not ui.configbool('ui', 'rollback', True):
4560 raise error.Abort(_('rollback is disabled because it is unsafe'),
4561 raise error.Abort(_('rollback is disabled because it is unsafe'),
4561 hint=('see `hg help -v rollback` for information'))
4562 hint=('see `hg help -v rollback` for information'))
4562 return repo.rollback(dryrun=opts.get('dry_run'),
4563 return repo.rollback(dryrun=opts.get('dry_run'),
4563 force=opts.get('force'))
4564 force=opts.get('force'))
4564
4565
4565 @command('root', [])
4566 @command('root', [])
4566 def root(ui, repo):
4567 def root(ui, repo):
4567 """print the root (top) of the current working directory
4568 """print the root (top) of the current working directory
4568
4569
4569 Print the root directory of the current repository.
4570 Print the root directory of the current repository.
4570
4571
4571 Returns 0 on success.
4572 Returns 0 on success.
4572 """
4573 """
4573 ui.write(repo.root + "\n")
4574 ui.write(repo.root + "\n")
4574
4575
4575 @command('^serve',
4576 @command('^serve',
4576 [('A', 'accesslog', '', _('name of access log file to write to'),
4577 [('A', 'accesslog', '', _('name of access log file to write to'),
4577 _('FILE')),
4578 _('FILE')),
4578 ('d', 'daemon', None, _('run server in background')),
4579 ('d', 'daemon', None, _('run server in background')),
4579 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4580 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4580 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4581 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4581 # use string type, then we can check if something was passed
4582 # use string type, then we can check if something was passed
4582 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4583 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4583 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4584 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4584 _('ADDR')),
4585 _('ADDR')),
4585 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4586 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4586 _('PREFIX')),
4587 _('PREFIX')),
4587 ('n', 'name', '',
4588 ('n', 'name', '',
4588 _('name to show in web pages (default: working directory)'), _('NAME')),
4589 _('name to show in web pages (default: working directory)'), _('NAME')),
4589 ('', 'web-conf', '',
4590 ('', 'web-conf', '',
4590 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4591 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4591 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4592 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4592 _('FILE')),
4593 _('FILE')),
4593 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4594 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4594 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4595 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4595 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4596 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4596 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4597 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4597 ('', 'style', '', _('template style to use'), _('STYLE')),
4598 ('', 'style', '', _('template style to use'), _('STYLE')),
4598 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4599 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4599 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4600 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4600 _('[OPTION]...'),
4601 _('[OPTION]...'),
4601 optionalrepo=True)
4602 optionalrepo=True)
4602 def serve(ui, repo, **opts):
4603 def serve(ui, repo, **opts):
4603 """start stand-alone webserver
4604 """start stand-alone webserver
4604
4605
4605 Start a local HTTP repository browser and pull server. You can use
4606 Start a local HTTP repository browser and pull server. You can use
4606 this for ad-hoc sharing and browsing of repositories. It is
4607 this for ad-hoc sharing and browsing of repositories. It is
4607 recommended to use a real web server to serve a repository for
4608 recommended to use a real web server to serve a repository for
4608 longer periods of time.
4609 longer periods of time.
4609
4610
4610 Please note that the server does not implement access control.
4611 Please note that the server does not implement access control.
4611 This means that, by default, anybody can read from the server and
4612 This means that, by default, anybody can read from the server and
4612 nobody can write to it by default. Set the ``web.allow_push``
4613 nobody can write to it by default. Set the ``web.allow_push``
4613 option to ``*`` to allow everybody to push to the server. You
4614 option to ``*`` to allow everybody to push to the server. You
4614 should use a real web server if you need to authenticate users.
4615 should use a real web server if you need to authenticate users.
4615
4616
4616 By default, the server logs accesses to stdout and errors to
4617 By default, the server logs accesses to stdout and errors to
4617 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4618 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4618 files.
4619 files.
4619
4620
4620 To have the server choose a free port number to listen on, specify
4621 To have the server choose a free port number to listen on, specify
4621 a port number of 0; in this case, the server will print the port
4622 a port number of 0; in this case, the server will print the port
4622 number it uses.
4623 number it uses.
4623
4624
4624 Returns 0 on success.
4625 Returns 0 on success.
4625 """
4626 """
4626
4627
4627 if opts["stdio"] and opts["cmdserver"]:
4628 if opts["stdio"] and opts["cmdserver"]:
4628 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4629 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4629
4630
4630 if opts["stdio"]:
4631 if opts["stdio"]:
4631 if repo is None:
4632 if repo is None:
4632 raise error.RepoError(_("there is no Mercurial repository here"
4633 raise error.RepoError(_("there is no Mercurial repository here"
4633 " (.hg not found)"))
4634 " (.hg not found)"))
4634 s = sshserver.sshserver(ui, repo)
4635 s = sshserver.sshserver(ui, repo)
4635 s.serve_forever()
4636 s.serve_forever()
4636
4637
4637 service = server.createservice(ui, repo, opts)
4638 service = server.createservice(ui, repo, opts)
4638 return server.runservice(opts, initfn=service.init, runfn=service.run)
4639 return server.runservice(opts, initfn=service.init, runfn=service.run)
4639
4640
4640 @command('^status|st',
4641 @command('^status|st',
4641 [('A', 'all', None, _('show status of all files')),
4642 [('A', 'all', None, _('show status of all files')),
4642 ('m', 'modified', None, _('show only modified files')),
4643 ('m', 'modified', None, _('show only modified files')),
4643 ('a', 'added', None, _('show only added files')),
4644 ('a', 'added', None, _('show only added files')),
4644 ('r', 'removed', None, _('show only removed files')),
4645 ('r', 'removed', None, _('show only removed files')),
4645 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4646 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4646 ('c', 'clean', None, _('show only files without changes')),
4647 ('c', 'clean', None, _('show only files without changes')),
4647 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4648 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4648 ('i', 'ignored', None, _('show only ignored files')),
4649 ('i', 'ignored', None, _('show only ignored files')),
4649 ('n', 'no-status', None, _('hide status prefix')),
4650 ('n', 'no-status', None, _('hide status prefix')),
4650 ('C', 'copies', None, _('show source of copied files')),
4651 ('C', 'copies', None, _('show source of copied files')),
4651 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4652 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4652 ('', 'rev', [], _('show difference from revision'), _('REV')),
4653 ('', 'rev', [], _('show difference from revision'), _('REV')),
4653 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4654 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4654 ] + walkopts + subrepoopts + formatteropts,
4655 ] + walkopts + subrepoopts + formatteropts,
4655 _('[OPTION]... [FILE]...'),
4656 _('[OPTION]... [FILE]...'),
4656 inferrepo=True)
4657 inferrepo=True)
4657 def status(ui, repo, *pats, **opts):
4658 def status(ui, repo, *pats, **opts):
4658 """show changed files in the working directory
4659 """show changed files in the working directory
4659
4660
4660 Show status of files in the repository. If names are given, only
4661 Show status of files in the repository. If names are given, only
4661 files that match are shown. Files that are clean or ignored or
4662 files that match are shown. Files that are clean or ignored or
4662 the source of a copy/move operation, are not listed unless
4663 the source of a copy/move operation, are not listed unless
4663 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4664 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4664 Unless options described with "show only ..." are given, the
4665 Unless options described with "show only ..." are given, the
4665 options -mardu are used.
4666 options -mardu are used.
4666
4667
4667 Option -q/--quiet hides untracked (unknown and ignored) files
4668 Option -q/--quiet hides untracked (unknown and ignored) files
4668 unless explicitly requested with -u/--unknown or -i/--ignored.
4669 unless explicitly requested with -u/--unknown or -i/--ignored.
4669
4670
4670 .. note::
4671 .. note::
4671
4672
4672 :hg:`status` may appear to disagree with diff if permissions have
4673 :hg:`status` may appear to disagree with diff if permissions have
4673 changed or a merge has occurred. The standard diff format does
4674 changed or a merge has occurred. The standard diff format does
4674 not report permission changes and diff only reports changes
4675 not report permission changes and diff only reports changes
4675 relative to one merge parent.
4676 relative to one merge parent.
4676
4677
4677 If one revision is given, it is used as the base revision.
4678 If one revision is given, it is used as the base revision.
4678 If two revisions are given, the differences between them are
4679 If two revisions are given, the differences between them are
4679 shown. The --change option can also be used as a shortcut to list
4680 shown. The --change option can also be used as a shortcut to list
4680 the changed files of a revision from its first parent.
4681 the changed files of a revision from its first parent.
4681
4682
4682 The codes used to show the status of files are::
4683 The codes used to show the status of files are::
4683
4684
4684 M = modified
4685 M = modified
4685 A = added
4686 A = added
4686 R = removed
4687 R = removed
4687 C = clean
4688 C = clean
4688 ! = missing (deleted by non-hg command, but still tracked)
4689 ! = missing (deleted by non-hg command, but still tracked)
4689 ? = not tracked
4690 ? = not tracked
4690 I = ignored
4691 I = ignored
4691 = origin of the previous file (with --copies)
4692 = origin of the previous file (with --copies)
4692
4693
4693 .. container:: verbose
4694 .. container:: verbose
4694
4695
4695 Examples:
4696 Examples:
4696
4697
4697 - show changes in the working directory relative to a
4698 - show changes in the working directory relative to a
4698 changeset::
4699 changeset::
4699
4700
4700 hg status --rev 9353
4701 hg status --rev 9353
4701
4702
4702 - show changes in the working directory relative to the
4703 - show changes in the working directory relative to the
4703 current directory (see :hg:`help patterns` for more information)::
4704 current directory (see :hg:`help patterns` for more information)::
4704
4705
4705 hg status re:
4706 hg status re:
4706
4707
4707 - show all changes including copies in an existing changeset::
4708 - show all changes including copies in an existing changeset::
4708
4709
4709 hg status --copies --change 9353
4710 hg status --copies --change 9353
4710
4711
4711 - get a NUL separated list of added files, suitable for xargs::
4712 - get a NUL separated list of added files, suitable for xargs::
4712
4713
4713 hg status -an0
4714 hg status -an0
4714
4715
4715 Returns 0 on success.
4716 Returns 0 on success.
4716 """
4717 """
4717
4718
4718 revs = opts.get('rev')
4719 revs = opts.get('rev')
4719 change = opts.get('change')
4720 change = opts.get('change')
4720
4721
4721 if revs and change:
4722 if revs and change:
4722 msg = _('cannot specify --rev and --change at the same time')
4723 msg = _('cannot specify --rev and --change at the same time')
4723 raise error.Abort(msg)
4724 raise error.Abort(msg)
4724 elif change:
4725 elif change:
4725 node2 = scmutil.revsingle(repo, change, None).node()
4726 node2 = scmutil.revsingle(repo, change, None).node()
4726 node1 = repo[node2].p1().node()
4727 node1 = repo[node2].p1().node()
4727 else:
4728 else:
4728 node1, node2 = scmutil.revpair(repo, revs)
4729 node1, node2 = scmutil.revpair(repo, revs)
4729
4730
4730 if pats:
4731 if pats:
4731 cwd = repo.getcwd()
4732 cwd = repo.getcwd()
4732 else:
4733 else:
4733 cwd = ''
4734 cwd = ''
4734
4735
4735 if opts.get('print0'):
4736 if opts.get('print0'):
4736 end = '\0'
4737 end = '\0'
4737 else:
4738 else:
4738 end = '\n'
4739 end = '\n'
4739 copy = {}
4740 copy = {}
4740 states = 'modified added removed deleted unknown ignored clean'.split()
4741 states = 'modified added removed deleted unknown ignored clean'.split()
4741 show = [k for k in states if opts.get(k)]
4742 show = [k for k in states if opts.get(k)]
4742 if opts.get('all'):
4743 if opts.get('all'):
4743 show += ui.quiet and (states[:4] + ['clean']) or states
4744 show += ui.quiet and (states[:4] + ['clean']) or states
4744 if not show:
4745 if not show:
4745 if ui.quiet:
4746 if ui.quiet:
4746 show = states[:4]
4747 show = states[:4]
4747 else:
4748 else:
4748 show = states[:5]
4749 show = states[:5]
4749
4750
4750 m = scmutil.match(repo[node2], pats, opts)
4751 m = scmutil.match(repo[node2], pats, opts)
4751 stat = repo.status(node1, node2, m,
4752 stat = repo.status(node1, node2, m,
4752 'ignored' in show, 'clean' in show, 'unknown' in show,
4753 'ignored' in show, 'clean' in show, 'unknown' in show,
4753 opts.get('subrepos'))
4754 opts.get('subrepos'))
4754 changestates = zip(states, 'MAR!?IC', stat)
4755 changestates = zip(states, 'MAR!?IC', stat)
4755
4756
4756 if (opts.get('all') or opts.get('copies')
4757 if (opts.get('all') or opts.get('copies')
4757 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4758 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4758 copy = copies.pathcopies(repo[node1], repo[node2], m)
4759 copy = copies.pathcopies(repo[node1], repo[node2], m)
4759
4760
4760 ui.pager('status')
4761 ui.pager('status')
4761 fm = ui.formatter('status', opts)
4762 fm = ui.formatter('status', opts)
4762 fmt = '%s' + end
4763 fmt = '%s' + end
4763 showchar = not opts.get('no_status')
4764 showchar = not opts.get('no_status')
4764
4765
4765 for state, char, files in changestates:
4766 for state, char, files in changestates:
4766 if state in show:
4767 if state in show:
4767 label = 'status.' + state
4768 label = 'status.' + state
4768 for f in files:
4769 for f in files:
4769 fm.startitem()
4770 fm.startitem()
4770 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4771 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4771 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4772 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4772 if f in copy:
4773 if f in copy:
4773 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4774 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4774 label='status.copied')
4775 label='status.copied')
4775 fm.end()
4776 fm.end()
4776
4777
4777 @command('^summary|sum',
4778 @command('^summary|sum',
4778 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4779 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4779 def summary(ui, repo, **opts):
4780 def summary(ui, repo, **opts):
4780 """summarize working directory state
4781 """summarize working directory state
4781
4782
4782 This generates a brief summary of the working directory state,
4783 This generates a brief summary of the working directory state,
4783 including parents, branch, commit status, phase and available updates.
4784 including parents, branch, commit status, phase and available updates.
4784
4785
4785 With the --remote option, this will check the default paths for
4786 With the --remote option, this will check the default paths for
4786 incoming and outgoing changes. This can be time-consuming.
4787 incoming and outgoing changes. This can be time-consuming.
4787
4788
4788 Returns 0 on success.
4789 Returns 0 on success.
4789 """
4790 """
4790
4791
4791 ui.pager('summary')
4792 ui.pager('summary')
4792 ctx = repo[None]
4793 ctx = repo[None]
4793 parents = ctx.parents()
4794 parents = ctx.parents()
4794 pnode = parents[0].node()
4795 pnode = parents[0].node()
4795 marks = []
4796 marks = []
4796
4797
4797 ms = None
4798 ms = None
4798 try:
4799 try:
4799 ms = mergemod.mergestate.read(repo)
4800 ms = mergemod.mergestate.read(repo)
4800 except error.UnsupportedMergeRecords as e:
4801 except error.UnsupportedMergeRecords as e:
4801 s = ' '.join(e.recordtypes)
4802 s = ' '.join(e.recordtypes)
4802 ui.warn(
4803 ui.warn(
4803 _('warning: merge state has unsupported record types: %s\n') % s)
4804 _('warning: merge state has unsupported record types: %s\n') % s)
4804 unresolved = 0
4805 unresolved = 0
4805 else:
4806 else:
4806 unresolved = [f for f in ms if ms[f] == 'u']
4807 unresolved = [f for f in ms if ms[f] == 'u']
4807
4808
4808 for p in parents:
4809 for p in parents:
4809 # label with log.changeset (instead of log.parent) since this
4810 # label with log.changeset (instead of log.parent) since this
4810 # shows a working directory parent *changeset*:
4811 # shows a working directory parent *changeset*:
4811 # i18n: column positioning for "hg summary"
4812 # i18n: column positioning for "hg summary"
4812 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4813 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4813 label=cmdutil._changesetlabels(p))
4814 label=cmdutil._changesetlabels(p))
4814 ui.write(' '.join(p.tags()), label='log.tag')
4815 ui.write(' '.join(p.tags()), label='log.tag')
4815 if p.bookmarks():
4816 if p.bookmarks():
4816 marks.extend(p.bookmarks())
4817 marks.extend(p.bookmarks())
4817 if p.rev() == -1:
4818 if p.rev() == -1:
4818 if not len(repo):
4819 if not len(repo):
4819 ui.write(_(' (empty repository)'))
4820 ui.write(_(' (empty repository)'))
4820 else:
4821 else:
4821 ui.write(_(' (no revision checked out)'))
4822 ui.write(_(' (no revision checked out)'))
4822 if p.troubled():
4823 if p.troubled():
4823 ui.write(' ('
4824 ui.write(' ('
4824 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4825 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4825 for trouble in p.troubles())
4826 for trouble in p.troubles())
4826 + ')')
4827 + ')')
4827 ui.write('\n')
4828 ui.write('\n')
4828 if p.description():
4829 if p.description():
4829 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4830 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4830 label='log.summary')
4831 label='log.summary')
4831
4832
4832 branch = ctx.branch()
4833 branch = ctx.branch()
4833 bheads = repo.branchheads(branch)
4834 bheads = repo.branchheads(branch)
4834 # i18n: column positioning for "hg summary"
4835 # i18n: column positioning for "hg summary"
4835 m = _('branch: %s\n') % branch
4836 m = _('branch: %s\n') % branch
4836 if branch != 'default':
4837 if branch != 'default':
4837 ui.write(m, label='log.branch')
4838 ui.write(m, label='log.branch')
4838 else:
4839 else:
4839 ui.status(m, label='log.branch')
4840 ui.status(m, label='log.branch')
4840
4841
4841 if marks:
4842 if marks:
4842 active = repo._activebookmark
4843 active = repo._activebookmark
4843 # i18n: column positioning for "hg summary"
4844 # i18n: column positioning for "hg summary"
4844 ui.write(_('bookmarks:'), label='log.bookmark')
4845 ui.write(_('bookmarks:'), label='log.bookmark')
4845 if active is not None:
4846 if active is not None:
4846 if active in marks:
4847 if active in marks:
4847 ui.write(' *' + active, label=activebookmarklabel)
4848 ui.write(' *' + active, label=activebookmarklabel)
4848 marks.remove(active)
4849 marks.remove(active)
4849 else:
4850 else:
4850 ui.write(' [%s]' % active, label=activebookmarklabel)
4851 ui.write(' [%s]' % active, label=activebookmarklabel)
4851 for m in marks:
4852 for m in marks:
4852 ui.write(' ' + m, label='log.bookmark')
4853 ui.write(' ' + m, label='log.bookmark')
4853 ui.write('\n', label='log.bookmark')
4854 ui.write('\n', label='log.bookmark')
4854
4855
4855 status = repo.status(unknown=True)
4856 status = repo.status(unknown=True)
4856
4857
4857 c = repo.dirstate.copies()
4858 c = repo.dirstate.copies()
4858 copied, renamed = [], []
4859 copied, renamed = [], []
4859 for d, s in c.iteritems():
4860 for d, s in c.iteritems():
4860 if s in status.removed:
4861 if s in status.removed:
4861 status.removed.remove(s)
4862 status.removed.remove(s)
4862 renamed.append(d)
4863 renamed.append(d)
4863 else:
4864 else:
4864 copied.append(d)
4865 copied.append(d)
4865 if d in status.added:
4866 if d in status.added:
4866 status.added.remove(d)
4867 status.added.remove(d)
4867
4868
4868 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4869 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4869
4870
4870 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4871 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4871 (ui.label(_('%d added'), 'status.added'), status.added),
4872 (ui.label(_('%d added'), 'status.added'), status.added),
4872 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4873 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4873 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4874 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4874 (ui.label(_('%d copied'), 'status.copied'), copied),
4875 (ui.label(_('%d copied'), 'status.copied'), copied),
4875 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4876 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4876 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4877 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4877 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4878 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4878 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4879 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4879 t = []
4880 t = []
4880 for l, s in labels:
4881 for l, s in labels:
4881 if s:
4882 if s:
4882 t.append(l % len(s))
4883 t.append(l % len(s))
4883
4884
4884 t = ', '.join(t)
4885 t = ', '.join(t)
4885 cleanworkdir = False
4886 cleanworkdir = False
4886
4887
4887 if repo.vfs.exists('graftstate'):
4888 if repo.vfs.exists('graftstate'):
4888 t += _(' (graft in progress)')
4889 t += _(' (graft in progress)')
4889 if repo.vfs.exists('updatestate'):
4890 if repo.vfs.exists('updatestate'):
4890 t += _(' (interrupted update)')
4891 t += _(' (interrupted update)')
4891 elif len(parents) > 1:
4892 elif len(parents) > 1:
4892 t += _(' (merge)')
4893 t += _(' (merge)')
4893 elif branch != parents[0].branch():
4894 elif branch != parents[0].branch():
4894 t += _(' (new branch)')
4895 t += _(' (new branch)')
4895 elif (parents[0].closesbranch() and
4896 elif (parents[0].closesbranch() and
4896 pnode in repo.branchheads(branch, closed=True)):
4897 pnode in repo.branchheads(branch, closed=True)):
4897 t += _(' (head closed)')
4898 t += _(' (head closed)')
4898 elif not (status.modified or status.added or status.removed or renamed or
4899 elif not (status.modified or status.added or status.removed or renamed or
4899 copied or subs):
4900 copied or subs):
4900 t += _(' (clean)')
4901 t += _(' (clean)')
4901 cleanworkdir = True
4902 cleanworkdir = True
4902 elif pnode not in bheads:
4903 elif pnode not in bheads:
4903 t += _(' (new branch head)')
4904 t += _(' (new branch head)')
4904
4905
4905 if parents:
4906 if parents:
4906 pendingphase = max(p.phase() for p in parents)
4907 pendingphase = max(p.phase() for p in parents)
4907 else:
4908 else:
4908 pendingphase = phases.public
4909 pendingphase = phases.public
4909
4910
4910 if pendingphase > phases.newcommitphase(ui):
4911 if pendingphase > phases.newcommitphase(ui):
4911 t += ' (%s)' % phases.phasenames[pendingphase]
4912 t += ' (%s)' % phases.phasenames[pendingphase]
4912
4913
4913 if cleanworkdir:
4914 if cleanworkdir:
4914 # i18n: column positioning for "hg summary"
4915 # i18n: column positioning for "hg summary"
4915 ui.status(_('commit: %s\n') % t.strip())
4916 ui.status(_('commit: %s\n') % t.strip())
4916 else:
4917 else:
4917 # i18n: column positioning for "hg summary"
4918 # i18n: column positioning for "hg summary"
4918 ui.write(_('commit: %s\n') % t.strip())
4919 ui.write(_('commit: %s\n') % t.strip())
4919
4920
4920 # all ancestors of branch heads - all ancestors of parent = new csets
4921 # all ancestors of branch heads - all ancestors of parent = new csets
4921 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4922 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4922 bheads))
4923 bheads))
4923
4924
4924 if new == 0:
4925 if new == 0:
4925 # i18n: column positioning for "hg summary"
4926 # i18n: column positioning for "hg summary"
4926 ui.status(_('update: (current)\n'))
4927 ui.status(_('update: (current)\n'))
4927 elif pnode not in bheads:
4928 elif pnode not in bheads:
4928 # i18n: column positioning for "hg summary"
4929 # i18n: column positioning for "hg summary"
4929 ui.write(_('update: %d new changesets (update)\n') % new)
4930 ui.write(_('update: %d new changesets (update)\n') % new)
4930 else:
4931 else:
4931 # i18n: column positioning for "hg summary"
4932 # i18n: column positioning for "hg summary"
4932 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4933 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4933 (new, len(bheads)))
4934 (new, len(bheads)))
4934
4935
4935 t = []
4936 t = []
4936 draft = len(repo.revs('draft()'))
4937 draft = len(repo.revs('draft()'))
4937 if draft:
4938 if draft:
4938 t.append(_('%d draft') % draft)
4939 t.append(_('%d draft') % draft)
4939 secret = len(repo.revs('secret()'))
4940 secret = len(repo.revs('secret()'))
4940 if secret:
4941 if secret:
4941 t.append(_('%d secret') % secret)
4942 t.append(_('%d secret') % secret)
4942
4943
4943 if draft or secret:
4944 if draft or secret:
4944 ui.status(_('phases: %s\n') % ', '.join(t))
4945 ui.status(_('phases: %s\n') % ', '.join(t))
4945
4946
4946 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4947 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4947 for trouble in ("unstable", "divergent", "bumped"):
4948 for trouble in ("unstable", "divergent", "bumped"):
4948 numtrouble = len(repo.revs(trouble + "()"))
4949 numtrouble = len(repo.revs(trouble + "()"))
4949 # We write all the possibilities to ease translation
4950 # We write all the possibilities to ease translation
4950 troublemsg = {
4951 troublemsg = {
4951 "unstable": _("unstable: %d changesets"),
4952 "unstable": _("unstable: %d changesets"),
4952 "divergent": _("divergent: %d changesets"),
4953 "divergent": _("divergent: %d changesets"),
4953 "bumped": _("bumped: %d changesets"),
4954 "bumped": _("bumped: %d changesets"),
4954 }
4955 }
4955 if numtrouble > 0:
4956 if numtrouble > 0:
4956 ui.status(troublemsg[trouble] % numtrouble + "\n")
4957 ui.status(troublemsg[trouble] % numtrouble + "\n")
4957
4958
4958 cmdutil.summaryhooks(ui, repo)
4959 cmdutil.summaryhooks(ui, repo)
4959
4960
4960 if opts.get('remote'):
4961 if opts.get('remote'):
4961 needsincoming, needsoutgoing = True, True
4962 needsincoming, needsoutgoing = True, True
4962 else:
4963 else:
4963 needsincoming, needsoutgoing = False, False
4964 needsincoming, needsoutgoing = False, False
4964 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4965 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4965 if i:
4966 if i:
4966 needsincoming = True
4967 needsincoming = True
4967 if o:
4968 if o:
4968 needsoutgoing = True
4969 needsoutgoing = True
4969 if not needsincoming and not needsoutgoing:
4970 if not needsincoming and not needsoutgoing:
4970 return
4971 return
4971
4972
4972 def getincoming():
4973 def getincoming():
4973 source, branches = hg.parseurl(ui.expandpath('default'))
4974 source, branches = hg.parseurl(ui.expandpath('default'))
4974 sbranch = branches[0]
4975 sbranch = branches[0]
4975 try:
4976 try:
4976 other = hg.peer(repo, {}, source)
4977 other = hg.peer(repo, {}, source)
4977 except error.RepoError:
4978 except error.RepoError:
4978 if opts.get('remote'):
4979 if opts.get('remote'):
4979 raise
4980 raise
4980 return source, sbranch, None, None, None
4981 return source, sbranch, None, None, None
4981 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4982 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
4982 if revs:
4983 if revs:
4983 revs = [other.lookup(rev) for rev in revs]
4984 revs = [other.lookup(rev) for rev in revs]
4984 ui.debug('comparing with %s\n' % util.hidepassword(source))
4985 ui.debug('comparing with %s\n' % util.hidepassword(source))
4985 repo.ui.pushbuffer()
4986 repo.ui.pushbuffer()
4986 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4987 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
4987 repo.ui.popbuffer()
4988 repo.ui.popbuffer()
4988 return source, sbranch, other, commoninc, commoninc[1]
4989 return source, sbranch, other, commoninc, commoninc[1]
4989
4990
4990 if needsincoming:
4991 if needsincoming:
4991 source, sbranch, sother, commoninc, incoming = getincoming()
4992 source, sbranch, sother, commoninc, incoming = getincoming()
4992 else:
4993 else:
4993 source = sbranch = sother = commoninc = incoming = None
4994 source = sbranch = sother = commoninc = incoming = None
4994
4995
4995 def getoutgoing():
4996 def getoutgoing():
4996 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4997 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
4997 dbranch = branches[0]
4998 dbranch = branches[0]
4998 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4999 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
4999 if source != dest:
5000 if source != dest:
5000 try:
5001 try:
5001 dother = hg.peer(repo, {}, dest)
5002 dother = hg.peer(repo, {}, dest)
5002 except error.RepoError:
5003 except error.RepoError:
5003 if opts.get('remote'):
5004 if opts.get('remote'):
5004 raise
5005 raise
5005 return dest, dbranch, None, None
5006 return dest, dbranch, None, None
5006 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5007 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5007 elif sother is None:
5008 elif sother is None:
5008 # there is no explicit destination peer, but source one is invalid
5009 # there is no explicit destination peer, but source one is invalid
5009 return dest, dbranch, None, None
5010 return dest, dbranch, None, None
5010 else:
5011 else:
5011 dother = sother
5012 dother = sother
5012 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5013 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5013 common = None
5014 common = None
5014 else:
5015 else:
5015 common = commoninc
5016 common = commoninc
5016 if revs:
5017 if revs:
5017 revs = [repo.lookup(rev) for rev in revs]
5018 revs = [repo.lookup(rev) for rev in revs]
5018 repo.ui.pushbuffer()
5019 repo.ui.pushbuffer()
5019 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5020 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5020 commoninc=common)
5021 commoninc=common)
5021 repo.ui.popbuffer()
5022 repo.ui.popbuffer()
5022 return dest, dbranch, dother, outgoing
5023 return dest, dbranch, dother, outgoing
5023
5024
5024 if needsoutgoing:
5025 if needsoutgoing:
5025 dest, dbranch, dother, outgoing = getoutgoing()
5026 dest, dbranch, dother, outgoing = getoutgoing()
5026 else:
5027 else:
5027 dest = dbranch = dother = outgoing = None
5028 dest = dbranch = dother = outgoing = None
5028
5029
5029 if opts.get('remote'):
5030 if opts.get('remote'):
5030 t = []
5031 t = []
5031 if incoming:
5032 if incoming:
5032 t.append(_('1 or more incoming'))
5033 t.append(_('1 or more incoming'))
5033 o = outgoing.missing
5034 o = outgoing.missing
5034 if o:
5035 if o:
5035 t.append(_('%d outgoing') % len(o))
5036 t.append(_('%d outgoing') % len(o))
5036 other = dother or sother
5037 other = dother or sother
5037 if 'bookmarks' in other.listkeys('namespaces'):
5038 if 'bookmarks' in other.listkeys('namespaces'):
5038 counts = bookmarks.summary(repo, other)
5039 counts = bookmarks.summary(repo, other)
5039 if counts[0] > 0:
5040 if counts[0] > 0:
5040 t.append(_('%d incoming bookmarks') % counts[0])
5041 t.append(_('%d incoming bookmarks') % counts[0])
5041 if counts[1] > 0:
5042 if counts[1] > 0:
5042 t.append(_('%d outgoing bookmarks') % counts[1])
5043 t.append(_('%d outgoing bookmarks') % counts[1])
5043
5044
5044 if t:
5045 if t:
5045 # i18n: column positioning for "hg summary"
5046 # i18n: column positioning for "hg summary"
5046 ui.write(_('remote: %s\n') % (', '.join(t)))
5047 ui.write(_('remote: %s\n') % (', '.join(t)))
5047 else:
5048 else:
5048 # i18n: column positioning for "hg summary"
5049 # i18n: column positioning for "hg summary"
5049 ui.status(_('remote: (synced)\n'))
5050 ui.status(_('remote: (synced)\n'))
5050
5051
5051 cmdutil.summaryremotehooks(ui, repo, opts,
5052 cmdutil.summaryremotehooks(ui, repo, opts,
5052 ((source, sbranch, sother, commoninc),
5053 ((source, sbranch, sother, commoninc),
5053 (dest, dbranch, dother, outgoing)))
5054 (dest, dbranch, dother, outgoing)))
5054
5055
5055 @command('tag',
5056 @command('tag',
5056 [('f', 'force', None, _('force tag')),
5057 [('f', 'force', None, _('force tag')),
5057 ('l', 'local', None, _('make the tag local')),
5058 ('l', 'local', None, _('make the tag local')),
5058 ('r', 'rev', '', _('revision to tag'), _('REV')),
5059 ('r', 'rev', '', _('revision to tag'), _('REV')),
5059 ('', 'remove', None, _('remove a tag')),
5060 ('', 'remove', None, _('remove a tag')),
5060 # -l/--local is already there, commitopts cannot be used
5061 # -l/--local is already there, commitopts cannot be used
5061 ('e', 'edit', None, _('invoke editor on commit messages')),
5062 ('e', 'edit', None, _('invoke editor on commit messages')),
5062 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5063 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5063 ] + commitopts2,
5064 ] + commitopts2,
5064 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5065 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5065 def tag(ui, repo, name1, *names, **opts):
5066 def tag(ui, repo, name1, *names, **opts):
5066 """add one or more tags for the current or given revision
5067 """add one or more tags for the current or given revision
5067
5068
5068 Name a particular revision using <name>.
5069 Name a particular revision using <name>.
5069
5070
5070 Tags are used to name particular revisions of the repository and are
5071 Tags are used to name particular revisions of the repository and are
5071 very useful to compare different revisions, to go back to significant
5072 very useful to compare different revisions, to go back to significant
5072 earlier versions or to mark branch points as releases, etc. Changing
5073 earlier versions or to mark branch points as releases, etc. Changing
5073 an existing tag is normally disallowed; use -f/--force to override.
5074 an existing tag is normally disallowed; use -f/--force to override.
5074
5075
5075 If no revision is given, the parent of the working directory is
5076 If no revision is given, the parent of the working directory is
5076 used.
5077 used.
5077
5078
5078 To facilitate version control, distribution, and merging of tags,
5079 To facilitate version control, distribution, and merging of tags,
5079 they are stored as a file named ".hgtags" which is managed similarly
5080 they are stored as a file named ".hgtags" which is managed similarly
5080 to other project files and can be hand-edited if necessary. This
5081 to other project files and can be hand-edited if necessary. This
5081 also means that tagging creates a new commit. The file
5082 also means that tagging creates a new commit. The file
5082 ".hg/localtags" is used for local tags (not shared among
5083 ".hg/localtags" is used for local tags (not shared among
5083 repositories).
5084 repositories).
5084
5085
5085 Tag commits are usually made at the head of a branch. If the parent
5086 Tag commits are usually made at the head of a branch. If the parent
5086 of the working directory is not a branch head, :hg:`tag` aborts; use
5087 of the working directory is not a branch head, :hg:`tag` aborts; use
5087 -f/--force to force the tag commit to be based on a non-head
5088 -f/--force to force the tag commit to be based on a non-head
5088 changeset.
5089 changeset.
5089
5090
5090 See :hg:`help dates` for a list of formats valid for -d/--date.
5091 See :hg:`help dates` for a list of formats valid for -d/--date.
5091
5092
5092 Since tag names have priority over branch names during revision
5093 Since tag names have priority over branch names during revision
5093 lookup, using an existing branch name as a tag name is discouraged.
5094 lookup, using an existing branch name as a tag name is discouraged.
5094
5095
5095 Returns 0 on success.
5096 Returns 0 on success.
5096 """
5097 """
5097 wlock = lock = None
5098 wlock = lock = None
5098 try:
5099 try:
5099 wlock = repo.wlock()
5100 wlock = repo.wlock()
5100 lock = repo.lock()
5101 lock = repo.lock()
5101 rev_ = "."
5102 rev_ = "."
5102 names = [t.strip() for t in (name1,) + names]
5103 names = [t.strip() for t in (name1,) + names]
5103 if len(names) != len(set(names)):
5104 if len(names) != len(set(names)):
5104 raise error.Abort(_('tag names must be unique'))
5105 raise error.Abort(_('tag names must be unique'))
5105 for n in names:
5106 for n in names:
5106 scmutil.checknewlabel(repo, n, 'tag')
5107 scmutil.checknewlabel(repo, n, 'tag')
5107 if not n:
5108 if not n:
5108 raise error.Abort(_('tag names cannot consist entirely of '
5109 raise error.Abort(_('tag names cannot consist entirely of '
5109 'whitespace'))
5110 'whitespace'))
5110 if opts.get('rev') and opts.get('remove'):
5111 if opts.get('rev') and opts.get('remove'):
5111 raise error.Abort(_("--rev and --remove are incompatible"))
5112 raise error.Abort(_("--rev and --remove are incompatible"))
5112 if opts.get('rev'):
5113 if opts.get('rev'):
5113 rev_ = opts['rev']
5114 rev_ = opts['rev']
5114 message = opts.get('message')
5115 message = opts.get('message')
5115 if opts.get('remove'):
5116 if opts.get('remove'):
5116 if opts.get('local'):
5117 if opts.get('local'):
5117 expectedtype = 'local'
5118 expectedtype = 'local'
5118 else:
5119 else:
5119 expectedtype = 'global'
5120 expectedtype = 'global'
5120
5121
5121 for n in names:
5122 for n in names:
5122 if not repo.tagtype(n):
5123 if not repo.tagtype(n):
5123 raise error.Abort(_("tag '%s' does not exist") % n)
5124 raise error.Abort(_("tag '%s' does not exist") % n)
5124 if repo.tagtype(n) != expectedtype:
5125 if repo.tagtype(n) != expectedtype:
5125 if expectedtype == 'global':
5126 if expectedtype == 'global':
5126 raise error.Abort(_("tag '%s' is not a global tag") % n)
5127 raise error.Abort(_("tag '%s' is not a global tag") % n)
5127 else:
5128 else:
5128 raise error.Abort(_("tag '%s' is not a local tag") % n)
5129 raise error.Abort(_("tag '%s' is not a local tag") % n)
5129 rev_ = 'null'
5130 rev_ = 'null'
5130 if not message:
5131 if not message:
5131 # we don't translate commit messages
5132 # we don't translate commit messages
5132 message = 'Removed tag %s' % ', '.join(names)
5133 message = 'Removed tag %s' % ', '.join(names)
5133 elif not opts.get('force'):
5134 elif not opts.get('force'):
5134 for n in names:
5135 for n in names:
5135 if n in repo.tags():
5136 if n in repo.tags():
5136 raise error.Abort(_("tag '%s' already exists "
5137 raise error.Abort(_("tag '%s' already exists "
5137 "(use -f to force)") % n)
5138 "(use -f to force)") % n)
5138 if not opts.get('local'):
5139 if not opts.get('local'):
5139 p1, p2 = repo.dirstate.parents()
5140 p1, p2 = repo.dirstate.parents()
5140 if p2 != nullid:
5141 if p2 != nullid:
5141 raise error.Abort(_('uncommitted merge'))
5142 raise error.Abort(_('uncommitted merge'))
5142 bheads = repo.branchheads()
5143 bheads = repo.branchheads()
5143 if not opts.get('force') and bheads and p1 not in bheads:
5144 if not opts.get('force') and bheads and p1 not in bheads:
5144 raise error.Abort(_('working directory is not at a branch head '
5145 raise error.Abort(_('working directory is not at a branch head '
5145 '(use -f to force)'))
5146 '(use -f to force)'))
5146 r = scmutil.revsingle(repo, rev_).node()
5147 r = scmutil.revsingle(repo, rev_).node()
5147
5148
5148 if not message:
5149 if not message:
5149 # we don't translate commit messages
5150 # we don't translate commit messages
5150 message = ('Added tag %s for changeset %s' %
5151 message = ('Added tag %s for changeset %s' %
5151 (', '.join(names), short(r)))
5152 (', '.join(names), short(r)))
5152
5153
5153 date = opts.get('date')
5154 date = opts.get('date')
5154 if date:
5155 if date:
5155 date = util.parsedate(date)
5156 date = util.parsedate(date)
5156
5157
5157 if opts.get('remove'):
5158 if opts.get('remove'):
5158 editform = 'tag.remove'
5159 editform = 'tag.remove'
5159 else:
5160 else:
5160 editform = 'tag.add'
5161 editform = 'tag.add'
5161 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5162 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5162
5163
5163 # don't allow tagging the null rev
5164 # don't allow tagging the null rev
5164 if (not opts.get('remove') and
5165 if (not opts.get('remove') and
5165 scmutil.revsingle(repo, rev_).rev() == nullrev):
5166 scmutil.revsingle(repo, rev_).rev() == nullrev):
5166 raise error.Abort(_("cannot tag null revision"))
5167 raise error.Abort(_("cannot tag null revision"))
5167
5168
5168 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5169 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5169 editor=editor)
5170 editor=editor)
5170 finally:
5171 finally:
5171 release(lock, wlock)
5172 release(lock, wlock)
5172
5173
5173 @command('tags', formatteropts, '')
5174 @command('tags', formatteropts, '')
5174 def tags(ui, repo, **opts):
5175 def tags(ui, repo, **opts):
5175 """list repository tags
5176 """list repository tags
5176
5177
5177 This lists both regular and local tags. When the -v/--verbose
5178 This lists both regular and local tags. When the -v/--verbose
5178 switch is used, a third column "local" is printed for local tags.
5179 switch is used, a third column "local" is printed for local tags.
5179 When the -q/--quiet switch is used, only the tag name is printed.
5180 When the -q/--quiet switch is used, only the tag name is printed.
5180
5181
5181 Returns 0 on success.
5182 Returns 0 on success.
5182 """
5183 """
5183
5184
5184 ui.pager('tags')
5185 ui.pager('tags')
5185 fm = ui.formatter('tags', opts)
5186 fm = ui.formatter('tags', opts)
5186 hexfunc = fm.hexfunc
5187 hexfunc = fm.hexfunc
5187 tagtype = ""
5188 tagtype = ""
5188
5189
5189 for t, n in reversed(repo.tagslist()):
5190 for t, n in reversed(repo.tagslist()):
5190 hn = hexfunc(n)
5191 hn = hexfunc(n)
5191 label = 'tags.normal'
5192 label = 'tags.normal'
5192 tagtype = ''
5193 tagtype = ''
5193 if repo.tagtype(t) == 'local':
5194 if repo.tagtype(t) == 'local':
5194 label = 'tags.local'
5195 label = 'tags.local'
5195 tagtype = 'local'
5196 tagtype = 'local'
5196
5197
5197 fm.startitem()
5198 fm.startitem()
5198 fm.write('tag', '%s', t, label=label)
5199 fm.write('tag', '%s', t, label=label)
5199 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5200 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5200 fm.condwrite(not ui.quiet, 'rev node', fmt,
5201 fm.condwrite(not ui.quiet, 'rev node', fmt,
5201 repo.changelog.rev(n), hn, label=label)
5202 repo.changelog.rev(n), hn, label=label)
5202 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5203 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5203 tagtype, label=label)
5204 tagtype, label=label)
5204 fm.plain('\n')
5205 fm.plain('\n')
5205 fm.end()
5206 fm.end()
5206
5207
5207 @command('tip',
5208 @command('tip',
5208 [('p', 'patch', None, _('show patch')),
5209 [('p', 'patch', None, _('show patch')),
5209 ('g', 'git', None, _('use git extended diff format')),
5210 ('g', 'git', None, _('use git extended diff format')),
5210 ] + templateopts,
5211 ] + templateopts,
5211 _('[-p] [-g]'))
5212 _('[-p] [-g]'))
5212 def tip(ui, repo, **opts):
5213 def tip(ui, repo, **opts):
5213 """show the tip revision (DEPRECATED)
5214 """show the tip revision (DEPRECATED)
5214
5215
5215 The tip revision (usually just called the tip) is the changeset
5216 The tip revision (usually just called the tip) is the changeset
5216 most recently added to the repository (and therefore the most
5217 most recently added to the repository (and therefore the most
5217 recently changed head).
5218 recently changed head).
5218
5219
5219 If you have just made a commit, that commit will be the tip. If
5220 If you have just made a commit, that commit will be the tip. If
5220 you have just pulled changes from another repository, the tip of
5221 you have just pulled changes from another repository, the tip of
5221 that repository becomes the current tip. The "tip" tag is special
5222 that repository becomes the current tip. The "tip" tag is special
5222 and cannot be renamed or assigned to a different changeset.
5223 and cannot be renamed or assigned to a different changeset.
5223
5224
5224 This command is deprecated, please use :hg:`heads` instead.
5225 This command is deprecated, please use :hg:`heads` instead.
5225
5226
5226 Returns 0 on success.
5227 Returns 0 on success.
5227 """
5228 """
5228 displayer = cmdutil.show_changeset(ui, repo, opts)
5229 displayer = cmdutil.show_changeset(ui, repo, opts)
5229 displayer.show(repo['tip'])
5230 displayer.show(repo['tip'])
5230 displayer.close()
5231 displayer.close()
5231
5232
5232 @command('unbundle',
5233 @command('unbundle',
5233 [('u', 'update', None,
5234 [('u', 'update', None,
5234 _('update to new branch head if changesets were unbundled'))],
5235 _('update to new branch head if changesets were unbundled'))],
5235 _('[-u] FILE...'))
5236 _('[-u] FILE...'))
5236 def unbundle(ui, repo, fname1, *fnames, **opts):
5237 def unbundle(ui, repo, fname1, *fnames, **opts):
5237 """apply one or more changegroup files
5238 """apply one or more changegroup files
5238
5239
5239 Apply one or more compressed changegroup files generated by the
5240 Apply one or more compressed changegroup files generated by the
5240 bundle command.
5241 bundle command.
5241
5242
5242 Returns 0 on success, 1 if an update has unresolved files.
5243 Returns 0 on success, 1 if an update has unresolved files.
5243 """
5244 """
5244 fnames = (fname1,) + fnames
5245 fnames = (fname1,) + fnames
5245
5246
5246 with repo.lock():
5247 with repo.lock():
5247 for fname in fnames:
5248 for fname in fnames:
5248 f = hg.openpath(ui, fname)
5249 f = hg.openpath(ui, fname)
5249 gen = exchange.readbundle(ui, f, fname)
5250 gen = exchange.readbundle(ui, f, fname)
5250 if isinstance(gen, bundle2.unbundle20):
5251 if isinstance(gen, bundle2.unbundle20):
5251 tr = repo.transaction('unbundle')
5252 tr = repo.transaction('unbundle')
5252 try:
5253 try:
5253 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5254 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5254 url='bundle:' + fname)
5255 url='bundle:' + fname)
5255 tr.close()
5256 tr.close()
5256 except error.BundleUnknownFeatureError as exc:
5257 except error.BundleUnknownFeatureError as exc:
5257 raise error.Abort(_('%s: unknown bundle feature, %s')
5258 raise error.Abort(_('%s: unknown bundle feature, %s')
5258 % (fname, exc),
5259 % (fname, exc),
5259 hint=_("see https://mercurial-scm.org/"
5260 hint=_("see https://mercurial-scm.org/"
5260 "wiki/BundleFeature for more "
5261 "wiki/BundleFeature for more "
5261 "information"))
5262 "information"))
5262 finally:
5263 finally:
5263 if tr:
5264 if tr:
5264 tr.release()
5265 tr.release()
5265 changes = [r.get('return', 0)
5266 changes = [r.get('return', 0)
5266 for r in op.records['changegroup']]
5267 for r in op.records['changegroup']]
5267 modheads = changegroup.combineresults(changes)
5268 modheads = changegroup.combineresults(changes)
5268 elif isinstance(gen, streamclone.streamcloneapplier):
5269 elif isinstance(gen, streamclone.streamcloneapplier):
5269 raise error.Abort(
5270 raise error.Abort(
5270 _('packed bundles cannot be applied with '
5271 _('packed bundles cannot be applied with '
5271 '"hg unbundle"'),
5272 '"hg unbundle"'),
5272 hint=_('use "hg debugapplystreamclonebundle"'))
5273 hint=_('use "hg debugapplystreamclonebundle"'))
5273 else:
5274 else:
5274 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5275 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5275
5276
5276 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5277 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5277
5278
5278 @command('^update|up|checkout|co',
5279 @command('^update|up|checkout|co',
5279 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5280 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5280 ('c', 'check', None, _('require clean working directory')),
5281 ('c', 'check', None, _('require clean working directory')),
5281 ('m', 'merge', None, _('merge uncommitted changes')),
5282 ('m', 'merge', None, _('merge uncommitted changes')),
5282 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5283 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5283 ('r', 'rev', '', _('revision'), _('REV'))
5284 ('r', 'rev', '', _('revision'), _('REV'))
5284 ] + mergetoolopts,
5285 ] + mergetoolopts,
5285 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5286 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5286 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5287 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5287 merge=None, tool=None):
5288 merge=None, tool=None):
5288 """update working directory (or switch revisions)
5289 """update working directory (or switch revisions)
5289
5290
5290 Update the repository's working directory to the specified
5291 Update the repository's working directory to the specified
5291 changeset. If no changeset is specified, update to the tip of the
5292 changeset. If no changeset is specified, update to the tip of the
5292 current named branch and move the active bookmark (see :hg:`help
5293 current named branch and move the active bookmark (see :hg:`help
5293 bookmarks`).
5294 bookmarks`).
5294
5295
5295 Update sets the working directory's parent revision to the specified
5296 Update sets the working directory's parent revision to the specified
5296 changeset (see :hg:`help parents`).
5297 changeset (see :hg:`help parents`).
5297
5298
5298 If the changeset is not a descendant or ancestor of the working
5299 If the changeset is not a descendant or ancestor of the working
5299 directory's parent and there are uncommitted changes, the update is
5300 directory's parent and there are uncommitted changes, the update is
5300 aborted. With the -c/--check option, the working directory is checked
5301 aborted. With the -c/--check option, the working directory is checked
5301 for uncommitted changes; if none are found, the working directory is
5302 for uncommitted changes; if none are found, the working directory is
5302 updated to the specified changeset.
5303 updated to the specified changeset.
5303
5304
5304 .. container:: verbose
5305 .. container:: verbose
5305
5306
5306 The -C/--clean, -c/--check, and -m/--merge options control what
5307 The -C/--clean, -c/--check, and -m/--merge options control what
5307 happens if the working directory contains uncommitted changes.
5308 happens if the working directory contains uncommitted changes.
5308 At most of one of them can be specified.
5309 At most of one of them can be specified.
5309
5310
5310 1. If no option is specified, and if
5311 1. If no option is specified, and if
5311 the requested changeset is an ancestor or descendant of
5312 the requested changeset is an ancestor or descendant of
5312 the working directory's parent, the uncommitted changes
5313 the working directory's parent, the uncommitted changes
5313 are merged into the requested changeset and the merged
5314 are merged into the requested changeset and the merged
5314 result is left uncommitted. If the requested changeset is
5315 result is left uncommitted. If the requested changeset is
5315 not an ancestor or descendant (that is, it is on another
5316 not an ancestor or descendant (that is, it is on another
5316 branch), the update is aborted and the uncommitted changes
5317 branch), the update is aborted and the uncommitted changes
5317 are preserved.
5318 are preserved.
5318
5319
5319 2. With the -m/--merge option, the update is allowed even if the
5320 2. With the -m/--merge option, the update is allowed even if the
5320 requested changeset is not an ancestor or descendant of
5321 requested changeset is not an ancestor or descendant of
5321 the working directory's parent.
5322 the working directory's parent.
5322
5323
5323 3. With the -c/--check option, the update is aborted and the
5324 3. With the -c/--check option, the update is aborted and the
5324 uncommitted changes are preserved.
5325 uncommitted changes are preserved.
5325
5326
5326 4. With the -C/--clean option, uncommitted changes are discarded and
5327 4. With the -C/--clean option, uncommitted changes are discarded and
5327 the working directory is updated to the requested changeset.
5328 the working directory is updated to the requested changeset.
5328
5329
5329 To cancel an uncommitted merge (and lose your changes), use
5330 To cancel an uncommitted merge (and lose your changes), use
5330 :hg:`update --clean .`.
5331 :hg:`update --clean .`.
5331
5332
5332 Use null as the changeset to remove the working directory (like
5333 Use null as the changeset to remove the working directory (like
5333 :hg:`clone -U`).
5334 :hg:`clone -U`).
5334
5335
5335 If you want to revert just one file to an older revision, use
5336 If you want to revert just one file to an older revision, use
5336 :hg:`revert [-r REV] NAME`.
5337 :hg:`revert [-r REV] NAME`.
5337
5338
5338 See :hg:`help dates` for a list of formats valid for -d/--date.
5339 See :hg:`help dates` for a list of formats valid for -d/--date.
5339
5340
5340 Returns 0 on success, 1 if there are unresolved files.
5341 Returns 0 on success, 1 if there are unresolved files.
5341 """
5342 """
5342 if rev and node:
5343 if rev and node:
5343 raise error.Abort(_("please specify just one revision"))
5344 raise error.Abort(_("please specify just one revision"))
5344
5345
5345 if rev is None or rev == '':
5346 if rev is None or rev == '':
5346 rev = node
5347 rev = node
5347
5348
5348 if date and rev is not None:
5349 if date and rev is not None:
5349 raise error.Abort(_("you can't specify a revision and a date"))
5350 raise error.Abort(_("you can't specify a revision and a date"))
5350
5351
5351 if len([x for x in (clean, check, merge) if x]) > 1:
5352 if len([x for x in (clean, check, merge) if x]) > 1:
5352 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5353 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5353 "or -m/merge"))
5354 "or -m/merge"))
5354
5355
5355 updatecheck = None
5356 updatecheck = None
5356 if check:
5357 if check:
5357 updatecheck = 'abort'
5358 updatecheck = 'abort'
5358 elif merge:
5359 elif merge:
5359 updatecheck = 'none'
5360 updatecheck = 'none'
5360
5361
5361 with repo.wlock():
5362 with repo.wlock():
5362 cmdutil.clearunfinished(repo)
5363 cmdutil.clearunfinished(repo)
5363
5364
5364 if date:
5365 if date:
5365 rev = cmdutil.finddate(ui, repo, date)
5366 rev = cmdutil.finddate(ui, repo, date)
5366
5367
5367 # if we defined a bookmark, we have to remember the original name
5368 # if we defined a bookmark, we have to remember the original name
5368 brev = rev
5369 brev = rev
5369 rev = scmutil.revsingle(repo, rev, rev).rev()
5370 rev = scmutil.revsingle(repo, rev, rev).rev()
5370
5371
5371 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5372 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5372
5373
5373 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5374 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5374 updatecheck=updatecheck)
5375 updatecheck=updatecheck)
5375
5376
5376 @command('verify', [])
5377 @command('verify', [])
5377 def verify(ui, repo):
5378 def verify(ui, repo):
5378 """verify the integrity of the repository
5379 """verify the integrity of the repository
5379
5380
5380 Verify the integrity of the current repository.
5381 Verify the integrity of the current repository.
5381
5382
5382 This will perform an extensive check of the repository's
5383 This will perform an extensive check of the repository's
5383 integrity, validating the hashes and checksums of each entry in
5384 integrity, validating the hashes and checksums of each entry in
5384 the changelog, manifest, and tracked files, as well as the
5385 the changelog, manifest, and tracked files, as well as the
5385 integrity of their crosslinks and indices.
5386 integrity of their crosslinks and indices.
5386
5387
5387 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5388 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5388 for more information about recovery from corruption of the
5389 for more information about recovery from corruption of the
5389 repository.
5390 repository.
5390
5391
5391 Returns 0 on success, 1 if errors are encountered.
5392 Returns 0 on success, 1 if errors are encountered.
5392 """
5393 """
5393 return hg.verify(repo)
5394 return hg.verify(repo)
5394
5395
5395 @command('version', [] + formatteropts, norepo=True)
5396 @command('version', [] + formatteropts, norepo=True)
5396 def version_(ui, **opts):
5397 def version_(ui, **opts):
5397 """output version and copyright information"""
5398 """output version and copyright information"""
5398 if ui.verbose:
5399 if ui.verbose:
5399 ui.pager('version')
5400 ui.pager('version')
5400 fm = ui.formatter("version", opts)
5401 fm = ui.formatter("version", opts)
5401 fm.startitem()
5402 fm.startitem()
5402 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5403 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5403 util.version())
5404 util.version())
5404 license = _(
5405 license = _(
5405 "(see https://mercurial-scm.org for more information)\n"
5406 "(see https://mercurial-scm.org for more information)\n"
5406 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5407 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5407 "This is free software; see the source for copying conditions. "
5408 "This is free software; see the source for copying conditions. "
5408 "There is NO\nwarranty; "
5409 "There is NO\nwarranty; "
5409 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5410 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5410 )
5411 )
5411 if not ui.quiet:
5412 if not ui.quiet:
5412 fm.plain(license)
5413 fm.plain(license)
5413
5414
5414 if ui.verbose:
5415 if ui.verbose:
5415 fm.plain(_("\nEnabled extensions:\n\n"))
5416 fm.plain(_("\nEnabled extensions:\n\n"))
5416 # format names and versions into columns
5417 # format names and versions into columns
5417 names = []
5418 names = []
5418 vers = []
5419 vers = []
5419 isinternals = []
5420 isinternals = []
5420 for name, module in extensions.extensions():
5421 for name, module in extensions.extensions():
5421 names.append(name)
5422 names.append(name)
5422 vers.append(extensions.moduleversion(module) or None)
5423 vers.append(extensions.moduleversion(module) or None)
5423 isinternals.append(extensions.ismoduleinternal(module))
5424 isinternals.append(extensions.ismoduleinternal(module))
5424 fn = fm.nested("extensions")
5425 fn = fm.nested("extensions")
5425 if names:
5426 if names:
5426 namefmt = " %%-%ds " % max(len(n) for n in names)
5427 namefmt = " %%-%ds " % max(len(n) for n in names)
5427 places = [_("external"), _("internal")]
5428 places = [_("external"), _("internal")]
5428 for n, v, p in zip(names, vers, isinternals):
5429 for n, v, p in zip(names, vers, isinternals):
5429 fn.startitem()
5430 fn.startitem()
5430 fn.condwrite(ui.verbose, "name", namefmt, n)
5431 fn.condwrite(ui.verbose, "name", namefmt, n)
5431 if ui.verbose:
5432 if ui.verbose:
5432 fn.plain("%s " % places[p])
5433 fn.plain("%s " % places[p])
5433 fn.data(bundled=p)
5434 fn.data(bundled=p)
5434 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5435 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5435 if ui.verbose:
5436 if ui.verbose:
5436 fn.plain("\n")
5437 fn.plain("\n")
5437 fn.end()
5438 fn.end()
5438 fm.end()
5439 fm.end()
5439
5440
5440 def loadcmdtable(ui, name, cmdtable):
5441 def loadcmdtable(ui, name, cmdtable):
5441 """Load command functions from specified cmdtable
5442 """Load command functions from specified cmdtable
5442 """
5443 """
5443 overrides = [cmd for cmd in cmdtable if cmd in table]
5444 overrides = [cmd for cmd in cmdtable if cmd in table]
5444 if overrides:
5445 if overrides:
5445 ui.warn(_("extension '%s' overrides commands: %s\n")
5446 ui.warn(_("extension '%s' overrides commands: %s\n")
5446 % (name, " ".join(overrides)))
5447 % (name, " ".join(overrides)))
5447 table.update(cmdtable)
5448 table.update(cmdtable)
@@ -1,716 +1,722 b''
1 $ hg init a
1 $ hg init a
2 $ cd a
2 $ cd a
3 $ echo 'root' >root
3 $ echo 'root' >root
4 $ hg add root
4 $ hg add root
5 $ hg commit -d '0 0' -m "Adding root node"
5 $ hg commit -d '0 0' -m "Adding root node"
6
6
7 $ echo 'a' >a
7 $ echo 'a' >a
8 $ hg add a
8 $ hg add a
9 $ hg branch a
9 $ hg branch a
10 marked working directory as branch a
10 marked working directory as branch a
11 (branches are permanent and global, did you want a bookmark?)
11 (branches are permanent and global, did you want a bookmark?)
12 $ hg commit -d '1 0' -m "Adding a branch"
12 $ hg commit -d '1 0' -m "Adding a branch"
13
13
14 $ hg branch q
14 $ hg branch q
15 marked working directory as branch q
15 marked working directory as branch q
16 $ echo 'aa' >a
16 $ echo 'aa' >a
17 $ hg branch -C
17 $ hg branch -C
18 reset working directory to branch a
18 reset working directory to branch a
19 $ hg commit -d '2 0' -m "Adding to a branch"
19 $ hg commit -d '2 0' -m "Adding to a branch"
20
20
21 $ hg update -C 0
21 $ hg update -C 0
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
22 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
23 $ echo 'b' >b
23 $ echo 'b' >b
24 $ hg add b
24 $ hg add b
25 $ hg branch b
25 $ hg branch b
26 marked working directory as branch b
26 marked working directory as branch b
27 $ hg commit -d '2 0' -m "Adding b branch"
27 $ hg commit -d '2 0' -m "Adding b branch"
28
28
29 $ echo 'bh1' >bh1
29 $ echo 'bh1' >bh1
30 $ hg add bh1
30 $ hg add bh1
31 $ hg commit -d '3 0' -m "Adding b branch head 1"
31 $ hg commit -d '3 0' -m "Adding b branch head 1"
32
32
33 $ hg update -C 2
33 $ hg update -C 2
34 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
34 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 $ echo 'bh2' >bh2
35 $ echo 'bh2' >bh2
36 $ hg add bh2
36 $ hg add bh2
37 $ hg commit -d '4 0' -m "Adding b branch head 2"
37 $ hg commit -d '4 0' -m "Adding b branch head 2"
38
38
39 $ echo 'c' >c
39 $ echo 'c' >c
40 $ hg add c
40 $ hg add c
41 $ hg branch c
41 $ hg branch c
42 marked working directory as branch c
42 marked working directory as branch c
43 $ hg commit -d '5 0' -m "Adding c branch"
43 $ hg commit -d '5 0' -m "Adding c branch"
44
44
45 reserved names
45 reserved names
46
46
47 $ hg branch tip
47 $ hg branch tip
48 abort: the name 'tip' is reserved
48 abort: the name 'tip' is reserved
49 [255]
49 [255]
50 $ hg branch null
50 $ hg branch null
51 abort: the name 'null' is reserved
51 abort: the name 'null' is reserved
52 [255]
52 [255]
53 $ hg branch .
53 $ hg branch .
54 abort: the name '.' is reserved
54 abort: the name '.' is reserved
55 [255]
55 [255]
56
56
57 invalid characters
57 invalid characters
58
58
59 $ hg branch 'foo:bar'
59 $ hg branch 'foo:bar'
60 abort: ':' cannot be used in a name
60 abort: ':' cannot be used in a name
61 [255]
61 [255]
62
62
63 $ hg branch 'foo
63 $ hg branch 'foo
64 > bar'
64 > bar'
65 abort: '\n' cannot be used in a name
65 abort: '\n' cannot be used in a name
66 [255]
66 [255]
67
67
68 trailing or leading spaces should be stripped before testing duplicates
68 trailing or leading spaces should be stripped before testing duplicates
69
69
70 $ hg branch 'b '
70 $ hg branch 'b '
71 abort: a branch of the same name already exists
71 abort: a branch of the same name already exists
72 (use 'hg update' to switch to it)
72 (use 'hg update' to switch to it)
73 [255]
73 [255]
74
74
75 $ hg branch ' b'
75 $ hg branch ' b'
76 abort: a branch of the same name already exists
76 abort: a branch of the same name already exists
77 (use 'hg update' to switch to it)
77 (use 'hg update' to switch to it)
78 [255]
78 [255]
79
79
80 verify update will accept invalid legacy branch names
80 verify update will accept invalid legacy branch names
81
81
82 $ hg init test-invalid-branch-name
82 $ hg init test-invalid-branch-name
83 $ cd test-invalid-branch-name
83 $ cd test-invalid-branch-name
84 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
84 $ hg pull -u "$TESTDIR"/bundles/test-invalid-branch-name.hg
85 pulling from *test-invalid-branch-name.hg (glob)
85 pulling from *test-invalid-branch-name.hg (glob)
86 requesting all changes
86 requesting all changes
87 adding changesets
87 adding changesets
88 adding manifests
88 adding manifests
89 adding file changes
89 adding file changes
90 added 3 changesets with 3 changes to 2 files
90 added 3 changesets with 3 changes to 2 files
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
92
92
93 $ hg update '"colon:test"'
93 $ hg update '"colon:test"'
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 $ cd ..
95 $ cd ..
96
96
97 $ echo 'd' >d
97 $ echo 'd' >d
98 $ hg add d
98 $ hg add d
99 $ hg branch 'a branch name much longer than the default justification used by branches'
99 $ hg branch 'a branch name much longer than the default justification used by branches'
100 marked working directory as branch a branch name much longer than the default justification used by branches
100 marked working directory as branch a branch name much longer than the default justification used by branches
101 $ hg commit -d '6 0' -m "Adding d branch"
101 $ hg commit -d '6 0' -m "Adding d branch"
102
102
103 $ hg branches
103 $ hg branches
104 a branch name much longer than the default justification used by branches 7:10ff5895aa57
104 a branch name much longer than the default justification used by branches 7:10ff5895aa57
105 b 4:aee39cd168d0
105 b 4:aee39cd168d0
106 c 6:589736a22561 (inactive)
106 c 6:589736a22561 (inactive)
107 a 5:d8cbc61dbaa6 (inactive)
107 a 5:d8cbc61dbaa6 (inactive)
108 default 0:19709c5a4e75 (inactive)
108 default 0:19709c5a4e75 (inactive)
109
109
110 -------
110 -------
111
111
112 $ hg branches -a
112 $ hg branches -a
113 a branch name much longer than the default justification used by branches 7:10ff5895aa57
113 a branch name much longer than the default justification used by branches 7:10ff5895aa57
114 b 4:aee39cd168d0
114 b 4:aee39cd168d0
115
115
116 --- Branch a
116 --- Branch a
117
117
118 $ hg log -b a
118 $ hg log -b a
119 changeset: 5:d8cbc61dbaa6
119 changeset: 5:d8cbc61dbaa6
120 branch: a
120 branch: a
121 parent: 2:881fe2b92ad0
121 parent: 2:881fe2b92ad0
122 user: test
122 user: test
123 date: Thu Jan 01 00:00:04 1970 +0000
123 date: Thu Jan 01 00:00:04 1970 +0000
124 summary: Adding b branch head 2
124 summary: Adding b branch head 2
125
125
126 changeset: 2:881fe2b92ad0
126 changeset: 2:881fe2b92ad0
127 branch: a
127 branch: a
128 user: test
128 user: test
129 date: Thu Jan 01 00:00:02 1970 +0000
129 date: Thu Jan 01 00:00:02 1970 +0000
130 summary: Adding to a branch
130 summary: Adding to a branch
131
131
132 changeset: 1:dd6b440dd85a
132 changeset: 1:dd6b440dd85a
133 branch: a
133 branch: a
134 user: test
134 user: test
135 date: Thu Jan 01 00:00:01 1970 +0000
135 date: Thu Jan 01 00:00:01 1970 +0000
136 summary: Adding a branch
136 summary: Adding a branch
137
137
138
138
139 ---- Branch b
139 ---- Branch b
140
140
141 $ hg log -b b
141 $ hg log -b b
142 changeset: 4:aee39cd168d0
142 changeset: 4:aee39cd168d0
143 branch: b
143 branch: b
144 user: test
144 user: test
145 date: Thu Jan 01 00:00:03 1970 +0000
145 date: Thu Jan 01 00:00:03 1970 +0000
146 summary: Adding b branch head 1
146 summary: Adding b branch head 1
147
147
148 changeset: 3:ac22033332d1
148 changeset: 3:ac22033332d1
149 branch: b
149 branch: b
150 parent: 0:19709c5a4e75
150 parent: 0:19709c5a4e75
151 user: test
151 user: test
152 date: Thu Jan 01 00:00:02 1970 +0000
152 date: Thu Jan 01 00:00:02 1970 +0000
153 summary: Adding b branch
153 summary: Adding b branch
154
154
155
155
156 ---- going to test branch closing
156 ---- going to test branch closing
157
157
158 $ hg branches
158 $ hg branches
159 a branch name much longer than the default justification used by branches 7:10ff5895aa57
159 a branch name much longer than the default justification used by branches 7:10ff5895aa57
160 b 4:aee39cd168d0
160 b 4:aee39cd168d0
161 c 6:589736a22561 (inactive)
161 c 6:589736a22561 (inactive)
162 a 5:d8cbc61dbaa6 (inactive)
162 a 5:d8cbc61dbaa6 (inactive)
163 default 0:19709c5a4e75 (inactive)
163 default 0:19709c5a4e75 (inactive)
164 $ hg up -C b
164 $ hg up -C b
165 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
165 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
166 $ echo 'xxx1' >> b
166 $ echo 'xxx1' >> b
167 $ hg commit -d '7 0' -m 'adding cset to branch b'
167 $ hg commit -d '7 0' -m 'adding cset to branch b'
168 $ hg up -C aee39cd168d0
168 $ hg up -C aee39cd168d0
169 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 $ echo 'xxx2' >> b
170 $ echo 'xxx2' >> b
171 $ hg commit -d '8 0' -m 'adding head to branch b'
171 $ hg commit -d '8 0' -m 'adding head to branch b'
172 created new head
172 created new head
173 $ echo 'xxx3' >> b
173 $ echo 'xxx3' >> b
174 $ hg commit -d '9 0' -m 'adding another cset to branch b'
174 $ hg commit -d '9 0' -m 'adding another cset to branch b'
175 $ hg branches
175 $ hg branches
176 b 10:bfbe841b666e
176 b 10:bfbe841b666e
177 a branch name much longer than the default justification used by branches 7:10ff5895aa57
177 a branch name much longer than the default justification used by branches 7:10ff5895aa57
178 c 6:589736a22561 (inactive)
178 c 6:589736a22561 (inactive)
179 a 5:d8cbc61dbaa6 (inactive)
179 a 5:d8cbc61dbaa6 (inactive)
180 default 0:19709c5a4e75 (inactive)
180 default 0:19709c5a4e75 (inactive)
181 $ hg heads --closed
181 $ hg heads --closed
182 changeset: 10:bfbe841b666e
182 changeset: 10:bfbe841b666e
183 branch: b
183 branch: b
184 tag: tip
184 tag: tip
185 user: test
185 user: test
186 date: Thu Jan 01 00:00:09 1970 +0000
186 date: Thu Jan 01 00:00:09 1970 +0000
187 summary: adding another cset to branch b
187 summary: adding another cset to branch b
188
188
189 changeset: 8:eebb944467c9
189 changeset: 8:eebb944467c9
190 branch: b
190 branch: b
191 parent: 4:aee39cd168d0
191 parent: 4:aee39cd168d0
192 user: test
192 user: test
193 date: Thu Jan 01 00:00:07 1970 +0000
193 date: Thu Jan 01 00:00:07 1970 +0000
194 summary: adding cset to branch b
194 summary: adding cset to branch b
195
195
196 changeset: 7:10ff5895aa57
196 changeset: 7:10ff5895aa57
197 branch: a branch name much longer than the default justification used by branches
197 branch: a branch name much longer than the default justification used by branches
198 user: test
198 user: test
199 date: Thu Jan 01 00:00:06 1970 +0000
199 date: Thu Jan 01 00:00:06 1970 +0000
200 summary: Adding d branch
200 summary: Adding d branch
201
201
202 changeset: 6:589736a22561
202 changeset: 6:589736a22561
203 branch: c
203 branch: c
204 user: test
204 user: test
205 date: Thu Jan 01 00:00:05 1970 +0000
205 date: Thu Jan 01 00:00:05 1970 +0000
206 summary: Adding c branch
206 summary: Adding c branch
207
207
208 changeset: 5:d8cbc61dbaa6
208 changeset: 5:d8cbc61dbaa6
209 branch: a
209 branch: a
210 parent: 2:881fe2b92ad0
210 parent: 2:881fe2b92ad0
211 user: test
211 user: test
212 date: Thu Jan 01 00:00:04 1970 +0000
212 date: Thu Jan 01 00:00:04 1970 +0000
213 summary: Adding b branch head 2
213 summary: Adding b branch head 2
214
214
215 changeset: 0:19709c5a4e75
215 changeset: 0:19709c5a4e75
216 user: test
216 user: test
217 date: Thu Jan 01 00:00:00 1970 +0000
217 date: Thu Jan 01 00:00:00 1970 +0000
218 summary: Adding root node
218 summary: Adding root node
219
219
220 $ hg heads
220 $ hg heads
221 changeset: 10:bfbe841b666e
221 changeset: 10:bfbe841b666e
222 branch: b
222 branch: b
223 tag: tip
223 tag: tip
224 user: test
224 user: test
225 date: Thu Jan 01 00:00:09 1970 +0000
225 date: Thu Jan 01 00:00:09 1970 +0000
226 summary: adding another cset to branch b
226 summary: adding another cset to branch b
227
227
228 changeset: 8:eebb944467c9
228 changeset: 8:eebb944467c9
229 branch: b
229 branch: b
230 parent: 4:aee39cd168d0
230 parent: 4:aee39cd168d0
231 user: test
231 user: test
232 date: Thu Jan 01 00:00:07 1970 +0000
232 date: Thu Jan 01 00:00:07 1970 +0000
233 summary: adding cset to branch b
233 summary: adding cset to branch b
234
234
235 changeset: 7:10ff5895aa57
235 changeset: 7:10ff5895aa57
236 branch: a branch name much longer than the default justification used by branches
236 branch: a branch name much longer than the default justification used by branches
237 user: test
237 user: test
238 date: Thu Jan 01 00:00:06 1970 +0000
238 date: Thu Jan 01 00:00:06 1970 +0000
239 summary: Adding d branch
239 summary: Adding d branch
240
240
241 changeset: 6:589736a22561
241 changeset: 6:589736a22561
242 branch: c
242 branch: c
243 user: test
243 user: test
244 date: Thu Jan 01 00:00:05 1970 +0000
244 date: Thu Jan 01 00:00:05 1970 +0000
245 summary: Adding c branch
245 summary: Adding c branch
246
246
247 changeset: 5:d8cbc61dbaa6
247 changeset: 5:d8cbc61dbaa6
248 branch: a
248 branch: a
249 parent: 2:881fe2b92ad0
249 parent: 2:881fe2b92ad0
250 user: test
250 user: test
251 date: Thu Jan 01 00:00:04 1970 +0000
251 date: Thu Jan 01 00:00:04 1970 +0000
252 summary: Adding b branch head 2
252 summary: Adding b branch head 2
253
253
254 changeset: 0:19709c5a4e75
254 changeset: 0:19709c5a4e75
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
256 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: Adding root node
257 summary: Adding root node
258
258
259 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
259 $ hg commit -d '9 0' --close-branch -m 'prune bad branch'
260 $ hg branches -a
260 $ hg branches -a
261 b 8:eebb944467c9
261 b 8:eebb944467c9
262 a branch name much longer than the default justification used by branches 7:10ff5895aa57
262 a branch name much longer than the default justification used by branches 7:10ff5895aa57
263 $ hg up -C b
263 $ hg up -C b
264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
265 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
265 $ hg commit -d '9 0' --close-branch -m 'close this part branch too'
266 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
266 $ hg commit -d '9 0' --close-branch -m 're-closing this branch'
267 abort: can only close branch heads
267 abort: can only close branch heads
268 [255]
268 [255]
269
269
270 $ hg log -r tip --debug
270 $ hg log -r tip --debug
271 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
271 changeset: 12:e3d49c0575d8fc2cb1cd6859c747c14f5f6d499f
272 branch: b
272 branch: b
273 tag: tip
273 tag: tip
274 phase: draft
274 phase: draft
275 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
275 parent: 8:eebb944467c9fb9651ed232aeaf31b3c0a7fc6c1
276 parent: -1:0000000000000000000000000000000000000000
276 parent: -1:0000000000000000000000000000000000000000
277 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
277 manifest: 8:6f9ed32d2b310e391a4f107d5f0f071df785bfee
278 user: test
278 user: test
279 date: Thu Jan 01 00:00:09 1970 +0000
279 date: Thu Jan 01 00:00:09 1970 +0000
280 extra: branch=b
280 extra: branch=b
281 extra: close=1
281 extra: close=1
282 description:
282 description:
283 close this part branch too
283 close this part branch too
284
284
285
285
286 --- b branch should be inactive
286 --- b branch should be inactive
287
287
288 $ hg branches
288 $ hg branches
289 a branch name much longer than the default justification used by branches 7:10ff5895aa57
289 a branch name much longer than the default justification used by branches 7:10ff5895aa57
290 c 6:589736a22561 (inactive)
290 c 6:589736a22561 (inactive)
291 a 5:d8cbc61dbaa6 (inactive)
291 a 5:d8cbc61dbaa6 (inactive)
292 default 0:19709c5a4e75 (inactive)
292 default 0:19709c5a4e75 (inactive)
293 $ hg branches -c
293 $ hg branches -c
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
294 a branch name much longer than the default justification used by branches 7:10ff5895aa57
295 b 12:e3d49c0575d8 (closed)
295 b 12:e3d49c0575d8 (closed)
296 c 6:589736a22561 (inactive)
296 c 6:589736a22561 (inactive)
297 a 5:d8cbc61dbaa6 (inactive)
297 a 5:d8cbc61dbaa6 (inactive)
298 default 0:19709c5a4e75 (inactive)
298 default 0:19709c5a4e75 (inactive)
299 $ hg branches -a
299 $ hg branches -a
300 a branch name much longer than the default justification used by branches 7:10ff5895aa57
300 a branch name much longer than the default justification used by branches 7:10ff5895aa57
301 $ hg branches -q
301 $ hg branches -q
302 a branch name much longer than the default justification used by branches
302 a branch name much longer than the default justification used by branches
303 c
303 c
304 a
304 a
305 default
305 default
306 $ hg heads b
306 $ hg heads b
307 no open branch heads found on branches b
307 no open branch heads found on branches b
308 [1]
308 [1]
309 $ hg heads --closed b
309 $ hg heads --closed b
310 changeset: 12:e3d49c0575d8
310 changeset: 12:e3d49c0575d8
311 branch: b
311 branch: b
312 tag: tip
312 tag: tip
313 parent: 8:eebb944467c9
313 parent: 8:eebb944467c9
314 user: test
314 user: test
315 date: Thu Jan 01 00:00:09 1970 +0000
315 date: Thu Jan 01 00:00:09 1970 +0000
316 summary: close this part branch too
316 summary: close this part branch too
317
317
318 changeset: 11:d3f163457ebf
318 changeset: 11:d3f163457ebf
319 branch: b
319 branch: b
320 user: test
320 user: test
321 date: Thu Jan 01 00:00:09 1970 +0000
321 date: Thu Jan 01 00:00:09 1970 +0000
322 summary: prune bad branch
322 summary: prune bad branch
323
323
324 $ echo 'xxx4' >> b
324 $ echo 'xxx4' >> b
325 $ hg commit -d '9 0' -m 'reopen branch with a change'
325 $ hg commit -d '9 0' -m 'reopen branch with a change'
326 reopening closed branch head 12
326 reopening closed branch head 12
327
327
328 --- branch b is back in action
328 --- branch b is back in action
329
329
330 $ hg branches -a
330 $ hg branches -a
331 b 13:e23b5505d1ad
331 b 13:e23b5505d1ad
332 a branch name much longer than the default justification used by branches 7:10ff5895aa57
332 a branch name much longer than the default justification used by branches 7:10ff5895aa57
333
333
334 ---- test heads listings
334 ---- test heads listings
335
335
336 $ hg heads
336 $ hg heads
337 changeset: 13:e23b5505d1ad
337 changeset: 13:e23b5505d1ad
338 branch: b
338 branch: b
339 tag: tip
339 tag: tip
340 user: test
340 user: test
341 date: Thu Jan 01 00:00:09 1970 +0000
341 date: Thu Jan 01 00:00:09 1970 +0000
342 summary: reopen branch with a change
342 summary: reopen branch with a change
343
343
344 changeset: 7:10ff5895aa57
344 changeset: 7:10ff5895aa57
345 branch: a branch name much longer than the default justification used by branches
345 branch: a branch name much longer than the default justification used by branches
346 user: test
346 user: test
347 date: Thu Jan 01 00:00:06 1970 +0000
347 date: Thu Jan 01 00:00:06 1970 +0000
348 summary: Adding d branch
348 summary: Adding d branch
349
349
350 changeset: 6:589736a22561
350 changeset: 6:589736a22561
351 branch: c
351 branch: c
352 user: test
352 user: test
353 date: Thu Jan 01 00:00:05 1970 +0000
353 date: Thu Jan 01 00:00:05 1970 +0000
354 summary: Adding c branch
354 summary: Adding c branch
355
355
356 changeset: 5:d8cbc61dbaa6
356 changeset: 5:d8cbc61dbaa6
357 branch: a
357 branch: a
358 parent: 2:881fe2b92ad0
358 parent: 2:881fe2b92ad0
359 user: test
359 user: test
360 date: Thu Jan 01 00:00:04 1970 +0000
360 date: Thu Jan 01 00:00:04 1970 +0000
361 summary: Adding b branch head 2
361 summary: Adding b branch head 2
362
362
363 changeset: 0:19709c5a4e75
363 changeset: 0:19709c5a4e75
364 user: test
364 user: test
365 date: Thu Jan 01 00:00:00 1970 +0000
365 date: Thu Jan 01 00:00:00 1970 +0000
366 summary: Adding root node
366 summary: Adding root node
367
367
368
368
369 branch default
369 branch default
370
370
371 $ hg heads default
371 $ hg heads default
372 changeset: 0:19709c5a4e75
372 changeset: 0:19709c5a4e75
373 user: test
373 user: test
374 date: Thu Jan 01 00:00:00 1970 +0000
374 date: Thu Jan 01 00:00:00 1970 +0000
375 summary: Adding root node
375 summary: Adding root node
376
376
377
377
378 branch a
378 branch a
379
379
380 $ hg heads a
380 $ hg heads a
381 changeset: 5:d8cbc61dbaa6
381 changeset: 5:d8cbc61dbaa6
382 branch: a
382 branch: a
383 parent: 2:881fe2b92ad0
383 parent: 2:881fe2b92ad0
384 user: test
384 user: test
385 date: Thu Jan 01 00:00:04 1970 +0000
385 date: Thu Jan 01 00:00:04 1970 +0000
386 summary: Adding b branch head 2
386 summary: Adding b branch head 2
387
387
388 $ hg heads --active a
388 $ hg heads --active a
389 no open branch heads found on branches a
389 no open branch heads found on branches a
390 [1]
390 [1]
391
391
392 branch b
392 branch b
393
393
394 $ hg heads b
394 $ hg heads b
395 changeset: 13:e23b5505d1ad
395 changeset: 13:e23b5505d1ad
396 branch: b
396 branch: b
397 tag: tip
397 tag: tip
398 user: test
398 user: test
399 date: Thu Jan 01 00:00:09 1970 +0000
399 date: Thu Jan 01 00:00:09 1970 +0000
400 summary: reopen branch with a change
400 summary: reopen branch with a change
401
401
402 $ hg heads --closed b
402 $ hg heads --closed b
403 changeset: 13:e23b5505d1ad
403 changeset: 13:e23b5505d1ad
404 branch: b
404 branch: b
405 tag: tip
405 tag: tip
406 user: test
406 user: test
407 date: Thu Jan 01 00:00:09 1970 +0000
407 date: Thu Jan 01 00:00:09 1970 +0000
408 summary: reopen branch with a change
408 summary: reopen branch with a change
409
409
410 changeset: 11:d3f163457ebf
410 changeset: 11:d3f163457ebf
411 branch: b
411 branch: b
412 user: test
412 user: test
413 date: Thu Jan 01 00:00:09 1970 +0000
413 date: Thu Jan 01 00:00:09 1970 +0000
414 summary: prune bad branch
414 summary: prune bad branch
415
415
416 default branch colors:
416 default branch colors:
417
417
418 $ cat <<EOF >> $HGRCPATH
418 $ cat <<EOF >> $HGRCPATH
419 > [extensions]
419 > [extensions]
420 > color =
420 > color =
421 > [color]
421 > [color]
422 > mode = ansi
422 > mode = ansi
423 > EOF
423 > EOF
424
424
425 $ hg up -C c
425 $ hg up -C c
426 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
426 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
427 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
427 $ hg commit -d '9 0' --close-branch -m 'reclosing this branch'
428 $ hg up -C b
428 $ hg up -C b
429 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
429 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
430 $ hg branches --color=always
430 $ hg branches --color=always
431 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
431 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
432 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
432 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
433 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
433 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
434 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
434 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
435
435
436 default closed branch color:
436 default closed branch color:
437
437
438 $ hg branches --color=always --closed
438 $ hg branches --color=always --closed
439 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
439 \x1b[0;32mb\x1b[0m\x1b[0;33m 13:e23b5505d1ad\x1b[0m (esc)
440 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
440 \x1b[0;0ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;33m 7:10ff5895aa57\x1b[0m (esc)
441 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
441 \x1b[0;30;1mc\x1b[0m\x1b[0;33m 14:f894c25619d3\x1b[0m (closed) (esc)
442 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
442 \x1b[0;0ma\x1b[0m\x1b[0;33m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
443 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
443 \x1b[0;0mdefault\x1b[0m\x1b[0;33m 0:19709c5a4e75\x1b[0m (inactive) (esc)
444
444
445 $ cat <<EOF >> $HGRCPATH
445 $ cat <<EOF >> $HGRCPATH
446 > [extensions]
446 > [extensions]
447 > color =
447 > color =
448 > [color]
448 > [color]
449 > branches.active = green
449 > branches.active = green
450 > branches.closed = blue
450 > branches.closed = blue
451 > branches.current = red
451 > branches.current = red
452 > branches.inactive = magenta
452 > branches.inactive = magenta
453 > log.changeset = cyan
453 > log.changeset = cyan
454 > EOF
454 > EOF
455
455
456 custom branch colors:
456 custom branch colors:
457
457
458 $ hg branches --color=always
458 $ hg branches --color=always
459 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
459 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
460 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
460 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
461 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
461 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
462 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
462 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
463
463
464 custom closed branch color:
464 custom closed branch color:
465
465
466 $ hg branches --color=always --closed
466 $ hg branches --color=always --closed
467 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
467 \x1b[0;31mb\x1b[0m\x1b[0;36m 13:e23b5505d1ad\x1b[0m (esc)
468 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
468 \x1b[0;32ma branch name much longer than the default justification used by branches\x1b[0m\x1b[0;36m 7:10ff5895aa57\x1b[0m (esc)
469 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
469 \x1b[0;34mc\x1b[0m\x1b[0;36m 14:f894c25619d3\x1b[0m (closed) (esc)
470 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
470 \x1b[0;35ma\x1b[0m\x1b[0;36m 5:d8cbc61dbaa6\x1b[0m (inactive) (esc)
471 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
471 \x1b[0;35mdefault\x1b[0m\x1b[0;36m 0:19709c5a4e75\x1b[0m (inactive) (esc)
472
472
473 template output:
473 template output:
474
474
475 $ hg branches -Tjson --closed
475 $ hg branches -Tjson --closed
476 [
476 [
477 {
477 {
478 "active": true,
478 "active": true,
479 "branch": "b",
479 "branch": "b",
480 "closed": false,
480 "closed": false,
481 "current": true,
481 "current": true,
482 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
482 "node": "e23b5505d1ad24aab6f84fd8c7cb8cd8e5e93be0",
483 "rev": 13
483 "rev": 13
484 },
484 },
485 {
485 {
486 "active": true,
486 "active": true,
487 "branch": "a branch name much longer than the default justification used by branches",
487 "branch": "a branch name much longer than the default justification used by branches",
488 "closed": false,
488 "closed": false,
489 "current": false,
489 "current": false,
490 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
490 "node": "10ff5895aa5793bd378da574af8cec8ea408d831",
491 "rev": 7
491 "rev": 7
492 },
492 },
493 {
493 {
494 "active": false,
494 "active": false,
495 "branch": "c",
495 "branch": "c",
496 "closed": true,
496 "closed": true,
497 "current": false,
497 "current": false,
498 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
498 "node": "f894c25619d3f1484639d81be950e0a07bc6f1f6",
499 "rev": 14
499 "rev": 14
500 },
500 },
501 {
501 {
502 "active": false,
502 "active": false,
503 "branch": "a",
503 "branch": "a",
504 "closed": false,
504 "closed": false,
505 "current": false,
505 "current": false,
506 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
506 "node": "d8cbc61dbaa6dc817175d1e301eecb863f280832",
507 "rev": 5
507 "rev": 5
508 },
508 },
509 {
509 {
510 "active": false,
510 "active": false,
511 "branch": "default",
511 "branch": "default",
512 "closed": false,
512 "closed": false,
513 "current": false,
513 "current": false,
514 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
514 "node": "19709c5a4e75bf938f8e349aff97438539bb729e",
515 "rev": 0
515 "rev": 0
516 }
516 }
517 ]
517 ]
518
518
519 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
519 $ hg branches --closed -T '{if(closed, "{branch}\n")}'
520 c
520 c
521
521
522 $ hg branches -T '{word(0, branch)}: {desc|firstline}\n'
523 b: reopen branch with a change
524 a: Adding d branch
525 a: Adding b branch head 2
526 default: Adding root node
527
522 Tests of revision branch name caching
528 Tests of revision branch name caching
523
529
524 We rev branch cache is updated automatically. In these tests we use a trick to
530 We rev branch cache is updated automatically. In these tests we use a trick to
525 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
531 trigger rebuilds. We remove the branch head cache and run 'hg head' to cause a
526 rebuild that also will populate the rev branch cache.
532 rebuild that also will populate the rev branch cache.
527
533
528 revision branch cache is created when building the branch head cache
534 revision branch cache is created when building the branch head cache
529 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
535 $ rm -rf .hg/cache; hg head a -T '{rev}\n'
530 5
536 5
531 $ f --hexdump --size .hg/cache/rbc-*
537 $ f --hexdump --size .hg/cache/rbc-*
532 .hg/cache/rbc-names-v1: size=87
538 .hg/cache/rbc-names-v1: size=87
533 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
539 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
534 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
540 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
535 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
541 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
536 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
542 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
537 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
543 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
538 0050: 72 61 6e 63 68 65 73 |ranches|
544 0050: 72 61 6e 63 68 65 73 |ranches|
539 .hg/cache/rbc-revs-v1: size=120
545 .hg/cache/rbc-revs-v1: size=120
540 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
546 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
541 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
547 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
542 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
548 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
543 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
549 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
544 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
550 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
545 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
551 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
546 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
552 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
547 0070: f8 94 c2 56 80 00 00 03 |...V....|
553 0070: f8 94 c2 56 80 00 00 03 |...V....|
548
554
549 no errors when revbranchcache is not writable
555 no errors when revbranchcache is not writable
550
556
551 $ echo >> .hg/cache/rbc-revs-v1
557 $ echo >> .hg/cache/rbc-revs-v1
552 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
558 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
553 $ mkdir .hg/cache/rbc-revs-v1
559 $ mkdir .hg/cache/rbc-revs-v1
554 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
560 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n'
555 5
561 5
556 $ rmdir .hg/cache/rbc-revs-v1
562 $ rmdir .hg/cache/rbc-revs-v1
557 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
563 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
558
564
559 no errors when wlock cannot be acquired
565 no errors when wlock cannot be acquired
560
566
561 #if unix-permissions
567 #if unix-permissions
562 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
568 $ mv .hg/cache/rbc-revs-v1 .hg/cache/rbc-revs-v1_
563 $ rm -f .hg/cache/branch*
569 $ rm -f .hg/cache/branch*
564 $ chmod 555 .hg
570 $ chmod 555 .hg
565 $ hg head a -T '{rev}\n'
571 $ hg head a -T '{rev}\n'
566 5
572 5
567 $ chmod 755 .hg
573 $ chmod 755 .hg
568 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
574 $ mv .hg/cache/rbc-revs-v1_ .hg/cache/rbc-revs-v1
569 #endif
575 #endif
570
576
571 recovery from invalid cache revs file with trailing data
577 recovery from invalid cache revs file with trailing data
572 $ echo >> .hg/cache/rbc-revs-v1
578 $ echo >> .hg/cache/rbc-revs-v1
573 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
579 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
574 5
580 5
575 truncating cache/rbc-revs-v1 to 120
581 truncating cache/rbc-revs-v1 to 120
576 $ f --size .hg/cache/rbc-revs*
582 $ f --size .hg/cache/rbc-revs*
577 .hg/cache/rbc-revs-v1: size=120
583 .hg/cache/rbc-revs-v1: size=120
578 recovery from invalid cache file with partial last record
584 recovery from invalid cache file with partial last record
579 $ mv .hg/cache/rbc-revs-v1 .
585 $ mv .hg/cache/rbc-revs-v1 .
580 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
586 $ f -qDB 119 rbc-revs-v1 > .hg/cache/rbc-revs-v1
581 $ f --size .hg/cache/rbc-revs*
587 $ f --size .hg/cache/rbc-revs*
582 .hg/cache/rbc-revs-v1: size=119
588 .hg/cache/rbc-revs-v1: size=119
583 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
589 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
584 5
590 5
585 truncating cache/rbc-revs-v1 to 112
591 truncating cache/rbc-revs-v1 to 112
586 $ f --size .hg/cache/rbc-revs*
592 $ f --size .hg/cache/rbc-revs*
587 .hg/cache/rbc-revs-v1: size=120
593 .hg/cache/rbc-revs-v1: size=120
588 recovery from invalid cache file with missing record - no truncation
594 recovery from invalid cache file with missing record - no truncation
589 $ mv .hg/cache/rbc-revs-v1 .
595 $ mv .hg/cache/rbc-revs-v1 .
590 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
596 $ f -qDB 112 rbc-revs-v1 > .hg/cache/rbc-revs-v1
591 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
597 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
592 5
598 5
593 $ f --size .hg/cache/rbc-revs*
599 $ f --size .hg/cache/rbc-revs*
594 .hg/cache/rbc-revs-v1: size=120
600 .hg/cache/rbc-revs-v1: size=120
595 recovery from invalid cache file with some bad records
601 recovery from invalid cache file with some bad records
596 $ mv .hg/cache/rbc-revs-v1 .
602 $ mv .hg/cache/rbc-revs-v1 .
597 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
603 $ f -qDB 8 rbc-revs-v1 > .hg/cache/rbc-revs-v1
598 $ f --size .hg/cache/rbc-revs*
604 $ f --size .hg/cache/rbc-revs*
599 .hg/cache/rbc-revs-v1: size=8
605 .hg/cache/rbc-revs-v1: size=8
600 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
606 $ f -qDB 112 rbc-revs-v1 >> .hg/cache/rbc-revs-v1
601 $ f --size .hg/cache/rbc-revs*
607 $ f --size .hg/cache/rbc-revs*
602 .hg/cache/rbc-revs-v1: size=120
608 .hg/cache/rbc-revs-v1: size=120
603 $ hg log -r 'branch(.)' -T '{rev} ' --debug
609 $ hg log -r 'branch(.)' -T '{rev} ' --debug
604 history modification detected - truncating revision branch cache to revision 13
610 history modification detected - truncating revision branch cache to revision 13
605 history modification detected - truncating revision branch cache to revision 1
611 history modification detected - truncating revision branch cache to revision 1
606 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
612 3 4 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 8
607 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
613 $ rm -f .hg/cache/branch* && hg head a -T '{rev}\n' --debug
608 5
614 5
609 truncating cache/rbc-revs-v1 to 104
615 truncating cache/rbc-revs-v1 to 104
610 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
616 $ f --size --hexdump --bytes=16 .hg/cache/rbc-revs*
611 .hg/cache/rbc-revs-v1: size=120
617 .hg/cache/rbc-revs-v1: size=120
612 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
618 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
613 cache is updated when committing
619 cache is updated when committing
614 $ hg branch i-will-regret-this
620 $ hg branch i-will-regret-this
615 marked working directory as branch i-will-regret-this
621 marked working directory as branch i-will-regret-this
616 $ hg ci -m regrets
622 $ hg ci -m regrets
617 $ f --size .hg/cache/rbc-*
623 $ f --size .hg/cache/rbc-*
618 .hg/cache/rbc-names-v1: size=106
624 .hg/cache/rbc-names-v1: size=106
619 .hg/cache/rbc-revs-v1: size=128
625 .hg/cache/rbc-revs-v1: size=128
620 update after rollback - the cache will be correct but rbc-names will will still
626 update after rollback - the cache will be correct but rbc-names will will still
621 contain the branch name even though it no longer is used
627 contain the branch name even though it no longer is used
622 $ hg up -qr '.^'
628 $ hg up -qr '.^'
623 $ hg rollback -qf
629 $ hg rollback -qf
624 $ f --size --hexdump .hg/cache/rbc-*
630 $ f --size --hexdump .hg/cache/rbc-*
625 .hg/cache/rbc-names-v1: size=106
631 .hg/cache/rbc-names-v1: size=106
626 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
632 0000: 64 65 66 61 75 6c 74 00 61 00 62 00 63 00 61 20 |default.a.b.c.a |
627 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
633 0010: 62 72 61 6e 63 68 20 6e 61 6d 65 20 6d 75 63 68 |branch name much|
628 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
634 0020: 20 6c 6f 6e 67 65 72 20 74 68 61 6e 20 74 68 65 | longer than the|
629 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
635 0030: 20 64 65 66 61 75 6c 74 20 6a 75 73 74 69 66 69 | default justifi|
630 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
636 0040: 63 61 74 69 6f 6e 20 75 73 65 64 20 62 79 20 62 |cation used by b|
631 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
637 0050: 72 61 6e 63 68 65 73 00 69 2d 77 69 6c 6c 2d 72 |ranches.i-will-r|
632 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
638 0060: 65 67 72 65 74 2d 74 68 69 73 |egret-this|
633 .hg/cache/rbc-revs-v1: size=120
639 .hg/cache/rbc-revs-v1: size=120
634 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
640 0000: 19 70 9c 5a 00 00 00 00 dd 6b 44 0d 00 00 00 01 |.p.Z.....kD.....|
635 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
641 0010: 88 1f e2 b9 00 00 00 01 ac 22 03 33 00 00 00 02 |.........".3....|
636 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
642 0020: ae e3 9c d1 00 00 00 02 d8 cb c6 1d 00 00 00 01 |................|
637 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
643 0030: 58 97 36 a2 00 00 00 03 10 ff 58 95 00 00 00 04 |X.6.......X.....|
638 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
644 0040: ee bb 94 44 00 00 00 02 5f 40 61 bb 00 00 00 02 |...D...._@a.....|
639 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
645 0050: bf be 84 1b 00 00 00 02 d3 f1 63 45 80 00 00 02 |..........cE....|
640 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
646 0060: e3 d4 9c 05 80 00 00 02 e2 3b 55 05 00 00 00 02 |.........;U.....|
641 0070: f8 94 c2 56 80 00 00 03 |...V....|
647 0070: f8 94 c2 56 80 00 00 03 |...V....|
642 cache is updated/truncated when stripping - it is thus very hard to get in a
648 cache is updated/truncated when stripping - it is thus very hard to get in a
643 situation where the cache is out of sync and the hash check detects it
649 situation where the cache is out of sync and the hash check detects it
644 $ hg --config extensions.strip= strip -r tip --nob
650 $ hg --config extensions.strip= strip -r tip --nob
645 $ f --size .hg/cache/rbc-revs*
651 $ f --size .hg/cache/rbc-revs*
646 .hg/cache/rbc-revs-v1: size=112
652 .hg/cache/rbc-revs-v1: size=112
647
653
648 cache is rebuilt when corruption is detected
654 cache is rebuilt when corruption is detected
649 $ echo > .hg/cache/rbc-names-v1
655 $ echo > .hg/cache/rbc-names-v1
650 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
656 $ hg log -r '5:&branch(.)' -T '{rev} ' --debug
651 referenced branch names not found - rebuilding revision branch cache from scratch
657 referenced branch names not found - rebuilding revision branch cache from scratch
652 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
658 8 9 10 11 12 13 truncating cache/rbc-revs-v1 to 40
653 $ f --size --hexdump .hg/cache/rbc-*
659 $ f --size --hexdump .hg/cache/rbc-*
654 .hg/cache/rbc-names-v1: size=79
660 .hg/cache/rbc-names-v1: size=79
655 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
661 0000: 62 00 61 00 63 00 61 20 62 72 61 6e 63 68 20 6e |b.a.c.a branch n|
656 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
662 0010: 61 6d 65 20 6d 75 63 68 20 6c 6f 6e 67 65 72 20 |ame much longer |
657 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
663 0020: 74 68 61 6e 20 74 68 65 20 64 65 66 61 75 6c 74 |than the default|
658 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
664 0030: 20 6a 75 73 74 69 66 69 63 61 74 69 6f 6e 20 75 | justification u|
659 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
665 0040: 73 65 64 20 62 79 20 62 72 61 6e 63 68 65 73 |sed by branches|
660 .hg/cache/rbc-revs-v1: size=112
666 .hg/cache/rbc-revs-v1: size=112
661 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
667 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
662 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
668 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
663 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
669 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 01 |................|
664 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
670 0030: 58 97 36 a2 00 00 00 02 10 ff 58 95 00 00 00 03 |X.6.......X.....|
665 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
671 0040: ee bb 94 44 00 00 00 00 5f 40 61 bb 00 00 00 00 |...D...._@a.....|
666 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
672 0050: bf be 84 1b 00 00 00 00 d3 f1 63 45 80 00 00 00 |..........cE....|
667 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
673 0060: e3 d4 9c 05 80 00 00 00 e2 3b 55 05 00 00 00 00 |.........;U.....|
668
674
669 Test that cache files are created and grows correctly:
675 Test that cache files are created and grows correctly:
670
676
671 $ rm .hg/cache/rbc*
677 $ rm .hg/cache/rbc*
672 $ hg log -r "5 & branch(5)" -T "{rev}\n"
678 $ hg log -r "5 & branch(5)" -T "{rev}\n"
673 5
679 5
674 $ f --size --hexdump .hg/cache/rbc-*
680 $ f --size --hexdump .hg/cache/rbc-*
675 .hg/cache/rbc-names-v1: size=1
681 .hg/cache/rbc-names-v1: size=1
676 0000: 61 |a|
682 0000: 61 |a|
677 .hg/cache/rbc-revs-v1: size=112
683 .hg/cache/rbc-revs-v1: size=112
678 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
684 0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
679 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
685 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
680 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
686 0020: 00 00 00 00 00 00 00 00 d8 cb c6 1d 00 00 00 00 |................|
681 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
687 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
682 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
688 0040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
683 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
689 0050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
684 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
690 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
685
691
686 $ cd ..
692 $ cd ..
687
693
688 Test for multiple incorrect branch cache entries:
694 Test for multiple incorrect branch cache entries:
689
695
690 $ hg init b
696 $ hg init b
691 $ cd b
697 $ cd b
692 $ touch f
698 $ touch f
693 $ hg ci -Aqmf
699 $ hg ci -Aqmf
694 $ echo >> f
700 $ echo >> f
695 $ hg ci -Amf
701 $ hg ci -Amf
696 $ hg branch -q branch
702 $ hg branch -q branch
697 $ hg ci -Amf
703 $ hg ci -Amf
698
704
699 $ f --size --hexdump .hg/cache/rbc-*
705 $ f --size --hexdump .hg/cache/rbc-*
700 .hg/cache/rbc-names-v1: size=14
706 .hg/cache/rbc-names-v1: size=14
701 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
707 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
702 .hg/cache/rbc-revs-v1: size=24
708 .hg/cache/rbc-revs-v1: size=24
703 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
709 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
704 0010: 56 46 78 69 00 00 00 01 |VFxi....|
710 0010: 56 46 78 69 00 00 00 01 |VFxi....|
705 $ : > .hg/cache/rbc-revs-v1
711 $ : > .hg/cache/rbc-revs-v1
706
712
707 No superfluous rebuilding of cache:
713 No superfluous rebuilding of cache:
708 $ hg log -r "branch(null)&branch(branch)" --debug
714 $ hg log -r "branch(null)&branch(branch)" --debug
709 $ f --size --hexdump .hg/cache/rbc-*
715 $ f --size --hexdump .hg/cache/rbc-*
710 .hg/cache/rbc-names-v1: size=14
716 .hg/cache/rbc-names-v1: size=14
711 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
717 0000: 64 65 66 61 75 6c 74 00 62 72 61 6e 63 68 |default.branch|
712 .hg/cache/rbc-revs-v1: size=24
718 .hg/cache/rbc-revs-v1: size=24
713 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
719 0000: 66 e5 f5 aa 00 00 00 00 fa 4c 04 e5 00 00 00 00 |f........L......|
714 0010: 56 46 78 69 00 00 00 01 |VFxi....|
720 0010: 56 46 78 69 00 00 00 01 |VFxi....|
715
721
716 $ cd ..
722 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now