##// END OF EJS Templates
py3: convert kwargs' keys to str before passing in cmdutil.getcommiteditor
Pulkit Goyal -
r32192:76f938ec default
parent child Browse files
Show More
@@ -1,5512 +1,5515 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 rcutil,
46 rcutil,
47 revsetlang,
47 revsetlang,
48 scmutil,
48 scmutil,
49 server,
49 server,
50 sshserver,
50 sshserver,
51 streamclone,
51 streamclone,
52 tags as tagsmod,
52 tags as tagsmod,
53 templatekw,
53 templatekw,
54 ui as uimod,
54 ui as uimod,
55 util,
55 util,
56 )
56 )
57
57
58 release = lockmod.release
58 release = lockmod.release
59
59
60 table = {}
60 table = {}
61
61
62 command = cmdutil.command(table)
62 command = cmdutil.command(table)
63
63
64 # label constants
64 # label constants
65 # until 3.5, bookmarks.current was the advertised name, not
65 # until 3.5, bookmarks.current was the advertised name, not
66 # bookmarks.active, so we must use both to avoid breaking old
66 # bookmarks.active, so we must use both to avoid breaking old
67 # custom styles
67 # custom styles
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
68 activebookmarklabel = 'bookmarks.active bookmarks.current'
69
69
70 # common command options
70 # common command options
71
71
72 globalopts = [
72 globalopts = [
73 ('R', 'repository', '',
73 ('R', 'repository', '',
74 _('repository root directory or name of overlay bundle file'),
74 _('repository root directory or name of overlay bundle file'),
75 _('REPO')),
75 _('REPO')),
76 ('', 'cwd', '',
76 ('', 'cwd', '',
77 _('change working directory'), _('DIR')),
77 _('change working directory'), _('DIR')),
78 ('y', 'noninteractive', None,
78 ('y', 'noninteractive', None,
79 _('do not prompt, automatically pick the first choice for all prompts')),
79 _('do not prompt, automatically pick the first choice for all prompts')),
80 ('q', 'quiet', None, _('suppress output')),
80 ('q', 'quiet', None, _('suppress output')),
81 ('v', 'verbose', None, _('enable additional output')),
81 ('v', 'verbose', None, _('enable additional output')),
82 ('', 'color', '',
82 ('', 'color', '',
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
83 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
84 # and should not be translated
84 # and should not be translated
85 _("when to colorize (boolean, always, auto, never, or debug)"),
85 _("when to colorize (boolean, always, auto, never, or debug)"),
86 _('TYPE')),
86 _('TYPE')),
87 ('', 'config', [],
87 ('', 'config', [],
88 _('set/override config option (use \'section.name=value\')'),
88 _('set/override config option (use \'section.name=value\')'),
89 _('CONFIG')),
89 _('CONFIG')),
90 ('', 'debug', None, _('enable debugging output')),
90 ('', 'debug', None, _('enable debugging output')),
91 ('', 'debugger', None, _('start debugger')),
91 ('', 'debugger', None, _('start debugger')),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
92 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
93 _('ENCODE')),
93 _('ENCODE')),
94 ('', 'encodingmode', encoding.encodingmode,
94 ('', 'encodingmode', encoding.encodingmode,
95 _('set the charset encoding mode'), _('MODE')),
95 _('set the charset encoding mode'), _('MODE')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
96 ('', 'traceback', None, _('always print a traceback on exception')),
97 ('', 'time', None, _('time how long the command takes')),
97 ('', 'time', None, _('time how long the command takes')),
98 ('', 'profile', None, _('print command execution profile')),
98 ('', 'profile', None, _('print command execution profile')),
99 ('', 'version', None, _('output version information and exit')),
99 ('', 'version', None, _('output version information and exit')),
100 ('h', 'help', None, _('display help and exit')),
100 ('h', 'help', None, _('display help and exit')),
101 ('', 'hidden', False, _('consider hidden changesets')),
101 ('', 'hidden', False, _('consider hidden changesets')),
102 ('', 'pager', 'auto',
102 ('', 'pager', 'auto',
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
103 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
104 ]
104 ]
105
105
106 dryrunopts = [('n', 'dry-run', None,
106 dryrunopts = [('n', 'dry-run', None,
107 _('do not perform actions, just print output'))]
107 _('do not perform actions, just print output'))]
108
108
109 remoteopts = [
109 remoteopts = [
110 ('e', 'ssh', '',
110 ('e', 'ssh', '',
111 _('specify ssh command to use'), _('CMD')),
111 _('specify ssh command to use'), _('CMD')),
112 ('', 'remotecmd', '',
112 ('', 'remotecmd', '',
113 _('specify hg command to run on the remote side'), _('CMD')),
113 _('specify hg command to run on the remote side'), _('CMD')),
114 ('', 'insecure', None,
114 ('', 'insecure', None,
115 _('do not verify server certificate (ignoring web.cacerts config)')),
115 _('do not verify server certificate (ignoring web.cacerts config)')),
116 ]
116 ]
117
117
118 walkopts = [
118 walkopts = [
119 ('I', 'include', [],
119 ('I', 'include', [],
120 _('include names matching the given patterns'), _('PATTERN')),
120 _('include names matching the given patterns'), _('PATTERN')),
121 ('X', 'exclude', [],
121 ('X', 'exclude', [],
122 _('exclude names matching the given patterns'), _('PATTERN')),
122 _('exclude names matching the given patterns'), _('PATTERN')),
123 ]
123 ]
124
124
125 commitopts = [
125 commitopts = [
126 ('m', 'message', '',
126 ('m', 'message', '',
127 _('use text as commit message'), _('TEXT')),
127 _('use text as commit message'), _('TEXT')),
128 ('l', 'logfile', '',
128 ('l', 'logfile', '',
129 _('read commit message from file'), _('FILE')),
129 _('read commit message from file'), _('FILE')),
130 ]
130 ]
131
131
132 commitopts2 = [
132 commitopts2 = [
133 ('d', 'date', '',
133 ('d', 'date', '',
134 _('record the specified date as commit date'), _('DATE')),
134 _('record the specified date as commit date'), _('DATE')),
135 ('u', 'user', '',
135 ('u', 'user', '',
136 _('record the specified user as committer'), _('USER')),
136 _('record the specified user as committer'), _('USER')),
137 ]
137 ]
138
138
139 # hidden for now
139 # hidden for now
140 formatteropts = [
140 formatteropts = [
141 ('T', 'template', '',
141 ('T', 'template', '',
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
142 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
143 ]
143 ]
144
144
145 templateopts = [
145 templateopts = [
146 ('', 'style', '',
146 ('', 'style', '',
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
147 _('display using template map file (DEPRECATED)'), _('STYLE')),
148 ('T', 'template', '',
148 ('T', 'template', '',
149 _('display with template'), _('TEMPLATE')),
149 _('display with template'), _('TEMPLATE')),
150 ]
150 ]
151
151
152 logopts = [
152 logopts = [
153 ('p', 'patch', None, _('show patch')),
153 ('p', 'patch', None, _('show patch')),
154 ('g', 'git', None, _('use git extended diff format')),
154 ('g', 'git', None, _('use git extended diff format')),
155 ('l', 'limit', '',
155 ('l', 'limit', '',
156 _('limit number of changes displayed'), _('NUM')),
156 _('limit number of changes displayed'), _('NUM')),
157 ('M', 'no-merges', None, _('do not show merges')),
157 ('M', 'no-merges', None, _('do not show merges')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'stat', None, _('output diffstat-style summary of changes')),
159 ('G', 'graph', None, _("show the revision DAG")),
159 ('G', 'graph', None, _("show the revision DAG")),
160 ] + templateopts
160 ] + templateopts
161
161
162 diffopts = [
162 diffopts = [
163 ('a', 'text', None, _('treat all files as text')),
163 ('a', 'text', None, _('treat all files as text')),
164 ('g', 'git', None, _('use git extended diff format')),
164 ('g', 'git', None, _('use git extended diff format')),
165 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
165 ('', 'binary', None, _('generate binary diffs in git mode (default)')),
166 ('', 'nodates', None, _('omit dates from diff headers'))
166 ('', 'nodates', None, _('omit dates from diff headers'))
167 ]
167 ]
168
168
169 diffwsopts = [
169 diffwsopts = [
170 ('w', 'ignore-all-space', None,
170 ('w', 'ignore-all-space', None,
171 _('ignore white space when comparing lines')),
171 _('ignore white space when comparing lines')),
172 ('b', 'ignore-space-change', None,
172 ('b', 'ignore-space-change', None,
173 _('ignore changes in the amount of white space')),
173 _('ignore changes in the amount of white space')),
174 ('B', 'ignore-blank-lines', None,
174 ('B', 'ignore-blank-lines', None,
175 _('ignore changes whose lines are all blank')),
175 _('ignore changes whose lines are all blank')),
176 ]
176 ]
177
177
178 diffopts2 = [
178 diffopts2 = [
179 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
179 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
180 ('p', 'show-function', None, _('show which function each change is in')),
180 ('p', 'show-function', None, _('show which function each change is in')),
181 ('', 'reverse', None, _('produce a diff that undoes the changes')),
181 ('', 'reverse', None, _('produce a diff that undoes the changes')),
182 ] + diffwsopts + [
182 ] + diffwsopts + [
183 ('U', 'unified', '',
183 ('U', 'unified', '',
184 _('number of lines of context to show'), _('NUM')),
184 _('number of lines of context to show'), _('NUM')),
185 ('', 'stat', None, _('output diffstat-style summary of changes')),
185 ('', 'stat', None, _('output diffstat-style summary of changes')),
186 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
186 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
187 ]
187 ]
188
188
189 mergetoolopts = [
189 mergetoolopts = [
190 ('t', 'tool', '', _('specify merge tool')),
190 ('t', 'tool', '', _('specify merge tool')),
191 ]
191 ]
192
192
193 similarityopts = [
193 similarityopts = [
194 ('s', 'similarity', '',
194 ('s', 'similarity', '',
195 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
195 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
196 ]
196 ]
197
197
198 subrepoopts = [
198 subrepoopts = [
199 ('S', 'subrepos', None,
199 ('S', 'subrepos', None,
200 _('recurse into subrepositories'))
200 _('recurse into subrepositories'))
201 ]
201 ]
202
202
203 debugrevlogopts = [
203 debugrevlogopts = [
204 ('c', 'changelog', False, _('open changelog')),
204 ('c', 'changelog', False, _('open changelog')),
205 ('m', 'manifest', False, _('open manifest')),
205 ('m', 'manifest', False, _('open manifest')),
206 ('', 'dir', '', _('open directory manifest')),
206 ('', 'dir', '', _('open directory manifest')),
207 ]
207 ]
208
208
209 # Commands start here, listed alphabetically
209 # Commands start here, listed alphabetically
210
210
211 @command('^add',
211 @command('^add',
212 walkopts + subrepoopts + dryrunopts,
212 walkopts + subrepoopts + dryrunopts,
213 _('[OPTION]... [FILE]...'),
213 _('[OPTION]... [FILE]...'),
214 inferrepo=True)
214 inferrepo=True)
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
259 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
260 return rejected and 1 or 0
260 return rejected and 1 or 0
261
261
262 @command('addremove',
262 @command('addremove',
263 similarityopts + subrepoopts + walkopts + dryrunopts,
263 similarityopts + subrepoopts + walkopts + dryrunopts,
264 _('[OPTION]... [FILE]...'),
264 _('[OPTION]... [FILE]...'),
265 inferrepo=True)
265 inferrepo=True)
266 def addremove(ui, repo, *pats, **opts):
266 def addremove(ui, repo, *pats, **opts):
267 """add all new files, delete all missing files
267 """add all new files, delete all missing files
268
268
269 Add all new files and remove all missing files from the
269 Add all new files and remove all missing files from the
270 repository.
270 repository.
271
271
272 Unless names are given, new files are ignored if they match any of
272 Unless names are given, new files are ignored if they match any of
273 the patterns in ``.hgignore``. As with add, these changes take
273 the patterns in ``.hgignore``. As with add, these changes take
274 effect at the next commit.
274 effect at the next commit.
275
275
276 Use the -s/--similarity option to detect renamed files. This
276 Use the -s/--similarity option to detect renamed files. This
277 option takes a percentage between 0 (disabled) and 100 (files must
277 option takes a percentage between 0 (disabled) and 100 (files must
278 be identical) as its parameter. With a parameter greater than 0,
278 be identical) as its parameter. With a parameter greater than 0,
279 this compares every removed file with every added file and records
279 this compares every removed file with every added file and records
280 those similar enough as renames. Detecting renamed files this way
280 those similar enough as renames. Detecting renamed files this way
281 can be expensive. After using this option, :hg:`status -C` can be
281 can be expensive. After using this option, :hg:`status -C` can be
282 used to check which files were identified as moved or renamed. If
282 used to check which files were identified as moved or renamed. If
283 not specified, -s/--similarity defaults to 100 and only renames of
283 not specified, -s/--similarity defaults to 100 and only renames of
284 identical files are detected.
284 identical files are detected.
285
285
286 .. container:: verbose
286 .. container:: verbose
287
287
288 Examples:
288 Examples:
289
289
290 - A number of files (bar.c and foo.c) are new,
290 - A number of files (bar.c and foo.c) are new,
291 while foobar.c has been removed (without using :hg:`remove`)
291 while foobar.c has been removed (without using :hg:`remove`)
292 from the repository::
292 from the repository::
293
293
294 $ ls
294 $ ls
295 bar.c foo.c
295 bar.c foo.c
296 $ hg status
296 $ hg status
297 ! foobar.c
297 ! foobar.c
298 ? bar.c
298 ? bar.c
299 ? foo.c
299 ? foo.c
300 $ hg addremove
300 $ hg addremove
301 adding bar.c
301 adding bar.c
302 adding foo.c
302 adding foo.c
303 removing foobar.c
303 removing foobar.c
304 $ hg status
304 $ hg status
305 A bar.c
305 A bar.c
306 A foo.c
306 A foo.c
307 R foobar.c
307 R foobar.c
308
308
309 - A file foobar.c was moved to foo.c without using :hg:`rename`.
309 - A file foobar.c was moved to foo.c without using :hg:`rename`.
310 Afterwards, it was edited slightly::
310 Afterwards, it was edited slightly::
311
311
312 $ ls
312 $ ls
313 foo.c
313 foo.c
314 $ hg status
314 $ hg status
315 ! foobar.c
315 ! foobar.c
316 ? foo.c
316 ? foo.c
317 $ hg addremove --similarity 90
317 $ hg addremove --similarity 90
318 removing foobar.c
318 removing foobar.c
319 adding foo.c
319 adding foo.c
320 recording removal of foobar.c as rename to foo.c (94% similar)
320 recording removal of foobar.c as rename to foo.c (94% similar)
321 $ hg status -C
321 $ hg status -C
322 A foo.c
322 A foo.c
323 foobar.c
323 foobar.c
324 R foobar.c
324 R foobar.c
325
325
326 Returns 0 if all files are successfully added.
326 Returns 0 if all files are successfully added.
327 """
327 """
328 opts = pycompat.byteskwargs(opts)
328 opts = pycompat.byteskwargs(opts)
329 try:
329 try:
330 sim = float(opts.get('similarity') or 100)
330 sim = float(opts.get('similarity') or 100)
331 except ValueError:
331 except ValueError:
332 raise error.Abort(_('similarity must be a number'))
332 raise error.Abort(_('similarity must be a number'))
333 if sim < 0 or sim > 100:
333 if sim < 0 or sim > 100:
334 raise error.Abort(_('similarity must be between 0 and 100'))
334 raise error.Abort(_('similarity must be between 0 and 100'))
335 matcher = scmutil.match(repo[None], pats, opts)
335 matcher = scmutil.match(repo[None], pats, opts)
336 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
336 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
337
337
338 @command('^annotate|blame',
338 @command('^annotate|blame',
339 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
339 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
340 ('', 'follow', None,
340 ('', 'follow', None,
341 _('follow copies/renames and list the filename (DEPRECATED)')),
341 _('follow copies/renames and list the filename (DEPRECATED)')),
342 ('', 'no-follow', None, _("don't follow copies and renames")),
342 ('', 'no-follow', None, _("don't follow copies and renames")),
343 ('a', 'text', None, _('treat all files as text')),
343 ('a', 'text', None, _('treat all files as text')),
344 ('u', 'user', None, _('list the author (long with -v)')),
344 ('u', 'user', None, _('list the author (long with -v)')),
345 ('f', 'file', None, _('list the filename')),
345 ('f', 'file', None, _('list the filename')),
346 ('d', 'date', None, _('list the date (short with -q)')),
346 ('d', 'date', None, _('list the date (short with -q)')),
347 ('n', 'number', None, _('list the revision number (default)')),
347 ('n', 'number', None, _('list the revision number (default)')),
348 ('c', 'changeset', None, _('list the changeset')),
348 ('c', 'changeset', None, _('list the changeset')),
349 ('l', 'line-number', None, _('show line number at the first appearance'))
349 ('l', 'line-number', None, _('show line number at the first appearance'))
350 ] + diffwsopts + walkopts + formatteropts,
350 ] + diffwsopts + walkopts + formatteropts,
351 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
351 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
352 inferrepo=True)
352 inferrepo=True)
353 def annotate(ui, repo, *pats, **opts):
353 def annotate(ui, repo, *pats, **opts):
354 """show changeset information by line for each file
354 """show changeset information by line for each file
355
355
356 List changes in files, showing the revision id responsible for
356 List changes in files, showing the revision id responsible for
357 each line.
357 each line.
358
358
359 This command is useful for discovering when a change was made and
359 This command is useful for discovering when a change was made and
360 by whom.
360 by whom.
361
361
362 If you include --file, --user, or --date, the revision number is
362 If you include --file, --user, or --date, the revision number is
363 suppressed unless you also include --number.
363 suppressed unless you also include --number.
364
364
365 Without the -a/--text option, annotate will avoid processing files
365 Without the -a/--text option, annotate will avoid processing files
366 it detects as binary. With -a, annotate will annotate the file
366 it detects as binary. With -a, annotate will annotate the file
367 anyway, although the results will probably be neither useful
367 anyway, although the results will probably be neither useful
368 nor desirable.
368 nor desirable.
369
369
370 Returns 0 on success.
370 Returns 0 on success.
371 """
371 """
372 opts = pycompat.byteskwargs(opts)
372 opts = pycompat.byteskwargs(opts)
373 if not pats:
373 if not pats:
374 raise error.Abort(_('at least one filename or pattern is required'))
374 raise error.Abort(_('at least one filename or pattern is required'))
375
375
376 if opts.get('follow'):
376 if opts.get('follow'):
377 # --follow is deprecated and now just an alias for -f/--file
377 # --follow is deprecated and now just an alias for -f/--file
378 # to mimic the behavior of Mercurial before version 1.5
378 # to mimic the behavior of Mercurial before version 1.5
379 opts['file'] = True
379 opts['file'] = True
380
380
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
381 ctx = scmutil.revsingle(repo, opts.get('rev'))
382
382
383 fm = ui.formatter('annotate', opts)
383 fm = ui.formatter('annotate', opts)
384 if ui.quiet:
384 if ui.quiet:
385 datefunc = util.shortdate
385 datefunc = util.shortdate
386 else:
386 else:
387 datefunc = util.datestr
387 datefunc = util.datestr
388 if ctx.rev() is None:
388 if ctx.rev() is None:
389 def hexfn(node):
389 def hexfn(node):
390 if node is None:
390 if node is None:
391 return None
391 return None
392 else:
392 else:
393 return fm.hexfunc(node)
393 return fm.hexfunc(node)
394 if opts.get('changeset'):
394 if opts.get('changeset'):
395 # omit "+" suffix which is appended to node hex
395 # omit "+" suffix which is appended to node hex
396 def formatrev(rev):
396 def formatrev(rev):
397 if rev is None:
397 if rev is None:
398 return '%d' % ctx.p1().rev()
398 return '%d' % ctx.p1().rev()
399 else:
399 else:
400 return '%d' % rev
400 return '%d' % rev
401 else:
401 else:
402 def formatrev(rev):
402 def formatrev(rev):
403 if rev is None:
403 if rev is None:
404 return '%d+' % ctx.p1().rev()
404 return '%d+' % ctx.p1().rev()
405 else:
405 else:
406 return '%d ' % rev
406 return '%d ' % rev
407 def formathex(hex):
407 def formathex(hex):
408 if hex is None:
408 if hex is None:
409 return '%s+' % fm.hexfunc(ctx.p1().node())
409 return '%s+' % fm.hexfunc(ctx.p1().node())
410 else:
410 else:
411 return '%s ' % hex
411 return '%s ' % hex
412 else:
412 else:
413 hexfn = fm.hexfunc
413 hexfn = fm.hexfunc
414 formatrev = formathex = str
414 formatrev = formathex = str
415
415
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
416 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
417 ('number', ' ', lambda x: x[0].rev(), formatrev),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
418 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
419 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
420 ('file', ' ', lambda x: x[0].path(), str),
420 ('file', ' ', lambda x: x[0].path(), str),
421 ('line_number', ':', lambda x: x[1], str),
421 ('line_number', ':', lambda x: x[1], str),
422 ]
422 ]
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
423 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
424
424
425 if (not opts.get('user') and not opts.get('changeset')
425 if (not opts.get('user') and not opts.get('changeset')
426 and not opts.get('date') and not opts.get('file')):
426 and not opts.get('date') and not opts.get('file')):
427 opts['number'] = True
427 opts['number'] = True
428
428
429 linenumber = opts.get('line_number') is not None
429 linenumber = opts.get('line_number') is not None
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
430 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
431 raise error.Abort(_('at least one of -n/-c is required for -l'))
432
432
433 ui.pager('annotate')
433 ui.pager('annotate')
434
434
435 if fm.isplain():
435 if fm.isplain():
436 def makefunc(get, fmt):
436 def makefunc(get, fmt):
437 return lambda x: fmt(get(x))
437 return lambda x: fmt(get(x))
438 else:
438 else:
439 def makefunc(get, fmt):
439 def makefunc(get, fmt):
440 return get
440 return get
441 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
441 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
442 if opts.get(op)]
442 if opts.get(op)]
443 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
443 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
444 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
444 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
445 if opts.get(op))
445 if opts.get(op))
446
446
447 def bad(x, y):
447 def bad(x, y):
448 raise error.Abort("%s: %s" % (x, y))
448 raise error.Abort("%s: %s" % (x, y))
449
449
450 m = scmutil.match(ctx, pats, opts, badfn=bad)
450 m = scmutil.match(ctx, pats, opts, badfn=bad)
451
451
452 follow = not opts.get('no_follow')
452 follow = not opts.get('no_follow')
453 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
453 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
454 whitespace=True)
454 whitespace=True)
455 for abs in ctx.walk(m):
455 for abs in ctx.walk(m):
456 fctx = ctx[abs]
456 fctx = ctx[abs]
457 if not opts.get('text') and fctx.isbinary():
457 if not opts.get('text') and fctx.isbinary():
458 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
458 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
459 continue
459 continue
460
460
461 lines = fctx.annotate(follow=follow, linenumber=linenumber,
461 lines = fctx.annotate(follow=follow, linenumber=linenumber,
462 diffopts=diffopts)
462 diffopts=diffopts)
463 if not lines:
463 if not lines:
464 continue
464 continue
465 formats = []
465 formats = []
466 pieces = []
466 pieces = []
467
467
468 for f, sep in funcmap:
468 for f, sep in funcmap:
469 l = [f(n) for n, dummy in lines]
469 l = [f(n) for n, dummy in lines]
470 if fm.isplain():
470 if fm.isplain():
471 sizes = [encoding.colwidth(x) for x in l]
471 sizes = [encoding.colwidth(x) for x in l]
472 ml = max(sizes)
472 ml = max(sizes)
473 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
473 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
474 else:
474 else:
475 formats.append(['%s' for x in l])
475 formats.append(['%s' for x in l])
476 pieces.append(l)
476 pieces.append(l)
477
477
478 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
478 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
479 fm.startitem()
479 fm.startitem()
480 fm.write(fields, "".join(f), *p)
480 fm.write(fields, "".join(f), *p)
481 fm.write('line', ": %s", l[1])
481 fm.write('line', ": %s", l[1])
482
482
483 if not lines[-1][1].endswith('\n'):
483 if not lines[-1][1].endswith('\n'):
484 fm.plain('\n')
484 fm.plain('\n')
485
485
486 fm.end()
486 fm.end()
487
487
488 @command('archive',
488 @command('archive',
489 [('', 'no-decode', None, _('do not pass files through decoders')),
489 [('', 'no-decode', None, _('do not pass files through decoders')),
490 ('p', 'prefix', '', _('directory prefix for files in archive'),
490 ('p', 'prefix', '', _('directory prefix for files in archive'),
491 _('PREFIX')),
491 _('PREFIX')),
492 ('r', 'rev', '', _('revision to distribute'), _('REV')),
492 ('r', 'rev', '', _('revision to distribute'), _('REV')),
493 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
493 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
494 ] + subrepoopts + walkopts,
494 ] + subrepoopts + walkopts,
495 _('[OPTION]... DEST'))
495 _('[OPTION]... DEST'))
496 def archive(ui, repo, dest, **opts):
496 def archive(ui, repo, dest, **opts):
497 '''create an unversioned archive of a repository revision
497 '''create an unversioned archive of a repository revision
498
498
499 By default, the revision used is the parent of the working
499 By default, the revision used is the parent of the working
500 directory; use -r/--rev to specify a different revision.
500 directory; use -r/--rev to specify a different revision.
501
501
502 The archive type is automatically detected based on file
502 The archive type is automatically detected based on file
503 extension (to override, use -t/--type).
503 extension (to override, use -t/--type).
504
504
505 .. container:: verbose
505 .. container:: verbose
506
506
507 Examples:
507 Examples:
508
508
509 - create a zip file containing the 1.0 release::
509 - create a zip file containing the 1.0 release::
510
510
511 hg archive -r 1.0 project-1.0.zip
511 hg archive -r 1.0 project-1.0.zip
512
512
513 - create a tarball excluding .hg files::
513 - create a tarball excluding .hg files::
514
514
515 hg archive project.tar.gz -X ".hg*"
515 hg archive project.tar.gz -X ".hg*"
516
516
517 Valid types are:
517 Valid types are:
518
518
519 :``files``: a directory full of files (default)
519 :``files``: a directory full of files (default)
520 :``tar``: tar archive, uncompressed
520 :``tar``: tar archive, uncompressed
521 :``tbz2``: tar archive, compressed using bzip2
521 :``tbz2``: tar archive, compressed using bzip2
522 :``tgz``: tar archive, compressed using gzip
522 :``tgz``: tar archive, compressed using gzip
523 :``uzip``: zip archive, uncompressed
523 :``uzip``: zip archive, uncompressed
524 :``zip``: zip archive, compressed using deflate
524 :``zip``: zip archive, compressed using deflate
525
525
526 The exact name of the destination archive or directory is given
526 The exact name of the destination archive or directory is given
527 using a format string; see :hg:`help export` for details.
527 using a format string; see :hg:`help export` for details.
528
528
529 Each member added to an archive file has a directory prefix
529 Each member added to an archive file has a directory prefix
530 prepended. Use -p/--prefix to specify a format string for the
530 prepended. Use -p/--prefix to specify a format string for the
531 prefix. The default is the basename of the archive, with suffixes
531 prefix. The default is the basename of the archive, with suffixes
532 removed.
532 removed.
533
533
534 Returns 0 on success.
534 Returns 0 on success.
535 '''
535 '''
536
536
537 opts = pycompat.byteskwargs(opts)
537 opts = pycompat.byteskwargs(opts)
538 ctx = scmutil.revsingle(repo, opts.get('rev'))
538 ctx = scmutil.revsingle(repo, opts.get('rev'))
539 if not ctx:
539 if not ctx:
540 raise error.Abort(_('no working directory: please specify a revision'))
540 raise error.Abort(_('no working directory: please specify a revision'))
541 node = ctx.node()
541 node = ctx.node()
542 dest = cmdutil.makefilename(repo, dest, node)
542 dest = cmdutil.makefilename(repo, dest, node)
543 if os.path.realpath(dest) == repo.root:
543 if os.path.realpath(dest) == repo.root:
544 raise error.Abort(_('repository root cannot be destination'))
544 raise error.Abort(_('repository root cannot be destination'))
545
545
546 kind = opts.get('type') or archival.guesskind(dest) or 'files'
546 kind = opts.get('type') or archival.guesskind(dest) or 'files'
547 prefix = opts.get('prefix')
547 prefix = opts.get('prefix')
548
548
549 if dest == '-':
549 if dest == '-':
550 if kind == 'files':
550 if kind == 'files':
551 raise error.Abort(_('cannot archive plain files to stdout'))
551 raise error.Abort(_('cannot archive plain files to stdout'))
552 dest = cmdutil.makefileobj(repo, dest)
552 dest = cmdutil.makefileobj(repo, dest)
553 if not prefix:
553 if not prefix:
554 prefix = os.path.basename(repo.root) + '-%h'
554 prefix = os.path.basename(repo.root) + '-%h'
555
555
556 prefix = cmdutil.makefilename(repo, prefix, node)
556 prefix = cmdutil.makefilename(repo, prefix, node)
557 matchfn = scmutil.match(ctx, [], opts)
557 matchfn = scmutil.match(ctx, [], opts)
558 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
558 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
559 matchfn, prefix, subrepos=opts.get('subrepos'))
559 matchfn, prefix, subrepos=opts.get('subrepos'))
560
560
561 @command('backout',
561 @command('backout',
562 [('', 'merge', None, _('merge with old dirstate parent after backout')),
562 [('', 'merge', None, _('merge with old dirstate parent after backout')),
563 ('', 'commit', None,
563 ('', 'commit', None,
564 _('commit if no conflicts were encountered (DEPRECATED)')),
564 _('commit if no conflicts were encountered (DEPRECATED)')),
565 ('', 'no-commit', None, _('do not commit')),
565 ('', 'no-commit', None, _('do not commit')),
566 ('', 'parent', '',
566 ('', 'parent', '',
567 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
567 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
568 ('r', 'rev', '', _('revision to backout'), _('REV')),
568 ('r', 'rev', '', _('revision to backout'), _('REV')),
569 ('e', 'edit', False, _('invoke editor on commit messages')),
569 ('e', 'edit', False, _('invoke editor on commit messages')),
570 ] + mergetoolopts + walkopts + commitopts + commitopts2,
570 ] + mergetoolopts + walkopts + commitopts + commitopts2,
571 _('[OPTION]... [-r] REV'))
571 _('[OPTION]... [-r] REV'))
572 def backout(ui, repo, node=None, rev=None, **opts):
572 def backout(ui, repo, node=None, rev=None, **opts):
573 '''reverse effect of earlier changeset
573 '''reverse effect of earlier changeset
574
574
575 Prepare a new changeset with the effect of REV undone in the
575 Prepare a new changeset with the effect of REV undone in the
576 current working directory. If no conflicts were encountered,
576 current working directory. If no conflicts were encountered,
577 it will be committed immediately.
577 it will be committed immediately.
578
578
579 If REV is the parent of the working directory, then this new changeset
579 If REV is the parent of the working directory, then this new changeset
580 is committed automatically (unless --no-commit is specified).
580 is committed automatically (unless --no-commit is specified).
581
581
582 .. note::
582 .. note::
583
583
584 :hg:`backout` cannot be used to fix either an unwanted or
584 :hg:`backout` cannot be used to fix either an unwanted or
585 incorrect merge.
585 incorrect merge.
586
586
587 .. container:: verbose
587 .. container:: verbose
588
588
589 Examples:
589 Examples:
590
590
591 - Reverse the effect of the parent of the working directory.
591 - Reverse the effect of the parent of the working directory.
592 This backout will be committed immediately::
592 This backout will be committed immediately::
593
593
594 hg backout -r .
594 hg backout -r .
595
595
596 - Reverse the effect of previous bad revision 23::
596 - Reverse the effect of previous bad revision 23::
597
597
598 hg backout -r 23
598 hg backout -r 23
599
599
600 - Reverse the effect of previous bad revision 23 and
600 - Reverse the effect of previous bad revision 23 and
601 leave changes uncommitted::
601 leave changes uncommitted::
602
602
603 hg backout -r 23 --no-commit
603 hg backout -r 23 --no-commit
604 hg commit -m "Backout revision 23"
604 hg commit -m "Backout revision 23"
605
605
606 By default, the pending changeset will have one parent,
606 By default, the pending changeset will have one parent,
607 maintaining a linear history. With --merge, the pending
607 maintaining a linear history. With --merge, the pending
608 changeset will instead have two parents: the old parent of the
608 changeset will instead have two parents: the old parent of the
609 working directory and a new child of REV that simply undoes REV.
609 working directory and a new child of REV that simply undoes REV.
610
610
611 Before version 1.7, the behavior without --merge was equivalent
611 Before version 1.7, the behavior without --merge was equivalent
612 to specifying --merge followed by :hg:`update --clean .` to
612 to specifying --merge followed by :hg:`update --clean .` to
613 cancel the merge and leave the child of REV as a head to be
613 cancel the merge and leave the child of REV as a head to be
614 merged separately.
614 merged separately.
615
615
616 See :hg:`help dates` for a list of formats valid for -d/--date.
616 See :hg:`help dates` for a list of formats valid for -d/--date.
617
617
618 See :hg:`help revert` for a way to restore files to the state
618 See :hg:`help revert` for a way to restore files to the state
619 of another revision.
619 of another revision.
620
620
621 Returns 0 on success, 1 if nothing to backout or there are unresolved
621 Returns 0 on success, 1 if nothing to backout or there are unresolved
622 files.
622 files.
623 '''
623 '''
624 wlock = lock = None
624 wlock = lock = None
625 try:
625 try:
626 wlock = repo.wlock()
626 wlock = repo.wlock()
627 lock = repo.lock()
627 lock = repo.lock()
628 return _dobackout(ui, repo, node, rev, **opts)
628 return _dobackout(ui, repo, node, rev, **opts)
629 finally:
629 finally:
630 release(lock, wlock)
630 release(lock, wlock)
631
631
632 def _dobackout(ui, repo, node=None, rev=None, **opts):
632 def _dobackout(ui, repo, node=None, rev=None, **opts):
633 opts = pycompat.byteskwargs(opts)
633 opts = pycompat.byteskwargs(opts)
634 if opts.get('commit') and opts.get('no_commit'):
634 if opts.get('commit') and opts.get('no_commit'):
635 raise error.Abort(_("cannot use --commit with --no-commit"))
635 raise error.Abort(_("cannot use --commit with --no-commit"))
636 if opts.get('merge') and opts.get('no_commit'):
636 if opts.get('merge') and opts.get('no_commit'):
637 raise error.Abort(_("cannot use --merge with --no-commit"))
637 raise error.Abort(_("cannot use --merge with --no-commit"))
638
638
639 if rev and node:
639 if rev and node:
640 raise error.Abort(_("please specify just one revision"))
640 raise error.Abort(_("please specify just one revision"))
641
641
642 if not rev:
642 if not rev:
643 rev = node
643 rev = node
644
644
645 if not rev:
645 if not rev:
646 raise error.Abort(_("please specify a revision to backout"))
646 raise error.Abort(_("please specify a revision to backout"))
647
647
648 date = opts.get('date')
648 date = opts.get('date')
649 if date:
649 if date:
650 opts['date'] = util.parsedate(date)
650 opts['date'] = util.parsedate(date)
651
651
652 cmdutil.checkunfinished(repo)
652 cmdutil.checkunfinished(repo)
653 cmdutil.bailifchanged(repo)
653 cmdutil.bailifchanged(repo)
654 node = scmutil.revsingle(repo, rev).node()
654 node = scmutil.revsingle(repo, rev).node()
655
655
656 op1, op2 = repo.dirstate.parents()
656 op1, op2 = repo.dirstate.parents()
657 if not repo.changelog.isancestor(node, op1):
657 if not repo.changelog.isancestor(node, op1):
658 raise error.Abort(_('cannot backout change that is not an ancestor'))
658 raise error.Abort(_('cannot backout change that is not an ancestor'))
659
659
660 p1, p2 = repo.changelog.parents(node)
660 p1, p2 = repo.changelog.parents(node)
661 if p1 == nullid:
661 if p1 == nullid:
662 raise error.Abort(_('cannot backout a change with no parents'))
662 raise error.Abort(_('cannot backout a change with no parents'))
663 if p2 != nullid:
663 if p2 != nullid:
664 if not opts.get('parent'):
664 if not opts.get('parent'):
665 raise error.Abort(_('cannot backout a merge changeset'))
665 raise error.Abort(_('cannot backout a merge changeset'))
666 p = repo.lookup(opts['parent'])
666 p = repo.lookup(opts['parent'])
667 if p not in (p1, p2):
667 if p not in (p1, p2):
668 raise error.Abort(_('%s is not a parent of %s') %
668 raise error.Abort(_('%s is not a parent of %s') %
669 (short(p), short(node)))
669 (short(p), short(node)))
670 parent = p
670 parent = p
671 else:
671 else:
672 if opts.get('parent'):
672 if opts.get('parent'):
673 raise error.Abort(_('cannot use --parent on non-merge changeset'))
673 raise error.Abort(_('cannot use --parent on non-merge changeset'))
674 parent = p1
674 parent = p1
675
675
676 # the backout should appear on the same branch
676 # the backout should appear on the same branch
677 branch = repo.dirstate.branch()
677 branch = repo.dirstate.branch()
678 bheads = repo.branchheads(branch)
678 bheads = repo.branchheads(branch)
679 rctx = scmutil.revsingle(repo, hex(parent))
679 rctx = scmutil.revsingle(repo, hex(parent))
680 if not opts.get('merge') and op1 != node:
680 if not opts.get('merge') and op1 != node:
681 dsguard = dirstateguard.dirstateguard(repo, 'backout')
681 dsguard = dirstateguard.dirstateguard(repo, 'backout')
682 try:
682 try:
683 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
683 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
684 'backout')
684 'backout')
685 stats = mergemod.update(repo, parent, True, True, node, False)
685 stats = mergemod.update(repo, parent, True, True, node, False)
686 repo.setparents(op1, op2)
686 repo.setparents(op1, op2)
687 dsguard.close()
687 dsguard.close()
688 hg._showstats(repo, stats)
688 hg._showstats(repo, stats)
689 if stats[3]:
689 if stats[3]:
690 repo.ui.status(_("use 'hg resolve' to retry unresolved "
690 repo.ui.status(_("use 'hg resolve' to retry unresolved "
691 "file merges\n"))
691 "file merges\n"))
692 return 1
692 return 1
693 finally:
693 finally:
694 ui.setconfig('ui', 'forcemerge', '', '')
694 ui.setconfig('ui', 'forcemerge', '', '')
695 lockmod.release(dsguard)
695 lockmod.release(dsguard)
696 else:
696 else:
697 hg.clean(repo, node, show_stats=False)
697 hg.clean(repo, node, show_stats=False)
698 repo.dirstate.setbranch(branch)
698 repo.dirstate.setbranch(branch)
699 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
699 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
700
700
701 if opts.get('no_commit'):
701 if opts.get('no_commit'):
702 msg = _("changeset %s backed out, "
702 msg = _("changeset %s backed out, "
703 "don't forget to commit.\n")
703 "don't forget to commit.\n")
704 ui.status(msg % short(node))
704 ui.status(msg % short(node))
705 return 0
705 return 0
706
706
707 def commitfunc(ui, repo, message, match, opts):
707 def commitfunc(ui, repo, message, match, opts):
708 editform = 'backout'
708 editform = 'backout'
709 e = cmdutil.getcommiteditor(editform=editform, **opts)
709 e = cmdutil.getcommiteditor(editform=editform,
710 **pycompat.strkwargs(opts))
710 if not message:
711 if not message:
711 # we don't translate commit messages
712 # we don't translate commit messages
712 message = "Backed out changeset %s" % short(node)
713 message = "Backed out changeset %s" % short(node)
713 e = cmdutil.getcommiteditor(edit=True, editform=editform)
714 e = cmdutil.getcommiteditor(edit=True, editform=editform)
714 return repo.commit(message, opts.get('user'), opts.get('date'),
715 return repo.commit(message, opts.get('user'), opts.get('date'),
715 match, editor=e)
716 match, editor=e)
716 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
717 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
717 if not newnode:
718 if not newnode:
718 ui.status(_("nothing changed\n"))
719 ui.status(_("nothing changed\n"))
719 return 1
720 return 1
720 cmdutil.commitstatus(repo, newnode, branch, bheads)
721 cmdutil.commitstatus(repo, newnode, branch, bheads)
721
722
722 def nice(node):
723 def nice(node):
723 return '%d:%s' % (repo.changelog.rev(node), short(node))
724 return '%d:%s' % (repo.changelog.rev(node), short(node))
724 ui.status(_('changeset %s backs out changeset %s\n') %
725 ui.status(_('changeset %s backs out changeset %s\n') %
725 (nice(repo.changelog.tip()), nice(node)))
726 (nice(repo.changelog.tip()), nice(node)))
726 if opts.get('merge') and op1 != node:
727 if opts.get('merge') and op1 != node:
727 hg.clean(repo, op1, show_stats=False)
728 hg.clean(repo, op1, show_stats=False)
728 ui.status(_('merging with changeset %s\n')
729 ui.status(_('merging with changeset %s\n')
729 % nice(repo.changelog.tip()))
730 % nice(repo.changelog.tip()))
730 try:
731 try:
731 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
732 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
732 'backout')
733 'backout')
733 return hg.merge(repo, hex(repo.changelog.tip()))
734 return hg.merge(repo, hex(repo.changelog.tip()))
734 finally:
735 finally:
735 ui.setconfig('ui', 'forcemerge', '', '')
736 ui.setconfig('ui', 'forcemerge', '', '')
736 return 0
737 return 0
737
738
738 @command('bisect',
739 @command('bisect',
739 [('r', 'reset', False, _('reset bisect state')),
740 [('r', 'reset', False, _('reset bisect state')),
740 ('g', 'good', False, _('mark changeset good')),
741 ('g', 'good', False, _('mark changeset good')),
741 ('b', 'bad', False, _('mark changeset bad')),
742 ('b', 'bad', False, _('mark changeset bad')),
742 ('s', 'skip', False, _('skip testing changeset')),
743 ('s', 'skip', False, _('skip testing changeset')),
743 ('e', 'extend', False, _('extend the bisect range')),
744 ('e', 'extend', False, _('extend the bisect range')),
744 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
745 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
745 ('U', 'noupdate', False, _('do not update to target'))],
746 ('U', 'noupdate', False, _('do not update to target'))],
746 _("[-gbsr] [-U] [-c CMD] [REV]"))
747 _("[-gbsr] [-U] [-c CMD] [REV]"))
747 def bisect(ui, repo, rev=None, extra=None, command=None,
748 def bisect(ui, repo, rev=None, extra=None, command=None,
748 reset=None, good=None, bad=None, skip=None, extend=None,
749 reset=None, good=None, bad=None, skip=None, extend=None,
749 noupdate=None):
750 noupdate=None):
750 """subdivision search of changesets
751 """subdivision search of changesets
751
752
752 This command helps to find changesets which introduce problems. To
753 This command helps to find changesets which introduce problems. To
753 use, mark the earliest changeset you know exhibits the problem as
754 use, mark the earliest changeset you know exhibits the problem as
754 bad, then mark the latest changeset which is free from the problem
755 bad, then mark the latest changeset which is free from the problem
755 as good. Bisect will update your working directory to a revision
756 as good. Bisect will update your working directory to a revision
756 for testing (unless the -U/--noupdate option is specified). Once
757 for testing (unless the -U/--noupdate option is specified). Once
757 you have performed tests, mark the working directory as good or
758 you have performed tests, mark the working directory as good or
758 bad, and bisect will either update to another candidate changeset
759 bad, and bisect will either update to another candidate changeset
759 or announce that it has found the bad revision.
760 or announce that it has found the bad revision.
760
761
761 As a shortcut, you can also use the revision argument to mark a
762 As a shortcut, you can also use the revision argument to mark a
762 revision as good or bad without checking it out first.
763 revision as good or bad without checking it out first.
763
764
764 If you supply a command, it will be used for automatic bisection.
765 If you supply a command, it will be used for automatic bisection.
765 The environment variable HG_NODE will contain the ID of the
766 The environment variable HG_NODE will contain the ID of the
766 changeset being tested. The exit status of the command will be
767 changeset being tested. The exit status of the command will be
767 used to mark revisions as good or bad: status 0 means good, 125
768 used to mark revisions as good or bad: status 0 means good, 125
768 means to skip the revision, 127 (command not found) will abort the
769 means to skip the revision, 127 (command not found) will abort the
769 bisection, and any other non-zero exit status means the revision
770 bisection, and any other non-zero exit status means the revision
770 is bad.
771 is bad.
771
772
772 .. container:: verbose
773 .. container:: verbose
773
774
774 Some examples:
775 Some examples:
775
776
776 - start a bisection with known bad revision 34, and good revision 12::
777 - start a bisection with known bad revision 34, and good revision 12::
777
778
778 hg bisect --bad 34
779 hg bisect --bad 34
779 hg bisect --good 12
780 hg bisect --good 12
780
781
781 - advance the current bisection by marking current revision as good or
782 - advance the current bisection by marking current revision as good or
782 bad::
783 bad::
783
784
784 hg bisect --good
785 hg bisect --good
785 hg bisect --bad
786 hg bisect --bad
786
787
787 - mark the current revision, or a known revision, to be skipped (e.g. if
788 - mark the current revision, or a known revision, to be skipped (e.g. if
788 that revision is not usable because of another issue)::
789 that revision is not usable because of another issue)::
789
790
790 hg bisect --skip
791 hg bisect --skip
791 hg bisect --skip 23
792 hg bisect --skip 23
792
793
793 - skip all revisions that do not touch directories ``foo`` or ``bar``::
794 - skip all revisions that do not touch directories ``foo`` or ``bar``::
794
795
795 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
796 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
796
797
797 - forget the current bisection::
798 - forget the current bisection::
798
799
799 hg bisect --reset
800 hg bisect --reset
800
801
801 - use 'make && make tests' to automatically find the first broken
802 - use 'make && make tests' to automatically find the first broken
802 revision::
803 revision::
803
804
804 hg bisect --reset
805 hg bisect --reset
805 hg bisect --bad 34
806 hg bisect --bad 34
806 hg bisect --good 12
807 hg bisect --good 12
807 hg bisect --command "make && make tests"
808 hg bisect --command "make && make tests"
808
809
809 - see all changesets whose states are already known in the current
810 - see all changesets whose states are already known in the current
810 bisection::
811 bisection::
811
812
812 hg log -r "bisect(pruned)"
813 hg log -r "bisect(pruned)"
813
814
814 - see the changeset currently being bisected (especially useful
815 - see the changeset currently being bisected (especially useful
815 if running with -U/--noupdate)::
816 if running with -U/--noupdate)::
816
817
817 hg log -r "bisect(current)"
818 hg log -r "bisect(current)"
818
819
819 - see all changesets that took part in the current bisection::
820 - see all changesets that took part in the current bisection::
820
821
821 hg log -r "bisect(range)"
822 hg log -r "bisect(range)"
822
823
823 - you can even get a nice graph::
824 - you can even get a nice graph::
824
825
825 hg log --graph -r "bisect(range)"
826 hg log --graph -r "bisect(range)"
826
827
827 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
828 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
828
829
829 Returns 0 on success.
830 Returns 0 on success.
830 """
831 """
831 # backward compatibility
832 # backward compatibility
832 if rev in "good bad reset init".split():
833 if rev in "good bad reset init".split():
833 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
834 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
834 cmd, rev, extra = rev, extra, None
835 cmd, rev, extra = rev, extra, None
835 if cmd == "good":
836 if cmd == "good":
836 good = True
837 good = True
837 elif cmd == "bad":
838 elif cmd == "bad":
838 bad = True
839 bad = True
839 else:
840 else:
840 reset = True
841 reset = True
841 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
842 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
842 raise error.Abort(_('incompatible arguments'))
843 raise error.Abort(_('incompatible arguments'))
843
844
844 if reset:
845 if reset:
845 hbisect.resetstate(repo)
846 hbisect.resetstate(repo)
846 return
847 return
847
848
848 state = hbisect.load_state(repo)
849 state = hbisect.load_state(repo)
849
850
850 # update state
851 # update state
851 if good or bad or skip:
852 if good or bad or skip:
852 if rev:
853 if rev:
853 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
854 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
854 else:
855 else:
855 nodes = [repo.lookup('.')]
856 nodes = [repo.lookup('.')]
856 if good:
857 if good:
857 state['good'] += nodes
858 state['good'] += nodes
858 elif bad:
859 elif bad:
859 state['bad'] += nodes
860 state['bad'] += nodes
860 elif skip:
861 elif skip:
861 state['skip'] += nodes
862 state['skip'] += nodes
862 hbisect.save_state(repo, state)
863 hbisect.save_state(repo, state)
863 if not (state['good'] and state['bad']):
864 if not (state['good'] and state['bad']):
864 return
865 return
865
866
866 def mayupdate(repo, node, show_stats=True):
867 def mayupdate(repo, node, show_stats=True):
867 """common used update sequence"""
868 """common used update sequence"""
868 if noupdate:
869 if noupdate:
869 return
870 return
870 cmdutil.checkunfinished(repo)
871 cmdutil.checkunfinished(repo)
871 cmdutil.bailifchanged(repo)
872 cmdutil.bailifchanged(repo)
872 return hg.clean(repo, node, show_stats=show_stats)
873 return hg.clean(repo, node, show_stats=show_stats)
873
874
874 displayer = cmdutil.show_changeset(ui, repo, {})
875 displayer = cmdutil.show_changeset(ui, repo, {})
875
876
876 if command:
877 if command:
877 changesets = 1
878 changesets = 1
878 if noupdate:
879 if noupdate:
879 try:
880 try:
880 node = state['current'][0]
881 node = state['current'][0]
881 except LookupError:
882 except LookupError:
882 raise error.Abort(_('current bisect revision is unknown - '
883 raise error.Abort(_('current bisect revision is unknown - '
883 'start a new bisect to fix'))
884 'start a new bisect to fix'))
884 else:
885 else:
885 node, p2 = repo.dirstate.parents()
886 node, p2 = repo.dirstate.parents()
886 if p2 != nullid:
887 if p2 != nullid:
887 raise error.Abort(_('current bisect revision is a merge'))
888 raise error.Abort(_('current bisect revision is a merge'))
888 if rev:
889 if rev:
889 node = repo[scmutil.revsingle(repo, rev, node)].node()
890 node = repo[scmutil.revsingle(repo, rev, node)].node()
890 try:
891 try:
891 while changesets:
892 while changesets:
892 # update state
893 # update state
893 state['current'] = [node]
894 state['current'] = [node]
894 hbisect.save_state(repo, state)
895 hbisect.save_state(repo, state)
895 status = ui.system(command, environ={'HG_NODE': hex(node)},
896 status = ui.system(command, environ={'HG_NODE': hex(node)},
896 blockedtag='bisect_check')
897 blockedtag='bisect_check')
897 if status == 125:
898 if status == 125:
898 transition = "skip"
899 transition = "skip"
899 elif status == 0:
900 elif status == 0:
900 transition = "good"
901 transition = "good"
901 # status < 0 means process was killed
902 # status < 0 means process was killed
902 elif status == 127:
903 elif status == 127:
903 raise error.Abort(_("failed to execute %s") % command)
904 raise error.Abort(_("failed to execute %s") % command)
904 elif status < 0:
905 elif status < 0:
905 raise error.Abort(_("%s killed") % command)
906 raise error.Abort(_("%s killed") % command)
906 else:
907 else:
907 transition = "bad"
908 transition = "bad"
908 state[transition].append(node)
909 state[transition].append(node)
909 ctx = repo[node]
910 ctx = repo[node]
910 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
911 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
911 hbisect.checkstate(state)
912 hbisect.checkstate(state)
912 # bisect
913 # bisect
913 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
914 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
914 # update to next check
915 # update to next check
915 node = nodes[0]
916 node = nodes[0]
916 mayupdate(repo, node, show_stats=False)
917 mayupdate(repo, node, show_stats=False)
917 finally:
918 finally:
918 state['current'] = [node]
919 state['current'] = [node]
919 hbisect.save_state(repo, state)
920 hbisect.save_state(repo, state)
920 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
921 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
921 return
922 return
922
923
923 hbisect.checkstate(state)
924 hbisect.checkstate(state)
924
925
925 # actually bisect
926 # actually bisect
926 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
927 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
927 if extend:
928 if extend:
928 if not changesets:
929 if not changesets:
929 extendnode = hbisect.extendrange(repo, state, nodes, good)
930 extendnode = hbisect.extendrange(repo, state, nodes, good)
930 if extendnode is not None:
931 if extendnode is not None:
931 ui.write(_("Extending search to changeset %d:%s\n")
932 ui.write(_("Extending search to changeset %d:%s\n")
932 % (extendnode.rev(), extendnode))
933 % (extendnode.rev(), extendnode))
933 state['current'] = [extendnode.node()]
934 state['current'] = [extendnode.node()]
934 hbisect.save_state(repo, state)
935 hbisect.save_state(repo, state)
935 return mayupdate(repo, extendnode.node())
936 return mayupdate(repo, extendnode.node())
936 raise error.Abort(_("nothing to extend"))
937 raise error.Abort(_("nothing to extend"))
937
938
938 if changesets == 0:
939 if changesets == 0:
939 hbisect.printresult(ui, repo, state, displayer, nodes, good)
940 hbisect.printresult(ui, repo, state, displayer, nodes, good)
940 else:
941 else:
941 assert len(nodes) == 1 # only a single node can be tested next
942 assert len(nodes) == 1 # only a single node can be tested next
942 node = nodes[0]
943 node = nodes[0]
943 # compute the approximate number of remaining tests
944 # compute the approximate number of remaining tests
944 tests, size = 0, 2
945 tests, size = 0, 2
945 while size <= changesets:
946 while size <= changesets:
946 tests, size = tests + 1, size * 2
947 tests, size = tests + 1, size * 2
947 rev = repo.changelog.rev(node)
948 rev = repo.changelog.rev(node)
948 ui.write(_("Testing changeset %d:%s "
949 ui.write(_("Testing changeset %d:%s "
949 "(%d changesets remaining, ~%d tests)\n")
950 "(%d changesets remaining, ~%d tests)\n")
950 % (rev, short(node), changesets, tests))
951 % (rev, short(node), changesets, tests))
951 state['current'] = [node]
952 state['current'] = [node]
952 hbisect.save_state(repo, state)
953 hbisect.save_state(repo, state)
953 return mayupdate(repo, node)
954 return mayupdate(repo, node)
954
955
955 @command('bookmarks|bookmark',
956 @command('bookmarks|bookmark',
956 [('f', 'force', False, _('force')),
957 [('f', 'force', False, _('force')),
957 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
958 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
958 ('d', 'delete', False, _('delete a given bookmark')),
959 ('d', 'delete', False, _('delete a given bookmark')),
959 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
960 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
960 ('i', 'inactive', False, _('mark a bookmark inactive')),
961 ('i', 'inactive', False, _('mark a bookmark inactive')),
961 ] + formatteropts,
962 ] + formatteropts,
962 _('hg bookmarks [OPTIONS]... [NAME]...'))
963 _('hg bookmarks [OPTIONS]... [NAME]...'))
963 def bookmark(ui, repo, *names, **opts):
964 def bookmark(ui, repo, *names, **opts):
964 '''create a new bookmark or list existing bookmarks
965 '''create a new bookmark or list existing bookmarks
965
966
966 Bookmarks are labels on changesets to help track lines of development.
967 Bookmarks are labels on changesets to help track lines of development.
967 Bookmarks are unversioned and can be moved, renamed and deleted.
968 Bookmarks are unversioned and can be moved, renamed and deleted.
968 Deleting or moving a bookmark has no effect on the associated changesets.
969 Deleting or moving a bookmark has no effect on the associated changesets.
969
970
970 Creating or updating to a bookmark causes it to be marked as 'active'.
971 Creating or updating to a bookmark causes it to be marked as 'active'.
971 The active bookmark is indicated with a '*'.
972 The active bookmark is indicated with a '*'.
972 When a commit is made, the active bookmark will advance to the new commit.
973 When a commit is made, the active bookmark will advance to the new commit.
973 A plain :hg:`update` will also advance an active bookmark, if possible.
974 A plain :hg:`update` will also advance an active bookmark, if possible.
974 Updating away from a bookmark will cause it to be deactivated.
975 Updating away from a bookmark will cause it to be deactivated.
975
976
976 Bookmarks can be pushed and pulled between repositories (see
977 Bookmarks can be pushed and pulled between repositories (see
977 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
978 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
978 diverged, a new 'divergent bookmark' of the form 'name@path' will
979 diverged, a new 'divergent bookmark' of the form 'name@path' will
979 be created. Using :hg:`merge` will resolve the divergence.
980 be created. Using :hg:`merge` will resolve the divergence.
980
981
981 A bookmark named '@' has the special property that :hg:`clone` will
982 A bookmark named '@' has the special property that :hg:`clone` will
982 check it out by default if it exists.
983 check it out by default if it exists.
983
984
984 .. container:: verbose
985 .. container:: verbose
985
986
986 Examples:
987 Examples:
987
988
988 - create an active bookmark for a new line of development::
989 - create an active bookmark for a new line of development::
989
990
990 hg book new-feature
991 hg book new-feature
991
992
992 - create an inactive bookmark as a place marker::
993 - create an inactive bookmark as a place marker::
993
994
994 hg book -i reviewed
995 hg book -i reviewed
995
996
996 - create an inactive bookmark on another changeset::
997 - create an inactive bookmark on another changeset::
997
998
998 hg book -r .^ tested
999 hg book -r .^ tested
999
1000
1000 - rename bookmark turkey to dinner::
1001 - rename bookmark turkey to dinner::
1001
1002
1002 hg book -m turkey dinner
1003 hg book -m turkey dinner
1003
1004
1004 - move the '@' bookmark from another branch::
1005 - move the '@' bookmark from another branch::
1005
1006
1006 hg book -f @
1007 hg book -f @
1007 '''
1008 '''
1008 opts = pycompat.byteskwargs(opts)
1009 opts = pycompat.byteskwargs(opts)
1009 force = opts.get('force')
1010 force = opts.get('force')
1010 rev = opts.get('rev')
1011 rev = opts.get('rev')
1011 delete = opts.get('delete')
1012 delete = opts.get('delete')
1012 rename = opts.get('rename')
1013 rename = opts.get('rename')
1013 inactive = opts.get('inactive')
1014 inactive = opts.get('inactive')
1014
1015
1015 def checkformat(mark):
1016 def checkformat(mark):
1016 mark = mark.strip()
1017 mark = mark.strip()
1017 if not mark:
1018 if not mark:
1018 raise error.Abort(_("bookmark names cannot consist entirely of "
1019 raise error.Abort(_("bookmark names cannot consist entirely of "
1019 "whitespace"))
1020 "whitespace"))
1020 scmutil.checknewlabel(repo, mark, 'bookmark')
1021 scmutil.checknewlabel(repo, mark, 'bookmark')
1021 return mark
1022 return mark
1022
1023
1023 def checkconflict(repo, mark, cur, force=False, target=None):
1024 def checkconflict(repo, mark, cur, force=False, target=None):
1024 if mark in marks and not force:
1025 if mark in marks and not force:
1025 if target:
1026 if target:
1026 if marks[mark] == target and target == cur:
1027 if marks[mark] == target and target == cur:
1027 # re-activating a bookmark
1028 # re-activating a bookmark
1028 return
1029 return
1029 anc = repo.changelog.ancestors([repo[target].rev()])
1030 anc = repo.changelog.ancestors([repo[target].rev()])
1030 bmctx = repo[marks[mark]]
1031 bmctx = repo[marks[mark]]
1031 divs = [repo[b].node() for b in marks
1032 divs = [repo[b].node() for b in marks
1032 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1033 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1033
1034
1034 # allow resolving a single divergent bookmark even if moving
1035 # allow resolving a single divergent bookmark even if moving
1035 # the bookmark across branches when a revision is specified
1036 # the bookmark across branches when a revision is specified
1036 # that contains a divergent bookmark
1037 # that contains a divergent bookmark
1037 if bmctx.rev() not in anc and target in divs:
1038 if bmctx.rev() not in anc and target in divs:
1038 bookmarks.deletedivergent(repo, [target], mark)
1039 bookmarks.deletedivergent(repo, [target], mark)
1039 return
1040 return
1040
1041
1041 deletefrom = [b for b in divs
1042 deletefrom = [b for b in divs
1042 if repo[b].rev() in anc or b == target]
1043 if repo[b].rev() in anc or b == target]
1043 bookmarks.deletedivergent(repo, deletefrom, mark)
1044 bookmarks.deletedivergent(repo, deletefrom, mark)
1044 if bookmarks.validdest(repo, bmctx, repo[target]):
1045 if bookmarks.validdest(repo, bmctx, repo[target]):
1045 ui.status(_("moving bookmark '%s' forward from %s\n") %
1046 ui.status(_("moving bookmark '%s' forward from %s\n") %
1046 (mark, short(bmctx.node())))
1047 (mark, short(bmctx.node())))
1047 return
1048 return
1048 raise error.Abort(_("bookmark '%s' already exists "
1049 raise error.Abort(_("bookmark '%s' already exists "
1049 "(use -f to force)") % mark)
1050 "(use -f to force)") % mark)
1050 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1051 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1051 and not force):
1052 and not force):
1052 raise error.Abort(
1053 raise error.Abort(
1053 _("a bookmark cannot have the name of an existing branch"))
1054 _("a bookmark cannot have the name of an existing branch"))
1054
1055
1055 if delete and rename:
1056 if delete and rename:
1056 raise error.Abort(_("--delete and --rename are incompatible"))
1057 raise error.Abort(_("--delete and --rename are incompatible"))
1057 if delete and rev:
1058 if delete and rev:
1058 raise error.Abort(_("--rev is incompatible with --delete"))
1059 raise error.Abort(_("--rev is incompatible with --delete"))
1059 if rename and rev:
1060 if rename and rev:
1060 raise error.Abort(_("--rev is incompatible with --rename"))
1061 raise error.Abort(_("--rev is incompatible with --rename"))
1061 if not names and (delete or rev):
1062 if not names and (delete or rev):
1062 raise error.Abort(_("bookmark name required"))
1063 raise error.Abort(_("bookmark name required"))
1063
1064
1064 if delete or rename or names or inactive:
1065 if delete or rename or names or inactive:
1065 wlock = lock = tr = None
1066 wlock = lock = tr = None
1066 try:
1067 try:
1067 wlock = repo.wlock()
1068 wlock = repo.wlock()
1068 lock = repo.lock()
1069 lock = repo.lock()
1069 cur = repo.changectx('.').node()
1070 cur = repo.changectx('.').node()
1070 marks = repo._bookmarks
1071 marks = repo._bookmarks
1071 if delete:
1072 if delete:
1072 tr = repo.transaction('bookmark')
1073 tr = repo.transaction('bookmark')
1073 for mark in names:
1074 for mark in names:
1074 if mark not in marks:
1075 if mark not in marks:
1075 raise error.Abort(_("bookmark '%s' does not exist") %
1076 raise error.Abort(_("bookmark '%s' does not exist") %
1076 mark)
1077 mark)
1077 if mark == repo._activebookmark:
1078 if mark == repo._activebookmark:
1078 bookmarks.deactivate(repo)
1079 bookmarks.deactivate(repo)
1079 del marks[mark]
1080 del marks[mark]
1080
1081
1081 elif rename:
1082 elif rename:
1082 tr = repo.transaction('bookmark')
1083 tr = repo.transaction('bookmark')
1083 if not names:
1084 if not names:
1084 raise error.Abort(_("new bookmark name required"))
1085 raise error.Abort(_("new bookmark name required"))
1085 elif len(names) > 1:
1086 elif len(names) > 1:
1086 raise error.Abort(_("only one new bookmark name allowed"))
1087 raise error.Abort(_("only one new bookmark name allowed"))
1087 mark = checkformat(names[0])
1088 mark = checkformat(names[0])
1088 if rename not in marks:
1089 if rename not in marks:
1089 raise error.Abort(_("bookmark '%s' does not exist")
1090 raise error.Abort(_("bookmark '%s' does not exist")
1090 % rename)
1091 % rename)
1091 checkconflict(repo, mark, cur, force)
1092 checkconflict(repo, mark, cur, force)
1092 marks[mark] = marks[rename]
1093 marks[mark] = marks[rename]
1093 if repo._activebookmark == rename and not inactive:
1094 if repo._activebookmark == rename and not inactive:
1094 bookmarks.activate(repo, mark)
1095 bookmarks.activate(repo, mark)
1095 del marks[rename]
1096 del marks[rename]
1096 elif names:
1097 elif names:
1097 tr = repo.transaction('bookmark')
1098 tr = repo.transaction('bookmark')
1098 newact = None
1099 newact = None
1099 for mark in names:
1100 for mark in names:
1100 mark = checkformat(mark)
1101 mark = checkformat(mark)
1101 if newact is None:
1102 if newact is None:
1102 newact = mark
1103 newact = mark
1103 if inactive and mark == repo._activebookmark:
1104 if inactive and mark == repo._activebookmark:
1104 bookmarks.deactivate(repo)
1105 bookmarks.deactivate(repo)
1105 return
1106 return
1106 tgt = cur
1107 tgt = cur
1107 if rev:
1108 if rev:
1108 tgt = scmutil.revsingle(repo, rev).node()
1109 tgt = scmutil.revsingle(repo, rev).node()
1109 checkconflict(repo, mark, cur, force, tgt)
1110 checkconflict(repo, mark, cur, force, tgt)
1110 marks[mark] = tgt
1111 marks[mark] = tgt
1111 if not inactive and cur == marks[newact] and not rev:
1112 if not inactive and cur == marks[newact] and not rev:
1112 bookmarks.activate(repo, newact)
1113 bookmarks.activate(repo, newact)
1113 elif cur != tgt and newact == repo._activebookmark:
1114 elif cur != tgt and newact == repo._activebookmark:
1114 bookmarks.deactivate(repo)
1115 bookmarks.deactivate(repo)
1115 elif inactive:
1116 elif inactive:
1116 if len(marks) == 0:
1117 if len(marks) == 0:
1117 ui.status(_("no bookmarks set\n"))
1118 ui.status(_("no bookmarks set\n"))
1118 elif not repo._activebookmark:
1119 elif not repo._activebookmark:
1119 ui.status(_("no active bookmark\n"))
1120 ui.status(_("no active bookmark\n"))
1120 else:
1121 else:
1121 bookmarks.deactivate(repo)
1122 bookmarks.deactivate(repo)
1122 if tr is not None:
1123 if tr is not None:
1123 marks.recordchange(tr)
1124 marks.recordchange(tr)
1124 tr.close()
1125 tr.close()
1125 finally:
1126 finally:
1126 lockmod.release(tr, lock, wlock)
1127 lockmod.release(tr, lock, wlock)
1127 else: # show bookmarks
1128 else: # show bookmarks
1128 fm = ui.formatter('bookmarks', opts)
1129 fm = ui.formatter('bookmarks', opts)
1129 hexfn = fm.hexfunc
1130 hexfn = fm.hexfunc
1130 marks = repo._bookmarks
1131 marks = repo._bookmarks
1131 if len(marks) == 0 and fm.isplain():
1132 if len(marks) == 0 and fm.isplain():
1132 ui.status(_("no bookmarks set\n"))
1133 ui.status(_("no bookmarks set\n"))
1133 for bmark, n in sorted(marks.iteritems()):
1134 for bmark, n in sorted(marks.iteritems()):
1134 active = repo._activebookmark
1135 active = repo._activebookmark
1135 if bmark == active:
1136 if bmark == active:
1136 prefix, label = '*', activebookmarklabel
1137 prefix, label = '*', activebookmarklabel
1137 else:
1138 else:
1138 prefix, label = ' ', ''
1139 prefix, label = ' ', ''
1139
1140
1140 fm.startitem()
1141 fm.startitem()
1141 if not ui.quiet:
1142 if not ui.quiet:
1142 fm.plain(' %s ' % prefix, label=label)
1143 fm.plain(' %s ' % prefix, label=label)
1143 fm.write('bookmark', '%s', bmark, label=label)
1144 fm.write('bookmark', '%s', bmark, label=label)
1144 pad = " " * (25 - encoding.colwidth(bmark))
1145 pad = " " * (25 - encoding.colwidth(bmark))
1145 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1146 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1146 repo.changelog.rev(n), hexfn(n), label=label)
1147 repo.changelog.rev(n), hexfn(n), label=label)
1147 fm.data(active=(bmark == active))
1148 fm.data(active=(bmark == active))
1148 fm.plain('\n')
1149 fm.plain('\n')
1149 fm.end()
1150 fm.end()
1150
1151
1151 @command('branch',
1152 @command('branch',
1152 [('f', 'force', None,
1153 [('f', 'force', None,
1153 _('set branch name even if it shadows an existing branch')),
1154 _('set branch name even if it shadows an existing branch')),
1154 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1155 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1155 _('[-fC] [NAME]'))
1156 _('[-fC] [NAME]'))
1156 def branch(ui, repo, label=None, **opts):
1157 def branch(ui, repo, label=None, **opts):
1157 """set or show the current branch name
1158 """set or show the current branch name
1158
1159
1159 .. note::
1160 .. note::
1160
1161
1161 Branch names are permanent and global. Use :hg:`bookmark` to create a
1162 Branch names are permanent and global. Use :hg:`bookmark` to create a
1162 light-weight bookmark instead. See :hg:`help glossary` for more
1163 light-weight bookmark instead. See :hg:`help glossary` for more
1163 information about named branches and bookmarks.
1164 information about named branches and bookmarks.
1164
1165
1165 With no argument, show the current branch name. With one argument,
1166 With no argument, show the current branch name. With one argument,
1166 set the working directory branch name (the branch will not exist
1167 set the working directory branch name (the branch will not exist
1167 in the repository until the next commit). Standard practice
1168 in the repository until the next commit). Standard practice
1168 recommends that primary development take place on the 'default'
1169 recommends that primary development take place on the 'default'
1169 branch.
1170 branch.
1170
1171
1171 Unless -f/--force is specified, branch will not let you set a
1172 Unless -f/--force is specified, branch will not let you set a
1172 branch name that already exists.
1173 branch name that already exists.
1173
1174
1174 Use -C/--clean to reset the working directory branch to that of
1175 Use -C/--clean to reset the working directory branch to that of
1175 the parent of the working directory, negating a previous branch
1176 the parent of the working directory, negating a previous branch
1176 change.
1177 change.
1177
1178
1178 Use the command :hg:`update` to switch to an existing branch. Use
1179 Use the command :hg:`update` to switch to an existing branch. Use
1179 :hg:`commit --close-branch` to mark this branch head as closed.
1180 :hg:`commit --close-branch` to mark this branch head as closed.
1180 When all heads of a branch are closed, the branch will be
1181 When all heads of a branch are closed, the branch will be
1181 considered closed.
1182 considered closed.
1182
1183
1183 Returns 0 on success.
1184 Returns 0 on success.
1184 """
1185 """
1185 opts = pycompat.byteskwargs(opts)
1186 opts = pycompat.byteskwargs(opts)
1186 if label:
1187 if label:
1187 label = label.strip()
1188 label = label.strip()
1188
1189
1189 if not opts.get('clean') and not label:
1190 if not opts.get('clean') and not label:
1190 ui.write("%s\n" % repo.dirstate.branch())
1191 ui.write("%s\n" % repo.dirstate.branch())
1191 return
1192 return
1192
1193
1193 with repo.wlock():
1194 with repo.wlock():
1194 if opts.get('clean'):
1195 if opts.get('clean'):
1195 label = repo[None].p1().branch()
1196 label = repo[None].p1().branch()
1196 repo.dirstate.setbranch(label)
1197 repo.dirstate.setbranch(label)
1197 ui.status(_('reset working directory to branch %s\n') % label)
1198 ui.status(_('reset working directory to branch %s\n') % label)
1198 elif label:
1199 elif label:
1199 if not opts.get('force') and label in repo.branchmap():
1200 if not opts.get('force') and label in repo.branchmap():
1200 if label not in [p.branch() for p in repo[None].parents()]:
1201 if label not in [p.branch() for p in repo[None].parents()]:
1201 raise error.Abort(_('a branch of the same name already'
1202 raise error.Abort(_('a branch of the same name already'
1202 ' exists'),
1203 ' exists'),
1203 # i18n: "it" refers to an existing branch
1204 # i18n: "it" refers to an existing branch
1204 hint=_("use 'hg update' to switch to it"))
1205 hint=_("use 'hg update' to switch to it"))
1205 scmutil.checknewlabel(repo, label, 'branch')
1206 scmutil.checknewlabel(repo, label, 'branch')
1206 repo.dirstate.setbranch(label)
1207 repo.dirstate.setbranch(label)
1207 ui.status(_('marked working directory as branch %s\n') % label)
1208 ui.status(_('marked working directory as branch %s\n') % label)
1208
1209
1209 # find any open named branches aside from default
1210 # find any open named branches aside from default
1210 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1211 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1211 if n != "default" and not c]
1212 if n != "default" and not c]
1212 if not others:
1213 if not others:
1213 ui.status(_('(branches are permanent and global, '
1214 ui.status(_('(branches are permanent and global, '
1214 'did you want a bookmark?)\n'))
1215 'did you want a bookmark?)\n'))
1215
1216
1216 @command('branches',
1217 @command('branches',
1217 [('a', 'active', False,
1218 [('a', 'active', False,
1218 _('show only branches that have unmerged heads (DEPRECATED)')),
1219 _('show only branches that have unmerged heads (DEPRECATED)')),
1219 ('c', 'closed', False, _('show normal and closed branches')),
1220 ('c', 'closed', False, _('show normal and closed branches')),
1220 ] + formatteropts,
1221 ] + formatteropts,
1221 _('[-c]'))
1222 _('[-c]'))
1222 def branches(ui, repo, active=False, closed=False, **opts):
1223 def branches(ui, repo, active=False, closed=False, **opts):
1223 """list repository named branches
1224 """list repository named branches
1224
1225
1225 List the repository's named branches, indicating which ones are
1226 List the repository's named branches, indicating which ones are
1226 inactive. If -c/--closed is specified, also list branches which have
1227 inactive. If -c/--closed is specified, also list branches which have
1227 been marked closed (see :hg:`commit --close-branch`).
1228 been marked closed (see :hg:`commit --close-branch`).
1228
1229
1229 Use the command :hg:`update` to switch to an existing branch.
1230 Use the command :hg:`update` to switch to an existing branch.
1230
1231
1231 Returns 0.
1232 Returns 0.
1232 """
1233 """
1233
1234
1234 opts = pycompat.byteskwargs(opts)
1235 opts = pycompat.byteskwargs(opts)
1235 ui.pager('branches')
1236 ui.pager('branches')
1236 fm = ui.formatter('branches', opts)
1237 fm = ui.formatter('branches', opts)
1237 hexfunc = fm.hexfunc
1238 hexfunc = fm.hexfunc
1238
1239
1239 allheads = set(repo.heads())
1240 allheads = set(repo.heads())
1240 branches = []
1241 branches = []
1241 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1242 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1242 isactive = not isclosed and bool(set(heads) & allheads)
1243 isactive = not isclosed and bool(set(heads) & allheads)
1243 branches.append((tag, repo[tip], isactive, not isclosed))
1244 branches.append((tag, repo[tip], isactive, not isclosed))
1244 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1245 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1245 reverse=True)
1246 reverse=True)
1246
1247
1247 for tag, ctx, isactive, isopen in branches:
1248 for tag, ctx, isactive, isopen in branches:
1248 if active and not isactive:
1249 if active and not isactive:
1249 continue
1250 continue
1250 if isactive:
1251 if isactive:
1251 label = 'branches.active'
1252 label = 'branches.active'
1252 notice = ''
1253 notice = ''
1253 elif not isopen:
1254 elif not isopen:
1254 if not closed:
1255 if not closed:
1255 continue
1256 continue
1256 label = 'branches.closed'
1257 label = 'branches.closed'
1257 notice = _(' (closed)')
1258 notice = _(' (closed)')
1258 else:
1259 else:
1259 label = 'branches.inactive'
1260 label = 'branches.inactive'
1260 notice = _(' (inactive)')
1261 notice = _(' (inactive)')
1261 current = (tag == repo.dirstate.branch())
1262 current = (tag == repo.dirstate.branch())
1262 if current:
1263 if current:
1263 label = 'branches.current'
1264 label = 'branches.current'
1264
1265
1265 fm.startitem()
1266 fm.startitem()
1266 fm.write('branch', '%s', tag, label=label)
1267 fm.write('branch', '%s', tag, label=label)
1267 rev = ctx.rev()
1268 rev = ctx.rev()
1268 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1269 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1269 fmt = ' ' * padsize + ' %d:%s'
1270 fmt = ' ' * padsize + ' %d:%s'
1270 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1271 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1271 label='log.changeset changeset.%s' % ctx.phasestr())
1272 label='log.changeset changeset.%s' % ctx.phasestr())
1272 fm.context(ctx=ctx)
1273 fm.context(ctx=ctx)
1273 fm.data(active=isactive, closed=not isopen, current=current)
1274 fm.data(active=isactive, closed=not isopen, current=current)
1274 if not ui.quiet:
1275 if not ui.quiet:
1275 fm.plain(notice)
1276 fm.plain(notice)
1276 fm.plain('\n')
1277 fm.plain('\n')
1277 fm.end()
1278 fm.end()
1278
1279
1279 @command('bundle',
1280 @command('bundle',
1280 [('f', 'force', None, _('run even when the destination is unrelated')),
1281 [('f', 'force', None, _('run even when the destination is unrelated')),
1281 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1282 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1282 _('REV')),
1283 _('REV')),
1283 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1284 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1284 _('BRANCH')),
1285 _('BRANCH')),
1285 ('', 'base', [],
1286 ('', 'base', [],
1286 _('a base changeset assumed to be available at the destination'),
1287 _('a base changeset assumed to be available at the destination'),
1287 _('REV')),
1288 _('REV')),
1288 ('a', 'all', None, _('bundle all changesets in the repository')),
1289 ('a', 'all', None, _('bundle all changesets in the repository')),
1289 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1290 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1290 ] + remoteopts,
1291 ] + remoteopts,
1291 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1292 _('[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1292 def bundle(ui, repo, fname, dest=None, **opts):
1293 def bundle(ui, repo, fname, dest=None, **opts):
1293 """create a bundle file
1294 """create a bundle file
1294
1295
1295 Generate a bundle file containing data to be added to a repository.
1296 Generate a bundle file containing data to be added to a repository.
1296
1297
1297 To create a bundle containing all changesets, use -a/--all
1298 To create a bundle containing all changesets, use -a/--all
1298 (or --base null). Otherwise, hg assumes the destination will have
1299 (or --base null). Otherwise, hg assumes the destination will have
1299 all the nodes you specify with --base parameters. Otherwise, hg
1300 all the nodes you specify with --base parameters. Otherwise, hg
1300 will assume the repository has all the nodes in destination, or
1301 will assume the repository has all the nodes in destination, or
1301 default-push/default if no destination is specified.
1302 default-push/default if no destination is specified.
1302
1303
1303 You can change bundle format with the -t/--type option. See
1304 You can change bundle format with the -t/--type option. See
1304 :hg:`help bundlespec` for documentation on this format. By default,
1305 :hg:`help bundlespec` for documentation on this format. By default,
1305 the most appropriate format is used and compression defaults to
1306 the most appropriate format is used and compression defaults to
1306 bzip2.
1307 bzip2.
1307
1308
1308 The bundle file can then be transferred using conventional means
1309 The bundle file can then be transferred using conventional means
1309 and applied to another repository with the unbundle or pull
1310 and applied to another repository with the unbundle or pull
1310 command. This is useful when direct push and pull are not
1311 command. This is useful when direct push and pull are not
1311 available or when exporting an entire repository is undesirable.
1312 available or when exporting an entire repository is undesirable.
1312
1313
1313 Applying bundles preserves all changeset contents including
1314 Applying bundles preserves all changeset contents including
1314 permissions, copy/rename information, and revision history.
1315 permissions, copy/rename information, and revision history.
1315
1316
1316 Returns 0 on success, 1 if no changes found.
1317 Returns 0 on success, 1 if no changes found.
1317 """
1318 """
1318 opts = pycompat.byteskwargs(opts)
1319 opts = pycompat.byteskwargs(opts)
1319 revs = None
1320 revs = None
1320 if 'rev' in opts:
1321 if 'rev' in opts:
1321 revstrings = opts['rev']
1322 revstrings = opts['rev']
1322 revs = scmutil.revrange(repo, revstrings)
1323 revs = scmutil.revrange(repo, revstrings)
1323 if revstrings and not revs:
1324 if revstrings and not revs:
1324 raise error.Abort(_('no commits to bundle'))
1325 raise error.Abort(_('no commits to bundle'))
1325
1326
1326 bundletype = opts.get('type', 'bzip2').lower()
1327 bundletype = opts.get('type', 'bzip2').lower()
1327 try:
1328 try:
1328 bcompression, cgversion, params = exchange.parsebundlespec(
1329 bcompression, cgversion, params = exchange.parsebundlespec(
1329 repo, bundletype, strict=False)
1330 repo, bundletype, strict=False)
1330 except error.UnsupportedBundleSpecification as e:
1331 except error.UnsupportedBundleSpecification as e:
1331 raise error.Abort(str(e),
1332 raise error.Abort(str(e),
1332 hint=_("see 'hg help bundlespec' for supported "
1333 hint=_("see 'hg help bundlespec' for supported "
1333 "values for --type"))
1334 "values for --type"))
1334
1335
1335 # Packed bundles are a pseudo bundle format for now.
1336 # Packed bundles are a pseudo bundle format for now.
1336 if cgversion == 's1':
1337 if cgversion == 's1':
1337 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1338 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1338 hint=_("use 'hg debugcreatestreamclonebundle'"))
1339 hint=_("use 'hg debugcreatestreamclonebundle'"))
1339
1340
1340 if opts.get('all'):
1341 if opts.get('all'):
1341 if dest:
1342 if dest:
1342 raise error.Abort(_("--all is incompatible with specifying "
1343 raise error.Abort(_("--all is incompatible with specifying "
1343 "a destination"))
1344 "a destination"))
1344 if opts.get('base'):
1345 if opts.get('base'):
1345 ui.warn(_("ignoring --base because --all was specified\n"))
1346 ui.warn(_("ignoring --base because --all was specified\n"))
1346 base = ['null']
1347 base = ['null']
1347 else:
1348 else:
1348 base = scmutil.revrange(repo, opts.get('base'))
1349 base = scmutil.revrange(repo, opts.get('base'))
1349 if cgversion not in changegroup.supportedoutgoingversions(repo):
1350 if cgversion not in changegroup.supportedoutgoingversions(repo):
1350 raise error.Abort(_("repository does not support bundle version %s") %
1351 raise error.Abort(_("repository does not support bundle version %s") %
1351 cgversion)
1352 cgversion)
1352
1353
1353 if base:
1354 if base:
1354 if dest:
1355 if dest:
1355 raise error.Abort(_("--base is incompatible with specifying "
1356 raise error.Abort(_("--base is incompatible with specifying "
1356 "a destination"))
1357 "a destination"))
1357 common = [repo.lookup(rev) for rev in base]
1358 common = [repo.lookup(rev) for rev in base]
1358 heads = revs and map(repo.lookup, revs) or None
1359 heads = revs and map(repo.lookup, revs) or None
1359 outgoing = discovery.outgoing(repo, common, heads)
1360 outgoing = discovery.outgoing(repo, common, heads)
1360 else:
1361 else:
1361 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1362 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1362 dest, branches = hg.parseurl(dest, opts.get('branch'))
1363 dest, branches = hg.parseurl(dest, opts.get('branch'))
1363 other = hg.peer(repo, opts, dest)
1364 other = hg.peer(repo, opts, dest)
1364 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1365 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1365 heads = revs and map(repo.lookup, revs) or revs
1366 heads = revs and map(repo.lookup, revs) or revs
1366 outgoing = discovery.findcommonoutgoing(repo, other,
1367 outgoing = discovery.findcommonoutgoing(repo, other,
1367 onlyheads=heads,
1368 onlyheads=heads,
1368 force=opts.get('force'),
1369 force=opts.get('force'),
1369 portable=True)
1370 portable=True)
1370 cg = changegroup.getchangegroup(repo, 'bundle', outgoing, version=cgversion)
1371 cg = changegroup.getchangegroup(repo, 'bundle', outgoing, version=cgversion)
1371 if not cg:
1372 if not cg:
1372 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1373 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1373 return 1
1374 return 1
1374
1375
1375 if cgversion == '01': #bundle1
1376 if cgversion == '01': #bundle1
1376 if bcompression is None:
1377 if bcompression is None:
1377 bcompression = 'UN'
1378 bcompression = 'UN'
1378 bversion = 'HG10' + bcompression
1379 bversion = 'HG10' + bcompression
1379 bcompression = None
1380 bcompression = None
1380 elif cgversion in ('02', '03'):
1381 elif cgversion in ('02', '03'):
1381 bversion = 'HG20'
1382 bversion = 'HG20'
1382 else:
1383 else:
1383 raise error.ProgrammingError(
1384 raise error.ProgrammingError(
1384 'bundle: unexpected changegroup version %s' % cgversion)
1385 'bundle: unexpected changegroup version %s' % cgversion)
1385
1386
1386 # TODO compression options should be derived from bundlespec parsing.
1387 # TODO compression options should be derived from bundlespec parsing.
1387 # This is a temporary hack to allow adjusting bundle compression
1388 # This is a temporary hack to allow adjusting bundle compression
1388 # level without a) formalizing the bundlespec changes to declare it
1389 # level without a) formalizing the bundlespec changes to declare it
1389 # b) introducing a command flag.
1390 # b) introducing a command flag.
1390 compopts = {}
1391 compopts = {}
1391 complevel = ui.configint('experimental', 'bundlecomplevel')
1392 complevel = ui.configint('experimental', 'bundlecomplevel')
1392 if complevel is not None:
1393 if complevel is not None:
1393 compopts['level'] = complevel
1394 compopts['level'] = complevel
1394
1395
1395 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1396 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1396 compopts=compopts)
1397 compopts=compopts)
1397
1398
1398 @command('cat',
1399 @command('cat',
1399 [('o', 'output', '',
1400 [('o', 'output', '',
1400 _('print output to file with formatted name'), _('FORMAT')),
1401 _('print output to file with formatted name'), _('FORMAT')),
1401 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('r', 'rev', '', _('print the given revision'), _('REV')),
1402 ('', 'decode', None, _('apply any matching decode filter')),
1403 ('', 'decode', None, _('apply any matching decode filter')),
1403 ] + walkopts,
1404 ] + walkopts,
1404 _('[OPTION]... FILE...'),
1405 _('[OPTION]... FILE...'),
1405 inferrepo=True)
1406 inferrepo=True)
1406 def cat(ui, repo, file1, *pats, **opts):
1407 def cat(ui, repo, file1, *pats, **opts):
1407 """output the current or given revision of files
1408 """output the current or given revision of files
1408
1409
1409 Print the specified files as they were at the given revision. If
1410 Print the specified files as they were at the given revision. If
1410 no revision is given, the parent of the working directory is used.
1411 no revision is given, the parent of the working directory is used.
1411
1412
1412 Output may be to a file, in which case the name of the file is
1413 Output may be to a file, in which case the name of the file is
1413 given using a format string. The formatting rules as follows:
1414 given using a format string. The formatting rules as follows:
1414
1415
1415 :``%%``: literal "%" character
1416 :``%%``: literal "%" character
1416 :``%s``: basename of file being printed
1417 :``%s``: basename of file being printed
1417 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%d``: dirname of file being printed, or '.' if in repository root
1418 :``%p``: root-relative path name of file being printed
1419 :``%p``: root-relative path name of file being printed
1419 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%H``: changeset hash (40 hexadecimal digits)
1420 :``%R``: changeset revision number
1421 :``%R``: changeset revision number
1421 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%h``: short-form changeset hash (12 hexadecimal digits)
1422 :``%r``: zero-padded changeset revision number
1423 :``%r``: zero-padded changeset revision number
1423 :``%b``: basename of the exporting repository
1424 :``%b``: basename of the exporting repository
1424
1425
1425 Returns 0 on success.
1426 Returns 0 on success.
1426 """
1427 """
1427 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 ctx = scmutil.revsingle(repo, opts.get('rev'))
1428 m = scmutil.match(ctx, (file1,) + pats, opts)
1429 m = scmutil.match(ctx, (file1,) + pats, opts)
1429
1430
1430 ui.pager('cat')
1431 ui.pager('cat')
1431 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1432 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1432
1433
1433 @command('^clone',
1434 @command('^clone',
1434 [('U', 'noupdate', None, _('the clone will include an empty working '
1435 [('U', 'noupdate', None, _('the clone will include an empty working '
1435 'directory (only a repository)')),
1436 'directory (only a repository)')),
1436 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1437 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1437 _('REV')),
1438 _('REV')),
1438 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1439 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1439 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1440 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1440 ('', 'pull', None, _('use pull protocol to copy metadata')),
1441 ('', 'pull', None, _('use pull protocol to copy metadata')),
1441 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1442 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1442 ] + remoteopts,
1443 ] + remoteopts,
1443 _('[OPTION]... SOURCE [DEST]'),
1444 _('[OPTION]... SOURCE [DEST]'),
1444 norepo=True)
1445 norepo=True)
1445 def clone(ui, source, dest=None, **opts):
1446 def clone(ui, source, dest=None, **opts):
1446 """make a copy of an existing repository
1447 """make a copy of an existing repository
1447
1448
1448 Create a copy of an existing repository in a new directory.
1449 Create a copy of an existing repository in a new directory.
1449
1450
1450 If no destination directory name is specified, it defaults to the
1451 If no destination directory name is specified, it defaults to the
1451 basename of the source.
1452 basename of the source.
1452
1453
1453 The location of the source is added to the new repository's
1454 The location of the source is added to the new repository's
1454 ``.hg/hgrc`` file, as the default to be used for future pulls.
1455 ``.hg/hgrc`` file, as the default to be used for future pulls.
1455
1456
1456 Only local paths and ``ssh://`` URLs are supported as
1457 Only local paths and ``ssh://`` URLs are supported as
1457 destinations. For ``ssh://`` destinations, no working directory or
1458 destinations. For ``ssh://`` destinations, no working directory or
1458 ``.hg/hgrc`` will be created on the remote side.
1459 ``.hg/hgrc`` will be created on the remote side.
1459
1460
1460 If the source repository has a bookmark called '@' set, that
1461 If the source repository has a bookmark called '@' set, that
1461 revision will be checked out in the new repository by default.
1462 revision will be checked out in the new repository by default.
1462
1463
1463 To check out a particular version, use -u/--update, or
1464 To check out a particular version, use -u/--update, or
1464 -U/--noupdate to create a clone with no working directory.
1465 -U/--noupdate to create a clone with no working directory.
1465
1466
1466 To pull only a subset of changesets, specify one or more revisions
1467 To pull only a subset of changesets, specify one or more revisions
1467 identifiers with -r/--rev or branches with -b/--branch. The
1468 identifiers with -r/--rev or branches with -b/--branch. The
1468 resulting clone will contain only the specified changesets and
1469 resulting clone will contain only the specified changesets and
1469 their ancestors. These options (or 'clone src#rev dest') imply
1470 their ancestors. These options (or 'clone src#rev dest') imply
1470 --pull, even for local source repositories.
1471 --pull, even for local source repositories.
1471
1472
1472 .. note::
1473 .. note::
1473
1474
1474 Specifying a tag will include the tagged changeset but not the
1475 Specifying a tag will include the tagged changeset but not the
1475 changeset containing the tag.
1476 changeset containing the tag.
1476
1477
1477 .. container:: verbose
1478 .. container:: verbose
1478
1479
1479 For efficiency, hardlinks are used for cloning whenever the
1480 For efficiency, hardlinks are used for cloning whenever the
1480 source and destination are on the same filesystem (note this
1481 source and destination are on the same filesystem (note this
1481 applies only to the repository data, not to the working
1482 applies only to the repository data, not to the working
1482 directory). Some filesystems, such as AFS, implement hardlinking
1483 directory). Some filesystems, such as AFS, implement hardlinking
1483 incorrectly, but do not report errors. In these cases, use the
1484 incorrectly, but do not report errors. In these cases, use the
1484 --pull option to avoid hardlinking.
1485 --pull option to avoid hardlinking.
1485
1486
1486 In some cases, you can clone repositories and the working
1487 In some cases, you can clone repositories and the working
1487 directory using full hardlinks with ::
1488 directory using full hardlinks with ::
1488
1489
1489 $ cp -al REPO REPOCLONE
1490 $ cp -al REPO REPOCLONE
1490
1491
1491 This is the fastest way to clone, but it is not always safe. The
1492 This is the fastest way to clone, but it is not always safe. The
1492 operation is not atomic (making sure REPO is not modified during
1493 operation is not atomic (making sure REPO is not modified during
1493 the operation is up to you) and you have to make sure your
1494 the operation is up to you) and you have to make sure your
1494 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1495 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1495 so). Also, this is not compatible with certain extensions that
1496 so). Also, this is not compatible with certain extensions that
1496 place their metadata under the .hg directory, such as mq.
1497 place their metadata under the .hg directory, such as mq.
1497
1498
1498 Mercurial will update the working directory to the first applicable
1499 Mercurial will update the working directory to the first applicable
1499 revision from this list:
1500 revision from this list:
1500
1501
1501 a) null if -U or the source repository has no changesets
1502 a) null if -U or the source repository has no changesets
1502 b) if -u . and the source repository is local, the first parent of
1503 b) if -u . and the source repository is local, the first parent of
1503 the source repository's working directory
1504 the source repository's working directory
1504 c) the changeset specified with -u (if a branch name, this means the
1505 c) the changeset specified with -u (if a branch name, this means the
1505 latest head of that branch)
1506 latest head of that branch)
1506 d) the changeset specified with -r
1507 d) the changeset specified with -r
1507 e) the tipmost head specified with -b
1508 e) the tipmost head specified with -b
1508 f) the tipmost head specified with the url#branch source syntax
1509 f) the tipmost head specified with the url#branch source syntax
1509 g) the revision marked with the '@' bookmark, if present
1510 g) the revision marked with the '@' bookmark, if present
1510 h) the tipmost head of the default branch
1511 h) the tipmost head of the default branch
1511 i) tip
1512 i) tip
1512
1513
1513 When cloning from servers that support it, Mercurial may fetch
1514 When cloning from servers that support it, Mercurial may fetch
1514 pre-generated data from a server-advertised URL. When this is done,
1515 pre-generated data from a server-advertised URL. When this is done,
1515 hooks operating on incoming changesets and changegroups may fire twice,
1516 hooks operating on incoming changesets and changegroups may fire twice,
1516 once for the bundle fetched from the URL and another for any additional
1517 once for the bundle fetched from the URL and another for any additional
1517 data not fetched from this URL. In addition, if an error occurs, the
1518 data not fetched from this URL. In addition, if an error occurs, the
1518 repository may be rolled back to a partial clone. This behavior may
1519 repository may be rolled back to a partial clone. This behavior may
1519 change in future releases. See :hg:`help -e clonebundles` for more.
1520 change in future releases. See :hg:`help -e clonebundles` for more.
1520
1521
1521 Examples:
1522 Examples:
1522
1523
1523 - clone a remote repository to a new directory named hg/::
1524 - clone a remote repository to a new directory named hg/::
1524
1525
1525 hg clone https://www.mercurial-scm.org/repo/hg/
1526 hg clone https://www.mercurial-scm.org/repo/hg/
1526
1527
1527 - create a lightweight local clone::
1528 - create a lightweight local clone::
1528
1529
1529 hg clone project/ project-feature/
1530 hg clone project/ project-feature/
1530
1531
1531 - clone from an absolute path on an ssh server (note double-slash)::
1532 - clone from an absolute path on an ssh server (note double-slash)::
1532
1533
1533 hg clone ssh://user@server//home/projects/alpha/
1534 hg clone ssh://user@server//home/projects/alpha/
1534
1535
1535 - do a high-speed clone over a LAN while checking out a
1536 - do a high-speed clone over a LAN while checking out a
1536 specified version::
1537 specified version::
1537
1538
1538 hg clone --uncompressed http://server/repo -u 1.5
1539 hg clone --uncompressed http://server/repo -u 1.5
1539
1540
1540 - create a repository without changesets after a particular revision::
1541 - create a repository without changesets after a particular revision::
1541
1542
1542 hg clone -r 04e544 experimental/ good/
1543 hg clone -r 04e544 experimental/ good/
1543
1544
1544 - clone (and track) a particular named branch::
1545 - clone (and track) a particular named branch::
1545
1546
1546 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1547 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1547
1548
1548 See :hg:`help urls` for details on specifying URLs.
1549 See :hg:`help urls` for details on specifying URLs.
1549
1550
1550 Returns 0 on success.
1551 Returns 0 on success.
1551 """
1552 """
1552 opts = pycompat.byteskwargs(opts)
1553 opts = pycompat.byteskwargs(opts)
1553 if opts.get('noupdate') and opts.get('updaterev'):
1554 if opts.get('noupdate') and opts.get('updaterev'):
1554 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1555 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1555
1556
1556 r = hg.clone(ui, opts, source, dest,
1557 r = hg.clone(ui, opts, source, dest,
1557 pull=opts.get('pull'),
1558 pull=opts.get('pull'),
1558 stream=opts.get('uncompressed'),
1559 stream=opts.get('uncompressed'),
1559 rev=opts.get('rev'),
1560 rev=opts.get('rev'),
1560 update=opts.get('updaterev') or not opts.get('noupdate'),
1561 update=opts.get('updaterev') or not opts.get('noupdate'),
1561 branch=opts.get('branch'),
1562 branch=opts.get('branch'),
1562 shareopts=opts.get('shareopts'))
1563 shareopts=opts.get('shareopts'))
1563
1564
1564 return r is None
1565 return r is None
1565
1566
1566 @command('^commit|ci',
1567 @command('^commit|ci',
1567 [('A', 'addremove', None,
1568 [('A', 'addremove', None,
1568 _('mark new/missing files as added/removed before committing')),
1569 _('mark new/missing files as added/removed before committing')),
1569 ('', 'close-branch', None,
1570 ('', 'close-branch', None,
1570 _('mark a branch head as closed')),
1571 _('mark a branch head as closed')),
1571 ('', 'amend', None, _('amend the parent of the working directory')),
1572 ('', 'amend', None, _('amend the parent of the working directory')),
1572 ('s', 'secret', None, _('use the secret phase for committing')),
1573 ('s', 'secret', None, _('use the secret phase for committing')),
1573 ('e', 'edit', None, _('invoke editor on commit messages')),
1574 ('e', 'edit', None, _('invoke editor on commit messages')),
1574 ('i', 'interactive', None, _('use interactive mode')),
1575 ('i', 'interactive', None, _('use interactive mode')),
1575 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1576 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1576 _('[OPTION]... [FILE]...'),
1577 _('[OPTION]... [FILE]...'),
1577 inferrepo=True)
1578 inferrepo=True)
1578 def commit(ui, repo, *pats, **opts):
1579 def commit(ui, repo, *pats, **opts):
1579 """commit the specified files or all outstanding changes
1580 """commit the specified files or all outstanding changes
1580
1581
1581 Commit changes to the given files into the repository. Unlike a
1582 Commit changes to the given files into the repository. Unlike a
1582 centralized SCM, this operation is a local operation. See
1583 centralized SCM, this operation is a local operation. See
1583 :hg:`push` for a way to actively distribute your changes.
1584 :hg:`push` for a way to actively distribute your changes.
1584
1585
1585 If a list of files is omitted, all changes reported by :hg:`status`
1586 If a list of files is omitted, all changes reported by :hg:`status`
1586 will be committed.
1587 will be committed.
1587
1588
1588 If you are committing the result of a merge, do not provide any
1589 If you are committing the result of a merge, do not provide any
1589 filenames or -I/-X filters.
1590 filenames or -I/-X filters.
1590
1591
1591 If no commit message is specified, Mercurial starts your
1592 If no commit message is specified, Mercurial starts your
1592 configured editor where you can enter a message. In case your
1593 configured editor where you can enter a message. In case your
1593 commit fails, you will find a backup of your message in
1594 commit fails, you will find a backup of your message in
1594 ``.hg/last-message.txt``.
1595 ``.hg/last-message.txt``.
1595
1596
1596 The --close-branch flag can be used to mark the current branch
1597 The --close-branch flag can be used to mark the current branch
1597 head closed. When all heads of a branch are closed, the branch
1598 head closed. When all heads of a branch are closed, the branch
1598 will be considered closed and no longer listed.
1599 will be considered closed and no longer listed.
1599
1600
1600 The --amend flag can be used to amend the parent of the
1601 The --amend flag can be used to amend the parent of the
1601 working directory with a new commit that contains the changes
1602 working directory with a new commit that contains the changes
1602 in the parent in addition to those currently reported by :hg:`status`,
1603 in the parent in addition to those currently reported by :hg:`status`,
1603 if there are any. The old commit is stored in a backup bundle in
1604 if there are any. The old commit is stored in a backup bundle in
1604 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1605 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1605 on how to restore it).
1606 on how to restore it).
1606
1607
1607 Message, user and date are taken from the amended commit unless
1608 Message, user and date are taken from the amended commit unless
1608 specified. When a message isn't specified on the command line,
1609 specified. When a message isn't specified on the command line,
1609 the editor will open with the message of the amended commit.
1610 the editor will open with the message of the amended commit.
1610
1611
1611 It is not possible to amend public changesets (see :hg:`help phases`)
1612 It is not possible to amend public changesets (see :hg:`help phases`)
1612 or changesets that have children.
1613 or changesets that have children.
1613
1614
1614 See :hg:`help dates` for a list of formats valid for -d/--date.
1615 See :hg:`help dates` for a list of formats valid for -d/--date.
1615
1616
1616 Returns 0 on success, 1 if nothing changed.
1617 Returns 0 on success, 1 if nothing changed.
1617
1618
1618 .. container:: verbose
1619 .. container:: verbose
1619
1620
1620 Examples:
1621 Examples:
1621
1622
1622 - commit all files ending in .py::
1623 - commit all files ending in .py::
1623
1624
1624 hg commit --include "set:**.py"
1625 hg commit --include "set:**.py"
1625
1626
1626 - commit all non-binary files::
1627 - commit all non-binary files::
1627
1628
1628 hg commit --exclude "set:binary()"
1629 hg commit --exclude "set:binary()"
1629
1630
1630 - amend the current commit and set the date to now::
1631 - amend the current commit and set the date to now::
1631
1632
1632 hg commit --amend --date now
1633 hg commit --amend --date now
1633 """
1634 """
1634 wlock = lock = None
1635 wlock = lock = None
1635 try:
1636 try:
1636 wlock = repo.wlock()
1637 wlock = repo.wlock()
1637 lock = repo.lock()
1638 lock = repo.lock()
1638 return _docommit(ui, repo, *pats, **opts)
1639 return _docommit(ui, repo, *pats, **opts)
1639 finally:
1640 finally:
1640 release(lock, wlock)
1641 release(lock, wlock)
1641
1642
1642 def _docommit(ui, repo, *pats, **opts):
1643 def _docommit(ui, repo, *pats, **opts):
1643 if opts.get(r'interactive'):
1644 if opts.get(r'interactive'):
1644 opts.pop(r'interactive')
1645 opts.pop(r'interactive')
1645 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1646 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1646 cmdutil.recordfilter, *pats,
1647 cmdutil.recordfilter, *pats,
1647 **opts)
1648 **opts)
1648 # ret can be 0 (no changes to record) or the value returned by
1649 # ret can be 0 (no changes to record) or the value returned by
1649 # commit(), 1 if nothing changed or None on success.
1650 # commit(), 1 if nothing changed or None on success.
1650 return 1 if ret == 0 else ret
1651 return 1 if ret == 0 else ret
1651
1652
1652 opts = pycompat.byteskwargs(opts)
1653 opts = pycompat.byteskwargs(opts)
1653 if opts.get('subrepos'):
1654 if opts.get('subrepos'):
1654 if opts.get('amend'):
1655 if opts.get('amend'):
1655 raise error.Abort(_('cannot amend with --subrepos'))
1656 raise error.Abort(_('cannot amend with --subrepos'))
1656 # Let --subrepos on the command line override config setting.
1657 # Let --subrepos on the command line override config setting.
1657 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1658 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1658
1659
1659 cmdutil.checkunfinished(repo, commit=True)
1660 cmdutil.checkunfinished(repo, commit=True)
1660
1661
1661 branch = repo[None].branch()
1662 branch = repo[None].branch()
1662 bheads = repo.branchheads(branch)
1663 bheads = repo.branchheads(branch)
1663
1664
1664 extra = {}
1665 extra = {}
1665 if opts.get('close_branch'):
1666 if opts.get('close_branch'):
1666 extra['close'] = 1
1667 extra['close'] = 1
1667
1668
1668 if not bheads:
1669 if not bheads:
1669 raise error.Abort(_('can only close branch heads'))
1670 raise error.Abort(_('can only close branch heads'))
1670 elif opts.get('amend'):
1671 elif opts.get('amend'):
1671 if repo[None].parents()[0].p1().branch() != branch and \
1672 if repo[None].parents()[0].p1().branch() != branch and \
1672 repo[None].parents()[0].p2().branch() != branch:
1673 repo[None].parents()[0].p2().branch() != branch:
1673 raise error.Abort(_('can only close branch heads'))
1674 raise error.Abort(_('can only close branch heads'))
1674
1675
1675 if opts.get('amend'):
1676 if opts.get('amend'):
1676 if ui.configbool('ui', 'commitsubrepos'):
1677 if ui.configbool('ui', 'commitsubrepos'):
1677 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1678 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1678
1679
1679 old = repo['.']
1680 old = repo['.']
1680 if not old.mutable():
1681 if not old.mutable():
1681 raise error.Abort(_('cannot amend public changesets'))
1682 raise error.Abort(_('cannot amend public changesets'))
1682 if len(repo[None].parents()) > 1:
1683 if len(repo[None].parents()) > 1:
1683 raise error.Abort(_('cannot amend while merging'))
1684 raise error.Abort(_('cannot amend while merging'))
1684 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1685 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1685 if not allowunstable and old.children():
1686 if not allowunstable and old.children():
1686 raise error.Abort(_('cannot amend changeset with children'))
1687 raise error.Abort(_('cannot amend changeset with children'))
1687
1688
1688 # Currently histedit gets confused if an amend happens while histedit
1689 # Currently histedit gets confused if an amend happens while histedit
1689 # is in progress. Since we have a checkunfinished command, we are
1690 # is in progress. Since we have a checkunfinished command, we are
1690 # temporarily honoring it.
1691 # temporarily honoring it.
1691 #
1692 #
1692 # Note: eventually this guard will be removed. Please do not expect
1693 # Note: eventually this guard will be removed. Please do not expect
1693 # this behavior to remain.
1694 # this behavior to remain.
1694 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1695 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1695 cmdutil.checkunfinished(repo)
1696 cmdutil.checkunfinished(repo)
1696
1697
1697 # commitfunc is used only for temporary amend commit by cmdutil.amend
1698 # commitfunc is used only for temporary amend commit by cmdutil.amend
1698 def commitfunc(ui, repo, message, match, opts):
1699 def commitfunc(ui, repo, message, match, opts):
1699 return repo.commit(message,
1700 return repo.commit(message,
1700 opts.get('user') or old.user(),
1701 opts.get('user') or old.user(),
1701 opts.get('date') or old.date(),
1702 opts.get('date') or old.date(),
1702 match,
1703 match,
1703 extra=extra)
1704 extra=extra)
1704
1705
1705 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1706 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1706 if node == old.node():
1707 if node == old.node():
1707 ui.status(_("nothing changed\n"))
1708 ui.status(_("nothing changed\n"))
1708 return 1
1709 return 1
1709 else:
1710 else:
1710 def commitfunc(ui, repo, message, match, opts):
1711 def commitfunc(ui, repo, message, match, opts):
1711 overrides = {}
1712 overrides = {}
1712 if opts.get('secret'):
1713 if opts.get('secret'):
1713 overrides[('phases', 'new-commit')] = 'secret'
1714 overrides[('phases', 'new-commit')] = 'secret'
1714
1715
1715 baseui = repo.baseui
1716 baseui = repo.baseui
1716 with baseui.configoverride(overrides, 'commit'):
1717 with baseui.configoverride(overrides, 'commit'):
1717 with ui.configoverride(overrides, 'commit'):
1718 with ui.configoverride(overrides, 'commit'):
1718 editform = cmdutil.mergeeditform(repo[None],
1719 editform = cmdutil.mergeeditform(repo[None],
1719 'commit.normal')
1720 'commit.normal')
1720 editor = cmdutil.getcommiteditor(
1721 editor = cmdutil.getcommiteditor(
1721 editform=editform, **pycompat.strkwargs(opts))
1722 editform=editform, **pycompat.strkwargs(opts))
1722 return repo.commit(message,
1723 return repo.commit(message,
1723 opts.get('user'),
1724 opts.get('user'),
1724 opts.get('date'),
1725 opts.get('date'),
1725 match,
1726 match,
1726 editor=editor,
1727 editor=editor,
1727 extra=extra)
1728 extra=extra)
1728
1729
1729 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1730 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1730
1731
1731 if not node:
1732 if not node:
1732 stat = cmdutil.postcommitstatus(repo, pats, opts)
1733 stat = cmdutil.postcommitstatus(repo, pats, opts)
1733 if stat[3]:
1734 if stat[3]:
1734 ui.status(_("nothing changed (%d missing files, see "
1735 ui.status(_("nothing changed (%d missing files, see "
1735 "'hg status')\n") % len(stat[3]))
1736 "'hg status')\n") % len(stat[3]))
1736 else:
1737 else:
1737 ui.status(_("nothing changed\n"))
1738 ui.status(_("nothing changed\n"))
1738 return 1
1739 return 1
1739
1740
1740 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1741 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1741
1742
1742 @command('config|showconfig|debugconfig',
1743 @command('config|showconfig|debugconfig',
1743 [('u', 'untrusted', None, _('show untrusted configuration options')),
1744 [('u', 'untrusted', None, _('show untrusted configuration options')),
1744 ('e', 'edit', None, _('edit user config')),
1745 ('e', 'edit', None, _('edit user config')),
1745 ('l', 'local', None, _('edit repository config')),
1746 ('l', 'local', None, _('edit repository config')),
1746 ('g', 'global', None, _('edit global config'))] + formatteropts,
1747 ('g', 'global', None, _('edit global config'))] + formatteropts,
1747 _('[-u] [NAME]...'),
1748 _('[-u] [NAME]...'),
1748 optionalrepo=True)
1749 optionalrepo=True)
1749 def config(ui, repo, *values, **opts):
1750 def config(ui, repo, *values, **opts):
1750 """show combined config settings from all hgrc files
1751 """show combined config settings from all hgrc files
1751
1752
1752 With no arguments, print names and values of all config items.
1753 With no arguments, print names and values of all config items.
1753
1754
1754 With one argument of the form section.name, print just the value
1755 With one argument of the form section.name, print just the value
1755 of that config item.
1756 of that config item.
1756
1757
1757 With multiple arguments, print names and values of all config
1758 With multiple arguments, print names and values of all config
1758 items with matching section names.
1759 items with matching section names.
1759
1760
1760 With --edit, start an editor on the user-level config file. With
1761 With --edit, start an editor on the user-level config file. With
1761 --global, edit the system-wide config file. With --local, edit the
1762 --global, edit the system-wide config file. With --local, edit the
1762 repository-level config file.
1763 repository-level config file.
1763
1764
1764 With --debug, the source (filename and line number) is printed
1765 With --debug, the source (filename and line number) is printed
1765 for each config item.
1766 for each config item.
1766
1767
1767 See :hg:`help config` for more information about config files.
1768 See :hg:`help config` for more information about config files.
1768
1769
1769 Returns 0 on success, 1 if NAME does not exist.
1770 Returns 0 on success, 1 if NAME does not exist.
1770
1771
1771 """
1772 """
1772
1773
1773 opts = pycompat.byteskwargs(opts)
1774 opts = pycompat.byteskwargs(opts)
1774 if opts.get('edit') or opts.get('local') or opts.get('global'):
1775 if opts.get('edit') or opts.get('local') or opts.get('global'):
1775 if opts.get('local') and opts.get('global'):
1776 if opts.get('local') and opts.get('global'):
1776 raise error.Abort(_("can't use --local and --global together"))
1777 raise error.Abort(_("can't use --local and --global together"))
1777
1778
1778 if opts.get('local'):
1779 if opts.get('local'):
1779 if not repo:
1780 if not repo:
1780 raise error.Abort(_("can't use --local outside a repository"))
1781 raise error.Abort(_("can't use --local outside a repository"))
1781 paths = [repo.vfs.join('hgrc')]
1782 paths = [repo.vfs.join('hgrc')]
1782 elif opts.get('global'):
1783 elif opts.get('global'):
1783 paths = rcutil.systemrcpath()
1784 paths = rcutil.systemrcpath()
1784 else:
1785 else:
1785 paths = rcutil.userrcpath()
1786 paths = rcutil.userrcpath()
1786
1787
1787 for f in paths:
1788 for f in paths:
1788 if os.path.exists(f):
1789 if os.path.exists(f):
1789 break
1790 break
1790 else:
1791 else:
1791 if opts.get('global'):
1792 if opts.get('global'):
1792 samplehgrc = uimod.samplehgrcs['global']
1793 samplehgrc = uimod.samplehgrcs['global']
1793 elif opts.get('local'):
1794 elif opts.get('local'):
1794 samplehgrc = uimod.samplehgrcs['local']
1795 samplehgrc = uimod.samplehgrcs['local']
1795 else:
1796 else:
1796 samplehgrc = uimod.samplehgrcs['user']
1797 samplehgrc = uimod.samplehgrcs['user']
1797
1798
1798 f = paths[0]
1799 f = paths[0]
1799 fp = open(f, "w")
1800 fp = open(f, "w")
1800 fp.write(samplehgrc)
1801 fp.write(samplehgrc)
1801 fp.close()
1802 fp.close()
1802
1803
1803 editor = ui.geteditor()
1804 editor = ui.geteditor()
1804 ui.system("%s \"%s\"" % (editor, f),
1805 ui.system("%s \"%s\"" % (editor, f),
1805 onerr=error.Abort, errprefix=_("edit failed"),
1806 onerr=error.Abort, errprefix=_("edit failed"),
1806 blockedtag='config_edit')
1807 blockedtag='config_edit')
1807 return
1808 return
1808 ui.pager('config')
1809 ui.pager('config')
1809 fm = ui.formatter('config', opts)
1810 fm = ui.formatter('config', opts)
1810 for t, f in rcutil.rccomponents():
1811 for t, f in rcutil.rccomponents():
1811 if t == 'path':
1812 if t == 'path':
1812 ui.debug('read config from: %s\n' % f)
1813 ui.debug('read config from: %s\n' % f)
1813 elif t == 'items':
1814 elif t == 'items':
1814 for section, name, value, source in f:
1815 for section, name, value, source in f:
1815 ui.debug('set config by: %s\n' % source)
1816 ui.debug('set config by: %s\n' % source)
1816 else:
1817 else:
1817 raise error.ProgrammingError('unknown rctype: %s' % t)
1818 raise error.ProgrammingError('unknown rctype: %s' % t)
1818 untrusted = bool(opts.get('untrusted'))
1819 untrusted = bool(opts.get('untrusted'))
1819 if values:
1820 if values:
1820 sections = [v for v in values if '.' not in v]
1821 sections = [v for v in values if '.' not in v]
1821 items = [v for v in values if '.' in v]
1822 items = [v for v in values if '.' in v]
1822 if len(items) > 1 or items and sections:
1823 if len(items) > 1 or items and sections:
1823 raise error.Abort(_('only one config item permitted'))
1824 raise error.Abort(_('only one config item permitted'))
1824 matched = False
1825 matched = False
1825 for section, name, value in ui.walkconfig(untrusted=untrusted):
1826 for section, name, value in ui.walkconfig(untrusted=untrusted):
1826 source = ui.configsource(section, name, untrusted)
1827 source = ui.configsource(section, name, untrusted)
1827 value = pycompat.bytestr(value)
1828 value = pycompat.bytestr(value)
1828 if fm.isplain():
1829 if fm.isplain():
1829 source = source or 'none'
1830 source = source or 'none'
1830 value = value.replace('\n', '\\n')
1831 value = value.replace('\n', '\\n')
1831 entryname = section + '.' + name
1832 entryname = section + '.' + name
1832 if values:
1833 if values:
1833 for v in values:
1834 for v in values:
1834 if v == section:
1835 if v == section:
1835 fm.startitem()
1836 fm.startitem()
1836 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1837 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1837 fm.write('name value', '%s=%s\n', entryname, value)
1838 fm.write('name value', '%s=%s\n', entryname, value)
1838 matched = True
1839 matched = True
1839 elif v == entryname:
1840 elif v == entryname:
1840 fm.startitem()
1841 fm.startitem()
1841 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1842 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1842 fm.write('value', '%s\n', value)
1843 fm.write('value', '%s\n', value)
1843 fm.data(name=entryname)
1844 fm.data(name=entryname)
1844 matched = True
1845 matched = True
1845 else:
1846 else:
1846 fm.startitem()
1847 fm.startitem()
1847 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1848 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1848 fm.write('name value', '%s=%s\n', entryname, value)
1849 fm.write('name value', '%s=%s\n', entryname, value)
1849 matched = True
1850 matched = True
1850 fm.end()
1851 fm.end()
1851 if matched:
1852 if matched:
1852 return 0
1853 return 0
1853 return 1
1854 return 1
1854
1855
1855 @command('copy|cp',
1856 @command('copy|cp',
1856 [('A', 'after', None, _('record a copy that has already occurred')),
1857 [('A', 'after', None, _('record a copy that has already occurred')),
1857 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1858 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1858 ] + walkopts + dryrunopts,
1859 ] + walkopts + dryrunopts,
1859 _('[OPTION]... [SOURCE]... DEST'))
1860 _('[OPTION]... [SOURCE]... DEST'))
1860 def copy(ui, repo, *pats, **opts):
1861 def copy(ui, repo, *pats, **opts):
1861 """mark files as copied for the next commit
1862 """mark files as copied for the next commit
1862
1863
1863 Mark dest as having copies of source files. If dest is a
1864 Mark dest as having copies of source files. If dest is a
1864 directory, copies are put in that directory. If dest is a file,
1865 directory, copies are put in that directory. If dest is a file,
1865 the source must be a single file.
1866 the source must be a single file.
1866
1867
1867 By default, this command copies the contents of files as they
1868 By default, this command copies the contents of files as they
1868 exist in the working directory. If invoked with -A/--after, the
1869 exist in the working directory. If invoked with -A/--after, the
1869 operation is recorded, but no copying is performed.
1870 operation is recorded, but no copying is performed.
1870
1871
1871 This command takes effect with the next commit. To undo a copy
1872 This command takes effect with the next commit. To undo a copy
1872 before that, see :hg:`revert`.
1873 before that, see :hg:`revert`.
1873
1874
1874 Returns 0 on success, 1 if errors are encountered.
1875 Returns 0 on success, 1 if errors are encountered.
1875 """
1876 """
1876 opts = pycompat.byteskwargs(opts)
1877 opts = pycompat.byteskwargs(opts)
1877 with repo.wlock(False):
1878 with repo.wlock(False):
1878 return cmdutil.copy(ui, repo, pats, opts)
1879 return cmdutil.copy(ui, repo, pats, opts)
1879
1880
1880 @command('^diff',
1881 @command('^diff',
1881 [('r', 'rev', [], _('revision'), _('REV')),
1882 [('r', 'rev', [], _('revision'), _('REV')),
1882 ('c', 'change', '', _('change made by revision'), _('REV'))
1883 ('c', 'change', '', _('change made by revision'), _('REV'))
1883 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1884 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1884 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1885 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1885 inferrepo=True)
1886 inferrepo=True)
1886 def diff(ui, repo, *pats, **opts):
1887 def diff(ui, repo, *pats, **opts):
1887 """diff repository (or selected files)
1888 """diff repository (or selected files)
1888
1889
1889 Show differences between revisions for the specified files.
1890 Show differences between revisions for the specified files.
1890
1891
1891 Differences between files are shown using the unified diff format.
1892 Differences between files are shown using the unified diff format.
1892
1893
1893 .. note::
1894 .. note::
1894
1895
1895 :hg:`diff` may generate unexpected results for merges, as it will
1896 :hg:`diff` may generate unexpected results for merges, as it will
1896 default to comparing against the working directory's first
1897 default to comparing against the working directory's first
1897 parent changeset if no revisions are specified.
1898 parent changeset if no revisions are specified.
1898
1899
1899 When two revision arguments are given, then changes are shown
1900 When two revision arguments are given, then changes are shown
1900 between those revisions. If only one revision is specified then
1901 between those revisions. If only one revision is specified then
1901 that revision is compared to the working directory, and, when no
1902 that revision is compared to the working directory, and, when no
1902 revisions are specified, the working directory files are compared
1903 revisions are specified, the working directory files are compared
1903 to its first parent.
1904 to its first parent.
1904
1905
1905 Alternatively you can specify -c/--change with a revision to see
1906 Alternatively you can specify -c/--change with a revision to see
1906 the changes in that changeset relative to its first parent.
1907 the changes in that changeset relative to its first parent.
1907
1908
1908 Without the -a/--text option, diff will avoid generating diffs of
1909 Without the -a/--text option, diff will avoid generating diffs of
1909 files it detects as binary. With -a, diff will generate a diff
1910 files it detects as binary. With -a, diff will generate a diff
1910 anyway, probably with undesirable results.
1911 anyway, probably with undesirable results.
1911
1912
1912 Use the -g/--git option to generate diffs in the git extended diff
1913 Use the -g/--git option to generate diffs in the git extended diff
1913 format. For more information, read :hg:`help diffs`.
1914 format. For more information, read :hg:`help diffs`.
1914
1915
1915 .. container:: verbose
1916 .. container:: verbose
1916
1917
1917 Examples:
1918 Examples:
1918
1919
1919 - compare a file in the current working directory to its parent::
1920 - compare a file in the current working directory to its parent::
1920
1921
1921 hg diff foo.c
1922 hg diff foo.c
1922
1923
1923 - compare two historical versions of a directory, with rename info::
1924 - compare two historical versions of a directory, with rename info::
1924
1925
1925 hg diff --git -r 1.0:1.2 lib/
1926 hg diff --git -r 1.0:1.2 lib/
1926
1927
1927 - get change stats relative to the last change on some date::
1928 - get change stats relative to the last change on some date::
1928
1929
1929 hg diff --stat -r "date('may 2')"
1930 hg diff --stat -r "date('may 2')"
1930
1931
1931 - diff all newly-added files that contain a keyword::
1932 - diff all newly-added files that contain a keyword::
1932
1933
1933 hg diff "set:added() and grep(GNU)"
1934 hg diff "set:added() and grep(GNU)"
1934
1935
1935 - compare a revision and its parents::
1936 - compare a revision and its parents::
1936
1937
1937 hg diff -c 9353 # compare against first parent
1938 hg diff -c 9353 # compare against first parent
1938 hg diff -r 9353^:9353 # same using revset syntax
1939 hg diff -r 9353^:9353 # same using revset syntax
1939 hg diff -r 9353^2:9353 # compare against the second parent
1940 hg diff -r 9353^2:9353 # compare against the second parent
1940
1941
1941 Returns 0 on success.
1942 Returns 0 on success.
1942 """
1943 """
1943
1944
1944 opts = pycompat.byteskwargs(opts)
1945 opts = pycompat.byteskwargs(opts)
1945 revs = opts.get('rev')
1946 revs = opts.get('rev')
1946 change = opts.get('change')
1947 change = opts.get('change')
1947 stat = opts.get('stat')
1948 stat = opts.get('stat')
1948 reverse = opts.get('reverse')
1949 reverse = opts.get('reverse')
1949
1950
1950 if revs and change:
1951 if revs and change:
1951 msg = _('cannot specify --rev and --change at the same time')
1952 msg = _('cannot specify --rev and --change at the same time')
1952 raise error.Abort(msg)
1953 raise error.Abort(msg)
1953 elif change:
1954 elif change:
1954 node2 = scmutil.revsingle(repo, change, None).node()
1955 node2 = scmutil.revsingle(repo, change, None).node()
1955 node1 = repo[node2].p1().node()
1956 node1 = repo[node2].p1().node()
1956 else:
1957 else:
1957 node1, node2 = scmutil.revpair(repo, revs)
1958 node1, node2 = scmutil.revpair(repo, revs)
1958
1959
1959 if reverse:
1960 if reverse:
1960 node1, node2 = node2, node1
1961 node1, node2 = node2, node1
1961
1962
1962 diffopts = patch.diffallopts(ui, opts)
1963 diffopts = patch.diffallopts(ui, opts)
1963 m = scmutil.match(repo[node2], pats, opts)
1964 m = scmutil.match(repo[node2], pats, opts)
1964 ui.pager('diff')
1965 ui.pager('diff')
1965 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1966 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1966 listsubrepos=opts.get('subrepos'),
1967 listsubrepos=opts.get('subrepos'),
1967 root=opts.get('root'))
1968 root=opts.get('root'))
1968
1969
1969 @command('^export',
1970 @command('^export',
1970 [('o', 'output', '',
1971 [('o', 'output', '',
1971 _('print output to file with formatted name'), _('FORMAT')),
1972 _('print output to file with formatted name'), _('FORMAT')),
1972 ('', 'switch-parent', None, _('diff against the second parent')),
1973 ('', 'switch-parent', None, _('diff against the second parent')),
1973 ('r', 'rev', [], _('revisions to export'), _('REV')),
1974 ('r', 'rev', [], _('revisions to export'), _('REV')),
1974 ] + diffopts,
1975 ] + diffopts,
1975 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1976 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1976 def export(ui, repo, *changesets, **opts):
1977 def export(ui, repo, *changesets, **opts):
1977 """dump the header and diffs for one or more changesets
1978 """dump the header and diffs for one or more changesets
1978
1979
1979 Print the changeset header and diffs for one or more revisions.
1980 Print the changeset header and diffs for one or more revisions.
1980 If no revision is given, the parent of the working directory is used.
1981 If no revision is given, the parent of the working directory is used.
1981
1982
1982 The information shown in the changeset header is: author, date,
1983 The information shown in the changeset header is: author, date,
1983 branch name (if non-default), changeset hash, parent(s) and commit
1984 branch name (if non-default), changeset hash, parent(s) and commit
1984 comment.
1985 comment.
1985
1986
1986 .. note::
1987 .. note::
1987
1988
1988 :hg:`export` may generate unexpected diff output for merge
1989 :hg:`export` may generate unexpected diff output for merge
1989 changesets, as it will compare the merge changeset against its
1990 changesets, as it will compare the merge changeset against its
1990 first parent only.
1991 first parent only.
1991
1992
1992 Output may be to a file, in which case the name of the file is
1993 Output may be to a file, in which case the name of the file is
1993 given using a format string. The formatting rules are as follows:
1994 given using a format string. The formatting rules are as follows:
1994
1995
1995 :``%%``: literal "%" character
1996 :``%%``: literal "%" character
1996 :``%H``: changeset hash (40 hexadecimal digits)
1997 :``%H``: changeset hash (40 hexadecimal digits)
1997 :``%N``: number of patches being generated
1998 :``%N``: number of patches being generated
1998 :``%R``: changeset revision number
1999 :``%R``: changeset revision number
1999 :``%b``: basename of the exporting repository
2000 :``%b``: basename of the exporting repository
2000 :``%h``: short-form changeset hash (12 hexadecimal digits)
2001 :``%h``: short-form changeset hash (12 hexadecimal digits)
2001 :``%m``: first line of the commit message (only alphanumeric characters)
2002 :``%m``: first line of the commit message (only alphanumeric characters)
2002 :``%n``: zero-padded sequence number, starting at 1
2003 :``%n``: zero-padded sequence number, starting at 1
2003 :``%r``: zero-padded changeset revision number
2004 :``%r``: zero-padded changeset revision number
2004
2005
2005 Without the -a/--text option, export will avoid generating diffs
2006 Without the -a/--text option, export will avoid generating diffs
2006 of files it detects as binary. With -a, export will generate a
2007 of files it detects as binary. With -a, export will generate a
2007 diff anyway, probably with undesirable results.
2008 diff anyway, probably with undesirable results.
2008
2009
2009 Use the -g/--git option to generate diffs in the git extended diff
2010 Use the -g/--git option to generate diffs in the git extended diff
2010 format. See :hg:`help diffs` for more information.
2011 format. See :hg:`help diffs` for more information.
2011
2012
2012 With the --switch-parent option, the diff will be against the
2013 With the --switch-parent option, the diff will be against the
2013 second parent. It can be useful to review a merge.
2014 second parent. It can be useful to review a merge.
2014
2015
2015 .. container:: verbose
2016 .. container:: verbose
2016
2017
2017 Examples:
2018 Examples:
2018
2019
2019 - use export and import to transplant a bugfix to the current
2020 - use export and import to transplant a bugfix to the current
2020 branch::
2021 branch::
2021
2022
2022 hg export -r 9353 | hg import -
2023 hg export -r 9353 | hg import -
2023
2024
2024 - export all the changesets between two revisions to a file with
2025 - export all the changesets between two revisions to a file with
2025 rename information::
2026 rename information::
2026
2027
2027 hg export --git -r 123:150 > changes.txt
2028 hg export --git -r 123:150 > changes.txt
2028
2029
2029 - split outgoing changes into a series of patches with
2030 - split outgoing changes into a series of patches with
2030 descriptive names::
2031 descriptive names::
2031
2032
2032 hg export -r "outgoing()" -o "%n-%m.patch"
2033 hg export -r "outgoing()" -o "%n-%m.patch"
2033
2034
2034 Returns 0 on success.
2035 Returns 0 on success.
2035 """
2036 """
2036 opts = pycompat.byteskwargs(opts)
2037 opts = pycompat.byteskwargs(opts)
2037 changesets += tuple(opts.get('rev', []))
2038 changesets += tuple(opts.get('rev', []))
2038 if not changesets:
2039 if not changesets:
2039 changesets = ['.']
2040 changesets = ['.']
2040 revs = scmutil.revrange(repo, changesets)
2041 revs = scmutil.revrange(repo, changesets)
2041 if not revs:
2042 if not revs:
2042 raise error.Abort(_("export requires at least one changeset"))
2043 raise error.Abort(_("export requires at least one changeset"))
2043 if len(revs) > 1:
2044 if len(revs) > 1:
2044 ui.note(_('exporting patches:\n'))
2045 ui.note(_('exporting patches:\n'))
2045 else:
2046 else:
2046 ui.note(_('exporting patch:\n'))
2047 ui.note(_('exporting patch:\n'))
2047 ui.pager('export')
2048 ui.pager('export')
2048 cmdutil.export(repo, revs, template=opts.get('output'),
2049 cmdutil.export(repo, revs, template=opts.get('output'),
2049 switch_parent=opts.get('switch_parent'),
2050 switch_parent=opts.get('switch_parent'),
2050 opts=patch.diffallopts(ui, opts))
2051 opts=patch.diffallopts(ui, opts))
2051
2052
2052 @command('files',
2053 @command('files',
2053 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2054 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2054 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2055 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2055 ] + walkopts + formatteropts + subrepoopts,
2056 ] + walkopts + formatteropts + subrepoopts,
2056 _('[OPTION]... [FILE]...'))
2057 _('[OPTION]... [FILE]...'))
2057 def files(ui, repo, *pats, **opts):
2058 def files(ui, repo, *pats, **opts):
2058 """list tracked files
2059 """list tracked files
2059
2060
2060 Print files under Mercurial control in the working directory or
2061 Print files under Mercurial control in the working directory or
2061 specified revision for given files (excluding removed files).
2062 specified revision for given files (excluding removed files).
2062 Files can be specified as filenames or filesets.
2063 Files can be specified as filenames or filesets.
2063
2064
2064 If no files are given to match, this command prints the names
2065 If no files are given to match, this command prints the names
2065 of all files under Mercurial control.
2066 of all files under Mercurial control.
2066
2067
2067 .. container:: verbose
2068 .. container:: verbose
2068
2069
2069 Examples:
2070 Examples:
2070
2071
2071 - list all files under the current directory::
2072 - list all files under the current directory::
2072
2073
2073 hg files .
2074 hg files .
2074
2075
2075 - shows sizes and flags for current revision::
2076 - shows sizes and flags for current revision::
2076
2077
2077 hg files -vr .
2078 hg files -vr .
2078
2079
2079 - list all files named README::
2080 - list all files named README::
2080
2081
2081 hg files -I "**/README"
2082 hg files -I "**/README"
2082
2083
2083 - list all binary files::
2084 - list all binary files::
2084
2085
2085 hg files "set:binary()"
2086 hg files "set:binary()"
2086
2087
2087 - find files containing a regular expression::
2088 - find files containing a regular expression::
2088
2089
2089 hg files "set:grep('bob')"
2090 hg files "set:grep('bob')"
2090
2091
2091 - search tracked file contents with xargs and grep::
2092 - search tracked file contents with xargs and grep::
2092
2093
2093 hg files -0 | xargs -0 grep foo
2094 hg files -0 | xargs -0 grep foo
2094
2095
2095 See :hg:`help patterns` and :hg:`help filesets` for more information
2096 See :hg:`help patterns` and :hg:`help filesets` for more information
2096 on specifying file patterns.
2097 on specifying file patterns.
2097
2098
2098 Returns 0 if a match is found, 1 otherwise.
2099 Returns 0 if a match is found, 1 otherwise.
2099
2100
2100 """
2101 """
2101
2102
2102 opts = pycompat.byteskwargs(opts)
2103 opts = pycompat.byteskwargs(opts)
2103 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2104 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2104
2105
2105 end = '\n'
2106 end = '\n'
2106 if opts.get('print0'):
2107 if opts.get('print0'):
2107 end = '\0'
2108 end = '\0'
2108 fmt = '%s' + end
2109 fmt = '%s' + end
2109
2110
2110 m = scmutil.match(ctx, pats, opts)
2111 m = scmutil.match(ctx, pats, opts)
2111 ui.pager('files')
2112 ui.pager('files')
2112 with ui.formatter('files', opts) as fm:
2113 with ui.formatter('files', opts) as fm:
2113 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2114 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2114
2115
2115 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2116 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2116 def forget(ui, repo, *pats, **opts):
2117 def forget(ui, repo, *pats, **opts):
2117 """forget the specified files on the next commit
2118 """forget the specified files on the next commit
2118
2119
2119 Mark the specified files so they will no longer be tracked
2120 Mark the specified files so they will no longer be tracked
2120 after the next commit.
2121 after the next commit.
2121
2122
2122 This only removes files from the current branch, not from the
2123 This only removes files from the current branch, not from the
2123 entire project history, and it does not delete them from the
2124 entire project history, and it does not delete them from the
2124 working directory.
2125 working directory.
2125
2126
2126 To delete the file from the working directory, see :hg:`remove`.
2127 To delete the file from the working directory, see :hg:`remove`.
2127
2128
2128 To undo a forget before the next commit, see :hg:`add`.
2129 To undo a forget before the next commit, see :hg:`add`.
2129
2130
2130 .. container:: verbose
2131 .. container:: verbose
2131
2132
2132 Examples:
2133 Examples:
2133
2134
2134 - forget newly-added binary files::
2135 - forget newly-added binary files::
2135
2136
2136 hg forget "set:added() and binary()"
2137 hg forget "set:added() and binary()"
2137
2138
2138 - forget files that would be excluded by .hgignore::
2139 - forget files that would be excluded by .hgignore::
2139
2140
2140 hg forget "set:hgignore()"
2141 hg forget "set:hgignore()"
2141
2142
2142 Returns 0 on success.
2143 Returns 0 on success.
2143 """
2144 """
2144
2145
2145 opts = pycompat.byteskwargs(opts)
2146 opts = pycompat.byteskwargs(opts)
2146 if not pats:
2147 if not pats:
2147 raise error.Abort(_('no files specified'))
2148 raise error.Abort(_('no files specified'))
2148
2149
2149 m = scmutil.match(repo[None], pats, opts)
2150 m = scmutil.match(repo[None], pats, opts)
2150 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2151 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2151 return rejected and 1 or 0
2152 return rejected and 1 or 0
2152
2153
2153 @command(
2154 @command(
2154 'graft',
2155 'graft',
2155 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2156 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2156 ('c', 'continue', False, _('resume interrupted graft')),
2157 ('c', 'continue', False, _('resume interrupted graft')),
2157 ('e', 'edit', False, _('invoke editor on commit messages')),
2158 ('e', 'edit', False, _('invoke editor on commit messages')),
2158 ('', 'log', None, _('append graft info to log message')),
2159 ('', 'log', None, _('append graft info to log message')),
2159 ('f', 'force', False, _('force graft')),
2160 ('f', 'force', False, _('force graft')),
2160 ('D', 'currentdate', False,
2161 ('D', 'currentdate', False,
2161 _('record the current date as commit date')),
2162 _('record the current date as commit date')),
2162 ('U', 'currentuser', False,
2163 ('U', 'currentuser', False,
2163 _('record the current user as committer'), _('DATE'))]
2164 _('record the current user as committer'), _('DATE'))]
2164 + commitopts2 + mergetoolopts + dryrunopts,
2165 + commitopts2 + mergetoolopts + dryrunopts,
2165 _('[OPTION]... [-r REV]... REV...'))
2166 _('[OPTION]... [-r REV]... REV...'))
2166 def graft(ui, repo, *revs, **opts):
2167 def graft(ui, repo, *revs, **opts):
2167 '''copy changes from other branches onto the current branch
2168 '''copy changes from other branches onto the current branch
2168
2169
2169 This command uses Mercurial's merge logic to copy individual
2170 This command uses Mercurial's merge logic to copy individual
2170 changes from other branches without merging branches in the
2171 changes from other branches without merging branches in the
2171 history graph. This is sometimes known as 'backporting' or
2172 history graph. This is sometimes known as 'backporting' or
2172 'cherry-picking'. By default, graft will copy user, date, and
2173 'cherry-picking'. By default, graft will copy user, date, and
2173 description from the source changesets.
2174 description from the source changesets.
2174
2175
2175 Changesets that are ancestors of the current revision, that have
2176 Changesets that are ancestors of the current revision, that have
2176 already been grafted, or that are merges will be skipped.
2177 already been grafted, or that are merges will be skipped.
2177
2178
2178 If --log is specified, log messages will have a comment appended
2179 If --log is specified, log messages will have a comment appended
2179 of the form::
2180 of the form::
2180
2181
2181 (grafted from CHANGESETHASH)
2182 (grafted from CHANGESETHASH)
2182
2183
2183 If --force is specified, revisions will be grafted even if they
2184 If --force is specified, revisions will be grafted even if they
2184 are already ancestors of or have been grafted to the destination.
2185 are already ancestors of or have been grafted to the destination.
2185 This is useful when the revisions have since been backed out.
2186 This is useful when the revisions have since been backed out.
2186
2187
2187 If a graft merge results in conflicts, the graft process is
2188 If a graft merge results in conflicts, the graft process is
2188 interrupted so that the current merge can be manually resolved.
2189 interrupted so that the current merge can be manually resolved.
2189 Once all conflicts are addressed, the graft process can be
2190 Once all conflicts are addressed, the graft process can be
2190 continued with the -c/--continue option.
2191 continued with the -c/--continue option.
2191
2192
2192 .. note::
2193 .. note::
2193
2194
2194 The -c/--continue option does not reapply earlier options, except
2195 The -c/--continue option does not reapply earlier options, except
2195 for --force.
2196 for --force.
2196
2197
2197 .. container:: verbose
2198 .. container:: verbose
2198
2199
2199 Examples:
2200 Examples:
2200
2201
2201 - copy a single change to the stable branch and edit its description::
2202 - copy a single change to the stable branch and edit its description::
2202
2203
2203 hg update stable
2204 hg update stable
2204 hg graft --edit 9393
2205 hg graft --edit 9393
2205
2206
2206 - graft a range of changesets with one exception, updating dates::
2207 - graft a range of changesets with one exception, updating dates::
2207
2208
2208 hg graft -D "2085::2093 and not 2091"
2209 hg graft -D "2085::2093 and not 2091"
2209
2210
2210 - continue a graft after resolving conflicts::
2211 - continue a graft after resolving conflicts::
2211
2212
2212 hg graft -c
2213 hg graft -c
2213
2214
2214 - show the source of a grafted changeset::
2215 - show the source of a grafted changeset::
2215
2216
2216 hg log --debug -r .
2217 hg log --debug -r .
2217
2218
2218 - show revisions sorted by date::
2219 - show revisions sorted by date::
2219
2220
2220 hg log -r "sort(all(), date)"
2221 hg log -r "sort(all(), date)"
2221
2222
2222 See :hg:`help revisions` for more about specifying revisions.
2223 See :hg:`help revisions` for more about specifying revisions.
2223
2224
2224 Returns 0 on successful completion.
2225 Returns 0 on successful completion.
2225 '''
2226 '''
2226 with repo.wlock():
2227 with repo.wlock():
2227 return _dograft(ui, repo, *revs, **opts)
2228 return _dograft(ui, repo, *revs, **opts)
2228
2229
2229 def _dograft(ui, repo, *revs, **opts):
2230 def _dograft(ui, repo, *revs, **opts):
2230 opts = pycompat.byteskwargs(opts)
2231 opts = pycompat.byteskwargs(opts)
2231 if revs and opts.get('rev'):
2232 if revs and opts.get('rev'):
2232 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2233 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2233 'revision ordering!\n'))
2234 'revision ordering!\n'))
2234
2235
2235 revs = list(revs)
2236 revs = list(revs)
2236 revs.extend(opts.get('rev'))
2237 revs.extend(opts.get('rev'))
2237
2238
2238 if not opts.get('user') and opts.get('currentuser'):
2239 if not opts.get('user') and opts.get('currentuser'):
2239 opts['user'] = ui.username()
2240 opts['user'] = ui.username()
2240 if not opts.get('date') and opts.get('currentdate'):
2241 if not opts.get('date') and opts.get('currentdate'):
2241 opts['date'] = "%d %d" % util.makedate()
2242 opts['date'] = "%d %d" % util.makedate()
2242
2243
2243 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2244 editor = cmdutil.getcommiteditor(editform='graft',
2245 **pycompat.strkwargs(opts))
2244
2246
2245 cont = False
2247 cont = False
2246 if opts.get('continue'):
2248 if opts.get('continue'):
2247 cont = True
2249 cont = True
2248 if revs:
2250 if revs:
2249 raise error.Abort(_("can't specify --continue and revisions"))
2251 raise error.Abort(_("can't specify --continue and revisions"))
2250 # read in unfinished revisions
2252 # read in unfinished revisions
2251 try:
2253 try:
2252 nodes = repo.vfs.read('graftstate').splitlines()
2254 nodes = repo.vfs.read('graftstate').splitlines()
2253 revs = [repo[node].rev() for node in nodes]
2255 revs = [repo[node].rev() for node in nodes]
2254 except IOError as inst:
2256 except IOError as inst:
2255 if inst.errno != errno.ENOENT:
2257 if inst.errno != errno.ENOENT:
2256 raise
2258 raise
2257 cmdutil.wrongtooltocontinue(repo, _('graft'))
2259 cmdutil.wrongtooltocontinue(repo, _('graft'))
2258 else:
2260 else:
2259 cmdutil.checkunfinished(repo)
2261 cmdutil.checkunfinished(repo)
2260 cmdutil.bailifchanged(repo)
2262 cmdutil.bailifchanged(repo)
2261 if not revs:
2263 if not revs:
2262 raise error.Abort(_('no revisions specified'))
2264 raise error.Abort(_('no revisions specified'))
2263 revs = scmutil.revrange(repo, revs)
2265 revs = scmutil.revrange(repo, revs)
2264
2266
2265 skipped = set()
2267 skipped = set()
2266 # check for merges
2268 # check for merges
2267 for rev in repo.revs('%ld and merge()', revs):
2269 for rev in repo.revs('%ld and merge()', revs):
2268 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2270 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2269 skipped.add(rev)
2271 skipped.add(rev)
2270 revs = [r for r in revs if r not in skipped]
2272 revs = [r for r in revs if r not in skipped]
2271 if not revs:
2273 if not revs:
2272 return -1
2274 return -1
2273
2275
2274 # Don't check in the --continue case, in effect retaining --force across
2276 # Don't check in the --continue case, in effect retaining --force across
2275 # --continues. That's because without --force, any revisions we decided to
2277 # --continues. That's because without --force, any revisions we decided to
2276 # skip would have been filtered out here, so they wouldn't have made their
2278 # skip would have been filtered out here, so they wouldn't have made their
2277 # way to the graftstate. With --force, any revisions we would have otherwise
2279 # way to the graftstate. With --force, any revisions we would have otherwise
2278 # skipped would not have been filtered out, and if they hadn't been applied
2280 # skipped would not have been filtered out, and if they hadn't been applied
2279 # already, they'd have been in the graftstate.
2281 # already, they'd have been in the graftstate.
2280 if not (cont or opts.get('force')):
2282 if not (cont or opts.get('force')):
2281 # check for ancestors of dest branch
2283 # check for ancestors of dest branch
2282 crev = repo['.'].rev()
2284 crev = repo['.'].rev()
2283 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2285 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2284 # XXX make this lazy in the future
2286 # XXX make this lazy in the future
2285 # don't mutate while iterating, create a copy
2287 # don't mutate while iterating, create a copy
2286 for rev in list(revs):
2288 for rev in list(revs):
2287 if rev in ancestors:
2289 if rev in ancestors:
2288 ui.warn(_('skipping ancestor revision %d:%s\n') %
2290 ui.warn(_('skipping ancestor revision %d:%s\n') %
2289 (rev, repo[rev]))
2291 (rev, repo[rev]))
2290 # XXX remove on list is slow
2292 # XXX remove on list is slow
2291 revs.remove(rev)
2293 revs.remove(rev)
2292 if not revs:
2294 if not revs:
2293 return -1
2295 return -1
2294
2296
2295 # analyze revs for earlier grafts
2297 # analyze revs for earlier grafts
2296 ids = {}
2298 ids = {}
2297 for ctx in repo.set("%ld", revs):
2299 for ctx in repo.set("%ld", revs):
2298 ids[ctx.hex()] = ctx.rev()
2300 ids[ctx.hex()] = ctx.rev()
2299 n = ctx.extra().get('source')
2301 n = ctx.extra().get('source')
2300 if n:
2302 if n:
2301 ids[n] = ctx.rev()
2303 ids[n] = ctx.rev()
2302
2304
2303 # check ancestors for earlier grafts
2305 # check ancestors for earlier grafts
2304 ui.debug('scanning for duplicate grafts\n')
2306 ui.debug('scanning for duplicate grafts\n')
2305
2307
2306 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2308 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2307 ctx = repo[rev]
2309 ctx = repo[rev]
2308 n = ctx.extra().get('source')
2310 n = ctx.extra().get('source')
2309 if n in ids:
2311 if n in ids:
2310 try:
2312 try:
2311 r = repo[n].rev()
2313 r = repo[n].rev()
2312 except error.RepoLookupError:
2314 except error.RepoLookupError:
2313 r = None
2315 r = None
2314 if r in revs:
2316 if r in revs:
2315 ui.warn(_('skipping revision %d:%s '
2317 ui.warn(_('skipping revision %d:%s '
2316 '(already grafted to %d:%s)\n')
2318 '(already grafted to %d:%s)\n')
2317 % (r, repo[r], rev, ctx))
2319 % (r, repo[r], rev, ctx))
2318 revs.remove(r)
2320 revs.remove(r)
2319 elif ids[n] in revs:
2321 elif ids[n] in revs:
2320 if r is None:
2322 if r is None:
2321 ui.warn(_('skipping already grafted revision %d:%s '
2323 ui.warn(_('skipping already grafted revision %d:%s '
2322 '(%d:%s also has unknown origin %s)\n')
2324 '(%d:%s also has unknown origin %s)\n')
2323 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2325 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2324 else:
2326 else:
2325 ui.warn(_('skipping already grafted revision %d:%s '
2327 ui.warn(_('skipping already grafted revision %d:%s '
2326 '(%d:%s also has origin %d:%s)\n')
2328 '(%d:%s also has origin %d:%s)\n')
2327 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2329 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2328 revs.remove(ids[n])
2330 revs.remove(ids[n])
2329 elif ctx.hex() in ids:
2331 elif ctx.hex() in ids:
2330 r = ids[ctx.hex()]
2332 r = ids[ctx.hex()]
2331 ui.warn(_('skipping already grafted revision %d:%s '
2333 ui.warn(_('skipping already grafted revision %d:%s '
2332 '(was grafted from %d:%s)\n') %
2334 '(was grafted from %d:%s)\n') %
2333 (r, repo[r], rev, ctx))
2335 (r, repo[r], rev, ctx))
2334 revs.remove(r)
2336 revs.remove(r)
2335 if not revs:
2337 if not revs:
2336 return -1
2338 return -1
2337
2339
2338 for pos, ctx in enumerate(repo.set("%ld", revs)):
2340 for pos, ctx in enumerate(repo.set("%ld", revs)):
2339 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2341 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2340 ctx.description().split('\n', 1)[0])
2342 ctx.description().split('\n', 1)[0])
2341 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2343 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2342 if names:
2344 if names:
2343 desc += ' (%s)' % ' '.join(names)
2345 desc += ' (%s)' % ' '.join(names)
2344 ui.status(_('grafting %s\n') % desc)
2346 ui.status(_('grafting %s\n') % desc)
2345 if opts.get('dry_run'):
2347 if opts.get('dry_run'):
2346 continue
2348 continue
2347
2349
2348 source = ctx.extra().get('source')
2350 source = ctx.extra().get('source')
2349 extra = {}
2351 extra = {}
2350 if source:
2352 if source:
2351 extra['source'] = source
2353 extra['source'] = source
2352 extra['intermediate-source'] = ctx.hex()
2354 extra['intermediate-source'] = ctx.hex()
2353 else:
2355 else:
2354 extra['source'] = ctx.hex()
2356 extra['source'] = ctx.hex()
2355 user = ctx.user()
2357 user = ctx.user()
2356 if opts.get('user'):
2358 if opts.get('user'):
2357 user = opts['user']
2359 user = opts['user']
2358 date = ctx.date()
2360 date = ctx.date()
2359 if opts.get('date'):
2361 if opts.get('date'):
2360 date = opts['date']
2362 date = opts['date']
2361 message = ctx.description()
2363 message = ctx.description()
2362 if opts.get('log'):
2364 if opts.get('log'):
2363 message += '\n(grafted from %s)' % ctx.hex()
2365 message += '\n(grafted from %s)' % ctx.hex()
2364
2366
2365 # we don't merge the first commit when continuing
2367 # we don't merge the first commit when continuing
2366 if not cont:
2368 if not cont:
2367 # perform the graft merge with p1(rev) as 'ancestor'
2369 # perform the graft merge with p1(rev) as 'ancestor'
2368 try:
2370 try:
2369 # ui.forcemerge is an internal variable, do not document
2371 # ui.forcemerge is an internal variable, do not document
2370 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2372 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2371 'graft')
2373 'graft')
2372 stats = mergemod.graft(repo, ctx, ctx.p1(),
2374 stats = mergemod.graft(repo, ctx, ctx.p1(),
2373 ['local', 'graft'])
2375 ['local', 'graft'])
2374 finally:
2376 finally:
2375 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2377 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2376 # report any conflicts
2378 # report any conflicts
2377 if stats and stats[3] > 0:
2379 if stats and stats[3] > 0:
2378 # write out state for --continue
2380 # write out state for --continue
2379 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2381 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2380 repo.vfs.write('graftstate', ''.join(nodelines))
2382 repo.vfs.write('graftstate', ''.join(nodelines))
2381 extra = ''
2383 extra = ''
2382 if opts.get('user'):
2384 if opts.get('user'):
2383 extra += ' --user %s' % util.shellquote(opts['user'])
2385 extra += ' --user %s' % util.shellquote(opts['user'])
2384 if opts.get('date'):
2386 if opts.get('date'):
2385 extra += ' --date %s' % util.shellquote(opts['date'])
2387 extra += ' --date %s' % util.shellquote(opts['date'])
2386 if opts.get('log'):
2388 if opts.get('log'):
2387 extra += ' --log'
2389 extra += ' --log'
2388 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2390 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2389 raise error.Abort(
2391 raise error.Abort(
2390 _("unresolved conflicts, can't continue"),
2392 _("unresolved conflicts, can't continue"),
2391 hint=hint)
2393 hint=hint)
2392 else:
2394 else:
2393 cont = False
2395 cont = False
2394
2396
2395 # commit
2397 # commit
2396 node = repo.commit(text=message, user=user,
2398 node = repo.commit(text=message, user=user,
2397 date=date, extra=extra, editor=editor)
2399 date=date, extra=extra, editor=editor)
2398 if node is None:
2400 if node is None:
2399 ui.warn(
2401 ui.warn(
2400 _('note: graft of %d:%s created no changes to commit\n') %
2402 _('note: graft of %d:%s created no changes to commit\n') %
2401 (ctx.rev(), ctx))
2403 (ctx.rev(), ctx))
2402
2404
2403 # remove state when we complete successfully
2405 # remove state when we complete successfully
2404 if not opts.get('dry_run'):
2406 if not opts.get('dry_run'):
2405 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2407 repo.vfs.unlinkpath('graftstate', ignoremissing=True)
2406
2408
2407 return 0
2409 return 0
2408
2410
2409 @command('grep',
2411 @command('grep',
2410 [('0', 'print0', None, _('end fields with NUL')),
2412 [('0', 'print0', None, _('end fields with NUL')),
2411 ('', 'all', None, _('print all revisions that match')),
2413 ('', 'all', None, _('print all revisions that match')),
2412 ('a', 'text', None, _('treat all files as text')),
2414 ('a', 'text', None, _('treat all files as text')),
2413 ('f', 'follow', None,
2415 ('f', 'follow', None,
2414 _('follow changeset history,'
2416 _('follow changeset history,'
2415 ' or file history across copies and renames')),
2417 ' or file history across copies and renames')),
2416 ('i', 'ignore-case', None, _('ignore case when matching')),
2418 ('i', 'ignore-case', None, _('ignore case when matching')),
2417 ('l', 'files-with-matches', None,
2419 ('l', 'files-with-matches', None,
2418 _('print only filenames and revisions that match')),
2420 _('print only filenames and revisions that match')),
2419 ('n', 'line-number', None, _('print matching line numbers')),
2421 ('n', 'line-number', None, _('print matching line numbers')),
2420 ('r', 'rev', [],
2422 ('r', 'rev', [],
2421 _('only search files changed within revision range'), _('REV')),
2423 _('only search files changed within revision range'), _('REV')),
2422 ('u', 'user', None, _('list the author (long with -v)')),
2424 ('u', 'user', None, _('list the author (long with -v)')),
2423 ('d', 'date', None, _('list the date (short with -q)')),
2425 ('d', 'date', None, _('list the date (short with -q)')),
2424 ] + formatteropts + walkopts,
2426 ] + formatteropts + walkopts,
2425 _('[OPTION]... PATTERN [FILE]...'),
2427 _('[OPTION]... PATTERN [FILE]...'),
2426 inferrepo=True)
2428 inferrepo=True)
2427 def grep(ui, repo, pattern, *pats, **opts):
2429 def grep(ui, repo, pattern, *pats, **opts):
2428 """search revision history for a pattern in specified files
2430 """search revision history for a pattern in specified files
2429
2431
2430 Search revision history for a regular expression in the specified
2432 Search revision history for a regular expression in the specified
2431 files or the entire project.
2433 files or the entire project.
2432
2434
2433 By default, grep prints the most recent revision number for each
2435 By default, grep prints the most recent revision number for each
2434 file in which it finds a match. To get it to print every revision
2436 file in which it finds a match. To get it to print every revision
2435 that contains a change in match status ("-" for a match that becomes
2437 that contains a change in match status ("-" for a match that becomes
2436 a non-match, or "+" for a non-match that becomes a match), use the
2438 a non-match, or "+" for a non-match that becomes a match), use the
2437 --all flag.
2439 --all flag.
2438
2440
2439 PATTERN can be any Python (roughly Perl-compatible) regular
2441 PATTERN can be any Python (roughly Perl-compatible) regular
2440 expression.
2442 expression.
2441
2443
2442 If no FILEs are specified (and -f/--follow isn't set), all files in
2444 If no FILEs are specified (and -f/--follow isn't set), all files in
2443 the repository are searched, including those that don't exist in the
2445 the repository are searched, including those that don't exist in the
2444 current branch or have been deleted in a prior changeset.
2446 current branch or have been deleted in a prior changeset.
2445
2447
2446 Returns 0 if a match is found, 1 otherwise.
2448 Returns 0 if a match is found, 1 otherwise.
2447 """
2449 """
2448 opts = pycompat.byteskwargs(opts)
2450 opts = pycompat.byteskwargs(opts)
2449 reflags = re.M
2451 reflags = re.M
2450 if opts.get('ignore_case'):
2452 if opts.get('ignore_case'):
2451 reflags |= re.I
2453 reflags |= re.I
2452 try:
2454 try:
2453 regexp = util.re.compile(pattern, reflags)
2455 regexp = util.re.compile(pattern, reflags)
2454 except re.error as inst:
2456 except re.error as inst:
2455 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2457 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2456 return 1
2458 return 1
2457 sep, eol = ':', '\n'
2459 sep, eol = ':', '\n'
2458 if opts.get('print0'):
2460 if opts.get('print0'):
2459 sep = eol = '\0'
2461 sep = eol = '\0'
2460
2462
2461 getfile = util.lrucachefunc(repo.file)
2463 getfile = util.lrucachefunc(repo.file)
2462
2464
2463 def matchlines(body):
2465 def matchlines(body):
2464 begin = 0
2466 begin = 0
2465 linenum = 0
2467 linenum = 0
2466 while begin < len(body):
2468 while begin < len(body):
2467 match = regexp.search(body, begin)
2469 match = regexp.search(body, begin)
2468 if not match:
2470 if not match:
2469 break
2471 break
2470 mstart, mend = match.span()
2472 mstart, mend = match.span()
2471 linenum += body.count('\n', begin, mstart) + 1
2473 linenum += body.count('\n', begin, mstart) + 1
2472 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2474 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2473 begin = body.find('\n', mend) + 1 or len(body) + 1
2475 begin = body.find('\n', mend) + 1 or len(body) + 1
2474 lend = begin - 1
2476 lend = begin - 1
2475 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2477 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2476
2478
2477 class linestate(object):
2479 class linestate(object):
2478 def __init__(self, line, linenum, colstart, colend):
2480 def __init__(self, line, linenum, colstart, colend):
2479 self.line = line
2481 self.line = line
2480 self.linenum = linenum
2482 self.linenum = linenum
2481 self.colstart = colstart
2483 self.colstart = colstart
2482 self.colend = colend
2484 self.colend = colend
2483
2485
2484 def __hash__(self):
2486 def __hash__(self):
2485 return hash((self.linenum, self.line))
2487 return hash((self.linenum, self.line))
2486
2488
2487 def __eq__(self, other):
2489 def __eq__(self, other):
2488 return self.line == other.line
2490 return self.line == other.line
2489
2491
2490 def findpos(self):
2492 def findpos(self):
2491 """Iterate all (start, end) indices of matches"""
2493 """Iterate all (start, end) indices of matches"""
2492 yield self.colstart, self.colend
2494 yield self.colstart, self.colend
2493 p = self.colend
2495 p = self.colend
2494 while p < len(self.line):
2496 while p < len(self.line):
2495 m = regexp.search(self.line, p)
2497 m = regexp.search(self.line, p)
2496 if not m:
2498 if not m:
2497 break
2499 break
2498 yield m.span()
2500 yield m.span()
2499 p = m.end()
2501 p = m.end()
2500
2502
2501 matches = {}
2503 matches = {}
2502 copies = {}
2504 copies = {}
2503 def grepbody(fn, rev, body):
2505 def grepbody(fn, rev, body):
2504 matches[rev].setdefault(fn, [])
2506 matches[rev].setdefault(fn, [])
2505 m = matches[rev][fn]
2507 m = matches[rev][fn]
2506 for lnum, cstart, cend, line in matchlines(body):
2508 for lnum, cstart, cend, line in matchlines(body):
2507 s = linestate(line, lnum, cstart, cend)
2509 s = linestate(line, lnum, cstart, cend)
2508 m.append(s)
2510 m.append(s)
2509
2511
2510 def difflinestates(a, b):
2512 def difflinestates(a, b):
2511 sm = difflib.SequenceMatcher(None, a, b)
2513 sm = difflib.SequenceMatcher(None, a, b)
2512 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2514 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2513 if tag == 'insert':
2515 if tag == 'insert':
2514 for i in xrange(blo, bhi):
2516 for i in xrange(blo, bhi):
2515 yield ('+', b[i])
2517 yield ('+', b[i])
2516 elif tag == 'delete':
2518 elif tag == 'delete':
2517 for i in xrange(alo, ahi):
2519 for i in xrange(alo, ahi):
2518 yield ('-', a[i])
2520 yield ('-', a[i])
2519 elif tag == 'replace':
2521 elif tag == 'replace':
2520 for i in xrange(alo, ahi):
2522 for i in xrange(alo, ahi):
2521 yield ('-', a[i])
2523 yield ('-', a[i])
2522 for i in xrange(blo, bhi):
2524 for i in xrange(blo, bhi):
2523 yield ('+', b[i])
2525 yield ('+', b[i])
2524
2526
2525 def display(fm, fn, ctx, pstates, states):
2527 def display(fm, fn, ctx, pstates, states):
2526 rev = ctx.rev()
2528 rev = ctx.rev()
2527 if fm.isplain():
2529 if fm.isplain():
2528 formatuser = ui.shortuser
2530 formatuser = ui.shortuser
2529 else:
2531 else:
2530 formatuser = str
2532 formatuser = str
2531 if ui.quiet:
2533 if ui.quiet:
2532 datefmt = '%Y-%m-%d'
2534 datefmt = '%Y-%m-%d'
2533 else:
2535 else:
2534 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2536 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2535 found = False
2537 found = False
2536 @util.cachefunc
2538 @util.cachefunc
2537 def binary():
2539 def binary():
2538 flog = getfile(fn)
2540 flog = getfile(fn)
2539 return util.binary(flog.read(ctx.filenode(fn)))
2541 return util.binary(flog.read(ctx.filenode(fn)))
2540
2542
2541 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2543 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2542 if opts.get('all'):
2544 if opts.get('all'):
2543 iter = difflinestates(pstates, states)
2545 iter = difflinestates(pstates, states)
2544 else:
2546 else:
2545 iter = [('', l) for l in states]
2547 iter = [('', l) for l in states]
2546 for change, l in iter:
2548 for change, l in iter:
2547 fm.startitem()
2549 fm.startitem()
2548 fm.data(node=fm.hexfunc(ctx.node()))
2550 fm.data(node=fm.hexfunc(ctx.node()))
2549 cols = [
2551 cols = [
2550 ('filename', fn, True),
2552 ('filename', fn, True),
2551 ('rev', rev, True),
2553 ('rev', rev, True),
2552 ('linenumber', l.linenum, opts.get('line_number')),
2554 ('linenumber', l.linenum, opts.get('line_number')),
2553 ]
2555 ]
2554 if opts.get('all'):
2556 if opts.get('all'):
2555 cols.append(('change', change, True))
2557 cols.append(('change', change, True))
2556 cols.extend([
2558 cols.extend([
2557 ('user', formatuser(ctx.user()), opts.get('user')),
2559 ('user', formatuser(ctx.user()), opts.get('user')),
2558 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2560 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2559 ])
2561 ])
2560 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2562 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2561 for name, data, cond in cols:
2563 for name, data, cond in cols:
2562 field = fieldnamemap.get(name, name)
2564 field = fieldnamemap.get(name, name)
2563 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2565 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2564 if cond and name != lastcol:
2566 if cond and name != lastcol:
2565 fm.plain(sep, label='grep.sep')
2567 fm.plain(sep, label='grep.sep')
2566 if not opts.get('files_with_matches'):
2568 if not opts.get('files_with_matches'):
2567 fm.plain(sep, label='grep.sep')
2569 fm.plain(sep, label='grep.sep')
2568 if not opts.get('text') and binary():
2570 if not opts.get('text') and binary():
2569 fm.plain(_(" Binary file matches"))
2571 fm.plain(_(" Binary file matches"))
2570 else:
2572 else:
2571 displaymatches(fm.nested('texts'), l)
2573 displaymatches(fm.nested('texts'), l)
2572 fm.plain(eol)
2574 fm.plain(eol)
2573 found = True
2575 found = True
2574 if opts.get('files_with_matches'):
2576 if opts.get('files_with_matches'):
2575 break
2577 break
2576 return found
2578 return found
2577
2579
2578 def displaymatches(fm, l):
2580 def displaymatches(fm, l):
2579 p = 0
2581 p = 0
2580 for s, e in l.findpos():
2582 for s, e in l.findpos():
2581 if p < s:
2583 if p < s:
2582 fm.startitem()
2584 fm.startitem()
2583 fm.write('text', '%s', l.line[p:s])
2585 fm.write('text', '%s', l.line[p:s])
2584 fm.data(matched=False)
2586 fm.data(matched=False)
2585 fm.startitem()
2587 fm.startitem()
2586 fm.write('text', '%s', l.line[s:e], label='grep.match')
2588 fm.write('text', '%s', l.line[s:e], label='grep.match')
2587 fm.data(matched=True)
2589 fm.data(matched=True)
2588 p = e
2590 p = e
2589 if p < len(l.line):
2591 if p < len(l.line):
2590 fm.startitem()
2592 fm.startitem()
2591 fm.write('text', '%s', l.line[p:])
2593 fm.write('text', '%s', l.line[p:])
2592 fm.data(matched=False)
2594 fm.data(matched=False)
2593 fm.end()
2595 fm.end()
2594
2596
2595 skip = {}
2597 skip = {}
2596 revfiles = {}
2598 revfiles = {}
2597 matchfn = scmutil.match(repo[None], pats, opts)
2599 matchfn = scmutil.match(repo[None], pats, opts)
2598 found = False
2600 found = False
2599 follow = opts.get('follow')
2601 follow = opts.get('follow')
2600
2602
2601 def prep(ctx, fns):
2603 def prep(ctx, fns):
2602 rev = ctx.rev()
2604 rev = ctx.rev()
2603 pctx = ctx.p1()
2605 pctx = ctx.p1()
2604 parent = pctx.rev()
2606 parent = pctx.rev()
2605 matches.setdefault(rev, {})
2607 matches.setdefault(rev, {})
2606 matches.setdefault(parent, {})
2608 matches.setdefault(parent, {})
2607 files = revfiles.setdefault(rev, [])
2609 files = revfiles.setdefault(rev, [])
2608 for fn in fns:
2610 for fn in fns:
2609 flog = getfile(fn)
2611 flog = getfile(fn)
2610 try:
2612 try:
2611 fnode = ctx.filenode(fn)
2613 fnode = ctx.filenode(fn)
2612 except error.LookupError:
2614 except error.LookupError:
2613 continue
2615 continue
2614
2616
2615 copied = flog.renamed(fnode)
2617 copied = flog.renamed(fnode)
2616 copy = follow and copied and copied[0]
2618 copy = follow and copied and copied[0]
2617 if copy:
2619 if copy:
2618 copies.setdefault(rev, {})[fn] = copy
2620 copies.setdefault(rev, {})[fn] = copy
2619 if fn in skip:
2621 if fn in skip:
2620 if copy:
2622 if copy:
2621 skip[copy] = True
2623 skip[copy] = True
2622 continue
2624 continue
2623 files.append(fn)
2625 files.append(fn)
2624
2626
2625 if fn not in matches[rev]:
2627 if fn not in matches[rev]:
2626 grepbody(fn, rev, flog.read(fnode))
2628 grepbody(fn, rev, flog.read(fnode))
2627
2629
2628 pfn = copy or fn
2630 pfn = copy or fn
2629 if pfn not in matches[parent]:
2631 if pfn not in matches[parent]:
2630 try:
2632 try:
2631 fnode = pctx.filenode(pfn)
2633 fnode = pctx.filenode(pfn)
2632 grepbody(pfn, parent, flog.read(fnode))
2634 grepbody(pfn, parent, flog.read(fnode))
2633 except error.LookupError:
2635 except error.LookupError:
2634 pass
2636 pass
2635
2637
2636 ui.pager('grep')
2638 ui.pager('grep')
2637 fm = ui.formatter('grep', opts)
2639 fm = ui.formatter('grep', opts)
2638 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2640 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2639 rev = ctx.rev()
2641 rev = ctx.rev()
2640 parent = ctx.p1().rev()
2642 parent = ctx.p1().rev()
2641 for fn in sorted(revfiles.get(rev, [])):
2643 for fn in sorted(revfiles.get(rev, [])):
2642 states = matches[rev][fn]
2644 states = matches[rev][fn]
2643 copy = copies.get(rev, {}).get(fn)
2645 copy = copies.get(rev, {}).get(fn)
2644 if fn in skip:
2646 if fn in skip:
2645 if copy:
2647 if copy:
2646 skip[copy] = True
2648 skip[copy] = True
2647 continue
2649 continue
2648 pstates = matches.get(parent, {}).get(copy or fn, [])
2650 pstates = matches.get(parent, {}).get(copy or fn, [])
2649 if pstates or states:
2651 if pstates or states:
2650 r = display(fm, fn, ctx, pstates, states)
2652 r = display(fm, fn, ctx, pstates, states)
2651 found = found or r
2653 found = found or r
2652 if r and not opts.get('all'):
2654 if r and not opts.get('all'):
2653 skip[fn] = True
2655 skip[fn] = True
2654 if copy:
2656 if copy:
2655 skip[copy] = True
2657 skip[copy] = True
2656 del matches[rev]
2658 del matches[rev]
2657 del revfiles[rev]
2659 del revfiles[rev]
2658 fm.end()
2660 fm.end()
2659
2661
2660 return not found
2662 return not found
2661
2663
2662 @command('heads',
2664 @command('heads',
2663 [('r', 'rev', '',
2665 [('r', 'rev', '',
2664 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2666 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2665 ('t', 'topo', False, _('show topological heads only')),
2667 ('t', 'topo', False, _('show topological heads only')),
2666 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2668 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2667 ('c', 'closed', False, _('show normal and closed branch heads')),
2669 ('c', 'closed', False, _('show normal and closed branch heads')),
2668 ] + templateopts,
2670 ] + templateopts,
2669 _('[-ct] [-r STARTREV] [REV]...'))
2671 _('[-ct] [-r STARTREV] [REV]...'))
2670 def heads(ui, repo, *branchrevs, **opts):
2672 def heads(ui, repo, *branchrevs, **opts):
2671 """show branch heads
2673 """show branch heads
2672
2674
2673 With no arguments, show all open branch heads in the repository.
2675 With no arguments, show all open branch heads in the repository.
2674 Branch heads are changesets that have no descendants on the
2676 Branch heads are changesets that have no descendants on the
2675 same branch. They are where development generally takes place and
2677 same branch. They are where development generally takes place and
2676 are the usual targets for update and merge operations.
2678 are the usual targets for update and merge operations.
2677
2679
2678 If one or more REVs are given, only open branch heads on the
2680 If one or more REVs are given, only open branch heads on the
2679 branches associated with the specified changesets are shown. This
2681 branches associated with the specified changesets are shown. This
2680 means that you can use :hg:`heads .` to see the heads on the
2682 means that you can use :hg:`heads .` to see the heads on the
2681 currently checked-out branch.
2683 currently checked-out branch.
2682
2684
2683 If -c/--closed is specified, also show branch heads marked closed
2685 If -c/--closed is specified, also show branch heads marked closed
2684 (see :hg:`commit --close-branch`).
2686 (see :hg:`commit --close-branch`).
2685
2687
2686 If STARTREV is specified, only those heads that are descendants of
2688 If STARTREV is specified, only those heads that are descendants of
2687 STARTREV will be displayed.
2689 STARTREV will be displayed.
2688
2690
2689 If -t/--topo is specified, named branch mechanics will be ignored and only
2691 If -t/--topo is specified, named branch mechanics will be ignored and only
2690 topological heads (changesets with no children) will be shown.
2692 topological heads (changesets with no children) will be shown.
2691
2693
2692 Returns 0 if matching heads are found, 1 if not.
2694 Returns 0 if matching heads are found, 1 if not.
2693 """
2695 """
2694
2696
2695 opts = pycompat.byteskwargs(opts)
2697 opts = pycompat.byteskwargs(opts)
2696 start = None
2698 start = None
2697 if 'rev' in opts:
2699 if 'rev' in opts:
2698 start = scmutil.revsingle(repo, opts['rev'], None).node()
2700 start = scmutil.revsingle(repo, opts['rev'], None).node()
2699
2701
2700 if opts.get('topo'):
2702 if opts.get('topo'):
2701 heads = [repo[h] for h in repo.heads(start)]
2703 heads = [repo[h] for h in repo.heads(start)]
2702 else:
2704 else:
2703 heads = []
2705 heads = []
2704 for branch in repo.branchmap():
2706 for branch in repo.branchmap():
2705 heads += repo.branchheads(branch, start, opts.get('closed'))
2707 heads += repo.branchheads(branch, start, opts.get('closed'))
2706 heads = [repo[h] for h in heads]
2708 heads = [repo[h] for h in heads]
2707
2709
2708 if branchrevs:
2710 if branchrevs:
2709 branches = set(repo[br].branch() for br in branchrevs)
2711 branches = set(repo[br].branch() for br in branchrevs)
2710 heads = [h for h in heads if h.branch() in branches]
2712 heads = [h for h in heads if h.branch() in branches]
2711
2713
2712 if opts.get('active') and branchrevs:
2714 if opts.get('active') and branchrevs:
2713 dagheads = repo.heads(start)
2715 dagheads = repo.heads(start)
2714 heads = [h for h in heads if h.node() in dagheads]
2716 heads = [h for h in heads if h.node() in dagheads]
2715
2717
2716 if branchrevs:
2718 if branchrevs:
2717 haveheads = set(h.branch() for h in heads)
2719 haveheads = set(h.branch() for h in heads)
2718 if branches - haveheads:
2720 if branches - haveheads:
2719 headless = ', '.join(b for b in branches - haveheads)
2721 headless = ', '.join(b for b in branches - haveheads)
2720 msg = _('no open branch heads found on branches %s')
2722 msg = _('no open branch heads found on branches %s')
2721 if opts.get('rev'):
2723 if opts.get('rev'):
2722 msg += _(' (started at %s)') % opts['rev']
2724 msg += _(' (started at %s)') % opts['rev']
2723 ui.warn((msg + '\n') % headless)
2725 ui.warn((msg + '\n') % headless)
2724
2726
2725 if not heads:
2727 if not heads:
2726 return 1
2728 return 1
2727
2729
2728 ui.pager('heads')
2730 ui.pager('heads')
2729 heads = sorted(heads, key=lambda x: -x.rev())
2731 heads = sorted(heads, key=lambda x: -x.rev())
2730 displayer = cmdutil.show_changeset(ui, repo, opts)
2732 displayer = cmdutil.show_changeset(ui, repo, opts)
2731 for ctx in heads:
2733 for ctx in heads:
2732 displayer.show(ctx)
2734 displayer.show(ctx)
2733 displayer.close()
2735 displayer.close()
2734
2736
2735 @command('help',
2737 @command('help',
2736 [('e', 'extension', None, _('show only help for extensions')),
2738 [('e', 'extension', None, _('show only help for extensions')),
2737 ('c', 'command', None, _('show only help for commands')),
2739 ('c', 'command', None, _('show only help for commands')),
2738 ('k', 'keyword', None, _('show topics matching keyword')),
2740 ('k', 'keyword', None, _('show topics matching keyword')),
2739 ('s', 'system', [], _('show help for specific platform(s)')),
2741 ('s', 'system', [], _('show help for specific platform(s)')),
2740 ],
2742 ],
2741 _('[-ecks] [TOPIC]'),
2743 _('[-ecks] [TOPIC]'),
2742 norepo=True)
2744 norepo=True)
2743 def help_(ui, name=None, **opts):
2745 def help_(ui, name=None, **opts):
2744 """show help for a given topic or a help overview
2746 """show help for a given topic or a help overview
2745
2747
2746 With no arguments, print a list of commands with short help messages.
2748 With no arguments, print a list of commands with short help messages.
2747
2749
2748 Given a topic, extension, or command name, print help for that
2750 Given a topic, extension, or command name, print help for that
2749 topic.
2751 topic.
2750
2752
2751 Returns 0 if successful.
2753 Returns 0 if successful.
2752 """
2754 """
2753
2755
2754 keep = opts.get(r'system') or []
2756 keep = opts.get(r'system') or []
2755 if len(keep) == 0:
2757 if len(keep) == 0:
2756 if pycompat.sysplatform.startswith('win'):
2758 if pycompat.sysplatform.startswith('win'):
2757 keep.append('windows')
2759 keep.append('windows')
2758 elif pycompat.sysplatform == 'OpenVMS':
2760 elif pycompat.sysplatform == 'OpenVMS':
2759 keep.append('vms')
2761 keep.append('vms')
2760 elif pycompat.sysplatform == 'plan9':
2762 elif pycompat.sysplatform == 'plan9':
2761 keep.append('plan9')
2763 keep.append('plan9')
2762 else:
2764 else:
2763 keep.append('unix')
2765 keep.append('unix')
2764 keep.append(pycompat.sysplatform.lower())
2766 keep.append(pycompat.sysplatform.lower())
2765 if ui.verbose:
2767 if ui.verbose:
2766 keep.append('verbose')
2768 keep.append('verbose')
2767
2769
2768 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2770 formatted = help.formattedhelp(ui, name, keep=keep, **opts)
2769 ui.pager('help')
2771 ui.pager('help')
2770 ui.write(formatted)
2772 ui.write(formatted)
2771
2773
2772
2774
2773 @command('identify|id',
2775 @command('identify|id',
2774 [('r', 'rev', '',
2776 [('r', 'rev', '',
2775 _('identify the specified revision'), _('REV')),
2777 _('identify the specified revision'), _('REV')),
2776 ('n', 'num', None, _('show local revision number')),
2778 ('n', 'num', None, _('show local revision number')),
2777 ('i', 'id', None, _('show global revision id')),
2779 ('i', 'id', None, _('show global revision id')),
2778 ('b', 'branch', None, _('show branch')),
2780 ('b', 'branch', None, _('show branch')),
2779 ('t', 'tags', None, _('show tags')),
2781 ('t', 'tags', None, _('show tags')),
2780 ('B', 'bookmarks', None, _('show bookmarks')),
2782 ('B', 'bookmarks', None, _('show bookmarks')),
2781 ] + remoteopts,
2783 ] + remoteopts,
2782 _('[-nibtB] [-r REV] [SOURCE]'),
2784 _('[-nibtB] [-r REV] [SOURCE]'),
2783 optionalrepo=True)
2785 optionalrepo=True)
2784 def identify(ui, repo, source=None, rev=None,
2786 def identify(ui, repo, source=None, rev=None,
2785 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2787 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2786 """identify the working directory or specified revision
2788 """identify the working directory or specified revision
2787
2789
2788 Print a summary identifying the repository state at REV using one or
2790 Print a summary identifying the repository state at REV using one or
2789 two parent hash identifiers, followed by a "+" if the working
2791 two parent hash identifiers, followed by a "+" if the working
2790 directory has uncommitted changes, the branch name (if not default),
2792 directory has uncommitted changes, the branch name (if not default),
2791 a list of tags, and a list of bookmarks.
2793 a list of tags, and a list of bookmarks.
2792
2794
2793 When REV is not given, print a summary of the current state of the
2795 When REV is not given, print a summary of the current state of the
2794 repository.
2796 repository.
2795
2797
2796 Specifying a path to a repository root or Mercurial bundle will
2798 Specifying a path to a repository root or Mercurial bundle will
2797 cause lookup to operate on that repository/bundle.
2799 cause lookup to operate on that repository/bundle.
2798
2800
2799 .. container:: verbose
2801 .. container:: verbose
2800
2802
2801 Examples:
2803 Examples:
2802
2804
2803 - generate a build identifier for the working directory::
2805 - generate a build identifier for the working directory::
2804
2806
2805 hg id --id > build-id.dat
2807 hg id --id > build-id.dat
2806
2808
2807 - find the revision corresponding to a tag::
2809 - find the revision corresponding to a tag::
2808
2810
2809 hg id -n -r 1.3
2811 hg id -n -r 1.3
2810
2812
2811 - check the most recent revision of a remote repository::
2813 - check the most recent revision of a remote repository::
2812
2814
2813 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2815 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2814
2816
2815 See :hg:`log` for generating more information about specific revisions,
2817 See :hg:`log` for generating more information about specific revisions,
2816 including full hash identifiers.
2818 including full hash identifiers.
2817
2819
2818 Returns 0 if successful.
2820 Returns 0 if successful.
2819 """
2821 """
2820
2822
2821 opts = pycompat.byteskwargs(opts)
2823 opts = pycompat.byteskwargs(opts)
2822 if not repo and not source:
2824 if not repo and not source:
2823 raise error.Abort(_("there is no Mercurial repository here "
2825 raise error.Abort(_("there is no Mercurial repository here "
2824 "(.hg not found)"))
2826 "(.hg not found)"))
2825
2827
2826 if ui.debugflag:
2828 if ui.debugflag:
2827 hexfunc = hex
2829 hexfunc = hex
2828 else:
2830 else:
2829 hexfunc = short
2831 hexfunc = short
2830 default = not (num or id or branch or tags or bookmarks)
2832 default = not (num or id or branch or tags or bookmarks)
2831 output = []
2833 output = []
2832 revs = []
2834 revs = []
2833
2835
2834 if source:
2836 if source:
2835 source, branches = hg.parseurl(ui.expandpath(source))
2837 source, branches = hg.parseurl(ui.expandpath(source))
2836 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2838 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2837 repo = peer.local()
2839 repo = peer.local()
2838 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2840 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2839
2841
2840 if not repo:
2842 if not repo:
2841 if num or branch or tags:
2843 if num or branch or tags:
2842 raise error.Abort(
2844 raise error.Abort(
2843 _("can't query remote revision number, branch, or tags"))
2845 _("can't query remote revision number, branch, or tags"))
2844 if not rev and revs:
2846 if not rev and revs:
2845 rev = revs[0]
2847 rev = revs[0]
2846 if not rev:
2848 if not rev:
2847 rev = "tip"
2849 rev = "tip"
2848
2850
2849 remoterev = peer.lookup(rev)
2851 remoterev = peer.lookup(rev)
2850 if default or id:
2852 if default or id:
2851 output = [hexfunc(remoterev)]
2853 output = [hexfunc(remoterev)]
2852
2854
2853 def getbms():
2855 def getbms():
2854 bms = []
2856 bms = []
2855
2857
2856 if 'bookmarks' in peer.listkeys('namespaces'):
2858 if 'bookmarks' in peer.listkeys('namespaces'):
2857 hexremoterev = hex(remoterev)
2859 hexremoterev = hex(remoterev)
2858 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2860 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2859 if bmr == hexremoterev]
2861 if bmr == hexremoterev]
2860
2862
2861 return sorted(bms)
2863 return sorted(bms)
2862
2864
2863 if bookmarks:
2865 if bookmarks:
2864 output.extend(getbms())
2866 output.extend(getbms())
2865 elif default and not ui.quiet:
2867 elif default and not ui.quiet:
2866 # multiple bookmarks for a single parent separated by '/'
2868 # multiple bookmarks for a single parent separated by '/'
2867 bm = '/'.join(getbms())
2869 bm = '/'.join(getbms())
2868 if bm:
2870 if bm:
2869 output.append(bm)
2871 output.append(bm)
2870 else:
2872 else:
2871 ctx = scmutil.revsingle(repo, rev, None)
2873 ctx = scmutil.revsingle(repo, rev, None)
2872
2874
2873 if ctx.rev() is None:
2875 if ctx.rev() is None:
2874 ctx = repo[None]
2876 ctx = repo[None]
2875 parents = ctx.parents()
2877 parents = ctx.parents()
2876 taglist = []
2878 taglist = []
2877 for p in parents:
2879 for p in parents:
2878 taglist.extend(p.tags())
2880 taglist.extend(p.tags())
2879
2881
2880 changed = ""
2882 changed = ""
2881 if default or id or num:
2883 if default or id or num:
2882 if (any(repo.status())
2884 if (any(repo.status())
2883 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2885 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2884 changed = '+'
2886 changed = '+'
2885 if default or id:
2887 if default or id:
2886 output = ["%s%s" %
2888 output = ["%s%s" %
2887 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2889 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2888 if num:
2890 if num:
2889 output.append("%s%s" %
2891 output.append("%s%s" %
2890 ('+'.join([str(p.rev()) for p in parents]), changed))
2892 ('+'.join([str(p.rev()) for p in parents]), changed))
2891 else:
2893 else:
2892 if default or id:
2894 if default or id:
2893 output = [hexfunc(ctx.node())]
2895 output = [hexfunc(ctx.node())]
2894 if num:
2896 if num:
2895 output.append(str(ctx.rev()))
2897 output.append(str(ctx.rev()))
2896 taglist = ctx.tags()
2898 taglist = ctx.tags()
2897
2899
2898 if default and not ui.quiet:
2900 if default and not ui.quiet:
2899 b = ctx.branch()
2901 b = ctx.branch()
2900 if b != 'default':
2902 if b != 'default':
2901 output.append("(%s)" % b)
2903 output.append("(%s)" % b)
2902
2904
2903 # multiple tags for a single parent separated by '/'
2905 # multiple tags for a single parent separated by '/'
2904 t = '/'.join(taglist)
2906 t = '/'.join(taglist)
2905 if t:
2907 if t:
2906 output.append(t)
2908 output.append(t)
2907
2909
2908 # multiple bookmarks for a single parent separated by '/'
2910 # multiple bookmarks for a single parent separated by '/'
2909 bm = '/'.join(ctx.bookmarks())
2911 bm = '/'.join(ctx.bookmarks())
2910 if bm:
2912 if bm:
2911 output.append(bm)
2913 output.append(bm)
2912 else:
2914 else:
2913 if branch:
2915 if branch:
2914 output.append(ctx.branch())
2916 output.append(ctx.branch())
2915
2917
2916 if tags:
2918 if tags:
2917 output.extend(taglist)
2919 output.extend(taglist)
2918
2920
2919 if bookmarks:
2921 if bookmarks:
2920 output.extend(ctx.bookmarks())
2922 output.extend(ctx.bookmarks())
2921
2923
2922 ui.write("%s\n" % ' '.join(output))
2924 ui.write("%s\n" % ' '.join(output))
2923
2925
2924 @command('import|patch',
2926 @command('import|patch',
2925 [('p', 'strip', 1,
2927 [('p', 'strip', 1,
2926 _('directory strip option for patch. This has the same '
2928 _('directory strip option for patch. This has the same '
2927 'meaning as the corresponding patch option'), _('NUM')),
2929 'meaning as the corresponding patch option'), _('NUM')),
2928 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2930 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2929 ('e', 'edit', False, _('invoke editor on commit messages')),
2931 ('e', 'edit', False, _('invoke editor on commit messages')),
2930 ('f', 'force', None,
2932 ('f', 'force', None,
2931 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2933 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2932 ('', 'no-commit', None,
2934 ('', 'no-commit', None,
2933 _("don't commit, just update the working directory")),
2935 _("don't commit, just update the working directory")),
2934 ('', 'bypass', None,
2936 ('', 'bypass', None,
2935 _("apply patch without touching the working directory")),
2937 _("apply patch without touching the working directory")),
2936 ('', 'partial', None,
2938 ('', 'partial', None,
2937 _('commit even if some hunks fail')),
2939 _('commit even if some hunks fail')),
2938 ('', 'exact', None,
2940 ('', 'exact', None,
2939 _('abort if patch would apply lossily')),
2941 _('abort if patch would apply lossily')),
2940 ('', 'prefix', '',
2942 ('', 'prefix', '',
2941 _('apply patch to subdirectory'), _('DIR')),
2943 _('apply patch to subdirectory'), _('DIR')),
2942 ('', 'import-branch', None,
2944 ('', 'import-branch', None,
2943 _('use any branch information in patch (implied by --exact)'))] +
2945 _('use any branch information in patch (implied by --exact)'))] +
2944 commitopts + commitopts2 + similarityopts,
2946 commitopts + commitopts2 + similarityopts,
2945 _('[OPTION]... PATCH...'))
2947 _('[OPTION]... PATCH...'))
2946 def import_(ui, repo, patch1=None, *patches, **opts):
2948 def import_(ui, repo, patch1=None, *patches, **opts):
2947 """import an ordered set of patches
2949 """import an ordered set of patches
2948
2950
2949 Import a list of patches and commit them individually (unless
2951 Import a list of patches and commit them individually (unless
2950 --no-commit is specified).
2952 --no-commit is specified).
2951
2953
2952 To read a patch from standard input (stdin), use "-" as the patch
2954 To read a patch from standard input (stdin), use "-" as the patch
2953 name. If a URL is specified, the patch will be downloaded from
2955 name. If a URL is specified, the patch will be downloaded from
2954 there.
2956 there.
2955
2957
2956 Import first applies changes to the working directory (unless
2958 Import first applies changes to the working directory (unless
2957 --bypass is specified), import will abort if there are outstanding
2959 --bypass is specified), import will abort if there are outstanding
2958 changes.
2960 changes.
2959
2961
2960 Use --bypass to apply and commit patches directly to the
2962 Use --bypass to apply and commit patches directly to the
2961 repository, without affecting the working directory. Without
2963 repository, without affecting the working directory. Without
2962 --exact, patches will be applied on top of the working directory
2964 --exact, patches will be applied on top of the working directory
2963 parent revision.
2965 parent revision.
2964
2966
2965 You can import a patch straight from a mail message. Even patches
2967 You can import a patch straight from a mail message. Even patches
2966 as attachments work (to use the body part, it must have type
2968 as attachments work (to use the body part, it must have type
2967 text/plain or text/x-patch). From and Subject headers of email
2969 text/plain or text/x-patch). From and Subject headers of email
2968 message are used as default committer and commit message. All
2970 message are used as default committer and commit message. All
2969 text/plain body parts before first diff are added to the commit
2971 text/plain body parts before first diff are added to the commit
2970 message.
2972 message.
2971
2973
2972 If the imported patch was generated by :hg:`export`, user and
2974 If the imported patch was generated by :hg:`export`, user and
2973 description from patch override values from message headers and
2975 description from patch override values from message headers and
2974 body. Values given on command line with -m/--message and -u/--user
2976 body. Values given on command line with -m/--message and -u/--user
2975 override these.
2977 override these.
2976
2978
2977 If --exact is specified, import will set the working directory to
2979 If --exact is specified, import will set the working directory to
2978 the parent of each patch before applying it, and will abort if the
2980 the parent of each patch before applying it, and will abort if the
2979 resulting changeset has a different ID than the one recorded in
2981 resulting changeset has a different ID than the one recorded in
2980 the patch. This will guard against various ways that portable
2982 the patch. This will guard against various ways that portable
2981 patch formats and mail systems might fail to transfer Mercurial
2983 patch formats and mail systems might fail to transfer Mercurial
2982 data or metadata. See :hg:`bundle` for lossless transmission.
2984 data or metadata. See :hg:`bundle` for lossless transmission.
2983
2985
2984 Use --partial to ensure a changeset will be created from the patch
2986 Use --partial to ensure a changeset will be created from the patch
2985 even if some hunks fail to apply. Hunks that fail to apply will be
2987 even if some hunks fail to apply. Hunks that fail to apply will be
2986 written to a <target-file>.rej file. Conflicts can then be resolved
2988 written to a <target-file>.rej file. Conflicts can then be resolved
2987 by hand before :hg:`commit --amend` is run to update the created
2989 by hand before :hg:`commit --amend` is run to update the created
2988 changeset. This flag exists to let people import patches that
2990 changeset. This flag exists to let people import patches that
2989 partially apply without losing the associated metadata (author,
2991 partially apply without losing the associated metadata (author,
2990 date, description, ...).
2992 date, description, ...).
2991
2993
2992 .. note::
2994 .. note::
2993
2995
2994 When no hunks apply cleanly, :hg:`import --partial` will create
2996 When no hunks apply cleanly, :hg:`import --partial` will create
2995 an empty changeset, importing only the patch metadata.
2997 an empty changeset, importing only the patch metadata.
2996
2998
2997 With -s/--similarity, hg will attempt to discover renames and
2999 With -s/--similarity, hg will attempt to discover renames and
2998 copies in the patch in the same way as :hg:`addremove`.
3000 copies in the patch in the same way as :hg:`addremove`.
2999
3001
3000 It is possible to use external patch programs to perform the patch
3002 It is possible to use external patch programs to perform the patch
3001 by setting the ``ui.patch`` configuration option. For the default
3003 by setting the ``ui.patch`` configuration option. For the default
3002 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3004 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3003 See :hg:`help config` for more information about configuration
3005 See :hg:`help config` for more information about configuration
3004 files and how to use these options.
3006 files and how to use these options.
3005
3007
3006 See :hg:`help dates` for a list of formats valid for -d/--date.
3008 See :hg:`help dates` for a list of formats valid for -d/--date.
3007
3009
3008 .. container:: verbose
3010 .. container:: verbose
3009
3011
3010 Examples:
3012 Examples:
3011
3013
3012 - import a traditional patch from a website and detect renames::
3014 - import a traditional patch from a website and detect renames::
3013
3015
3014 hg import -s 80 http://example.com/bugfix.patch
3016 hg import -s 80 http://example.com/bugfix.patch
3015
3017
3016 - import a changeset from an hgweb server::
3018 - import a changeset from an hgweb server::
3017
3019
3018 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3020 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3019
3021
3020 - import all the patches in an Unix-style mbox::
3022 - import all the patches in an Unix-style mbox::
3021
3023
3022 hg import incoming-patches.mbox
3024 hg import incoming-patches.mbox
3023
3025
3024 - import patches from stdin::
3026 - import patches from stdin::
3025
3027
3026 hg import -
3028 hg import -
3027
3029
3028 - attempt to exactly restore an exported changeset (not always
3030 - attempt to exactly restore an exported changeset (not always
3029 possible)::
3031 possible)::
3030
3032
3031 hg import --exact proposed-fix.patch
3033 hg import --exact proposed-fix.patch
3032
3034
3033 - use an external tool to apply a patch which is too fuzzy for
3035 - use an external tool to apply a patch which is too fuzzy for
3034 the default internal tool.
3036 the default internal tool.
3035
3037
3036 hg import --config ui.patch="patch --merge" fuzzy.patch
3038 hg import --config ui.patch="patch --merge" fuzzy.patch
3037
3039
3038 - change the default fuzzing from 2 to a less strict 7
3040 - change the default fuzzing from 2 to a less strict 7
3039
3041
3040 hg import --config ui.fuzz=7 fuzz.patch
3042 hg import --config ui.fuzz=7 fuzz.patch
3041
3043
3042 Returns 0 on success, 1 on partial success (see --partial).
3044 Returns 0 on success, 1 on partial success (see --partial).
3043 """
3045 """
3044
3046
3045 opts = pycompat.byteskwargs(opts)
3047 opts = pycompat.byteskwargs(opts)
3046 if not patch1:
3048 if not patch1:
3047 raise error.Abort(_('need at least one patch to import'))
3049 raise error.Abort(_('need at least one patch to import'))
3048
3050
3049 patches = (patch1,) + patches
3051 patches = (patch1,) + patches
3050
3052
3051 date = opts.get('date')
3053 date = opts.get('date')
3052 if date:
3054 if date:
3053 opts['date'] = util.parsedate(date)
3055 opts['date'] = util.parsedate(date)
3054
3056
3055 exact = opts.get('exact')
3057 exact = opts.get('exact')
3056 update = not opts.get('bypass')
3058 update = not opts.get('bypass')
3057 if not update and opts.get('no_commit'):
3059 if not update and opts.get('no_commit'):
3058 raise error.Abort(_('cannot use --no-commit with --bypass'))
3060 raise error.Abort(_('cannot use --no-commit with --bypass'))
3059 try:
3061 try:
3060 sim = float(opts.get('similarity') or 0)
3062 sim = float(opts.get('similarity') or 0)
3061 except ValueError:
3063 except ValueError:
3062 raise error.Abort(_('similarity must be a number'))
3064 raise error.Abort(_('similarity must be a number'))
3063 if sim < 0 or sim > 100:
3065 if sim < 0 or sim > 100:
3064 raise error.Abort(_('similarity must be between 0 and 100'))
3066 raise error.Abort(_('similarity must be between 0 and 100'))
3065 if sim and not update:
3067 if sim and not update:
3066 raise error.Abort(_('cannot use --similarity with --bypass'))
3068 raise error.Abort(_('cannot use --similarity with --bypass'))
3067 if exact:
3069 if exact:
3068 if opts.get('edit'):
3070 if opts.get('edit'):
3069 raise error.Abort(_('cannot use --exact with --edit'))
3071 raise error.Abort(_('cannot use --exact with --edit'))
3070 if opts.get('prefix'):
3072 if opts.get('prefix'):
3071 raise error.Abort(_('cannot use --exact with --prefix'))
3073 raise error.Abort(_('cannot use --exact with --prefix'))
3072
3074
3073 base = opts["base"]
3075 base = opts["base"]
3074 wlock = dsguard = lock = tr = None
3076 wlock = dsguard = lock = tr = None
3075 msgs = []
3077 msgs = []
3076 ret = 0
3078 ret = 0
3077
3079
3078
3080
3079 try:
3081 try:
3080 wlock = repo.wlock()
3082 wlock = repo.wlock()
3081
3083
3082 if update:
3084 if update:
3083 cmdutil.checkunfinished(repo)
3085 cmdutil.checkunfinished(repo)
3084 if (exact or not opts.get('force')):
3086 if (exact or not opts.get('force')):
3085 cmdutil.bailifchanged(repo)
3087 cmdutil.bailifchanged(repo)
3086
3088
3087 if not opts.get('no_commit'):
3089 if not opts.get('no_commit'):
3088 lock = repo.lock()
3090 lock = repo.lock()
3089 tr = repo.transaction('import')
3091 tr = repo.transaction('import')
3090 else:
3092 else:
3091 dsguard = dirstateguard.dirstateguard(repo, 'import')
3093 dsguard = dirstateguard.dirstateguard(repo, 'import')
3092 parents = repo[None].parents()
3094 parents = repo[None].parents()
3093 for patchurl in patches:
3095 for patchurl in patches:
3094 if patchurl == '-':
3096 if patchurl == '-':
3095 ui.status(_('applying patch from stdin\n'))
3097 ui.status(_('applying patch from stdin\n'))
3096 patchfile = ui.fin
3098 patchfile = ui.fin
3097 patchurl = 'stdin' # for error message
3099 patchurl = 'stdin' # for error message
3098 else:
3100 else:
3099 patchurl = os.path.join(base, patchurl)
3101 patchurl = os.path.join(base, patchurl)
3100 ui.status(_('applying %s\n') % patchurl)
3102 ui.status(_('applying %s\n') % patchurl)
3101 patchfile = hg.openpath(ui, patchurl)
3103 patchfile = hg.openpath(ui, patchurl)
3102
3104
3103 haspatch = False
3105 haspatch = False
3104 for hunk in patch.split(patchfile):
3106 for hunk in patch.split(patchfile):
3105 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3107 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3106 parents, opts,
3108 parents, opts,
3107 msgs, hg.clean)
3109 msgs, hg.clean)
3108 if msg:
3110 if msg:
3109 haspatch = True
3111 haspatch = True
3110 ui.note(msg + '\n')
3112 ui.note(msg + '\n')
3111 if update or exact:
3113 if update or exact:
3112 parents = repo[None].parents()
3114 parents = repo[None].parents()
3113 else:
3115 else:
3114 parents = [repo[node]]
3116 parents = [repo[node]]
3115 if rej:
3117 if rej:
3116 ui.write_err(_("patch applied partially\n"))
3118 ui.write_err(_("patch applied partially\n"))
3117 ui.write_err(_("(fix the .rej files and run "
3119 ui.write_err(_("(fix the .rej files and run "
3118 "`hg commit --amend`)\n"))
3120 "`hg commit --amend`)\n"))
3119 ret = 1
3121 ret = 1
3120 break
3122 break
3121
3123
3122 if not haspatch:
3124 if not haspatch:
3123 raise error.Abort(_('%s: no diffs found') % patchurl)
3125 raise error.Abort(_('%s: no diffs found') % patchurl)
3124
3126
3125 if tr:
3127 if tr:
3126 tr.close()
3128 tr.close()
3127 if msgs:
3129 if msgs:
3128 repo.savecommitmessage('\n* * *\n'.join(msgs))
3130 repo.savecommitmessage('\n* * *\n'.join(msgs))
3129 if dsguard:
3131 if dsguard:
3130 dsguard.close()
3132 dsguard.close()
3131 return ret
3133 return ret
3132 finally:
3134 finally:
3133 if tr:
3135 if tr:
3134 tr.release()
3136 tr.release()
3135 release(lock, dsguard, wlock)
3137 release(lock, dsguard, wlock)
3136
3138
3137 @command('incoming|in',
3139 @command('incoming|in',
3138 [('f', 'force', None,
3140 [('f', 'force', None,
3139 _('run even if remote repository is unrelated')),
3141 _('run even if remote repository is unrelated')),
3140 ('n', 'newest-first', None, _('show newest record first')),
3142 ('n', 'newest-first', None, _('show newest record first')),
3141 ('', 'bundle', '',
3143 ('', 'bundle', '',
3142 _('file to store the bundles into'), _('FILE')),
3144 _('file to store the bundles into'), _('FILE')),
3143 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3145 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3144 ('B', 'bookmarks', False, _("compare bookmarks")),
3146 ('B', 'bookmarks', False, _("compare bookmarks")),
3145 ('b', 'branch', [],
3147 ('b', 'branch', [],
3146 _('a specific branch you would like to pull'), _('BRANCH')),
3148 _('a specific branch you would like to pull'), _('BRANCH')),
3147 ] + logopts + remoteopts + subrepoopts,
3149 ] + logopts + remoteopts + subrepoopts,
3148 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3150 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3149 def incoming(ui, repo, source="default", **opts):
3151 def incoming(ui, repo, source="default", **opts):
3150 """show new changesets found in source
3152 """show new changesets found in source
3151
3153
3152 Show new changesets found in the specified path/URL or the default
3154 Show new changesets found in the specified path/URL or the default
3153 pull location. These are the changesets that would have been pulled
3155 pull location. These are the changesets that would have been pulled
3154 if a pull at the time you issued this command.
3156 if a pull at the time you issued this command.
3155
3157
3156 See pull for valid source format details.
3158 See pull for valid source format details.
3157
3159
3158 .. container:: verbose
3160 .. container:: verbose
3159
3161
3160 With -B/--bookmarks, the result of bookmark comparison between
3162 With -B/--bookmarks, the result of bookmark comparison between
3161 local and remote repositories is displayed. With -v/--verbose,
3163 local and remote repositories is displayed. With -v/--verbose,
3162 status is also displayed for each bookmark like below::
3164 status is also displayed for each bookmark like below::
3163
3165
3164 BM1 01234567890a added
3166 BM1 01234567890a added
3165 BM2 1234567890ab advanced
3167 BM2 1234567890ab advanced
3166 BM3 234567890abc diverged
3168 BM3 234567890abc diverged
3167 BM4 34567890abcd changed
3169 BM4 34567890abcd changed
3168
3170
3169 The action taken locally when pulling depends on the
3171 The action taken locally when pulling depends on the
3170 status of each bookmark:
3172 status of each bookmark:
3171
3173
3172 :``added``: pull will create it
3174 :``added``: pull will create it
3173 :``advanced``: pull will update it
3175 :``advanced``: pull will update it
3174 :``diverged``: pull will create a divergent bookmark
3176 :``diverged``: pull will create a divergent bookmark
3175 :``changed``: result depends on remote changesets
3177 :``changed``: result depends on remote changesets
3176
3178
3177 From the point of view of pulling behavior, bookmark
3179 From the point of view of pulling behavior, bookmark
3178 existing only in the remote repository are treated as ``added``,
3180 existing only in the remote repository are treated as ``added``,
3179 even if it is in fact locally deleted.
3181 even if it is in fact locally deleted.
3180
3182
3181 .. container:: verbose
3183 .. container:: verbose
3182
3184
3183 For remote repository, using --bundle avoids downloading the
3185 For remote repository, using --bundle avoids downloading the
3184 changesets twice if the incoming is followed by a pull.
3186 changesets twice if the incoming is followed by a pull.
3185
3187
3186 Examples:
3188 Examples:
3187
3189
3188 - show incoming changes with patches and full description::
3190 - show incoming changes with patches and full description::
3189
3191
3190 hg incoming -vp
3192 hg incoming -vp
3191
3193
3192 - show incoming changes excluding merges, store a bundle::
3194 - show incoming changes excluding merges, store a bundle::
3193
3195
3194 hg in -vpM --bundle incoming.hg
3196 hg in -vpM --bundle incoming.hg
3195 hg pull incoming.hg
3197 hg pull incoming.hg
3196
3198
3197 - briefly list changes inside a bundle::
3199 - briefly list changes inside a bundle::
3198
3200
3199 hg in changes.hg -T "{desc|firstline}\\n"
3201 hg in changes.hg -T "{desc|firstline}\\n"
3200
3202
3201 Returns 0 if there are incoming changes, 1 otherwise.
3203 Returns 0 if there are incoming changes, 1 otherwise.
3202 """
3204 """
3203 opts = pycompat.byteskwargs(opts)
3205 opts = pycompat.byteskwargs(opts)
3204 if opts.get('graph'):
3206 if opts.get('graph'):
3205 cmdutil.checkunsupportedgraphflags([], opts)
3207 cmdutil.checkunsupportedgraphflags([], opts)
3206 def display(other, chlist, displayer):
3208 def display(other, chlist, displayer):
3207 revdag = cmdutil.graphrevs(other, chlist, opts)
3209 revdag = cmdutil.graphrevs(other, chlist, opts)
3208 cmdutil.displaygraph(ui, repo, revdag, displayer,
3210 cmdutil.displaygraph(ui, repo, revdag, displayer,
3209 graphmod.asciiedges)
3211 graphmod.asciiedges)
3210
3212
3211 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3213 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3212 return 0
3214 return 0
3213
3215
3214 if opts.get('bundle') and opts.get('subrepos'):
3216 if opts.get('bundle') and opts.get('subrepos'):
3215 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3217 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3216
3218
3217 if opts.get('bookmarks'):
3219 if opts.get('bookmarks'):
3218 source, branches = hg.parseurl(ui.expandpath(source),
3220 source, branches = hg.parseurl(ui.expandpath(source),
3219 opts.get('branch'))
3221 opts.get('branch'))
3220 other = hg.peer(repo, opts, source)
3222 other = hg.peer(repo, opts, source)
3221 if 'bookmarks' not in other.listkeys('namespaces'):
3223 if 'bookmarks' not in other.listkeys('namespaces'):
3222 ui.warn(_("remote doesn't support bookmarks\n"))
3224 ui.warn(_("remote doesn't support bookmarks\n"))
3223 return 0
3225 return 0
3224 ui.pager('incoming')
3226 ui.pager('incoming')
3225 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3227 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3226 return bookmarks.incoming(ui, repo, other)
3228 return bookmarks.incoming(ui, repo, other)
3227
3229
3228 repo._subtoppath = ui.expandpath(source)
3230 repo._subtoppath = ui.expandpath(source)
3229 try:
3231 try:
3230 return hg.incoming(ui, repo, source, opts)
3232 return hg.incoming(ui, repo, source, opts)
3231 finally:
3233 finally:
3232 del repo._subtoppath
3234 del repo._subtoppath
3233
3235
3234
3236
3235 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3237 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3236 norepo=True)
3238 norepo=True)
3237 def init(ui, dest=".", **opts):
3239 def init(ui, dest=".", **opts):
3238 """create a new repository in the given directory
3240 """create a new repository in the given directory
3239
3241
3240 Initialize a new repository in the given directory. If the given
3242 Initialize a new repository in the given directory. If the given
3241 directory does not exist, it will be created.
3243 directory does not exist, it will be created.
3242
3244
3243 If no directory is given, the current directory is used.
3245 If no directory is given, the current directory is used.
3244
3246
3245 It is possible to specify an ``ssh://`` URL as the destination.
3247 It is possible to specify an ``ssh://`` URL as the destination.
3246 See :hg:`help urls` for more information.
3248 See :hg:`help urls` for more information.
3247
3249
3248 Returns 0 on success.
3250 Returns 0 on success.
3249 """
3251 """
3250 opts = pycompat.byteskwargs(opts)
3252 opts = pycompat.byteskwargs(opts)
3251 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3253 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3252
3254
3253 @command('locate',
3255 @command('locate',
3254 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3256 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3255 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3257 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3256 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3258 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3257 ] + walkopts,
3259 ] + walkopts,
3258 _('[OPTION]... [PATTERN]...'))
3260 _('[OPTION]... [PATTERN]...'))
3259 def locate(ui, repo, *pats, **opts):
3261 def locate(ui, repo, *pats, **opts):
3260 """locate files matching specific patterns (DEPRECATED)
3262 """locate files matching specific patterns (DEPRECATED)
3261
3263
3262 Print files under Mercurial control in the working directory whose
3264 Print files under Mercurial control in the working directory whose
3263 names match the given patterns.
3265 names match the given patterns.
3264
3266
3265 By default, this command searches all directories in the working
3267 By default, this command searches all directories in the working
3266 directory. To search just the current directory and its
3268 directory. To search just the current directory and its
3267 subdirectories, use "--include .".
3269 subdirectories, use "--include .".
3268
3270
3269 If no patterns are given to match, this command prints the names
3271 If no patterns are given to match, this command prints the names
3270 of all files under Mercurial control in the working directory.
3272 of all files under Mercurial control in the working directory.
3271
3273
3272 If you want to feed the output of this command into the "xargs"
3274 If you want to feed the output of this command into the "xargs"
3273 command, use the -0 option to both this command and "xargs". This
3275 command, use the -0 option to both this command and "xargs". This
3274 will avoid the problem of "xargs" treating single filenames that
3276 will avoid the problem of "xargs" treating single filenames that
3275 contain whitespace as multiple filenames.
3277 contain whitespace as multiple filenames.
3276
3278
3277 See :hg:`help files` for a more versatile command.
3279 See :hg:`help files` for a more versatile command.
3278
3280
3279 Returns 0 if a match is found, 1 otherwise.
3281 Returns 0 if a match is found, 1 otherwise.
3280 """
3282 """
3281 opts = pycompat.byteskwargs(opts)
3283 opts = pycompat.byteskwargs(opts)
3282 if opts.get('print0'):
3284 if opts.get('print0'):
3283 end = '\0'
3285 end = '\0'
3284 else:
3286 else:
3285 end = '\n'
3287 end = '\n'
3286 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3288 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3287
3289
3288 ret = 1
3290 ret = 1
3289 ctx = repo[rev]
3291 ctx = repo[rev]
3290 m = scmutil.match(ctx, pats, opts, default='relglob',
3292 m = scmutil.match(ctx, pats, opts, default='relglob',
3291 badfn=lambda x, y: False)
3293 badfn=lambda x, y: False)
3292
3294
3293 ui.pager('locate')
3295 ui.pager('locate')
3294 for abs in ctx.matches(m):
3296 for abs in ctx.matches(m):
3295 if opts.get('fullpath'):
3297 if opts.get('fullpath'):
3296 ui.write(repo.wjoin(abs), end)
3298 ui.write(repo.wjoin(abs), end)
3297 else:
3299 else:
3298 ui.write(((pats and m.rel(abs)) or abs), end)
3300 ui.write(((pats and m.rel(abs)) or abs), end)
3299 ret = 0
3301 ret = 0
3300
3302
3301 return ret
3303 return ret
3302
3304
3303 @command('^log|history',
3305 @command('^log|history',
3304 [('f', 'follow', None,
3306 [('f', 'follow', None,
3305 _('follow changeset history, or file history across copies and renames')),
3307 _('follow changeset history, or file history across copies and renames')),
3306 ('', 'follow-first', None,
3308 ('', 'follow-first', None,
3307 _('only follow the first parent of merge changesets (DEPRECATED)')),
3309 _('only follow the first parent of merge changesets (DEPRECATED)')),
3308 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3310 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3309 ('C', 'copies', None, _('show copied files')),
3311 ('C', 'copies', None, _('show copied files')),
3310 ('k', 'keyword', [],
3312 ('k', 'keyword', [],
3311 _('do case-insensitive search for a given text'), _('TEXT')),
3313 _('do case-insensitive search for a given text'), _('TEXT')),
3312 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3314 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3313 ('', 'removed', None, _('include revisions where files were removed')),
3315 ('', 'removed', None, _('include revisions where files were removed')),
3314 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3316 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3315 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3317 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3316 ('', 'only-branch', [],
3318 ('', 'only-branch', [],
3317 _('show only changesets within the given named branch (DEPRECATED)'),
3319 _('show only changesets within the given named branch (DEPRECATED)'),
3318 _('BRANCH')),
3320 _('BRANCH')),
3319 ('b', 'branch', [],
3321 ('b', 'branch', [],
3320 _('show changesets within the given named branch'), _('BRANCH')),
3322 _('show changesets within the given named branch'), _('BRANCH')),
3321 ('P', 'prune', [],
3323 ('P', 'prune', [],
3322 _('do not display revision or any of its ancestors'), _('REV')),
3324 _('do not display revision or any of its ancestors'), _('REV')),
3323 ] + logopts + walkopts,
3325 ] + logopts + walkopts,
3324 _('[OPTION]... [FILE]'),
3326 _('[OPTION]... [FILE]'),
3325 inferrepo=True)
3327 inferrepo=True)
3326 def log(ui, repo, *pats, **opts):
3328 def log(ui, repo, *pats, **opts):
3327 """show revision history of entire repository or files
3329 """show revision history of entire repository or files
3328
3330
3329 Print the revision history of the specified files or the entire
3331 Print the revision history of the specified files or the entire
3330 project.
3332 project.
3331
3333
3332 If no revision range is specified, the default is ``tip:0`` unless
3334 If no revision range is specified, the default is ``tip:0`` unless
3333 --follow is set, in which case the working directory parent is
3335 --follow is set, in which case the working directory parent is
3334 used as the starting revision.
3336 used as the starting revision.
3335
3337
3336 File history is shown without following rename or copy history of
3338 File history is shown without following rename or copy history of
3337 files. Use -f/--follow with a filename to follow history across
3339 files. Use -f/--follow with a filename to follow history across
3338 renames and copies. --follow without a filename will only show
3340 renames and copies. --follow without a filename will only show
3339 ancestors or descendants of the starting revision.
3341 ancestors or descendants of the starting revision.
3340
3342
3341 By default this command prints revision number and changeset id,
3343 By default this command prints revision number and changeset id,
3342 tags, non-trivial parents, user, date and time, and a summary for
3344 tags, non-trivial parents, user, date and time, and a summary for
3343 each commit. When the -v/--verbose switch is used, the list of
3345 each commit. When the -v/--verbose switch is used, the list of
3344 changed files and full commit message are shown.
3346 changed files and full commit message are shown.
3345
3347
3346 With --graph the revisions are shown as an ASCII art DAG with the most
3348 With --graph the revisions are shown as an ASCII art DAG with the most
3347 recent changeset at the top.
3349 recent changeset at the top.
3348 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3350 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3349 and '+' represents a fork where the changeset from the lines below is a
3351 and '+' represents a fork where the changeset from the lines below is a
3350 parent of the 'o' merge on the same line.
3352 parent of the 'o' merge on the same line.
3351 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3353 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
3352 of a '|' indicates one or more revisions in a path are omitted.
3354 of a '|' indicates one or more revisions in a path are omitted.
3353
3355
3354 .. note::
3356 .. note::
3355
3357
3356 :hg:`log --patch` may generate unexpected diff output for merge
3358 :hg:`log --patch` may generate unexpected diff output for merge
3357 changesets, as it will only compare the merge changeset against
3359 changesets, as it will only compare the merge changeset against
3358 its first parent. Also, only files different from BOTH parents
3360 its first parent. Also, only files different from BOTH parents
3359 will appear in files:.
3361 will appear in files:.
3360
3362
3361 .. note::
3363 .. note::
3362
3364
3363 For performance reasons, :hg:`log FILE` may omit duplicate changes
3365 For performance reasons, :hg:`log FILE` may omit duplicate changes
3364 made on branches and will not show removals or mode changes. To
3366 made on branches and will not show removals or mode changes. To
3365 see all such changes, use the --removed switch.
3367 see all such changes, use the --removed switch.
3366
3368
3367 .. container:: verbose
3369 .. container:: verbose
3368
3370
3369 Some examples:
3371 Some examples:
3370
3372
3371 - changesets with full descriptions and file lists::
3373 - changesets with full descriptions and file lists::
3372
3374
3373 hg log -v
3375 hg log -v
3374
3376
3375 - changesets ancestral to the working directory::
3377 - changesets ancestral to the working directory::
3376
3378
3377 hg log -f
3379 hg log -f
3378
3380
3379 - last 10 commits on the current branch::
3381 - last 10 commits on the current branch::
3380
3382
3381 hg log -l 10 -b .
3383 hg log -l 10 -b .
3382
3384
3383 - changesets showing all modifications of a file, including removals::
3385 - changesets showing all modifications of a file, including removals::
3384
3386
3385 hg log --removed file.c
3387 hg log --removed file.c
3386
3388
3387 - all changesets that touch a directory, with diffs, excluding merges::
3389 - all changesets that touch a directory, with diffs, excluding merges::
3388
3390
3389 hg log -Mp lib/
3391 hg log -Mp lib/
3390
3392
3391 - all revision numbers that match a keyword::
3393 - all revision numbers that match a keyword::
3392
3394
3393 hg log -k bug --template "{rev}\\n"
3395 hg log -k bug --template "{rev}\\n"
3394
3396
3395 - the full hash identifier of the working directory parent::
3397 - the full hash identifier of the working directory parent::
3396
3398
3397 hg log -r . --template "{node}\\n"
3399 hg log -r . --template "{node}\\n"
3398
3400
3399 - list available log templates::
3401 - list available log templates::
3400
3402
3401 hg log -T list
3403 hg log -T list
3402
3404
3403 - check if a given changeset is included in a tagged release::
3405 - check if a given changeset is included in a tagged release::
3404
3406
3405 hg log -r "a21ccf and ancestor(1.9)"
3407 hg log -r "a21ccf and ancestor(1.9)"
3406
3408
3407 - find all changesets by some user in a date range::
3409 - find all changesets by some user in a date range::
3408
3410
3409 hg log -k alice -d "may 2008 to jul 2008"
3411 hg log -k alice -d "may 2008 to jul 2008"
3410
3412
3411 - summary of all changesets after the last tag::
3413 - summary of all changesets after the last tag::
3412
3414
3413 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3415 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3414
3416
3415 See :hg:`help dates` for a list of formats valid for -d/--date.
3417 See :hg:`help dates` for a list of formats valid for -d/--date.
3416
3418
3417 See :hg:`help revisions` for more about specifying and ordering
3419 See :hg:`help revisions` for more about specifying and ordering
3418 revisions.
3420 revisions.
3419
3421
3420 See :hg:`help templates` for more about pre-packaged styles and
3422 See :hg:`help templates` for more about pre-packaged styles and
3421 specifying custom templates.
3423 specifying custom templates.
3422
3424
3423 Returns 0 on success.
3425 Returns 0 on success.
3424
3426
3425 """
3427 """
3426 opts = pycompat.byteskwargs(opts)
3428 opts = pycompat.byteskwargs(opts)
3427 if opts.get('follow') and opts.get('rev'):
3429 if opts.get('follow') and opts.get('rev'):
3428 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3430 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3429 del opts['follow']
3431 del opts['follow']
3430
3432
3431 if opts.get('graph'):
3433 if opts.get('graph'):
3432 return cmdutil.graphlog(ui, repo, pats, opts)
3434 return cmdutil.graphlog(ui, repo, pats, opts)
3433
3435
3434 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3436 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3435 limit = cmdutil.loglimit(opts)
3437 limit = cmdutil.loglimit(opts)
3436 count = 0
3438 count = 0
3437
3439
3438 getrenamed = None
3440 getrenamed = None
3439 if opts.get('copies'):
3441 if opts.get('copies'):
3440 endrev = None
3442 endrev = None
3441 if opts.get('rev'):
3443 if opts.get('rev'):
3442 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3444 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3443 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3445 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3444
3446
3445 ui.pager('log')
3447 ui.pager('log')
3446 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3448 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3447 for rev in revs:
3449 for rev in revs:
3448 if count == limit:
3450 if count == limit:
3449 break
3451 break
3450 ctx = repo[rev]
3452 ctx = repo[rev]
3451 copies = None
3453 copies = None
3452 if getrenamed is not None and rev:
3454 if getrenamed is not None and rev:
3453 copies = []
3455 copies = []
3454 for fn in ctx.files():
3456 for fn in ctx.files():
3455 rename = getrenamed(fn, rev)
3457 rename = getrenamed(fn, rev)
3456 if rename:
3458 if rename:
3457 copies.append((fn, rename[0]))
3459 copies.append((fn, rename[0]))
3458 if filematcher:
3460 if filematcher:
3459 revmatchfn = filematcher(ctx.rev())
3461 revmatchfn = filematcher(ctx.rev())
3460 else:
3462 else:
3461 revmatchfn = None
3463 revmatchfn = None
3462 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3464 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3463 if displayer.flush(ctx):
3465 if displayer.flush(ctx):
3464 count += 1
3466 count += 1
3465
3467
3466 displayer.close()
3468 displayer.close()
3467
3469
3468 @command('manifest',
3470 @command('manifest',
3469 [('r', 'rev', '', _('revision to display'), _('REV')),
3471 [('r', 'rev', '', _('revision to display'), _('REV')),
3470 ('', 'all', False, _("list files from all revisions"))]
3472 ('', 'all', False, _("list files from all revisions"))]
3471 + formatteropts,
3473 + formatteropts,
3472 _('[-r REV]'))
3474 _('[-r REV]'))
3473 def manifest(ui, repo, node=None, rev=None, **opts):
3475 def manifest(ui, repo, node=None, rev=None, **opts):
3474 """output the current or given revision of the project manifest
3476 """output the current or given revision of the project manifest
3475
3477
3476 Print a list of version controlled files for the given revision.
3478 Print a list of version controlled files for the given revision.
3477 If no revision is given, the first parent of the working directory
3479 If no revision is given, the first parent of the working directory
3478 is used, or the null revision if no revision is checked out.
3480 is used, or the null revision if no revision is checked out.
3479
3481
3480 With -v, print file permissions, symlink and executable bits.
3482 With -v, print file permissions, symlink and executable bits.
3481 With --debug, print file revision hashes.
3483 With --debug, print file revision hashes.
3482
3484
3483 If option --all is specified, the list of all files from all revisions
3485 If option --all is specified, the list of all files from all revisions
3484 is printed. This includes deleted and renamed files.
3486 is printed. This includes deleted and renamed files.
3485
3487
3486 Returns 0 on success.
3488 Returns 0 on success.
3487 """
3489 """
3488 opts = pycompat.byteskwargs(opts)
3490 opts = pycompat.byteskwargs(opts)
3489 fm = ui.formatter('manifest', opts)
3491 fm = ui.formatter('manifest', opts)
3490
3492
3491 if opts.get('all'):
3493 if opts.get('all'):
3492 if rev or node:
3494 if rev or node:
3493 raise error.Abort(_("can't specify a revision with --all"))
3495 raise error.Abort(_("can't specify a revision with --all"))
3494
3496
3495 res = []
3497 res = []
3496 prefix = "data/"
3498 prefix = "data/"
3497 suffix = ".i"
3499 suffix = ".i"
3498 plen = len(prefix)
3500 plen = len(prefix)
3499 slen = len(suffix)
3501 slen = len(suffix)
3500 with repo.lock():
3502 with repo.lock():
3501 for fn, b, size in repo.store.datafiles():
3503 for fn, b, size in repo.store.datafiles():
3502 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3504 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3503 res.append(fn[plen:-slen])
3505 res.append(fn[plen:-slen])
3504 ui.pager('manifest')
3506 ui.pager('manifest')
3505 for f in res:
3507 for f in res:
3506 fm.startitem()
3508 fm.startitem()
3507 fm.write("path", '%s\n', f)
3509 fm.write("path", '%s\n', f)
3508 fm.end()
3510 fm.end()
3509 return
3511 return
3510
3512
3511 if rev and node:
3513 if rev and node:
3512 raise error.Abort(_("please specify just one revision"))
3514 raise error.Abort(_("please specify just one revision"))
3513
3515
3514 if not node:
3516 if not node:
3515 node = rev
3517 node = rev
3516
3518
3517 char = {'l': '@', 'x': '*', '': ''}
3519 char = {'l': '@', 'x': '*', '': ''}
3518 mode = {'l': '644', 'x': '755', '': '644'}
3520 mode = {'l': '644', 'x': '755', '': '644'}
3519 ctx = scmutil.revsingle(repo, node)
3521 ctx = scmutil.revsingle(repo, node)
3520 mf = ctx.manifest()
3522 mf = ctx.manifest()
3521 ui.pager('manifest')
3523 ui.pager('manifest')
3522 for f in ctx:
3524 for f in ctx:
3523 fm.startitem()
3525 fm.startitem()
3524 fl = ctx[f].flags()
3526 fl = ctx[f].flags()
3525 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3527 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3526 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3528 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3527 fm.write('path', '%s\n', f)
3529 fm.write('path', '%s\n', f)
3528 fm.end()
3530 fm.end()
3529
3531
3530 @command('^merge',
3532 @command('^merge',
3531 [('f', 'force', None,
3533 [('f', 'force', None,
3532 _('force a merge including outstanding changes (DEPRECATED)')),
3534 _('force a merge including outstanding changes (DEPRECATED)')),
3533 ('r', 'rev', '', _('revision to merge'), _('REV')),
3535 ('r', 'rev', '', _('revision to merge'), _('REV')),
3534 ('P', 'preview', None,
3536 ('P', 'preview', None,
3535 _('review revisions to merge (no merge is performed)'))
3537 _('review revisions to merge (no merge is performed)'))
3536 ] + mergetoolopts,
3538 ] + mergetoolopts,
3537 _('[-P] [[-r] REV]'))
3539 _('[-P] [[-r] REV]'))
3538 def merge(ui, repo, node=None, **opts):
3540 def merge(ui, repo, node=None, **opts):
3539 """merge another revision into working directory
3541 """merge another revision into working directory
3540
3542
3541 The current working directory is updated with all changes made in
3543 The current working directory is updated with all changes made in
3542 the requested revision since the last common predecessor revision.
3544 the requested revision since the last common predecessor revision.
3543
3545
3544 Files that changed between either parent are marked as changed for
3546 Files that changed between either parent are marked as changed for
3545 the next commit and a commit must be performed before any further
3547 the next commit and a commit must be performed before any further
3546 updates to the repository are allowed. The next commit will have
3548 updates to the repository are allowed. The next commit will have
3547 two parents.
3549 two parents.
3548
3550
3549 ``--tool`` can be used to specify the merge tool used for file
3551 ``--tool`` can be used to specify the merge tool used for file
3550 merges. It overrides the HGMERGE environment variable and your
3552 merges. It overrides the HGMERGE environment variable and your
3551 configuration files. See :hg:`help merge-tools` for options.
3553 configuration files. See :hg:`help merge-tools` for options.
3552
3554
3553 If no revision is specified, the working directory's parent is a
3555 If no revision is specified, the working directory's parent is a
3554 head revision, and the current branch contains exactly one other
3556 head revision, and the current branch contains exactly one other
3555 head, the other head is merged with by default. Otherwise, an
3557 head, the other head is merged with by default. Otherwise, an
3556 explicit revision with which to merge with must be provided.
3558 explicit revision with which to merge with must be provided.
3557
3559
3558 See :hg:`help resolve` for information on handling file conflicts.
3560 See :hg:`help resolve` for information on handling file conflicts.
3559
3561
3560 To undo an uncommitted merge, use :hg:`update --clean .` which
3562 To undo an uncommitted merge, use :hg:`update --clean .` which
3561 will check out a clean copy of the original merge parent, losing
3563 will check out a clean copy of the original merge parent, losing
3562 all changes.
3564 all changes.
3563
3565
3564 Returns 0 on success, 1 if there are unresolved files.
3566 Returns 0 on success, 1 if there are unresolved files.
3565 """
3567 """
3566
3568
3567 opts = pycompat.byteskwargs(opts)
3569 opts = pycompat.byteskwargs(opts)
3568 if opts.get('rev') and node:
3570 if opts.get('rev') and node:
3569 raise error.Abort(_("please specify just one revision"))
3571 raise error.Abort(_("please specify just one revision"))
3570 if not node:
3572 if not node:
3571 node = opts.get('rev')
3573 node = opts.get('rev')
3572
3574
3573 if node:
3575 if node:
3574 node = scmutil.revsingle(repo, node).node()
3576 node = scmutil.revsingle(repo, node).node()
3575
3577
3576 if not node:
3578 if not node:
3577 node = repo[destutil.destmerge(repo)].node()
3579 node = repo[destutil.destmerge(repo)].node()
3578
3580
3579 if opts.get('preview'):
3581 if opts.get('preview'):
3580 # find nodes that are ancestors of p2 but not of p1
3582 # find nodes that are ancestors of p2 but not of p1
3581 p1 = repo.lookup('.')
3583 p1 = repo.lookup('.')
3582 p2 = repo.lookup(node)
3584 p2 = repo.lookup(node)
3583 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3585 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3584
3586
3585 displayer = cmdutil.show_changeset(ui, repo, opts)
3587 displayer = cmdutil.show_changeset(ui, repo, opts)
3586 for node in nodes:
3588 for node in nodes:
3587 displayer.show(repo[node])
3589 displayer.show(repo[node])
3588 displayer.close()
3590 displayer.close()
3589 return 0
3591 return 0
3590
3592
3591 try:
3593 try:
3592 # ui.forcemerge is an internal variable, do not document
3594 # ui.forcemerge is an internal variable, do not document
3593 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3595 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3594 force = opts.get('force')
3596 force = opts.get('force')
3595 labels = ['working copy', 'merge rev']
3597 labels = ['working copy', 'merge rev']
3596 return hg.merge(repo, node, force=force, mergeforce=force,
3598 return hg.merge(repo, node, force=force, mergeforce=force,
3597 labels=labels)
3599 labels=labels)
3598 finally:
3600 finally:
3599 ui.setconfig('ui', 'forcemerge', '', 'merge')
3601 ui.setconfig('ui', 'forcemerge', '', 'merge')
3600
3602
3601 @command('outgoing|out',
3603 @command('outgoing|out',
3602 [('f', 'force', None, _('run even when the destination is unrelated')),
3604 [('f', 'force', None, _('run even when the destination is unrelated')),
3603 ('r', 'rev', [],
3605 ('r', 'rev', [],
3604 _('a changeset intended to be included in the destination'), _('REV')),
3606 _('a changeset intended to be included in the destination'), _('REV')),
3605 ('n', 'newest-first', None, _('show newest record first')),
3607 ('n', 'newest-first', None, _('show newest record first')),
3606 ('B', 'bookmarks', False, _('compare bookmarks')),
3608 ('B', 'bookmarks', False, _('compare bookmarks')),
3607 ('b', 'branch', [], _('a specific branch you would like to push'),
3609 ('b', 'branch', [], _('a specific branch you would like to push'),
3608 _('BRANCH')),
3610 _('BRANCH')),
3609 ] + logopts + remoteopts + subrepoopts,
3611 ] + logopts + remoteopts + subrepoopts,
3610 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3612 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3611 def outgoing(ui, repo, dest=None, **opts):
3613 def outgoing(ui, repo, dest=None, **opts):
3612 """show changesets not found in the destination
3614 """show changesets not found in the destination
3613
3615
3614 Show changesets not found in the specified destination repository
3616 Show changesets not found in the specified destination repository
3615 or the default push location. These are the changesets that would
3617 or the default push location. These are the changesets that would
3616 be pushed if a push was requested.
3618 be pushed if a push was requested.
3617
3619
3618 See pull for details of valid destination formats.
3620 See pull for details of valid destination formats.
3619
3621
3620 .. container:: verbose
3622 .. container:: verbose
3621
3623
3622 With -B/--bookmarks, the result of bookmark comparison between
3624 With -B/--bookmarks, the result of bookmark comparison between
3623 local and remote repositories is displayed. With -v/--verbose,
3625 local and remote repositories is displayed. With -v/--verbose,
3624 status is also displayed for each bookmark like below::
3626 status is also displayed for each bookmark like below::
3625
3627
3626 BM1 01234567890a added
3628 BM1 01234567890a added
3627 BM2 deleted
3629 BM2 deleted
3628 BM3 234567890abc advanced
3630 BM3 234567890abc advanced
3629 BM4 34567890abcd diverged
3631 BM4 34567890abcd diverged
3630 BM5 4567890abcde changed
3632 BM5 4567890abcde changed
3631
3633
3632 The action taken when pushing depends on the
3634 The action taken when pushing depends on the
3633 status of each bookmark:
3635 status of each bookmark:
3634
3636
3635 :``added``: push with ``-B`` will create it
3637 :``added``: push with ``-B`` will create it
3636 :``deleted``: push with ``-B`` will delete it
3638 :``deleted``: push with ``-B`` will delete it
3637 :``advanced``: push will update it
3639 :``advanced``: push will update it
3638 :``diverged``: push with ``-B`` will update it
3640 :``diverged``: push with ``-B`` will update it
3639 :``changed``: push with ``-B`` will update it
3641 :``changed``: push with ``-B`` will update it
3640
3642
3641 From the point of view of pushing behavior, bookmarks
3643 From the point of view of pushing behavior, bookmarks
3642 existing only in the remote repository are treated as
3644 existing only in the remote repository are treated as
3643 ``deleted``, even if it is in fact added remotely.
3645 ``deleted``, even if it is in fact added remotely.
3644
3646
3645 Returns 0 if there are outgoing changes, 1 otherwise.
3647 Returns 0 if there are outgoing changes, 1 otherwise.
3646 """
3648 """
3647 opts = pycompat.byteskwargs(opts)
3649 opts = pycompat.byteskwargs(opts)
3648 if opts.get('graph'):
3650 if opts.get('graph'):
3649 cmdutil.checkunsupportedgraphflags([], opts)
3651 cmdutil.checkunsupportedgraphflags([], opts)
3650 o, other = hg._outgoing(ui, repo, dest, opts)
3652 o, other = hg._outgoing(ui, repo, dest, opts)
3651 if not o:
3653 if not o:
3652 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3654 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3653 return
3655 return
3654
3656
3655 revdag = cmdutil.graphrevs(repo, o, opts)
3657 revdag = cmdutil.graphrevs(repo, o, opts)
3656 ui.pager('outgoing')
3658 ui.pager('outgoing')
3657 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3659 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3658 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3660 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3659 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3661 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3660 return 0
3662 return 0
3661
3663
3662 if opts.get('bookmarks'):
3664 if opts.get('bookmarks'):
3663 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3665 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3664 dest, branches = hg.parseurl(dest, opts.get('branch'))
3666 dest, branches = hg.parseurl(dest, opts.get('branch'))
3665 other = hg.peer(repo, opts, dest)
3667 other = hg.peer(repo, opts, dest)
3666 if 'bookmarks' not in other.listkeys('namespaces'):
3668 if 'bookmarks' not in other.listkeys('namespaces'):
3667 ui.warn(_("remote doesn't support bookmarks\n"))
3669 ui.warn(_("remote doesn't support bookmarks\n"))
3668 return 0
3670 return 0
3669 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3671 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3670 ui.pager('outgoing')
3672 ui.pager('outgoing')
3671 return bookmarks.outgoing(ui, repo, other)
3673 return bookmarks.outgoing(ui, repo, other)
3672
3674
3673 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3675 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3674 try:
3676 try:
3675 return hg.outgoing(ui, repo, dest, opts)
3677 return hg.outgoing(ui, repo, dest, opts)
3676 finally:
3678 finally:
3677 del repo._subtoppath
3679 del repo._subtoppath
3678
3680
3679 @command('parents',
3681 @command('parents',
3680 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3682 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3681 ] + templateopts,
3683 ] + templateopts,
3682 _('[-r REV] [FILE]'),
3684 _('[-r REV] [FILE]'),
3683 inferrepo=True)
3685 inferrepo=True)
3684 def parents(ui, repo, file_=None, **opts):
3686 def parents(ui, repo, file_=None, **opts):
3685 """show the parents of the working directory or revision (DEPRECATED)
3687 """show the parents of the working directory or revision (DEPRECATED)
3686
3688
3687 Print the working directory's parent revisions. If a revision is
3689 Print the working directory's parent revisions. If a revision is
3688 given via -r/--rev, the parent of that revision will be printed.
3690 given via -r/--rev, the parent of that revision will be printed.
3689 If a file argument is given, the revision in which the file was
3691 If a file argument is given, the revision in which the file was
3690 last changed (before the working directory revision or the
3692 last changed (before the working directory revision or the
3691 argument to --rev if given) is printed.
3693 argument to --rev if given) is printed.
3692
3694
3693 This command is equivalent to::
3695 This command is equivalent to::
3694
3696
3695 hg log -r "p1()+p2()" or
3697 hg log -r "p1()+p2()" or
3696 hg log -r "p1(REV)+p2(REV)" or
3698 hg log -r "p1(REV)+p2(REV)" or
3697 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3699 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3698 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3700 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3699
3701
3700 See :hg:`summary` and :hg:`help revsets` for related information.
3702 See :hg:`summary` and :hg:`help revsets` for related information.
3701
3703
3702 Returns 0 on success.
3704 Returns 0 on success.
3703 """
3705 """
3704
3706
3705 opts = pycompat.byteskwargs(opts)
3707 opts = pycompat.byteskwargs(opts)
3706 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3708 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3707
3709
3708 if file_:
3710 if file_:
3709 m = scmutil.match(ctx, (file_,), opts)
3711 m = scmutil.match(ctx, (file_,), opts)
3710 if m.anypats() or len(m.files()) != 1:
3712 if m.anypats() or len(m.files()) != 1:
3711 raise error.Abort(_('can only specify an explicit filename'))
3713 raise error.Abort(_('can only specify an explicit filename'))
3712 file_ = m.files()[0]
3714 file_ = m.files()[0]
3713 filenodes = []
3715 filenodes = []
3714 for cp in ctx.parents():
3716 for cp in ctx.parents():
3715 if not cp:
3717 if not cp:
3716 continue
3718 continue
3717 try:
3719 try:
3718 filenodes.append(cp.filenode(file_))
3720 filenodes.append(cp.filenode(file_))
3719 except error.LookupError:
3721 except error.LookupError:
3720 pass
3722 pass
3721 if not filenodes:
3723 if not filenodes:
3722 raise error.Abort(_("'%s' not found in manifest!") % file_)
3724 raise error.Abort(_("'%s' not found in manifest!") % file_)
3723 p = []
3725 p = []
3724 for fn in filenodes:
3726 for fn in filenodes:
3725 fctx = repo.filectx(file_, fileid=fn)
3727 fctx = repo.filectx(file_, fileid=fn)
3726 p.append(fctx.node())
3728 p.append(fctx.node())
3727 else:
3729 else:
3728 p = [cp.node() for cp in ctx.parents()]
3730 p = [cp.node() for cp in ctx.parents()]
3729
3731
3730 displayer = cmdutil.show_changeset(ui, repo, opts)
3732 displayer = cmdutil.show_changeset(ui, repo, opts)
3731 for n in p:
3733 for n in p:
3732 if n != nullid:
3734 if n != nullid:
3733 displayer.show(repo[n])
3735 displayer.show(repo[n])
3734 displayer.close()
3736 displayer.close()
3735
3737
3736 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3738 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3737 def paths(ui, repo, search=None, **opts):
3739 def paths(ui, repo, search=None, **opts):
3738 """show aliases for remote repositories
3740 """show aliases for remote repositories
3739
3741
3740 Show definition of symbolic path name NAME. If no name is given,
3742 Show definition of symbolic path name NAME. If no name is given,
3741 show definition of all available names.
3743 show definition of all available names.
3742
3744
3743 Option -q/--quiet suppresses all output when searching for NAME
3745 Option -q/--quiet suppresses all output when searching for NAME
3744 and shows only the path names when listing all definitions.
3746 and shows only the path names when listing all definitions.
3745
3747
3746 Path names are defined in the [paths] section of your
3748 Path names are defined in the [paths] section of your
3747 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3749 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3748 repository, ``.hg/hgrc`` is used, too.
3750 repository, ``.hg/hgrc`` is used, too.
3749
3751
3750 The path names ``default`` and ``default-push`` have a special
3752 The path names ``default`` and ``default-push`` have a special
3751 meaning. When performing a push or pull operation, they are used
3753 meaning. When performing a push or pull operation, they are used
3752 as fallbacks if no location is specified on the command-line.
3754 as fallbacks if no location is specified on the command-line.
3753 When ``default-push`` is set, it will be used for push and
3755 When ``default-push`` is set, it will be used for push and
3754 ``default`` will be used for pull; otherwise ``default`` is used
3756 ``default`` will be used for pull; otherwise ``default`` is used
3755 as the fallback for both. When cloning a repository, the clone
3757 as the fallback for both. When cloning a repository, the clone
3756 source is written as ``default`` in ``.hg/hgrc``.
3758 source is written as ``default`` in ``.hg/hgrc``.
3757
3759
3758 .. note::
3760 .. note::
3759
3761
3760 ``default`` and ``default-push`` apply to all inbound (e.g.
3762 ``default`` and ``default-push`` apply to all inbound (e.g.
3761 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3763 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3762 and :hg:`bundle`) operations.
3764 and :hg:`bundle`) operations.
3763
3765
3764 See :hg:`help urls` for more information.
3766 See :hg:`help urls` for more information.
3765
3767
3766 Returns 0 on success.
3768 Returns 0 on success.
3767 """
3769 """
3768
3770
3769 opts = pycompat.byteskwargs(opts)
3771 opts = pycompat.byteskwargs(opts)
3770 ui.pager('paths')
3772 ui.pager('paths')
3771 if search:
3773 if search:
3772 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3774 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3773 if name == search]
3775 if name == search]
3774 else:
3776 else:
3775 pathitems = sorted(ui.paths.iteritems())
3777 pathitems = sorted(ui.paths.iteritems())
3776
3778
3777 fm = ui.formatter('paths', opts)
3779 fm = ui.formatter('paths', opts)
3778 if fm.isplain():
3780 if fm.isplain():
3779 hidepassword = util.hidepassword
3781 hidepassword = util.hidepassword
3780 else:
3782 else:
3781 hidepassword = str
3783 hidepassword = str
3782 if ui.quiet:
3784 if ui.quiet:
3783 namefmt = '%s\n'
3785 namefmt = '%s\n'
3784 else:
3786 else:
3785 namefmt = '%s = '
3787 namefmt = '%s = '
3786 showsubopts = not search and not ui.quiet
3788 showsubopts = not search and not ui.quiet
3787
3789
3788 for name, path in pathitems:
3790 for name, path in pathitems:
3789 fm.startitem()
3791 fm.startitem()
3790 fm.condwrite(not search, 'name', namefmt, name)
3792 fm.condwrite(not search, 'name', namefmt, name)
3791 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3793 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3792 for subopt, value in sorted(path.suboptions.items()):
3794 for subopt, value in sorted(path.suboptions.items()):
3793 assert subopt not in ('name', 'url')
3795 assert subopt not in ('name', 'url')
3794 if showsubopts:
3796 if showsubopts:
3795 fm.plain('%s:%s = ' % (name, subopt))
3797 fm.plain('%s:%s = ' % (name, subopt))
3796 fm.condwrite(showsubopts, subopt, '%s\n', value)
3798 fm.condwrite(showsubopts, subopt, '%s\n', value)
3797
3799
3798 fm.end()
3800 fm.end()
3799
3801
3800 if search and not pathitems:
3802 if search and not pathitems:
3801 if not ui.quiet:
3803 if not ui.quiet:
3802 ui.warn(_("not found!\n"))
3804 ui.warn(_("not found!\n"))
3803 return 1
3805 return 1
3804 else:
3806 else:
3805 return 0
3807 return 0
3806
3808
3807 @command('phase',
3809 @command('phase',
3808 [('p', 'public', False, _('set changeset phase to public')),
3810 [('p', 'public', False, _('set changeset phase to public')),
3809 ('d', 'draft', False, _('set changeset phase to draft')),
3811 ('d', 'draft', False, _('set changeset phase to draft')),
3810 ('s', 'secret', False, _('set changeset phase to secret')),
3812 ('s', 'secret', False, _('set changeset phase to secret')),
3811 ('f', 'force', False, _('allow to move boundary backward')),
3813 ('f', 'force', False, _('allow to move boundary backward')),
3812 ('r', 'rev', [], _('target revision'), _('REV')),
3814 ('r', 'rev', [], _('target revision'), _('REV')),
3813 ],
3815 ],
3814 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3816 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3815 def phase(ui, repo, *revs, **opts):
3817 def phase(ui, repo, *revs, **opts):
3816 """set or show the current phase name
3818 """set or show the current phase name
3817
3819
3818 With no argument, show the phase name of the current revision(s).
3820 With no argument, show the phase name of the current revision(s).
3819
3821
3820 With one of -p/--public, -d/--draft or -s/--secret, change the
3822 With one of -p/--public, -d/--draft or -s/--secret, change the
3821 phase value of the specified revisions.
3823 phase value of the specified revisions.
3822
3824
3823 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3825 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3824 lower phase to an higher phase. Phases are ordered as follows::
3826 lower phase to an higher phase. Phases are ordered as follows::
3825
3827
3826 public < draft < secret
3828 public < draft < secret
3827
3829
3828 Returns 0 on success, 1 if some phases could not be changed.
3830 Returns 0 on success, 1 if some phases could not be changed.
3829
3831
3830 (For more information about the phases concept, see :hg:`help phases`.)
3832 (For more information about the phases concept, see :hg:`help phases`.)
3831 """
3833 """
3832 opts = pycompat.byteskwargs(opts)
3834 opts = pycompat.byteskwargs(opts)
3833 # search for a unique phase argument
3835 # search for a unique phase argument
3834 targetphase = None
3836 targetphase = None
3835 for idx, name in enumerate(phases.phasenames):
3837 for idx, name in enumerate(phases.phasenames):
3836 if opts[name]:
3838 if opts[name]:
3837 if targetphase is not None:
3839 if targetphase is not None:
3838 raise error.Abort(_('only one phase can be specified'))
3840 raise error.Abort(_('only one phase can be specified'))
3839 targetphase = idx
3841 targetphase = idx
3840
3842
3841 # look for specified revision
3843 # look for specified revision
3842 revs = list(revs)
3844 revs = list(revs)
3843 revs.extend(opts['rev'])
3845 revs.extend(opts['rev'])
3844 if not revs:
3846 if not revs:
3845 # display both parents as the second parent phase can influence
3847 # display both parents as the second parent phase can influence
3846 # the phase of a merge commit
3848 # the phase of a merge commit
3847 revs = [c.rev() for c in repo[None].parents()]
3849 revs = [c.rev() for c in repo[None].parents()]
3848
3850
3849 revs = scmutil.revrange(repo, revs)
3851 revs = scmutil.revrange(repo, revs)
3850
3852
3851 lock = None
3853 lock = None
3852 ret = 0
3854 ret = 0
3853 if targetphase is None:
3855 if targetphase is None:
3854 # display
3856 # display
3855 for r in revs:
3857 for r in revs:
3856 ctx = repo[r]
3858 ctx = repo[r]
3857 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3859 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3858 else:
3860 else:
3859 tr = None
3861 tr = None
3860 lock = repo.lock()
3862 lock = repo.lock()
3861 try:
3863 try:
3862 tr = repo.transaction("phase")
3864 tr = repo.transaction("phase")
3863 # set phase
3865 # set phase
3864 if not revs:
3866 if not revs:
3865 raise error.Abort(_('empty revision set'))
3867 raise error.Abort(_('empty revision set'))
3866 nodes = [repo[r].node() for r in revs]
3868 nodes = [repo[r].node() for r in revs]
3867 # moving revision from public to draft may hide them
3869 # moving revision from public to draft may hide them
3868 # We have to check result on an unfiltered repository
3870 # We have to check result on an unfiltered repository
3869 unfi = repo.unfiltered()
3871 unfi = repo.unfiltered()
3870 getphase = unfi._phasecache.phase
3872 getphase = unfi._phasecache.phase
3871 olddata = [getphase(unfi, r) for r in unfi]
3873 olddata = [getphase(unfi, r) for r in unfi]
3872 phases.advanceboundary(repo, tr, targetphase, nodes)
3874 phases.advanceboundary(repo, tr, targetphase, nodes)
3873 if opts['force']:
3875 if opts['force']:
3874 phases.retractboundary(repo, tr, targetphase, nodes)
3876 phases.retractboundary(repo, tr, targetphase, nodes)
3875 tr.close()
3877 tr.close()
3876 finally:
3878 finally:
3877 if tr is not None:
3879 if tr is not None:
3878 tr.release()
3880 tr.release()
3879 lock.release()
3881 lock.release()
3880 getphase = unfi._phasecache.phase
3882 getphase = unfi._phasecache.phase
3881 newdata = [getphase(unfi, r) for r in unfi]
3883 newdata = [getphase(unfi, r) for r in unfi]
3882 changes = sum(newdata[r] != olddata[r] for r in unfi)
3884 changes = sum(newdata[r] != olddata[r] for r in unfi)
3883 cl = unfi.changelog
3885 cl = unfi.changelog
3884 rejected = [n for n in nodes
3886 rejected = [n for n in nodes
3885 if newdata[cl.rev(n)] < targetphase]
3887 if newdata[cl.rev(n)] < targetphase]
3886 if rejected:
3888 if rejected:
3887 ui.warn(_('cannot move %i changesets to a higher '
3889 ui.warn(_('cannot move %i changesets to a higher '
3888 'phase, use --force\n') % len(rejected))
3890 'phase, use --force\n') % len(rejected))
3889 ret = 1
3891 ret = 1
3890 if changes:
3892 if changes:
3891 msg = _('phase changed for %i changesets\n') % changes
3893 msg = _('phase changed for %i changesets\n') % changes
3892 if ret:
3894 if ret:
3893 ui.status(msg)
3895 ui.status(msg)
3894 else:
3896 else:
3895 ui.note(msg)
3897 ui.note(msg)
3896 else:
3898 else:
3897 ui.warn(_('no phases changed\n'))
3899 ui.warn(_('no phases changed\n'))
3898 return ret
3900 return ret
3899
3901
3900 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3902 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3901 """Run after a changegroup has been added via pull/unbundle
3903 """Run after a changegroup has been added via pull/unbundle
3902
3904
3903 This takes arguments below:
3905 This takes arguments below:
3904
3906
3905 :modheads: change of heads by pull/unbundle
3907 :modheads: change of heads by pull/unbundle
3906 :optupdate: updating working directory is needed or not
3908 :optupdate: updating working directory is needed or not
3907 :checkout: update destination revision (or None to default destination)
3909 :checkout: update destination revision (or None to default destination)
3908 :brev: a name, which might be a bookmark to be activated after updating
3910 :brev: a name, which might be a bookmark to be activated after updating
3909 """
3911 """
3910 if modheads == 0:
3912 if modheads == 0:
3911 return
3913 return
3912 if optupdate:
3914 if optupdate:
3913 try:
3915 try:
3914 return hg.updatetotally(ui, repo, checkout, brev)
3916 return hg.updatetotally(ui, repo, checkout, brev)
3915 except error.UpdateAbort as inst:
3917 except error.UpdateAbort as inst:
3916 msg = _("not updating: %s") % str(inst)
3918 msg = _("not updating: %s") % str(inst)
3917 hint = inst.hint
3919 hint = inst.hint
3918 raise error.UpdateAbort(msg, hint=hint)
3920 raise error.UpdateAbort(msg, hint=hint)
3919 if modheads > 1:
3921 if modheads > 1:
3920 currentbranchheads = len(repo.branchheads())
3922 currentbranchheads = len(repo.branchheads())
3921 if currentbranchheads == modheads:
3923 if currentbranchheads == modheads:
3922 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3924 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3923 elif currentbranchheads > 1:
3925 elif currentbranchheads > 1:
3924 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3926 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3925 "merge)\n"))
3927 "merge)\n"))
3926 else:
3928 else:
3927 ui.status(_("(run 'hg heads' to see heads)\n"))
3929 ui.status(_("(run 'hg heads' to see heads)\n"))
3928 else:
3930 else:
3929 ui.status(_("(run 'hg update' to get a working copy)\n"))
3931 ui.status(_("(run 'hg update' to get a working copy)\n"))
3930
3932
3931 @command('^pull',
3933 @command('^pull',
3932 [('u', 'update', None,
3934 [('u', 'update', None,
3933 _('update to new branch head if changesets were pulled')),
3935 _('update to new branch head if changesets were pulled')),
3934 ('f', 'force', None, _('run even when remote repository is unrelated')),
3936 ('f', 'force', None, _('run even when remote repository is unrelated')),
3935 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3937 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3936 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3938 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3937 ('b', 'branch', [], _('a specific branch you would like to pull'),
3939 ('b', 'branch', [], _('a specific branch you would like to pull'),
3938 _('BRANCH')),
3940 _('BRANCH')),
3939 ] + remoteopts,
3941 ] + remoteopts,
3940 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3942 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3941 def pull(ui, repo, source="default", **opts):
3943 def pull(ui, repo, source="default", **opts):
3942 """pull changes from the specified source
3944 """pull changes from the specified source
3943
3945
3944 Pull changes from a remote repository to a local one.
3946 Pull changes from a remote repository to a local one.
3945
3947
3946 This finds all changes from the repository at the specified path
3948 This finds all changes from the repository at the specified path
3947 or URL and adds them to a local repository (the current one unless
3949 or URL and adds them to a local repository (the current one unless
3948 -R is specified). By default, this does not update the copy of the
3950 -R is specified). By default, this does not update the copy of the
3949 project in the working directory.
3951 project in the working directory.
3950
3952
3951 Use :hg:`incoming` if you want to see what would have been added
3953 Use :hg:`incoming` if you want to see what would have been added
3952 by a pull at the time you issued this command. If you then decide
3954 by a pull at the time you issued this command. If you then decide
3953 to add those changes to the repository, you should use :hg:`pull
3955 to add those changes to the repository, you should use :hg:`pull
3954 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3956 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3955
3957
3956 If SOURCE is omitted, the 'default' path will be used.
3958 If SOURCE is omitted, the 'default' path will be used.
3957 See :hg:`help urls` for more information.
3959 See :hg:`help urls` for more information.
3958
3960
3959 Specifying bookmark as ``.`` is equivalent to specifying the active
3961 Specifying bookmark as ``.`` is equivalent to specifying the active
3960 bookmark's name.
3962 bookmark's name.
3961
3963
3962 Returns 0 on success, 1 if an update had unresolved files.
3964 Returns 0 on success, 1 if an update had unresolved files.
3963 """
3965 """
3964
3966
3965 opts = pycompat.byteskwargs(opts)
3967 opts = pycompat.byteskwargs(opts)
3966 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3968 if ui.configbool('commands', 'update.requiredest') and opts.get('update'):
3967 msg = _('update destination required by configuration')
3969 msg = _('update destination required by configuration')
3968 hint = _('use hg pull followed by hg update DEST')
3970 hint = _('use hg pull followed by hg update DEST')
3969 raise error.Abort(msg, hint=hint)
3971 raise error.Abort(msg, hint=hint)
3970
3972
3971 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3973 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3972 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3974 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3973 other = hg.peer(repo, opts, source)
3975 other = hg.peer(repo, opts, source)
3974 try:
3976 try:
3975 revs, checkout = hg.addbranchrevs(repo, other, branches,
3977 revs, checkout = hg.addbranchrevs(repo, other, branches,
3976 opts.get('rev'))
3978 opts.get('rev'))
3977
3979
3978
3980
3979 pullopargs = {}
3981 pullopargs = {}
3980 if opts.get('bookmark'):
3982 if opts.get('bookmark'):
3981 if not revs:
3983 if not revs:
3982 revs = []
3984 revs = []
3983 # The list of bookmark used here is not the one used to actually
3985 # The list of bookmark used here is not the one used to actually
3984 # update the bookmark name. This can result in the revision pulled
3986 # update the bookmark name. This can result in the revision pulled
3985 # not ending up with the name of the bookmark because of a race
3987 # not ending up with the name of the bookmark because of a race
3986 # condition on the server. (See issue 4689 for details)
3988 # condition on the server. (See issue 4689 for details)
3987 remotebookmarks = other.listkeys('bookmarks')
3989 remotebookmarks = other.listkeys('bookmarks')
3988 pullopargs['remotebookmarks'] = remotebookmarks
3990 pullopargs['remotebookmarks'] = remotebookmarks
3989 for b in opts['bookmark']:
3991 for b in opts['bookmark']:
3990 b = repo._bookmarks.expandname(b)
3992 b = repo._bookmarks.expandname(b)
3991 if b not in remotebookmarks:
3993 if b not in remotebookmarks:
3992 raise error.Abort(_('remote bookmark %s not found!') % b)
3994 raise error.Abort(_('remote bookmark %s not found!') % b)
3993 revs.append(remotebookmarks[b])
3995 revs.append(remotebookmarks[b])
3994
3996
3995 if revs:
3997 if revs:
3996 try:
3998 try:
3997 # When 'rev' is a bookmark name, we cannot guarantee that it
3999 # When 'rev' is a bookmark name, we cannot guarantee that it
3998 # will be updated with that name because of a race condition
4000 # will be updated with that name because of a race condition
3999 # server side. (See issue 4689 for details)
4001 # server side. (See issue 4689 for details)
4000 oldrevs = revs
4002 oldrevs = revs
4001 revs = [] # actually, nodes
4003 revs = [] # actually, nodes
4002 for r in oldrevs:
4004 for r in oldrevs:
4003 node = other.lookup(r)
4005 node = other.lookup(r)
4004 revs.append(node)
4006 revs.append(node)
4005 if r == checkout:
4007 if r == checkout:
4006 checkout = node
4008 checkout = node
4007 except error.CapabilityError:
4009 except error.CapabilityError:
4008 err = _("other repository doesn't support revision lookup, "
4010 err = _("other repository doesn't support revision lookup, "
4009 "so a rev cannot be specified.")
4011 "so a rev cannot be specified.")
4010 raise error.Abort(err)
4012 raise error.Abort(err)
4011
4013
4012 pullopargs.update(opts.get('opargs', {}))
4014 pullopargs.update(opts.get('opargs', {}))
4013 modheads = exchange.pull(repo, other, heads=revs,
4015 modheads = exchange.pull(repo, other, heads=revs,
4014 force=opts.get('force'),
4016 force=opts.get('force'),
4015 bookmarks=opts.get('bookmark', ()),
4017 bookmarks=opts.get('bookmark', ()),
4016 opargs=pullopargs).cgresult
4018 opargs=pullopargs).cgresult
4017
4019
4018 # brev is a name, which might be a bookmark to be activated at
4020 # brev is a name, which might be a bookmark to be activated at
4019 # the end of the update. In other words, it is an explicit
4021 # the end of the update. In other words, it is an explicit
4020 # destination of the update
4022 # destination of the update
4021 brev = None
4023 brev = None
4022
4024
4023 if checkout:
4025 if checkout:
4024 checkout = str(repo.changelog.rev(checkout))
4026 checkout = str(repo.changelog.rev(checkout))
4025
4027
4026 # order below depends on implementation of
4028 # order below depends on implementation of
4027 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4029 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4028 # because 'checkout' is determined without it.
4030 # because 'checkout' is determined without it.
4029 if opts.get('rev'):
4031 if opts.get('rev'):
4030 brev = opts['rev'][0]
4032 brev = opts['rev'][0]
4031 elif opts.get('branch'):
4033 elif opts.get('branch'):
4032 brev = opts['branch'][0]
4034 brev = opts['branch'][0]
4033 else:
4035 else:
4034 brev = branches[0]
4036 brev = branches[0]
4035 repo._subtoppath = source
4037 repo._subtoppath = source
4036 try:
4038 try:
4037 ret = postincoming(ui, repo, modheads, opts.get('update'),
4039 ret = postincoming(ui, repo, modheads, opts.get('update'),
4038 checkout, brev)
4040 checkout, brev)
4039
4041
4040 finally:
4042 finally:
4041 del repo._subtoppath
4043 del repo._subtoppath
4042
4044
4043 finally:
4045 finally:
4044 other.close()
4046 other.close()
4045 return ret
4047 return ret
4046
4048
4047 @command('^push',
4049 @command('^push',
4048 [('f', 'force', None, _('force push')),
4050 [('f', 'force', None, _('force push')),
4049 ('r', 'rev', [],
4051 ('r', 'rev', [],
4050 _('a changeset intended to be included in the destination'),
4052 _('a changeset intended to be included in the destination'),
4051 _('REV')),
4053 _('REV')),
4052 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4054 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4053 ('b', 'branch', [],
4055 ('b', 'branch', [],
4054 _('a specific branch you would like to push'), _('BRANCH')),
4056 _('a specific branch you would like to push'), _('BRANCH')),
4055 ('', 'new-branch', False, _('allow pushing a new branch')),
4057 ('', 'new-branch', False, _('allow pushing a new branch')),
4056 ] + remoteopts,
4058 ] + remoteopts,
4057 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4059 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4058 def push(ui, repo, dest=None, **opts):
4060 def push(ui, repo, dest=None, **opts):
4059 """push changes to the specified destination
4061 """push changes to the specified destination
4060
4062
4061 Push changesets from the local repository to the specified
4063 Push changesets from the local repository to the specified
4062 destination.
4064 destination.
4063
4065
4064 This operation is symmetrical to pull: it is identical to a pull
4066 This operation is symmetrical to pull: it is identical to a pull
4065 in the destination repository from the current one.
4067 in the destination repository from the current one.
4066
4068
4067 By default, push will not allow creation of new heads at the
4069 By default, push will not allow creation of new heads at the
4068 destination, since multiple heads would make it unclear which head
4070 destination, since multiple heads would make it unclear which head
4069 to use. In this situation, it is recommended to pull and merge
4071 to use. In this situation, it is recommended to pull and merge
4070 before pushing.
4072 before pushing.
4071
4073
4072 Use --new-branch if you want to allow push to create a new named
4074 Use --new-branch if you want to allow push to create a new named
4073 branch that is not present at the destination. This allows you to
4075 branch that is not present at the destination. This allows you to
4074 only create a new branch without forcing other changes.
4076 only create a new branch without forcing other changes.
4075
4077
4076 .. note::
4078 .. note::
4077
4079
4078 Extra care should be taken with the -f/--force option,
4080 Extra care should be taken with the -f/--force option,
4079 which will push all new heads on all branches, an action which will
4081 which will push all new heads on all branches, an action which will
4080 almost always cause confusion for collaborators.
4082 almost always cause confusion for collaborators.
4081
4083
4082 If -r/--rev is used, the specified revision and all its ancestors
4084 If -r/--rev is used, the specified revision and all its ancestors
4083 will be pushed to the remote repository.
4085 will be pushed to the remote repository.
4084
4086
4085 If -B/--bookmark is used, the specified bookmarked revision, its
4087 If -B/--bookmark is used, the specified bookmarked revision, its
4086 ancestors, and the bookmark will be pushed to the remote
4088 ancestors, and the bookmark will be pushed to the remote
4087 repository. Specifying ``.`` is equivalent to specifying the active
4089 repository. Specifying ``.`` is equivalent to specifying the active
4088 bookmark's name.
4090 bookmark's name.
4089
4091
4090 Please see :hg:`help urls` for important details about ``ssh://``
4092 Please see :hg:`help urls` for important details about ``ssh://``
4091 URLs. If DESTINATION is omitted, a default path will be used.
4093 URLs. If DESTINATION is omitted, a default path will be used.
4092
4094
4093 Returns 0 if push was successful, 1 if nothing to push.
4095 Returns 0 if push was successful, 1 if nothing to push.
4094 """
4096 """
4095
4097
4096 opts = pycompat.byteskwargs(opts)
4098 opts = pycompat.byteskwargs(opts)
4097 if opts.get('bookmark'):
4099 if opts.get('bookmark'):
4098 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4100 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4099 for b in opts['bookmark']:
4101 for b in opts['bookmark']:
4100 # translate -B options to -r so changesets get pushed
4102 # translate -B options to -r so changesets get pushed
4101 b = repo._bookmarks.expandname(b)
4103 b = repo._bookmarks.expandname(b)
4102 if b in repo._bookmarks:
4104 if b in repo._bookmarks:
4103 opts.setdefault('rev', []).append(b)
4105 opts.setdefault('rev', []).append(b)
4104 else:
4106 else:
4105 # if we try to push a deleted bookmark, translate it to null
4107 # if we try to push a deleted bookmark, translate it to null
4106 # this lets simultaneous -r, -b options continue working
4108 # this lets simultaneous -r, -b options continue working
4107 opts.setdefault('rev', []).append("null")
4109 opts.setdefault('rev', []).append("null")
4108
4110
4109 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4111 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4110 if not path:
4112 if not path:
4111 raise error.Abort(_('default repository not configured!'),
4113 raise error.Abort(_('default repository not configured!'),
4112 hint=_("see 'hg help config.paths'"))
4114 hint=_("see 'hg help config.paths'"))
4113 dest = path.pushloc or path.loc
4115 dest = path.pushloc or path.loc
4114 branches = (path.branch, opts.get('branch') or [])
4116 branches = (path.branch, opts.get('branch') or [])
4115 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4117 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4116 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4118 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4117 other = hg.peer(repo, opts, dest)
4119 other = hg.peer(repo, opts, dest)
4118
4120
4119 if revs:
4121 if revs:
4120 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4122 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4121 if not revs:
4123 if not revs:
4122 raise error.Abort(_("specified revisions evaluate to an empty set"),
4124 raise error.Abort(_("specified revisions evaluate to an empty set"),
4123 hint=_("use different revision arguments"))
4125 hint=_("use different revision arguments"))
4124 elif path.pushrev:
4126 elif path.pushrev:
4125 # It doesn't make any sense to specify ancestor revisions. So limit
4127 # It doesn't make any sense to specify ancestor revisions. So limit
4126 # to DAG heads to make discovery simpler.
4128 # to DAG heads to make discovery simpler.
4127 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4129 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4128 revs = scmutil.revrange(repo, [expr])
4130 revs = scmutil.revrange(repo, [expr])
4129 revs = [repo[rev].node() for rev in revs]
4131 revs = [repo[rev].node() for rev in revs]
4130 if not revs:
4132 if not revs:
4131 raise error.Abort(_('default push revset for path evaluates to an '
4133 raise error.Abort(_('default push revset for path evaluates to an '
4132 'empty set'))
4134 'empty set'))
4133
4135
4134 repo._subtoppath = dest
4136 repo._subtoppath = dest
4135 try:
4137 try:
4136 # push subrepos depth-first for coherent ordering
4138 # push subrepos depth-first for coherent ordering
4137 c = repo['']
4139 c = repo['']
4138 subs = c.substate # only repos that are committed
4140 subs = c.substate # only repos that are committed
4139 for s in sorted(subs):
4141 for s in sorted(subs):
4140 result = c.sub(s).push(opts)
4142 result = c.sub(s).push(opts)
4141 if result == 0:
4143 if result == 0:
4142 return not result
4144 return not result
4143 finally:
4145 finally:
4144 del repo._subtoppath
4146 del repo._subtoppath
4145 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4147 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4146 newbranch=opts.get('new_branch'),
4148 newbranch=opts.get('new_branch'),
4147 bookmarks=opts.get('bookmark', ()),
4149 bookmarks=opts.get('bookmark', ()),
4148 opargs=opts.get('opargs'))
4150 opargs=opts.get('opargs'))
4149
4151
4150 result = not pushop.cgresult
4152 result = not pushop.cgresult
4151
4153
4152 if pushop.bkresult is not None:
4154 if pushop.bkresult is not None:
4153 if pushop.bkresult == 2:
4155 if pushop.bkresult == 2:
4154 result = 2
4156 result = 2
4155 elif not result and pushop.bkresult:
4157 elif not result and pushop.bkresult:
4156 result = 2
4158 result = 2
4157
4159
4158 return result
4160 return result
4159
4161
4160 @command('recover', [])
4162 @command('recover', [])
4161 def recover(ui, repo):
4163 def recover(ui, repo):
4162 """roll back an interrupted transaction
4164 """roll back an interrupted transaction
4163
4165
4164 Recover from an interrupted commit or pull.
4166 Recover from an interrupted commit or pull.
4165
4167
4166 This command tries to fix the repository status after an
4168 This command tries to fix the repository status after an
4167 interrupted operation. It should only be necessary when Mercurial
4169 interrupted operation. It should only be necessary when Mercurial
4168 suggests it.
4170 suggests it.
4169
4171
4170 Returns 0 if successful, 1 if nothing to recover or verify fails.
4172 Returns 0 if successful, 1 if nothing to recover or verify fails.
4171 """
4173 """
4172 if repo.recover():
4174 if repo.recover():
4173 return hg.verify(repo)
4175 return hg.verify(repo)
4174 return 1
4176 return 1
4175
4177
4176 @command('^remove|rm',
4178 @command('^remove|rm',
4177 [('A', 'after', None, _('record delete for missing files')),
4179 [('A', 'after', None, _('record delete for missing files')),
4178 ('f', 'force', None,
4180 ('f', 'force', None,
4179 _('forget added files, delete modified files')),
4181 _('forget added files, delete modified files')),
4180 ] + subrepoopts + walkopts,
4182 ] + subrepoopts + walkopts,
4181 _('[OPTION]... FILE...'),
4183 _('[OPTION]... FILE...'),
4182 inferrepo=True)
4184 inferrepo=True)
4183 def remove(ui, repo, *pats, **opts):
4185 def remove(ui, repo, *pats, **opts):
4184 """remove the specified files on the next commit
4186 """remove the specified files on the next commit
4185
4187
4186 Schedule the indicated files for removal from the current branch.
4188 Schedule the indicated files for removal from the current branch.
4187
4189
4188 This command schedules the files to be removed at the next commit.
4190 This command schedules the files to be removed at the next commit.
4189 To undo a remove before that, see :hg:`revert`. To undo added
4191 To undo a remove before that, see :hg:`revert`. To undo added
4190 files, see :hg:`forget`.
4192 files, see :hg:`forget`.
4191
4193
4192 .. container:: verbose
4194 .. container:: verbose
4193
4195
4194 -A/--after can be used to remove only files that have already
4196 -A/--after can be used to remove only files that have already
4195 been deleted, -f/--force can be used to force deletion, and -Af
4197 been deleted, -f/--force can be used to force deletion, and -Af
4196 can be used to remove files from the next revision without
4198 can be used to remove files from the next revision without
4197 deleting them from the working directory.
4199 deleting them from the working directory.
4198
4200
4199 The following table details the behavior of remove for different
4201 The following table details the behavior of remove for different
4200 file states (columns) and option combinations (rows). The file
4202 file states (columns) and option combinations (rows). The file
4201 states are Added [A], Clean [C], Modified [M] and Missing [!]
4203 states are Added [A], Clean [C], Modified [M] and Missing [!]
4202 (as reported by :hg:`status`). The actions are Warn, Remove
4204 (as reported by :hg:`status`). The actions are Warn, Remove
4203 (from branch) and Delete (from disk):
4205 (from branch) and Delete (from disk):
4204
4206
4205 ========= == == == ==
4207 ========= == == == ==
4206 opt/state A C M !
4208 opt/state A C M !
4207 ========= == == == ==
4209 ========= == == == ==
4208 none W RD W R
4210 none W RD W R
4209 -f R RD RD R
4211 -f R RD RD R
4210 -A W W W R
4212 -A W W W R
4211 -Af R R R R
4213 -Af R R R R
4212 ========= == == == ==
4214 ========= == == == ==
4213
4215
4214 .. note::
4216 .. note::
4215
4217
4216 :hg:`remove` never deletes files in Added [A] state from the
4218 :hg:`remove` never deletes files in Added [A] state from the
4217 working directory, not even if ``--force`` is specified.
4219 working directory, not even if ``--force`` is specified.
4218
4220
4219 Returns 0 on success, 1 if any warnings encountered.
4221 Returns 0 on success, 1 if any warnings encountered.
4220 """
4222 """
4221
4223
4222 opts = pycompat.byteskwargs(opts)
4224 opts = pycompat.byteskwargs(opts)
4223 after, force = opts.get('after'), opts.get('force')
4225 after, force = opts.get('after'), opts.get('force')
4224 if not pats and not after:
4226 if not pats and not after:
4225 raise error.Abort(_('no files specified'))
4227 raise error.Abort(_('no files specified'))
4226
4228
4227 m = scmutil.match(repo[None], pats, opts)
4229 m = scmutil.match(repo[None], pats, opts)
4228 subrepos = opts.get('subrepos')
4230 subrepos = opts.get('subrepos')
4229 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4231 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4230
4232
4231 @command('rename|move|mv',
4233 @command('rename|move|mv',
4232 [('A', 'after', None, _('record a rename that has already occurred')),
4234 [('A', 'after', None, _('record a rename that has already occurred')),
4233 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4235 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4234 ] + walkopts + dryrunopts,
4236 ] + walkopts + dryrunopts,
4235 _('[OPTION]... SOURCE... DEST'))
4237 _('[OPTION]... SOURCE... DEST'))
4236 def rename(ui, repo, *pats, **opts):
4238 def rename(ui, repo, *pats, **opts):
4237 """rename files; equivalent of copy + remove
4239 """rename files; equivalent of copy + remove
4238
4240
4239 Mark dest as copies of sources; mark sources for deletion. If dest
4241 Mark dest as copies of sources; mark sources for deletion. If dest
4240 is a directory, copies are put in that directory. If dest is a
4242 is a directory, copies are put in that directory. If dest is a
4241 file, there can only be one source.
4243 file, there can only be one source.
4242
4244
4243 By default, this command copies the contents of files as they
4245 By default, this command copies the contents of files as they
4244 exist in the working directory. If invoked with -A/--after, the
4246 exist in the working directory. If invoked with -A/--after, the
4245 operation is recorded, but no copying is performed.
4247 operation is recorded, but no copying is performed.
4246
4248
4247 This command takes effect at the next commit. To undo a rename
4249 This command takes effect at the next commit. To undo a rename
4248 before that, see :hg:`revert`.
4250 before that, see :hg:`revert`.
4249
4251
4250 Returns 0 on success, 1 if errors are encountered.
4252 Returns 0 on success, 1 if errors are encountered.
4251 """
4253 """
4252 opts = pycompat.byteskwargs(opts)
4254 opts = pycompat.byteskwargs(opts)
4253 with repo.wlock(False):
4255 with repo.wlock(False):
4254 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4256 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4255
4257
4256 @command('resolve',
4258 @command('resolve',
4257 [('a', 'all', None, _('select all unresolved files')),
4259 [('a', 'all', None, _('select all unresolved files')),
4258 ('l', 'list', None, _('list state of files needing merge')),
4260 ('l', 'list', None, _('list state of files needing merge')),
4259 ('m', 'mark', None, _('mark files as resolved')),
4261 ('m', 'mark', None, _('mark files as resolved')),
4260 ('u', 'unmark', None, _('mark files as unresolved')),
4262 ('u', 'unmark', None, _('mark files as unresolved')),
4261 ('n', 'no-status', None, _('hide status prefix'))]
4263 ('n', 'no-status', None, _('hide status prefix'))]
4262 + mergetoolopts + walkopts + formatteropts,
4264 + mergetoolopts + walkopts + formatteropts,
4263 _('[OPTION]... [FILE]...'),
4265 _('[OPTION]... [FILE]...'),
4264 inferrepo=True)
4266 inferrepo=True)
4265 def resolve(ui, repo, *pats, **opts):
4267 def resolve(ui, repo, *pats, **opts):
4266 """redo merges or set/view the merge status of files
4268 """redo merges or set/view the merge status of files
4267
4269
4268 Merges with unresolved conflicts are often the result of
4270 Merges with unresolved conflicts are often the result of
4269 non-interactive merging using the ``internal:merge`` configuration
4271 non-interactive merging using the ``internal:merge`` configuration
4270 setting, or a command-line merge tool like ``diff3``. The resolve
4272 setting, or a command-line merge tool like ``diff3``. The resolve
4271 command is used to manage the files involved in a merge, after
4273 command is used to manage the files involved in a merge, after
4272 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4274 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4273 working directory must have two parents). See :hg:`help
4275 working directory must have two parents). See :hg:`help
4274 merge-tools` for information on configuring merge tools.
4276 merge-tools` for information on configuring merge tools.
4275
4277
4276 The resolve command can be used in the following ways:
4278 The resolve command can be used in the following ways:
4277
4279
4278 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4280 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4279 files, discarding any previous merge attempts. Re-merging is not
4281 files, discarding any previous merge attempts. Re-merging is not
4280 performed for files already marked as resolved. Use ``--all/-a``
4282 performed for files already marked as resolved. Use ``--all/-a``
4281 to select all unresolved files. ``--tool`` can be used to specify
4283 to select all unresolved files. ``--tool`` can be used to specify
4282 the merge tool used for the given files. It overrides the HGMERGE
4284 the merge tool used for the given files. It overrides the HGMERGE
4283 environment variable and your configuration files. Previous file
4285 environment variable and your configuration files. Previous file
4284 contents are saved with a ``.orig`` suffix.
4286 contents are saved with a ``.orig`` suffix.
4285
4287
4286 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4288 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4287 (e.g. after having manually fixed-up the files). The default is
4289 (e.g. after having manually fixed-up the files). The default is
4288 to mark all unresolved files.
4290 to mark all unresolved files.
4289
4291
4290 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4292 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4291 default is to mark all resolved files.
4293 default is to mark all resolved files.
4292
4294
4293 - :hg:`resolve -l`: list files which had or still have conflicts.
4295 - :hg:`resolve -l`: list files which had or still have conflicts.
4294 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4296 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4295 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4297 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4296 the list. See :hg:`help filesets` for details.
4298 the list. See :hg:`help filesets` for details.
4297
4299
4298 .. note::
4300 .. note::
4299
4301
4300 Mercurial will not let you commit files with unresolved merge
4302 Mercurial will not let you commit files with unresolved merge
4301 conflicts. You must use :hg:`resolve -m ...` before you can
4303 conflicts. You must use :hg:`resolve -m ...` before you can
4302 commit after a conflicting merge.
4304 commit after a conflicting merge.
4303
4305
4304 Returns 0 on success, 1 if any files fail a resolve attempt.
4306 Returns 0 on success, 1 if any files fail a resolve attempt.
4305 """
4307 """
4306
4308
4307 opts = pycompat.byteskwargs(opts)
4309 opts = pycompat.byteskwargs(opts)
4308 flaglist = 'all mark unmark list no_status'.split()
4310 flaglist = 'all mark unmark list no_status'.split()
4309 all, mark, unmark, show, nostatus = \
4311 all, mark, unmark, show, nostatus = \
4310 [opts.get(o) for o in flaglist]
4312 [opts.get(o) for o in flaglist]
4311
4313
4312 if (show and (mark or unmark)) or (mark and unmark):
4314 if (show and (mark or unmark)) or (mark and unmark):
4313 raise error.Abort(_("too many options specified"))
4315 raise error.Abort(_("too many options specified"))
4314 if pats and all:
4316 if pats and all:
4315 raise error.Abort(_("can't specify --all and patterns"))
4317 raise error.Abort(_("can't specify --all and patterns"))
4316 if not (all or pats or show or mark or unmark):
4318 if not (all or pats or show or mark or unmark):
4317 raise error.Abort(_('no files or directories specified'),
4319 raise error.Abort(_('no files or directories specified'),
4318 hint=('use --all to re-merge all unresolved files'))
4320 hint=('use --all to re-merge all unresolved files'))
4319
4321
4320 if show:
4322 if show:
4321 ui.pager('resolve')
4323 ui.pager('resolve')
4322 fm = ui.formatter('resolve', opts)
4324 fm = ui.formatter('resolve', opts)
4323 ms = mergemod.mergestate.read(repo)
4325 ms = mergemod.mergestate.read(repo)
4324 m = scmutil.match(repo[None], pats, opts)
4326 m = scmutil.match(repo[None], pats, opts)
4325 for f in ms:
4327 for f in ms:
4326 if not m(f):
4328 if not m(f):
4327 continue
4329 continue
4328 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4330 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4329 'd': 'driverresolved'}[ms[f]]
4331 'd': 'driverresolved'}[ms[f]]
4330 fm.startitem()
4332 fm.startitem()
4331 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4333 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4332 fm.write('path', '%s\n', f, label=l)
4334 fm.write('path', '%s\n', f, label=l)
4333 fm.end()
4335 fm.end()
4334 return 0
4336 return 0
4335
4337
4336 with repo.wlock():
4338 with repo.wlock():
4337 ms = mergemod.mergestate.read(repo)
4339 ms = mergemod.mergestate.read(repo)
4338
4340
4339 if not (ms.active() or repo.dirstate.p2() != nullid):
4341 if not (ms.active() or repo.dirstate.p2() != nullid):
4340 raise error.Abort(
4342 raise error.Abort(
4341 _('resolve command not applicable when not merging'))
4343 _('resolve command not applicable when not merging'))
4342
4344
4343 wctx = repo[None]
4345 wctx = repo[None]
4344
4346
4345 if ms.mergedriver and ms.mdstate() == 'u':
4347 if ms.mergedriver and ms.mdstate() == 'u':
4346 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4348 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4347 ms.commit()
4349 ms.commit()
4348 # allow mark and unmark to go through
4350 # allow mark and unmark to go through
4349 if not mark and not unmark and not proceed:
4351 if not mark and not unmark and not proceed:
4350 return 1
4352 return 1
4351
4353
4352 m = scmutil.match(wctx, pats, opts)
4354 m = scmutil.match(wctx, pats, opts)
4353 ret = 0
4355 ret = 0
4354 didwork = False
4356 didwork = False
4355 runconclude = False
4357 runconclude = False
4356
4358
4357 tocomplete = []
4359 tocomplete = []
4358 for f in ms:
4360 for f in ms:
4359 if not m(f):
4361 if not m(f):
4360 continue
4362 continue
4361
4363
4362 didwork = True
4364 didwork = True
4363
4365
4364 # don't let driver-resolved files be marked, and run the conclude
4366 # don't let driver-resolved files be marked, and run the conclude
4365 # step if asked to resolve
4367 # step if asked to resolve
4366 if ms[f] == "d":
4368 if ms[f] == "d":
4367 exact = m.exact(f)
4369 exact = m.exact(f)
4368 if mark:
4370 if mark:
4369 if exact:
4371 if exact:
4370 ui.warn(_('not marking %s as it is driver-resolved\n')
4372 ui.warn(_('not marking %s as it is driver-resolved\n')
4371 % f)
4373 % f)
4372 elif unmark:
4374 elif unmark:
4373 if exact:
4375 if exact:
4374 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4376 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4375 % f)
4377 % f)
4376 else:
4378 else:
4377 runconclude = True
4379 runconclude = True
4378 continue
4380 continue
4379
4381
4380 if mark:
4382 if mark:
4381 ms.mark(f, "r")
4383 ms.mark(f, "r")
4382 elif unmark:
4384 elif unmark:
4383 ms.mark(f, "u")
4385 ms.mark(f, "u")
4384 else:
4386 else:
4385 # backup pre-resolve (merge uses .orig for its own purposes)
4387 # backup pre-resolve (merge uses .orig for its own purposes)
4386 a = repo.wjoin(f)
4388 a = repo.wjoin(f)
4387 try:
4389 try:
4388 util.copyfile(a, a + ".resolve")
4390 util.copyfile(a, a + ".resolve")
4389 except (IOError, OSError) as inst:
4391 except (IOError, OSError) as inst:
4390 if inst.errno != errno.ENOENT:
4392 if inst.errno != errno.ENOENT:
4391 raise
4393 raise
4392
4394
4393 try:
4395 try:
4394 # preresolve file
4396 # preresolve file
4395 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4397 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4396 'resolve')
4398 'resolve')
4397 complete, r = ms.preresolve(f, wctx)
4399 complete, r = ms.preresolve(f, wctx)
4398 if not complete:
4400 if not complete:
4399 tocomplete.append(f)
4401 tocomplete.append(f)
4400 elif r:
4402 elif r:
4401 ret = 1
4403 ret = 1
4402 finally:
4404 finally:
4403 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4405 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4404 ms.commit()
4406 ms.commit()
4405
4407
4406 # replace filemerge's .orig file with our resolve file, but only
4408 # replace filemerge's .orig file with our resolve file, but only
4407 # for merges that are complete
4409 # for merges that are complete
4408 if complete:
4410 if complete:
4409 try:
4411 try:
4410 util.rename(a + ".resolve",
4412 util.rename(a + ".resolve",
4411 scmutil.origpath(ui, repo, a))
4413 scmutil.origpath(ui, repo, a))
4412 except OSError as inst:
4414 except OSError as inst:
4413 if inst.errno != errno.ENOENT:
4415 if inst.errno != errno.ENOENT:
4414 raise
4416 raise
4415
4417
4416 for f in tocomplete:
4418 for f in tocomplete:
4417 try:
4419 try:
4418 # resolve file
4420 # resolve file
4419 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4421 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4420 'resolve')
4422 'resolve')
4421 r = ms.resolve(f, wctx)
4423 r = ms.resolve(f, wctx)
4422 if r:
4424 if r:
4423 ret = 1
4425 ret = 1
4424 finally:
4426 finally:
4425 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4427 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4426 ms.commit()
4428 ms.commit()
4427
4429
4428 # replace filemerge's .orig file with our resolve file
4430 # replace filemerge's .orig file with our resolve file
4429 a = repo.wjoin(f)
4431 a = repo.wjoin(f)
4430 try:
4432 try:
4431 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4433 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4432 except OSError as inst:
4434 except OSError as inst:
4433 if inst.errno != errno.ENOENT:
4435 if inst.errno != errno.ENOENT:
4434 raise
4436 raise
4435
4437
4436 ms.commit()
4438 ms.commit()
4437 ms.recordactions()
4439 ms.recordactions()
4438
4440
4439 if not didwork and pats:
4441 if not didwork and pats:
4440 hint = None
4442 hint = None
4441 if not any([p for p in pats if p.find(':') >= 0]):
4443 if not any([p for p in pats if p.find(':') >= 0]):
4442 pats = ['path:%s' % p for p in pats]
4444 pats = ['path:%s' % p for p in pats]
4443 m = scmutil.match(wctx, pats, opts)
4445 m = scmutil.match(wctx, pats, opts)
4444 for f in ms:
4446 for f in ms:
4445 if not m(f):
4447 if not m(f):
4446 continue
4448 continue
4447 flags = ''.join(['-%s ' % o[0] for o in flaglist
4449 flags = ''.join(['-%s ' % o[0] for o in flaglist
4448 if opts.get(o)])
4450 if opts.get(o)])
4449 hint = _("(try: hg resolve %s%s)\n") % (
4451 hint = _("(try: hg resolve %s%s)\n") % (
4450 flags,
4452 flags,
4451 ' '.join(pats))
4453 ' '.join(pats))
4452 break
4454 break
4453 ui.warn(_("arguments do not match paths that need resolving\n"))
4455 ui.warn(_("arguments do not match paths that need resolving\n"))
4454 if hint:
4456 if hint:
4455 ui.warn(hint)
4457 ui.warn(hint)
4456 elif ms.mergedriver and ms.mdstate() != 's':
4458 elif ms.mergedriver and ms.mdstate() != 's':
4457 # run conclude step when either a driver-resolved file is requested
4459 # run conclude step when either a driver-resolved file is requested
4458 # or there are no driver-resolved files
4460 # or there are no driver-resolved files
4459 # we can't use 'ret' to determine whether any files are unresolved
4461 # we can't use 'ret' to determine whether any files are unresolved
4460 # because we might not have tried to resolve some
4462 # because we might not have tried to resolve some
4461 if ((runconclude or not list(ms.driverresolved()))
4463 if ((runconclude or not list(ms.driverresolved()))
4462 and not list(ms.unresolved())):
4464 and not list(ms.unresolved())):
4463 proceed = mergemod.driverconclude(repo, ms, wctx)
4465 proceed = mergemod.driverconclude(repo, ms, wctx)
4464 ms.commit()
4466 ms.commit()
4465 if not proceed:
4467 if not proceed:
4466 return 1
4468 return 1
4467
4469
4468 # Nudge users into finishing an unfinished operation
4470 # Nudge users into finishing an unfinished operation
4469 unresolvedf = list(ms.unresolved())
4471 unresolvedf = list(ms.unresolved())
4470 driverresolvedf = list(ms.driverresolved())
4472 driverresolvedf = list(ms.driverresolved())
4471 if not unresolvedf and not driverresolvedf:
4473 if not unresolvedf and not driverresolvedf:
4472 ui.status(_('(no more unresolved files)\n'))
4474 ui.status(_('(no more unresolved files)\n'))
4473 cmdutil.checkafterresolved(repo)
4475 cmdutil.checkafterresolved(repo)
4474 elif not unresolvedf:
4476 elif not unresolvedf:
4475 ui.status(_('(no more unresolved files -- '
4477 ui.status(_('(no more unresolved files -- '
4476 'run "hg resolve --all" to conclude)\n'))
4478 'run "hg resolve --all" to conclude)\n'))
4477
4479
4478 return ret
4480 return ret
4479
4481
4480 @command('revert',
4482 @command('revert',
4481 [('a', 'all', None, _('revert all changes when no arguments given')),
4483 [('a', 'all', None, _('revert all changes when no arguments given')),
4482 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4484 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4483 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4485 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4484 ('C', 'no-backup', None, _('do not save backup copies of files')),
4486 ('C', 'no-backup', None, _('do not save backup copies of files')),
4485 ('i', 'interactive', None,
4487 ('i', 'interactive', None,
4486 _('interactively select the changes (EXPERIMENTAL)')),
4488 _('interactively select the changes (EXPERIMENTAL)')),
4487 ] + walkopts + dryrunopts,
4489 ] + walkopts + dryrunopts,
4488 _('[OPTION]... [-r REV] [NAME]...'))
4490 _('[OPTION]... [-r REV] [NAME]...'))
4489 def revert(ui, repo, *pats, **opts):
4491 def revert(ui, repo, *pats, **opts):
4490 """restore files to their checkout state
4492 """restore files to their checkout state
4491
4493
4492 .. note::
4494 .. note::
4493
4495
4494 To check out earlier revisions, you should use :hg:`update REV`.
4496 To check out earlier revisions, you should use :hg:`update REV`.
4495 To cancel an uncommitted merge (and lose your changes),
4497 To cancel an uncommitted merge (and lose your changes),
4496 use :hg:`update --clean .`.
4498 use :hg:`update --clean .`.
4497
4499
4498 With no revision specified, revert the specified files or directories
4500 With no revision specified, revert the specified files or directories
4499 to the contents they had in the parent of the working directory.
4501 to the contents they had in the parent of the working directory.
4500 This restores the contents of files to an unmodified
4502 This restores the contents of files to an unmodified
4501 state and unschedules adds, removes, copies, and renames. If the
4503 state and unschedules adds, removes, copies, and renames. If the
4502 working directory has two parents, you must explicitly specify a
4504 working directory has two parents, you must explicitly specify a
4503 revision.
4505 revision.
4504
4506
4505 Using the -r/--rev or -d/--date options, revert the given files or
4507 Using the -r/--rev or -d/--date options, revert the given files or
4506 directories to their states as of a specific revision. Because
4508 directories to their states as of a specific revision. Because
4507 revert does not change the working directory parents, this will
4509 revert does not change the working directory parents, this will
4508 cause these files to appear modified. This can be helpful to "back
4510 cause these files to appear modified. This can be helpful to "back
4509 out" some or all of an earlier change. See :hg:`backout` for a
4511 out" some or all of an earlier change. See :hg:`backout` for a
4510 related method.
4512 related method.
4511
4513
4512 Modified files are saved with a .orig suffix before reverting.
4514 Modified files are saved with a .orig suffix before reverting.
4513 To disable these backups, use --no-backup. It is possible to store
4515 To disable these backups, use --no-backup. It is possible to store
4514 the backup files in a custom directory relative to the root of the
4516 the backup files in a custom directory relative to the root of the
4515 repository by setting the ``ui.origbackuppath`` configuration
4517 repository by setting the ``ui.origbackuppath`` configuration
4516 option.
4518 option.
4517
4519
4518 See :hg:`help dates` for a list of formats valid for -d/--date.
4520 See :hg:`help dates` for a list of formats valid for -d/--date.
4519
4521
4520 See :hg:`help backout` for a way to reverse the effect of an
4522 See :hg:`help backout` for a way to reverse the effect of an
4521 earlier changeset.
4523 earlier changeset.
4522
4524
4523 Returns 0 on success.
4525 Returns 0 on success.
4524 """
4526 """
4525
4527
4526 if opts.get("date"):
4528 if opts.get("date"):
4527 if opts.get("rev"):
4529 if opts.get("rev"):
4528 raise error.Abort(_("you can't specify a revision and a date"))
4530 raise error.Abort(_("you can't specify a revision and a date"))
4529 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4531 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4530
4532
4531 parent, p2 = repo.dirstate.parents()
4533 parent, p2 = repo.dirstate.parents()
4532 if not opts.get('rev') and p2 != nullid:
4534 if not opts.get('rev') and p2 != nullid:
4533 # revert after merge is a trap for new users (issue2915)
4535 # revert after merge is a trap for new users (issue2915)
4534 raise error.Abort(_('uncommitted merge with no revision specified'),
4536 raise error.Abort(_('uncommitted merge with no revision specified'),
4535 hint=_("use 'hg update' or see 'hg help revert'"))
4537 hint=_("use 'hg update' or see 'hg help revert'"))
4536
4538
4537 ctx = scmutil.revsingle(repo, opts.get('rev'))
4539 ctx = scmutil.revsingle(repo, opts.get('rev'))
4538
4540
4539 if (not (pats or opts.get('include') or opts.get('exclude') or
4541 if (not (pats or opts.get('include') or opts.get('exclude') or
4540 opts.get('all') or opts.get('interactive'))):
4542 opts.get('all') or opts.get('interactive'))):
4541 msg = _("no files or directories specified")
4543 msg = _("no files or directories specified")
4542 if p2 != nullid:
4544 if p2 != nullid:
4543 hint = _("uncommitted merge, use --all to discard all changes,"
4545 hint = _("uncommitted merge, use --all to discard all changes,"
4544 " or 'hg update -C .' to abort the merge")
4546 " or 'hg update -C .' to abort the merge")
4545 raise error.Abort(msg, hint=hint)
4547 raise error.Abort(msg, hint=hint)
4546 dirty = any(repo.status())
4548 dirty = any(repo.status())
4547 node = ctx.node()
4549 node = ctx.node()
4548 if node != parent:
4550 if node != parent:
4549 if dirty:
4551 if dirty:
4550 hint = _("uncommitted changes, use --all to discard all"
4552 hint = _("uncommitted changes, use --all to discard all"
4551 " changes, or 'hg update %s' to update") % ctx.rev()
4553 " changes, or 'hg update %s' to update") % ctx.rev()
4552 else:
4554 else:
4553 hint = _("use --all to revert all files,"
4555 hint = _("use --all to revert all files,"
4554 " or 'hg update %s' to update") % ctx.rev()
4556 " or 'hg update %s' to update") % ctx.rev()
4555 elif dirty:
4557 elif dirty:
4556 hint = _("uncommitted changes, use --all to discard all changes")
4558 hint = _("uncommitted changes, use --all to discard all changes")
4557 else:
4559 else:
4558 hint = _("use --all to revert all files")
4560 hint = _("use --all to revert all files")
4559 raise error.Abort(msg, hint=hint)
4561 raise error.Abort(msg, hint=hint)
4560
4562
4561 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4563 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4562
4564
4563 @command('rollback', dryrunopts +
4565 @command('rollback', dryrunopts +
4564 [('f', 'force', False, _('ignore safety measures'))])
4566 [('f', 'force', False, _('ignore safety measures'))])
4565 def rollback(ui, repo, **opts):
4567 def rollback(ui, repo, **opts):
4566 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4568 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4567
4569
4568 Please use :hg:`commit --amend` instead of rollback to correct
4570 Please use :hg:`commit --amend` instead of rollback to correct
4569 mistakes in the last commit.
4571 mistakes in the last commit.
4570
4572
4571 This command should be used with care. There is only one level of
4573 This command should be used with care. There is only one level of
4572 rollback, and there is no way to undo a rollback. It will also
4574 rollback, and there is no way to undo a rollback. It will also
4573 restore the dirstate at the time of the last transaction, losing
4575 restore the dirstate at the time of the last transaction, losing
4574 any dirstate changes since that time. This command does not alter
4576 any dirstate changes since that time. This command does not alter
4575 the working directory.
4577 the working directory.
4576
4578
4577 Transactions are used to encapsulate the effects of all commands
4579 Transactions are used to encapsulate the effects of all commands
4578 that create new changesets or propagate existing changesets into a
4580 that create new changesets or propagate existing changesets into a
4579 repository.
4581 repository.
4580
4582
4581 .. container:: verbose
4583 .. container:: verbose
4582
4584
4583 For example, the following commands are transactional, and their
4585 For example, the following commands are transactional, and their
4584 effects can be rolled back:
4586 effects can be rolled back:
4585
4587
4586 - commit
4588 - commit
4587 - import
4589 - import
4588 - pull
4590 - pull
4589 - push (with this repository as the destination)
4591 - push (with this repository as the destination)
4590 - unbundle
4592 - unbundle
4591
4593
4592 To avoid permanent data loss, rollback will refuse to rollback a
4594 To avoid permanent data loss, rollback will refuse to rollback a
4593 commit transaction if it isn't checked out. Use --force to
4595 commit transaction if it isn't checked out. Use --force to
4594 override this protection.
4596 override this protection.
4595
4597
4596 The rollback command can be entirely disabled by setting the
4598 The rollback command can be entirely disabled by setting the
4597 ``ui.rollback`` configuration setting to false. If you're here
4599 ``ui.rollback`` configuration setting to false. If you're here
4598 because you want to use rollback and it's disabled, you can
4600 because you want to use rollback and it's disabled, you can
4599 re-enable the command by setting ``ui.rollback`` to true.
4601 re-enable the command by setting ``ui.rollback`` to true.
4600
4602
4601 This command is not intended for use on public repositories. Once
4603 This command is not intended for use on public repositories. Once
4602 changes are visible for pull by other users, rolling a transaction
4604 changes are visible for pull by other users, rolling a transaction
4603 back locally is ineffective (someone else may already have pulled
4605 back locally is ineffective (someone else may already have pulled
4604 the changes). Furthermore, a race is possible with readers of the
4606 the changes). Furthermore, a race is possible with readers of the
4605 repository; for example an in-progress pull from the repository
4607 repository; for example an in-progress pull from the repository
4606 may fail if a rollback is performed.
4608 may fail if a rollback is performed.
4607
4609
4608 Returns 0 on success, 1 if no rollback data is available.
4610 Returns 0 on success, 1 if no rollback data is available.
4609 """
4611 """
4610 if not ui.configbool('ui', 'rollback', True):
4612 if not ui.configbool('ui', 'rollback', True):
4611 raise error.Abort(_('rollback is disabled because it is unsafe'),
4613 raise error.Abort(_('rollback is disabled because it is unsafe'),
4612 hint=('see `hg help -v rollback` for information'))
4614 hint=('see `hg help -v rollback` for information'))
4613 return repo.rollback(dryrun=opts.get(r'dry_run'),
4615 return repo.rollback(dryrun=opts.get(r'dry_run'),
4614 force=opts.get(r'force'))
4616 force=opts.get(r'force'))
4615
4617
4616 @command('root', [])
4618 @command('root', [])
4617 def root(ui, repo):
4619 def root(ui, repo):
4618 """print the root (top) of the current working directory
4620 """print the root (top) of the current working directory
4619
4621
4620 Print the root directory of the current repository.
4622 Print the root directory of the current repository.
4621
4623
4622 Returns 0 on success.
4624 Returns 0 on success.
4623 """
4625 """
4624 ui.write(repo.root + "\n")
4626 ui.write(repo.root + "\n")
4625
4627
4626 @command('^serve',
4628 @command('^serve',
4627 [('A', 'accesslog', '', _('name of access log file to write to'),
4629 [('A', 'accesslog', '', _('name of access log file to write to'),
4628 _('FILE')),
4630 _('FILE')),
4629 ('d', 'daemon', None, _('run server in background')),
4631 ('d', 'daemon', None, _('run server in background')),
4630 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4632 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4631 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4633 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4632 # use string type, then we can check if something was passed
4634 # use string type, then we can check if something was passed
4633 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4635 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4634 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4636 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4635 _('ADDR')),
4637 _('ADDR')),
4636 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4638 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4637 _('PREFIX')),
4639 _('PREFIX')),
4638 ('n', 'name', '',
4640 ('n', 'name', '',
4639 _('name to show in web pages (default: working directory)'), _('NAME')),
4641 _('name to show in web pages (default: working directory)'), _('NAME')),
4640 ('', 'web-conf', '',
4642 ('', 'web-conf', '',
4641 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4643 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4642 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4644 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4643 _('FILE')),
4645 _('FILE')),
4644 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4646 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4645 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4647 ('', 'stdio', None, _('for remote clients (ADVANCED)')),
4646 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4648 ('', 'cmdserver', '', _('for remote clients (ADVANCED)'), _('MODE')),
4647 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4649 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4648 ('', 'style', '', _('template style to use'), _('STYLE')),
4650 ('', 'style', '', _('template style to use'), _('STYLE')),
4649 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4651 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4650 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4652 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))]
4651 + subrepoopts,
4653 + subrepoopts,
4652 _('[OPTION]...'),
4654 _('[OPTION]...'),
4653 optionalrepo=True)
4655 optionalrepo=True)
4654 def serve(ui, repo, **opts):
4656 def serve(ui, repo, **opts):
4655 """start stand-alone webserver
4657 """start stand-alone webserver
4656
4658
4657 Start a local HTTP repository browser and pull server. You can use
4659 Start a local HTTP repository browser and pull server. You can use
4658 this for ad-hoc sharing and browsing of repositories. It is
4660 this for ad-hoc sharing and browsing of repositories. It is
4659 recommended to use a real web server to serve a repository for
4661 recommended to use a real web server to serve a repository for
4660 longer periods of time.
4662 longer periods of time.
4661
4663
4662 Please note that the server does not implement access control.
4664 Please note that the server does not implement access control.
4663 This means that, by default, anybody can read from the server and
4665 This means that, by default, anybody can read from the server and
4664 nobody can write to it by default. Set the ``web.allow_push``
4666 nobody can write to it by default. Set the ``web.allow_push``
4665 option to ``*`` to allow everybody to push to the server. You
4667 option to ``*`` to allow everybody to push to the server. You
4666 should use a real web server if you need to authenticate users.
4668 should use a real web server if you need to authenticate users.
4667
4669
4668 By default, the server logs accesses to stdout and errors to
4670 By default, the server logs accesses to stdout and errors to
4669 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4671 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4670 files.
4672 files.
4671
4673
4672 To have the server choose a free port number to listen on, specify
4674 To have the server choose a free port number to listen on, specify
4673 a port number of 0; in this case, the server will print the port
4675 a port number of 0; in this case, the server will print the port
4674 number it uses.
4676 number it uses.
4675
4677
4676 Returns 0 on success.
4678 Returns 0 on success.
4677 """
4679 """
4678
4680
4679 opts = pycompat.byteskwargs(opts)
4681 opts = pycompat.byteskwargs(opts)
4680 if opts["stdio"] and opts["cmdserver"]:
4682 if opts["stdio"] and opts["cmdserver"]:
4681 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4683 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4682
4684
4683 if opts["stdio"]:
4685 if opts["stdio"]:
4684 if repo is None:
4686 if repo is None:
4685 raise error.RepoError(_("there is no Mercurial repository here"
4687 raise error.RepoError(_("there is no Mercurial repository here"
4686 " (.hg not found)"))
4688 " (.hg not found)"))
4687 s = sshserver.sshserver(ui, repo)
4689 s = sshserver.sshserver(ui, repo)
4688 s.serve_forever()
4690 s.serve_forever()
4689
4691
4690 service = server.createservice(ui, repo, opts)
4692 service = server.createservice(ui, repo, opts)
4691 return server.runservice(opts, initfn=service.init, runfn=service.run)
4693 return server.runservice(opts, initfn=service.init, runfn=service.run)
4692
4694
4693 @command('^status|st',
4695 @command('^status|st',
4694 [('A', 'all', None, _('show status of all files')),
4696 [('A', 'all', None, _('show status of all files')),
4695 ('m', 'modified', None, _('show only modified files')),
4697 ('m', 'modified', None, _('show only modified files')),
4696 ('a', 'added', None, _('show only added files')),
4698 ('a', 'added', None, _('show only added files')),
4697 ('r', 'removed', None, _('show only removed files')),
4699 ('r', 'removed', None, _('show only removed files')),
4698 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4700 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4699 ('c', 'clean', None, _('show only files without changes')),
4701 ('c', 'clean', None, _('show only files without changes')),
4700 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4702 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4701 ('i', 'ignored', None, _('show only ignored files')),
4703 ('i', 'ignored', None, _('show only ignored files')),
4702 ('n', 'no-status', None, _('hide status prefix')),
4704 ('n', 'no-status', None, _('hide status prefix')),
4703 ('C', 'copies', None, _('show source of copied files')),
4705 ('C', 'copies', None, _('show source of copied files')),
4704 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4706 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4705 ('', 'rev', [], _('show difference from revision'), _('REV')),
4707 ('', 'rev', [], _('show difference from revision'), _('REV')),
4706 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4708 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4707 ] + walkopts + subrepoopts + formatteropts,
4709 ] + walkopts + subrepoopts + formatteropts,
4708 _('[OPTION]... [FILE]...'),
4710 _('[OPTION]... [FILE]...'),
4709 inferrepo=True)
4711 inferrepo=True)
4710 def status(ui, repo, *pats, **opts):
4712 def status(ui, repo, *pats, **opts):
4711 """show changed files in the working directory
4713 """show changed files in the working directory
4712
4714
4713 Show status of files in the repository. If names are given, only
4715 Show status of files in the repository. If names are given, only
4714 files that match are shown. Files that are clean or ignored or
4716 files that match are shown. Files that are clean or ignored or
4715 the source of a copy/move operation, are not listed unless
4717 the source of a copy/move operation, are not listed unless
4716 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4718 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4717 Unless options described with "show only ..." are given, the
4719 Unless options described with "show only ..." are given, the
4718 options -mardu are used.
4720 options -mardu are used.
4719
4721
4720 Option -q/--quiet hides untracked (unknown and ignored) files
4722 Option -q/--quiet hides untracked (unknown and ignored) files
4721 unless explicitly requested with -u/--unknown or -i/--ignored.
4723 unless explicitly requested with -u/--unknown or -i/--ignored.
4722
4724
4723 .. note::
4725 .. note::
4724
4726
4725 :hg:`status` may appear to disagree with diff if permissions have
4727 :hg:`status` may appear to disagree with diff if permissions have
4726 changed or a merge has occurred. The standard diff format does
4728 changed or a merge has occurred. The standard diff format does
4727 not report permission changes and diff only reports changes
4729 not report permission changes and diff only reports changes
4728 relative to one merge parent.
4730 relative to one merge parent.
4729
4731
4730 If one revision is given, it is used as the base revision.
4732 If one revision is given, it is used as the base revision.
4731 If two revisions are given, the differences between them are
4733 If two revisions are given, the differences between them are
4732 shown. The --change option can also be used as a shortcut to list
4734 shown. The --change option can also be used as a shortcut to list
4733 the changed files of a revision from its first parent.
4735 the changed files of a revision from its first parent.
4734
4736
4735 The codes used to show the status of files are::
4737 The codes used to show the status of files are::
4736
4738
4737 M = modified
4739 M = modified
4738 A = added
4740 A = added
4739 R = removed
4741 R = removed
4740 C = clean
4742 C = clean
4741 ! = missing (deleted by non-hg command, but still tracked)
4743 ! = missing (deleted by non-hg command, but still tracked)
4742 ? = not tracked
4744 ? = not tracked
4743 I = ignored
4745 I = ignored
4744 = origin of the previous file (with --copies)
4746 = origin of the previous file (with --copies)
4745
4747
4746 .. container:: verbose
4748 .. container:: verbose
4747
4749
4748 Examples:
4750 Examples:
4749
4751
4750 - show changes in the working directory relative to a
4752 - show changes in the working directory relative to a
4751 changeset::
4753 changeset::
4752
4754
4753 hg status --rev 9353
4755 hg status --rev 9353
4754
4756
4755 - show changes in the working directory relative to the
4757 - show changes in the working directory relative to the
4756 current directory (see :hg:`help patterns` for more information)::
4758 current directory (see :hg:`help patterns` for more information)::
4757
4759
4758 hg status re:
4760 hg status re:
4759
4761
4760 - show all changes including copies in an existing changeset::
4762 - show all changes including copies in an existing changeset::
4761
4763
4762 hg status --copies --change 9353
4764 hg status --copies --change 9353
4763
4765
4764 - get a NUL separated list of added files, suitable for xargs::
4766 - get a NUL separated list of added files, suitable for xargs::
4765
4767
4766 hg status -an0
4768 hg status -an0
4767
4769
4768 Returns 0 on success.
4770 Returns 0 on success.
4769 """
4771 """
4770
4772
4771 opts = pycompat.byteskwargs(opts)
4773 opts = pycompat.byteskwargs(opts)
4772 revs = opts.get('rev')
4774 revs = opts.get('rev')
4773 change = opts.get('change')
4775 change = opts.get('change')
4774
4776
4775 if revs and change:
4777 if revs and change:
4776 msg = _('cannot specify --rev and --change at the same time')
4778 msg = _('cannot specify --rev and --change at the same time')
4777 raise error.Abort(msg)
4779 raise error.Abort(msg)
4778 elif change:
4780 elif change:
4779 node2 = scmutil.revsingle(repo, change, None).node()
4781 node2 = scmutil.revsingle(repo, change, None).node()
4780 node1 = repo[node2].p1().node()
4782 node1 = repo[node2].p1().node()
4781 else:
4783 else:
4782 node1, node2 = scmutil.revpair(repo, revs)
4784 node1, node2 = scmutil.revpair(repo, revs)
4783
4785
4784 if pats or ui.configbool('commands', 'status.relative'):
4786 if pats or ui.configbool('commands', 'status.relative'):
4785 cwd = repo.getcwd()
4787 cwd = repo.getcwd()
4786 else:
4788 else:
4787 cwd = ''
4789 cwd = ''
4788
4790
4789 if opts.get('print0'):
4791 if opts.get('print0'):
4790 end = '\0'
4792 end = '\0'
4791 else:
4793 else:
4792 end = '\n'
4794 end = '\n'
4793 copy = {}
4795 copy = {}
4794 states = 'modified added removed deleted unknown ignored clean'.split()
4796 states = 'modified added removed deleted unknown ignored clean'.split()
4795 show = [k for k in states if opts.get(k)]
4797 show = [k for k in states if opts.get(k)]
4796 if opts.get('all'):
4798 if opts.get('all'):
4797 show += ui.quiet and (states[:4] + ['clean']) or states
4799 show += ui.quiet and (states[:4] + ['clean']) or states
4798 if not show:
4800 if not show:
4799 if ui.quiet:
4801 if ui.quiet:
4800 show = states[:4]
4802 show = states[:4]
4801 else:
4803 else:
4802 show = states[:5]
4804 show = states[:5]
4803
4805
4804 m = scmutil.match(repo[node2], pats, opts)
4806 m = scmutil.match(repo[node2], pats, opts)
4805 stat = repo.status(node1, node2, m,
4807 stat = repo.status(node1, node2, m,
4806 'ignored' in show, 'clean' in show, 'unknown' in show,
4808 'ignored' in show, 'clean' in show, 'unknown' in show,
4807 opts.get('subrepos'))
4809 opts.get('subrepos'))
4808 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4810 changestates = zip(states, pycompat.iterbytestr('MAR!?IC'), stat)
4809
4811
4810 if (opts.get('all') or opts.get('copies')
4812 if (opts.get('all') or opts.get('copies')
4811 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4813 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4812 copy = copies.pathcopies(repo[node1], repo[node2], m)
4814 copy = copies.pathcopies(repo[node1], repo[node2], m)
4813
4815
4814 ui.pager('status')
4816 ui.pager('status')
4815 fm = ui.formatter('status', opts)
4817 fm = ui.formatter('status', opts)
4816 fmt = '%s' + end
4818 fmt = '%s' + end
4817 showchar = not opts.get('no_status')
4819 showchar = not opts.get('no_status')
4818
4820
4819 for state, char, files in changestates:
4821 for state, char, files in changestates:
4820 if state in show:
4822 if state in show:
4821 label = 'status.' + state
4823 label = 'status.' + state
4822 for f in files:
4824 for f in files:
4823 fm.startitem()
4825 fm.startitem()
4824 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4826 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4825 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4827 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4826 if f in copy:
4828 if f in copy:
4827 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4829 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4828 label='status.copied')
4830 label='status.copied')
4829 fm.end()
4831 fm.end()
4830
4832
4831 @command('^summary|sum',
4833 @command('^summary|sum',
4832 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4834 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4833 def summary(ui, repo, **opts):
4835 def summary(ui, repo, **opts):
4834 """summarize working directory state
4836 """summarize working directory state
4835
4837
4836 This generates a brief summary of the working directory state,
4838 This generates a brief summary of the working directory state,
4837 including parents, branch, commit status, phase and available updates.
4839 including parents, branch, commit status, phase and available updates.
4838
4840
4839 With the --remote option, this will check the default paths for
4841 With the --remote option, this will check the default paths for
4840 incoming and outgoing changes. This can be time-consuming.
4842 incoming and outgoing changes. This can be time-consuming.
4841
4843
4842 Returns 0 on success.
4844 Returns 0 on success.
4843 """
4845 """
4844
4846
4845 opts = pycompat.byteskwargs(opts)
4847 opts = pycompat.byteskwargs(opts)
4846 ui.pager('summary')
4848 ui.pager('summary')
4847 ctx = repo[None]
4849 ctx = repo[None]
4848 parents = ctx.parents()
4850 parents = ctx.parents()
4849 pnode = parents[0].node()
4851 pnode = parents[0].node()
4850 marks = []
4852 marks = []
4851
4853
4852 ms = None
4854 ms = None
4853 try:
4855 try:
4854 ms = mergemod.mergestate.read(repo)
4856 ms = mergemod.mergestate.read(repo)
4855 except error.UnsupportedMergeRecords as e:
4857 except error.UnsupportedMergeRecords as e:
4856 s = ' '.join(e.recordtypes)
4858 s = ' '.join(e.recordtypes)
4857 ui.warn(
4859 ui.warn(
4858 _('warning: merge state has unsupported record types: %s\n') % s)
4860 _('warning: merge state has unsupported record types: %s\n') % s)
4859 unresolved = 0
4861 unresolved = 0
4860 else:
4862 else:
4861 unresolved = [f for f in ms if ms[f] == 'u']
4863 unresolved = [f for f in ms if ms[f] == 'u']
4862
4864
4863 for p in parents:
4865 for p in parents:
4864 # label with log.changeset (instead of log.parent) since this
4866 # label with log.changeset (instead of log.parent) since this
4865 # shows a working directory parent *changeset*:
4867 # shows a working directory parent *changeset*:
4866 # i18n: column positioning for "hg summary"
4868 # i18n: column positioning for "hg summary"
4867 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4869 ui.write(_('parent: %d:%s ') % (p.rev(), p),
4868 label=cmdutil._changesetlabels(p))
4870 label=cmdutil._changesetlabels(p))
4869 ui.write(' '.join(p.tags()), label='log.tag')
4871 ui.write(' '.join(p.tags()), label='log.tag')
4870 if p.bookmarks():
4872 if p.bookmarks():
4871 marks.extend(p.bookmarks())
4873 marks.extend(p.bookmarks())
4872 if p.rev() == -1:
4874 if p.rev() == -1:
4873 if not len(repo):
4875 if not len(repo):
4874 ui.write(_(' (empty repository)'))
4876 ui.write(_(' (empty repository)'))
4875 else:
4877 else:
4876 ui.write(_(' (no revision checked out)'))
4878 ui.write(_(' (no revision checked out)'))
4877 if p.obsolete():
4879 if p.obsolete():
4878 ui.write(_(' (obsolete)'))
4880 ui.write(_(' (obsolete)'))
4879 if p.troubled():
4881 if p.troubled():
4880 ui.write(' ('
4882 ui.write(' ('
4881 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4883 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4882 for trouble in p.troubles())
4884 for trouble in p.troubles())
4883 + ')')
4885 + ')')
4884 ui.write('\n')
4886 ui.write('\n')
4885 if p.description():
4887 if p.description():
4886 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4888 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4887 label='log.summary')
4889 label='log.summary')
4888
4890
4889 branch = ctx.branch()
4891 branch = ctx.branch()
4890 bheads = repo.branchheads(branch)
4892 bheads = repo.branchheads(branch)
4891 # i18n: column positioning for "hg summary"
4893 # i18n: column positioning for "hg summary"
4892 m = _('branch: %s\n') % branch
4894 m = _('branch: %s\n') % branch
4893 if branch != 'default':
4895 if branch != 'default':
4894 ui.write(m, label='log.branch')
4896 ui.write(m, label='log.branch')
4895 else:
4897 else:
4896 ui.status(m, label='log.branch')
4898 ui.status(m, label='log.branch')
4897
4899
4898 if marks:
4900 if marks:
4899 active = repo._activebookmark
4901 active = repo._activebookmark
4900 # i18n: column positioning for "hg summary"
4902 # i18n: column positioning for "hg summary"
4901 ui.write(_('bookmarks:'), label='log.bookmark')
4903 ui.write(_('bookmarks:'), label='log.bookmark')
4902 if active is not None:
4904 if active is not None:
4903 if active in marks:
4905 if active in marks:
4904 ui.write(' *' + active, label=activebookmarklabel)
4906 ui.write(' *' + active, label=activebookmarklabel)
4905 marks.remove(active)
4907 marks.remove(active)
4906 else:
4908 else:
4907 ui.write(' [%s]' % active, label=activebookmarklabel)
4909 ui.write(' [%s]' % active, label=activebookmarklabel)
4908 for m in marks:
4910 for m in marks:
4909 ui.write(' ' + m, label='log.bookmark')
4911 ui.write(' ' + m, label='log.bookmark')
4910 ui.write('\n', label='log.bookmark')
4912 ui.write('\n', label='log.bookmark')
4911
4913
4912 status = repo.status(unknown=True)
4914 status = repo.status(unknown=True)
4913
4915
4914 c = repo.dirstate.copies()
4916 c = repo.dirstate.copies()
4915 copied, renamed = [], []
4917 copied, renamed = [], []
4916 for d, s in c.iteritems():
4918 for d, s in c.iteritems():
4917 if s in status.removed:
4919 if s in status.removed:
4918 status.removed.remove(s)
4920 status.removed.remove(s)
4919 renamed.append(d)
4921 renamed.append(d)
4920 else:
4922 else:
4921 copied.append(d)
4923 copied.append(d)
4922 if d in status.added:
4924 if d in status.added:
4923 status.added.remove(d)
4925 status.added.remove(d)
4924
4926
4925 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4927 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4926
4928
4927 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4929 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4928 (ui.label(_('%d added'), 'status.added'), status.added),
4930 (ui.label(_('%d added'), 'status.added'), status.added),
4929 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4931 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4930 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4932 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4931 (ui.label(_('%d copied'), 'status.copied'), copied),
4933 (ui.label(_('%d copied'), 'status.copied'), copied),
4932 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4934 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4933 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4935 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4934 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4936 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4935 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4937 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4936 t = []
4938 t = []
4937 for l, s in labels:
4939 for l, s in labels:
4938 if s:
4940 if s:
4939 t.append(l % len(s))
4941 t.append(l % len(s))
4940
4942
4941 t = ', '.join(t)
4943 t = ', '.join(t)
4942 cleanworkdir = False
4944 cleanworkdir = False
4943
4945
4944 if repo.vfs.exists('graftstate'):
4946 if repo.vfs.exists('graftstate'):
4945 t += _(' (graft in progress)')
4947 t += _(' (graft in progress)')
4946 if repo.vfs.exists('updatestate'):
4948 if repo.vfs.exists('updatestate'):
4947 t += _(' (interrupted update)')
4949 t += _(' (interrupted update)')
4948 elif len(parents) > 1:
4950 elif len(parents) > 1:
4949 t += _(' (merge)')
4951 t += _(' (merge)')
4950 elif branch != parents[0].branch():
4952 elif branch != parents[0].branch():
4951 t += _(' (new branch)')
4953 t += _(' (new branch)')
4952 elif (parents[0].closesbranch() and
4954 elif (parents[0].closesbranch() and
4953 pnode in repo.branchheads(branch, closed=True)):
4955 pnode in repo.branchheads(branch, closed=True)):
4954 t += _(' (head closed)')
4956 t += _(' (head closed)')
4955 elif not (status.modified or status.added or status.removed or renamed or
4957 elif not (status.modified or status.added or status.removed or renamed or
4956 copied or subs):
4958 copied or subs):
4957 t += _(' (clean)')
4959 t += _(' (clean)')
4958 cleanworkdir = True
4960 cleanworkdir = True
4959 elif pnode not in bheads:
4961 elif pnode not in bheads:
4960 t += _(' (new branch head)')
4962 t += _(' (new branch head)')
4961
4963
4962 if parents:
4964 if parents:
4963 pendingphase = max(p.phase() for p in parents)
4965 pendingphase = max(p.phase() for p in parents)
4964 else:
4966 else:
4965 pendingphase = phases.public
4967 pendingphase = phases.public
4966
4968
4967 if pendingphase > phases.newcommitphase(ui):
4969 if pendingphase > phases.newcommitphase(ui):
4968 t += ' (%s)' % phases.phasenames[pendingphase]
4970 t += ' (%s)' % phases.phasenames[pendingphase]
4969
4971
4970 if cleanworkdir:
4972 if cleanworkdir:
4971 # i18n: column positioning for "hg summary"
4973 # i18n: column positioning for "hg summary"
4972 ui.status(_('commit: %s\n') % t.strip())
4974 ui.status(_('commit: %s\n') % t.strip())
4973 else:
4975 else:
4974 # i18n: column positioning for "hg summary"
4976 # i18n: column positioning for "hg summary"
4975 ui.write(_('commit: %s\n') % t.strip())
4977 ui.write(_('commit: %s\n') % t.strip())
4976
4978
4977 # all ancestors of branch heads - all ancestors of parent = new csets
4979 # all ancestors of branch heads - all ancestors of parent = new csets
4978 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4980 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4979 bheads))
4981 bheads))
4980
4982
4981 if new == 0:
4983 if new == 0:
4982 # i18n: column positioning for "hg summary"
4984 # i18n: column positioning for "hg summary"
4983 ui.status(_('update: (current)\n'))
4985 ui.status(_('update: (current)\n'))
4984 elif pnode not in bheads:
4986 elif pnode not in bheads:
4985 # i18n: column positioning for "hg summary"
4987 # i18n: column positioning for "hg summary"
4986 ui.write(_('update: %d new changesets (update)\n') % new)
4988 ui.write(_('update: %d new changesets (update)\n') % new)
4987 else:
4989 else:
4988 # i18n: column positioning for "hg summary"
4990 # i18n: column positioning for "hg summary"
4989 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4991 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4990 (new, len(bheads)))
4992 (new, len(bheads)))
4991
4993
4992 t = []
4994 t = []
4993 draft = len(repo.revs('draft()'))
4995 draft = len(repo.revs('draft()'))
4994 if draft:
4996 if draft:
4995 t.append(_('%d draft') % draft)
4997 t.append(_('%d draft') % draft)
4996 secret = len(repo.revs('secret()'))
4998 secret = len(repo.revs('secret()'))
4997 if secret:
4999 if secret:
4998 t.append(_('%d secret') % secret)
5000 t.append(_('%d secret') % secret)
4999
5001
5000 if draft or secret:
5002 if draft or secret:
5001 ui.status(_('phases: %s\n') % ', '.join(t))
5003 ui.status(_('phases: %s\n') % ', '.join(t))
5002
5004
5003 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5005 if obsolete.isenabled(repo, obsolete.createmarkersopt):
5004 for trouble in ("unstable", "divergent", "bumped"):
5006 for trouble in ("unstable", "divergent", "bumped"):
5005 numtrouble = len(repo.revs(trouble + "()"))
5007 numtrouble = len(repo.revs(trouble + "()"))
5006 # We write all the possibilities to ease translation
5008 # We write all the possibilities to ease translation
5007 troublemsg = {
5009 troublemsg = {
5008 "unstable": _("unstable: %d changesets"),
5010 "unstable": _("unstable: %d changesets"),
5009 "divergent": _("divergent: %d changesets"),
5011 "divergent": _("divergent: %d changesets"),
5010 "bumped": _("bumped: %d changesets"),
5012 "bumped": _("bumped: %d changesets"),
5011 }
5013 }
5012 if numtrouble > 0:
5014 if numtrouble > 0:
5013 ui.status(troublemsg[trouble] % numtrouble + "\n")
5015 ui.status(troublemsg[trouble] % numtrouble + "\n")
5014
5016
5015 cmdutil.summaryhooks(ui, repo)
5017 cmdutil.summaryhooks(ui, repo)
5016
5018
5017 if opts.get('remote'):
5019 if opts.get('remote'):
5018 needsincoming, needsoutgoing = True, True
5020 needsincoming, needsoutgoing = True, True
5019 else:
5021 else:
5020 needsincoming, needsoutgoing = False, False
5022 needsincoming, needsoutgoing = False, False
5021 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5023 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5022 if i:
5024 if i:
5023 needsincoming = True
5025 needsincoming = True
5024 if o:
5026 if o:
5025 needsoutgoing = True
5027 needsoutgoing = True
5026 if not needsincoming and not needsoutgoing:
5028 if not needsincoming and not needsoutgoing:
5027 return
5029 return
5028
5030
5029 def getincoming():
5031 def getincoming():
5030 source, branches = hg.parseurl(ui.expandpath('default'))
5032 source, branches = hg.parseurl(ui.expandpath('default'))
5031 sbranch = branches[0]
5033 sbranch = branches[0]
5032 try:
5034 try:
5033 other = hg.peer(repo, {}, source)
5035 other = hg.peer(repo, {}, source)
5034 except error.RepoError:
5036 except error.RepoError:
5035 if opts.get('remote'):
5037 if opts.get('remote'):
5036 raise
5038 raise
5037 return source, sbranch, None, None, None
5039 return source, sbranch, None, None, None
5038 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5040 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5039 if revs:
5041 if revs:
5040 revs = [other.lookup(rev) for rev in revs]
5042 revs = [other.lookup(rev) for rev in revs]
5041 ui.debug('comparing with %s\n' % util.hidepassword(source))
5043 ui.debug('comparing with %s\n' % util.hidepassword(source))
5042 repo.ui.pushbuffer()
5044 repo.ui.pushbuffer()
5043 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5045 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5044 repo.ui.popbuffer()
5046 repo.ui.popbuffer()
5045 return source, sbranch, other, commoninc, commoninc[1]
5047 return source, sbranch, other, commoninc, commoninc[1]
5046
5048
5047 if needsincoming:
5049 if needsincoming:
5048 source, sbranch, sother, commoninc, incoming = getincoming()
5050 source, sbranch, sother, commoninc, incoming = getincoming()
5049 else:
5051 else:
5050 source = sbranch = sother = commoninc = incoming = None
5052 source = sbranch = sother = commoninc = incoming = None
5051
5053
5052 def getoutgoing():
5054 def getoutgoing():
5053 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5055 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5054 dbranch = branches[0]
5056 dbranch = branches[0]
5055 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5057 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5056 if source != dest:
5058 if source != dest:
5057 try:
5059 try:
5058 dother = hg.peer(repo, {}, dest)
5060 dother = hg.peer(repo, {}, dest)
5059 except error.RepoError:
5061 except error.RepoError:
5060 if opts.get('remote'):
5062 if opts.get('remote'):
5061 raise
5063 raise
5062 return dest, dbranch, None, None
5064 return dest, dbranch, None, None
5063 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5065 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5064 elif sother is None:
5066 elif sother is None:
5065 # there is no explicit destination peer, but source one is invalid
5067 # there is no explicit destination peer, but source one is invalid
5066 return dest, dbranch, None, None
5068 return dest, dbranch, None, None
5067 else:
5069 else:
5068 dother = sother
5070 dother = sother
5069 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5071 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5070 common = None
5072 common = None
5071 else:
5073 else:
5072 common = commoninc
5074 common = commoninc
5073 if revs:
5075 if revs:
5074 revs = [repo.lookup(rev) for rev in revs]
5076 revs = [repo.lookup(rev) for rev in revs]
5075 repo.ui.pushbuffer()
5077 repo.ui.pushbuffer()
5076 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5078 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5077 commoninc=common)
5079 commoninc=common)
5078 repo.ui.popbuffer()
5080 repo.ui.popbuffer()
5079 return dest, dbranch, dother, outgoing
5081 return dest, dbranch, dother, outgoing
5080
5082
5081 if needsoutgoing:
5083 if needsoutgoing:
5082 dest, dbranch, dother, outgoing = getoutgoing()
5084 dest, dbranch, dother, outgoing = getoutgoing()
5083 else:
5085 else:
5084 dest = dbranch = dother = outgoing = None
5086 dest = dbranch = dother = outgoing = None
5085
5087
5086 if opts.get('remote'):
5088 if opts.get('remote'):
5087 t = []
5089 t = []
5088 if incoming:
5090 if incoming:
5089 t.append(_('1 or more incoming'))
5091 t.append(_('1 or more incoming'))
5090 o = outgoing.missing
5092 o = outgoing.missing
5091 if o:
5093 if o:
5092 t.append(_('%d outgoing') % len(o))
5094 t.append(_('%d outgoing') % len(o))
5093 other = dother or sother
5095 other = dother or sother
5094 if 'bookmarks' in other.listkeys('namespaces'):
5096 if 'bookmarks' in other.listkeys('namespaces'):
5095 counts = bookmarks.summary(repo, other)
5097 counts = bookmarks.summary(repo, other)
5096 if counts[0] > 0:
5098 if counts[0] > 0:
5097 t.append(_('%d incoming bookmarks') % counts[0])
5099 t.append(_('%d incoming bookmarks') % counts[0])
5098 if counts[1] > 0:
5100 if counts[1] > 0:
5099 t.append(_('%d outgoing bookmarks') % counts[1])
5101 t.append(_('%d outgoing bookmarks') % counts[1])
5100
5102
5101 if t:
5103 if t:
5102 # i18n: column positioning for "hg summary"
5104 # i18n: column positioning for "hg summary"
5103 ui.write(_('remote: %s\n') % (', '.join(t)))
5105 ui.write(_('remote: %s\n') % (', '.join(t)))
5104 else:
5106 else:
5105 # i18n: column positioning for "hg summary"
5107 # i18n: column positioning for "hg summary"
5106 ui.status(_('remote: (synced)\n'))
5108 ui.status(_('remote: (synced)\n'))
5107
5109
5108 cmdutil.summaryremotehooks(ui, repo, opts,
5110 cmdutil.summaryremotehooks(ui, repo, opts,
5109 ((source, sbranch, sother, commoninc),
5111 ((source, sbranch, sother, commoninc),
5110 (dest, dbranch, dother, outgoing)))
5112 (dest, dbranch, dother, outgoing)))
5111
5113
5112 @command('tag',
5114 @command('tag',
5113 [('f', 'force', None, _('force tag')),
5115 [('f', 'force', None, _('force tag')),
5114 ('l', 'local', None, _('make the tag local')),
5116 ('l', 'local', None, _('make the tag local')),
5115 ('r', 'rev', '', _('revision to tag'), _('REV')),
5117 ('r', 'rev', '', _('revision to tag'), _('REV')),
5116 ('', 'remove', None, _('remove a tag')),
5118 ('', 'remove', None, _('remove a tag')),
5117 # -l/--local is already there, commitopts cannot be used
5119 # -l/--local is already there, commitopts cannot be used
5118 ('e', 'edit', None, _('invoke editor on commit messages')),
5120 ('e', 'edit', None, _('invoke editor on commit messages')),
5119 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5121 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5120 ] + commitopts2,
5122 ] + commitopts2,
5121 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5123 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5122 def tag(ui, repo, name1, *names, **opts):
5124 def tag(ui, repo, name1, *names, **opts):
5123 """add one or more tags for the current or given revision
5125 """add one or more tags for the current or given revision
5124
5126
5125 Name a particular revision using <name>.
5127 Name a particular revision using <name>.
5126
5128
5127 Tags are used to name particular revisions of the repository and are
5129 Tags are used to name particular revisions of the repository and are
5128 very useful to compare different revisions, to go back to significant
5130 very useful to compare different revisions, to go back to significant
5129 earlier versions or to mark branch points as releases, etc. Changing
5131 earlier versions or to mark branch points as releases, etc. Changing
5130 an existing tag is normally disallowed; use -f/--force to override.
5132 an existing tag is normally disallowed; use -f/--force to override.
5131
5133
5132 If no revision is given, the parent of the working directory is
5134 If no revision is given, the parent of the working directory is
5133 used.
5135 used.
5134
5136
5135 To facilitate version control, distribution, and merging of tags,
5137 To facilitate version control, distribution, and merging of tags,
5136 they are stored as a file named ".hgtags" which is managed similarly
5138 they are stored as a file named ".hgtags" which is managed similarly
5137 to other project files and can be hand-edited if necessary. This
5139 to other project files and can be hand-edited if necessary. This
5138 also means that tagging creates a new commit. The file
5140 also means that tagging creates a new commit. The file
5139 ".hg/localtags" is used for local tags (not shared among
5141 ".hg/localtags" is used for local tags (not shared among
5140 repositories).
5142 repositories).
5141
5143
5142 Tag commits are usually made at the head of a branch. If the parent
5144 Tag commits are usually made at the head of a branch. If the parent
5143 of the working directory is not a branch head, :hg:`tag` aborts; use
5145 of the working directory is not a branch head, :hg:`tag` aborts; use
5144 -f/--force to force the tag commit to be based on a non-head
5146 -f/--force to force the tag commit to be based on a non-head
5145 changeset.
5147 changeset.
5146
5148
5147 See :hg:`help dates` for a list of formats valid for -d/--date.
5149 See :hg:`help dates` for a list of formats valid for -d/--date.
5148
5150
5149 Since tag names have priority over branch names during revision
5151 Since tag names have priority over branch names during revision
5150 lookup, using an existing branch name as a tag name is discouraged.
5152 lookup, using an existing branch name as a tag name is discouraged.
5151
5153
5152 Returns 0 on success.
5154 Returns 0 on success.
5153 """
5155 """
5154 opts = pycompat.byteskwargs(opts)
5156 opts = pycompat.byteskwargs(opts)
5155 wlock = lock = None
5157 wlock = lock = None
5156 try:
5158 try:
5157 wlock = repo.wlock()
5159 wlock = repo.wlock()
5158 lock = repo.lock()
5160 lock = repo.lock()
5159 rev_ = "."
5161 rev_ = "."
5160 names = [t.strip() for t in (name1,) + names]
5162 names = [t.strip() for t in (name1,) + names]
5161 if len(names) != len(set(names)):
5163 if len(names) != len(set(names)):
5162 raise error.Abort(_('tag names must be unique'))
5164 raise error.Abort(_('tag names must be unique'))
5163 for n in names:
5165 for n in names:
5164 scmutil.checknewlabel(repo, n, 'tag')
5166 scmutil.checknewlabel(repo, n, 'tag')
5165 if not n:
5167 if not n:
5166 raise error.Abort(_('tag names cannot consist entirely of '
5168 raise error.Abort(_('tag names cannot consist entirely of '
5167 'whitespace'))
5169 'whitespace'))
5168 if opts.get('rev') and opts.get('remove'):
5170 if opts.get('rev') and opts.get('remove'):
5169 raise error.Abort(_("--rev and --remove are incompatible"))
5171 raise error.Abort(_("--rev and --remove are incompatible"))
5170 if opts.get('rev'):
5172 if opts.get('rev'):
5171 rev_ = opts['rev']
5173 rev_ = opts['rev']
5172 message = opts.get('message')
5174 message = opts.get('message')
5173 if opts.get('remove'):
5175 if opts.get('remove'):
5174 if opts.get('local'):
5176 if opts.get('local'):
5175 expectedtype = 'local'
5177 expectedtype = 'local'
5176 else:
5178 else:
5177 expectedtype = 'global'
5179 expectedtype = 'global'
5178
5180
5179 for n in names:
5181 for n in names:
5180 if not repo.tagtype(n):
5182 if not repo.tagtype(n):
5181 raise error.Abort(_("tag '%s' does not exist") % n)
5183 raise error.Abort(_("tag '%s' does not exist") % n)
5182 if repo.tagtype(n) != expectedtype:
5184 if repo.tagtype(n) != expectedtype:
5183 if expectedtype == 'global':
5185 if expectedtype == 'global':
5184 raise error.Abort(_("tag '%s' is not a global tag") % n)
5186 raise error.Abort(_("tag '%s' is not a global tag") % n)
5185 else:
5187 else:
5186 raise error.Abort(_("tag '%s' is not a local tag") % n)
5188 raise error.Abort(_("tag '%s' is not a local tag") % n)
5187 rev_ = 'null'
5189 rev_ = 'null'
5188 if not message:
5190 if not message:
5189 # we don't translate commit messages
5191 # we don't translate commit messages
5190 message = 'Removed tag %s' % ', '.join(names)
5192 message = 'Removed tag %s' % ', '.join(names)
5191 elif not opts.get('force'):
5193 elif not opts.get('force'):
5192 for n in names:
5194 for n in names:
5193 if n in repo.tags():
5195 if n in repo.tags():
5194 raise error.Abort(_("tag '%s' already exists "
5196 raise error.Abort(_("tag '%s' already exists "
5195 "(use -f to force)") % n)
5197 "(use -f to force)") % n)
5196 if not opts.get('local'):
5198 if not opts.get('local'):
5197 p1, p2 = repo.dirstate.parents()
5199 p1, p2 = repo.dirstate.parents()
5198 if p2 != nullid:
5200 if p2 != nullid:
5199 raise error.Abort(_('uncommitted merge'))
5201 raise error.Abort(_('uncommitted merge'))
5200 bheads = repo.branchheads()
5202 bheads = repo.branchheads()
5201 if not opts.get('force') and bheads and p1 not in bheads:
5203 if not opts.get('force') and bheads and p1 not in bheads:
5202 raise error.Abort(_('working directory is not at a branch head '
5204 raise error.Abort(_('working directory is not at a branch head '
5203 '(use -f to force)'))
5205 '(use -f to force)'))
5204 r = scmutil.revsingle(repo, rev_).node()
5206 r = scmutil.revsingle(repo, rev_).node()
5205
5207
5206 if not message:
5208 if not message:
5207 # we don't translate commit messages
5209 # we don't translate commit messages
5208 message = ('Added tag %s for changeset %s' %
5210 message = ('Added tag %s for changeset %s' %
5209 (', '.join(names), short(r)))
5211 (', '.join(names), short(r)))
5210
5212
5211 date = opts.get('date')
5213 date = opts.get('date')
5212 if date:
5214 if date:
5213 date = util.parsedate(date)
5215 date = util.parsedate(date)
5214
5216
5215 if opts.get('remove'):
5217 if opts.get('remove'):
5216 editform = 'tag.remove'
5218 editform = 'tag.remove'
5217 else:
5219 else:
5218 editform = 'tag.add'
5220 editform = 'tag.add'
5219 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5221 editor = cmdutil.getcommiteditor(editform=editform,
5222 **pycompat.strkwargs(opts))
5220
5223
5221 # don't allow tagging the null rev
5224 # don't allow tagging the null rev
5222 if (not opts.get('remove') and
5225 if (not opts.get('remove') and
5223 scmutil.revsingle(repo, rev_).rev() == nullrev):
5226 scmutil.revsingle(repo, rev_).rev() == nullrev):
5224 raise error.Abort(_("cannot tag null revision"))
5227 raise error.Abort(_("cannot tag null revision"))
5225
5228
5226 tagsmod.tag(repo, names, r, message, opts.get('local'),
5229 tagsmod.tag(repo, names, r, message, opts.get('local'),
5227 opts.get('user'), date, editor=editor)
5230 opts.get('user'), date, editor=editor)
5228 finally:
5231 finally:
5229 release(lock, wlock)
5232 release(lock, wlock)
5230
5233
5231 @command('tags', formatteropts, '')
5234 @command('tags', formatteropts, '')
5232 def tags(ui, repo, **opts):
5235 def tags(ui, repo, **opts):
5233 """list repository tags
5236 """list repository tags
5234
5237
5235 This lists both regular and local tags. When the -v/--verbose
5238 This lists both regular and local tags. When the -v/--verbose
5236 switch is used, a third column "local" is printed for local tags.
5239 switch is used, a third column "local" is printed for local tags.
5237 When the -q/--quiet switch is used, only the tag name is printed.
5240 When the -q/--quiet switch is used, only the tag name is printed.
5238
5241
5239 Returns 0 on success.
5242 Returns 0 on success.
5240 """
5243 """
5241
5244
5242 opts = pycompat.byteskwargs(opts)
5245 opts = pycompat.byteskwargs(opts)
5243 ui.pager('tags')
5246 ui.pager('tags')
5244 fm = ui.formatter('tags', opts)
5247 fm = ui.formatter('tags', opts)
5245 hexfunc = fm.hexfunc
5248 hexfunc = fm.hexfunc
5246 tagtype = ""
5249 tagtype = ""
5247
5250
5248 for t, n in reversed(repo.tagslist()):
5251 for t, n in reversed(repo.tagslist()):
5249 hn = hexfunc(n)
5252 hn = hexfunc(n)
5250 label = 'tags.normal'
5253 label = 'tags.normal'
5251 tagtype = ''
5254 tagtype = ''
5252 if repo.tagtype(t) == 'local':
5255 if repo.tagtype(t) == 'local':
5253 label = 'tags.local'
5256 label = 'tags.local'
5254 tagtype = 'local'
5257 tagtype = 'local'
5255
5258
5256 fm.startitem()
5259 fm.startitem()
5257 fm.write('tag', '%s', t, label=label)
5260 fm.write('tag', '%s', t, label=label)
5258 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5261 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5259 fm.condwrite(not ui.quiet, 'rev node', fmt,
5262 fm.condwrite(not ui.quiet, 'rev node', fmt,
5260 repo.changelog.rev(n), hn, label=label)
5263 repo.changelog.rev(n), hn, label=label)
5261 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5264 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5262 tagtype, label=label)
5265 tagtype, label=label)
5263 fm.plain('\n')
5266 fm.plain('\n')
5264 fm.end()
5267 fm.end()
5265
5268
5266 @command('tip',
5269 @command('tip',
5267 [('p', 'patch', None, _('show patch')),
5270 [('p', 'patch', None, _('show patch')),
5268 ('g', 'git', None, _('use git extended diff format')),
5271 ('g', 'git', None, _('use git extended diff format')),
5269 ] + templateopts,
5272 ] + templateopts,
5270 _('[-p] [-g]'))
5273 _('[-p] [-g]'))
5271 def tip(ui, repo, **opts):
5274 def tip(ui, repo, **opts):
5272 """show the tip revision (DEPRECATED)
5275 """show the tip revision (DEPRECATED)
5273
5276
5274 The tip revision (usually just called the tip) is the changeset
5277 The tip revision (usually just called the tip) is the changeset
5275 most recently added to the repository (and therefore the most
5278 most recently added to the repository (and therefore the most
5276 recently changed head).
5279 recently changed head).
5277
5280
5278 If you have just made a commit, that commit will be the tip. If
5281 If you have just made a commit, that commit will be the tip. If
5279 you have just pulled changes from another repository, the tip of
5282 you have just pulled changes from another repository, the tip of
5280 that repository becomes the current tip. The "tip" tag is special
5283 that repository becomes the current tip. The "tip" tag is special
5281 and cannot be renamed or assigned to a different changeset.
5284 and cannot be renamed or assigned to a different changeset.
5282
5285
5283 This command is deprecated, please use :hg:`heads` instead.
5286 This command is deprecated, please use :hg:`heads` instead.
5284
5287
5285 Returns 0 on success.
5288 Returns 0 on success.
5286 """
5289 """
5287 opts = pycompat.byteskwargs(opts)
5290 opts = pycompat.byteskwargs(opts)
5288 displayer = cmdutil.show_changeset(ui, repo, opts)
5291 displayer = cmdutil.show_changeset(ui, repo, opts)
5289 displayer.show(repo['tip'])
5292 displayer.show(repo['tip'])
5290 displayer.close()
5293 displayer.close()
5291
5294
5292 @command('unbundle',
5295 @command('unbundle',
5293 [('u', 'update', None,
5296 [('u', 'update', None,
5294 _('update to new branch head if changesets were unbundled'))],
5297 _('update to new branch head if changesets were unbundled'))],
5295 _('[-u] FILE...'))
5298 _('[-u] FILE...'))
5296 def unbundle(ui, repo, fname1, *fnames, **opts):
5299 def unbundle(ui, repo, fname1, *fnames, **opts):
5297 """apply one or more bundle files
5300 """apply one or more bundle files
5298
5301
5299 Apply one or more bundle files generated by :hg:`bundle`.
5302 Apply one or more bundle files generated by :hg:`bundle`.
5300
5303
5301 Returns 0 on success, 1 if an update has unresolved files.
5304 Returns 0 on success, 1 if an update has unresolved files.
5302 """
5305 """
5303 fnames = (fname1,) + fnames
5306 fnames = (fname1,) + fnames
5304
5307
5305 with repo.lock():
5308 with repo.lock():
5306 for fname in fnames:
5309 for fname in fnames:
5307 f = hg.openpath(ui, fname)
5310 f = hg.openpath(ui, fname)
5308 gen = exchange.readbundle(ui, f, fname)
5311 gen = exchange.readbundle(ui, f, fname)
5309 if isinstance(gen, bundle2.unbundle20):
5312 if isinstance(gen, bundle2.unbundle20):
5310 tr = repo.transaction('unbundle')
5313 tr = repo.transaction('unbundle')
5311 try:
5314 try:
5312 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5315 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5313 url='bundle:' + fname)
5316 url='bundle:' + fname)
5314 tr.close()
5317 tr.close()
5315 except error.BundleUnknownFeatureError as exc:
5318 except error.BundleUnknownFeatureError as exc:
5316 raise error.Abort(_('%s: unknown bundle feature, %s')
5319 raise error.Abort(_('%s: unknown bundle feature, %s')
5317 % (fname, exc),
5320 % (fname, exc),
5318 hint=_("see https://mercurial-scm.org/"
5321 hint=_("see https://mercurial-scm.org/"
5319 "wiki/BundleFeature for more "
5322 "wiki/BundleFeature for more "
5320 "information"))
5323 "information"))
5321 finally:
5324 finally:
5322 if tr:
5325 if tr:
5323 tr.release()
5326 tr.release()
5324 changes = [r.get('return', 0)
5327 changes = [r.get('return', 0)
5325 for r in op.records['changegroup']]
5328 for r in op.records['changegroup']]
5326 modheads = changegroup.combineresults(changes)
5329 modheads = changegroup.combineresults(changes)
5327 elif isinstance(gen, streamclone.streamcloneapplier):
5330 elif isinstance(gen, streamclone.streamcloneapplier):
5328 raise error.Abort(
5331 raise error.Abort(
5329 _('packed bundles cannot be applied with '
5332 _('packed bundles cannot be applied with '
5330 '"hg unbundle"'),
5333 '"hg unbundle"'),
5331 hint=_('use "hg debugapplystreamclonebundle"'))
5334 hint=_('use "hg debugapplystreamclonebundle"'))
5332 else:
5335 else:
5333 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5336 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5334
5337
5335 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5338 return postincoming(ui, repo, modheads, opts.get(r'update'), None, None)
5336
5339
5337 @command('^update|up|checkout|co',
5340 @command('^update|up|checkout|co',
5338 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5341 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5339 ('c', 'check', None, _('require clean working directory')),
5342 ('c', 'check', None, _('require clean working directory')),
5340 ('m', 'merge', None, _('merge uncommitted changes')),
5343 ('m', 'merge', None, _('merge uncommitted changes')),
5341 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5344 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5342 ('r', 'rev', '', _('revision'), _('REV'))
5345 ('r', 'rev', '', _('revision'), _('REV'))
5343 ] + mergetoolopts,
5346 ] + mergetoolopts,
5344 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5347 _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
5345 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5348 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5346 merge=None, tool=None):
5349 merge=None, tool=None):
5347 """update working directory (or switch revisions)
5350 """update working directory (or switch revisions)
5348
5351
5349 Update the repository's working directory to the specified
5352 Update the repository's working directory to the specified
5350 changeset. If no changeset is specified, update to the tip of the
5353 changeset. If no changeset is specified, update to the tip of the
5351 current named branch and move the active bookmark (see :hg:`help
5354 current named branch and move the active bookmark (see :hg:`help
5352 bookmarks`).
5355 bookmarks`).
5353
5356
5354 Update sets the working directory's parent revision to the specified
5357 Update sets the working directory's parent revision to the specified
5355 changeset (see :hg:`help parents`).
5358 changeset (see :hg:`help parents`).
5356
5359
5357 If the changeset is not a descendant or ancestor of the working
5360 If the changeset is not a descendant or ancestor of the working
5358 directory's parent and there are uncommitted changes, the update is
5361 directory's parent and there are uncommitted changes, the update is
5359 aborted. With the -c/--check option, the working directory is checked
5362 aborted. With the -c/--check option, the working directory is checked
5360 for uncommitted changes; if none are found, the working directory is
5363 for uncommitted changes; if none are found, the working directory is
5361 updated to the specified changeset.
5364 updated to the specified changeset.
5362
5365
5363 .. container:: verbose
5366 .. container:: verbose
5364
5367
5365 The -C/--clean, -c/--check, and -m/--merge options control what
5368 The -C/--clean, -c/--check, and -m/--merge options control what
5366 happens if the working directory contains uncommitted changes.
5369 happens if the working directory contains uncommitted changes.
5367 At most of one of them can be specified.
5370 At most of one of them can be specified.
5368
5371
5369 1. If no option is specified, and if
5372 1. If no option is specified, and if
5370 the requested changeset is an ancestor or descendant of
5373 the requested changeset is an ancestor or descendant of
5371 the working directory's parent, the uncommitted changes
5374 the working directory's parent, the uncommitted changes
5372 are merged into the requested changeset and the merged
5375 are merged into the requested changeset and the merged
5373 result is left uncommitted. If the requested changeset is
5376 result is left uncommitted. If the requested changeset is
5374 not an ancestor or descendant (that is, it is on another
5377 not an ancestor or descendant (that is, it is on another
5375 branch), the update is aborted and the uncommitted changes
5378 branch), the update is aborted and the uncommitted changes
5376 are preserved.
5379 are preserved.
5377
5380
5378 2. With the -m/--merge option, the update is allowed even if the
5381 2. With the -m/--merge option, the update is allowed even if the
5379 requested changeset is not an ancestor or descendant of
5382 requested changeset is not an ancestor or descendant of
5380 the working directory's parent.
5383 the working directory's parent.
5381
5384
5382 3. With the -c/--check option, the update is aborted and the
5385 3. With the -c/--check option, the update is aborted and the
5383 uncommitted changes are preserved.
5386 uncommitted changes are preserved.
5384
5387
5385 4. With the -C/--clean option, uncommitted changes are discarded and
5388 4. With the -C/--clean option, uncommitted changes are discarded and
5386 the working directory is updated to the requested changeset.
5389 the working directory is updated to the requested changeset.
5387
5390
5388 To cancel an uncommitted merge (and lose your changes), use
5391 To cancel an uncommitted merge (and lose your changes), use
5389 :hg:`update --clean .`.
5392 :hg:`update --clean .`.
5390
5393
5391 Use null as the changeset to remove the working directory (like
5394 Use null as the changeset to remove the working directory (like
5392 :hg:`clone -U`).
5395 :hg:`clone -U`).
5393
5396
5394 If you want to revert just one file to an older revision, use
5397 If you want to revert just one file to an older revision, use
5395 :hg:`revert [-r REV] NAME`.
5398 :hg:`revert [-r REV] NAME`.
5396
5399
5397 See :hg:`help dates` for a list of formats valid for -d/--date.
5400 See :hg:`help dates` for a list of formats valid for -d/--date.
5398
5401
5399 Returns 0 on success, 1 if there are unresolved files.
5402 Returns 0 on success, 1 if there are unresolved files.
5400 """
5403 """
5401 if rev and node:
5404 if rev and node:
5402 raise error.Abort(_("please specify just one revision"))
5405 raise error.Abort(_("please specify just one revision"))
5403
5406
5404 if ui.configbool('commands', 'update.requiredest'):
5407 if ui.configbool('commands', 'update.requiredest'):
5405 if not node and not rev and not date:
5408 if not node and not rev and not date:
5406 raise error.Abort(_('you must specify a destination'),
5409 raise error.Abort(_('you must specify a destination'),
5407 hint=_('for example: hg update ".::"'))
5410 hint=_('for example: hg update ".::"'))
5408
5411
5409 if rev is None or rev == '':
5412 if rev is None or rev == '':
5410 rev = node
5413 rev = node
5411
5414
5412 if date and rev is not None:
5415 if date and rev is not None:
5413 raise error.Abort(_("you can't specify a revision and a date"))
5416 raise error.Abort(_("you can't specify a revision and a date"))
5414
5417
5415 if len([x for x in (clean, check, merge) if x]) > 1:
5418 if len([x for x in (clean, check, merge) if x]) > 1:
5416 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5419 raise error.Abort(_("can only specify one of -C/--clean, -c/--check, "
5417 "or -m/merge"))
5420 "or -m/merge"))
5418
5421
5419 updatecheck = None
5422 updatecheck = None
5420 if check:
5423 if check:
5421 updatecheck = 'abort'
5424 updatecheck = 'abort'
5422 elif merge:
5425 elif merge:
5423 updatecheck = 'none'
5426 updatecheck = 'none'
5424
5427
5425 with repo.wlock():
5428 with repo.wlock():
5426 cmdutil.clearunfinished(repo)
5429 cmdutil.clearunfinished(repo)
5427
5430
5428 if date:
5431 if date:
5429 rev = cmdutil.finddate(ui, repo, date)
5432 rev = cmdutil.finddate(ui, repo, date)
5430
5433
5431 # if we defined a bookmark, we have to remember the original name
5434 # if we defined a bookmark, we have to remember the original name
5432 brev = rev
5435 brev = rev
5433 rev = scmutil.revsingle(repo, rev, rev).rev()
5436 rev = scmutil.revsingle(repo, rev, rev).rev()
5434
5437
5435 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5438 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5436
5439
5437 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5440 return hg.updatetotally(ui, repo, rev, brev, clean=clean,
5438 updatecheck=updatecheck)
5441 updatecheck=updatecheck)
5439
5442
5440 @command('verify', [])
5443 @command('verify', [])
5441 def verify(ui, repo):
5444 def verify(ui, repo):
5442 """verify the integrity of the repository
5445 """verify the integrity of the repository
5443
5446
5444 Verify the integrity of the current repository.
5447 Verify the integrity of the current repository.
5445
5448
5446 This will perform an extensive check of the repository's
5449 This will perform an extensive check of the repository's
5447 integrity, validating the hashes and checksums of each entry in
5450 integrity, validating the hashes and checksums of each entry in
5448 the changelog, manifest, and tracked files, as well as the
5451 the changelog, manifest, and tracked files, as well as the
5449 integrity of their crosslinks and indices.
5452 integrity of their crosslinks and indices.
5450
5453
5451 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5454 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5452 for more information about recovery from corruption of the
5455 for more information about recovery from corruption of the
5453 repository.
5456 repository.
5454
5457
5455 Returns 0 on success, 1 if errors are encountered.
5458 Returns 0 on success, 1 if errors are encountered.
5456 """
5459 """
5457 return hg.verify(repo)
5460 return hg.verify(repo)
5458
5461
5459 @command('version', [] + formatteropts, norepo=True)
5462 @command('version', [] + formatteropts, norepo=True)
5460 def version_(ui, **opts):
5463 def version_(ui, **opts):
5461 """output version and copyright information"""
5464 """output version and copyright information"""
5462 opts = pycompat.byteskwargs(opts)
5465 opts = pycompat.byteskwargs(opts)
5463 if ui.verbose:
5466 if ui.verbose:
5464 ui.pager('version')
5467 ui.pager('version')
5465 fm = ui.formatter("version", opts)
5468 fm = ui.formatter("version", opts)
5466 fm.startitem()
5469 fm.startitem()
5467 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5470 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5468 util.version())
5471 util.version())
5469 license = _(
5472 license = _(
5470 "(see https://mercurial-scm.org for more information)\n"
5473 "(see https://mercurial-scm.org for more information)\n"
5471 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5474 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5472 "This is free software; see the source for copying conditions. "
5475 "This is free software; see the source for copying conditions. "
5473 "There is NO\nwarranty; "
5476 "There is NO\nwarranty; "
5474 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5477 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5475 )
5478 )
5476 if not ui.quiet:
5479 if not ui.quiet:
5477 fm.plain(license)
5480 fm.plain(license)
5478
5481
5479 if ui.verbose:
5482 if ui.verbose:
5480 fm.plain(_("\nEnabled extensions:\n\n"))
5483 fm.plain(_("\nEnabled extensions:\n\n"))
5481 # format names and versions into columns
5484 # format names and versions into columns
5482 names = []
5485 names = []
5483 vers = []
5486 vers = []
5484 isinternals = []
5487 isinternals = []
5485 for name, module in extensions.extensions():
5488 for name, module in extensions.extensions():
5486 names.append(name)
5489 names.append(name)
5487 vers.append(extensions.moduleversion(module) or None)
5490 vers.append(extensions.moduleversion(module) or None)
5488 isinternals.append(extensions.ismoduleinternal(module))
5491 isinternals.append(extensions.ismoduleinternal(module))
5489 fn = fm.nested("extensions")
5492 fn = fm.nested("extensions")
5490 if names:
5493 if names:
5491 namefmt = " %%-%ds " % max(len(n) for n in names)
5494 namefmt = " %%-%ds " % max(len(n) for n in names)
5492 places = [_("external"), _("internal")]
5495 places = [_("external"), _("internal")]
5493 for n, v, p in zip(names, vers, isinternals):
5496 for n, v, p in zip(names, vers, isinternals):
5494 fn.startitem()
5497 fn.startitem()
5495 fn.condwrite(ui.verbose, "name", namefmt, n)
5498 fn.condwrite(ui.verbose, "name", namefmt, n)
5496 if ui.verbose:
5499 if ui.verbose:
5497 fn.plain("%s " % places[p])
5500 fn.plain("%s " % places[p])
5498 fn.data(bundled=p)
5501 fn.data(bundled=p)
5499 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5502 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5500 if ui.verbose:
5503 if ui.verbose:
5501 fn.plain("\n")
5504 fn.plain("\n")
5502 fn.end()
5505 fn.end()
5503 fm.end()
5506 fm.end()
5504
5507
5505 def loadcmdtable(ui, name, cmdtable):
5508 def loadcmdtable(ui, name, cmdtable):
5506 """Load command functions from specified cmdtable
5509 """Load command functions from specified cmdtable
5507 """
5510 """
5508 overrides = [cmd for cmd in cmdtable if cmd in table]
5511 overrides = [cmd for cmd in cmdtable if cmd in table]
5509 if overrides:
5512 if overrides:
5510 ui.warn(_("extension '%s' overrides commands: %s\n")
5513 ui.warn(_("extension '%s' overrides commands: %s\n")
5511 % (name, " ".join(overrides)))
5514 % (name, " ".join(overrides)))
5512 table.update(cmdtable)
5515 table.update(cmdtable)
General Comments 0
You need to be logged in to leave comments. Login now