##// END OF EJS Templates
outgoing: avoid running pager until we're actually showing changes...
Augie Fackler -
r31058:d2ed0abc default
parent child Browse files
Show More
@@ -1,5465 +1,5464 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 minirst,
42 minirst,
43 obsolete,
43 obsolete,
44 patch,
44 patch,
45 phases,
45 phases,
46 pycompat,
46 pycompat,
47 revsetlang,
47 revsetlang,
48 scmutil,
48 scmutil,
49 server,
49 server,
50 sshserver,
50 sshserver,
51 streamclone,
51 streamclone,
52 templatekw,
52 templatekw,
53 ui as uimod,
53 ui as uimod,
54 util,
54 util,
55 )
55 )
56
56
57 release = lockmod.release
57 release = lockmod.release
58
58
59 table = {}
59 table = {}
60
60
61 command = cmdutil.command(table)
61 command = cmdutil.command(table)
62
62
63 # label constants
63 # label constants
64 # until 3.5, bookmarks.current was the advertised name, not
64 # until 3.5, bookmarks.current was the advertised name, not
65 # bookmarks.active, so we must use both to avoid breaking old
65 # bookmarks.active, so we must use both to avoid breaking old
66 # custom styles
66 # custom styles
67 activebookmarklabel = 'bookmarks.active bookmarks.current'
67 activebookmarklabel = 'bookmarks.active bookmarks.current'
68
68
69 # common command options
69 # common command options
70
70
71 globalopts = [
71 globalopts = [
72 ('R', 'repository', '',
72 ('R', 'repository', '',
73 _('repository root directory or name of overlay bundle file'),
73 _('repository root directory or name of overlay bundle file'),
74 _('REPO')),
74 _('REPO')),
75 ('', 'cwd', '',
75 ('', 'cwd', '',
76 _('change working directory'), _('DIR')),
76 _('change working directory'), _('DIR')),
77 ('y', 'noninteractive', None,
77 ('y', 'noninteractive', None,
78 _('do not prompt, automatically pick the first choice for all prompts')),
78 _('do not prompt, automatically pick the first choice for all prompts')),
79 ('q', 'quiet', None, _('suppress output')),
79 ('q', 'quiet', None, _('suppress output')),
80 ('v', 'verbose', None, _('enable additional output')),
80 ('v', 'verbose', None, _('enable additional output')),
81 ('', 'config', [],
81 ('', 'config', [],
82 _('set/override config option (use \'section.name=value\')'),
82 _('set/override config option (use \'section.name=value\')'),
83 _('CONFIG')),
83 _('CONFIG')),
84 ('', 'debug', None, _('enable debugging output')),
84 ('', 'debug', None, _('enable debugging output')),
85 ('', 'debugger', None, _('start debugger')),
85 ('', 'debugger', None, _('start debugger')),
86 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
86 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
87 _('ENCODE')),
87 _('ENCODE')),
88 ('', 'encodingmode', encoding.encodingmode,
88 ('', 'encodingmode', encoding.encodingmode,
89 _('set the charset encoding mode'), _('MODE')),
89 _('set the charset encoding mode'), _('MODE')),
90 ('', 'traceback', None, _('always print a traceback on exception')),
90 ('', 'traceback', None, _('always print a traceback on exception')),
91 ('', 'time', None, _('time how long the command takes')),
91 ('', 'time', None, _('time how long the command takes')),
92 ('', 'profile', None, _('print command execution profile')),
92 ('', 'profile', None, _('print command execution profile')),
93 ('', 'version', None, _('output version information and exit')),
93 ('', 'version', None, _('output version information and exit')),
94 ('h', 'help', None, _('display help and exit')),
94 ('h', 'help', None, _('display help and exit')),
95 ('', 'hidden', False, _('consider hidden changesets')),
95 ('', 'hidden', False, _('consider hidden changesets')),
96 ('', 'pager', 'auto',
96 ('', 'pager', 'auto',
97 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
97 _("when to paginate (boolean, always, auto, or never)"), _('TYPE')),
98 ]
98 ]
99
99
100 dryrunopts = [('n', 'dry-run', None,
100 dryrunopts = [('n', 'dry-run', None,
101 _('do not perform actions, just print output'))]
101 _('do not perform actions, just print output'))]
102
102
103 remoteopts = [
103 remoteopts = [
104 ('e', 'ssh', '',
104 ('e', 'ssh', '',
105 _('specify ssh command to use'), _('CMD')),
105 _('specify ssh command to use'), _('CMD')),
106 ('', 'remotecmd', '',
106 ('', 'remotecmd', '',
107 _('specify hg command to run on the remote side'), _('CMD')),
107 _('specify hg command to run on the remote side'), _('CMD')),
108 ('', 'insecure', None,
108 ('', 'insecure', None,
109 _('do not verify server certificate (ignoring web.cacerts config)')),
109 _('do not verify server certificate (ignoring web.cacerts config)')),
110 ]
110 ]
111
111
112 walkopts = [
112 walkopts = [
113 ('I', 'include', [],
113 ('I', 'include', [],
114 _('include names matching the given patterns'), _('PATTERN')),
114 _('include names matching the given patterns'), _('PATTERN')),
115 ('X', 'exclude', [],
115 ('X', 'exclude', [],
116 _('exclude names matching the given patterns'), _('PATTERN')),
116 _('exclude names matching the given patterns'), _('PATTERN')),
117 ]
117 ]
118
118
119 commitopts = [
119 commitopts = [
120 ('m', 'message', '',
120 ('m', 'message', '',
121 _('use text as commit message'), _('TEXT')),
121 _('use text as commit message'), _('TEXT')),
122 ('l', 'logfile', '',
122 ('l', 'logfile', '',
123 _('read commit message from file'), _('FILE')),
123 _('read commit message from file'), _('FILE')),
124 ]
124 ]
125
125
126 commitopts2 = [
126 commitopts2 = [
127 ('d', 'date', '',
127 ('d', 'date', '',
128 _('record the specified date as commit date'), _('DATE')),
128 _('record the specified date as commit date'), _('DATE')),
129 ('u', 'user', '',
129 ('u', 'user', '',
130 _('record the specified user as committer'), _('USER')),
130 _('record the specified user as committer'), _('USER')),
131 ]
131 ]
132
132
133 # hidden for now
133 # hidden for now
134 formatteropts = [
134 formatteropts = [
135 ('T', 'template', '',
135 ('T', 'template', '',
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
136 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
137 ]
137 ]
138
138
139 templateopts = [
139 templateopts = [
140 ('', 'style', '',
140 ('', 'style', '',
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
141 _('display using template map file (DEPRECATED)'), _('STYLE')),
142 ('T', 'template', '',
142 ('T', 'template', '',
143 _('display with template'), _('TEMPLATE')),
143 _('display with template'), _('TEMPLATE')),
144 ]
144 ]
145
145
146 logopts = [
146 logopts = [
147 ('p', 'patch', None, _('show patch')),
147 ('p', 'patch', None, _('show patch')),
148 ('g', 'git', None, _('use git extended diff format')),
148 ('g', 'git', None, _('use git extended diff format')),
149 ('l', 'limit', '',
149 ('l', 'limit', '',
150 _('limit number of changes displayed'), _('NUM')),
150 _('limit number of changes displayed'), _('NUM')),
151 ('M', 'no-merges', None, _('do not show merges')),
151 ('M', 'no-merges', None, _('do not show merges')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
152 ('', 'stat', None, _('output diffstat-style summary of changes')),
153 ('G', 'graph', None, _("show the revision DAG")),
153 ('G', 'graph', None, _("show the revision DAG")),
154 ] + templateopts
154 ] + templateopts
155
155
156 diffopts = [
156 diffopts = [
157 ('a', 'text', None, _('treat all files as text')),
157 ('a', 'text', None, _('treat all files as text')),
158 ('g', 'git', None, _('use git extended diff format')),
158 ('g', 'git', None, _('use git extended diff format')),
159 ('', 'nodates', None, _('omit dates from diff headers'))
159 ('', 'nodates', None, _('omit dates from diff headers'))
160 ]
160 ]
161
161
162 diffwsopts = [
162 diffwsopts = [
163 ('w', 'ignore-all-space', None,
163 ('w', 'ignore-all-space', None,
164 _('ignore white space when comparing lines')),
164 _('ignore white space when comparing lines')),
165 ('b', 'ignore-space-change', None,
165 ('b', 'ignore-space-change', None,
166 _('ignore changes in the amount of white space')),
166 _('ignore changes in the amount of white space')),
167 ('B', 'ignore-blank-lines', None,
167 ('B', 'ignore-blank-lines', None,
168 _('ignore changes whose lines are all blank')),
168 _('ignore changes whose lines are all blank')),
169 ]
169 ]
170
170
171 diffopts2 = [
171 diffopts2 = [
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
172 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
173 ('p', 'show-function', None, _('show which function each change is in')),
173 ('p', 'show-function', None, _('show which function each change is in')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
174 ('', 'reverse', None, _('produce a diff that undoes the changes')),
175 ] + diffwsopts + [
175 ] + diffwsopts + [
176 ('U', 'unified', '',
176 ('U', 'unified', '',
177 _('number of lines of context to show'), _('NUM')),
177 _('number of lines of context to show'), _('NUM')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
178 ('', 'stat', None, _('output diffstat-style summary of changes')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
179 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
180 ]
180 ]
181
181
182 mergetoolopts = [
182 mergetoolopts = [
183 ('t', 'tool', '', _('specify merge tool')),
183 ('t', 'tool', '', _('specify merge tool')),
184 ]
184 ]
185
185
186 similarityopts = [
186 similarityopts = [
187 ('s', 'similarity', '',
187 ('s', 'similarity', '',
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
188 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
189 ]
189 ]
190
190
191 subrepoopts = [
191 subrepoopts = [
192 ('S', 'subrepos', None,
192 ('S', 'subrepos', None,
193 _('recurse into subrepositories'))
193 _('recurse into subrepositories'))
194 ]
194 ]
195
195
196 debugrevlogopts = [
196 debugrevlogopts = [
197 ('c', 'changelog', False, _('open changelog')),
197 ('c', 'changelog', False, _('open changelog')),
198 ('m', 'manifest', False, _('open manifest')),
198 ('m', 'manifest', False, _('open manifest')),
199 ('', 'dir', '', _('open directory manifest')),
199 ('', 'dir', '', _('open directory manifest')),
200 ]
200 ]
201
201
202 # Commands start here, listed alphabetically
202 # Commands start here, listed alphabetically
203
203
204 @command('^add',
204 @command('^add',
205 walkopts + subrepoopts + dryrunopts,
205 walkopts + subrepoopts + dryrunopts,
206 _('[OPTION]... [FILE]...'),
206 _('[OPTION]... [FILE]...'),
207 inferrepo=True)
207 inferrepo=True)
208 def add(ui, repo, *pats, **opts):
208 def add(ui, repo, *pats, **opts):
209 """add the specified files on the next commit
209 """add the specified files on the next commit
210
210
211 Schedule files to be version controlled and added to the
211 Schedule files to be version controlled and added to the
212 repository.
212 repository.
213
213
214 The files will be added to the repository at the next commit. To
214 The files will be added to the repository at the next commit. To
215 undo an add before that, see :hg:`forget`.
215 undo an add before that, see :hg:`forget`.
216
216
217 If no names are given, add all files to the repository (except
217 If no names are given, add all files to the repository (except
218 files matching ``.hgignore``).
218 files matching ``.hgignore``).
219
219
220 .. container:: verbose
220 .. container:: verbose
221
221
222 Examples:
222 Examples:
223
223
224 - New (unknown) files are added
224 - New (unknown) files are added
225 automatically by :hg:`add`::
225 automatically by :hg:`add`::
226
226
227 $ ls
227 $ ls
228 foo.c
228 foo.c
229 $ hg status
229 $ hg status
230 ? foo.c
230 ? foo.c
231 $ hg add
231 $ hg add
232 adding foo.c
232 adding foo.c
233 $ hg status
233 $ hg status
234 A foo.c
234 A foo.c
235
235
236 - Specific files to be added can be specified::
236 - Specific files to be added can be specified::
237
237
238 $ ls
238 $ ls
239 bar.c foo.c
239 bar.c foo.c
240 $ hg status
240 $ hg status
241 ? bar.c
241 ? bar.c
242 ? foo.c
242 ? foo.c
243 $ hg add bar.c
243 $ hg add bar.c
244 $ hg status
244 $ hg status
245 A bar.c
245 A bar.c
246 ? foo.c
246 ? foo.c
247
247
248 Returns 0 if all files are successfully added.
248 Returns 0 if all files are successfully added.
249 """
249 """
250
250
251 m = scmutil.match(repo[None], pats, opts)
251 m = scmutil.match(repo[None], pats, opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
252 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
253 return rejected and 1 or 0
253 return rejected and 1 or 0
254
254
255 @command('addremove',
255 @command('addremove',
256 similarityopts + subrepoopts + walkopts + dryrunopts,
256 similarityopts + subrepoopts + walkopts + dryrunopts,
257 _('[OPTION]... [FILE]...'),
257 _('[OPTION]... [FILE]...'),
258 inferrepo=True)
258 inferrepo=True)
259 def addremove(ui, repo, *pats, **opts):
259 def addremove(ui, repo, *pats, **opts):
260 """add all new files, delete all missing files
260 """add all new files, delete all missing files
261
261
262 Add all new files and remove all missing files from the
262 Add all new files and remove all missing files from the
263 repository.
263 repository.
264
264
265 Unless names are given, new files are ignored if they match any of
265 Unless names are given, new files are ignored if they match any of
266 the patterns in ``.hgignore``. As with add, these changes take
266 the patterns in ``.hgignore``. As with add, these changes take
267 effect at the next commit.
267 effect at the next commit.
268
268
269 Use the -s/--similarity option to detect renamed files. This
269 Use the -s/--similarity option to detect renamed files. This
270 option takes a percentage between 0 (disabled) and 100 (files must
270 option takes a percentage between 0 (disabled) and 100 (files must
271 be identical) as its parameter. With a parameter greater than 0,
271 be identical) as its parameter. With a parameter greater than 0,
272 this compares every removed file with every added file and records
272 this compares every removed file with every added file and records
273 those similar enough as renames. Detecting renamed files this way
273 those similar enough as renames. Detecting renamed files this way
274 can be expensive. After using this option, :hg:`status -C` can be
274 can be expensive. After using this option, :hg:`status -C` can be
275 used to check which files were identified as moved or renamed. If
275 used to check which files were identified as moved or renamed. If
276 not specified, -s/--similarity defaults to 100 and only renames of
276 not specified, -s/--similarity defaults to 100 and only renames of
277 identical files are detected.
277 identical files are detected.
278
278
279 .. container:: verbose
279 .. container:: verbose
280
280
281 Examples:
281 Examples:
282
282
283 - A number of files (bar.c and foo.c) are new,
283 - A number of files (bar.c and foo.c) are new,
284 while foobar.c has been removed (without using :hg:`remove`)
284 while foobar.c has been removed (without using :hg:`remove`)
285 from the repository::
285 from the repository::
286
286
287 $ ls
287 $ ls
288 bar.c foo.c
288 bar.c foo.c
289 $ hg status
289 $ hg status
290 ! foobar.c
290 ! foobar.c
291 ? bar.c
291 ? bar.c
292 ? foo.c
292 ? foo.c
293 $ hg addremove
293 $ hg addremove
294 adding bar.c
294 adding bar.c
295 adding foo.c
295 adding foo.c
296 removing foobar.c
296 removing foobar.c
297 $ hg status
297 $ hg status
298 A bar.c
298 A bar.c
299 A foo.c
299 A foo.c
300 R foobar.c
300 R foobar.c
301
301
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
302 - A file foobar.c was moved to foo.c without using :hg:`rename`.
303 Afterwards, it was edited slightly::
303 Afterwards, it was edited slightly::
304
304
305 $ ls
305 $ ls
306 foo.c
306 foo.c
307 $ hg status
307 $ hg status
308 ! foobar.c
308 ! foobar.c
309 ? foo.c
309 ? foo.c
310 $ hg addremove --similarity 90
310 $ hg addremove --similarity 90
311 removing foobar.c
311 removing foobar.c
312 adding foo.c
312 adding foo.c
313 recording removal of foobar.c as rename to foo.c (94% similar)
313 recording removal of foobar.c as rename to foo.c (94% similar)
314 $ hg status -C
314 $ hg status -C
315 A foo.c
315 A foo.c
316 foobar.c
316 foobar.c
317 R foobar.c
317 R foobar.c
318
318
319 Returns 0 if all files are successfully added.
319 Returns 0 if all files are successfully added.
320 """
320 """
321 try:
321 try:
322 sim = float(opts.get('similarity') or 100)
322 sim = float(opts.get('similarity') or 100)
323 except ValueError:
323 except ValueError:
324 raise error.Abort(_('similarity must be a number'))
324 raise error.Abort(_('similarity must be a number'))
325 if sim < 0 or sim > 100:
325 if sim < 0 or sim > 100:
326 raise error.Abort(_('similarity must be between 0 and 100'))
326 raise error.Abort(_('similarity must be between 0 and 100'))
327 matcher = scmutil.match(repo[None], pats, opts)
327 matcher = scmutil.match(repo[None], pats, opts)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
328 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
329
329
330 @command('^annotate|blame',
330 @command('^annotate|blame',
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
331 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
332 ('', 'follow', None,
332 ('', 'follow', None,
333 _('follow copies/renames and list the filename (DEPRECATED)')),
333 _('follow copies/renames and list the filename (DEPRECATED)')),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
334 ('', 'no-follow', None, _("don't follow copies and renames")),
335 ('a', 'text', None, _('treat all files as text')),
335 ('a', 'text', None, _('treat all files as text')),
336 ('u', 'user', None, _('list the author (long with -v)')),
336 ('u', 'user', None, _('list the author (long with -v)')),
337 ('f', 'file', None, _('list the filename')),
337 ('f', 'file', None, _('list the filename')),
338 ('d', 'date', None, _('list the date (short with -q)')),
338 ('d', 'date', None, _('list the date (short with -q)')),
339 ('n', 'number', None, _('list the revision number (default)')),
339 ('n', 'number', None, _('list the revision number (default)')),
340 ('c', 'changeset', None, _('list the changeset')),
340 ('c', 'changeset', None, _('list the changeset')),
341 ('l', 'line-number', None, _('show line number at the first appearance'))
341 ('l', 'line-number', None, _('show line number at the first appearance'))
342 ] + diffwsopts + walkopts + formatteropts,
342 ] + diffwsopts + walkopts + formatteropts,
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
343 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
344 inferrepo=True)
344 inferrepo=True)
345 def annotate(ui, repo, *pats, **opts):
345 def annotate(ui, repo, *pats, **opts):
346 """show changeset information by line for each file
346 """show changeset information by line for each file
347
347
348 List changes in files, showing the revision id responsible for
348 List changes in files, showing the revision id responsible for
349 each line.
349 each line.
350
350
351 This command is useful for discovering when a change was made and
351 This command is useful for discovering when a change was made and
352 by whom.
352 by whom.
353
353
354 If you include --file, --user, or --date, the revision number is
354 If you include --file, --user, or --date, the revision number is
355 suppressed unless you also include --number.
355 suppressed unless you also include --number.
356
356
357 Without the -a/--text option, annotate will avoid processing files
357 Without the -a/--text option, annotate will avoid processing files
358 it detects as binary. With -a, annotate will annotate the file
358 it detects as binary. With -a, annotate will annotate the file
359 anyway, although the results will probably be neither useful
359 anyway, although the results will probably be neither useful
360 nor desirable.
360 nor desirable.
361
361
362 Returns 0 on success.
362 Returns 0 on success.
363 """
363 """
364 if not pats:
364 if not pats:
365 raise error.Abort(_('at least one filename or pattern is required'))
365 raise error.Abort(_('at least one filename or pattern is required'))
366
366
367 if opts.get('follow'):
367 if opts.get('follow'):
368 # --follow is deprecated and now just an alias for -f/--file
368 # --follow is deprecated and now just an alias for -f/--file
369 # to mimic the behavior of Mercurial before version 1.5
369 # to mimic the behavior of Mercurial before version 1.5
370 opts['file'] = True
370 opts['file'] = True
371
371
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
372 ctx = scmutil.revsingle(repo, opts.get('rev'))
373
373
374 fm = ui.formatter('annotate', opts)
374 fm = ui.formatter('annotate', opts)
375 if ui.quiet:
375 if ui.quiet:
376 datefunc = util.shortdate
376 datefunc = util.shortdate
377 else:
377 else:
378 datefunc = util.datestr
378 datefunc = util.datestr
379 if ctx.rev() is None:
379 if ctx.rev() is None:
380 def hexfn(node):
380 def hexfn(node):
381 if node is None:
381 if node is None:
382 return None
382 return None
383 else:
383 else:
384 return fm.hexfunc(node)
384 return fm.hexfunc(node)
385 if opts.get('changeset'):
385 if opts.get('changeset'):
386 # omit "+" suffix which is appended to node hex
386 # omit "+" suffix which is appended to node hex
387 def formatrev(rev):
387 def formatrev(rev):
388 if rev is None:
388 if rev is None:
389 return '%d' % ctx.p1().rev()
389 return '%d' % ctx.p1().rev()
390 else:
390 else:
391 return '%d' % rev
391 return '%d' % rev
392 else:
392 else:
393 def formatrev(rev):
393 def formatrev(rev):
394 if rev is None:
394 if rev is None:
395 return '%d+' % ctx.p1().rev()
395 return '%d+' % ctx.p1().rev()
396 else:
396 else:
397 return '%d ' % rev
397 return '%d ' % rev
398 def formathex(hex):
398 def formathex(hex):
399 if hex is None:
399 if hex is None:
400 return '%s+' % fm.hexfunc(ctx.p1().node())
400 return '%s+' % fm.hexfunc(ctx.p1().node())
401 else:
401 else:
402 return '%s ' % hex
402 return '%s ' % hex
403 else:
403 else:
404 hexfn = fm.hexfunc
404 hexfn = fm.hexfunc
405 formatrev = formathex = str
405 formatrev = formathex = str
406
406
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
407 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
408 ('number', ' ', lambda x: x[0].rev(), formatrev),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
409 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
410 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
411 ('file', ' ', lambda x: x[0].path(), str),
411 ('file', ' ', lambda x: x[0].path(), str),
412 ('line_number', ':', lambda x: x[1], str),
412 ('line_number', ':', lambda x: x[1], str),
413 ]
413 ]
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
414 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
415
415
416 if (not opts.get('user') and not opts.get('changeset')
416 if (not opts.get('user') and not opts.get('changeset')
417 and not opts.get('date') and not opts.get('file')):
417 and not opts.get('date') and not opts.get('file')):
418 opts['number'] = True
418 opts['number'] = True
419
419
420 linenumber = opts.get('line_number') is not None
420 linenumber = opts.get('line_number') is not None
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
421 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
422 raise error.Abort(_('at least one of -n/-c is required for -l'))
423
423
424 ui.pager('annotate')
424 ui.pager('annotate')
425
425
426 if fm.isplain():
426 if fm.isplain():
427 def makefunc(get, fmt):
427 def makefunc(get, fmt):
428 return lambda x: fmt(get(x))
428 return lambda x: fmt(get(x))
429 else:
429 else:
430 def makefunc(get, fmt):
430 def makefunc(get, fmt):
431 return get
431 return get
432 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
432 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
433 if opts.get(op)]
433 if opts.get(op)]
434 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
434 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
435 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
435 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
436 if opts.get(op))
436 if opts.get(op))
437
437
438 def bad(x, y):
438 def bad(x, y):
439 raise error.Abort("%s: %s" % (x, y))
439 raise error.Abort("%s: %s" % (x, y))
440
440
441 m = scmutil.match(ctx, pats, opts, badfn=bad)
441 m = scmutil.match(ctx, pats, opts, badfn=bad)
442
442
443 follow = not opts.get('no_follow')
443 follow = not opts.get('no_follow')
444 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
444 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
445 whitespace=True)
445 whitespace=True)
446 for abs in ctx.walk(m):
446 for abs in ctx.walk(m):
447 fctx = ctx[abs]
447 fctx = ctx[abs]
448 if not opts.get('text') and util.binary(fctx.data()):
448 if not opts.get('text') and util.binary(fctx.data()):
449 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
449 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
450 continue
450 continue
451
451
452 lines = fctx.annotate(follow=follow, linenumber=linenumber,
452 lines = fctx.annotate(follow=follow, linenumber=linenumber,
453 diffopts=diffopts)
453 diffopts=diffopts)
454 if not lines:
454 if not lines:
455 continue
455 continue
456 formats = []
456 formats = []
457 pieces = []
457 pieces = []
458
458
459 for f, sep in funcmap:
459 for f, sep in funcmap:
460 l = [f(n) for n, dummy in lines]
460 l = [f(n) for n, dummy in lines]
461 if fm.isplain():
461 if fm.isplain():
462 sizes = [encoding.colwidth(x) for x in l]
462 sizes = [encoding.colwidth(x) for x in l]
463 ml = max(sizes)
463 ml = max(sizes)
464 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
464 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
465 else:
465 else:
466 formats.append(['%s' for x in l])
466 formats.append(['%s' for x in l])
467 pieces.append(l)
467 pieces.append(l)
468
468
469 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
469 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
470 fm.startitem()
470 fm.startitem()
471 fm.write(fields, "".join(f), *p)
471 fm.write(fields, "".join(f), *p)
472 fm.write('line', ": %s", l[1])
472 fm.write('line', ": %s", l[1])
473
473
474 if not lines[-1][1].endswith('\n'):
474 if not lines[-1][1].endswith('\n'):
475 fm.plain('\n')
475 fm.plain('\n')
476
476
477 fm.end()
477 fm.end()
478
478
479 @command('archive',
479 @command('archive',
480 [('', 'no-decode', None, _('do not pass files through decoders')),
480 [('', 'no-decode', None, _('do not pass files through decoders')),
481 ('p', 'prefix', '', _('directory prefix for files in archive'),
481 ('p', 'prefix', '', _('directory prefix for files in archive'),
482 _('PREFIX')),
482 _('PREFIX')),
483 ('r', 'rev', '', _('revision to distribute'), _('REV')),
483 ('r', 'rev', '', _('revision to distribute'), _('REV')),
484 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
484 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
485 ] + subrepoopts + walkopts,
485 ] + subrepoopts + walkopts,
486 _('[OPTION]... DEST'))
486 _('[OPTION]... DEST'))
487 def archive(ui, repo, dest, **opts):
487 def archive(ui, repo, dest, **opts):
488 '''create an unversioned archive of a repository revision
488 '''create an unversioned archive of a repository revision
489
489
490 By default, the revision used is the parent of the working
490 By default, the revision used is the parent of the working
491 directory; use -r/--rev to specify a different revision.
491 directory; use -r/--rev to specify a different revision.
492
492
493 The archive type is automatically detected based on file
493 The archive type is automatically detected based on file
494 extension (to override, use -t/--type).
494 extension (to override, use -t/--type).
495
495
496 .. container:: verbose
496 .. container:: verbose
497
497
498 Examples:
498 Examples:
499
499
500 - create a zip file containing the 1.0 release::
500 - create a zip file containing the 1.0 release::
501
501
502 hg archive -r 1.0 project-1.0.zip
502 hg archive -r 1.0 project-1.0.zip
503
503
504 - create a tarball excluding .hg files::
504 - create a tarball excluding .hg files::
505
505
506 hg archive project.tar.gz -X ".hg*"
506 hg archive project.tar.gz -X ".hg*"
507
507
508 Valid types are:
508 Valid types are:
509
509
510 :``files``: a directory full of files (default)
510 :``files``: a directory full of files (default)
511 :``tar``: tar archive, uncompressed
511 :``tar``: tar archive, uncompressed
512 :``tbz2``: tar archive, compressed using bzip2
512 :``tbz2``: tar archive, compressed using bzip2
513 :``tgz``: tar archive, compressed using gzip
513 :``tgz``: tar archive, compressed using gzip
514 :``uzip``: zip archive, uncompressed
514 :``uzip``: zip archive, uncompressed
515 :``zip``: zip archive, compressed using deflate
515 :``zip``: zip archive, compressed using deflate
516
516
517 The exact name of the destination archive or directory is given
517 The exact name of the destination archive or directory is given
518 using a format string; see :hg:`help export` for details.
518 using a format string; see :hg:`help export` for details.
519
519
520 Each member added to an archive file has a directory prefix
520 Each member added to an archive file has a directory prefix
521 prepended. Use -p/--prefix to specify a format string for the
521 prepended. Use -p/--prefix to specify a format string for the
522 prefix. The default is the basename of the archive, with suffixes
522 prefix. The default is the basename of the archive, with suffixes
523 removed.
523 removed.
524
524
525 Returns 0 on success.
525 Returns 0 on success.
526 '''
526 '''
527
527
528 ctx = scmutil.revsingle(repo, opts.get('rev'))
528 ctx = scmutil.revsingle(repo, opts.get('rev'))
529 if not ctx:
529 if not ctx:
530 raise error.Abort(_('no working directory: please specify a revision'))
530 raise error.Abort(_('no working directory: please specify a revision'))
531 node = ctx.node()
531 node = ctx.node()
532 dest = cmdutil.makefilename(repo, dest, node)
532 dest = cmdutil.makefilename(repo, dest, node)
533 if os.path.realpath(dest) == repo.root:
533 if os.path.realpath(dest) == repo.root:
534 raise error.Abort(_('repository root cannot be destination'))
534 raise error.Abort(_('repository root cannot be destination'))
535
535
536 kind = opts.get('type') or archival.guesskind(dest) or 'files'
536 kind = opts.get('type') or archival.guesskind(dest) or 'files'
537 prefix = opts.get('prefix')
537 prefix = opts.get('prefix')
538
538
539 if dest == '-':
539 if dest == '-':
540 if kind == 'files':
540 if kind == 'files':
541 raise error.Abort(_('cannot archive plain files to stdout'))
541 raise error.Abort(_('cannot archive plain files to stdout'))
542 dest = cmdutil.makefileobj(repo, dest)
542 dest = cmdutil.makefileobj(repo, dest)
543 if not prefix:
543 if not prefix:
544 prefix = os.path.basename(repo.root) + '-%h'
544 prefix = os.path.basename(repo.root) + '-%h'
545
545
546 prefix = cmdutil.makefilename(repo, prefix, node)
546 prefix = cmdutil.makefilename(repo, prefix, node)
547 matchfn = scmutil.match(ctx, [], opts)
547 matchfn = scmutil.match(ctx, [], opts)
548 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
548 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
549 matchfn, prefix, subrepos=opts.get('subrepos'))
549 matchfn, prefix, subrepos=opts.get('subrepos'))
550
550
551 @command('backout',
551 @command('backout',
552 [('', 'merge', None, _('merge with old dirstate parent after backout')),
552 [('', 'merge', None, _('merge with old dirstate parent after backout')),
553 ('', 'commit', None,
553 ('', 'commit', None,
554 _('commit if no conflicts were encountered (DEPRECATED)')),
554 _('commit if no conflicts were encountered (DEPRECATED)')),
555 ('', 'no-commit', None, _('do not commit')),
555 ('', 'no-commit', None, _('do not commit')),
556 ('', 'parent', '',
556 ('', 'parent', '',
557 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
557 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
558 ('r', 'rev', '', _('revision to backout'), _('REV')),
558 ('r', 'rev', '', _('revision to backout'), _('REV')),
559 ('e', 'edit', False, _('invoke editor on commit messages')),
559 ('e', 'edit', False, _('invoke editor on commit messages')),
560 ] + mergetoolopts + walkopts + commitopts + commitopts2,
560 ] + mergetoolopts + walkopts + commitopts + commitopts2,
561 _('[OPTION]... [-r] REV'))
561 _('[OPTION]... [-r] REV'))
562 def backout(ui, repo, node=None, rev=None, **opts):
562 def backout(ui, repo, node=None, rev=None, **opts):
563 '''reverse effect of earlier changeset
563 '''reverse effect of earlier changeset
564
564
565 Prepare a new changeset with the effect of REV undone in the
565 Prepare a new changeset with the effect of REV undone in the
566 current working directory. If no conflicts were encountered,
566 current working directory. If no conflicts were encountered,
567 it will be committed immediately.
567 it will be committed immediately.
568
568
569 If REV is the parent of the working directory, then this new changeset
569 If REV is the parent of the working directory, then this new changeset
570 is committed automatically (unless --no-commit is specified).
570 is committed automatically (unless --no-commit is specified).
571
571
572 .. note::
572 .. note::
573
573
574 :hg:`backout` cannot be used to fix either an unwanted or
574 :hg:`backout` cannot be used to fix either an unwanted or
575 incorrect merge.
575 incorrect merge.
576
576
577 .. container:: verbose
577 .. container:: verbose
578
578
579 Examples:
579 Examples:
580
580
581 - Reverse the effect of the parent of the working directory.
581 - Reverse the effect of the parent of the working directory.
582 This backout will be committed immediately::
582 This backout will be committed immediately::
583
583
584 hg backout -r .
584 hg backout -r .
585
585
586 - Reverse the effect of previous bad revision 23::
586 - Reverse the effect of previous bad revision 23::
587
587
588 hg backout -r 23
588 hg backout -r 23
589
589
590 - Reverse the effect of previous bad revision 23 and
590 - Reverse the effect of previous bad revision 23 and
591 leave changes uncommitted::
591 leave changes uncommitted::
592
592
593 hg backout -r 23 --no-commit
593 hg backout -r 23 --no-commit
594 hg commit -m "Backout revision 23"
594 hg commit -m "Backout revision 23"
595
595
596 By default, the pending changeset will have one parent,
596 By default, the pending changeset will have one parent,
597 maintaining a linear history. With --merge, the pending
597 maintaining a linear history. With --merge, the pending
598 changeset will instead have two parents: the old parent of the
598 changeset will instead have two parents: the old parent of the
599 working directory and a new child of REV that simply undoes REV.
599 working directory and a new child of REV that simply undoes REV.
600
600
601 Before version 1.7, the behavior without --merge was equivalent
601 Before version 1.7, the behavior without --merge was equivalent
602 to specifying --merge followed by :hg:`update --clean .` to
602 to specifying --merge followed by :hg:`update --clean .` to
603 cancel the merge and leave the child of REV as a head to be
603 cancel the merge and leave the child of REV as a head to be
604 merged separately.
604 merged separately.
605
605
606 See :hg:`help dates` for a list of formats valid for -d/--date.
606 See :hg:`help dates` for a list of formats valid for -d/--date.
607
607
608 See :hg:`help revert` for a way to restore files to the state
608 See :hg:`help revert` for a way to restore files to the state
609 of another revision.
609 of another revision.
610
610
611 Returns 0 on success, 1 if nothing to backout or there are unresolved
611 Returns 0 on success, 1 if nothing to backout or there are unresolved
612 files.
612 files.
613 '''
613 '''
614 wlock = lock = None
614 wlock = lock = None
615 try:
615 try:
616 wlock = repo.wlock()
616 wlock = repo.wlock()
617 lock = repo.lock()
617 lock = repo.lock()
618 return _dobackout(ui, repo, node, rev, **opts)
618 return _dobackout(ui, repo, node, rev, **opts)
619 finally:
619 finally:
620 release(lock, wlock)
620 release(lock, wlock)
621
621
622 def _dobackout(ui, repo, node=None, rev=None, **opts):
622 def _dobackout(ui, repo, node=None, rev=None, **opts):
623 if opts.get('commit') and opts.get('no_commit'):
623 if opts.get('commit') and opts.get('no_commit'):
624 raise error.Abort(_("cannot use --commit with --no-commit"))
624 raise error.Abort(_("cannot use --commit with --no-commit"))
625 if opts.get('merge') and opts.get('no_commit'):
625 if opts.get('merge') and opts.get('no_commit'):
626 raise error.Abort(_("cannot use --merge with --no-commit"))
626 raise error.Abort(_("cannot use --merge with --no-commit"))
627
627
628 if rev and node:
628 if rev and node:
629 raise error.Abort(_("please specify just one revision"))
629 raise error.Abort(_("please specify just one revision"))
630
630
631 if not rev:
631 if not rev:
632 rev = node
632 rev = node
633
633
634 if not rev:
634 if not rev:
635 raise error.Abort(_("please specify a revision to backout"))
635 raise error.Abort(_("please specify a revision to backout"))
636
636
637 date = opts.get('date')
637 date = opts.get('date')
638 if date:
638 if date:
639 opts['date'] = util.parsedate(date)
639 opts['date'] = util.parsedate(date)
640
640
641 cmdutil.checkunfinished(repo)
641 cmdutil.checkunfinished(repo)
642 cmdutil.bailifchanged(repo)
642 cmdutil.bailifchanged(repo)
643 node = scmutil.revsingle(repo, rev).node()
643 node = scmutil.revsingle(repo, rev).node()
644
644
645 op1, op2 = repo.dirstate.parents()
645 op1, op2 = repo.dirstate.parents()
646 if not repo.changelog.isancestor(node, op1):
646 if not repo.changelog.isancestor(node, op1):
647 raise error.Abort(_('cannot backout change that is not an ancestor'))
647 raise error.Abort(_('cannot backout change that is not an ancestor'))
648
648
649 p1, p2 = repo.changelog.parents(node)
649 p1, p2 = repo.changelog.parents(node)
650 if p1 == nullid:
650 if p1 == nullid:
651 raise error.Abort(_('cannot backout a change with no parents'))
651 raise error.Abort(_('cannot backout a change with no parents'))
652 if p2 != nullid:
652 if p2 != nullid:
653 if not opts.get('parent'):
653 if not opts.get('parent'):
654 raise error.Abort(_('cannot backout a merge changeset'))
654 raise error.Abort(_('cannot backout a merge changeset'))
655 p = repo.lookup(opts['parent'])
655 p = repo.lookup(opts['parent'])
656 if p not in (p1, p2):
656 if p not in (p1, p2):
657 raise error.Abort(_('%s is not a parent of %s') %
657 raise error.Abort(_('%s is not a parent of %s') %
658 (short(p), short(node)))
658 (short(p), short(node)))
659 parent = p
659 parent = p
660 else:
660 else:
661 if opts.get('parent'):
661 if opts.get('parent'):
662 raise error.Abort(_('cannot use --parent on non-merge changeset'))
662 raise error.Abort(_('cannot use --parent on non-merge changeset'))
663 parent = p1
663 parent = p1
664
664
665 # the backout should appear on the same branch
665 # the backout should appear on the same branch
666 branch = repo.dirstate.branch()
666 branch = repo.dirstate.branch()
667 bheads = repo.branchheads(branch)
667 bheads = repo.branchheads(branch)
668 rctx = scmutil.revsingle(repo, hex(parent))
668 rctx = scmutil.revsingle(repo, hex(parent))
669 if not opts.get('merge') and op1 != node:
669 if not opts.get('merge') and op1 != node:
670 dsguard = dirstateguard.dirstateguard(repo, 'backout')
670 dsguard = dirstateguard.dirstateguard(repo, 'backout')
671 try:
671 try:
672 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
672 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
673 'backout')
673 'backout')
674 stats = mergemod.update(repo, parent, True, True, node, False)
674 stats = mergemod.update(repo, parent, True, True, node, False)
675 repo.setparents(op1, op2)
675 repo.setparents(op1, op2)
676 dsguard.close()
676 dsguard.close()
677 hg._showstats(repo, stats)
677 hg._showstats(repo, stats)
678 if stats[3]:
678 if stats[3]:
679 repo.ui.status(_("use 'hg resolve' to retry unresolved "
679 repo.ui.status(_("use 'hg resolve' to retry unresolved "
680 "file merges\n"))
680 "file merges\n"))
681 return 1
681 return 1
682 finally:
682 finally:
683 ui.setconfig('ui', 'forcemerge', '', '')
683 ui.setconfig('ui', 'forcemerge', '', '')
684 lockmod.release(dsguard)
684 lockmod.release(dsguard)
685 else:
685 else:
686 hg.clean(repo, node, show_stats=False)
686 hg.clean(repo, node, show_stats=False)
687 repo.dirstate.setbranch(branch)
687 repo.dirstate.setbranch(branch)
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
688 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
689
689
690 if opts.get('no_commit'):
690 if opts.get('no_commit'):
691 msg = _("changeset %s backed out, "
691 msg = _("changeset %s backed out, "
692 "don't forget to commit.\n")
692 "don't forget to commit.\n")
693 ui.status(msg % short(node))
693 ui.status(msg % short(node))
694 return 0
694 return 0
695
695
696 def commitfunc(ui, repo, message, match, opts):
696 def commitfunc(ui, repo, message, match, opts):
697 editform = 'backout'
697 editform = 'backout'
698 e = cmdutil.getcommiteditor(editform=editform, **opts)
698 e = cmdutil.getcommiteditor(editform=editform, **opts)
699 if not message:
699 if not message:
700 # we don't translate commit messages
700 # we don't translate commit messages
701 message = "Backed out changeset %s" % short(node)
701 message = "Backed out changeset %s" % short(node)
702 e = cmdutil.getcommiteditor(edit=True, editform=editform)
702 e = cmdutil.getcommiteditor(edit=True, editform=editform)
703 return repo.commit(message, opts.get('user'), opts.get('date'),
703 return repo.commit(message, opts.get('user'), opts.get('date'),
704 match, editor=e)
704 match, editor=e)
705 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
705 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
706 if not newnode:
706 if not newnode:
707 ui.status(_("nothing changed\n"))
707 ui.status(_("nothing changed\n"))
708 return 1
708 return 1
709 cmdutil.commitstatus(repo, newnode, branch, bheads)
709 cmdutil.commitstatus(repo, newnode, branch, bheads)
710
710
711 def nice(node):
711 def nice(node):
712 return '%d:%s' % (repo.changelog.rev(node), short(node))
712 return '%d:%s' % (repo.changelog.rev(node), short(node))
713 ui.status(_('changeset %s backs out changeset %s\n') %
713 ui.status(_('changeset %s backs out changeset %s\n') %
714 (nice(repo.changelog.tip()), nice(node)))
714 (nice(repo.changelog.tip()), nice(node)))
715 if opts.get('merge') and op1 != node:
715 if opts.get('merge') and op1 != node:
716 hg.clean(repo, op1, show_stats=False)
716 hg.clean(repo, op1, show_stats=False)
717 ui.status(_('merging with changeset %s\n')
717 ui.status(_('merging with changeset %s\n')
718 % nice(repo.changelog.tip()))
718 % nice(repo.changelog.tip()))
719 try:
719 try:
720 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
720 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
721 'backout')
721 'backout')
722 return hg.merge(repo, hex(repo.changelog.tip()))
722 return hg.merge(repo, hex(repo.changelog.tip()))
723 finally:
723 finally:
724 ui.setconfig('ui', 'forcemerge', '', '')
724 ui.setconfig('ui', 'forcemerge', '', '')
725 return 0
725 return 0
726
726
727 @command('bisect',
727 @command('bisect',
728 [('r', 'reset', False, _('reset bisect state')),
728 [('r', 'reset', False, _('reset bisect state')),
729 ('g', 'good', False, _('mark changeset good')),
729 ('g', 'good', False, _('mark changeset good')),
730 ('b', 'bad', False, _('mark changeset bad')),
730 ('b', 'bad', False, _('mark changeset bad')),
731 ('s', 'skip', False, _('skip testing changeset')),
731 ('s', 'skip', False, _('skip testing changeset')),
732 ('e', 'extend', False, _('extend the bisect range')),
732 ('e', 'extend', False, _('extend the bisect range')),
733 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
733 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
734 ('U', 'noupdate', False, _('do not update to target'))],
734 ('U', 'noupdate', False, _('do not update to target'))],
735 _("[-gbsr] [-U] [-c CMD] [REV]"))
735 _("[-gbsr] [-U] [-c CMD] [REV]"))
736 def bisect(ui, repo, rev=None, extra=None, command=None,
736 def bisect(ui, repo, rev=None, extra=None, command=None,
737 reset=None, good=None, bad=None, skip=None, extend=None,
737 reset=None, good=None, bad=None, skip=None, extend=None,
738 noupdate=None):
738 noupdate=None):
739 """subdivision search of changesets
739 """subdivision search of changesets
740
740
741 This command helps to find changesets which introduce problems. To
741 This command helps to find changesets which introduce problems. To
742 use, mark the earliest changeset you know exhibits the problem as
742 use, mark the earliest changeset you know exhibits the problem as
743 bad, then mark the latest changeset which is free from the problem
743 bad, then mark the latest changeset which is free from the problem
744 as good. Bisect will update your working directory to a revision
744 as good. Bisect will update your working directory to a revision
745 for testing (unless the -U/--noupdate option is specified). Once
745 for testing (unless the -U/--noupdate option is specified). Once
746 you have performed tests, mark the working directory as good or
746 you have performed tests, mark the working directory as good or
747 bad, and bisect will either update to another candidate changeset
747 bad, and bisect will either update to another candidate changeset
748 or announce that it has found the bad revision.
748 or announce that it has found the bad revision.
749
749
750 As a shortcut, you can also use the revision argument to mark a
750 As a shortcut, you can also use the revision argument to mark a
751 revision as good or bad without checking it out first.
751 revision as good or bad without checking it out first.
752
752
753 If you supply a command, it will be used for automatic bisection.
753 If you supply a command, it will be used for automatic bisection.
754 The environment variable HG_NODE will contain the ID of the
754 The environment variable HG_NODE will contain the ID of the
755 changeset being tested. The exit status of the command will be
755 changeset being tested. The exit status of the command will be
756 used to mark revisions as good or bad: status 0 means good, 125
756 used to mark revisions as good or bad: status 0 means good, 125
757 means to skip the revision, 127 (command not found) will abort the
757 means to skip the revision, 127 (command not found) will abort the
758 bisection, and any other non-zero exit status means the revision
758 bisection, and any other non-zero exit status means the revision
759 is bad.
759 is bad.
760
760
761 .. container:: verbose
761 .. container:: verbose
762
762
763 Some examples:
763 Some examples:
764
764
765 - start a bisection with known bad revision 34, and good revision 12::
765 - start a bisection with known bad revision 34, and good revision 12::
766
766
767 hg bisect --bad 34
767 hg bisect --bad 34
768 hg bisect --good 12
768 hg bisect --good 12
769
769
770 - advance the current bisection by marking current revision as good or
770 - advance the current bisection by marking current revision as good or
771 bad::
771 bad::
772
772
773 hg bisect --good
773 hg bisect --good
774 hg bisect --bad
774 hg bisect --bad
775
775
776 - mark the current revision, or a known revision, to be skipped (e.g. if
776 - mark the current revision, or a known revision, to be skipped (e.g. if
777 that revision is not usable because of another issue)::
777 that revision is not usable because of another issue)::
778
778
779 hg bisect --skip
779 hg bisect --skip
780 hg bisect --skip 23
780 hg bisect --skip 23
781
781
782 - skip all revisions that do not touch directories ``foo`` or ``bar``::
782 - skip all revisions that do not touch directories ``foo`` or ``bar``::
783
783
784 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
784 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
785
785
786 - forget the current bisection::
786 - forget the current bisection::
787
787
788 hg bisect --reset
788 hg bisect --reset
789
789
790 - use 'make && make tests' to automatically find the first broken
790 - use 'make && make tests' to automatically find the first broken
791 revision::
791 revision::
792
792
793 hg bisect --reset
793 hg bisect --reset
794 hg bisect --bad 34
794 hg bisect --bad 34
795 hg bisect --good 12
795 hg bisect --good 12
796 hg bisect --command "make && make tests"
796 hg bisect --command "make && make tests"
797
797
798 - see all changesets whose states are already known in the current
798 - see all changesets whose states are already known in the current
799 bisection::
799 bisection::
800
800
801 hg log -r "bisect(pruned)"
801 hg log -r "bisect(pruned)"
802
802
803 - see the changeset currently being bisected (especially useful
803 - see the changeset currently being bisected (especially useful
804 if running with -U/--noupdate)::
804 if running with -U/--noupdate)::
805
805
806 hg log -r "bisect(current)"
806 hg log -r "bisect(current)"
807
807
808 - see all changesets that took part in the current bisection::
808 - see all changesets that took part in the current bisection::
809
809
810 hg log -r "bisect(range)"
810 hg log -r "bisect(range)"
811
811
812 - you can even get a nice graph::
812 - you can even get a nice graph::
813
813
814 hg log --graph -r "bisect(range)"
814 hg log --graph -r "bisect(range)"
815
815
816 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
816 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
817
817
818 Returns 0 on success.
818 Returns 0 on success.
819 """
819 """
820 # backward compatibility
820 # backward compatibility
821 if rev in "good bad reset init".split():
821 if rev in "good bad reset init".split():
822 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
822 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
823 cmd, rev, extra = rev, extra, None
823 cmd, rev, extra = rev, extra, None
824 if cmd == "good":
824 if cmd == "good":
825 good = True
825 good = True
826 elif cmd == "bad":
826 elif cmd == "bad":
827 bad = True
827 bad = True
828 else:
828 else:
829 reset = True
829 reset = True
830 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
830 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
831 raise error.Abort(_('incompatible arguments'))
831 raise error.Abort(_('incompatible arguments'))
832
832
833 cmdutil.checkunfinished(repo)
833 cmdutil.checkunfinished(repo)
834
834
835 if reset:
835 if reset:
836 hbisect.resetstate(repo)
836 hbisect.resetstate(repo)
837 return
837 return
838
838
839 state = hbisect.load_state(repo)
839 state = hbisect.load_state(repo)
840
840
841 # update state
841 # update state
842 if good or bad or skip:
842 if good or bad or skip:
843 if rev:
843 if rev:
844 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
844 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
845 else:
845 else:
846 nodes = [repo.lookup('.')]
846 nodes = [repo.lookup('.')]
847 if good:
847 if good:
848 state['good'] += nodes
848 state['good'] += nodes
849 elif bad:
849 elif bad:
850 state['bad'] += nodes
850 state['bad'] += nodes
851 elif skip:
851 elif skip:
852 state['skip'] += nodes
852 state['skip'] += nodes
853 hbisect.save_state(repo, state)
853 hbisect.save_state(repo, state)
854 if not (state['good'] and state['bad']):
854 if not (state['good'] and state['bad']):
855 return
855 return
856
856
857 def mayupdate(repo, node, show_stats=True):
857 def mayupdate(repo, node, show_stats=True):
858 """common used update sequence"""
858 """common used update sequence"""
859 if noupdate:
859 if noupdate:
860 return
860 return
861 cmdutil.bailifchanged(repo)
861 cmdutil.bailifchanged(repo)
862 return hg.clean(repo, node, show_stats=show_stats)
862 return hg.clean(repo, node, show_stats=show_stats)
863
863
864 displayer = cmdutil.show_changeset(ui, repo, {})
864 displayer = cmdutil.show_changeset(ui, repo, {})
865
865
866 if command:
866 if command:
867 changesets = 1
867 changesets = 1
868 if noupdate:
868 if noupdate:
869 try:
869 try:
870 node = state['current'][0]
870 node = state['current'][0]
871 except LookupError:
871 except LookupError:
872 raise error.Abort(_('current bisect revision is unknown - '
872 raise error.Abort(_('current bisect revision is unknown - '
873 'start a new bisect to fix'))
873 'start a new bisect to fix'))
874 else:
874 else:
875 node, p2 = repo.dirstate.parents()
875 node, p2 = repo.dirstate.parents()
876 if p2 != nullid:
876 if p2 != nullid:
877 raise error.Abort(_('current bisect revision is a merge'))
877 raise error.Abort(_('current bisect revision is a merge'))
878 if rev:
878 if rev:
879 node = repo[scmutil.revsingle(repo, rev, node)].node()
879 node = repo[scmutil.revsingle(repo, rev, node)].node()
880 try:
880 try:
881 while changesets:
881 while changesets:
882 # update state
882 # update state
883 state['current'] = [node]
883 state['current'] = [node]
884 hbisect.save_state(repo, state)
884 hbisect.save_state(repo, state)
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
885 status = ui.system(command, environ={'HG_NODE': hex(node)})
886 if status == 125:
886 if status == 125:
887 transition = "skip"
887 transition = "skip"
888 elif status == 0:
888 elif status == 0:
889 transition = "good"
889 transition = "good"
890 # status < 0 means process was killed
890 # status < 0 means process was killed
891 elif status == 127:
891 elif status == 127:
892 raise error.Abort(_("failed to execute %s") % command)
892 raise error.Abort(_("failed to execute %s") % command)
893 elif status < 0:
893 elif status < 0:
894 raise error.Abort(_("%s killed") % command)
894 raise error.Abort(_("%s killed") % command)
895 else:
895 else:
896 transition = "bad"
896 transition = "bad"
897 state[transition].append(node)
897 state[transition].append(node)
898 ctx = repo[node]
898 ctx = repo[node]
899 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
899 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
900 hbisect.checkstate(state)
900 hbisect.checkstate(state)
901 # bisect
901 # bisect
902 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
902 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
903 # update to next check
903 # update to next check
904 node = nodes[0]
904 node = nodes[0]
905 mayupdate(repo, node, show_stats=False)
905 mayupdate(repo, node, show_stats=False)
906 finally:
906 finally:
907 state['current'] = [node]
907 state['current'] = [node]
908 hbisect.save_state(repo, state)
908 hbisect.save_state(repo, state)
909 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
909 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
910 return
910 return
911
911
912 hbisect.checkstate(state)
912 hbisect.checkstate(state)
913
913
914 # actually bisect
914 # actually bisect
915 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
915 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
916 if extend:
916 if extend:
917 if not changesets:
917 if not changesets:
918 extendnode = hbisect.extendrange(repo, state, nodes, good)
918 extendnode = hbisect.extendrange(repo, state, nodes, good)
919 if extendnode is not None:
919 if extendnode is not None:
920 ui.write(_("Extending search to changeset %d:%s\n")
920 ui.write(_("Extending search to changeset %d:%s\n")
921 % (extendnode.rev(), extendnode))
921 % (extendnode.rev(), extendnode))
922 state['current'] = [extendnode.node()]
922 state['current'] = [extendnode.node()]
923 hbisect.save_state(repo, state)
923 hbisect.save_state(repo, state)
924 return mayupdate(repo, extendnode.node())
924 return mayupdate(repo, extendnode.node())
925 raise error.Abort(_("nothing to extend"))
925 raise error.Abort(_("nothing to extend"))
926
926
927 if changesets == 0:
927 if changesets == 0:
928 hbisect.printresult(ui, repo, state, displayer, nodes, good)
928 hbisect.printresult(ui, repo, state, displayer, nodes, good)
929 else:
929 else:
930 assert len(nodes) == 1 # only a single node can be tested next
930 assert len(nodes) == 1 # only a single node can be tested next
931 node = nodes[0]
931 node = nodes[0]
932 # compute the approximate number of remaining tests
932 # compute the approximate number of remaining tests
933 tests, size = 0, 2
933 tests, size = 0, 2
934 while size <= changesets:
934 while size <= changesets:
935 tests, size = tests + 1, size * 2
935 tests, size = tests + 1, size * 2
936 rev = repo.changelog.rev(node)
936 rev = repo.changelog.rev(node)
937 ui.write(_("Testing changeset %d:%s "
937 ui.write(_("Testing changeset %d:%s "
938 "(%d changesets remaining, ~%d tests)\n")
938 "(%d changesets remaining, ~%d tests)\n")
939 % (rev, short(node), changesets, tests))
939 % (rev, short(node), changesets, tests))
940 state['current'] = [node]
940 state['current'] = [node]
941 hbisect.save_state(repo, state)
941 hbisect.save_state(repo, state)
942 return mayupdate(repo, node)
942 return mayupdate(repo, node)
943
943
944 @command('bookmarks|bookmark',
944 @command('bookmarks|bookmark',
945 [('f', 'force', False, _('force')),
945 [('f', 'force', False, _('force')),
946 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
946 ('r', 'rev', '', _('revision for bookmark action'), _('REV')),
947 ('d', 'delete', False, _('delete a given bookmark')),
947 ('d', 'delete', False, _('delete a given bookmark')),
948 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
948 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
949 ('i', 'inactive', False, _('mark a bookmark inactive')),
949 ('i', 'inactive', False, _('mark a bookmark inactive')),
950 ] + formatteropts,
950 ] + formatteropts,
951 _('hg bookmarks [OPTIONS]... [NAME]...'))
951 _('hg bookmarks [OPTIONS]... [NAME]...'))
952 def bookmark(ui, repo, *names, **opts):
952 def bookmark(ui, repo, *names, **opts):
953 '''create a new bookmark or list existing bookmarks
953 '''create a new bookmark or list existing bookmarks
954
954
955 Bookmarks are labels on changesets to help track lines of development.
955 Bookmarks are labels on changesets to help track lines of development.
956 Bookmarks are unversioned and can be moved, renamed and deleted.
956 Bookmarks are unversioned and can be moved, renamed and deleted.
957 Deleting or moving a bookmark has no effect on the associated changesets.
957 Deleting or moving a bookmark has no effect on the associated changesets.
958
958
959 Creating or updating to a bookmark causes it to be marked as 'active'.
959 Creating or updating to a bookmark causes it to be marked as 'active'.
960 The active bookmark is indicated with a '*'.
960 The active bookmark is indicated with a '*'.
961 When a commit is made, the active bookmark will advance to the new commit.
961 When a commit is made, the active bookmark will advance to the new commit.
962 A plain :hg:`update` will also advance an active bookmark, if possible.
962 A plain :hg:`update` will also advance an active bookmark, if possible.
963 Updating away from a bookmark will cause it to be deactivated.
963 Updating away from a bookmark will cause it to be deactivated.
964
964
965 Bookmarks can be pushed and pulled between repositories (see
965 Bookmarks can be pushed and pulled between repositories (see
966 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
966 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
967 diverged, a new 'divergent bookmark' of the form 'name@path' will
967 diverged, a new 'divergent bookmark' of the form 'name@path' will
968 be created. Using :hg:`merge` will resolve the divergence.
968 be created. Using :hg:`merge` will resolve the divergence.
969
969
970 A bookmark named '@' has the special property that :hg:`clone` will
970 A bookmark named '@' has the special property that :hg:`clone` will
971 check it out by default if it exists.
971 check it out by default if it exists.
972
972
973 .. container:: verbose
973 .. container:: verbose
974
974
975 Examples:
975 Examples:
976
976
977 - create an active bookmark for a new line of development::
977 - create an active bookmark for a new line of development::
978
978
979 hg book new-feature
979 hg book new-feature
980
980
981 - create an inactive bookmark as a place marker::
981 - create an inactive bookmark as a place marker::
982
982
983 hg book -i reviewed
983 hg book -i reviewed
984
984
985 - create an inactive bookmark on another changeset::
985 - create an inactive bookmark on another changeset::
986
986
987 hg book -r .^ tested
987 hg book -r .^ tested
988
988
989 - rename bookmark turkey to dinner::
989 - rename bookmark turkey to dinner::
990
990
991 hg book -m turkey dinner
991 hg book -m turkey dinner
992
992
993 - move the '@' bookmark from another branch::
993 - move the '@' bookmark from another branch::
994
994
995 hg book -f @
995 hg book -f @
996 '''
996 '''
997 force = opts.get('force')
997 force = opts.get('force')
998 rev = opts.get('rev')
998 rev = opts.get('rev')
999 delete = opts.get('delete')
999 delete = opts.get('delete')
1000 rename = opts.get('rename')
1000 rename = opts.get('rename')
1001 inactive = opts.get('inactive')
1001 inactive = opts.get('inactive')
1002
1002
1003 def checkformat(mark):
1003 def checkformat(mark):
1004 mark = mark.strip()
1004 mark = mark.strip()
1005 if not mark:
1005 if not mark:
1006 raise error.Abort(_("bookmark names cannot consist entirely of "
1006 raise error.Abort(_("bookmark names cannot consist entirely of "
1007 "whitespace"))
1007 "whitespace"))
1008 scmutil.checknewlabel(repo, mark, 'bookmark')
1008 scmutil.checknewlabel(repo, mark, 'bookmark')
1009 return mark
1009 return mark
1010
1010
1011 def checkconflict(repo, mark, cur, force=False, target=None):
1011 def checkconflict(repo, mark, cur, force=False, target=None):
1012 if mark in marks and not force:
1012 if mark in marks and not force:
1013 if target:
1013 if target:
1014 if marks[mark] == target and target == cur:
1014 if marks[mark] == target and target == cur:
1015 # re-activating a bookmark
1015 # re-activating a bookmark
1016 return
1016 return
1017 anc = repo.changelog.ancestors([repo[target].rev()])
1017 anc = repo.changelog.ancestors([repo[target].rev()])
1018 bmctx = repo[marks[mark]]
1018 bmctx = repo[marks[mark]]
1019 divs = [repo[b].node() for b in marks
1019 divs = [repo[b].node() for b in marks
1020 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1020 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1021
1021
1022 # allow resolving a single divergent bookmark even if moving
1022 # allow resolving a single divergent bookmark even if moving
1023 # the bookmark across branches when a revision is specified
1023 # the bookmark across branches when a revision is specified
1024 # that contains a divergent bookmark
1024 # that contains a divergent bookmark
1025 if bmctx.rev() not in anc and target in divs:
1025 if bmctx.rev() not in anc and target in divs:
1026 bookmarks.deletedivergent(repo, [target], mark)
1026 bookmarks.deletedivergent(repo, [target], mark)
1027 return
1027 return
1028
1028
1029 deletefrom = [b for b in divs
1029 deletefrom = [b for b in divs
1030 if repo[b].rev() in anc or b == target]
1030 if repo[b].rev() in anc or b == target]
1031 bookmarks.deletedivergent(repo, deletefrom, mark)
1031 bookmarks.deletedivergent(repo, deletefrom, mark)
1032 if bookmarks.validdest(repo, bmctx, repo[target]):
1032 if bookmarks.validdest(repo, bmctx, repo[target]):
1033 ui.status(_("moving bookmark '%s' forward from %s\n") %
1033 ui.status(_("moving bookmark '%s' forward from %s\n") %
1034 (mark, short(bmctx.node())))
1034 (mark, short(bmctx.node())))
1035 return
1035 return
1036 raise error.Abort(_("bookmark '%s' already exists "
1036 raise error.Abort(_("bookmark '%s' already exists "
1037 "(use -f to force)") % mark)
1037 "(use -f to force)") % mark)
1038 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1038 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1039 and not force):
1039 and not force):
1040 raise error.Abort(
1040 raise error.Abort(
1041 _("a bookmark cannot have the name of an existing branch"))
1041 _("a bookmark cannot have the name of an existing branch"))
1042
1042
1043 if delete and rename:
1043 if delete and rename:
1044 raise error.Abort(_("--delete and --rename are incompatible"))
1044 raise error.Abort(_("--delete and --rename are incompatible"))
1045 if delete and rev:
1045 if delete and rev:
1046 raise error.Abort(_("--rev is incompatible with --delete"))
1046 raise error.Abort(_("--rev is incompatible with --delete"))
1047 if rename and rev:
1047 if rename and rev:
1048 raise error.Abort(_("--rev is incompatible with --rename"))
1048 raise error.Abort(_("--rev is incompatible with --rename"))
1049 if not names and (delete or rev):
1049 if not names and (delete or rev):
1050 raise error.Abort(_("bookmark name required"))
1050 raise error.Abort(_("bookmark name required"))
1051
1051
1052 if delete or rename or names or inactive:
1052 if delete or rename or names or inactive:
1053 wlock = lock = tr = None
1053 wlock = lock = tr = None
1054 try:
1054 try:
1055 wlock = repo.wlock()
1055 wlock = repo.wlock()
1056 lock = repo.lock()
1056 lock = repo.lock()
1057 cur = repo.changectx('.').node()
1057 cur = repo.changectx('.').node()
1058 marks = repo._bookmarks
1058 marks = repo._bookmarks
1059 if delete:
1059 if delete:
1060 tr = repo.transaction('bookmark')
1060 tr = repo.transaction('bookmark')
1061 for mark in names:
1061 for mark in names:
1062 if mark not in marks:
1062 if mark not in marks:
1063 raise error.Abort(_("bookmark '%s' does not exist") %
1063 raise error.Abort(_("bookmark '%s' does not exist") %
1064 mark)
1064 mark)
1065 if mark == repo._activebookmark:
1065 if mark == repo._activebookmark:
1066 bookmarks.deactivate(repo)
1066 bookmarks.deactivate(repo)
1067 del marks[mark]
1067 del marks[mark]
1068
1068
1069 elif rename:
1069 elif rename:
1070 tr = repo.transaction('bookmark')
1070 tr = repo.transaction('bookmark')
1071 if not names:
1071 if not names:
1072 raise error.Abort(_("new bookmark name required"))
1072 raise error.Abort(_("new bookmark name required"))
1073 elif len(names) > 1:
1073 elif len(names) > 1:
1074 raise error.Abort(_("only one new bookmark name allowed"))
1074 raise error.Abort(_("only one new bookmark name allowed"))
1075 mark = checkformat(names[0])
1075 mark = checkformat(names[0])
1076 if rename not in marks:
1076 if rename not in marks:
1077 raise error.Abort(_("bookmark '%s' does not exist")
1077 raise error.Abort(_("bookmark '%s' does not exist")
1078 % rename)
1078 % rename)
1079 checkconflict(repo, mark, cur, force)
1079 checkconflict(repo, mark, cur, force)
1080 marks[mark] = marks[rename]
1080 marks[mark] = marks[rename]
1081 if repo._activebookmark == rename and not inactive:
1081 if repo._activebookmark == rename and not inactive:
1082 bookmarks.activate(repo, mark)
1082 bookmarks.activate(repo, mark)
1083 del marks[rename]
1083 del marks[rename]
1084 elif names:
1084 elif names:
1085 tr = repo.transaction('bookmark')
1085 tr = repo.transaction('bookmark')
1086 newact = None
1086 newact = None
1087 for mark in names:
1087 for mark in names:
1088 mark = checkformat(mark)
1088 mark = checkformat(mark)
1089 if newact is None:
1089 if newact is None:
1090 newact = mark
1090 newact = mark
1091 if inactive and mark == repo._activebookmark:
1091 if inactive and mark == repo._activebookmark:
1092 bookmarks.deactivate(repo)
1092 bookmarks.deactivate(repo)
1093 return
1093 return
1094 tgt = cur
1094 tgt = cur
1095 if rev:
1095 if rev:
1096 tgt = scmutil.revsingle(repo, rev).node()
1096 tgt = scmutil.revsingle(repo, rev).node()
1097 checkconflict(repo, mark, cur, force, tgt)
1097 checkconflict(repo, mark, cur, force, tgt)
1098 marks[mark] = tgt
1098 marks[mark] = tgt
1099 if not inactive and cur == marks[newact] and not rev:
1099 if not inactive and cur == marks[newact] and not rev:
1100 bookmarks.activate(repo, newact)
1100 bookmarks.activate(repo, newact)
1101 elif cur != tgt and newact == repo._activebookmark:
1101 elif cur != tgt and newact == repo._activebookmark:
1102 bookmarks.deactivate(repo)
1102 bookmarks.deactivate(repo)
1103 elif inactive:
1103 elif inactive:
1104 if len(marks) == 0:
1104 if len(marks) == 0:
1105 ui.status(_("no bookmarks set\n"))
1105 ui.status(_("no bookmarks set\n"))
1106 elif not repo._activebookmark:
1106 elif not repo._activebookmark:
1107 ui.status(_("no active bookmark\n"))
1107 ui.status(_("no active bookmark\n"))
1108 else:
1108 else:
1109 bookmarks.deactivate(repo)
1109 bookmarks.deactivate(repo)
1110 if tr is not None:
1110 if tr is not None:
1111 marks.recordchange(tr)
1111 marks.recordchange(tr)
1112 tr.close()
1112 tr.close()
1113 finally:
1113 finally:
1114 lockmod.release(tr, lock, wlock)
1114 lockmod.release(tr, lock, wlock)
1115 else: # show bookmarks
1115 else: # show bookmarks
1116 fm = ui.formatter('bookmarks', opts)
1116 fm = ui.formatter('bookmarks', opts)
1117 hexfn = fm.hexfunc
1117 hexfn = fm.hexfunc
1118 marks = repo._bookmarks
1118 marks = repo._bookmarks
1119 if len(marks) == 0 and fm.isplain():
1119 if len(marks) == 0 and fm.isplain():
1120 ui.status(_("no bookmarks set\n"))
1120 ui.status(_("no bookmarks set\n"))
1121 for bmark, n in sorted(marks.iteritems()):
1121 for bmark, n in sorted(marks.iteritems()):
1122 active = repo._activebookmark
1122 active = repo._activebookmark
1123 if bmark == active:
1123 if bmark == active:
1124 prefix, label = '*', activebookmarklabel
1124 prefix, label = '*', activebookmarklabel
1125 else:
1125 else:
1126 prefix, label = ' ', ''
1126 prefix, label = ' ', ''
1127
1127
1128 fm.startitem()
1128 fm.startitem()
1129 if not ui.quiet:
1129 if not ui.quiet:
1130 fm.plain(' %s ' % prefix, label=label)
1130 fm.plain(' %s ' % prefix, label=label)
1131 fm.write('bookmark', '%s', bmark, label=label)
1131 fm.write('bookmark', '%s', bmark, label=label)
1132 pad = " " * (25 - encoding.colwidth(bmark))
1132 pad = " " * (25 - encoding.colwidth(bmark))
1133 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1133 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1134 repo.changelog.rev(n), hexfn(n), label=label)
1134 repo.changelog.rev(n), hexfn(n), label=label)
1135 fm.data(active=(bmark == active))
1135 fm.data(active=(bmark == active))
1136 fm.plain('\n')
1136 fm.plain('\n')
1137 fm.end()
1137 fm.end()
1138
1138
1139 @command('branch',
1139 @command('branch',
1140 [('f', 'force', None,
1140 [('f', 'force', None,
1141 _('set branch name even if it shadows an existing branch')),
1141 _('set branch name even if it shadows an existing branch')),
1142 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1142 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1143 _('[-fC] [NAME]'))
1143 _('[-fC] [NAME]'))
1144 def branch(ui, repo, label=None, **opts):
1144 def branch(ui, repo, label=None, **opts):
1145 """set or show the current branch name
1145 """set or show the current branch name
1146
1146
1147 .. note::
1147 .. note::
1148
1148
1149 Branch names are permanent and global. Use :hg:`bookmark` to create a
1149 Branch names are permanent and global. Use :hg:`bookmark` to create a
1150 light-weight bookmark instead. See :hg:`help glossary` for more
1150 light-weight bookmark instead. See :hg:`help glossary` for more
1151 information about named branches and bookmarks.
1151 information about named branches and bookmarks.
1152
1152
1153 With no argument, show the current branch name. With one argument,
1153 With no argument, show the current branch name. With one argument,
1154 set the working directory branch name (the branch will not exist
1154 set the working directory branch name (the branch will not exist
1155 in the repository until the next commit). Standard practice
1155 in the repository until the next commit). Standard practice
1156 recommends that primary development take place on the 'default'
1156 recommends that primary development take place on the 'default'
1157 branch.
1157 branch.
1158
1158
1159 Unless -f/--force is specified, branch will not let you set a
1159 Unless -f/--force is specified, branch will not let you set a
1160 branch name that already exists.
1160 branch name that already exists.
1161
1161
1162 Use -C/--clean to reset the working directory branch to that of
1162 Use -C/--clean to reset the working directory branch to that of
1163 the parent of the working directory, negating a previous branch
1163 the parent of the working directory, negating a previous branch
1164 change.
1164 change.
1165
1165
1166 Use the command :hg:`update` to switch to an existing branch. Use
1166 Use the command :hg:`update` to switch to an existing branch. Use
1167 :hg:`commit --close-branch` to mark this branch head as closed.
1167 :hg:`commit --close-branch` to mark this branch head as closed.
1168 When all heads of a branch are closed, the branch will be
1168 When all heads of a branch are closed, the branch will be
1169 considered closed.
1169 considered closed.
1170
1170
1171 Returns 0 on success.
1171 Returns 0 on success.
1172 """
1172 """
1173 if label:
1173 if label:
1174 label = label.strip()
1174 label = label.strip()
1175
1175
1176 if not opts.get('clean') and not label:
1176 if not opts.get('clean') and not label:
1177 ui.write("%s\n" % repo.dirstate.branch())
1177 ui.write("%s\n" % repo.dirstate.branch())
1178 return
1178 return
1179
1179
1180 with repo.wlock():
1180 with repo.wlock():
1181 if opts.get('clean'):
1181 if opts.get('clean'):
1182 label = repo[None].p1().branch()
1182 label = repo[None].p1().branch()
1183 repo.dirstate.setbranch(label)
1183 repo.dirstate.setbranch(label)
1184 ui.status(_('reset working directory to branch %s\n') % label)
1184 ui.status(_('reset working directory to branch %s\n') % label)
1185 elif label:
1185 elif label:
1186 if not opts.get('force') and label in repo.branchmap():
1186 if not opts.get('force') and label in repo.branchmap():
1187 if label not in [p.branch() for p in repo[None].parents()]:
1187 if label not in [p.branch() for p in repo[None].parents()]:
1188 raise error.Abort(_('a branch of the same name already'
1188 raise error.Abort(_('a branch of the same name already'
1189 ' exists'),
1189 ' exists'),
1190 # i18n: "it" refers to an existing branch
1190 # i18n: "it" refers to an existing branch
1191 hint=_("use 'hg update' to switch to it"))
1191 hint=_("use 'hg update' to switch to it"))
1192 scmutil.checknewlabel(repo, label, 'branch')
1192 scmutil.checknewlabel(repo, label, 'branch')
1193 repo.dirstate.setbranch(label)
1193 repo.dirstate.setbranch(label)
1194 ui.status(_('marked working directory as branch %s\n') % label)
1194 ui.status(_('marked working directory as branch %s\n') % label)
1195
1195
1196 # find any open named branches aside from default
1196 # find any open named branches aside from default
1197 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1197 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1198 if n != "default" and not c]
1198 if n != "default" and not c]
1199 if not others:
1199 if not others:
1200 ui.status(_('(branches are permanent and global, '
1200 ui.status(_('(branches are permanent and global, '
1201 'did you want a bookmark?)\n'))
1201 'did you want a bookmark?)\n'))
1202
1202
1203 @command('branches',
1203 @command('branches',
1204 [('a', 'active', False,
1204 [('a', 'active', False,
1205 _('show only branches that have unmerged heads (DEPRECATED)')),
1205 _('show only branches that have unmerged heads (DEPRECATED)')),
1206 ('c', 'closed', False, _('show normal and closed branches')),
1206 ('c', 'closed', False, _('show normal and closed branches')),
1207 ] + formatteropts,
1207 ] + formatteropts,
1208 _('[-c]'))
1208 _('[-c]'))
1209 def branches(ui, repo, active=False, closed=False, **opts):
1209 def branches(ui, repo, active=False, closed=False, **opts):
1210 """list repository named branches
1210 """list repository named branches
1211
1211
1212 List the repository's named branches, indicating which ones are
1212 List the repository's named branches, indicating which ones are
1213 inactive. If -c/--closed is specified, also list branches which have
1213 inactive. If -c/--closed is specified, also list branches which have
1214 been marked closed (see :hg:`commit --close-branch`).
1214 been marked closed (see :hg:`commit --close-branch`).
1215
1215
1216 Use the command :hg:`update` to switch to an existing branch.
1216 Use the command :hg:`update` to switch to an existing branch.
1217
1217
1218 Returns 0.
1218 Returns 0.
1219 """
1219 """
1220
1220
1221 fm = ui.formatter('branches', opts)
1221 fm = ui.formatter('branches', opts)
1222 hexfunc = fm.hexfunc
1222 hexfunc = fm.hexfunc
1223
1223
1224 allheads = set(repo.heads())
1224 allheads = set(repo.heads())
1225 branches = []
1225 branches = []
1226 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1226 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1227 isactive = not isclosed and bool(set(heads) & allheads)
1227 isactive = not isclosed and bool(set(heads) & allheads)
1228 branches.append((tag, repo[tip], isactive, not isclosed))
1228 branches.append((tag, repo[tip], isactive, not isclosed))
1229 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1229 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1230 reverse=True)
1230 reverse=True)
1231
1231
1232 for tag, ctx, isactive, isopen in branches:
1232 for tag, ctx, isactive, isopen in branches:
1233 if active and not isactive:
1233 if active and not isactive:
1234 continue
1234 continue
1235 if isactive:
1235 if isactive:
1236 label = 'branches.active'
1236 label = 'branches.active'
1237 notice = ''
1237 notice = ''
1238 elif not isopen:
1238 elif not isopen:
1239 if not closed:
1239 if not closed:
1240 continue
1240 continue
1241 label = 'branches.closed'
1241 label = 'branches.closed'
1242 notice = _(' (closed)')
1242 notice = _(' (closed)')
1243 else:
1243 else:
1244 label = 'branches.inactive'
1244 label = 'branches.inactive'
1245 notice = _(' (inactive)')
1245 notice = _(' (inactive)')
1246 current = (tag == repo.dirstate.branch())
1246 current = (tag == repo.dirstate.branch())
1247 if current:
1247 if current:
1248 label = 'branches.current'
1248 label = 'branches.current'
1249
1249
1250 fm.startitem()
1250 fm.startitem()
1251 fm.write('branch', '%s', tag, label=label)
1251 fm.write('branch', '%s', tag, label=label)
1252 rev = ctx.rev()
1252 rev = ctx.rev()
1253 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1253 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1254 fmt = ' ' * padsize + ' %d:%s'
1254 fmt = ' ' * padsize + ' %d:%s'
1255 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1255 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1256 label='log.changeset changeset.%s' % ctx.phasestr())
1256 label='log.changeset changeset.%s' % ctx.phasestr())
1257 fm.data(active=isactive, closed=not isopen, current=current)
1257 fm.data(active=isactive, closed=not isopen, current=current)
1258 if not ui.quiet:
1258 if not ui.quiet:
1259 fm.plain(notice)
1259 fm.plain(notice)
1260 fm.plain('\n')
1260 fm.plain('\n')
1261 fm.end()
1261 fm.end()
1262
1262
1263 @command('bundle',
1263 @command('bundle',
1264 [('f', 'force', None, _('run even when the destination is unrelated')),
1264 [('f', 'force', None, _('run even when the destination is unrelated')),
1265 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1265 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1266 _('REV')),
1266 _('REV')),
1267 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1267 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1268 _('BRANCH')),
1268 _('BRANCH')),
1269 ('', 'base', [],
1269 ('', 'base', [],
1270 _('a base changeset assumed to be available at the destination'),
1270 _('a base changeset assumed to be available at the destination'),
1271 _('REV')),
1271 _('REV')),
1272 ('a', 'all', None, _('bundle all changesets in the repository')),
1272 ('a', 'all', None, _('bundle all changesets in the repository')),
1273 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1273 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1274 ] + remoteopts,
1274 ] + remoteopts,
1275 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1275 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1276 def bundle(ui, repo, fname, dest=None, **opts):
1276 def bundle(ui, repo, fname, dest=None, **opts):
1277 """create a changegroup file
1277 """create a changegroup file
1278
1278
1279 Generate a changegroup file collecting changesets to be added
1279 Generate a changegroup file collecting changesets to be added
1280 to a repository.
1280 to a repository.
1281
1281
1282 To create a bundle containing all changesets, use -a/--all
1282 To create a bundle containing all changesets, use -a/--all
1283 (or --base null). Otherwise, hg assumes the destination will have
1283 (or --base null). Otherwise, hg assumes the destination will have
1284 all the nodes you specify with --base parameters. Otherwise, hg
1284 all the nodes you specify with --base parameters. Otherwise, hg
1285 will assume the repository has all the nodes in destination, or
1285 will assume the repository has all the nodes in destination, or
1286 default-push/default if no destination is specified.
1286 default-push/default if no destination is specified.
1287
1287
1288 You can change bundle format with the -t/--type option. You can
1288 You can change bundle format with the -t/--type option. You can
1289 specify a compression, a bundle version or both using a dash
1289 specify a compression, a bundle version or both using a dash
1290 (comp-version). The available compression methods are: none, bzip2,
1290 (comp-version). The available compression methods are: none, bzip2,
1291 and gzip (by default, bundles are compressed using bzip2). The
1291 and gzip (by default, bundles are compressed using bzip2). The
1292 available formats are: v1, v2 (default to most suitable).
1292 available formats are: v1, v2 (default to most suitable).
1293
1293
1294 The bundle file can then be transferred using conventional means
1294 The bundle file can then be transferred using conventional means
1295 and applied to another repository with the unbundle or pull
1295 and applied to another repository with the unbundle or pull
1296 command. This is useful when direct push and pull are not
1296 command. This is useful when direct push and pull are not
1297 available or when exporting an entire repository is undesirable.
1297 available or when exporting an entire repository is undesirable.
1298
1298
1299 Applying bundles preserves all changeset contents including
1299 Applying bundles preserves all changeset contents including
1300 permissions, copy/rename information, and revision history.
1300 permissions, copy/rename information, and revision history.
1301
1301
1302 Returns 0 on success, 1 if no changes found.
1302 Returns 0 on success, 1 if no changes found.
1303 """
1303 """
1304 revs = None
1304 revs = None
1305 if 'rev' in opts:
1305 if 'rev' in opts:
1306 revstrings = opts['rev']
1306 revstrings = opts['rev']
1307 revs = scmutil.revrange(repo, revstrings)
1307 revs = scmutil.revrange(repo, revstrings)
1308 if revstrings and not revs:
1308 if revstrings and not revs:
1309 raise error.Abort(_('no commits to bundle'))
1309 raise error.Abort(_('no commits to bundle'))
1310
1310
1311 bundletype = opts.get('type', 'bzip2').lower()
1311 bundletype = opts.get('type', 'bzip2').lower()
1312 try:
1312 try:
1313 bcompression, cgversion, params = exchange.parsebundlespec(
1313 bcompression, cgversion, params = exchange.parsebundlespec(
1314 repo, bundletype, strict=False)
1314 repo, bundletype, strict=False)
1315 except error.UnsupportedBundleSpecification as e:
1315 except error.UnsupportedBundleSpecification as e:
1316 raise error.Abort(str(e),
1316 raise error.Abort(str(e),
1317 hint=_("see 'hg help bundle' for supported "
1317 hint=_("see 'hg help bundle' for supported "
1318 "values for --type"))
1318 "values for --type"))
1319
1319
1320 # Packed bundles are a pseudo bundle format for now.
1320 # Packed bundles are a pseudo bundle format for now.
1321 if cgversion == 's1':
1321 if cgversion == 's1':
1322 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1322 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1323 hint=_("use 'hg debugcreatestreamclonebundle'"))
1323 hint=_("use 'hg debugcreatestreamclonebundle'"))
1324
1324
1325 if opts.get('all'):
1325 if opts.get('all'):
1326 if dest:
1326 if dest:
1327 raise error.Abort(_("--all is incompatible with specifying "
1327 raise error.Abort(_("--all is incompatible with specifying "
1328 "a destination"))
1328 "a destination"))
1329 if opts.get('base'):
1329 if opts.get('base'):
1330 ui.warn(_("ignoring --base because --all was specified\n"))
1330 ui.warn(_("ignoring --base because --all was specified\n"))
1331 base = ['null']
1331 base = ['null']
1332 else:
1332 else:
1333 base = scmutil.revrange(repo, opts.get('base'))
1333 base = scmutil.revrange(repo, opts.get('base'))
1334 # TODO: get desired bundlecaps from command line.
1334 # TODO: get desired bundlecaps from command line.
1335 bundlecaps = None
1335 bundlecaps = None
1336 if cgversion not in changegroup.supportedoutgoingversions(repo):
1336 if cgversion not in changegroup.supportedoutgoingversions(repo):
1337 raise error.Abort(_("repository does not support bundle version %s") %
1337 raise error.Abort(_("repository does not support bundle version %s") %
1338 cgversion)
1338 cgversion)
1339
1339
1340 if base:
1340 if base:
1341 if dest:
1341 if dest:
1342 raise error.Abort(_("--base is incompatible with specifying "
1342 raise error.Abort(_("--base is incompatible with specifying "
1343 "a destination"))
1343 "a destination"))
1344 common = [repo.lookup(rev) for rev in base]
1344 common = [repo.lookup(rev) for rev in base]
1345 heads = revs and map(repo.lookup, revs) or None
1345 heads = revs and map(repo.lookup, revs) or None
1346 outgoing = discovery.outgoing(repo, common, heads)
1346 outgoing = discovery.outgoing(repo, common, heads)
1347 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1347 cg = changegroup.getchangegroup(repo, 'bundle', outgoing,
1348 bundlecaps=bundlecaps,
1348 bundlecaps=bundlecaps,
1349 version=cgversion)
1349 version=cgversion)
1350 outgoing = None
1350 outgoing = None
1351 else:
1351 else:
1352 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1352 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1353 dest, branches = hg.parseurl(dest, opts.get('branch'))
1353 dest, branches = hg.parseurl(dest, opts.get('branch'))
1354 other = hg.peer(repo, opts, dest)
1354 other = hg.peer(repo, opts, dest)
1355 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1355 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1356 heads = revs and map(repo.lookup, revs) or revs
1356 heads = revs and map(repo.lookup, revs) or revs
1357 outgoing = discovery.findcommonoutgoing(repo, other,
1357 outgoing = discovery.findcommonoutgoing(repo, other,
1358 onlyheads=heads,
1358 onlyheads=heads,
1359 force=opts.get('force'),
1359 force=opts.get('force'),
1360 portable=True)
1360 portable=True)
1361 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1361 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1362 bundlecaps, version=cgversion)
1362 bundlecaps, version=cgversion)
1363 if not cg:
1363 if not cg:
1364 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1364 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1365 return 1
1365 return 1
1366
1366
1367 if cgversion == '01': #bundle1
1367 if cgversion == '01': #bundle1
1368 if bcompression is None:
1368 if bcompression is None:
1369 bcompression = 'UN'
1369 bcompression = 'UN'
1370 bversion = 'HG10' + bcompression
1370 bversion = 'HG10' + bcompression
1371 bcompression = None
1371 bcompression = None
1372 else:
1372 else:
1373 assert cgversion == '02'
1373 assert cgversion == '02'
1374 bversion = 'HG20'
1374 bversion = 'HG20'
1375
1375
1376 # TODO compression options should be derived from bundlespec parsing.
1376 # TODO compression options should be derived from bundlespec parsing.
1377 # This is a temporary hack to allow adjusting bundle compression
1377 # This is a temporary hack to allow adjusting bundle compression
1378 # level without a) formalizing the bundlespec changes to declare it
1378 # level without a) formalizing the bundlespec changes to declare it
1379 # b) introducing a command flag.
1379 # b) introducing a command flag.
1380 compopts = {}
1380 compopts = {}
1381 complevel = ui.configint('experimental', 'bundlecomplevel')
1381 complevel = ui.configint('experimental', 'bundlecomplevel')
1382 if complevel is not None:
1382 if complevel is not None:
1383 compopts['level'] = complevel
1383 compopts['level'] = complevel
1384
1384
1385 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1385 bundle2.writebundle(ui, cg, fname, bversion, compression=bcompression,
1386 compopts=compopts)
1386 compopts=compopts)
1387
1387
1388 @command('cat',
1388 @command('cat',
1389 [('o', 'output', '',
1389 [('o', 'output', '',
1390 _('print output to file with formatted name'), _('FORMAT')),
1390 _('print output to file with formatted name'), _('FORMAT')),
1391 ('r', 'rev', '', _('print the given revision'), _('REV')),
1391 ('r', 'rev', '', _('print the given revision'), _('REV')),
1392 ('', 'decode', None, _('apply any matching decode filter')),
1392 ('', 'decode', None, _('apply any matching decode filter')),
1393 ] + walkopts,
1393 ] + walkopts,
1394 _('[OPTION]... FILE...'),
1394 _('[OPTION]... FILE...'),
1395 inferrepo=True)
1395 inferrepo=True)
1396 def cat(ui, repo, file1, *pats, **opts):
1396 def cat(ui, repo, file1, *pats, **opts):
1397 """output the current or given revision of files
1397 """output the current or given revision of files
1398
1398
1399 Print the specified files as they were at the given revision. If
1399 Print the specified files as they were at the given revision. If
1400 no revision is given, the parent of the working directory is used.
1400 no revision is given, the parent of the working directory is used.
1401
1401
1402 Output may be to a file, in which case the name of the file is
1402 Output may be to a file, in which case the name of the file is
1403 given using a format string. The formatting rules as follows:
1403 given using a format string. The formatting rules as follows:
1404
1404
1405 :``%%``: literal "%" character
1405 :``%%``: literal "%" character
1406 :``%s``: basename of file being printed
1406 :``%s``: basename of file being printed
1407 :``%d``: dirname of file being printed, or '.' if in repository root
1407 :``%d``: dirname of file being printed, or '.' if in repository root
1408 :``%p``: root-relative path name of file being printed
1408 :``%p``: root-relative path name of file being printed
1409 :``%H``: changeset hash (40 hexadecimal digits)
1409 :``%H``: changeset hash (40 hexadecimal digits)
1410 :``%R``: changeset revision number
1410 :``%R``: changeset revision number
1411 :``%h``: short-form changeset hash (12 hexadecimal digits)
1411 :``%h``: short-form changeset hash (12 hexadecimal digits)
1412 :``%r``: zero-padded changeset revision number
1412 :``%r``: zero-padded changeset revision number
1413 :``%b``: basename of the exporting repository
1413 :``%b``: basename of the exporting repository
1414
1414
1415 Returns 0 on success.
1415 Returns 0 on success.
1416 """
1416 """
1417 ctx = scmutil.revsingle(repo, opts.get('rev'))
1417 ctx = scmutil.revsingle(repo, opts.get('rev'))
1418 m = scmutil.match(ctx, (file1,) + pats, opts)
1418 m = scmutil.match(ctx, (file1,) + pats, opts)
1419
1419
1420 ui.pager('cat')
1420 ui.pager('cat')
1421 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1421 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1422
1422
1423 @command('^clone',
1423 @command('^clone',
1424 [('U', 'noupdate', None, _('the clone will include an empty working '
1424 [('U', 'noupdate', None, _('the clone will include an empty working '
1425 'directory (only a repository)')),
1425 'directory (only a repository)')),
1426 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1426 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1427 _('REV')),
1427 _('REV')),
1428 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1428 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1429 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1429 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1430 ('', 'pull', None, _('use pull protocol to copy metadata')),
1431 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1431 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1432 ] + remoteopts,
1432 ] + remoteopts,
1433 _('[OPTION]... SOURCE [DEST]'),
1433 _('[OPTION]... SOURCE [DEST]'),
1434 norepo=True)
1434 norepo=True)
1435 def clone(ui, source, dest=None, **opts):
1435 def clone(ui, source, dest=None, **opts):
1436 """make a copy of an existing repository
1436 """make a copy of an existing repository
1437
1437
1438 Create a copy of an existing repository in a new directory.
1438 Create a copy of an existing repository in a new directory.
1439
1439
1440 If no destination directory name is specified, it defaults to the
1440 If no destination directory name is specified, it defaults to the
1441 basename of the source.
1441 basename of the source.
1442
1442
1443 The location of the source is added to the new repository's
1443 The location of the source is added to the new repository's
1444 ``.hg/hgrc`` file, as the default to be used for future pulls.
1444 ``.hg/hgrc`` file, as the default to be used for future pulls.
1445
1445
1446 Only local paths and ``ssh://`` URLs are supported as
1446 Only local paths and ``ssh://`` URLs are supported as
1447 destinations. For ``ssh://`` destinations, no working directory or
1447 destinations. For ``ssh://`` destinations, no working directory or
1448 ``.hg/hgrc`` will be created on the remote side.
1448 ``.hg/hgrc`` will be created on the remote side.
1449
1449
1450 If the source repository has a bookmark called '@' set, that
1450 If the source repository has a bookmark called '@' set, that
1451 revision will be checked out in the new repository by default.
1451 revision will be checked out in the new repository by default.
1452
1452
1453 To check out a particular version, use -u/--update, or
1453 To check out a particular version, use -u/--update, or
1454 -U/--noupdate to create a clone with no working directory.
1454 -U/--noupdate to create a clone with no working directory.
1455
1455
1456 To pull only a subset of changesets, specify one or more revisions
1456 To pull only a subset of changesets, specify one or more revisions
1457 identifiers with -r/--rev or branches with -b/--branch. The
1457 identifiers with -r/--rev or branches with -b/--branch. The
1458 resulting clone will contain only the specified changesets and
1458 resulting clone will contain only the specified changesets and
1459 their ancestors. These options (or 'clone src#rev dest') imply
1459 their ancestors. These options (or 'clone src#rev dest') imply
1460 --pull, even for local source repositories.
1460 --pull, even for local source repositories.
1461
1461
1462 .. note::
1462 .. note::
1463
1463
1464 Specifying a tag will include the tagged changeset but not the
1464 Specifying a tag will include the tagged changeset but not the
1465 changeset containing the tag.
1465 changeset containing the tag.
1466
1466
1467 .. container:: verbose
1467 .. container:: verbose
1468
1468
1469 For efficiency, hardlinks are used for cloning whenever the
1469 For efficiency, hardlinks are used for cloning whenever the
1470 source and destination are on the same filesystem (note this
1470 source and destination are on the same filesystem (note this
1471 applies only to the repository data, not to the working
1471 applies only to the repository data, not to the working
1472 directory). Some filesystems, such as AFS, implement hardlinking
1472 directory). Some filesystems, such as AFS, implement hardlinking
1473 incorrectly, but do not report errors. In these cases, use the
1473 incorrectly, but do not report errors. In these cases, use the
1474 --pull option to avoid hardlinking.
1474 --pull option to avoid hardlinking.
1475
1475
1476 In some cases, you can clone repositories and the working
1476 In some cases, you can clone repositories and the working
1477 directory using full hardlinks with ::
1477 directory using full hardlinks with ::
1478
1478
1479 $ cp -al REPO REPOCLONE
1479 $ cp -al REPO REPOCLONE
1480
1480
1481 This is the fastest way to clone, but it is not always safe. The
1481 This is the fastest way to clone, but it is not always safe. The
1482 operation is not atomic (making sure REPO is not modified during
1482 operation is not atomic (making sure REPO is not modified during
1483 the operation is up to you) and you have to make sure your
1483 the operation is up to you) and you have to make sure your
1484 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1484 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1485 so). Also, this is not compatible with certain extensions that
1485 so). Also, this is not compatible with certain extensions that
1486 place their metadata under the .hg directory, such as mq.
1486 place their metadata under the .hg directory, such as mq.
1487
1487
1488 Mercurial will update the working directory to the first applicable
1488 Mercurial will update the working directory to the first applicable
1489 revision from this list:
1489 revision from this list:
1490
1490
1491 a) null if -U or the source repository has no changesets
1491 a) null if -U or the source repository has no changesets
1492 b) if -u . and the source repository is local, the first parent of
1492 b) if -u . and the source repository is local, the first parent of
1493 the source repository's working directory
1493 the source repository's working directory
1494 c) the changeset specified with -u (if a branch name, this means the
1494 c) the changeset specified with -u (if a branch name, this means the
1495 latest head of that branch)
1495 latest head of that branch)
1496 d) the changeset specified with -r
1496 d) the changeset specified with -r
1497 e) the tipmost head specified with -b
1497 e) the tipmost head specified with -b
1498 f) the tipmost head specified with the url#branch source syntax
1498 f) the tipmost head specified with the url#branch source syntax
1499 g) the revision marked with the '@' bookmark, if present
1499 g) the revision marked with the '@' bookmark, if present
1500 h) the tipmost head of the default branch
1500 h) the tipmost head of the default branch
1501 i) tip
1501 i) tip
1502
1502
1503 When cloning from servers that support it, Mercurial may fetch
1503 When cloning from servers that support it, Mercurial may fetch
1504 pre-generated data from a server-advertised URL. When this is done,
1504 pre-generated data from a server-advertised URL. When this is done,
1505 hooks operating on incoming changesets and changegroups may fire twice,
1505 hooks operating on incoming changesets and changegroups may fire twice,
1506 once for the bundle fetched from the URL and another for any additional
1506 once for the bundle fetched from the URL and another for any additional
1507 data not fetched from this URL. In addition, if an error occurs, the
1507 data not fetched from this URL. In addition, if an error occurs, the
1508 repository may be rolled back to a partial clone. This behavior may
1508 repository may be rolled back to a partial clone. This behavior may
1509 change in future releases. See :hg:`help -e clonebundles` for more.
1509 change in future releases. See :hg:`help -e clonebundles` for more.
1510
1510
1511 Examples:
1511 Examples:
1512
1512
1513 - clone a remote repository to a new directory named hg/::
1513 - clone a remote repository to a new directory named hg/::
1514
1514
1515 hg clone https://www.mercurial-scm.org/repo/hg/
1515 hg clone https://www.mercurial-scm.org/repo/hg/
1516
1516
1517 - create a lightweight local clone::
1517 - create a lightweight local clone::
1518
1518
1519 hg clone project/ project-feature/
1519 hg clone project/ project-feature/
1520
1520
1521 - clone from an absolute path on an ssh server (note double-slash)::
1521 - clone from an absolute path on an ssh server (note double-slash)::
1522
1522
1523 hg clone ssh://user@server//home/projects/alpha/
1523 hg clone ssh://user@server//home/projects/alpha/
1524
1524
1525 - do a high-speed clone over a LAN while checking out a
1525 - do a high-speed clone over a LAN while checking out a
1526 specified version::
1526 specified version::
1527
1527
1528 hg clone --uncompressed http://server/repo -u 1.5
1528 hg clone --uncompressed http://server/repo -u 1.5
1529
1529
1530 - create a repository without changesets after a particular revision::
1530 - create a repository without changesets after a particular revision::
1531
1531
1532 hg clone -r 04e544 experimental/ good/
1532 hg clone -r 04e544 experimental/ good/
1533
1533
1534 - clone (and track) a particular named branch::
1534 - clone (and track) a particular named branch::
1535
1535
1536 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1536 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1537
1537
1538 See :hg:`help urls` for details on specifying URLs.
1538 See :hg:`help urls` for details on specifying URLs.
1539
1539
1540 Returns 0 on success.
1540 Returns 0 on success.
1541 """
1541 """
1542 if opts.get('noupdate') and opts.get('updaterev'):
1542 if opts.get('noupdate') and opts.get('updaterev'):
1543 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1543 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1544
1544
1545 r = hg.clone(ui, opts, source, dest,
1545 r = hg.clone(ui, opts, source, dest,
1546 pull=opts.get('pull'),
1546 pull=opts.get('pull'),
1547 stream=opts.get('uncompressed'),
1547 stream=opts.get('uncompressed'),
1548 rev=opts.get('rev'),
1548 rev=opts.get('rev'),
1549 update=opts.get('updaterev') or not opts.get('noupdate'),
1549 update=opts.get('updaterev') or not opts.get('noupdate'),
1550 branch=opts.get('branch'),
1550 branch=opts.get('branch'),
1551 shareopts=opts.get('shareopts'))
1551 shareopts=opts.get('shareopts'))
1552
1552
1553 return r is None
1553 return r is None
1554
1554
1555 @command('^commit|ci',
1555 @command('^commit|ci',
1556 [('A', 'addremove', None,
1556 [('A', 'addremove', None,
1557 _('mark new/missing files as added/removed before committing')),
1557 _('mark new/missing files as added/removed before committing')),
1558 ('', 'close-branch', None,
1558 ('', 'close-branch', None,
1559 _('mark a branch head as closed')),
1559 _('mark a branch head as closed')),
1560 ('', 'amend', None, _('amend the parent of the working directory')),
1560 ('', 'amend', None, _('amend the parent of the working directory')),
1561 ('s', 'secret', None, _('use the secret phase for committing')),
1561 ('s', 'secret', None, _('use the secret phase for committing')),
1562 ('e', 'edit', None, _('invoke editor on commit messages')),
1562 ('e', 'edit', None, _('invoke editor on commit messages')),
1563 ('i', 'interactive', None, _('use interactive mode')),
1563 ('i', 'interactive', None, _('use interactive mode')),
1564 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1564 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1565 _('[OPTION]... [FILE]...'),
1565 _('[OPTION]... [FILE]...'),
1566 inferrepo=True)
1566 inferrepo=True)
1567 def commit(ui, repo, *pats, **opts):
1567 def commit(ui, repo, *pats, **opts):
1568 """commit the specified files or all outstanding changes
1568 """commit the specified files or all outstanding changes
1569
1569
1570 Commit changes to the given files into the repository. Unlike a
1570 Commit changes to the given files into the repository. Unlike a
1571 centralized SCM, this operation is a local operation. See
1571 centralized SCM, this operation is a local operation. See
1572 :hg:`push` for a way to actively distribute your changes.
1572 :hg:`push` for a way to actively distribute your changes.
1573
1573
1574 If a list of files is omitted, all changes reported by :hg:`status`
1574 If a list of files is omitted, all changes reported by :hg:`status`
1575 will be committed.
1575 will be committed.
1576
1576
1577 If you are committing the result of a merge, do not provide any
1577 If you are committing the result of a merge, do not provide any
1578 filenames or -I/-X filters.
1578 filenames or -I/-X filters.
1579
1579
1580 If no commit message is specified, Mercurial starts your
1580 If no commit message is specified, Mercurial starts your
1581 configured editor where you can enter a message. In case your
1581 configured editor where you can enter a message. In case your
1582 commit fails, you will find a backup of your message in
1582 commit fails, you will find a backup of your message in
1583 ``.hg/last-message.txt``.
1583 ``.hg/last-message.txt``.
1584
1584
1585 The --close-branch flag can be used to mark the current branch
1585 The --close-branch flag can be used to mark the current branch
1586 head closed. When all heads of a branch are closed, the branch
1586 head closed. When all heads of a branch are closed, the branch
1587 will be considered closed and no longer listed.
1587 will be considered closed and no longer listed.
1588
1588
1589 The --amend flag can be used to amend the parent of the
1589 The --amend flag can be used to amend the parent of the
1590 working directory with a new commit that contains the changes
1590 working directory with a new commit that contains the changes
1591 in the parent in addition to those currently reported by :hg:`status`,
1591 in the parent in addition to those currently reported by :hg:`status`,
1592 if there are any. The old commit is stored in a backup bundle in
1592 if there are any. The old commit is stored in a backup bundle in
1593 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1593 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1594 on how to restore it).
1594 on how to restore it).
1595
1595
1596 Message, user and date are taken from the amended commit unless
1596 Message, user and date are taken from the amended commit unless
1597 specified. When a message isn't specified on the command line,
1597 specified. When a message isn't specified on the command line,
1598 the editor will open with the message of the amended commit.
1598 the editor will open with the message of the amended commit.
1599
1599
1600 It is not possible to amend public changesets (see :hg:`help phases`)
1600 It is not possible to amend public changesets (see :hg:`help phases`)
1601 or changesets that have children.
1601 or changesets that have children.
1602
1602
1603 See :hg:`help dates` for a list of formats valid for -d/--date.
1603 See :hg:`help dates` for a list of formats valid for -d/--date.
1604
1604
1605 Returns 0 on success, 1 if nothing changed.
1605 Returns 0 on success, 1 if nothing changed.
1606
1606
1607 .. container:: verbose
1607 .. container:: verbose
1608
1608
1609 Examples:
1609 Examples:
1610
1610
1611 - commit all files ending in .py::
1611 - commit all files ending in .py::
1612
1612
1613 hg commit --include "set:**.py"
1613 hg commit --include "set:**.py"
1614
1614
1615 - commit all non-binary files::
1615 - commit all non-binary files::
1616
1616
1617 hg commit --exclude "set:binary()"
1617 hg commit --exclude "set:binary()"
1618
1618
1619 - amend the current commit and set the date to now::
1619 - amend the current commit and set the date to now::
1620
1620
1621 hg commit --amend --date now
1621 hg commit --amend --date now
1622 """
1622 """
1623 wlock = lock = None
1623 wlock = lock = None
1624 try:
1624 try:
1625 wlock = repo.wlock()
1625 wlock = repo.wlock()
1626 lock = repo.lock()
1626 lock = repo.lock()
1627 return _docommit(ui, repo, *pats, **opts)
1627 return _docommit(ui, repo, *pats, **opts)
1628 finally:
1628 finally:
1629 release(lock, wlock)
1629 release(lock, wlock)
1630
1630
1631 def _docommit(ui, repo, *pats, **opts):
1631 def _docommit(ui, repo, *pats, **opts):
1632 if opts.get('interactive'):
1632 if opts.get('interactive'):
1633 opts.pop('interactive')
1633 opts.pop('interactive')
1634 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1634 ret = cmdutil.dorecord(ui, repo, commit, None, False,
1635 cmdutil.recordfilter, *pats, **opts)
1635 cmdutil.recordfilter, *pats, **opts)
1636 # ret can be 0 (no changes to record) or the value returned by
1636 # ret can be 0 (no changes to record) or the value returned by
1637 # commit(), 1 if nothing changed or None on success.
1637 # commit(), 1 if nothing changed or None on success.
1638 return 1 if ret == 0 else ret
1638 return 1 if ret == 0 else ret
1639
1639
1640 if opts.get('subrepos'):
1640 if opts.get('subrepos'):
1641 if opts.get('amend'):
1641 if opts.get('amend'):
1642 raise error.Abort(_('cannot amend with --subrepos'))
1642 raise error.Abort(_('cannot amend with --subrepos'))
1643 # Let --subrepos on the command line override config setting.
1643 # Let --subrepos on the command line override config setting.
1644 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1644 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1645
1645
1646 cmdutil.checkunfinished(repo, commit=True)
1646 cmdutil.checkunfinished(repo, commit=True)
1647
1647
1648 branch = repo[None].branch()
1648 branch = repo[None].branch()
1649 bheads = repo.branchheads(branch)
1649 bheads = repo.branchheads(branch)
1650
1650
1651 extra = {}
1651 extra = {}
1652 if opts.get('close_branch'):
1652 if opts.get('close_branch'):
1653 extra['close'] = 1
1653 extra['close'] = 1
1654
1654
1655 if not bheads:
1655 if not bheads:
1656 raise error.Abort(_('can only close branch heads'))
1656 raise error.Abort(_('can only close branch heads'))
1657 elif opts.get('amend'):
1657 elif opts.get('amend'):
1658 if repo[None].parents()[0].p1().branch() != branch and \
1658 if repo[None].parents()[0].p1().branch() != branch and \
1659 repo[None].parents()[0].p2().branch() != branch:
1659 repo[None].parents()[0].p2().branch() != branch:
1660 raise error.Abort(_('can only close branch heads'))
1660 raise error.Abort(_('can only close branch heads'))
1661
1661
1662 if opts.get('amend'):
1662 if opts.get('amend'):
1663 if ui.configbool('ui', 'commitsubrepos'):
1663 if ui.configbool('ui', 'commitsubrepos'):
1664 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1664 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1665
1665
1666 old = repo['.']
1666 old = repo['.']
1667 if not old.mutable():
1667 if not old.mutable():
1668 raise error.Abort(_('cannot amend public changesets'))
1668 raise error.Abort(_('cannot amend public changesets'))
1669 if len(repo[None].parents()) > 1:
1669 if len(repo[None].parents()) > 1:
1670 raise error.Abort(_('cannot amend while merging'))
1670 raise error.Abort(_('cannot amend while merging'))
1671 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1671 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1672 if not allowunstable and old.children():
1672 if not allowunstable and old.children():
1673 raise error.Abort(_('cannot amend changeset with children'))
1673 raise error.Abort(_('cannot amend changeset with children'))
1674
1674
1675 # Currently histedit gets confused if an amend happens while histedit
1675 # Currently histedit gets confused if an amend happens while histedit
1676 # is in progress. Since we have a checkunfinished command, we are
1676 # is in progress. Since we have a checkunfinished command, we are
1677 # temporarily honoring it.
1677 # temporarily honoring it.
1678 #
1678 #
1679 # Note: eventually this guard will be removed. Please do not expect
1679 # Note: eventually this guard will be removed. Please do not expect
1680 # this behavior to remain.
1680 # this behavior to remain.
1681 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1681 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
1682 cmdutil.checkunfinished(repo)
1682 cmdutil.checkunfinished(repo)
1683
1683
1684 # commitfunc is used only for temporary amend commit by cmdutil.amend
1684 # commitfunc is used only for temporary amend commit by cmdutil.amend
1685 def commitfunc(ui, repo, message, match, opts):
1685 def commitfunc(ui, repo, message, match, opts):
1686 return repo.commit(message,
1686 return repo.commit(message,
1687 opts.get('user') or old.user(),
1687 opts.get('user') or old.user(),
1688 opts.get('date') or old.date(),
1688 opts.get('date') or old.date(),
1689 match,
1689 match,
1690 extra=extra)
1690 extra=extra)
1691
1691
1692 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1692 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1693 if node == old.node():
1693 if node == old.node():
1694 ui.status(_("nothing changed\n"))
1694 ui.status(_("nothing changed\n"))
1695 return 1
1695 return 1
1696 else:
1696 else:
1697 def commitfunc(ui, repo, message, match, opts):
1697 def commitfunc(ui, repo, message, match, opts):
1698 backup = ui.backupconfig('phases', 'new-commit')
1698 backup = ui.backupconfig('phases', 'new-commit')
1699 baseui = repo.baseui
1699 baseui = repo.baseui
1700 basebackup = baseui.backupconfig('phases', 'new-commit')
1700 basebackup = baseui.backupconfig('phases', 'new-commit')
1701 try:
1701 try:
1702 if opts.get('secret'):
1702 if opts.get('secret'):
1703 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1703 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1704 # Propagate to subrepos
1704 # Propagate to subrepos
1705 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1705 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1706
1706
1707 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1707 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1708 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1708 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1709 return repo.commit(message, opts.get('user'), opts.get('date'),
1709 return repo.commit(message, opts.get('user'), opts.get('date'),
1710 match,
1710 match,
1711 editor=editor,
1711 editor=editor,
1712 extra=extra)
1712 extra=extra)
1713 finally:
1713 finally:
1714 ui.restoreconfig(backup)
1714 ui.restoreconfig(backup)
1715 repo.baseui.restoreconfig(basebackup)
1715 repo.baseui.restoreconfig(basebackup)
1716
1716
1717
1717
1718 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1718 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1719
1719
1720 if not node:
1720 if not node:
1721 stat = cmdutil.postcommitstatus(repo, pats, opts)
1721 stat = cmdutil.postcommitstatus(repo, pats, opts)
1722 if stat[3]:
1722 if stat[3]:
1723 ui.status(_("nothing changed (%d missing files, see "
1723 ui.status(_("nothing changed (%d missing files, see "
1724 "'hg status')\n") % len(stat[3]))
1724 "'hg status')\n") % len(stat[3]))
1725 else:
1725 else:
1726 ui.status(_("nothing changed\n"))
1726 ui.status(_("nothing changed\n"))
1727 return 1
1727 return 1
1728
1728
1729 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1729 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1730
1730
1731 @command('config|showconfig|debugconfig',
1731 @command('config|showconfig|debugconfig',
1732 [('u', 'untrusted', None, _('show untrusted configuration options')),
1732 [('u', 'untrusted', None, _('show untrusted configuration options')),
1733 ('e', 'edit', None, _('edit user config')),
1733 ('e', 'edit', None, _('edit user config')),
1734 ('l', 'local', None, _('edit repository config')),
1734 ('l', 'local', None, _('edit repository config')),
1735 ('g', 'global', None, _('edit global config'))] + formatteropts,
1735 ('g', 'global', None, _('edit global config'))] + formatteropts,
1736 _('[-u] [NAME]...'),
1736 _('[-u] [NAME]...'),
1737 optionalrepo=True)
1737 optionalrepo=True)
1738 def config(ui, repo, *values, **opts):
1738 def config(ui, repo, *values, **opts):
1739 """show combined config settings from all hgrc files
1739 """show combined config settings from all hgrc files
1740
1740
1741 With no arguments, print names and values of all config items.
1741 With no arguments, print names and values of all config items.
1742
1742
1743 With one argument of the form section.name, print just the value
1743 With one argument of the form section.name, print just the value
1744 of that config item.
1744 of that config item.
1745
1745
1746 With multiple arguments, print names and values of all config
1746 With multiple arguments, print names and values of all config
1747 items with matching section names.
1747 items with matching section names.
1748
1748
1749 With --edit, start an editor on the user-level config file. With
1749 With --edit, start an editor on the user-level config file. With
1750 --global, edit the system-wide config file. With --local, edit the
1750 --global, edit the system-wide config file. With --local, edit the
1751 repository-level config file.
1751 repository-level config file.
1752
1752
1753 With --debug, the source (filename and line number) is printed
1753 With --debug, the source (filename and line number) is printed
1754 for each config item.
1754 for each config item.
1755
1755
1756 See :hg:`help config` for more information about config files.
1756 See :hg:`help config` for more information about config files.
1757
1757
1758 Returns 0 on success, 1 if NAME does not exist.
1758 Returns 0 on success, 1 if NAME does not exist.
1759
1759
1760 """
1760 """
1761
1761
1762 if opts.get('edit') or opts.get('local') or opts.get('global'):
1762 if opts.get('edit') or opts.get('local') or opts.get('global'):
1763 if opts.get('local') and opts.get('global'):
1763 if opts.get('local') and opts.get('global'):
1764 raise error.Abort(_("can't use --local and --global together"))
1764 raise error.Abort(_("can't use --local and --global together"))
1765
1765
1766 if opts.get('local'):
1766 if opts.get('local'):
1767 if not repo:
1767 if not repo:
1768 raise error.Abort(_("can't use --local outside a repository"))
1768 raise error.Abort(_("can't use --local outside a repository"))
1769 paths = [repo.join('hgrc')]
1769 paths = [repo.join('hgrc')]
1770 elif opts.get('global'):
1770 elif opts.get('global'):
1771 paths = scmutil.systemrcpath()
1771 paths = scmutil.systemrcpath()
1772 else:
1772 else:
1773 paths = scmutil.userrcpath()
1773 paths = scmutil.userrcpath()
1774
1774
1775 for f in paths:
1775 for f in paths:
1776 if os.path.exists(f):
1776 if os.path.exists(f):
1777 break
1777 break
1778 else:
1778 else:
1779 if opts.get('global'):
1779 if opts.get('global'):
1780 samplehgrc = uimod.samplehgrcs['global']
1780 samplehgrc = uimod.samplehgrcs['global']
1781 elif opts.get('local'):
1781 elif opts.get('local'):
1782 samplehgrc = uimod.samplehgrcs['local']
1782 samplehgrc = uimod.samplehgrcs['local']
1783 else:
1783 else:
1784 samplehgrc = uimod.samplehgrcs['user']
1784 samplehgrc = uimod.samplehgrcs['user']
1785
1785
1786 f = paths[0]
1786 f = paths[0]
1787 fp = open(f, "w")
1787 fp = open(f, "w")
1788 fp.write(samplehgrc)
1788 fp.write(samplehgrc)
1789 fp.close()
1789 fp.close()
1790
1790
1791 editor = ui.geteditor()
1791 editor = ui.geteditor()
1792 ui.system("%s \"%s\"" % (editor, f),
1792 ui.system("%s \"%s\"" % (editor, f),
1793 onerr=error.Abort, errprefix=_("edit failed"))
1793 onerr=error.Abort, errprefix=_("edit failed"))
1794 return
1794 return
1795 ui.pager('config')
1795 ui.pager('config')
1796 fm = ui.formatter('config', opts)
1796 fm = ui.formatter('config', opts)
1797 for f in scmutil.rcpath():
1797 for f in scmutil.rcpath():
1798 ui.debug('read config from: %s\n' % f)
1798 ui.debug('read config from: %s\n' % f)
1799 untrusted = bool(opts.get('untrusted'))
1799 untrusted = bool(opts.get('untrusted'))
1800 if values:
1800 if values:
1801 sections = [v for v in values if '.' not in v]
1801 sections = [v for v in values if '.' not in v]
1802 items = [v for v in values if '.' in v]
1802 items = [v for v in values if '.' in v]
1803 if len(items) > 1 or items and sections:
1803 if len(items) > 1 or items and sections:
1804 raise error.Abort(_('only one config item permitted'))
1804 raise error.Abort(_('only one config item permitted'))
1805 matched = False
1805 matched = False
1806 for section, name, value in ui.walkconfig(untrusted=untrusted):
1806 for section, name, value in ui.walkconfig(untrusted=untrusted):
1807 source = ui.configsource(section, name, untrusted)
1807 source = ui.configsource(section, name, untrusted)
1808 value = str(value)
1808 value = str(value)
1809 if fm.isplain():
1809 if fm.isplain():
1810 source = source or 'none'
1810 source = source or 'none'
1811 value = value.replace('\n', '\\n')
1811 value = value.replace('\n', '\\n')
1812 entryname = section + '.' + name
1812 entryname = section + '.' + name
1813 if values:
1813 if values:
1814 for v in values:
1814 for v in values:
1815 if v == section:
1815 if v == section:
1816 fm.startitem()
1816 fm.startitem()
1817 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1817 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1818 fm.write('name value', '%s=%s\n', entryname, value)
1818 fm.write('name value', '%s=%s\n', entryname, value)
1819 matched = True
1819 matched = True
1820 elif v == entryname:
1820 elif v == entryname:
1821 fm.startitem()
1821 fm.startitem()
1822 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1822 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1823 fm.write('value', '%s\n', value)
1823 fm.write('value', '%s\n', value)
1824 fm.data(name=entryname)
1824 fm.data(name=entryname)
1825 matched = True
1825 matched = True
1826 else:
1826 else:
1827 fm.startitem()
1827 fm.startitem()
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1828 fm.condwrite(ui.debugflag, 'source', '%s: ', source)
1829 fm.write('name value', '%s=%s\n', entryname, value)
1829 fm.write('name value', '%s=%s\n', entryname, value)
1830 matched = True
1830 matched = True
1831 fm.end()
1831 fm.end()
1832 if matched:
1832 if matched:
1833 return 0
1833 return 0
1834 return 1
1834 return 1
1835
1835
1836 @command('copy|cp',
1836 @command('copy|cp',
1837 [('A', 'after', None, _('record a copy that has already occurred')),
1837 [('A', 'after', None, _('record a copy that has already occurred')),
1838 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1838 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1839 ] + walkopts + dryrunopts,
1839 ] + walkopts + dryrunopts,
1840 _('[OPTION]... [SOURCE]... DEST'))
1840 _('[OPTION]... [SOURCE]... DEST'))
1841 def copy(ui, repo, *pats, **opts):
1841 def copy(ui, repo, *pats, **opts):
1842 """mark files as copied for the next commit
1842 """mark files as copied for the next commit
1843
1843
1844 Mark dest as having copies of source files. If dest is a
1844 Mark dest as having copies of source files. If dest is a
1845 directory, copies are put in that directory. If dest is a file,
1845 directory, copies are put in that directory. If dest is a file,
1846 the source must be a single file.
1846 the source must be a single file.
1847
1847
1848 By default, this command copies the contents of files as they
1848 By default, this command copies the contents of files as they
1849 exist in the working directory. If invoked with -A/--after, the
1849 exist in the working directory. If invoked with -A/--after, the
1850 operation is recorded, but no copying is performed.
1850 operation is recorded, but no copying is performed.
1851
1851
1852 This command takes effect with the next commit. To undo a copy
1852 This command takes effect with the next commit. To undo a copy
1853 before that, see :hg:`revert`.
1853 before that, see :hg:`revert`.
1854
1854
1855 Returns 0 on success, 1 if errors are encountered.
1855 Returns 0 on success, 1 if errors are encountered.
1856 """
1856 """
1857 with repo.wlock(False):
1857 with repo.wlock(False):
1858 return cmdutil.copy(ui, repo, pats, opts)
1858 return cmdutil.copy(ui, repo, pats, opts)
1859
1859
1860 @command('^diff',
1860 @command('^diff',
1861 [('r', 'rev', [], _('revision'), _('REV')),
1861 [('r', 'rev', [], _('revision'), _('REV')),
1862 ('c', 'change', '', _('change made by revision'), _('REV'))
1862 ('c', 'change', '', _('change made by revision'), _('REV'))
1863 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1863 ] + diffopts + diffopts2 + walkopts + subrepoopts,
1864 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1864 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
1865 inferrepo=True)
1865 inferrepo=True)
1866 def diff(ui, repo, *pats, **opts):
1866 def diff(ui, repo, *pats, **opts):
1867 """diff repository (or selected files)
1867 """diff repository (or selected files)
1868
1868
1869 Show differences between revisions for the specified files.
1869 Show differences between revisions for the specified files.
1870
1870
1871 Differences between files are shown using the unified diff format.
1871 Differences between files are shown using the unified diff format.
1872
1872
1873 .. note::
1873 .. note::
1874
1874
1875 :hg:`diff` may generate unexpected results for merges, as it will
1875 :hg:`diff` may generate unexpected results for merges, as it will
1876 default to comparing against the working directory's first
1876 default to comparing against the working directory's first
1877 parent changeset if no revisions are specified.
1877 parent changeset if no revisions are specified.
1878
1878
1879 When two revision arguments are given, then changes are shown
1879 When two revision arguments are given, then changes are shown
1880 between those revisions. If only one revision is specified then
1880 between those revisions. If only one revision is specified then
1881 that revision is compared to the working directory, and, when no
1881 that revision is compared to the working directory, and, when no
1882 revisions are specified, the working directory files are compared
1882 revisions are specified, the working directory files are compared
1883 to its first parent.
1883 to its first parent.
1884
1884
1885 Alternatively you can specify -c/--change with a revision to see
1885 Alternatively you can specify -c/--change with a revision to see
1886 the changes in that changeset relative to its first parent.
1886 the changes in that changeset relative to its first parent.
1887
1887
1888 Without the -a/--text option, diff will avoid generating diffs of
1888 Without the -a/--text option, diff will avoid generating diffs of
1889 files it detects as binary. With -a, diff will generate a diff
1889 files it detects as binary. With -a, diff will generate a diff
1890 anyway, probably with undesirable results.
1890 anyway, probably with undesirable results.
1891
1891
1892 Use the -g/--git option to generate diffs in the git extended diff
1892 Use the -g/--git option to generate diffs in the git extended diff
1893 format. For more information, read :hg:`help diffs`.
1893 format. For more information, read :hg:`help diffs`.
1894
1894
1895 .. container:: verbose
1895 .. container:: verbose
1896
1896
1897 Examples:
1897 Examples:
1898
1898
1899 - compare a file in the current working directory to its parent::
1899 - compare a file in the current working directory to its parent::
1900
1900
1901 hg diff foo.c
1901 hg diff foo.c
1902
1902
1903 - compare two historical versions of a directory, with rename info::
1903 - compare two historical versions of a directory, with rename info::
1904
1904
1905 hg diff --git -r 1.0:1.2 lib/
1905 hg diff --git -r 1.0:1.2 lib/
1906
1906
1907 - get change stats relative to the last change on some date::
1907 - get change stats relative to the last change on some date::
1908
1908
1909 hg diff --stat -r "date('may 2')"
1909 hg diff --stat -r "date('may 2')"
1910
1910
1911 - diff all newly-added files that contain a keyword::
1911 - diff all newly-added files that contain a keyword::
1912
1912
1913 hg diff "set:added() and grep(GNU)"
1913 hg diff "set:added() and grep(GNU)"
1914
1914
1915 - compare a revision and its parents::
1915 - compare a revision and its parents::
1916
1916
1917 hg diff -c 9353 # compare against first parent
1917 hg diff -c 9353 # compare against first parent
1918 hg diff -r 9353^:9353 # same using revset syntax
1918 hg diff -r 9353^:9353 # same using revset syntax
1919 hg diff -r 9353^2:9353 # compare against the second parent
1919 hg diff -r 9353^2:9353 # compare against the second parent
1920
1920
1921 Returns 0 on success.
1921 Returns 0 on success.
1922 """
1922 """
1923
1923
1924 revs = opts.get('rev')
1924 revs = opts.get('rev')
1925 change = opts.get('change')
1925 change = opts.get('change')
1926 stat = opts.get('stat')
1926 stat = opts.get('stat')
1927 reverse = opts.get('reverse')
1927 reverse = opts.get('reverse')
1928
1928
1929 if revs and change:
1929 if revs and change:
1930 msg = _('cannot specify --rev and --change at the same time')
1930 msg = _('cannot specify --rev and --change at the same time')
1931 raise error.Abort(msg)
1931 raise error.Abort(msg)
1932 elif change:
1932 elif change:
1933 node2 = scmutil.revsingle(repo, change, None).node()
1933 node2 = scmutil.revsingle(repo, change, None).node()
1934 node1 = repo[node2].p1().node()
1934 node1 = repo[node2].p1().node()
1935 else:
1935 else:
1936 node1, node2 = scmutil.revpair(repo, revs)
1936 node1, node2 = scmutil.revpair(repo, revs)
1937
1937
1938 if reverse:
1938 if reverse:
1939 node1, node2 = node2, node1
1939 node1, node2 = node2, node1
1940
1940
1941 diffopts = patch.diffallopts(ui, opts)
1941 diffopts = patch.diffallopts(ui, opts)
1942 m = scmutil.match(repo[node2], pats, opts)
1942 m = scmutil.match(repo[node2], pats, opts)
1943 ui.pager('diff')
1943 ui.pager('diff')
1944 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1944 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1945 listsubrepos=opts.get('subrepos'),
1945 listsubrepos=opts.get('subrepos'),
1946 root=opts.get('root'))
1946 root=opts.get('root'))
1947
1947
1948 @command('^export',
1948 @command('^export',
1949 [('o', 'output', '',
1949 [('o', 'output', '',
1950 _('print output to file with formatted name'), _('FORMAT')),
1950 _('print output to file with formatted name'), _('FORMAT')),
1951 ('', 'switch-parent', None, _('diff against the second parent')),
1951 ('', 'switch-parent', None, _('diff against the second parent')),
1952 ('r', 'rev', [], _('revisions to export'), _('REV')),
1952 ('r', 'rev', [], _('revisions to export'), _('REV')),
1953 ] + diffopts,
1953 ] + diffopts,
1954 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1954 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
1955 def export(ui, repo, *changesets, **opts):
1955 def export(ui, repo, *changesets, **opts):
1956 """dump the header and diffs for one or more changesets
1956 """dump the header and diffs for one or more changesets
1957
1957
1958 Print the changeset header and diffs for one or more revisions.
1958 Print the changeset header and diffs for one or more revisions.
1959 If no revision is given, the parent of the working directory is used.
1959 If no revision is given, the parent of the working directory is used.
1960
1960
1961 The information shown in the changeset header is: author, date,
1961 The information shown in the changeset header is: author, date,
1962 branch name (if non-default), changeset hash, parent(s) and commit
1962 branch name (if non-default), changeset hash, parent(s) and commit
1963 comment.
1963 comment.
1964
1964
1965 .. note::
1965 .. note::
1966
1966
1967 :hg:`export` may generate unexpected diff output for merge
1967 :hg:`export` may generate unexpected diff output for merge
1968 changesets, as it will compare the merge changeset against its
1968 changesets, as it will compare the merge changeset against its
1969 first parent only.
1969 first parent only.
1970
1970
1971 Output may be to a file, in which case the name of the file is
1971 Output may be to a file, in which case the name of the file is
1972 given using a format string. The formatting rules are as follows:
1972 given using a format string. The formatting rules are as follows:
1973
1973
1974 :``%%``: literal "%" character
1974 :``%%``: literal "%" character
1975 :``%H``: changeset hash (40 hexadecimal digits)
1975 :``%H``: changeset hash (40 hexadecimal digits)
1976 :``%N``: number of patches being generated
1976 :``%N``: number of patches being generated
1977 :``%R``: changeset revision number
1977 :``%R``: changeset revision number
1978 :``%b``: basename of the exporting repository
1978 :``%b``: basename of the exporting repository
1979 :``%h``: short-form changeset hash (12 hexadecimal digits)
1979 :``%h``: short-form changeset hash (12 hexadecimal digits)
1980 :``%m``: first line of the commit message (only alphanumeric characters)
1980 :``%m``: first line of the commit message (only alphanumeric characters)
1981 :``%n``: zero-padded sequence number, starting at 1
1981 :``%n``: zero-padded sequence number, starting at 1
1982 :``%r``: zero-padded changeset revision number
1982 :``%r``: zero-padded changeset revision number
1983
1983
1984 Without the -a/--text option, export will avoid generating diffs
1984 Without the -a/--text option, export will avoid generating diffs
1985 of files it detects as binary. With -a, export will generate a
1985 of files it detects as binary. With -a, export will generate a
1986 diff anyway, probably with undesirable results.
1986 diff anyway, probably with undesirable results.
1987
1987
1988 Use the -g/--git option to generate diffs in the git extended diff
1988 Use the -g/--git option to generate diffs in the git extended diff
1989 format. See :hg:`help diffs` for more information.
1989 format. See :hg:`help diffs` for more information.
1990
1990
1991 With the --switch-parent option, the diff will be against the
1991 With the --switch-parent option, the diff will be against the
1992 second parent. It can be useful to review a merge.
1992 second parent. It can be useful to review a merge.
1993
1993
1994 .. container:: verbose
1994 .. container:: verbose
1995
1995
1996 Examples:
1996 Examples:
1997
1997
1998 - use export and import to transplant a bugfix to the current
1998 - use export and import to transplant a bugfix to the current
1999 branch::
1999 branch::
2000
2000
2001 hg export -r 9353 | hg import -
2001 hg export -r 9353 | hg import -
2002
2002
2003 - export all the changesets between two revisions to a file with
2003 - export all the changesets between two revisions to a file with
2004 rename information::
2004 rename information::
2005
2005
2006 hg export --git -r 123:150 > changes.txt
2006 hg export --git -r 123:150 > changes.txt
2007
2007
2008 - split outgoing changes into a series of patches with
2008 - split outgoing changes into a series of patches with
2009 descriptive names::
2009 descriptive names::
2010
2010
2011 hg export -r "outgoing()" -o "%n-%m.patch"
2011 hg export -r "outgoing()" -o "%n-%m.patch"
2012
2012
2013 Returns 0 on success.
2013 Returns 0 on success.
2014 """
2014 """
2015 changesets += tuple(opts.get('rev', []))
2015 changesets += tuple(opts.get('rev', []))
2016 if not changesets:
2016 if not changesets:
2017 changesets = ['.']
2017 changesets = ['.']
2018 revs = scmutil.revrange(repo, changesets)
2018 revs = scmutil.revrange(repo, changesets)
2019 if not revs:
2019 if not revs:
2020 raise error.Abort(_("export requires at least one changeset"))
2020 raise error.Abort(_("export requires at least one changeset"))
2021 if len(revs) > 1:
2021 if len(revs) > 1:
2022 ui.note(_('exporting patches:\n'))
2022 ui.note(_('exporting patches:\n'))
2023 else:
2023 else:
2024 ui.note(_('exporting patch:\n'))
2024 ui.note(_('exporting patch:\n'))
2025 ui.pager('export')
2025 ui.pager('export')
2026 cmdutil.export(repo, revs, template=opts.get('output'),
2026 cmdutil.export(repo, revs, template=opts.get('output'),
2027 switch_parent=opts.get('switch_parent'),
2027 switch_parent=opts.get('switch_parent'),
2028 opts=patch.diffallopts(ui, opts))
2028 opts=patch.diffallopts(ui, opts))
2029
2029
2030 @command('files',
2030 @command('files',
2031 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2031 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
2032 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2032 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
2033 ] + walkopts + formatteropts + subrepoopts,
2033 ] + walkopts + formatteropts + subrepoopts,
2034 _('[OPTION]... [FILE]...'))
2034 _('[OPTION]... [FILE]...'))
2035 def files(ui, repo, *pats, **opts):
2035 def files(ui, repo, *pats, **opts):
2036 """list tracked files
2036 """list tracked files
2037
2037
2038 Print files under Mercurial control in the working directory or
2038 Print files under Mercurial control in the working directory or
2039 specified revision for given files (excluding removed files).
2039 specified revision for given files (excluding removed files).
2040 Files can be specified as filenames or filesets.
2040 Files can be specified as filenames or filesets.
2041
2041
2042 If no files are given to match, this command prints the names
2042 If no files are given to match, this command prints the names
2043 of all files under Mercurial control.
2043 of all files under Mercurial control.
2044
2044
2045 .. container:: verbose
2045 .. container:: verbose
2046
2046
2047 Examples:
2047 Examples:
2048
2048
2049 - list all files under the current directory::
2049 - list all files under the current directory::
2050
2050
2051 hg files .
2051 hg files .
2052
2052
2053 - shows sizes and flags for current revision::
2053 - shows sizes and flags for current revision::
2054
2054
2055 hg files -vr .
2055 hg files -vr .
2056
2056
2057 - list all files named README::
2057 - list all files named README::
2058
2058
2059 hg files -I "**/README"
2059 hg files -I "**/README"
2060
2060
2061 - list all binary files::
2061 - list all binary files::
2062
2062
2063 hg files "set:binary()"
2063 hg files "set:binary()"
2064
2064
2065 - find files containing a regular expression::
2065 - find files containing a regular expression::
2066
2066
2067 hg files "set:grep('bob')"
2067 hg files "set:grep('bob')"
2068
2068
2069 - search tracked file contents with xargs and grep::
2069 - search tracked file contents with xargs and grep::
2070
2070
2071 hg files -0 | xargs -0 grep foo
2071 hg files -0 | xargs -0 grep foo
2072
2072
2073 See :hg:`help patterns` and :hg:`help filesets` for more information
2073 See :hg:`help patterns` and :hg:`help filesets` for more information
2074 on specifying file patterns.
2074 on specifying file patterns.
2075
2075
2076 Returns 0 if a match is found, 1 otherwise.
2076 Returns 0 if a match is found, 1 otherwise.
2077
2077
2078 """
2078 """
2079 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2079 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2080
2080
2081 end = '\n'
2081 end = '\n'
2082 if opts.get('print0'):
2082 if opts.get('print0'):
2083 end = '\0'
2083 end = '\0'
2084 fmt = '%s' + end
2084 fmt = '%s' + end
2085
2085
2086 m = scmutil.match(ctx, pats, opts)
2086 m = scmutil.match(ctx, pats, opts)
2087 ui.pager('files')
2087 ui.pager('files')
2088 with ui.formatter('files', opts) as fm:
2088 with ui.formatter('files', opts) as fm:
2089 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2089 return cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
2090
2090
2091 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2091 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
2092 def forget(ui, repo, *pats, **opts):
2092 def forget(ui, repo, *pats, **opts):
2093 """forget the specified files on the next commit
2093 """forget the specified files on the next commit
2094
2094
2095 Mark the specified files so they will no longer be tracked
2095 Mark the specified files so they will no longer be tracked
2096 after the next commit.
2096 after the next commit.
2097
2097
2098 This only removes files from the current branch, not from the
2098 This only removes files from the current branch, not from the
2099 entire project history, and it does not delete them from the
2099 entire project history, and it does not delete them from the
2100 working directory.
2100 working directory.
2101
2101
2102 To delete the file from the working directory, see :hg:`remove`.
2102 To delete the file from the working directory, see :hg:`remove`.
2103
2103
2104 To undo a forget before the next commit, see :hg:`add`.
2104 To undo a forget before the next commit, see :hg:`add`.
2105
2105
2106 .. container:: verbose
2106 .. container:: verbose
2107
2107
2108 Examples:
2108 Examples:
2109
2109
2110 - forget newly-added binary files::
2110 - forget newly-added binary files::
2111
2111
2112 hg forget "set:added() and binary()"
2112 hg forget "set:added() and binary()"
2113
2113
2114 - forget files that would be excluded by .hgignore::
2114 - forget files that would be excluded by .hgignore::
2115
2115
2116 hg forget "set:hgignore()"
2116 hg forget "set:hgignore()"
2117
2117
2118 Returns 0 on success.
2118 Returns 0 on success.
2119 """
2119 """
2120
2120
2121 if not pats:
2121 if not pats:
2122 raise error.Abort(_('no files specified'))
2122 raise error.Abort(_('no files specified'))
2123
2123
2124 m = scmutil.match(repo[None], pats, opts)
2124 m = scmutil.match(repo[None], pats, opts)
2125 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2125 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2126 return rejected and 1 or 0
2126 return rejected and 1 or 0
2127
2127
2128 @command(
2128 @command(
2129 'graft',
2129 'graft',
2130 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2130 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2131 ('c', 'continue', False, _('resume interrupted graft')),
2131 ('c', 'continue', False, _('resume interrupted graft')),
2132 ('e', 'edit', False, _('invoke editor on commit messages')),
2132 ('e', 'edit', False, _('invoke editor on commit messages')),
2133 ('', 'log', None, _('append graft info to log message')),
2133 ('', 'log', None, _('append graft info to log message')),
2134 ('f', 'force', False, _('force graft')),
2134 ('f', 'force', False, _('force graft')),
2135 ('D', 'currentdate', False,
2135 ('D', 'currentdate', False,
2136 _('record the current date as commit date')),
2136 _('record the current date as commit date')),
2137 ('U', 'currentuser', False,
2137 ('U', 'currentuser', False,
2138 _('record the current user as committer'), _('DATE'))]
2138 _('record the current user as committer'), _('DATE'))]
2139 + commitopts2 + mergetoolopts + dryrunopts,
2139 + commitopts2 + mergetoolopts + dryrunopts,
2140 _('[OPTION]... [-r REV]... REV...'))
2140 _('[OPTION]... [-r REV]... REV...'))
2141 def graft(ui, repo, *revs, **opts):
2141 def graft(ui, repo, *revs, **opts):
2142 '''copy changes from other branches onto the current branch
2142 '''copy changes from other branches onto the current branch
2143
2143
2144 This command uses Mercurial's merge logic to copy individual
2144 This command uses Mercurial's merge logic to copy individual
2145 changes from other branches without merging branches in the
2145 changes from other branches without merging branches in the
2146 history graph. This is sometimes known as 'backporting' or
2146 history graph. This is sometimes known as 'backporting' or
2147 'cherry-picking'. By default, graft will copy user, date, and
2147 'cherry-picking'. By default, graft will copy user, date, and
2148 description from the source changesets.
2148 description from the source changesets.
2149
2149
2150 Changesets that are ancestors of the current revision, that have
2150 Changesets that are ancestors of the current revision, that have
2151 already been grafted, or that are merges will be skipped.
2151 already been grafted, or that are merges will be skipped.
2152
2152
2153 If --log is specified, log messages will have a comment appended
2153 If --log is specified, log messages will have a comment appended
2154 of the form::
2154 of the form::
2155
2155
2156 (grafted from CHANGESETHASH)
2156 (grafted from CHANGESETHASH)
2157
2157
2158 If --force is specified, revisions will be grafted even if they
2158 If --force is specified, revisions will be grafted even if they
2159 are already ancestors of or have been grafted to the destination.
2159 are already ancestors of or have been grafted to the destination.
2160 This is useful when the revisions have since been backed out.
2160 This is useful when the revisions have since been backed out.
2161
2161
2162 If a graft merge results in conflicts, the graft process is
2162 If a graft merge results in conflicts, the graft process is
2163 interrupted so that the current merge can be manually resolved.
2163 interrupted so that the current merge can be manually resolved.
2164 Once all conflicts are addressed, the graft process can be
2164 Once all conflicts are addressed, the graft process can be
2165 continued with the -c/--continue option.
2165 continued with the -c/--continue option.
2166
2166
2167 .. note::
2167 .. note::
2168
2168
2169 The -c/--continue option does not reapply earlier options, except
2169 The -c/--continue option does not reapply earlier options, except
2170 for --force.
2170 for --force.
2171
2171
2172 .. container:: verbose
2172 .. container:: verbose
2173
2173
2174 Examples:
2174 Examples:
2175
2175
2176 - copy a single change to the stable branch and edit its description::
2176 - copy a single change to the stable branch and edit its description::
2177
2177
2178 hg update stable
2178 hg update stable
2179 hg graft --edit 9393
2179 hg graft --edit 9393
2180
2180
2181 - graft a range of changesets with one exception, updating dates::
2181 - graft a range of changesets with one exception, updating dates::
2182
2182
2183 hg graft -D "2085::2093 and not 2091"
2183 hg graft -D "2085::2093 and not 2091"
2184
2184
2185 - continue a graft after resolving conflicts::
2185 - continue a graft after resolving conflicts::
2186
2186
2187 hg graft -c
2187 hg graft -c
2188
2188
2189 - show the source of a grafted changeset::
2189 - show the source of a grafted changeset::
2190
2190
2191 hg log --debug -r .
2191 hg log --debug -r .
2192
2192
2193 - show revisions sorted by date::
2193 - show revisions sorted by date::
2194
2194
2195 hg log -r "sort(all(), date)"
2195 hg log -r "sort(all(), date)"
2196
2196
2197 See :hg:`help revisions` for more about specifying revisions.
2197 See :hg:`help revisions` for more about specifying revisions.
2198
2198
2199 Returns 0 on successful completion.
2199 Returns 0 on successful completion.
2200 '''
2200 '''
2201 with repo.wlock():
2201 with repo.wlock():
2202 return _dograft(ui, repo, *revs, **opts)
2202 return _dograft(ui, repo, *revs, **opts)
2203
2203
2204 def _dograft(ui, repo, *revs, **opts):
2204 def _dograft(ui, repo, *revs, **opts):
2205 if revs and opts.get('rev'):
2205 if revs and opts.get('rev'):
2206 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2206 ui.warn(_('warning: inconsistent use of --rev might give unexpected '
2207 'revision ordering!\n'))
2207 'revision ordering!\n'))
2208
2208
2209 revs = list(revs)
2209 revs = list(revs)
2210 revs.extend(opts.get('rev'))
2210 revs.extend(opts.get('rev'))
2211
2211
2212 if not opts.get('user') and opts.get('currentuser'):
2212 if not opts.get('user') and opts.get('currentuser'):
2213 opts['user'] = ui.username()
2213 opts['user'] = ui.username()
2214 if not opts.get('date') and opts.get('currentdate'):
2214 if not opts.get('date') and opts.get('currentdate'):
2215 opts['date'] = "%d %d" % util.makedate()
2215 opts['date'] = "%d %d" % util.makedate()
2216
2216
2217 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2217 editor = cmdutil.getcommiteditor(editform='graft', **opts)
2218
2218
2219 cont = False
2219 cont = False
2220 if opts.get('continue'):
2220 if opts.get('continue'):
2221 cont = True
2221 cont = True
2222 if revs:
2222 if revs:
2223 raise error.Abort(_("can't specify --continue and revisions"))
2223 raise error.Abort(_("can't specify --continue and revisions"))
2224 # read in unfinished revisions
2224 # read in unfinished revisions
2225 try:
2225 try:
2226 nodes = repo.vfs.read('graftstate').splitlines()
2226 nodes = repo.vfs.read('graftstate').splitlines()
2227 revs = [repo[node].rev() for node in nodes]
2227 revs = [repo[node].rev() for node in nodes]
2228 except IOError as inst:
2228 except IOError as inst:
2229 if inst.errno != errno.ENOENT:
2229 if inst.errno != errno.ENOENT:
2230 raise
2230 raise
2231 cmdutil.wrongtooltocontinue(repo, _('graft'))
2231 cmdutil.wrongtooltocontinue(repo, _('graft'))
2232 else:
2232 else:
2233 cmdutil.checkunfinished(repo)
2233 cmdutil.checkunfinished(repo)
2234 cmdutil.bailifchanged(repo)
2234 cmdutil.bailifchanged(repo)
2235 if not revs:
2235 if not revs:
2236 raise error.Abort(_('no revisions specified'))
2236 raise error.Abort(_('no revisions specified'))
2237 revs = scmutil.revrange(repo, revs)
2237 revs = scmutil.revrange(repo, revs)
2238
2238
2239 skipped = set()
2239 skipped = set()
2240 # check for merges
2240 # check for merges
2241 for rev in repo.revs('%ld and merge()', revs):
2241 for rev in repo.revs('%ld and merge()', revs):
2242 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2242 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2243 skipped.add(rev)
2243 skipped.add(rev)
2244 revs = [r for r in revs if r not in skipped]
2244 revs = [r for r in revs if r not in skipped]
2245 if not revs:
2245 if not revs:
2246 return -1
2246 return -1
2247
2247
2248 # Don't check in the --continue case, in effect retaining --force across
2248 # Don't check in the --continue case, in effect retaining --force across
2249 # --continues. That's because without --force, any revisions we decided to
2249 # --continues. That's because without --force, any revisions we decided to
2250 # skip would have been filtered out here, so they wouldn't have made their
2250 # skip would have been filtered out here, so they wouldn't have made their
2251 # way to the graftstate. With --force, any revisions we would have otherwise
2251 # way to the graftstate. With --force, any revisions we would have otherwise
2252 # skipped would not have been filtered out, and if they hadn't been applied
2252 # skipped would not have been filtered out, and if they hadn't been applied
2253 # already, they'd have been in the graftstate.
2253 # already, they'd have been in the graftstate.
2254 if not (cont or opts.get('force')):
2254 if not (cont or opts.get('force')):
2255 # check for ancestors of dest branch
2255 # check for ancestors of dest branch
2256 crev = repo['.'].rev()
2256 crev = repo['.'].rev()
2257 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2257 ancestors = repo.changelog.ancestors([crev], inclusive=True)
2258 # XXX make this lazy in the future
2258 # XXX make this lazy in the future
2259 # don't mutate while iterating, create a copy
2259 # don't mutate while iterating, create a copy
2260 for rev in list(revs):
2260 for rev in list(revs):
2261 if rev in ancestors:
2261 if rev in ancestors:
2262 ui.warn(_('skipping ancestor revision %d:%s\n') %
2262 ui.warn(_('skipping ancestor revision %d:%s\n') %
2263 (rev, repo[rev]))
2263 (rev, repo[rev]))
2264 # XXX remove on list is slow
2264 # XXX remove on list is slow
2265 revs.remove(rev)
2265 revs.remove(rev)
2266 if not revs:
2266 if not revs:
2267 return -1
2267 return -1
2268
2268
2269 # analyze revs for earlier grafts
2269 # analyze revs for earlier grafts
2270 ids = {}
2270 ids = {}
2271 for ctx in repo.set("%ld", revs):
2271 for ctx in repo.set("%ld", revs):
2272 ids[ctx.hex()] = ctx.rev()
2272 ids[ctx.hex()] = ctx.rev()
2273 n = ctx.extra().get('source')
2273 n = ctx.extra().get('source')
2274 if n:
2274 if n:
2275 ids[n] = ctx.rev()
2275 ids[n] = ctx.rev()
2276
2276
2277 # check ancestors for earlier grafts
2277 # check ancestors for earlier grafts
2278 ui.debug('scanning for duplicate grafts\n')
2278 ui.debug('scanning for duplicate grafts\n')
2279
2279
2280 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2280 for rev in repo.changelog.findmissingrevs(revs, [crev]):
2281 ctx = repo[rev]
2281 ctx = repo[rev]
2282 n = ctx.extra().get('source')
2282 n = ctx.extra().get('source')
2283 if n in ids:
2283 if n in ids:
2284 try:
2284 try:
2285 r = repo[n].rev()
2285 r = repo[n].rev()
2286 except error.RepoLookupError:
2286 except error.RepoLookupError:
2287 r = None
2287 r = None
2288 if r in revs:
2288 if r in revs:
2289 ui.warn(_('skipping revision %d:%s '
2289 ui.warn(_('skipping revision %d:%s '
2290 '(already grafted to %d:%s)\n')
2290 '(already grafted to %d:%s)\n')
2291 % (r, repo[r], rev, ctx))
2291 % (r, repo[r], rev, ctx))
2292 revs.remove(r)
2292 revs.remove(r)
2293 elif ids[n] in revs:
2293 elif ids[n] in revs:
2294 if r is None:
2294 if r is None:
2295 ui.warn(_('skipping already grafted revision %d:%s '
2295 ui.warn(_('skipping already grafted revision %d:%s '
2296 '(%d:%s also has unknown origin %s)\n')
2296 '(%d:%s also has unknown origin %s)\n')
2297 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2297 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
2298 else:
2298 else:
2299 ui.warn(_('skipping already grafted revision %d:%s '
2299 ui.warn(_('skipping already grafted revision %d:%s '
2300 '(%d:%s also has origin %d:%s)\n')
2300 '(%d:%s also has origin %d:%s)\n')
2301 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2301 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
2302 revs.remove(ids[n])
2302 revs.remove(ids[n])
2303 elif ctx.hex() in ids:
2303 elif ctx.hex() in ids:
2304 r = ids[ctx.hex()]
2304 r = ids[ctx.hex()]
2305 ui.warn(_('skipping already grafted revision %d:%s '
2305 ui.warn(_('skipping already grafted revision %d:%s '
2306 '(was grafted from %d:%s)\n') %
2306 '(was grafted from %d:%s)\n') %
2307 (r, repo[r], rev, ctx))
2307 (r, repo[r], rev, ctx))
2308 revs.remove(r)
2308 revs.remove(r)
2309 if not revs:
2309 if not revs:
2310 return -1
2310 return -1
2311
2311
2312 for pos, ctx in enumerate(repo.set("%ld", revs)):
2312 for pos, ctx in enumerate(repo.set("%ld", revs)):
2313 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2313 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
2314 ctx.description().split('\n', 1)[0])
2314 ctx.description().split('\n', 1)[0])
2315 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2315 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
2316 if names:
2316 if names:
2317 desc += ' (%s)' % ' '.join(names)
2317 desc += ' (%s)' % ' '.join(names)
2318 ui.status(_('grafting %s\n') % desc)
2318 ui.status(_('grafting %s\n') % desc)
2319 if opts.get('dry_run'):
2319 if opts.get('dry_run'):
2320 continue
2320 continue
2321
2321
2322 source = ctx.extra().get('source')
2322 source = ctx.extra().get('source')
2323 extra = {}
2323 extra = {}
2324 if source:
2324 if source:
2325 extra['source'] = source
2325 extra['source'] = source
2326 extra['intermediate-source'] = ctx.hex()
2326 extra['intermediate-source'] = ctx.hex()
2327 else:
2327 else:
2328 extra['source'] = ctx.hex()
2328 extra['source'] = ctx.hex()
2329 user = ctx.user()
2329 user = ctx.user()
2330 if opts.get('user'):
2330 if opts.get('user'):
2331 user = opts['user']
2331 user = opts['user']
2332 date = ctx.date()
2332 date = ctx.date()
2333 if opts.get('date'):
2333 if opts.get('date'):
2334 date = opts['date']
2334 date = opts['date']
2335 message = ctx.description()
2335 message = ctx.description()
2336 if opts.get('log'):
2336 if opts.get('log'):
2337 message += '\n(grafted from %s)' % ctx.hex()
2337 message += '\n(grafted from %s)' % ctx.hex()
2338
2338
2339 # we don't merge the first commit when continuing
2339 # we don't merge the first commit when continuing
2340 if not cont:
2340 if not cont:
2341 # perform the graft merge with p1(rev) as 'ancestor'
2341 # perform the graft merge with p1(rev) as 'ancestor'
2342 try:
2342 try:
2343 # ui.forcemerge is an internal variable, do not document
2343 # ui.forcemerge is an internal variable, do not document
2344 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2344 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
2345 'graft')
2345 'graft')
2346 stats = mergemod.graft(repo, ctx, ctx.p1(),
2346 stats = mergemod.graft(repo, ctx, ctx.p1(),
2347 ['local', 'graft'])
2347 ['local', 'graft'])
2348 finally:
2348 finally:
2349 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2349 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
2350 # report any conflicts
2350 # report any conflicts
2351 if stats and stats[3] > 0:
2351 if stats and stats[3] > 0:
2352 # write out state for --continue
2352 # write out state for --continue
2353 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2353 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2354 repo.vfs.write('graftstate', ''.join(nodelines))
2354 repo.vfs.write('graftstate', ''.join(nodelines))
2355 extra = ''
2355 extra = ''
2356 if opts.get('user'):
2356 if opts.get('user'):
2357 extra += ' --user %s' % util.shellquote(opts['user'])
2357 extra += ' --user %s' % util.shellquote(opts['user'])
2358 if opts.get('date'):
2358 if opts.get('date'):
2359 extra += ' --date %s' % util.shellquote(opts['date'])
2359 extra += ' --date %s' % util.shellquote(opts['date'])
2360 if opts.get('log'):
2360 if opts.get('log'):
2361 extra += ' --log'
2361 extra += ' --log'
2362 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2362 hint=_("use 'hg resolve' and 'hg graft --continue%s'") % extra
2363 raise error.Abort(
2363 raise error.Abort(
2364 _("unresolved conflicts, can't continue"),
2364 _("unresolved conflicts, can't continue"),
2365 hint=hint)
2365 hint=hint)
2366 else:
2366 else:
2367 cont = False
2367 cont = False
2368
2368
2369 # commit
2369 # commit
2370 node = repo.commit(text=message, user=user,
2370 node = repo.commit(text=message, user=user,
2371 date=date, extra=extra, editor=editor)
2371 date=date, extra=extra, editor=editor)
2372 if node is None:
2372 if node is None:
2373 ui.warn(
2373 ui.warn(
2374 _('note: graft of %d:%s created no changes to commit\n') %
2374 _('note: graft of %d:%s created no changes to commit\n') %
2375 (ctx.rev(), ctx))
2375 (ctx.rev(), ctx))
2376
2376
2377 # remove state when we complete successfully
2377 # remove state when we complete successfully
2378 if not opts.get('dry_run'):
2378 if not opts.get('dry_run'):
2379 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2379 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
2380
2380
2381 return 0
2381 return 0
2382
2382
2383 @command('grep',
2383 @command('grep',
2384 [('0', 'print0', None, _('end fields with NUL')),
2384 [('0', 'print0', None, _('end fields with NUL')),
2385 ('', 'all', None, _('print all revisions that match')),
2385 ('', 'all', None, _('print all revisions that match')),
2386 ('a', 'text', None, _('treat all files as text')),
2386 ('a', 'text', None, _('treat all files as text')),
2387 ('f', 'follow', None,
2387 ('f', 'follow', None,
2388 _('follow changeset history,'
2388 _('follow changeset history,'
2389 ' or file history across copies and renames')),
2389 ' or file history across copies and renames')),
2390 ('i', 'ignore-case', None, _('ignore case when matching')),
2390 ('i', 'ignore-case', None, _('ignore case when matching')),
2391 ('l', 'files-with-matches', None,
2391 ('l', 'files-with-matches', None,
2392 _('print only filenames and revisions that match')),
2392 _('print only filenames and revisions that match')),
2393 ('n', 'line-number', None, _('print matching line numbers')),
2393 ('n', 'line-number', None, _('print matching line numbers')),
2394 ('r', 'rev', [],
2394 ('r', 'rev', [],
2395 _('only search files changed within revision range'), _('REV')),
2395 _('only search files changed within revision range'), _('REV')),
2396 ('u', 'user', None, _('list the author (long with -v)')),
2396 ('u', 'user', None, _('list the author (long with -v)')),
2397 ('d', 'date', None, _('list the date (short with -q)')),
2397 ('d', 'date', None, _('list the date (short with -q)')),
2398 ] + formatteropts + walkopts,
2398 ] + formatteropts + walkopts,
2399 _('[OPTION]... PATTERN [FILE]...'),
2399 _('[OPTION]... PATTERN [FILE]...'),
2400 inferrepo=True)
2400 inferrepo=True)
2401 def grep(ui, repo, pattern, *pats, **opts):
2401 def grep(ui, repo, pattern, *pats, **opts):
2402 """search revision history for a pattern in specified files
2402 """search revision history for a pattern in specified files
2403
2403
2404 Search revision history for a regular expression in the specified
2404 Search revision history for a regular expression in the specified
2405 files or the entire project.
2405 files or the entire project.
2406
2406
2407 By default, grep prints the most recent revision number for each
2407 By default, grep prints the most recent revision number for each
2408 file in which it finds a match. To get it to print every revision
2408 file in which it finds a match. To get it to print every revision
2409 that contains a change in match status ("-" for a match that becomes
2409 that contains a change in match status ("-" for a match that becomes
2410 a non-match, or "+" for a non-match that becomes a match), use the
2410 a non-match, or "+" for a non-match that becomes a match), use the
2411 --all flag.
2411 --all flag.
2412
2412
2413 PATTERN can be any Python (roughly Perl-compatible) regular
2413 PATTERN can be any Python (roughly Perl-compatible) regular
2414 expression.
2414 expression.
2415
2415
2416 If no FILEs are specified (and -f/--follow isn't set), all files in
2416 If no FILEs are specified (and -f/--follow isn't set), all files in
2417 the repository are searched, including those that don't exist in the
2417 the repository are searched, including those that don't exist in the
2418 current branch or have been deleted in a prior changeset.
2418 current branch or have been deleted in a prior changeset.
2419
2419
2420 Returns 0 if a match is found, 1 otherwise.
2420 Returns 0 if a match is found, 1 otherwise.
2421 """
2421 """
2422 reflags = re.M
2422 reflags = re.M
2423 if opts.get('ignore_case'):
2423 if opts.get('ignore_case'):
2424 reflags |= re.I
2424 reflags |= re.I
2425 try:
2425 try:
2426 regexp = util.re.compile(pattern, reflags)
2426 regexp = util.re.compile(pattern, reflags)
2427 except re.error as inst:
2427 except re.error as inst:
2428 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2428 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2429 return 1
2429 return 1
2430 sep, eol = ':', '\n'
2430 sep, eol = ':', '\n'
2431 if opts.get('print0'):
2431 if opts.get('print0'):
2432 sep = eol = '\0'
2432 sep = eol = '\0'
2433
2433
2434 getfile = util.lrucachefunc(repo.file)
2434 getfile = util.lrucachefunc(repo.file)
2435
2435
2436 def matchlines(body):
2436 def matchlines(body):
2437 begin = 0
2437 begin = 0
2438 linenum = 0
2438 linenum = 0
2439 while begin < len(body):
2439 while begin < len(body):
2440 match = regexp.search(body, begin)
2440 match = regexp.search(body, begin)
2441 if not match:
2441 if not match:
2442 break
2442 break
2443 mstart, mend = match.span()
2443 mstart, mend = match.span()
2444 linenum += body.count('\n', begin, mstart) + 1
2444 linenum += body.count('\n', begin, mstart) + 1
2445 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2445 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2446 begin = body.find('\n', mend) + 1 or len(body) + 1
2446 begin = body.find('\n', mend) + 1 or len(body) + 1
2447 lend = begin - 1
2447 lend = begin - 1
2448 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2448 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2449
2449
2450 class linestate(object):
2450 class linestate(object):
2451 def __init__(self, line, linenum, colstart, colend):
2451 def __init__(self, line, linenum, colstart, colend):
2452 self.line = line
2452 self.line = line
2453 self.linenum = linenum
2453 self.linenum = linenum
2454 self.colstart = colstart
2454 self.colstart = colstart
2455 self.colend = colend
2455 self.colend = colend
2456
2456
2457 def __hash__(self):
2457 def __hash__(self):
2458 return hash((self.linenum, self.line))
2458 return hash((self.linenum, self.line))
2459
2459
2460 def __eq__(self, other):
2460 def __eq__(self, other):
2461 return self.line == other.line
2461 return self.line == other.line
2462
2462
2463 def findpos(self):
2463 def findpos(self):
2464 """Iterate all (start, end) indices of matches"""
2464 """Iterate all (start, end) indices of matches"""
2465 yield self.colstart, self.colend
2465 yield self.colstart, self.colend
2466 p = self.colend
2466 p = self.colend
2467 while p < len(self.line):
2467 while p < len(self.line):
2468 m = regexp.search(self.line, p)
2468 m = regexp.search(self.line, p)
2469 if not m:
2469 if not m:
2470 break
2470 break
2471 yield m.span()
2471 yield m.span()
2472 p = m.end()
2472 p = m.end()
2473
2473
2474 matches = {}
2474 matches = {}
2475 copies = {}
2475 copies = {}
2476 def grepbody(fn, rev, body):
2476 def grepbody(fn, rev, body):
2477 matches[rev].setdefault(fn, [])
2477 matches[rev].setdefault(fn, [])
2478 m = matches[rev][fn]
2478 m = matches[rev][fn]
2479 for lnum, cstart, cend, line in matchlines(body):
2479 for lnum, cstart, cend, line in matchlines(body):
2480 s = linestate(line, lnum, cstart, cend)
2480 s = linestate(line, lnum, cstart, cend)
2481 m.append(s)
2481 m.append(s)
2482
2482
2483 def difflinestates(a, b):
2483 def difflinestates(a, b):
2484 sm = difflib.SequenceMatcher(None, a, b)
2484 sm = difflib.SequenceMatcher(None, a, b)
2485 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2485 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2486 if tag == 'insert':
2486 if tag == 'insert':
2487 for i in xrange(blo, bhi):
2487 for i in xrange(blo, bhi):
2488 yield ('+', b[i])
2488 yield ('+', b[i])
2489 elif tag == 'delete':
2489 elif tag == 'delete':
2490 for i in xrange(alo, ahi):
2490 for i in xrange(alo, ahi):
2491 yield ('-', a[i])
2491 yield ('-', a[i])
2492 elif tag == 'replace':
2492 elif tag == 'replace':
2493 for i in xrange(alo, ahi):
2493 for i in xrange(alo, ahi):
2494 yield ('-', a[i])
2494 yield ('-', a[i])
2495 for i in xrange(blo, bhi):
2495 for i in xrange(blo, bhi):
2496 yield ('+', b[i])
2496 yield ('+', b[i])
2497
2497
2498 def display(fm, fn, ctx, pstates, states):
2498 def display(fm, fn, ctx, pstates, states):
2499 rev = ctx.rev()
2499 rev = ctx.rev()
2500 if fm.isplain():
2500 if fm.isplain():
2501 formatuser = ui.shortuser
2501 formatuser = ui.shortuser
2502 else:
2502 else:
2503 formatuser = str
2503 formatuser = str
2504 if ui.quiet:
2504 if ui.quiet:
2505 datefmt = '%Y-%m-%d'
2505 datefmt = '%Y-%m-%d'
2506 else:
2506 else:
2507 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2507 datefmt = '%a %b %d %H:%M:%S %Y %1%2'
2508 found = False
2508 found = False
2509 @util.cachefunc
2509 @util.cachefunc
2510 def binary():
2510 def binary():
2511 flog = getfile(fn)
2511 flog = getfile(fn)
2512 return util.binary(flog.read(ctx.filenode(fn)))
2512 return util.binary(flog.read(ctx.filenode(fn)))
2513
2513
2514 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2514 fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'}
2515 if opts.get('all'):
2515 if opts.get('all'):
2516 iter = difflinestates(pstates, states)
2516 iter = difflinestates(pstates, states)
2517 else:
2517 else:
2518 iter = [('', l) for l in states]
2518 iter = [('', l) for l in states]
2519 for change, l in iter:
2519 for change, l in iter:
2520 fm.startitem()
2520 fm.startitem()
2521 fm.data(node=fm.hexfunc(ctx.node()))
2521 fm.data(node=fm.hexfunc(ctx.node()))
2522 cols = [
2522 cols = [
2523 ('filename', fn, True),
2523 ('filename', fn, True),
2524 ('rev', rev, True),
2524 ('rev', rev, True),
2525 ('linenumber', l.linenum, opts.get('line_number')),
2525 ('linenumber', l.linenum, opts.get('line_number')),
2526 ]
2526 ]
2527 if opts.get('all'):
2527 if opts.get('all'):
2528 cols.append(('change', change, True))
2528 cols.append(('change', change, True))
2529 cols.extend([
2529 cols.extend([
2530 ('user', formatuser(ctx.user()), opts.get('user')),
2530 ('user', formatuser(ctx.user()), opts.get('user')),
2531 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2531 ('date', fm.formatdate(ctx.date(), datefmt), opts.get('date')),
2532 ])
2532 ])
2533 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2533 lastcol = next(name for name, data, cond in reversed(cols) if cond)
2534 for name, data, cond in cols:
2534 for name, data, cond in cols:
2535 field = fieldnamemap.get(name, name)
2535 field = fieldnamemap.get(name, name)
2536 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2536 fm.condwrite(cond, field, '%s', data, label='grep.%s' % name)
2537 if cond and name != lastcol:
2537 if cond and name != lastcol:
2538 fm.plain(sep, label='grep.sep')
2538 fm.plain(sep, label='grep.sep')
2539 if not opts.get('files_with_matches'):
2539 if not opts.get('files_with_matches'):
2540 fm.plain(sep, label='grep.sep')
2540 fm.plain(sep, label='grep.sep')
2541 if not opts.get('text') and binary():
2541 if not opts.get('text') and binary():
2542 fm.plain(_(" Binary file matches"))
2542 fm.plain(_(" Binary file matches"))
2543 else:
2543 else:
2544 displaymatches(fm.nested('texts'), l)
2544 displaymatches(fm.nested('texts'), l)
2545 fm.plain(eol)
2545 fm.plain(eol)
2546 found = True
2546 found = True
2547 if opts.get('files_with_matches'):
2547 if opts.get('files_with_matches'):
2548 break
2548 break
2549 return found
2549 return found
2550
2550
2551 def displaymatches(fm, l):
2551 def displaymatches(fm, l):
2552 p = 0
2552 p = 0
2553 for s, e in l.findpos():
2553 for s, e in l.findpos():
2554 if p < s:
2554 if p < s:
2555 fm.startitem()
2555 fm.startitem()
2556 fm.write('text', '%s', l.line[p:s])
2556 fm.write('text', '%s', l.line[p:s])
2557 fm.data(matched=False)
2557 fm.data(matched=False)
2558 fm.startitem()
2558 fm.startitem()
2559 fm.write('text', '%s', l.line[s:e], label='grep.match')
2559 fm.write('text', '%s', l.line[s:e], label='grep.match')
2560 fm.data(matched=True)
2560 fm.data(matched=True)
2561 p = e
2561 p = e
2562 if p < len(l.line):
2562 if p < len(l.line):
2563 fm.startitem()
2563 fm.startitem()
2564 fm.write('text', '%s', l.line[p:])
2564 fm.write('text', '%s', l.line[p:])
2565 fm.data(matched=False)
2565 fm.data(matched=False)
2566 fm.end()
2566 fm.end()
2567
2567
2568 skip = {}
2568 skip = {}
2569 revfiles = {}
2569 revfiles = {}
2570 matchfn = scmutil.match(repo[None], pats, opts)
2570 matchfn = scmutil.match(repo[None], pats, opts)
2571 found = False
2571 found = False
2572 follow = opts.get('follow')
2572 follow = opts.get('follow')
2573
2573
2574 def prep(ctx, fns):
2574 def prep(ctx, fns):
2575 rev = ctx.rev()
2575 rev = ctx.rev()
2576 pctx = ctx.p1()
2576 pctx = ctx.p1()
2577 parent = pctx.rev()
2577 parent = pctx.rev()
2578 matches.setdefault(rev, {})
2578 matches.setdefault(rev, {})
2579 matches.setdefault(parent, {})
2579 matches.setdefault(parent, {})
2580 files = revfiles.setdefault(rev, [])
2580 files = revfiles.setdefault(rev, [])
2581 for fn in fns:
2581 for fn in fns:
2582 flog = getfile(fn)
2582 flog = getfile(fn)
2583 try:
2583 try:
2584 fnode = ctx.filenode(fn)
2584 fnode = ctx.filenode(fn)
2585 except error.LookupError:
2585 except error.LookupError:
2586 continue
2586 continue
2587
2587
2588 copied = flog.renamed(fnode)
2588 copied = flog.renamed(fnode)
2589 copy = follow and copied and copied[0]
2589 copy = follow and copied and copied[0]
2590 if copy:
2590 if copy:
2591 copies.setdefault(rev, {})[fn] = copy
2591 copies.setdefault(rev, {})[fn] = copy
2592 if fn in skip:
2592 if fn in skip:
2593 if copy:
2593 if copy:
2594 skip[copy] = True
2594 skip[copy] = True
2595 continue
2595 continue
2596 files.append(fn)
2596 files.append(fn)
2597
2597
2598 if fn not in matches[rev]:
2598 if fn not in matches[rev]:
2599 grepbody(fn, rev, flog.read(fnode))
2599 grepbody(fn, rev, flog.read(fnode))
2600
2600
2601 pfn = copy or fn
2601 pfn = copy or fn
2602 if pfn not in matches[parent]:
2602 if pfn not in matches[parent]:
2603 try:
2603 try:
2604 fnode = pctx.filenode(pfn)
2604 fnode = pctx.filenode(pfn)
2605 grepbody(pfn, parent, flog.read(fnode))
2605 grepbody(pfn, parent, flog.read(fnode))
2606 except error.LookupError:
2606 except error.LookupError:
2607 pass
2607 pass
2608
2608
2609 ui.pager('grep')
2609 ui.pager('grep')
2610 fm = ui.formatter('grep', opts)
2610 fm = ui.formatter('grep', opts)
2611 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2611 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2612 rev = ctx.rev()
2612 rev = ctx.rev()
2613 parent = ctx.p1().rev()
2613 parent = ctx.p1().rev()
2614 for fn in sorted(revfiles.get(rev, [])):
2614 for fn in sorted(revfiles.get(rev, [])):
2615 states = matches[rev][fn]
2615 states = matches[rev][fn]
2616 copy = copies.get(rev, {}).get(fn)
2616 copy = copies.get(rev, {}).get(fn)
2617 if fn in skip:
2617 if fn in skip:
2618 if copy:
2618 if copy:
2619 skip[copy] = True
2619 skip[copy] = True
2620 continue
2620 continue
2621 pstates = matches.get(parent, {}).get(copy or fn, [])
2621 pstates = matches.get(parent, {}).get(copy or fn, [])
2622 if pstates or states:
2622 if pstates or states:
2623 r = display(fm, fn, ctx, pstates, states)
2623 r = display(fm, fn, ctx, pstates, states)
2624 found = found or r
2624 found = found or r
2625 if r and not opts.get('all'):
2625 if r and not opts.get('all'):
2626 skip[fn] = True
2626 skip[fn] = True
2627 if copy:
2627 if copy:
2628 skip[copy] = True
2628 skip[copy] = True
2629 del matches[rev]
2629 del matches[rev]
2630 del revfiles[rev]
2630 del revfiles[rev]
2631 fm.end()
2631 fm.end()
2632
2632
2633 return not found
2633 return not found
2634
2634
2635 @command('heads',
2635 @command('heads',
2636 [('r', 'rev', '',
2636 [('r', 'rev', '',
2637 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2637 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
2638 ('t', 'topo', False, _('show topological heads only')),
2638 ('t', 'topo', False, _('show topological heads only')),
2639 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2639 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
2640 ('c', 'closed', False, _('show normal and closed branch heads')),
2640 ('c', 'closed', False, _('show normal and closed branch heads')),
2641 ] + templateopts,
2641 ] + templateopts,
2642 _('[-ct] [-r STARTREV] [REV]...'))
2642 _('[-ct] [-r STARTREV] [REV]...'))
2643 def heads(ui, repo, *branchrevs, **opts):
2643 def heads(ui, repo, *branchrevs, **opts):
2644 """show branch heads
2644 """show branch heads
2645
2645
2646 With no arguments, show all open branch heads in the repository.
2646 With no arguments, show all open branch heads in the repository.
2647 Branch heads are changesets that have no descendants on the
2647 Branch heads are changesets that have no descendants on the
2648 same branch. They are where development generally takes place and
2648 same branch. They are where development generally takes place and
2649 are the usual targets for update and merge operations.
2649 are the usual targets for update and merge operations.
2650
2650
2651 If one or more REVs are given, only open branch heads on the
2651 If one or more REVs are given, only open branch heads on the
2652 branches associated with the specified changesets are shown. This
2652 branches associated with the specified changesets are shown. This
2653 means that you can use :hg:`heads .` to see the heads on the
2653 means that you can use :hg:`heads .` to see the heads on the
2654 currently checked-out branch.
2654 currently checked-out branch.
2655
2655
2656 If -c/--closed is specified, also show branch heads marked closed
2656 If -c/--closed is specified, also show branch heads marked closed
2657 (see :hg:`commit --close-branch`).
2657 (see :hg:`commit --close-branch`).
2658
2658
2659 If STARTREV is specified, only those heads that are descendants of
2659 If STARTREV is specified, only those heads that are descendants of
2660 STARTREV will be displayed.
2660 STARTREV will be displayed.
2661
2661
2662 If -t/--topo is specified, named branch mechanics will be ignored and only
2662 If -t/--topo is specified, named branch mechanics will be ignored and only
2663 topological heads (changesets with no children) will be shown.
2663 topological heads (changesets with no children) will be shown.
2664
2664
2665 Returns 0 if matching heads are found, 1 if not.
2665 Returns 0 if matching heads are found, 1 if not.
2666 """
2666 """
2667
2667
2668 start = None
2668 start = None
2669 if 'rev' in opts:
2669 if 'rev' in opts:
2670 start = scmutil.revsingle(repo, opts['rev'], None).node()
2670 start = scmutil.revsingle(repo, opts['rev'], None).node()
2671
2671
2672 if opts.get('topo'):
2672 if opts.get('topo'):
2673 heads = [repo[h] for h in repo.heads(start)]
2673 heads = [repo[h] for h in repo.heads(start)]
2674 else:
2674 else:
2675 heads = []
2675 heads = []
2676 for branch in repo.branchmap():
2676 for branch in repo.branchmap():
2677 heads += repo.branchheads(branch, start, opts.get('closed'))
2677 heads += repo.branchheads(branch, start, opts.get('closed'))
2678 heads = [repo[h] for h in heads]
2678 heads = [repo[h] for h in heads]
2679
2679
2680 if branchrevs:
2680 if branchrevs:
2681 branches = set(repo[br].branch() for br in branchrevs)
2681 branches = set(repo[br].branch() for br in branchrevs)
2682 heads = [h for h in heads if h.branch() in branches]
2682 heads = [h for h in heads if h.branch() in branches]
2683
2683
2684 if opts.get('active') and branchrevs:
2684 if opts.get('active') and branchrevs:
2685 dagheads = repo.heads(start)
2685 dagheads = repo.heads(start)
2686 heads = [h for h in heads if h.node() in dagheads]
2686 heads = [h for h in heads if h.node() in dagheads]
2687
2687
2688 if branchrevs:
2688 if branchrevs:
2689 haveheads = set(h.branch() for h in heads)
2689 haveheads = set(h.branch() for h in heads)
2690 if branches - haveheads:
2690 if branches - haveheads:
2691 headless = ', '.join(b for b in branches - haveheads)
2691 headless = ', '.join(b for b in branches - haveheads)
2692 msg = _('no open branch heads found on branches %s')
2692 msg = _('no open branch heads found on branches %s')
2693 if opts.get('rev'):
2693 if opts.get('rev'):
2694 msg += _(' (started at %s)') % opts['rev']
2694 msg += _(' (started at %s)') % opts['rev']
2695 ui.warn((msg + '\n') % headless)
2695 ui.warn((msg + '\n') % headless)
2696
2696
2697 if not heads:
2697 if not heads:
2698 return 1
2698 return 1
2699
2699
2700 heads = sorted(heads, key=lambda x: -x.rev())
2700 heads = sorted(heads, key=lambda x: -x.rev())
2701 displayer = cmdutil.show_changeset(ui, repo, opts)
2701 displayer = cmdutil.show_changeset(ui, repo, opts)
2702 for ctx in heads:
2702 for ctx in heads:
2703 displayer.show(ctx)
2703 displayer.show(ctx)
2704 displayer.close()
2704 displayer.close()
2705
2705
2706 @command('help',
2706 @command('help',
2707 [('e', 'extension', None, _('show only help for extensions')),
2707 [('e', 'extension', None, _('show only help for extensions')),
2708 ('c', 'command', None, _('show only help for commands')),
2708 ('c', 'command', None, _('show only help for commands')),
2709 ('k', 'keyword', None, _('show topics matching keyword')),
2709 ('k', 'keyword', None, _('show topics matching keyword')),
2710 ('s', 'system', [], _('show help for specific platform(s)')),
2710 ('s', 'system', [], _('show help for specific platform(s)')),
2711 ],
2711 ],
2712 _('[-ecks] [TOPIC]'),
2712 _('[-ecks] [TOPIC]'),
2713 norepo=True)
2713 norepo=True)
2714 def help_(ui, name=None, **opts):
2714 def help_(ui, name=None, **opts):
2715 """show help for a given topic or a help overview
2715 """show help for a given topic or a help overview
2716
2716
2717 With no arguments, print a list of commands with short help messages.
2717 With no arguments, print a list of commands with short help messages.
2718
2718
2719 Given a topic, extension, or command name, print help for that
2719 Given a topic, extension, or command name, print help for that
2720 topic.
2720 topic.
2721
2721
2722 Returns 0 if successful.
2722 Returns 0 if successful.
2723 """
2723 """
2724 textwidth = ui.configint('ui', 'textwidth', 78)
2724 textwidth = ui.configint('ui', 'textwidth', 78)
2725 termwidth = ui.termwidth() - 2
2725 termwidth = ui.termwidth() - 2
2726 if textwidth <= 0 or termwidth < textwidth:
2726 if textwidth <= 0 or termwidth < textwidth:
2727 textwidth = termwidth
2727 textwidth = termwidth
2728
2728
2729 keep = opts.get('system') or []
2729 keep = opts.get('system') or []
2730 if len(keep) == 0:
2730 if len(keep) == 0:
2731 if pycompat.sysplatform.startswith('win'):
2731 if pycompat.sysplatform.startswith('win'):
2732 keep.append('windows')
2732 keep.append('windows')
2733 elif pycompat.sysplatform == 'OpenVMS':
2733 elif pycompat.sysplatform == 'OpenVMS':
2734 keep.append('vms')
2734 keep.append('vms')
2735 elif pycompat.sysplatform == 'plan9':
2735 elif pycompat.sysplatform == 'plan9':
2736 keep.append('plan9')
2736 keep.append('plan9')
2737 else:
2737 else:
2738 keep.append('unix')
2738 keep.append('unix')
2739 keep.append(pycompat.sysplatform.lower())
2739 keep.append(pycompat.sysplatform.lower())
2740 if ui.verbose:
2740 if ui.verbose:
2741 keep.append('verbose')
2741 keep.append('verbose')
2742
2742
2743 fullname = name
2743 fullname = name
2744 section = None
2744 section = None
2745 subtopic = None
2745 subtopic = None
2746 if name and '.' in name:
2746 if name and '.' in name:
2747 name, remaining = name.split('.', 1)
2747 name, remaining = name.split('.', 1)
2748 remaining = encoding.lower(remaining)
2748 remaining = encoding.lower(remaining)
2749 if '.' in remaining:
2749 if '.' in remaining:
2750 subtopic, section = remaining.split('.', 1)
2750 subtopic, section = remaining.split('.', 1)
2751 else:
2751 else:
2752 if name in help.subtopics:
2752 if name in help.subtopics:
2753 subtopic = remaining
2753 subtopic = remaining
2754 else:
2754 else:
2755 section = remaining
2755 section = remaining
2756
2756
2757 text = help.help_(ui, name, subtopic=subtopic, **opts)
2757 text = help.help_(ui, name, subtopic=subtopic, **opts)
2758
2758
2759 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2759 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2760 section=section)
2760 section=section)
2761
2761
2762 # We could have been given a weird ".foo" section without a name
2762 # We could have been given a weird ".foo" section without a name
2763 # to look for, or we could have simply failed to found "foo.bar"
2763 # to look for, or we could have simply failed to found "foo.bar"
2764 # because bar isn't a section of foo
2764 # because bar isn't a section of foo
2765 if section and not (formatted and name):
2765 if section and not (formatted and name):
2766 raise error.Abort(_("help section not found: %s") % fullname)
2766 raise error.Abort(_("help section not found: %s") % fullname)
2767
2767
2768 if 'verbose' in pruned:
2768 if 'verbose' in pruned:
2769 keep.append('omitted')
2769 keep.append('omitted')
2770 else:
2770 else:
2771 keep.append('notomitted')
2771 keep.append('notomitted')
2772 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2772 formatted, pruned = minirst.format(text, textwidth, keep=keep,
2773 section=section)
2773 section=section)
2774 ui.pager('help')
2774 ui.pager('help')
2775 ui.write(formatted)
2775 ui.write(formatted)
2776
2776
2777
2777
2778 @command('identify|id',
2778 @command('identify|id',
2779 [('r', 'rev', '',
2779 [('r', 'rev', '',
2780 _('identify the specified revision'), _('REV')),
2780 _('identify the specified revision'), _('REV')),
2781 ('n', 'num', None, _('show local revision number')),
2781 ('n', 'num', None, _('show local revision number')),
2782 ('i', 'id', None, _('show global revision id')),
2782 ('i', 'id', None, _('show global revision id')),
2783 ('b', 'branch', None, _('show branch')),
2783 ('b', 'branch', None, _('show branch')),
2784 ('t', 'tags', None, _('show tags')),
2784 ('t', 'tags', None, _('show tags')),
2785 ('B', 'bookmarks', None, _('show bookmarks')),
2785 ('B', 'bookmarks', None, _('show bookmarks')),
2786 ] + remoteopts,
2786 ] + remoteopts,
2787 _('[-nibtB] [-r REV] [SOURCE]'),
2787 _('[-nibtB] [-r REV] [SOURCE]'),
2788 optionalrepo=True)
2788 optionalrepo=True)
2789 def identify(ui, repo, source=None, rev=None,
2789 def identify(ui, repo, source=None, rev=None,
2790 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2790 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
2791 """identify the working directory or specified revision
2791 """identify the working directory or specified revision
2792
2792
2793 Print a summary identifying the repository state at REV using one or
2793 Print a summary identifying the repository state at REV using one or
2794 two parent hash identifiers, followed by a "+" if the working
2794 two parent hash identifiers, followed by a "+" if the working
2795 directory has uncommitted changes, the branch name (if not default),
2795 directory has uncommitted changes, the branch name (if not default),
2796 a list of tags, and a list of bookmarks.
2796 a list of tags, and a list of bookmarks.
2797
2797
2798 When REV is not given, print a summary of the current state of the
2798 When REV is not given, print a summary of the current state of the
2799 repository.
2799 repository.
2800
2800
2801 Specifying a path to a repository root or Mercurial bundle will
2801 Specifying a path to a repository root or Mercurial bundle will
2802 cause lookup to operate on that repository/bundle.
2802 cause lookup to operate on that repository/bundle.
2803
2803
2804 .. container:: verbose
2804 .. container:: verbose
2805
2805
2806 Examples:
2806 Examples:
2807
2807
2808 - generate a build identifier for the working directory::
2808 - generate a build identifier for the working directory::
2809
2809
2810 hg id --id > build-id.dat
2810 hg id --id > build-id.dat
2811
2811
2812 - find the revision corresponding to a tag::
2812 - find the revision corresponding to a tag::
2813
2813
2814 hg id -n -r 1.3
2814 hg id -n -r 1.3
2815
2815
2816 - check the most recent revision of a remote repository::
2816 - check the most recent revision of a remote repository::
2817
2817
2818 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2818 hg id -r tip https://www.mercurial-scm.org/repo/hg/
2819
2819
2820 See :hg:`log` for generating more information about specific revisions,
2820 See :hg:`log` for generating more information about specific revisions,
2821 including full hash identifiers.
2821 including full hash identifiers.
2822
2822
2823 Returns 0 if successful.
2823 Returns 0 if successful.
2824 """
2824 """
2825
2825
2826 if not repo and not source:
2826 if not repo and not source:
2827 raise error.Abort(_("there is no Mercurial repository here "
2827 raise error.Abort(_("there is no Mercurial repository here "
2828 "(.hg not found)"))
2828 "(.hg not found)"))
2829
2829
2830 if ui.debugflag:
2830 if ui.debugflag:
2831 hexfunc = hex
2831 hexfunc = hex
2832 else:
2832 else:
2833 hexfunc = short
2833 hexfunc = short
2834 default = not (num or id or branch or tags or bookmarks)
2834 default = not (num or id or branch or tags or bookmarks)
2835 output = []
2835 output = []
2836 revs = []
2836 revs = []
2837
2837
2838 if source:
2838 if source:
2839 source, branches = hg.parseurl(ui.expandpath(source))
2839 source, branches = hg.parseurl(ui.expandpath(source))
2840 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2840 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
2841 repo = peer.local()
2841 repo = peer.local()
2842 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2842 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
2843
2843
2844 if not repo:
2844 if not repo:
2845 if num or branch or tags:
2845 if num or branch or tags:
2846 raise error.Abort(
2846 raise error.Abort(
2847 _("can't query remote revision number, branch, or tags"))
2847 _("can't query remote revision number, branch, or tags"))
2848 if not rev and revs:
2848 if not rev and revs:
2849 rev = revs[0]
2849 rev = revs[0]
2850 if not rev:
2850 if not rev:
2851 rev = "tip"
2851 rev = "tip"
2852
2852
2853 remoterev = peer.lookup(rev)
2853 remoterev = peer.lookup(rev)
2854 if default or id:
2854 if default or id:
2855 output = [hexfunc(remoterev)]
2855 output = [hexfunc(remoterev)]
2856
2856
2857 def getbms():
2857 def getbms():
2858 bms = []
2858 bms = []
2859
2859
2860 if 'bookmarks' in peer.listkeys('namespaces'):
2860 if 'bookmarks' in peer.listkeys('namespaces'):
2861 hexremoterev = hex(remoterev)
2861 hexremoterev = hex(remoterev)
2862 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2862 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
2863 if bmr == hexremoterev]
2863 if bmr == hexremoterev]
2864
2864
2865 return sorted(bms)
2865 return sorted(bms)
2866
2866
2867 if bookmarks:
2867 if bookmarks:
2868 output.extend(getbms())
2868 output.extend(getbms())
2869 elif default and not ui.quiet:
2869 elif default and not ui.quiet:
2870 # multiple bookmarks for a single parent separated by '/'
2870 # multiple bookmarks for a single parent separated by '/'
2871 bm = '/'.join(getbms())
2871 bm = '/'.join(getbms())
2872 if bm:
2872 if bm:
2873 output.append(bm)
2873 output.append(bm)
2874 else:
2874 else:
2875 ctx = scmutil.revsingle(repo, rev, None)
2875 ctx = scmutil.revsingle(repo, rev, None)
2876
2876
2877 if ctx.rev() is None:
2877 if ctx.rev() is None:
2878 ctx = repo[None]
2878 ctx = repo[None]
2879 parents = ctx.parents()
2879 parents = ctx.parents()
2880 taglist = []
2880 taglist = []
2881 for p in parents:
2881 for p in parents:
2882 taglist.extend(p.tags())
2882 taglist.extend(p.tags())
2883
2883
2884 changed = ""
2884 changed = ""
2885 if default or id or num:
2885 if default or id or num:
2886 if (any(repo.status())
2886 if (any(repo.status())
2887 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2887 or any(ctx.sub(s).dirty() for s in ctx.substate)):
2888 changed = '+'
2888 changed = '+'
2889 if default or id:
2889 if default or id:
2890 output = ["%s%s" %
2890 output = ["%s%s" %
2891 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2891 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2892 if num:
2892 if num:
2893 output.append("%s%s" %
2893 output.append("%s%s" %
2894 ('+'.join([str(p.rev()) for p in parents]), changed))
2894 ('+'.join([str(p.rev()) for p in parents]), changed))
2895 else:
2895 else:
2896 if default or id:
2896 if default or id:
2897 output = [hexfunc(ctx.node())]
2897 output = [hexfunc(ctx.node())]
2898 if num:
2898 if num:
2899 output.append(str(ctx.rev()))
2899 output.append(str(ctx.rev()))
2900 taglist = ctx.tags()
2900 taglist = ctx.tags()
2901
2901
2902 if default and not ui.quiet:
2902 if default and not ui.quiet:
2903 b = ctx.branch()
2903 b = ctx.branch()
2904 if b != 'default':
2904 if b != 'default':
2905 output.append("(%s)" % b)
2905 output.append("(%s)" % b)
2906
2906
2907 # multiple tags for a single parent separated by '/'
2907 # multiple tags for a single parent separated by '/'
2908 t = '/'.join(taglist)
2908 t = '/'.join(taglist)
2909 if t:
2909 if t:
2910 output.append(t)
2910 output.append(t)
2911
2911
2912 # multiple bookmarks for a single parent separated by '/'
2912 # multiple bookmarks for a single parent separated by '/'
2913 bm = '/'.join(ctx.bookmarks())
2913 bm = '/'.join(ctx.bookmarks())
2914 if bm:
2914 if bm:
2915 output.append(bm)
2915 output.append(bm)
2916 else:
2916 else:
2917 if branch:
2917 if branch:
2918 output.append(ctx.branch())
2918 output.append(ctx.branch())
2919
2919
2920 if tags:
2920 if tags:
2921 output.extend(taglist)
2921 output.extend(taglist)
2922
2922
2923 if bookmarks:
2923 if bookmarks:
2924 output.extend(ctx.bookmarks())
2924 output.extend(ctx.bookmarks())
2925
2925
2926 ui.write("%s\n" % ' '.join(output))
2926 ui.write("%s\n" % ' '.join(output))
2927
2927
2928 @command('import|patch',
2928 @command('import|patch',
2929 [('p', 'strip', 1,
2929 [('p', 'strip', 1,
2930 _('directory strip option for patch. This has the same '
2930 _('directory strip option for patch. This has the same '
2931 'meaning as the corresponding patch option'), _('NUM')),
2931 'meaning as the corresponding patch option'), _('NUM')),
2932 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2932 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
2933 ('e', 'edit', False, _('invoke editor on commit messages')),
2933 ('e', 'edit', False, _('invoke editor on commit messages')),
2934 ('f', 'force', None,
2934 ('f', 'force', None,
2935 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2935 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
2936 ('', 'no-commit', None,
2936 ('', 'no-commit', None,
2937 _("don't commit, just update the working directory")),
2937 _("don't commit, just update the working directory")),
2938 ('', 'bypass', None,
2938 ('', 'bypass', None,
2939 _("apply patch without touching the working directory")),
2939 _("apply patch without touching the working directory")),
2940 ('', 'partial', None,
2940 ('', 'partial', None,
2941 _('commit even if some hunks fail')),
2941 _('commit even if some hunks fail')),
2942 ('', 'exact', None,
2942 ('', 'exact', None,
2943 _('abort if patch would apply lossily')),
2943 _('abort if patch would apply lossily')),
2944 ('', 'prefix', '',
2944 ('', 'prefix', '',
2945 _('apply patch to subdirectory'), _('DIR')),
2945 _('apply patch to subdirectory'), _('DIR')),
2946 ('', 'import-branch', None,
2946 ('', 'import-branch', None,
2947 _('use any branch information in patch (implied by --exact)'))] +
2947 _('use any branch information in patch (implied by --exact)'))] +
2948 commitopts + commitopts2 + similarityopts,
2948 commitopts + commitopts2 + similarityopts,
2949 _('[OPTION]... PATCH...'))
2949 _('[OPTION]... PATCH...'))
2950 def import_(ui, repo, patch1=None, *patches, **opts):
2950 def import_(ui, repo, patch1=None, *patches, **opts):
2951 """import an ordered set of patches
2951 """import an ordered set of patches
2952
2952
2953 Import a list of patches and commit them individually (unless
2953 Import a list of patches and commit them individually (unless
2954 --no-commit is specified).
2954 --no-commit is specified).
2955
2955
2956 To read a patch from standard input (stdin), use "-" as the patch
2956 To read a patch from standard input (stdin), use "-" as the patch
2957 name. If a URL is specified, the patch will be downloaded from
2957 name. If a URL is specified, the patch will be downloaded from
2958 there.
2958 there.
2959
2959
2960 Import first applies changes to the working directory (unless
2960 Import first applies changes to the working directory (unless
2961 --bypass is specified), import will abort if there are outstanding
2961 --bypass is specified), import will abort if there are outstanding
2962 changes.
2962 changes.
2963
2963
2964 Use --bypass to apply and commit patches directly to the
2964 Use --bypass to apply and commit patches directly to the
2965 repository, without affecting the working directory. Without
2965 repository, without affecting the working directory. Without
2966 --exact, patches will be applied on top of the working directory
2966 --exact, patches will be applied on top of the working directory
2967 parent revision.
2967 parent revision.
2968
2968
2969 You can import a patch straight from a mail message. Even patches
2969 You can import a patch straight from a mail message. Even patches
2970 as attachments work (to use the body part, it must have type
2970 as attachments work (to use the body part, it must have type
2971 text/plain or text/x-patch). From and Subject headers of email
2971 text/plain or text/x-patch). From and Subject headers of email
2972 message are used as default committer and commit message. All
2972 message are used as default committer and commit message. All
2973 text/plain body parts before first diff are added to the commit
2973 text/plain body parts before first diff are added to the commit
2974 message.
2974 message.
2975
2975
2976 If the imported patch was generated by :hg:`export`, user and
2976 If the imported patch was generated by :hg:`export`, user and
2977 description from patch override values from message headers and
2977 description from patch override values from message headers and
2978 body. Values given on command line with -m/--message and -u/--user
2978 body. Values given on command line with -m/--message and -u/--user
2979 override these.
2979 override these.
2980
2980
2981 If --exact is specified, import will set the working directory to
2981 If --exact is specified, import will set the working directory to
2982 the parent of each patch before applying it, and will abort if the
2982 the parent of each patch before applying it, and will abort if the
2983 resulting changeset has a different ID than the one recorded in
2983 resulting changeset has a different ID than the one recorded in
2984 the patch. This will guard against various ways that portable
2984 the patch. This will guard against various ways that portable
2985 patch formats and mail systems might fail to transfer Mercurial
2985 patch formats and mail systems might fail to transfer Mercurial
2986 data or metadata. See :hg:`bundle` for lossless transmission.
2986 data or metadata. See :hg:`bundle` for lossless transmission.
2987
2987
2988 Use --partial to ensure a changeset will be created from the patch
2988 Use --partial to ensure a changeset will be created from the patch
2989 even if some hunks fail to apply. Hunks that fail to apply will be
2989 even if some hunks fail to apply. Hunks that fail to apply will be
2990 written to a <target-file>.rej file. Conflicts can then be resolved
2990 written to a <target-file>.rej file. Conflicts can then be resolved
2991 by hand before :hg:`commit --amend` is run to update the created
2991 by hand before :hg:`commit --amend` is run to update the created
2992 changeset. This flag exists to let people import patches that
2992 changeset. This flag exists to let people import patches that
2993 partially apply without losing the associated metadata (author,
2993 partially apply without losing the associated metadata (author,
2994 date, description, ...).
2994 date, description, ...).
2995
2995
2996 .. note::
2996 .. note::
2997
2997
2998 When no hunks apply cleanly, :hg:`import --partial` will create
2998 When no hunks apply cleanly, :hg:`import --partial` will create
2999 an empty changeset, importing only the patch metadata.
2999 an empty changeset, importing only the patch metadata.
3000
3000
3001 With -s/--similarity, hg will attempt to discover renames and
3001 With -s/--similarity, hg will attempt to discover renames and
3002 copies in the patch in the same way as :hg:`addremove`.
3002 copies in the patch in the same way as :hg:`addremove`.
3003
3003
3004 It is possible to use external patch programs to perform the patch
3004 It is possible to use external patch programs to perform the patch
3005 by setting the ``ui.patch`` configuration option. For the default
3005 by setting the ``ui.patch`` configuration option. For the default
3006 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3006 internal tool, the fuzz can also be configured via ``patch.fuzz``.
3007 See :hg:`help config` for more information about configuration
3007 See :hg:`help config` for more information about configuration
3008 files and how to use these options.
3008 files and how to use these options.
3009
3009
3010 See :hg:`help dates` for a list of formats valid for -d/--date.
3010 See :hg:`help dates` for a list of formats valid for -d/--date.
3011
3011
3012 .. container:: verbose
3012 .. container:: verbose
3013
3013
3014 Examples:
3014 Examples:
3015
3015
3016 - import a traditional patch from a website and detect renames::
3016 - import a traditional patch from a website and detect renames::
3017
3017
3018 hg import -s 80 http://example.com/bugfix.patch
3018 hg import -s 80 http://example.com/bugfix.patch
3019
3019
3020 - import a changeset from an hgweb server::
3020 - import a changeset from an hgweb server::
3021
3021
3022 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3022 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
3023
3023
3024 - import all the patches in an Unix-style mbox::
3024 - import all the patches in an Unix-style mbox::
3025
3025
3026 hg import incoming-patches.mbox
3026 hg import incoming-patches.mbox
3027
3027
3028 - import patches from stdin::
3028 - import patches from stdin::
3029
3029
3030 hg import -
3030 hg import -
3031
3031
3032 - attempt to exactly restore an exported changeset (not always
3032 - attempt to exactly restore an exported changeset (not always
3033 possible)::
3033 possible)::
3034
3034
3035 hg import --exact proposed-fix.patch
3035 hg import --exact proposed-fix.patch
3036
3036
3037 - use an external tool to apply a patch which is too fuzzy for
3037 - use an external tool to apply a patch which is too fuzzy for
3038 the default internal tool.
3038 the default internal tool.
3039
3039
3040 hg import --config ui.patch="patch --merge" fuzzy.patch
3040 hg import --config ui.patch="patch --merge" fuzzy.patch
3041
3041
3042 - change the default fuzzing from 2 to a less strict 7
3042 - change the default fuzzing from 2 to a less strict 7
3043
3043
3044 hg import --config ui.fuzz=7 fuzz.patch
3044 hg import --config ui.fuzz=7 fuzz.patch
3045
3045
3046 Returns 0 on success, 1 on partial success (see --partial).
3046 Returns 0 on success, 1 on partial success (see --partial).
3047 """
3047 """
3048
3048
3049 if not patch1:
3049 if not patch1:
3050 raise error.Abort(_('need at least one patch to import'))
3050 raise error.Abort(_('need at least one patch to import'))
3051
3051
3052 patches = (patch1,) + patches
3052 patches = (patch1,) + patches
3053
3053
3054 date = opts.get('date')
3054 date = opts.get('date')
3055 if date:
3055 if date:
3056 opts['date'] = util.parsedate(date)
3056 opts['date'] = util.parsedate(date)
3057
3057
3058 exact = opts.get('exact')
3058 exact = opts.get('exact')
3059 update = not opts.get('bypass')
3059 update = not opts.get('bypass')
3060 if not update and opts.get('no_commit'):
3060 if not update and opts.get('no_commit'):
3061 raise error.Abort(_('cannot use --no-commit with --bypass'))
3061 raise error.Abort(_('cannot use --no-commit with --bypass'))
3062 try:
3062 try:
3063 sim = float(opts.get('similarity') or 0)
3063 sim = float(opts.get('similarity') or 0)
3064 except ValueError:
3064 except ValueError:
3065 raise error.Abort(_('similarity must be a number'))
3065 raise error.Abort(_('similarity must be a number'))
3066 if sim < 0 or sim > 100:
3066 if sim < 0 or sim > 100:
3067 raise error.Abort(_('similarity must be between 0 and 100'))
3067 raise error.Abort(_('similarity must be between 0 and 100'))
3068 if sim and not update:
3068 if sim and not update:
3069 raise error.Abort(_('cannot use --similarity with --bypass'))
3069 raise error.Abort(_('cannot use --similarity with --bypass'))
3070 if exact:
3070 if exact:
3071 if opts.get('edit'):
3071 if opts.get('edit'):
3072 raise error.Abort(_('cannot use --exact with --edit'))
3072 raise error.Abort(_('cannot use --exact with --edit'))
3073 if opts.get('prefix'):
3073 if opts.get('prefix'):
3074 raise error.Abort(_('cannot use --exact with --prefix'))
3074 raise error.Abort(_('cannot use --exact with --prefix'))
3075
3075
3076 base = opts["base"]
3076 base = opts["base"]
3077 wlock = dsguard = lock = tr = None
3077 wlock = dsguard = lock = tr = None
3078 msgs = []
3078 msgs = []
3079 ret = 0
3079 ret = 0
3080
3080
3081
3081
3082 try:
3082 try:
3083 wlock = repo.wlock()
3083 wlock = repo.wlock()
3084
3084
3085 if update:
3085 if update:
3086 cmdutil.checkunfinished(repo)
3086 cmdutil.checkunfinished(repo)
3087 if (exact or not opts.get('force')):
3087 if (exact or not opts.get('force')):
3088 cmdutil.bailifchanged(repo)
3088 cmdutil.bailifchanged(repo)
3089
3089
3090 if not opts.get('no_commit'):
3090 if not opts.get('no_commit'):
3091 lock = repo.lock()
3091 lock = repo.lock()
3092 tr = repo.transaction('import')
3092 tr = repo.transaction('import')
3093 else:
3093 else:
3094 dsguard = dirstateguard.dirstateguard(repo, 'import')
3094 dsguard = dirstateguard.dirstateguard(repo, 'import')
3095 parents = repo[None].parents()
3095 parents = repo[None].parents()
3096 for patchurl in patches:
3096 for patchurl in patches:
3097 if patchurl == '-':
3097 if patchurl == '-':
3098 ui.status(_('applying patch from stdin\n'))
3098 ui.status(_('applying patch from stdin\n'))
3099 patchfile = ui.fin
3099 patchfile = ui.fin
3100 patchurl = 'stdin' # for error message
3100 patchurl = 'stdin' # for error message
3101 else:
3101 else:
3102 patchurl = os.path.join(base, patchurl)
3102 patchurl = os.path.join(base, patchurl)
3103 ui.status(_('applying %s\n') % patchurl)
3103 ui.status(_('applying %s\n') % patchurl)
3104 patchfile = hg.openpath(ui, patchurl)
3104 patchfile = hg.openpath(ui, patchurl)
3105
3105
3106 haspatch = False
3106 haspatch = False
3107 for hunk in patch.split(patchfile):
3107 for hunk in patch.split(patchfile):
3108 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3108 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
3109 parents, opts,
3109 parents, opts,
3110 msgs, hg.clean)
3110 msgs, hg.clean)
3111 if msg:
3111 if msg:
3112 haspatch = True
3112 haspatch = True
3113 ui.note(msg + '\n')
3113 ui.note(msg + '\n')
3114 if update or exact:
3114 if update or exact:
3115 parents = repo[None].parents()
3115 parents = repo[None].parents()
3116 else:
3116 else:
3117 parents = [repo[node]]
3117 parents = [repo[node]]
3118 if rej:
3118 if rej:
3119 ui.write_err(_("patch applied partially\n"))
3119 ui.write_err(_("patch applied partially\n"))
3120 ui.write_err(_("(fix the .rej files and run "
3120 ui.write_err(_("(fix the .rej files and run "
3121 "`hg commit --amend`)\n"))
3121 "`hg commit --amend`)\n"))
3122 ret = 1
3122 ret = 1
3123 break
3123 break
3124
3124
3125 if not haspatch:
3125 if not haspatch:
3126 raise error.Abort(_('%s: no diffs found') % patchurl)
3126 raise error.Abort(_('%s: no diffs found') % patchurl)
3127
3127
3128 if tr:
3128 if tr:
3129 tr.close()
3129 tr.close()
3130 if msgs:
3130 if msgs:
3131 repo.savecommitmessage('\n* * *\n'.join(msgs))
3131 repo.savecommitmessage('\n* * *\n'.join(msgs))
3132 if dsguard:
3132 if dsguard:
3133 dsguard.close()
3133 dsguard.close()
3134 return ret
3134 return ret
3135 finally:
3135 finally:
3136 if tr:
3136 if tr:
3137 tr.release()
3137 tr.release()
3138 release(lock, dsguard, wlock)
3138 release(lock, dsguard, wlock)
3139
3139
3140 @command('incoming|in',
3140 @command('incoming|in',
3141 [('f', 'force', None,
3141 [('f', 'force', None,
3142 _('run even if remote repository is unrelated')),
3142 _('run even if remote repository is unrelated')),
3143 ('n', 'newest-first', None, _('show newest record first')),
3143 ('n', 'newest-first', None, _('show newest record first')),
3144 ('', 'bundle', '',
3144 ('', 'bundle', '',
3145 _('file to store the bundles into'), _('FILE')),
3145 _('file to store the bundles into'), _('FILE')),
3146 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3146 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3147 ('B', 'bookmarks', False, _("compare bookmarks")),
3147 ('B', 'bookmarks', False, _("compare bookmarks")),
3148 ('b', 'branch', [],
3148 ('b', 'branch', [],
3149 _('a specific branch you would like to pull'), _('BRANCH')),
3149 _('a specific branch you would like to pull'), _('BRANCH')),
3150 ] + logopts + remoteopts + subrepoopts,
3150 ] + logopts + remoteopts + subrepoopts,
3151 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3151 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3152 def incoming(ui, repo, source="default", **opts):
3152 def incoming(ui, repo, source="default", **opts):
3153 """show new changesets found in source
3153 """show new changesets found in source
3154
3154
3155 Show new changesets found in the specified path/URL or the default
3155 Show new changesets found in the specified path/URL or the default
3156 pull location. These are the changesets that would have been pulled
3156 pull location. These are the changesets that would have been pulled
3157 if a pull at the time you issued this command.
3157 if a pull at the time you issued this command.
3158
3158
3159 See pull for valid source format details.
3159 See pull for valid source format details.
3160
3160
3161 .. container:: verbose
3161 .. container:: verbose
3162
3162
3163 With -B/--bookmarks, the result of bookmark comparison between
3163 With -B/--bookmarks, the result of bookmark comparison between
3164 local and remote repositories is displayed. With -v/--verbose,
3164 local and remote repositories is displayed. With -v/--verbose,
3165 status is also displayed for each bookmark like below::
3165 status is also displayed for each bookmark like below::
3166
3166
3167 BM1 01234567890a added
3167 BM1 01234567890a added
3168 BM2 1234567890ab advanced
3168 BM2 1234567890ab advanced
3169 BM3 234567890abc diverged
3169 BM3 234567890abc diverged
3170 BM4 34567890abcd changed
3170 BM4 34567890abcd changed
3171
3171
3172 The action taken locally when pulling depends on the
3172 The action taken locally when pulling depends on the
3173 status of each bookmark:
3173 status of each bookmark:
3174
3174
3175 :``added``: pull will create it
3175 :``added``: pull will create it
3176 :``advanced``: pull will update it
3176 :``advanced``: pull will update it
3177 :``diverged``: pull will create a divergent bookmark
3177 :``diverged``: pull will create a divergent bookmark
3178 :``changed``: result depends on remote changesets
3178 :``changed``: result depends on remote changesets
3179
3179
3180 From the point of view of pulling behavior, bookmark
3180 From the point of view of pulling behavior, bookmark
3181 existing only in the remote repository are treated as ``added``,
3181 existing only in the remote repository are treated as ``added``,
3182 even if it is in fact locally deleted.
3182 even if it is in fact locally deleted.
3183
3183
3184 .. container:: verbose
3184 .. container:: verbose
3185
3185
3186 For remote repository, using --bundle avoids downloading the
3186 For remote repository, using --bundle avoids downloading the
3187 changesets twice if the incoming is followed by a pull.
3187 changesets twice if the incoming is followed by a pull.
3188
3188
3189 Examples:
3189 Examples:
3190
3190
3191 - show incoming changes with patches and full description::
3191 - show incoming changes with patches and full description::
3192
3192
3193 hg incoming -vp
3193 hg incoming -vp
3194
3194
3195 - show incoming changes excluding merges, store a bundle::
3195 - show incoming changes excluding merges, store a bundle::
3196
3196
3197 hg in -vpM --bundle incoming.hg
3197 hg in -vpM --bundle incoming.hg
3198 hg pull incoming.hg
3198 hg pull incoming.hg
3199
3199
3200 - briefly list changes inside a bundle::
3200 - briefly list changes inside a bundle::
3201
3201
3202 hg in changes.hg -T "{desc|firstline}\\n"
3202 hg in changes.hg -T "{desc|firstline}\\n"
3203
3203
3204 Returns 0 if there are incoming changes, 1 otherwise.
3204 Returns 0 if there are incoming changes, 1 otherwise.
3205 """
3205 """
3206 if opts.get('graph'):
3206 if opts.get('graph'):
3207 cmdutil.checkunsupportedgraphflags([], opts)
3207 cmdutil.checkunsupportedgraphflags([], opts)
3208 def display(other, chlist, displayer):
3208 def display(other, chlist, displayer):
3209 revdag = cmdutil.graphrevs(other, chlist, opts)
3209 revdag = cmdutil.graphrevs(other, chlist, opts)
3210 cmdutil.displaygraph(ui, repo, revdag, displayer,
3210 cmdutil.displaygraph(ui, repo, revdag, displayer,
3211 graphmod.asciiedges)
3211 graphmod.asciiedges)
3212
3212
3213 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3213 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3214 return 0
3214 return 0
3215
3215
3216 if opts.get('bundle') and opts.get('subrepos'):
3216 if opts.get('bundle') and opts.get('subrepos'):
3217 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3217 raise error.Abort(_('cannot combine --bundle and --subrepos'))
3218
3218
3219 if opts.get('bookmarks'):
3219 if opts.get('bookmarks'):
3220 source, branches = hg.parseurl(ui.expandpath(source),
3220 source, branches = hg.parseurl(ui.expandpath(source),
3221 opts.get('branch'))
3221 opts.get('branch'))
3222 other = hg.peer(repo, opts, source)
3222 other = hg.peer(repo, opts, source)
3223 if 'bookmarks' not in other.listkeys('namespaces'):
3223 if 'bookmarks' not in other.listkeys('namespaces'):
3224 ui.warn(_("remote doesn't support bookmarks\n"))
3224 ui.warn(_("remote doesn't support bookmarks\n"))
3225 return 0
3225 return 0
3226 ui.pager('incoming')
3226 ui.pager('incoming')
3227 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3227 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3228 return bookmarks.incoming(ui, repo, other)
3228 return bookmarks.incoming(ui, repo, other)
3229
3229
3230 repo._subtoppath = ui.expandpath(source)
3230 repo._subtoppath = ui.expandpath(source)
3231 try:
3231 try:
3232 return hg.incoming(ui, repo, source, opts)
3232 return hg.incoming(ui, repo, source, opts)
3233 finally:
3233 finally:
3234 del repo._subtoppath
3234 del repo._subtoppath
3235
3235
3236
3236
3237 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3237 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
3238 norepo=True)
3238 norepo=True)
3239 def init(ui, dest=".", **opts):
3239 def init(ui, dest=".", **opts):
3240 """create a new repository in the given directory
3240 """create a new repository in the given directory
3241
3241
3242 Initialize a new repository in the given directory. If the given
3242 Initialize a new repository in the given directory. If the given
3243 directory does not exist, it will be created.
3243 directory does not exist, it will be created.
3244
3244
3245 If no directory is given, the current directory is used.
3245 If no directory is given, the current directory is used.
3246
3246
3247 It is possible to specify an ``ssh://`` URL as the destination.
3247 It is possible to specify an ``ssh://`` URL as the destination.
3248 See :hg:`help urls` for more information.
3248 See :hg:`help urls` for more information.
3249
3249
3250 Returns 0 on success.
3250 Returns 0 on success.
3251 """
3251 """
3252 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3252 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3253
3253
3254 @command('locate',
3254 @command('locate',
3255 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3255 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3257 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3257 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3258 ] + walkopts,
3258 ] + walkopts,
3259 _('[OPTION]... [PATTERN]...'))
3259 _('[OPTION]... [PATTERN]...'))
3260 def locate(ui, repo, *pats, **opts):
3260 def locate(ui, repo, *pats, **opts):
3261 """locate files matching specific patterns (DEPRECATED)
3261 """locate files matching specific patterns (DEPRECATED)
3262
3262
3263 Print files under Mercurial control in the working directory whose
3263 Print files under Mercurial control in the working directory whose
3264 names match the given patterns.
3264 names match the given patterns.
3265
3265
3266 By default, this command searches all directories in the working
3266 By default, this command searches all directories in the working
3267 directory. To search just the current directory and its
3267 directory. To search just the current directory and its
3268 subdirectories, use "--include .".
3268 subdirectories, use "--include .".
3269
3269
3270 If no patterns are given to match, this command prints the names
3270 If no patterns are given to match, this command prints the names
3271 of all files under Mercurial control in the working directory.
3271 of all files under Mercurial control in the working directory.
3272
3272
3273 If you want to feed the output of this command into the "xargs"
3273 If you want to feed the output of this command into the "xargs"
3274 command, use the -0 option to both this command and "xargs". This
3274 command, use the -0 option to both this command and "xargs". This
3275 will avoid the problem of "xargs" treating single filenames that
3275 will avoid the problem of "xargs" treating single filenames that
3276 contain whitespace as multiple filenames.
3276 contain whitespace as multiple filenames.
3277
3277
3278 See :hg:`help files` for a more versatile command.
3278 See :hg:`help files` for a more versatile command.
3279
3279
3280 Returns 0 if a match is found, 1 otherwise.
3280 Returns 0 if a match is found, 1 otherwise.
3281 """
3281 """
3282 if opts.get('print0'):
3282 if opts.get('print0'):
3283 end = '\0'
3283 end = '\0'
3284 else:
3284 else:
3285 end = '\n'
3285 end = '\n'
3286 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3286 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3287
3287
3288 ret = 1
3288 ret = 1
3289 ctx = repo[rev]
3289 ctx = repo[rev]
3290 m = scmutil.match(ctx, pats, opts, default='relglob',
3290 m = scmutil.match(ctx, pats, opts, default='relglob',
3291 badfn=lambda x, y: False)
3291 badfn=lambda x, y: False)
3292
3292
3293 ui.pager('locate')
3293 ui.pager('locate')
3294 for abs in ctx.matches(m):
3294 for abs in ctx.matches(m):
3295 if opts.get('fullpath'):
3295 if opts.get('fullpath'):
3296 ui.write(repo.wjoin(abs), end)
3296 ui.write(repo.wjoin(abs), end)
3297 else:
3297 else:
3298 ui.write(((pats and m.rel(abs)) or abs), end)
3298 ui.write(((pats and m.rel(abs)) or abs), end)
3299 ret = 0
3299 ret = 0
3300
3300
3301 return ret
3301 return ret
3302
3302
3303 @command('^log|history',
3303 @command('^log|history',
3304 [('f', 'follow', None,
3304 [('f', 'follow', None,
3305 _('follow changeset history, or file history across copies and renames')),
3305 _('follow changeset history, or file history across copies and renames')),
3306 ('', 'follow-first', None,
3306 ('', 'follow-first', None,
3307 _('only follow the first parent of merge changesets (DEPRECATED)')),
3307 _('only follow the first parent of merge changesets (DEPRECATED)')),
3308 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3308 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3309 ('C', 'copies', None, _('show copied files')),
3309 ('C', 'copies', None, _('show copied files')),
3310 ('k', 'keyword', [],
3310 ('k', 'keyword', [],
3311 _('do case-insensitive search for a given text'), _('TEXT')),
3311 _('do case-insensitive search for a given text'), _('TEXT')),
3312 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3312 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
3313 ('', 'removed', None, _('include revisions where files were removed')),
3313 ('', 'removed', None, _('include revisions where files were removed')),
3314 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3314 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3315 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3315 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3316 ('', 'only-branch', [],
3316 ('', 'only-branch', [],
3317 _('show only changesets within the given named branch (DEPRECATED)'),
3317 _('show only changesets within the given named branch (DEPRECATED)'),
3318 _('BRANCH')),
3318 _('BRANCH')),
3319 ('b', 'branch', [],
3319 ('b', 'branch', [],
3320 _('show changesets within the given named branch'), _('BRANCH')),
3320 _('show changesets within the given named branch'), _('BRANCH')),
3321 ('P', 'prune', [],
3321 ('P', 'prune', [],
3322 _('do not display revision or any of its ancestors'), _('REV')),
3322 _('do not display revision or any of its ancestors'), _('REV')),
3323 ] + logopts + walkopts,
3323 ] + logopts + walkopts,
3324 _('[OPTION]... [FILE]'),
3324 _('[OPTION]... [FILE]'),
3325 inferrepo=True)
3325 inferrepo=True)
3326 def log(ui, repo, *pats, **opts):
3326 def log(ui, repo, *pats, **opts):
3327 """show revision history of entire repository or files
3327 """show revision history of entire repository or files
3328
3328
3329 Print the revision history of the specified files or the entire
3329 Print the revision history of the specified files or the entire
3330 project.
3330 project.
3331
3331
3332 If no revision range is specified, the default is ``tip:0`` unless
3332 If no revision range is specified, the default is ``tip:0`` unless
3333 --follow is set, in which case the working directory parent is
3333 --follow is set, in which case the working directory parent is
3334 used as the starting revision.
3334 used as the starting revision.
3335
3335
3336 File history is shown without following rename or copy history of
3336 File history is shown without following rename or copy history of
3337 files. Use -f/--follow with a filename to follow history across
3337 files. Use -f/--follow with a filename to follow history across
3338 renames and copies. --follow without a filename will only show
3338 renames and copies. --follow without a filename will only show
3339 ancestors or descendants of the starting revision.
3339 ancestors or descendants of the starting revision.
3340
3340
3341 By default this command prints revision number and changeset id,
3341 By default this command prints revision number and changeset id,
3342 tags, non-trivial parents, user, date and time, and a summary for
3342 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
3343 each commit. When the -v/--verbose switch is used, the list of
3344 changed files and full commit message are shown.
3344 changed files and full commit message are shown.
3345
3345
3346 With --graph the revisions are shown as an ASCII art DAG with the most
3346 With --graph the revisions are shown as an ASCII art DAG with the most
3347 recent changeset at the top.
3347 recent changeset at the top.
3348 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
3348 '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
3349 and '+' represents a fork where the changeset from the lines below is a
3350 parent of the 'o' merge on the same line.
3350 parent of the 'o' merge on the same line.
3351
3351
3352 .. note::
3352 .. note::
3353
3353
3354 :hg:`log --patch` may generate unexpected diff output for merge
3354 :hg:`log --patch` may generate unexpected diff output for merge
3355 changesets, as it will only compare the merge changeset against
3355 changesets, as it will only compare the merge changeset against
3356 its first parent. Also, only files different from BOTH parents
3356 its first parent. Also, only files different from BOTH parents
3357 will appear in files:.
3357 will appear in files:.
3358
3358
3359 .. note::
3359 .. note::
3360
3360
3361 For performance reasons, :hg:`log FILE` may omit duplicate changes
3361 For performance reasons, :hg:`log FILE` may omit duplicate changes
3362 made on branches and will not show removals or mode changes. To
3362 made on branches and will not show removals or mode changes. To
3363 see all such changes, use the --removed switch.
3363 see all such changes, use the --removed switch.
3364
3364
3365 .. container:: verbose
3365 .. container:: verbose
3366
3366
3367 Some examples:
3367 Some examples:
3368
3368
3369 - changesets with full descriptions and file lists::
3369 - changesets with full descriptions and file lists::
3370
3370
3371 hg log -v
3371 hg log -v
3372
3372
3373 - changesets ancestral to the working directory::
3373 - changesets ancestral to the working directory::
3374
3374
3375 hg log -f
3375 hg log -f
3376
3376
3377 - last 10 commits on the current branch::
3377 - last 10 commits on the current branch::
3378
3378
3379 hg log -l 10 -b .
3379 hg log -l 10 -b .
3380
3380
3381 - changesets showing all modifications of a file, including removals::
3381 - changesets showing all modifications of a file, including removals::
3382
3382
3383 hg log --removed file.c
3383 hg log --removed file.c
3384
3384
3385 - all changesets that touch a directory, with diffs, excluding merges::
3385 - all changesets that touch a directory, with diffs, excluding merges::
3386
3386
3387 hg log -Mp lib/
3387 hg log -Mp lib/
3388
3388
3389 - all revision numbers that match a keyword::
3389 - all revision numbers that match a keyword::
3390
3390
3391 hg log -k bug --template "{rev}\\n"
3391 hg log -k bug --template "{rev}\\n"
3392
3392
3393 - the full hash identifier of the working directory parent::
3393 - the full hash identifier of the working directory parent::
3394
3394
3395 hg log -r . --template "{node}\\n"
3395 hg log -r . --template "{node}\\n"
3396
3396
3397 - list available log templates::
3397 - list available log templates::
3398
3398
3399 hg log -T list
3399 hg log -T list
3400
3400
3401 - check if a given changeset is included in a tagged release::
3401 - check if a given changeset is included in a tagged release::
3402
3402
3403 hg log -r "a21ccf and ancestor(1.9)"
3403 hg log -r "a21ccf and ancestor(1.9)"
3404
3404
3405 - find all changesets by some user in a date range::
3405 - find all changesets by some user in a date range::
3406
3406
3407 hg log -k alice -d "may 2008 to jul 2008"
3407 hg log -k alice -d "may 2008 to jul 2008"
3408
3408
3409 - summary of all changesets after the last tag::
3409 - summary of all changesets after the last tag::
3410
3410
3411 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3411 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
3412
3412
3413 See :hg:`help dates` for a list of formats valid for -d/--date.
3413 See :hg:`help dates` for a list of formats valid for -d/--date.
3414
3414
3415 See :hg:`help revisions` for more about specifying and ordering
3415 See :hg:`help revisions` for more about specifying and ordering
3416 revisions.
3416 revisions.
3417
3417
3418 See :hg:`help templates` for more about pre-packaged styles and
3418 See :hg:`help templates` for more about pre-packaged styles and
3419 specifying custom templates.
3419 specifying custom templates.
3420
3420
3421 Returns 0 on success.
3421 Returns 0 on success.
3422
3422
3423 """
3423 """
3424 if opts.get('follow') and opts.get('rev'):
3424 if opts.get('follow') and opts.get('rev'):
3425 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3425 opts['rev'] = [revsetlang.formatspec('reverse(::%lr)', opts.get('rev'))]
3426 del opts['follow']
3426 del opts['follow']
3427
3427
3428 if opts.get('graph'):
3428 if opts.get('graph'):
3429 return cmdutil.graphlog(ui, repo, *pats, **opts)
3429 return cmdutil.graphlog(ui, repo, *pats, **opts)
3430
3430
3431 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3431 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
3432 limit = cmdutil.loglimit(opts)
3432 limit = cmdutil.loglimit(opts)
3433 count = 0
3433 count = 0
3434
3434
3435 getrenamed = None
3435 getrenamed = None
3436 if opts.get('copies'):
3436 if opts.get('copies'):
3437 endrev = None
3437 endrev = None
3438 if opts.get('rev'):
3438 if opts.get('rev'):
3439 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3439 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
3440 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3440 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
3441
3441
3442 ui.pager('log')
3442 ui.pager('log')
3443 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3443 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3444 for rev in revs:
3444 for rev in revs:
3445 if count == limit:
3445 if count == limit:
3446 break
3446 break
3447 ctx = repo[rev]
3447 ctx = repo[rev]
3448 copies = None
3448 copies = None
3449 if getrenamed is not None and rev:
3449 if getrenamed is not None and rev:
3450 copies = []
3450 copies = []
3451 for fn in ctx.files():
3451 for fn in ctx.files():
3452 rename = getrenamed(fn, rev)
3452 rename = getrenamed(fn, rev)
3453 if rename:
3453 if rename:
3454 copies.append((fn, rename[0]))
3454 copies.append((fn, rename[0]))
3455 if filematcher:
3455 if filematcher:
3456 revmatchfn = filematcher(ctx.rev())
3456 revmatchfn = filematcher(ctx.rev())
3457 else:
3457 else:
3458 revmatchfn = None
3458 revmatchfn = None
3459 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3459 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
3460 if displayer.flush(ctx):
3460 if displayer.flush(ctx):
3461 count += 1
3461 count += 1
3462
3462
3463 displayer.close()
3463 displayer.close()
3464
3464
3465 @command('manifest',
3465 @command('manifest',
3466 [('r', 'rev', '', _('revision to display'), _('REV')),
3466 [('r', 'rev', '', _('revision to display'), _('REV')),
3467 ('', 'all', False, _("list files from all revisions"))]
3467 ('', 'all', False, _("list files from all revisions"))]
3468 + formatteropts,
3468 + formatteropts,
3469 _('[-r REV]'))
3469 _('[-r REV]'))
3470 def manifest(ui, repo, node=None, rev=None, **opts):
3470 def manifest(ui, repo, node=None, rev=None, **opts):
3471 """output the current or given revision of the project manifest
3471 """output the current or given revision of the project manifest
3472
3472
3473 Print a list of version controlled files for the given revision.
3473 Print a list of version controlled files for the given revision.
3474 If no revision is given, the first parent of the working directory
3474 If no revision is given, the first parent of the working directory
3475 is used, or the null revision if no revision is checked out.
3475 is used, or the null revision if no revision is checked out.
3476
3476
3477 With -v, print file permissions, symlink and executable bits.
3477 With -v, print file permissions, symlink and executable bits.
3478 With --debug, print file revision hashes.
3478 With --debug, print file revision hashes.
3479
3479
3480 If option --all is specified, the list of all files from all revisions
3480 If option --all is specified, the list of all files from all revisions
3481 is printed. This includes deleted and renamed files.
3481 is printed. This includes deleted and renamed files.
3482
3482
3483 Returns 0 on success.
3483 Returns 0 on success.
3484 """
3484 """
3485 fm = ui.formatter('manifest', opts)
3485 fm = ui.formatter('manifest', opts)
3486
3486
3487 if opts.get('all'):
3487 if opts.get('all'):
3488 if rev or node:
3488 if rev or node:
3489 raise error.Abort(_("can't specify a revision with --all"))
3489 raise error.Abort(_("can't specify a revision with --all"))
3490
3490
3491 res = []
3491 res = []
3492 prefix = "data/"
3492 prefix = "data/"
3493 suffix = ".i"
3493 suffix = ".i"
3494 plen = len(prefix)
3494 plen = len(prefix)
3495 slen = len(suffix)
3495 slen = len(suffix)
3496 with repo.lock():
3496 with repo.lock():
3497 for fn, b, size in repo.store.datafiles():
3497 for fn, b, size in repo.store.datafiles():
3498 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3498 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
3499 res.append(fn[plen:-slen])
3499 res.append(fn[plen:-slen])
3500 ui.pager('manifest')
3500 ui.pager('manifest')
3501 for f in res:
3501 for f in res:
3502 fm.startitem()
3502 fm.startitem()
3503 fm.write("path", '%s\n', f)
3503 fm.write("path", '%s\n', f)
3504 fm.end()
3504 fm.end()
3505 return
3505 return
3506
3506
3507 if rev and node:
3507 if rev and node:
3508 raise error.Abort(_("please specify just one revision"))
3508 raise error.Abort(_("please specify just one revision"))
3509
3509
3510 if not node:
3510 if not node:
3511 node = rev
3511 node = rev
3512
3512
3513 char = {'l': '@', 'x': '*', '': ''}
3513 char = {'l': '@', 'x': '*', '': ''}
3514 mode = {'l': '644', 'x': '755', '': '644'}
3514 mode = {'l': '644', 'x': '755', '': '644'}
3515 ctx = scmutil.revsingle(repo, node)
3515 ctx = scmutil.revsingle(repo, node)
3516 mf = ctx.manifest()
3516 mf = ctx.manifest()
3517 ui.pager('manifest')
3517 ui.pager('manifest')
3518 for f in ctx:
3518 for f in ctx:
3519 fm.startitem()
3519 fm.startitem()
3520 fl = ctx[f].flags()
3520 fl = ctx[f].flags()
3521 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3521 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
3522 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3522 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
3523 fm.write('path', '%s\n', f)
3523 fm.write('path', '%s\n', f)
3524 fm.end()
3524 fm.end()
3525
3525
3526 @command('^merge',
3526 @command('^merge',
3527 [('f', 'force', None,
3527 [('f', 'force', None,
3528 _('force a merge including outstanding changes (DEPRECATED)')),
3528 _('force a merge including outstanding changes (DEPRECATED)')),
3529 ('r', 'rev', '', _('revision to merge'), _('REV')),
3529 ('r', 'rev', '', _('revision to merge'), _('REV')),
3530 ('P', 'preview', None,
3530 ('P', 'preview', None,
3531 _('review revisions to merge (no merge is performed)'))
3531 _('review revisions to merge (no merge is performed)'))
3532 ] + mergetoolopts,
3532 ] + mergetoolopts,
3533 _('[-P] [[-r] REV]'))
3533 _('[-P] [[-r] REV]'))
3534 def merge(ui, repo, node=None, **opts):
3534 def merge(ui, repo, node=None, **opts):
3535 """merge another revision into working directory
3535 """merge another revision into working directory
3536
3536
3537 The current working directory is updated with all changes made in
3537 The current working directory is updated with all changes made in
3538 the requested revision since the last common predecessor revision.
3538 the requested revision since the last common predecessor revision.
3539
3539
3540 Files that changed between either parent are marked as changed for
3540 Files that changed between either parent are marked as changed for
3541 the next commit and a commit must be performed before any further
3541 the next commit and a commit must be performed before any further
3542 updates to the repository are allowed. The next commit will have
3542 updates to the repository are allowed. The next commit will have
3543 two parents.
3543 two parents.
3544
3544
3545 ``--tool`` can be used to specify the merge tool used for file
3545 ``--tool`` can be used to specify the merge tool used for file
3546 merges. It overrides the HGMERGE environment variable and your
3546 merges. It overrides the HGMERGE environment variable and your
3547 configuration files. See :hg:`help merge-tools` for options.
3547 configuration files. See :hg:`help merge-tools` for options.
3548
3548
3549 If no revision is specified, the working directory's parent is a
3549 If no revision is specified, the working directory's parent is a
3550 head revision, and the current branch contains exactly one other
3550 head revision, and the current branch contains exactly one other
3551 head, the other head is merged with by default. Otherwise, an
3551 head, the other head is merged with by default. Otherwise, an
3552 explicit revision with which to merge with must be provided.
3552 explicit revision with which to merge with must be provided.
3553
3553
3554 See :hg:`help resolve` for information on handling file conflicts.
3554 See :hg:`help resolve` for information on handling file conflicts.
3555
3555
3556 To undo an uncommitted merge, use :hg:`update --clean .` which
3556 To undo an uncommitted merge, use :hg:`update --clean .` which
3557 will check out a clean copy of the original merge parent, losing
3557 will check out a clean copy of the original merge parent, losing
3558 all changes.
3558 all changes.
3559
3559
3560 Returns 0 on success, 1 if there are unresolved files.
3560 Returns 0 on success, 1 if there are unresolved files.
3561 """
3561 """
3562
3562
3563 if opts.get('rev') and node:
3563 if opts.get('rev') and node:
3564 raise error.Abort(_("please specify just one revision"))
3564 raise error.Abort(_("please specify just one revision"))
3565 if not node:
3565 if not node:
3566 node = opts.get('rev')
3566 node = opts.get('rev')
3567
3567
3568 if node:
3568 if node:
3569 node = scmutil.revsingle(repo, node).node()
3569 node = scmutil.revsingle(repo, node).node()
3570
3570
3571 if not node:
3571 if not node:
3572 node = repo[destutil.destmerge(repo)].node()
3572 node = repo[destutil.destmerge(repo)].node()
3573
3573
3574 if opts.get('preview'):
3574 if opts.get('preview'):
3575 # find nodes that are ancestors of p2 but not of p1
3575 # find nodes that are ancestors of p2 but not of p1
3576 p1 = repo.lookup('.')
3576 p1 = repo.lookup('.')
3577 p2 = repo.lookup(node)
3577 p2 = repo.lookup(node)
3578 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3578 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
3579
3579
3580 displayer = cmdutil.show_changeset(ui, repo, opts)
3580 displayer = cmdutil.show_changeset(ui, repo, opts)
3581 for node in nodes:
3581 for node in nodes:
3582 displayer.show(repo[node])
3582 displayer.show(repo[node])
3583 displayer.close()
3583 displayer.close()
3584 return 0
3584 return 0
3585
3585
3586 try:
3586 try:
3587 # ui.forcemerge is an internal variable, do not document
3587 # ui.forcemerge is an internal variable, do not document
3588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3588 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
3589 force = opts.get('force')
3589 force = opts.get('force')
3590 labels = ['working copy', 'merge rev']
3590 labels = ['working copy', 'merge rev']
3591 return hg.merge(repo, node, force=force, mergeforce=force,
3591 return hg.merge(repo, node, force=force, mergeforce=force,
3592 labels=labels)
3592 labels=labels)
3593 finally:
3593 finally:
3594 ui.setconfig('ui', 'forcemerge', '', 'merge')
3594 ui.setconfig('ui', 'forcemerge', '', 'merge')
3595
3595
3596 @command('outgoing|out',
3596 @command('outgoing|out',
3597 [('f', 'force', None, _('run even when the destination is unrelated')),
3597 [('f', 'force', None, _('run even when the destination is unrelated')),
3598 ('r', 'rev', [],
3598 ('r', 'rev', [],
3599 _('a changeset intended to be included in the destination'), _('REV')),
3599 _('a changeset intended to be included in the destination'), _('REV')),
3600 ('n', 'newest-first', None, _('show newest record first')),
3600 ('n', 'newest-first', None, _('show newest record first')),
3601 ('B', 'bookmarks', False, _('compare bookmarks')),
3601 ('B', 'bookmarks', False, _('compare bookmarks')),
3602 ('b', 'branch', [], _('a specific branch you would like to push'),
3602 ('b', 'branch', [], _('a specific branch you would like to push'),
3603 _('BRANCH')),
3603 _('BRANCH')),
3604 ] + logopts + remoteopts + subrepoopts,
3604 ] + logopts + remoteopts + subrepoopts,
3605 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3605 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
3606 def outgoing(ui, repo, dest=None, **opts):
3606 def outgoing(ui, repo, dest=None, **opts):
3607 """show changesets not found in the destination
3607 """show changesets not found in the destination
3608
3608
3609 Show changesets not found in the specified destination repository
3609 Show changesets not found in the specified destination repository
3610 or the default push location. These are the changesets that would
3610 or the default push location. These are the changesets that would
3611 be pushed if a push was requested.
3611 be pushed if a push was requested.
3612
3612
3613 See pull for details of valid destination formats.
3613 See pull for details of valid destination formats.
3614
3614
3615 .. container:: verbose
3615 .. container:: verbose
3616
3616
3617 With -B/--bookmarks, the result of bookmark comparison between
3617 With -B/--bookmarks, the result of bookmark comparison between
3618 local and remote repositories is displayed. With -v/--verbose,
3618 local and remote repositories is displayed. With -v/--verbose,
3619 status is also displayed for each bookmark like below::
3619 status is also displayed for each bookmark like below::
3620
3620
3621 BM1 01234567890a added
3621 BM1 01234567890a added
3622 BM2 deleted
3622 BM2 deleted
3623 BM3 234567890abc advanced
3623 BM3 234567890abc advanced
3624 BM4 34567890abcd diverged
3624 BM4 34567890abcd diverged
3625 BM5 4567890abcde changed
3625 BM5 4567890abcde changed
3626
3626
3627 The action taken when pushing depends on the
3627 The action taken when pushing depends on the
3628 status of each bookmark:
3628 status of each bookmark:
3629
3629
3630 :``added``: push with ``-B`` will create it
3630 :``added``: push with ``-B`` will create it
3631 :``deleted``: push with ``-B`` will delete it
3631 :``deleted``: push with ``-B`` will delete it
3632 :``advanced``: push will update it
3632 :``advanced``: push will update it
3633 :``diverged``: push with ``-B`` will update it
3633 :``diverged``: push with ``-B`` will update it
3634 :``changed``: push with ``-B`` will update it
3634 :``changed``: push with ``-B`` will update it
3635
3635
3636 From the point of view of pushing behavior, bookmarks
3636 From the point of view of pushing behavior, bookmarks
3637 existing only in the remote repository are treated as
3637 existing only in the remote repository are treated as
3638 ``deleted``, even if it is in fact added remotely.
3638 ``deleted``, even if it is in fact added remotely.
3639
3639
3640 Returns 0 if there are outgoing changes, 1 otherwise.
3640 Returns 0 if there are outgoing changes, 1 otherwise.
3641 """
3641 """
3642 if opts.get('graph'):
3642 if opts.get('graph'):
3643 cmdutil.checkunsupportedgraphflags([], opts)
3643 cmdutil.checkunsupportedgraphflags([], opts)
3644 ui.pager('outgoing')
3645 o, other = hg._outgoing(ui, repo, dest, opts)
3644 o, other = hg._outgoing(ui, repo, dest, opts)
3646 if not o:
3645 if not o:
3647 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3646 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3648 return
3647 return
3649
3648
3650 revdag = cmdutil.graphrevs(repo, o, opts)
3649 revdag = cmdutil.graphrevs(repo, o, opts)
3650 ui.pager('outgoing')
3651 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3651 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
3652 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3652 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
3653 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3653 cmdutil.outgoinghooks(ui, repo, other, opts, o)
3654 return 0
3654 return 0
3655
3655
3656 if opts.get('bookmarks'):
3656 if opts.get('bookmarks'):
3657 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3657 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3658 dest, branches = hg.parseurl(dest, opts.get('branch'))
3658 dest, branches = hg.parseurl(dest, opts.get('branch'))
3659 other = hg.peer(repo, opts, dest)
3659 other = hg.peer(repo, opts, dest)
3660 if 'bookmarks' not in other.listkeys('namespaces'):
3660 if 'bookmarks' not in other.listkeys('namespaces'):
3661 ui.warn(_("remote doesn't support bookmarks\n"))
3661 ui.warn(_("remote doesn't support bookmarks\n"))
3662 return 0
3662 return 0
3663 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3663 ui.pager('outgoing')
3664 ui.pager('outgoing')
3664 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
3665 return bookmarks.outgoing(ui, repo, other)
3665 return bookmarks.outgoing(ui, repo, other)
3666
3666
3667 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3667 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
3668 try:
3668 try:
3669 ui.pager('outgoing')
3670 return hg.outgoing(ui, repo, dest, opts)
3669 return hg.outgoing(ui, repo, dest, opts)
3671 finally:
3670 finally:
3672 del repo._subtoppath
3671 del repo._subtoppath
3673
3672
3674 @command('parents',
3673 @command('parents',
3675 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3674 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
3676 ] + templateopts,
3675 ] + templateopts,
3677 _('[-r REV] [FILE]'),
3676 _('[-r REV] [FILE]'),
3678 inferrepo=True)
3677 inferrepo=True)
3679 def parents(ui, repo, file_=None, **opts):
3678 def parents(ui, repo, file_=None, **opts):
3680 """show the parents of the working directory or revision (DEPRECATED)
3679 """show the parents of the working directory or revision (DEPRECATED)
3681
3680
3682 Print the working directory's parent revisions. If a revision is
3681 Print the working directory's parent revisions. If a revision is
3683 given via -r/--rev, the parent of that revision will be printed.
3682 given via -r/--rev, the parent of that revision will be printed.
3684 If a file argument is given, the revision in which the file was
3683 If a file argument is given, the revision in which the file was
3685 last changed (before the working directory revision or the
3684 last changed (before the working directory revision or the
3686 argument to --rev if given) is printed.
3685 argument to --rev if given) is printed.
3687
3686
3688 This command is equivalent to::
3687 This command is equivalent to::
3689
3688
3690 hg log -r "p1()+p2()" or
3689 hg log -r "p1()+p2()" or
3691 hg log -r "p1(REV)+p2(REV)" or
3690 hg log -r "p1(REV)+p2(REV)" or
3692 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3691 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
3693 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3692 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
3694
3693
3695 See :hg:`summary` and :hg:`help revsets` for related information.
3694 See :hg:`summary` and :hg:`help revsets` for related information.
3696
3695
3697 Returns 0 on success.
3696 Returns 0 on success.
3698 """
3697 """
3699
3698
3700 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3699 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3701
3700
3702 if file_:
3701 if file_:
3703 m = scmutil.match(ctx, (file_,), opts)
3702 m = scmutil.match(ctx, (file_,), opts)
3704 if m.anypats() or len(m.files()) != 1:
3703 if m.anypats() or len(m.files()) != 1:
3705 raise error.Abort(_('can only specify an explicit filename'))
3704 raise error.Abort(_('can only specify an explicit filename'))
3706 file_ = m.files()[0]
3705 file_ = m.files()[0]
3707 filenodes = []
3706 filenodes = []
3708 for cp in ctx.parents():
3707 for cp in ctx.parents():
3709 if not cp:
3708 if not cp:
3710 continue
3709 continue
3711 try:
3710 try:
3712 filenodes.append(cp.filenode(file_))
3711 filenodes.append(cp.filenode(file_))
3713 except error.LookupError:
3712 except error.LookupError:
3714 pass
3713 pass
3715 if not filenodes:
3714 if not filenodes:
3716 raise error.Abort(_("'%s' not found in manifest!") % file_)
3715 raise error.Abort(_("'%s' not found in manifest!") % file_)
3717 p = []
3716 p = []
3718 for fn in filenodes:
3717 for fn in filenodes:
3719 fctx = repo.filectx(file_, fileid=fn)
3718 fctx = repo.filectx(file_, fileid=fn)
3720 p.append(fctx.node())
3719 p.append(fctx.node())
3721 else:
3720 else:
3722 p = [cp.node() for cp in ctx.parents()]
3721 p = [cp.node() for cp in ctx.parents()]
3723
3722
3724 displayer = cmdutil.show_changeset(ui, repo, opts)
3723 displayer = cmdutil.show_changeset(ui, repo, opts)
3725 for n in p:
3724 for n in p:
3726 if n != nullid:
3725 if n != nullid:
3727 displayer.show(repo[n])
3726 displayer.show(repo[n])
3728 displayer.close()
3727 displayer.close()
3729
3728
3730 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3729 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
3731 def paths(ui, repo, search=None, **opts):
3730 def paths(ui, repo, search=None, **opts):
3732 """show aliases for remote repositories
3731 """show aliases for remote repositories
3733
3732
3734 Show definition of symbolic path name NAME. If no name is given,
3733 Show definition of symbolic path name NAME. If no name is given,
3735 show definition of all available names.
3734 show definition of all available names.
3736
3735
3737 Option -q/--quiet suppresses all output when searching for NAME
3736 Option -q/--quiet suppresses all output when searching for NAME
3738 and shows only the path names when listing all definitions.
3737 and shows only the path names when listing all definitions.
3739
3738
3740 Path names are defined in the [paths] section of your
3739 Path names are defined in the [paths] section of your
3741 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3740 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
3742 repository, ``.hg/hgrc`` is used, too.
3741 repository, ``.hg/hgrc`` is used, too.
3743
3742
3744 The path names ``default`` and ``default-push`` have a special
3743 The path names ``default`` and ``default-push`` have a special
3745 meaning. When performing a push or pull operation, they are used
3744 meaning. When performing a push or pull operation, they are used
3746 as fallbacks if no location is specified on the command-line.
3745 as fallbacks if no location is specified on the command-line.
3747 When ``default-push`` is set, it will be used for push and
3746 When ``default-push`` is set, it will be used for push and
3748 ``default`` will be used for pull; otherwise ``default`` is used
3747 ``default`` will be used for pull; otherwise ``default`` is used
3749 as the fallback for both. When cloning a repository, the clone
3748 as the fallback for both. When cloning a repository, the clone
3750 source is written as ``default`` in ``.hg/hgrc``.
3749 source is written as ``default`` in ``.hg/hgrc``.
3751
3750
3752 .. note::
3751 .. note::
3753
3752
3754 ``default`` and ``default-push`` apply to all inbound (e.g.
3753 ``default`` and ``default-push`` apply to all inbound (e.g.
3755 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3754 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
3756 and :hg:`bundle`) operations.
3755 and :hg:`bundle`) operations.
3757
3756
3758 See :hg:`help urls` for more information.
3757 See :hg:`help urls` for more information.
3759
3758
3760 Returns 0 on success.
3759 Returns 0 on success.
3761 """
3760 """
3762 ui.pager('paths')
3761 ui.pager('paths')
3763 if search:
3762 if search:
3764 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3763 pathitems = [(name, path) for name, path in ui.paths.iteritems()
3765 if name == search]
3764 if name == search]
3766 else:
3765 else:
3767 pathitems = sorted(ui.paths.iteritems())
3766 pathitems = sorted(ui.paths.iteritems())
3768
3767
3769 fm = ui.formatter('paths', opts)
3768 fm = ui.formatter('paths', opts)
3770 if fm.isplain():
3769 if fm.isplain():
3771 hidepassword = util.hidepassword
3770 hidepassword = util.hidepassword
3772 else:
3771 else:
3773 hidepassword = str
3772 hidepassword = str
3774 if ui.quiet:
3773 if ui.quiet:
3775 namefmt = '%s\n'
3774 namefmt = '%s\n'
3776 else:
3775 else:
3777 namefmt = '%s = '
3776 namefmt = '%s = '
3778 showsubopts = not search and not ui.quiet
3777 showsubopts = not search and not ui.quiet
3779
3778
3780 for name, path in pathitems:
3779 for name, path in pathitems:
3781 fm.startitem()
3780 fm.startitem()
3782 fm.condwrite(not search, 'name', namefmt, name)
3781 fm.condwrite(not search, 'name', namefmt, name)
3783 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3782 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
3784 for subopt, value in sorted(path.suboptions.items()):
3783 for subopt, value in sorted(path.suboptions.items()):
3785 assert subopt not in ('name', 'url')
3784 assert subopt not in ('name', 'url')
3786 if showsubopts:
3785 if showsubopts:
3787 fm.plain('%s:%s = ' % (name, subopt))
3786 fm.plain('%s:%s = ' % (name, subopt))
3788 fm.condwrite(showsubopts, subopt, '%s\n', value)
3787 fm.condwrite(showsubopts, subopt, '%s\n', value)
3789
3788
3790 fm.end()
3789 fm.end()
3791
3790
3792 if search and not pathitems:
3791 if search and not pathitems:
3793 if not ui.quiet:
3792 if not ui.quiet:
3794 ui.warn(_("not found!\n"))
3793 ui.warn(_("not found!\n"))
3795 return 1
3794 return 1
3796 else:
3795 else:
3797 return 0
3796 return 0
3798
3797
3799 @command('phase',
3798 @command('phase',
3800 [('p', 'public', False, _('set changeset phase to public')),
3799 [('p', 'public', False, _('set changeset phase to public')),
3801 ('d', 'draft', False, _('set changeset phase to draft')),
3800 ('d', 'draft', False, _('set changeset phase to draft')),
3802 ('s', 'secret', False, _('set changeset phase to secret')),
3801 ('s', 'secret', False, _('set changeset phase to secret')),
3803 ('f', 'force', False, _('allow to move boundary backward')),
3802 ('f', 'force', False, _('allow to move boundary backward')),
3804 ('r', 'rev', [], _('target revision'), _('REV')),
3803 ('r', 'rev', [], _('target revision'), _('REV')),
3805 ],
3804 ],
3806 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3805 _('[-p|-d|-s] [-f] [-r] [REV...]'))
3807 def phase(ui, repo, *revs, **opts):
3806 def phase(ui, repo, *revs, **opts):
3808 """set or show the current phase name
3807 """set or show the current phase name
3809
3808
3810 With no argument, show the phase name of the current revision(s).
3809 With no argument, show the phase name of the current revision(s).
3811
3810
3812 With one of -p/--public, -d/--draft or -s/--secret, change the
3811 With one of -p/--public, -d/--draft or -s/--secret, change the
3813 phase value of the specified revisions.
3812 phase value of the specified revisions.
3814
3813
3815 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3814 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
3816 lower phase to an higher phase. Phases are ordered as follows::
3815 lower phase to an higher phase. Phases are ordered as follows::
3817
3816
3818 public < draft < secret
3817 public < draft < secret
3819
3818
3820 Returns 0 on success, 1 if some phases could not be changed.
3819 Returns 0 on success, 1 if some phases could not be changed.
3821
3820
3822 (For more information about the phases concept, see :hg:`help phases`.)
3821 (For more information about the phases concept, see :hg:`help phases`.)
3823 """
3822 """
3824 # search for a unique phase argument
3823 # search for a unique phase argument
3825 targetphase = None
3824 targetphase = None
3826 for idx, name in enumerate(phases.phasenames):
3825 for idx, name in enumerate(phases.phasenames):
3827 if opts[name]:
3826 if opts[name]:
3828 if targetphase is not None:
3827 if targetphase is not None:
3829 raise error.Abort(_('only one phase can be specified'))
3828 raise error.Abort(_('only one phase can be specified'))
3830 targetphase = idx
3829 targetphase = idx
3831
3830
3832 # look for specified revision
3831 # look for specified revision
3833 revs = list(revs)
3832 revs = list(revs)
3834 revs.extend(opts['rev'])
3833 revs.extend(opts['rev'])
3835 if not revs:
3834 if not revs:
3836 # display both parents as the second parent phase can influence
3835 # display both parents as the second parent phase can influence
3837 # the phase of a merge commit
3836 # the phase of a merge commit
3838 revs = [c.rev() for c in repo[None].parents()]
3837 revs = [c.rev() for c in repo[None].parents()]
3839
3838
3840 revs = scmutil.revrange(repo, revs)
3839 revs = scmutil.revrange(repo, revs)
3841
3840
3842 lock = None
3841 lock = None
3843 ret = 0
3842 ret = 0
3844 if targetphase is None:
3843 if targetphase is None:
3845 # display
3844 # display
3846 for r in revs:
3845 for r in revs:
3847 ctx = repo[r]
3846 ctx = repo[r]
3848 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3847 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
3849 else:
3848 else:
3850 tr = None
3849 tr = None
3851 lock = repo.lock()
3850 lock = repo.lock()
3852 try:
3851 try:
3853 tr = repo.transaction("phase")
3852 tr = repo.transaction("phase")
3854 # set phase
3853 # set phase
3855 if not revs:
3854 if not revs:
3856 raise error.Abort(_('empty revision set'))
3855 raise error.Abort(_('empty revision set'))
3857 nodes = [repo[r].node() for r in revs]
3856 nodes = [repo[r].node() for r in revs]
3858 # moving revision from public to draft may hide them
3857 # moving revision from public to draft may hide them
3859 # We have to check result on an unfiltered repository
3858 # We have to check result on an unfiltered repository
3860 unfi = repo.unfiltered()
3859 unfi = repo.unfiltered()
3861 getphase = unfi._phasecache.phase
3860 getphase = unfi._phasecache.phase
3862 olddata = [getphase(unfi, r) for r in unfi]
3861 olddata = [getphase(unfi, r) for r in unfi]
3863 phases.advanceboundary(repo, tr, targetphase, nodes)
3862 phases.advanceboundary(repo, tr, targetphase, nodes)
3864 if opts['force']:
3863 if opts['force']:
3865 phases.retractboundary(repo, tr, targetphase, nodes)
3864 phases.retractboundary(repo, tr, targetphase, nodes)
3866 tr.close()
3865 tr.close()
3867 finally:
3866 finally:
3868 if tr is not None:
3867 if tr is not None:
3869 tr.release()
3868 tr.release()
3870 lock.release()
3869 lock.release()
3871 getphase = unfi._phasecache.phase
3870 getphase = unfi._phasecache.phase
3872 newdata = [getphase(unfi, r) for r in unfi]
3871 newdata = [getphase(unfi, r) for r in unfi]
3873 changes = sum(newdata[r] != olddata[r] for r in unfi)
3872 changes = sum(newdata[r] != olddata[r] for r in unfi)
3874 cl = unfi.changelog
3873 cl = unfi.changelog
3875 rejected = [n for n in nodes
3874 rejected = [n for n in nodes
3876 if newdata[cl.rev(n)] < targetphase]
3875 if newdata[cl.rev(n)] < targetphase]
3877 if rejected:
3876 if rejected:
3878 ui.warn(_('cannot move %i changesets to a higher '
3877 ui.warn(_('cannot move %i changesets to a higher '
3879 'phase, use --force\n') % len(rejected))
3878 'phase, use --force\n') % len(rejected))
3880 ret = 1
3879 ret = 1
3881 if changes:
3880 if changes:
3882 msg = _('phase changed for %i changesets\n') % changes
3881 msg = _('phase changed for %i changesets\n') % changes
3883 if ret:
3882 if ret:
3884 ui.status(msg)
3883 ui.status(msg)
3885 else:
3884 else:
3886 ui.note(msg)
3885 ui.note(msg)
3887 else:
3886 else:
3888 ui.warn(_('no phases changed\n'))
3887 ui.warn(_('no phases changed\n'))
3889 return ret
3888 return ret
3890
3889
3891 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3890 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
3892 """Run after a changegroup has been added via pull/unbundle
3891 """Run after a changegroup has been added via pull/unbundle
3893
3892
3894 This takes arguments below:
3893 This takes arguments below:
3895
3894
3896 :modheads: change of heads by pull/unbundle
3895 :modheads: change of heads by pull/unbundle
3897 :optupdate: updating working directory is needed or not
3896 :optupdate: updating working directory is needed or not
3898 :checkout: update destination revision (or None to default destination)
3897 :checkout: update destination revision (or None to default destination)
3899 :brev: a name, which might be a bookmark to be activated after updating
3898 :brev: a name, which might be a bookmark to be activated after updating
3900 """
3899 """
3901 if modheads == 0:
3900 if modheads == 0:
3902 return
3901 return
3903 if optupdate:
3902 if optupdate:
3904 try:
3903 try:
3905 return hg.updatetotally(ui, repo, checkout, brev)
3904 return hg.updatetotally(ui, repo, checkout, brev)
3906 except error.UpdateAbort as inst:
3905 except error.UpdateAbort as inst:
3907 msg = _("not updating: %s") % str(inst)
3906 msg = _("not updating: %s") % str(inst)
3908 hint = inst.hint
3907 hint = inst.hint
3909 raise error.UpdateAbort(msg, hint=hint)
3908 raise error.UpdateAbort(msg, hint=hint)
3910 if modheads > 1:
3909 if modheads > 1:
3911 currentbranchheads = len(repo.branchheads())
3910 currentbranchheads = len(repo.branchheads())
3912 if currentbranchheads == modheads:
3911 if currentbranchheads == modheads:
3913 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3912 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
3914 elif currentbranchheads > 1:
3913 elif currentbranchheads > 1:
3915 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3914 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
3916 "merge)\n"))
3915 "merge)\n"))
3917 else:
3916 else:
3918 ui.status(_("(run 'hg heads' to see heads)\n"))
3917 ui.status(_("(run 'hg heads' to see heads)\n"))
3919 else:
3918 else:
3920 ui.status(_("(run 'hg update' to get a working copy)\n"))
3919 ui.status(_("(run 'hg update' to get a working copy)\n"))
3921
3920
3922 @command('^pull',
3921 @command('^pull',
3923 [('u', 'update', None,
3922 [('u', 'update', None,
3924 _('update to new branch head if changesets were pulled')),
3923 _('update to new branch head if changesets were pulled')),
3925 ('f', 'force', None, _('run even when remote repository is unrelated')),
3924 ('f', 'force', None, _('run even when remote repository is unrelated')),
3926 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3925 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3927 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3926 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
3928 ('b', 'branch', [], _('a specific branch you would like to pull'),
3927 ('b', 'branch', [], _('a specific branch you would like to pull'),
3929 _('BRANCH')),
3928 _('BRANCH')),
3930 ] + remoteopts,
3929 ] + remoteopts,
3931 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3930 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
3932 def pull(ui, repo, source="default", **opts):
3931 def pull(ui, repo, source="default", **opts):
3933 """pull changes from the specified source
3932 """pull changes from the specified source
3934
3933
3935 Pull changes from a remote repository to a local one.
3934 Pull changes from a remote repository to a local one.
3936
3935
3937 This finds all changes from the repository at the specified path
3936 This finds all changes from the repository at the specified path
3938 or URL and adds them to a local repository (the current one unless
3937 or URL and adds them to a local repository (the current one unless
3939 -R is specified). By default, this does not update the copy of the
3938 -R is specified). By default, this does not update the copy of the
3940 project in the working directory.
3939 project in the working directory.
3941
3940
3942 Use :hg:`incoming` if you want to see what would have been added
3941 Use :hg:`incoming` if you want to see what would have been added
3943 by a pull at the time you issued this command. If you then decide
3942 by a pull at the time you issued this command. If you then decide
3944 to add those changes to the repository, you should use :hg:`pull
3943 to add those changes to the repository, you should use :hg:`pull
3945 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3944 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3946
3945
3947 If SOURCE is omitted, the 'default' path will be used.
3946 If SOURCE is omitted, the 'default' path will be used.
3948 See :hg:`help urls` for more information.
3947 See :hg:`help urls` for more information.
3949
3948
3950 Specifying bookmark as ``.`` is equivalent to specifying the active
3949 Specifying bookmark as ``.`` is equivalent to specifying the active
3951 bookmark's name.
3950 bookmark's name.
3952
3951
3953 Returns 0 on success, 1 if an update had unresolved files.
3952 Returns 0 on success, 1 if an update had unresolved files.
3954 """
3953 """
3955 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3954 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3956 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3955 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3957 other = hg.peer(repo, opts, source)
3956 other = hg.peer(repo, opts, source)
3958 try:
3957 try:
3959 revs, checkout = hg.addbranchrevs(repo, other, branches,
3958 revs, checkout = hg.addbranchrevs(repo, other, branches,
3960 opts.get('rev'))
3959 opts.get('rev'))
3961
3960
3962
3961
3963 pullopargs = {}
3962 pullopargs = {}
3964 if opts.get('bookmark'):
3963 if opts.get('bookmark'):
3965 if not revs:
3964 if not revs:
3966 revs = []
3965 revs = []
3967 # The list of bookmark used here is not the one used to actually
3966 # The list of bookmark used here is not the one used to actually
3968 # update the bookmark name. This can result in the revision pulled
3967 # update the bookmark name. This can result in the revision pulled
3969 # not ending up with the name of the bookmark because of a race
3968 # not ending up with the name of the bookmark because of a race
3970 # condition on the server. (See issue 4689 for details)
3969 # condition on the server. (See issue 4689 for details)
3971 remotebookmarks = other.listkeys('bookmarks')
3970 remotebookmarks = other.listkeys('bookmarks')
3972 pullopargs['remotebookmarks'] = remotebookmarks
3971 pullopargs['remotebookmarks'] = remotebookmarks
3973 for b in opts['bookmark']:
3972 for b in opts['bookmark']:
3974 b = repo._bookmarks.expandname(b)
3973 b = repo._bookmarks.expandname(b)
3975 if b not in remotebookmarks:
3974 if b not in remotebookmarks:
3976 raise error.Abort(_('remote bookmark %s not found!') % b)
3975 raise error.Abort(_('remote bookmark %s not found!') % b)
3977 revs.append(remotebookmarks[b])
3976 revs.append(remotebookmarks[b])
3978
3977
3979 if revs:
3978 if revs:
3980 try:
3979 try:
3981 # When 'rev' is a bookmark name, we cannot guarantee that it
3980 # When 'rev' is a bookmark name, we cannot guarantee that it
3982 # will be updated with that name because of a race condition
3981 # will be updated with that name because of a race condition
3983 # server side. (See issue 4689 for details)
3982 # server side. (See issue 4689 for details)
3984 oldrevs = revs
3983 oldrevs = revs
3985 revs = [] # actually, nodes
3984 revs = [] # actually, nodes
3986 for r in oldrevs:
3985 for r in oldrevs:
3987 node = other.lookup(r)
3986 node = other.lookup(r)
3988 revs.append(node)
3987 revs.append(node)
3989 if r == checkout:
3988 if r == checkout:
3990 checkout = node
3989 checkout = node
3991 except error.CapabilityError:
3990 except error.CapabilityError:
3992 err = _("other repository doesn't support revision lookup, "
3991 err = _("other repository doesn't support revision lookup, "
3993 "so a rev cannot be specified.")
3992 "so a rev cannot be specified.")
3994 raise error.Abort(err)
3993 raise error.Abort(err)
3995
3994
3996 pullopargs.update(opts.get('opargs', {}))
3995 pullopargs.update(opts.get('opargs', {}))
3997 modheads = exchange.pull(repo, other, heads=revs,
3996 modheads = exchange.pull(repo, other, heads=revs,
3998 force=opts.get('force'),
3997 force=opts.get('force'),
3999 bookmarks=opts.get('bookmark', ()),
3998 bookmarks=opts.get('bookmark', ()),
4000 opargs=pullopargs).cgresult
3999 opargs=pullopargs).cgresult
4001
4000
4002 # brev is a name, which might be a bookmark to be activated at
4001 # brev is a name, which might be a bookmark to be activated at
4003 # the end of the update. In other words, it is an explicit
4002 # the end of the update. In other words, it is an explicit
4004 # destination of the update
4003 # destination of the update
4005 brev = None
4004 brev = None
4006
4005
4007 if checkout:
4006 if checkout:
4008 checkout = str(repo.changelog.rev(checkout))
4007 checkout = str(repo.changelog.rev(checkout))
4009
4008
4010 # order below depends on implementation of
4009 # order below depends on implementation of
4011 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4010 # hg.addbranchrevs(). opts['bookmark'] is ignored,
4012 # because 'checkout' is determined without it.
4011 # because 'checkout' is determined without it.
4013 if opts.get('rev'):
4012 if opts.get('rev'):
4014 brev = opts['rev'][0]
4013 brev = opts['rev'][0]
4015 elif opts.get('branch'):
4014 elif opts.get('branch'):
4016 brev = opts['branch'][0]
4015 brev = opts['branch'][0]
4017 else:
4016 else:
4018 brev = branches[0]
4017 brev = branches[0]
4019 repo._subtoppath = source
4018 repo._subtoppath = source
4020 try:
4019 try:
4021 ret = postincoming(ui, repo, modheads, opts.get('update'),
4020 ret = postincoming(ui, repo, modheads, opts.get('update'),
4022 checkout, brev)
4021 checkout, brev)
4023
4022
4024 finally:
4023 finally:
4025 del repo._subtoppath
4024 del repo._subtoppath
4026
4025
4027 finally:
4026 finally:
4028 other.close()
4027 other.close()
4029 return ret
4028 return ret
4030
4029
4031 @command('^push',
4030 @command('^push',
4032 [('f', 'force', None, _('force push')),
4031 [('f', 'force', None, _('force push')),
4033 ('r', 'rev', [],
4032 ('r', 'rev', [],
4034 _('a changeset intended to be included in the destination'),
4033 _('a changeset intended to be included in the destination'),
4035 _('REV')),
4034 _('REV')),
4036 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4035 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4037 ('b', 'branch', [],
4036 ('b', 'branch', [],
4038 _('a specific branch you would like to push'), _('BRANCH')),
4037 _('a specific branch you would like to push'), _('BRANCH')),
4039 ('', 'new-branch', False, _('allow pushing a new branch')),
4038 ('', 'new-branch', False, _('allow pushing a new branch')),
4040 ] + remoteopts,
4039 ] + remoteopts,
4041 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4040 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4042 def push(ui, repo, dest=None, **opts):
4041 def push(ui, repo, dest=None, **opts):
4043 """push changes to the specified destination
4042 """push changes to the specified destination
4044
4043
4045 Push changesets from the local repository to the specified
4044 Push changesets from the local repository to the specified
4046 destination.
4045 destination.
4047
4046
4048 This operation is symmetrical to pull: it is identical to a pull
4047 This operation is symmetrical to pull: it is identical to a pull
4049 in the destination repository from the current one.
4048 in the destination repository from the current one.
4050
4049
4051 By default, push will not allow creation of new heads at the
4050 By default, push will not allow creation of new heads at the
4052 destination, since multiple heads would make it unclear which head
4051 destination, since multiple heads would make it unclear which head
4053 to use. In this situation, it is recommended to pull and merge
4052 to use. In this situation, it is recommended to pull and merge
4054 before pushing.
4053 before pushing.
4055
4054
4056 Use --new-branch if you want to allow push to create a new named
4055 Use --new-branch if you want to allow push to create a new named
4057 branch that is not present at the destination. This allows you to
4056 branch that is not present at the destination. This allows you to
4058 only create a new branch without forcing other changes.
4057 only create a new branch without forcing other changes.
4059
4058
4060 .. note::
4059 .. note::
4061
4060
4062 Extra care should be taken with the -f/--force option,
4061 Extra care should be taken with the -f/--force option,
4063 which will push all new heads on all branches, an action which will
4062 which will push all new heads on all branches, an action which will
4064 almost always cause confusion for collaborators.
4063 almost always cause confusion for collaborators.
4065
4064
4066 If -r/--rev is used, the specified revision and all its ancestors
4065 If -r/--rev is used, the specified revision and all its ancestors
4067 will be pushed to the remote repository.
4066 will be pushed to the remote repository.
4068
4067
4069 If -B/--bookmark is used, the specified bookmarked revision, its
4068 If -B/--bookmark is used, the specified bookmarked revision, its
4070 ancestors, and the bookmark will be pushed to the remote
4069 ancestors, and the bookmark will be pushed to the remote
4071 repository. Specifying ``.`` is equivalent to specifying the active
4070 repository. Specifying ``.`` is equivalent to specifying the active
4072 bookmark's name.
4071 bookmark's name.
4073
4072
4074 Please see :hg:`help urls` for important details about ``ssh://``
4073 Please see :hg:`help urls` for important details about ``ssh://``
4075 URLs. If DESTINATION is omitted, a default path will be used.
4074 URLs. If DESTINATION is omitted, a default path will be used.
4076
4075
4077 Returns 0 if push was successful, 1 if nothing to push.
4076 Returns 0 if push was successful, 1 if nothing to push.
4078 """
4077 """
4079
4078
4080 if opts.get('bookmark'):
4079 if opts.get('bookmark'):
4081 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4080 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
4082 for b in opts['bookmark']:
4081 for b in opts['bookmark']:
4083 # translate -B options to -r so changesets get pushed
4082 # translate -B options to -r so changesets get pushed
4084 b = repo._bookmarks.expandname(b)
4083 b = repo._bookmarks.expandname(b)
4085 if b in repo._bookmarks:
4084 if b in repo._bookmarks:
4086 opts.setdefault('rev', []).append(b)
4085 opts.setdefault('rev', []).append(b)
4087 else:
4086 else:
4088 # if we try to push a deleted bookmark, translate it to null
4087 # if we try to push a deleted bookmark, translate it to null
4089 # this lets simultaneous -r, -b options continue working
4088 # this lets simultaneous -r, -b options continue working
4090 opts.setdefault('rev', []).append("null")
4089 opts.setdefault('rev', []).append("null")
4091
4090
4092 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4091 path = ui.paths.getpath(dest, default=('default-push', 'default'))
4093 if not path:
4092 if not path:
4094 raise error.Abort(_('default repository not configured!'),
4093 raise error.Abort(_('default repository not configured!'),
4095 hint=_("see 'hg help config.paths'"))
4094 hint=_("see 'hg help config.paths'"))
4096 dest = path.pushloc or path.loc
4095 dest = path.pushloc or path.loc
4097 branches = (path.branch, opts.get('branch') or [])
4096 branches = (path.branch, opts.get('branch') or [])
4098 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4097 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4099 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4098 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4100 other = hg.peer(repo, opts, dest)
4099 other = hg.peer(repo, opts, dest)
4101
4100
4102 if revs:
4101 if revs:
4103 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4102 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4104 if not revs:
4103 if not revs:
4105 raise error.Abort(_("specified revisions evaluate to an empty set"),
4104 raise error.Abort(_("specified revisions evaluate to an empty set"),
4106 hint=_("use different revision arguments"))
4105 hint=_("use different revision arguments"))
4107 elif path.pushrev:
4106 elif path.pushrev:
4108 # It doesn't make any sense to specify ancestor revisions. So limit
4107 # It doesn't make any sense to specify ancestor revisions. So limit
4109 # to DAG heads to make discovery simpler.
4108 # to DAG heads to make discovery simpler.
4110 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4109 expr = revsetlang.formatspec('heads(%r)', path.pushrev)
4111 revs = scmutil.revrange(repo, [expr])
4110 revs = scmutil.revrange(repo, [expr])
4112 revs = [repo[rev].node() for rev in revs]
4111 revs = [repo[rev].node() for rev in revs]
4113 if not revs:
4112 if not revs:
4114 raise error.Abort(_('default push revset for path evaluates to an '
4113 raise error.Abort(_('default push revset for path evaluates to an '
4115 'empty set'))
4114 'empty set'))
4116
4115
4117 repo._subtoppath = dest
4116 repo._subtoppath = dest
4118 try:
4117 try:
4119 # push subrepos depth-first for coherent ordering
4118 # push subrepos depth-first for coherent ordering
4120 c = repo['']
4119 c = repo['']
4121 subs = c.substate # only repos that are committed
4120 subs = c.substate # only repos that are committed
4122 for s in sorted(subs):
4121 for s in sorted(subs):
4123 result = c.sub(s).push(opts)
4122 result = c.sub(s).push(opts)
4124 if result == 0:
4123 if result == 0:
4125 return not result
4124 return not result
4126 finally:
4125 finally:
4127 del repo._subtoppath
4126 del repo._subtoppath
4128 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4127 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
4129 newbranch=opts.get('new_branch'),
4128 newbranch=opts.get('new_branch'),
4130 bookmarks=opts.get('bookmark', ()),
4129 bookmarks=opts.get('bookmark', ()),
4131 opargs=opts.get('opargs'))
4130 opargs=opts.get('opargs'))
4132
4131
4133 result = not pushop.cgresult
4132 result = not pushop.cgresult
4134
4133
4135 if pushop.bkresult is not None:
4134 if pushop.bkresult is not None:
4136 if pushop.bkresult == 2:
4135 if pushop.bkresult == 2:
4137 result = 2
4136 result = 2
4138 elif not result and pushop.bkresult:
4137 elif not result and pushop.bkresult:
4139 result = 2
4138 result = 2
4140
4139
4141 return result
4140 return result
4142
4141
4143 @command('recover', [])
4142 @command('recover', [])
4144 def recover(ui, repo):
4143 def recover(ui, repo):
4145 """roll back an interrupted transaction
4144 """roll back an interrupted transaction
4146
4145
4147 Recover from an interrupted commit or pull.
4146 Recover from an interrupted commit or pull.
4148
4147
4149 This command tries to fix the repository status after an
4148 This command tries to fix the repository status after an
4150 interrupted operation. It should only be necessary when Mercurial
4149 interrupted operation. It should only be necessary when Mercurial
4151 suggests it.
4150 suggests it.
4152
4151
4153 Returns 0 if successful, 1 if nothing to recover or verify fails.
4152 Returns 0 if successful, 1 if nothing to recover or verify fails.
4154 """
4153 """
4155 if repo.recover():
4154 if repo.recover():
4156 return hg.verify(repo)
4155 return hg.verify(repo)
4157 return 1
4156 return 1
4158
4157
4159 @command('^remove|rm',
4158 @command('^remove|rm',
4160 [('A', 'after', None, _('record delete for missing files')),
4159 [('A', 'after', None, _('record delete for missing files')),
4161 ('f', 'force', None,
4160 ('f', 'force', None,
4162 _('forget added files, delete modified files')),
4161 _('forget added files, delete modified files')),
4163 ] + subrepoopts + walkopts,
4162 ] + subrepoopts + walkopts,
4164 _('[OPTION]... FILE...'),
4163 _('[OPTION]... FILE...'),
4165 inferrepo=True)
4164 inferrepo=True)
4166 def remove(ui, repo, *pats, **opts):
4165 def remove(ui, repo, *pats, **opts):
4167 """remove the specified files on the next commit
4166 """remove the specified files on the next commit
4168
4167
4169 Schedule the indicated files for removal from the current branch.
4168 Schedule the indicated files for removal from the current branch.
4170
4169
4171 This command schedules the files to be removed at the next commit.
4170 This command schedules the files to be removed at the next commit.
4172 To undo a remove before that, see :hg:`revert`. To undo added
4171 To undo a remove before that, see :hg:`revert`. To undo added
4173 files, see :hg:`forget`.
4172 files, see :hg:`forget`.
4174
4173
4175 .. container:: verbose
4174 .. container:: verbose
4176
4175
4177 -A/--after can be used to remove only files that have already
4176 -A/--after can be used to remove only files that have already
4178 been deleted, -f/--force can be used to force deletion, and -Af
4177 been deleted, -f/--force can be used to force deletion, and -Af
4179 can be used to remove files from the next revision without
4178 can be used to remove files from the next revision without
4180 deleting them from the working directory.
4179 deleting them from the working directory.
4181
4180
4182 The following table details the behavior of remove for different
4181 The following table details the behavior of remove for different
4183 file states (columns) and option combinations (rows). The file
4182 file states (columns) and option combinations (rows). The file
4184 states are Added [A], Clean [C], Modified [M] and Missing [!]
4183 states are Added [A], Clean [C], Modified [M] and Missing [!]
4185 (as reported by :hg:`status`). The actions are Warn, Remove
4184 (as reported by :hg:`status`). The actions are Warn, Remove
4186 (from branch) and Delete (from disk):
4185 (from branch) and Delete (from disk):
4187
4186
4188 ========= == == == ==
4187 ========= == == == ==
4189 opt/state A C M !
4188 opt/state A C M !
4190 ========= == == == ==
4189 ========= == == == ==
4191 none W RD W R
4190 none W RD W R
4192 -f R RD RD R
4191 -f R RD RD R
4193 -A W W W R
4192 -A W W W R
4194 -Af R R R R
4193 -Af R R R R
4195 ========= == == == ==
4194 ========= == == == ==
4196
4195
4197 .. note::
4196 .. note::
4198
4197
4199 :hg:`remove` never deletes files in Added [A] state from the
4198 :hg:`remove` never deletes files in Added [A] state from the
4200 working directory, not even if ``--force`` is specified.
4199 working directory, not even if ``--force`` is specified.
4201
4200
4202 Returns 0 on success, 1 if any warnings encountered.
4201 Returns 0 on success, 1 if any warnings encountered.
4203 """
4202 """
4204
4203
4205 after, force = opts.get('after'), opts.get('force')
4204 after, force = opts.get('after'), opts.get('force')
4206 if not pats and not after:
4205 if not pats and not after:
4207 raise error.Abort(_('no files specified'))
4206 raise error.Abort(_('no files specified'))
4208
4207
4209 m = scmutil.match(repo[None], pats, opts)
4208 m = scmutil.match(repo[None], pats, opts)
4210 subrepos = opts.get('subrepos')
4209 subrepos = opts.get('subrepos')
4211 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4210 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
4212
4211
4213 @command('rename|move|mv',
4212 @command('rename|move|mv',
4214 [('A', 'after', None, _('record a rename that has already occurred')),
4213 [('A', 'after', None, _('record a rename that has already occurred')),
4215 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4214 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4216 ] + walkopts + dryrunopts,
4215 ] + walkopts + dryrunopts,
4217 _('[OPTION]... SOURCE... DEST'))
4216 _('[OPTION]... SOURCE... DEST'))
4218 def rename(ui, repo, *pats, **opts):
4217 def rename(ui, repo, *pats, **opts):
4219 """rename files; equivalent of copy + remove
4218 """rename files; equivalent of copy + remove
4220
4219
4221 Mark dest as copies of sources; mark sources for deletion. If dest
4220 Mark dest as copies of sources; mark sources for deletion. If dest
4222 is a directory, copies are put in that directory. If dest is a
4221 is a directory, copies are put in that directory. If dest is a
4223 file, there can only be one source.
4222 file, there can only be one source.
4224
4223
4225 By default, this command copies the contents of files as they
4224 By default, this command copies the contents of files as they
4226 exist in the working directory. If invoked with -A/--after, the
4225 exist in the working directory. If invoked with -A/--after, the
4227 operation is recorded, but no copying is performed.
4226 operation is recorded, but no copying is performed.
4228
4227
4229 This command takes effect at the next commit. To undo a rename
4228 This command takes effect at the next commit. To undo a rename
4230 before that, see :hg:`revert`.
4229 before that, see :hg:`revert`.
4231
4230
4232 Returns 0 on success, 1 if errors are encountered.
4231 Returns 0 on success, 1 if errors are encountered.
4233 """
4232 """
4234 with repo.wlock(False):
4233 with repo.wlock(False):
4235 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4234 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4236
4235
4237 @command('resolve',
4236 @command('resolve',
4238 [('a', 'all', None, _('select all unresolved files')),
4237 [('a', 'all', None, _('select all unresolved files')),
4239 ('l', 'list', None, _('list state of files needing merge')),
4238 ('l', 'list', None, _('list state of files needing merge')),
4240 ('m', 'mark', None, _('mark files as resolved')),
4239 ('m', 'mark', None, _('mark files as resolved')),
4241 ('u', 'unmark', None, _('mark files as unresolved')),
4240 ('u', 'unmark', None, _('mark files as unresolved')),
4242 ('n', 'no-status', None, _('hide status prefix'))]
4241 ('n', 'no-status', None, _('hide status prefix'))]
4243 + mergetoolopts + walkopts + formatteropts,
4242 + mergetoolopts + walkopts + formatteropts,
4244 _('[OPTION]... [FILE]...'),
4243 _('[OPTION]... [FILE]...'),
4245 inferrepo=True)
4244 inferrepo=True)
4246 def resolve(ui, repo, *pats, **opts):
4245 def resolve(ui, repo, *pats, **opts):
4247 """redo merges or set/view the merge status of files
4246 """redo merges or set/view the merge status of files
4248
4247
4249 Merges with unresolved conflicts are often the result of
4248 Merges with unresolved conflicts are often the result of
4250 non-interactive merging using the ``internal:merge`` configuration
4249 non-interactive merging using the ``internal:merge`` configuration
4251 setting, or a command-line merge tool like ``diff3``. The resolve
4250 setting, or a command-line merge tool like ``diff3``. The resolve
4252 command is used to manage the files involved in a merge, after
4251 command is used to manage the files involved in a merge, after
4253 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4252 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4254 working directory must have two parents). See :hg:`help
4253 working directory must have two parents). See :hg:`help
4255 merge-tools` for information on configuring merge tools.
4254 merge-tools` for information on configuring merge tools.
4256
4255
4257 The resolve command can be used in the following ways:
4256 The resolve command can be used in the following ways:
4258
4257
4259 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4258 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4260 files, discarding any previous merge attempts. Re-merging is not
4259 files, discarding any previous merge attempts. Re-merging is not
4261 performed for files already marked as resolved. Use ``--all/-a``
4260 performed for files already marked as resolved. Use ``--all/-a``
4262 to select all unresolved files. ``--tool`` can be used to specify
4261 to select all unresolved files. ``--tool`` can be used to specify
4263 the merge tool used for the given files. It overrides the HGMERGE
4262 the merge tool used for the given files. It overrides the HGMERGE
4264 environment variable and your configuration files. Previous file
4263 environment variable and your configuration files. Previous file
4265 contents are saved with a ``.orig`` suffix.
4264 contents are saved with a ``.orig`` suffix.
4266
4265
4267 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4266 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4268 (e.g. after having manually fixed-up the files). The default is
4267 (e.g. after having manually fixed-up the files). The default is
4269 to mark all unresolved files.
4268 to mark all unresolved files.
4270
4269
4271 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4270 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4272 default is to mark all resolved files.
4271 default is to mark all resolved files.
4273
4272
4274 - :hg:`resolve -l`: list files which had or still have conflicts.
4273 - :hg:`resolve -l`: list files which had or still have conflicts.
4275 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4274 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4276 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4275 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
4277 the list. See :hg:`help filesets` for details.
4276 the list. See :hg:`help filesets` for details.
4278
4277
4279 .. note::
4278 .. note::
4280
4279
4281 Mercurial will not let you commit files with unresolved merge
4280 Mercurial will not let you commit files with unresolved merge
4282 conflicts. You must use :hg:`resolve -m ...` before you can
4281 conflicts. You must use :hg:`resolve -m ...` before you can
4283 commit after a conflicting merge.
4282 commit after a conflicting merge.
4284
4283
4285 Returns 0 on success, 1 if any files fail a resolve attempt.
4284 Returns 0 on success, 1 if any files fail a resolve attempt.
4286 """
4285 """
4287
4286
4288 flaglist = 'all mark unmark list no_status'.split()
4287 flaglist = 'all mark unmark list no_status'.split()
4289 all, mark, unmark, show, nostatus = \
4288 all, mark, unmark, show, nostatus = \
4290 [opts.get(o) for o in flaglist]
4289 [opts.get(o) for o in flaglist]
4291
4290
4292 if (show and (mark or unmark)) or (mark and unmark):
4291 if (show and (mark or unmark)) or (mark and unmark):
4293 raise error.Abort(_("too many options specified"))
4292 raise error.Abort(_("too many options specified"))
4294 if pats and all:
4293 if pats and all:
4295 raise error.Abort(_("can't specify --all and patterns"))
4294 raise error.Abort(_("can't specify --all and patterns"))
4296 if not (all or pats or show or mark or unmark):
4295 if not (all or pats or show or mark or unmark):
4297 raise error.Abort(_('no files or directories specified'),
4296 raise error.Abort(_('no files or directories specified'),
4298 hint=('use --all to re-merge all unresolved files'))
4297 hint=('use --all to re-merge all unresolved files'))
4299
4298
4300 if show:
4299 if show:
4301 ui.pager('resolve')
4300 ui.pager('resolve')
4302 fm = ui.formatter('resolve', opts)
4301 fm = ui.formatter('resolve', opts)
4303 ms = mergemod.mergestate.read(repo)
4302 ms = mergemod.mergestate.read(repo)
4304 m = scmutil.match(repo[None], pats, opts)
4303 m = scmutil.match(repo[None], pats, opts)
4305 for f in ms:
4304 for f in ms:
4306 if not m(f):
4305 if not m(f):
4307 continue
4306 continue
4308 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4307 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
4309 'd': 'driverresolved'}[ms[f]]
4308 'd': 'driverresolved'}[ms[f]]
4310 fm.startitem()
4309 fm.startitem()
4311 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4310 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
4312 fm.write('path', '%s\n', f, label=l)
4311 fm.write('path', '%s\n', f, label=l)
4313 fm.end()
4312 fm.end()
4314 return 0
4313 return 0
4315
4314
4316 with repo.wlock():
4315 with repo.wlock():
4317 ms = mergemod.mergestate.read(repo)
4316 ms = mergemod.mergestate.read(repo)
4318
4317
4319 if not (ms.active() or repo.dirstate.p2() != nullid):
4318 if not (ms.active() or repo.dirstate.p2() != nullid):
4320 raise error.Abort(
4319 raise error.Abort(
4321 _('resolve command not applicable when not merging'))
4320 _('resolve command not applicable when not merging'))
4322
4321
4323 wctx = repo[None]
4322 wctx = repo[None]
4324
4323
4325 if ms.mergedriver and ms.mdstate() == 'u':
4324 if ms.mergedriver and ms.mdstate() == 'u':
4326 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4325 proceed = mergemod.driverpreprocess(repo, ms, wctx)
4327 ms.commit()
4326 ms.commit()
4328 # allow mark and unmark to go through
4327 # allow mark and unmark to go through
4329 if not mark and not unmark and not proceed:
4328 if not mark and not unmark and not proceed:
4330 return 1
4329 return 1
4331
4330
4332 m = scmutil.match(wctx, pats, opts)
4331 m = scmutil.match(wctx, pats, opts)
4333 ret = 0
4332 ret = 0
4334 didwork = False
4333 didwork = False
4335 runconclude = False
4334 runconclude = False
4336
4335
4337 tocomplete = []
4336 tocomplete = []
4338 for f in ms:
4337 for f in ms:
4339 if not m(f):
4338 if not m(f):
4340 continue
4339 continue
4341
4340
4342 didwork = True
4341 didwork = True
4343
4342
4344 # don't let driver-resolved files be marked, and run the conclude
4343 # don't let driver-resolved files be marked, and run the conclude
4345 # step if asked to resolve
4344 # step if asked to resolve
4346 if ms[f] == "d":
4345 if ms[f] == "d":
4347 exact = m.exact(f)
4346 exact = m.exact(f)
4348 if mark:
4347 if mark:
4349 if exact:
4348 if exact:
4350 ui.warn(_('not marking %s as it is driver-resolved\n')
4349 ui.warn(_('not marking %s as it is driver-resolved\n')
4351 % f)
4350 % f)
4352 elif unmark:
4351 elif unmark:
4353 if exact:
4352 if exact:
4354 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4353 ui.warn(_('not unmarking %s as it is driver-resolved\n')
4355 % f)
4354 % f)
4356 else:
4355 else:
4357 runconclude = True
4356 runconclude = True
4358 continue
4357 continue
4359
4358
4360 if mark:
4359 if mark:
4361 ms.mark(f, "r")
4360 ms.mark(f, "r")
4362 elif unmark:
4361 elif unmark:
4363 ms.mark(f, "u")
4362 ms.mark(f, "u")
4364 else:
4363 else:
4365 # backup pre-resolve (merge uses .orig for its own purposes)
4364 # backup pre-resolve (merge uses .orig for its own purposes)
4366 a = repo.wjoin(f)
4365 a = repo.wjoin(f)
4367 try:
4366 try:
4368 util.copyfile(a, a + ".resolve")
4367 util.copyfile(a, a + ".resolve")
4369 except (IOError, OSError) as inst:
4368 except (IOError, OSError) as inst:
4370 if inst.errno != errno.ENOENT:
4369 if inst.errno != errno.ENOENT:
4371 raise
4370 raise
4372
4371
4373 try:
4372 try:
4374 # preresolve file
4373 # preresolve file
4375 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4374 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4376 'resolve')
4375 'resolve')
4377 complete, r = ms.preresolve(f, wctx)
4376 complete, r = ms.preresolve(f, wctx)
4378 if not complete:
4377 if not complete:
4379 tocomplete.append(f)
4378 tocomplete.append(f)
4380 elif r:
4379 elif r:
4381 ret = 1
4380 ret = 1
4382 finally:
4381 finally:
4383 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4382 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4384 ms.commit()
4383 ms.commit()
4385
4384
4386 # replace filemerge's .orig file with our resolve file, but only
4385 # replace filemerge's .orig file with our resolve file, but only
4387 # for merges that are complete
4386 # for merges that are complete
4388 if complete:
4387 if complete:
4389 try:
4388 try:
4390 util.rename(a + ".resolve",
4389 util.rename(a + ".resolve",
4391 scmutil.origpath(ui, repo, a))
4390 scmutil.origpath(ui, repo, a))
4392 except OSError as inst:
4391 except OSError as inst:
4393 if inst.errno != errno.ENOENT:
4392 if inst.errno != errno.ENOENT:
4394 raise
4393 raise
4395
4394
4396 for f in tocomplete:
4395 for f in tocomplete:
4397 try:
4396 try:
4398 # resolve file
4397 # resolve file
4399 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4398 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4400 'resolve')
4399 'resolve')
4401 r = ms.resolve(f, wctx)
4400 r = ms.resolve(f, wctx)
4402 if r:
4401 if r:
4403 ret = 1
4402 ret = 1
4404 finally:
4403 finally:
4405 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4404 ui.setconfig('ui', 'forcemerge', '', 'resolve')
4406 ms.commit()
4405 ms.commit()
4407
4406
4408 # replace filemerge's .orig file with our resolve file
4407 # replace filemerge's .orig file with our resolve file
4409 a = repo.wjoin(f)
4408 a = repo.wjoin(f)
4410 try:
4409 try:
4411 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4410 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
4412 except OSError as inst:
4411 except OSError as inst:
4413 if inst.errno != errno.ENOENT:
4412 if inst.errno != errno.ENOENT:
4414 raise
4413 raise
4415
4414
4416 ms.commit()
4415 ms.commit()
4417 ms.recordactions()
4416 ms.recordactions()
4418
4417
4419 if not didwork and pats:
4418 if not didwork and pats:
4420 hint = None
4419 hint = None
4421 if not any([p for p in pats if p.find(':') >= 0]):
4420 if not any([p for p in pats if p.find(':') >= 0]):
4422 pats = ['path:%s' % p for p in pats]
4421 pats = ['path:%s' % p for p in pats]
4423 m = scmutil.match(wctx, pats, opts)
4422 m = scmutil.match(wctx, pats, opts)
4424 for f in ms:
4423 for f in ms:
4425 if not m(f):
4424 if not m(f):
4426 continue
4425 continue
4427 flags = ''.join(['-%s ' % o[0] for o in flaglist
4426 flags = ''.join(['-%s ' % o[0] for o in flaglist
4428 if opts.get(o)])
4427 if opts.get(o)])
4429 hint = _("(try: hg resolve %s%s)\n") % (
4428 hint = _("(try: hg resolve %s%s)\n") % (
4430 flags,
4429 flags,
4431 ' '.join(pats))
4430 ' '.join(pats))
4432 break
4431 break
4433 ui.warn(_("arguments do not match paths that need resolving\n"))
4432 ui.warn(_("arguments do not match paths that need resolving\n"))
4434 if hint:
4433 if hint:
4435 ui.warn(hint)
4434 ui.warn(hint)
4436 elif ms.mergedriver and ms.mdstate() != 's':
4435 elif ms.mergedriver and ms.mdstate() != 's':
4437 # run conclude step when either a driver-resolved file is requested
4436 # run conclude step when either a driver-resolved file is requested
4438 # or there are no driver-resolved files
4437 # or there are no driver-resolved files
4439 # we can't use 'ret' to determine whether any files are unresolved
4438 # we can't use 'ret' to determine whether any files are unresolved
4440 # because we might not have tried to resolve some
4439 # because we might not have tried to resolve some
4441 if ((runconclude or not list(ms.driverresolved()))
4440 if ((runconclude or not list(ms.driverresolved()))
4442 and not list(ms.unresolved())):
4441 and not list(ms.unresolved())):
4443 proceed = mergemod.driverconclude(repo, ms, wctx)
4442 proceed = mergemod.driverconclude(repo, ms, wctx)
4444 ms.commit()
4443 ms.commit()
4445 if not proceed:
4444 if not proceed:
4446 return 1
4445 return 1
4447
4446
4448 # Nudge users into finishing an unfinished operation
4447 # Nudge users into finishing an unfinished operation
4449 unresolvedf = list(ms.unresolved())
4448 unresolvedf = list(ms.unresolved())
4450 driverresolvedf = list(ms.driverresolved())
4449 driverresolvedf = list(ms.driverresolved())
4451 if not unresolvedf and not driverresolvedf:
4450 if not unresolvedf and not driverresolvedf:
4452 ui.status(_('(no more unresolved files)\n'))
4451 ui.status(_('(no more unresolved files)\n'))
4453 cmdutil.checkafterresolved(repo)
4452 cmdutil.checkafterresolved(repo)
4454 elif not unresolvedf:
4453 elif not unresolvedf:
4455 ui.status(_('(no more unresolved files -- '
4454 ui.status(_('(no more unresolved files -- '
4456 'run "hg resolve --all" to conclude)\n'))
4455 'run "hg resolve --all" to conclude)\n'))
4457
4456
4458 return ret
4457 return ret
4459
4458
4460 @command('revert',
4459 @command('revert',
4461 [('a', 'all', None, _('revert all changes when no arguments given')),
4460 [('a', 'all', None, _('revert all changes when no arguments given')),
4462 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4461 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4463 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4462 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4464 ('C', 'no-backup', None, _('do not save backup copies of files')),
4463 ('C', 'no-backup', None, _('do not save backup copies of files')),
4465 ('i', 'interactive', None,
4464 ('i', 'interactive', None,
4466 _('interactively select the changes (EXPERIMENTAL)')),
4465 _('interactively select the changes (EXPERIMENTAL)')),
4467 ] + walkopts + dryrunopts,
4466 ] + walkopts + dryrunopts,
4468 _('[OPTION]... [-r REV] [NAME]...'))
4467 _('[OPTION]... [-r REV] [NAME]...'))
4469 def revert(ui, repo, *pats, **opts):
4468 def revert(ui, repo, *pats, **opts):
4470 """restore files to their checkout state
4469 """restore files to their checkout state
4471
4470
4472 .. note::
4471 .. note::
4473
4472
4474 To check out earlier revisions, you should use :hg:`update REV`.
4473 To check out earlier revisions, you should use :hg:`update REV`.
4475 To cancel an uncommitted merge (and lose your changes),
4474 To cancel an uncommitted merge (and lose your changes),
4476 use :hg:`update --clean .`.
4475 use :hg:`update --clean .`.
4477
4476
4478 With no revision specified, revert the specified files or directories
4477 With no revision specified, revert the specified files or directories
4479 to the contents they had in the parent of the working directory.
4478 to the contents they had in the parent of the working directory.
4480 This restores the contents of files to an unmodified
4479 This restores the contents of files to an unmodified
4481 state and unschedules adds, removes, copies, and renames. If the
4480 state and unschedules adds, removes, copies, and renames. If the
4482 working directory has two parents, you must explicitly specify a
4481 working directory has two parents, you must explicitly specify a
4483 revision.
4482 revision.
4484
4483
4485 Using the -r/--rev or -d/--date options, revert the given files or
4484 Using the -r/--rev or -d/--date options, revert the given files or
4486 directories to their states as of a specific revision. Because
4485 directories to their states as of a specific revision. Because
4487 revert does not change the working directory parents, this will
4486 revert does not change the working directory parents, this will
4488 cause these files to appear modified. This can be helpful to "back
4487 cause these files to appear modified. This can be helpful to "back
4489 out" some or all of an earlier change. See :hg:`backout` for a
4488 out" some or all of an earlier change. See :hg:`backout` for a
4490 related method.
4489 related method.
4491
4490
4492 Modified files are saved with a .orig suffix before reverting.
4491 Modified files are saved with a .orig suffix before reverting.
4493 To disable these backups, use --no-backup. It is possible to store
4492 To disable these backups, use --no-backup. It is possible to store
4494 the backup files in a custom directory relative to the root of the
4493 the backup files in a custom directory relative to the root of the
4495 repository by setting the ``ui.origbackuppath`` configuration
4494 repository by setting the ``ui.origbackuppath`` configuration
4496 option.
4495 option.
4497
4496
4498 See :hg:`help dates` for a list of formats valid for -d/--date.
4497 See :hg:`help dates` for a list of formats valid for -d/--date.
4499
4498
4500 See :hg:`help backout` for a way to reverse the effect of an
4499 See :hg:`help backout` for a way to reverse the effect of an
4501 earlier changeset.
4500 earlier changeset.
4502
4501
4503 Returns 0 on success.
4502 Returns 0 on success.
4504 """
4503 """
4505
4504
4506 if opts.get("date"):
4505 if opts.get("date"):
4507 if opts.get("rev"):
4506 if opts.get("rev"):
4508 raise error.Abort(_("you can't specify a revision and a date"))
4507 raise error.Abort(_("you can't specify a revision and a date"))
4509 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4508 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
4510
4509
4511 parent, p2 = repo.dirstate.parents()
4510 parent, p2 = repo.dirstate.parents()
4512 if not opts.get('rev') and p2 != nullid:
4511 if not opts.get('rev') and p2 != nullid:
4513 # revert after merge is a trap for new users (issue2915)
4512 # revert after merge is a trap for new users (issue2915)
4514 raise error.Abort(_('uncommitted merge with no revision specified'),
4513 raise error.Abort(_('uncommitted merge with no revision specified'),
4515 hint=_("use 'hg update' or see 'hg help revert'"))
4514 hint=_("use 'hg update' or see 'hg help revert'"))
4516
4515
4517 ctx = scmutil.revsingle(repo, opts.get('rev'))
4516 ctx = scmutil.revsingle(repo, opts.get('rev'))
4518
4517
4519 if (not (pats or opts.get('include') or opts.get('exclude') or
4518 if (not (pats or opts.get('include') or opts.get('exclude') or
4520 opts.get('all') or opts.get('interactive'))):
4519 opts.get('all') or opts.get('interactive'))):
4521 msg = _("no files or directories specified")
4520 msg = _("no files or directories specified")
4522 if p2 != nullid:
4521 if p2 != nullid:
4523 hint = _("uncommitted merge, use --all to discard all changes,"
4522 hint = _("uncommitted merge, use --all to discard all changes,"
4524 " or 'hg update -C .' to abort the merge")
4523 " or 'hg update -C .' to abort the merge")
4525 raise error.Abort(msg, hint=hint)
4524 raise error.Abort(msg, hint=hint)
4526 dirty = any(repo.status())
4525 dirty = any(repo.status())
4527 node = ctx.node()
4526 node = ctx.node()
4528 if node != parent:
4527 if node != parent:
4529 if dirty:
4528 if dirty:
4530 hint = _("uncommitted changes, use --all to discard all"
4529 hint = _("uncommitted changes, use --all to discard all"
4531 " changes, or 'hg update %s' to update") % ctx.rev()
4530 " changes, or 'hg update %s' to update") % ctx.rev()
4532 else:
4531 else:
4533 hint = _("use --all to revert all files,"
4532 hint = _("use --all to revert all files,"
4534 " or 'hg update %s' to update") % ctx.rev()
4533 " or 'hg update %s' to update") % ctx.rev()
4535 elif dirty:
4534 elif dirty:
4536 hint = _("uncommitted changes, use --all to discard all changes")
4535 hint = _("uncommitted changes, use --all to discard all changes")
4537 else:
4536 else:
4538 hint = _("use --all to revert all files")
4537 hint = _("use --all to revert all files")
4539 raise error.Abort(msg, hint=hint)
4538 raise error.Abort(msg, hint=hint)
4540
4539
4541 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4540 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
4542
4541
4543 @command('rollback', dryrunopts +
4542 @command('rollback', dryrunopts +
4544 [('f', 'force', False, _('ignore safety measures'))])
4543 [('f', 'force', False, _('ignore safety measures'))])
4545 def rollback(ui, repo, **opts):
4544 def rollback(ui, repo, **opts):
4546 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4545 """roll back the last transaction (DANGEROUS) (DEPRECATED)
4547
4546
4548 Please use :hg:`commit --amend` instead of rollback to correct
4547 Please use :hg:`commit --amend` instead of rollback to correct
4549 mistakes in the last commit.
4548 mistakes in the last commit.
4550
4549
4551 This command should be used with care. There is only one level of
4550 This command should be used with care. There is only one level of
4552 rollback, and there is no way to undo a rollback. It will also
4551 rollback, and there is no way to undo a rollback. It will also
4553 restore the dirstate at the time of the last transaction, losing
4552 restore the dirstate at the time of the last transaction, losing
4554 any dirstate changes since that time. This command does not alter
4553 any dirstate changes since that time. This command does not alter
4555 the working directory.
4554 the working directory.
4556
4555
4557 Transactions are used to encapsulate the effects of all commands
4556 Transactions are used to encapsulate the effects of all commands
4558 that create new changesets or propagate existing changesets into a
4557 that create new changesets or propagate existing changesets into a
4559 repository.
4558 repository.
4560
4559
4561 .. container:: verbose
4560 .. container:: verbose
4562
4561
4563 For example, the following commands are transactional, and their
4562 For example, the following commands are transactional, and their
4564 effects can be rolled back:
4563 effects can be rolled back:
4565
4564
4566 - commit
4565 - commit
4567 - import
4566 - import
4568 - pull
4567 - pull
4569 - push (with this repository as the destination)
4568 - push (with this repository as the destination)
4570 - unbundle
4569 - unbundle
4571
4570
4572 To avoid permanent data loss, rollback will refuse to rollback a
4571 To avoid permanent data loss, rollback will refuse to rollback a
4573 commit transaction if it isn't checked out. Use --force to
4572 commit transaction if it isn't checked out. Use --force to
4574 override this protection.
4573 override this protection.
4575
4574
4576 The rollback command can be entirely disabled by setting the
4575 The rollback command can be entirely disabled by setting the
4577 ``ui.rollback`` configuration setting to false. If you're here
4576 ``ui.rollback`` configuration setting to false. If you're here
4578 because you want to use rollback and it's disabled, you can
4577 because you want to use rollback and it's disabled, you can
4579 re-enable the command by setting ``ui.rollback`` to true.
4578 re-enable the command by setting ``ui.rollback`` to true.
4580
4579
4581 This command is not intended for use on public repositories. Once
4580 This command is not intended for use on public repositories. Once
4582 changes are visible for pull by other users, rolling a transaction
4581 changes are visible for pull by other users, rolling a transaction
4583 back locally is ineffective (someone else may already have pulled
4582 back locally is ineffective (someone else may already have pulled
4584 the changes). Furthermore, a race is possible with readers of the
4583 the changes). Furthermore, a race is possible with readers of the
4585 repository; for example an in-progress pull from the repository
4584 repository; for example an in-progress pull from the repository
4586 may fail if a rollback is performed.
4585 may fail if a rollback is performed.
4587
4586
4588 Returns 0 on success, 1 if no rollback data is available.
4587 Returns 0 on success, 1 if no rollback data is available.
4589 """
4588 """
4590 if not ui.configbool('ui', 'rollback', True):
4589 if not ui.configbool('ui', 'rollback', True):
4591 raise error.Abort(_('rollback is disabled because it is unsafe'),
4590 raise error.Abort(_('rollback is disabled because it is unsafe'),
4592 hint=('see `hg help -v rollback` for information'))
4591 hint=('see `hg help -v rollback` for information'))
4593 return repo.rollback(dryrun=opts.get('dry_run'),
4592 return repo.rollback(dryrun=opts.get('dry_run'),
4594 force=opts.get('force'))
4593 force=opts.get('force'))
4595
4594
4596 @command('root', [])
4595 @command('root', [])
4597 def root(ui, repo):
4596 def root(ui, repo):
4598 """print the root (top) of the current working directory
4597 """print the root (top) of the current working directory
4599
4598
4600 Print the root directory of the current repository.
4599 Print the root directory of the current repository.
4601
4600
4602 Returns 0 on success.
4601 Returns 0 on success.
4603 """
4602 """
4604 ui.write(repo.root + "\n")
4603 ui.write(repo.root + "\n")
4605
4604
4606 @command('^serve',
4605 @command('^serve',
4607 [('A', 'accesslog', '', _('name of access log file to write to'),
4606 [('A', 'accesslog', '', _('name of access log file to write to'),
4608 _('FILE')),
4607 _('FILE')),
4609 ('d', 'daemon', None, _('run server in background')),
4608 ('d', 'daemon', None, _('run server in background')),
4610 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4609 ('', 'daemon-postexec', [], _('used internally by daemon mode')),
4611 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4610 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
4612 # use string type, then we can check if something was passed
4611 # use string type, then we can check if something was passed
4613 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4612 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
4614 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4613 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
4615 _('ADDR')),
4614 _('ADDR')),
4616 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4615 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
4617 _('PREFIX')),
4616 _('PREFIX')),
4618 ('n', 'name', '',
4617 ('n', 'name', '',
4619 _('name to show in web pages (default: working directory)'), _('NAME')),
4618 _('name to show in web pages (default: working directory)'), _('NAME')),
4620 ('', 'web-conf', '',
4619 ('', 'web-conf', '',
4621 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4620 _("name of the hgweb config file (see 'hg help hgweb')"), _('FILE')),
4622 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4621 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
4623 _('FILE')),
4622 _('FILE')),
4624 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4623 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
4625 ('', 'stdio', None, _('for remote clients')),
4624 ('', 'stdio', None, _('for remote clients')),
4626 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4625 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
4627 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4626 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
4628 ('', 'style', '', _('template style to use'), _('STYLE')),
4627 ('', 'style', '', _('template style to use'), _('STYLE')),
4629 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4628 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4630 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4629 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
4631 _('[OPTION]...'),
4630 _('[OPTION]...'),
4632 optionalrepo=True)
4631 optionalrepo=True)
4633 def serve(ui, repo, **opts):
4632 def serve(ui, repo, **opts):
4634 """start stand-alone webserver
4633 """start stand-alone webserver
4635
4634
4636 Start a local HTTP repository browser and pull server. You can use
4635 Start a local HTTP repository browser and pull server. You can use
4637 this for ad-hoc sharing and browsing of repositories. It is
4636 this for ad-hoc sharing and browsing of repositories. It is
4638 recommended to use a real web server to serve a repository for
4637 recommended to use a real web server to serve a repository for
4639 longer periods of time.
4638 longer periods of time.
4640
4639
4641 Please note that the server does not implement access control.
4640 Please note that the server does not implement access control.
4642 This means that, by default, anybody can read from the server and
4641 This means that, by default, anybody can read from the server and
4643 nobody can write to it by default. Set the ``web.allow_push``
4642 nobody can write to it by default. Set the ``web.allow_push``
4644 option to ``*`` to allow everybody to push to the server. You
4643 option to ``*`` to allow everybody to push to the server. You
4645 should use a real web server if you need to authenticate users.
4644 should use a real web server if you need to authenticate users.
4646
4645
4647 By default, the server logs accesses to stdout and errors to
4646 By default, the server logs accesses to stdout and errors to
4648 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4647 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
4649 files.
4648 files.
4650
4649
4651 To have the server choose a free port number to listen on, specify
4650 To have the server choose a free port number to listen on, specify
4652 a port number of 0; in this case, the server will print the port
4651 a port number of 0; in this case, the server will print the port
4653 number it uses.
4652 number it uses.
4654
4653
4655 Returns 0 on success.
4654 Returns 0 on success.
4656 """
4655 """
4657
4656
4658 if opts["stdio"] and opts["cmdserver"]:
4657 if opts["stdio"] and opts["cmdserver"]:
4659 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4658 raise error.Abort(_("cannot use --stdio with --cmdserver"))
4660
4659
4661 if opts["stdio"]:
4660 if opts["stdio"]:
4662 if repo is None:
4661 if repo is None:
4663 raise error.RepoError(_("there is no Mercurial repository here"
4662 raise error.RepoError(_("there is no Mercurial repository here"
4664 " (.hg not found)"))
4663 " (.hg not found)"))
4665 s = sshserver.sshserver(ui, repo)
4664 s = sshserver.sshserver(ui, repo)
4666 s.serve_forever()
4665 s.serve_forever()
4667
4666
4668 service = server.createservice(ui, repo, opts)
4667 service = server.createservice(ui, repo, opts)
4669 return server.runservice(opts, initfn=service.init, runfn=service.run)
4668 return server.runservice(opts, initfn=service.init, runfn=service.run)
4670
4669
4671 @command('^status|st',
4670 @command('^status|st',
4672 [('A', 'all', None, _('show status of all files')),
4671 [('A', 'all', None, _('show status of all files')),
4673 ('m', 'modified', None, _('show only modified files')),
4672 ('m', 'modified', None, _('show only modified files')),
4674 ('a', 'added', None, _('show only added files')),
4673 ('a', 'added', None, _('show only added files')),
4675 ('r', 'removed', None, _('show only removed files')),
4674 ('r', 'removed', None, _('show only removed files')),
4676 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4675 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4677 ('c', 'clean', None, _('show only files without changes')),
4676 ('c', 'clean', None, _('show only files without changes')),
4678 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4677 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4679 ('i', 'ignored', None, _('show only ignored files')),
4678 ('i', 'ignored', None, _('show only ignored files')),
4680 ('n', 'no-status', None, _('hide status prefix')),
4679 ('n', 'no-status', None, _('hide status prefix')),
4681 ('C', 'copies', None, _('show source of copied files')),
4680 ('C', 'copies', None, _('show source of copied files')),
4682 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4681 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4683 ('', 'rev', [], _('show difference from revision'), _('REV')),
4682 ('', 'rev', [], _('show difference from revision'), _('REV')),
4684 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4683 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
4685 ] + walkopts + subrepoopts + formatteropts,
4684 ] + walkopts + subrepoopts + formatteropts,
4686 _('[OPTION]... [FILE]...'),
4685 _('[OPTION]... [FILE]...'),
4687 inferrepo=True)
4686 inferrepo=True)
4688 def status(ui, repo, *pats, **opts):
4687 def status(ui, repo, *pats, **opts):
4689 """show changed files in the working directory
4688 """show changed files in the working directory
4690
4689
4691 Show status of files in the repository. If names are given, only
4690 Show status of files in the repository. If names are given, only
4692 files that match are shown. Files that are clean or ignored or
4691 files that match are shown. Files that are clean or ignored or
4693 the source of a copy/move operation, are not listed unless
4692 the source of a copy/move operation, are not listed unless
4694 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4693 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
4695 Unless options described with "show only ..." are given, the
4694 Unless options described with "show only ..." are given, the
4696 options -mardu are used.
4695 options -mardu are used.
4697
4696
4698 Option -q/--quiet hides untracked (unknown and ignored) files
4697 Option -q/--quiet hides untracked (unknown and ignored) files
4699 unless explicitly requested with -u/--unknown or -i/--ignored.
4698 unless explicitly requested with -u/--unknown or -i/--ignored.
4700
4699
4701 .. note::
4700 .. note::
4702
4701
4703 :hg:`status` may appear to disagree with diff if permissions have
4702 :hg:`status` may appear to disagree with diff if permissions have
4704 changed or a merge has occurred. The standard diff format does
4703 changed or a merge has occurred. The standard diff format does
4705 not report permission changes and diff only reports changes
4704 not report permission changes and diff only reports changes
4706 relative to one merge parent.
4705 relative to one merge parent.
4707
4706
4708 If one revision is given, it is used as the base revision.
4707 If one revision is given, it is used as the base revision.
4709 If two revisions are given, the differences between them are
4708 If two revisions are given, the differences between them are
4710 shown. The --change option can also be used as a shortcut to list
4709 shown. The --change option can also be used as a shortcut to list
4711 the changed files of a revision from its first parent.
4710 the changed files of a revision from its first parent.
4712
4711
4713 The codes used to show the status of files are::
4712 The codes used to show the status of files are::
4714
4713
4715 M = modified
4714 M = modified
4716 A = added
4715 A = added
4717 R = removed
4716 R = removed
4718 C = clean
4717 C = clean
4719 ! = missing (deleted by non-hg command, but still tracked)
4718 ! = missing (deleted by non-hg command, but still tracked)
4720 ? = not tracked
4719 ? = not tracked
4721 I = ignored
4720 I = ignored
4722 = origin of the previous file (with --copies)
4721 = origin of the previous file (with --copies)
4723
4722
4724 .. container:: verbose
4723 .. container:: verbose
4725
4724
4726 Examples:
4725 Examples:
4727
4726
4728 - show changes in the working directory relative to a
4727 - show changes in the working directory relative to a
4729 changeset::
4728 changeset::
4730
4729
4731 hg status --rev 9353
4730 hg status --rev 9353
4732
4731
4733 - show changes in the working directory relative to the
4732 - show changes in the working directory relative to the
4734 current directory (see :hg:`help patterns` for more information)::
4733 current directory (see :hg:`help patterns` for more information)::
4735
4734
4736 hg status re:
4735 hg status re:
4737
4736
4738 - show all changes including copies in an existing changeset::
4737 - show all changes including copies in an existing changeset::
4739
4738
4740 hg status --copies --change 9353
4739 hg status --copies --change 9353
4741
4740
4742 - get a NUL separated list of added files, suitable for xargs::
4741 - get a NUL separated list of added files, suitable for xargs::
4743
4742
4744 hg status -an0
4743 hg status -an0
4745
4744
4746 Returns 0 on success.
4745 Returns 0 on success.
4747 """
4746 """
4748
4747
4749 revs = opts.get('rev')
4748 revs = opts.get('rev')
4750 change = opts.get('change')
4749 change = opts.get('change')
4751
4750
4752 if revs and change:
4751 if revs and change:
4753 msg = _('cannot specify --rev and --change at the same time')
4752 msg = _('cannot specify --rev and --change at the same time')
4754 raise error.Abort(msg)
4753 raise error.Abort(msg)
4755 elif change:
4754 elif change:
4756 node2 = scmutil.revsingle(repo, change, None).node()
4755 node2 = scmutil.revsingle(repo, change, None).node()
4757 node1 = repo[node2].p1().node()
4756 node1 = repo[node2].p1().node()
4758 else:
4757 else:
4759 node1, node2 = scmutil.revpair(repo, revs)
4758 node1, node2 = scmutil.revpair(repo, revs)
4760
4759
4761 if pats:
4760 if pats:
4762 cwd = repo.getcwd()
4761 cwd = repo.getcwd()
4763 else:
4762 else:
4764 cwd = ''
4763 cwd = ''
4765
4764
4766 if opts.get('print0'):
4765 if opts.get('print0'):
4767 end = '\0'
4766 end = '\0'
4768 else:
4767 else:
4769 end = '\n'
4768 end = '\n'
4770 copy = {}
4769 copy = {}
4771 states = 'modified added removed deleted unknown ignored clean'.split()
4770 states = 'modified added removed deleted unknown ignored clean'.split()
4772 show = [k for k in states if opts.get(k)]
4771 show = [k for k in states if opts.get(k)]
4773 if opts.get('all'):
4772 if opts.get('all'):
4774 show += ui.quiet and (states[:4] + ['clean']) or states
4773 show += ui.quiet and (states[:4] + ['clean']) or states
4775 if not show:
4774 if not show:
4776 if ui.quiet:
4775 if ui.quiet:
4777 show = states[:4]
4776 show = states[:4]
4778 else:
4777 else:
4779 show = states[:5]
4778 show = states[:5]
4780
4779
4781 m = scmutil.match(repo[node2], pats, opts)
4780 m = scmutil.match(repo[node2], pats, opts)
4782 stat = repo.status(node1, node2, m,
4781 stat = repo.status(node1, node2, m,
4783 'ignored' in show, 'clean' in show, 'unknown' in show,
4782 'ignored' in show, 'clean' in show, 'unknown' in show,
4784 opts.get('subrepos'))
4783 opts.get('subrepos'))
4785 changestates = zip(states, 'MAR!?IC', stat)
4784 changestates = zip(states, 'MAR!?IC', stat)
4786
4785
4787 if (opts.get('all') or opts.get('copies')
4786 if (opts.get('all') or opts.get('copies')
4788 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4787 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
4789 copy = copies.pathcopies(repo[node1], repo[node2], m)
4788 copy = copies.pathcopies(repo[node1], repo[node2], m)
4790
4789
4791 ui.pager('status')
4790 ui.pager('status')
4792 fm = ui.formatter('status', opts)
4791 fm = ui.formatter('status', opts)
4793 fmt = '%s' + end
4792 fmt = '%s' + end
4794 showchar = not opts.get('no_status')
4793 showchar = not opts.get('no_status')
4795
4794
4796 for state, char, files in changestates:
4795 for state, char, files in changestates:
4797 if state in show:
4796 if state in show:
4798 label = 'status.' + state
4797 label = 'status.' + state
4799 for f in files:
4798 for f in files:
4800 fm.startitem()
4799 fm.startitem()
4801 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4800 fm.condwrite(showchar, 'status', '%s ', char, label=label)
4802 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4801 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
4803 if f in copy:
4802 if f in copy:
4804 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4803 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
4805 label='status.copied')
4804 label='status.copied')
4806 fm.end()
4805 fm.end()
4807
4806
4808 @command('^summary|sum',
4807 @command('^summary|sum',
4809 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4808 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
4810 def summary(ui, repo, **opts):
4809 def summary(ui, repo, **opts):
4811 """summarize working directory state
4810 """summarize working directory state
4812
4811
4813 This generates a brief summary of the working directory state,
4812 This generates a brief summary of the working directory state,
4814 including parents, branch, commit status, phase and available updates.
4813 including parents, branch, commit status, phase and available updates.
4815
4814
4816 With the --remote option, this will check the default paths for
4815 With the --remote option, this will check the default paths for
4817 incoming and outgoing changes. This can be time-consuming.
4816 incoming and outgoing changes. This can be time-consuming.
4818
4817
4819 Returns 0 on success.
4818 Returns 0 on success.
4820 """
4819 """
4821
4820
4822 ui.pager('summary')
4821 ui.pager('summary')
4823 ctx = repo[None]
4822 ctx = repo[None]
4824 parents = ctx.parents()
4823 parents = ctx.parents()
4825 pnode = parents[0].node()
4824 pnode = parents[0].node()
4826 marks = []
4825 marks = []
4827
4826
4828 ms = None
4827 ms = None
4829 try:
4828 try:
4830 ms = mergemod.mergestate.read(repo)
4829 ms = mergemod.mergestate.read(repo)
4831 except error.UnsupportedMergeRecords as e:
4830 except error.UnsupportedMergeRecords as e:
4832 s = ' '.join(e.recordtypes)
4831 s = ' '.join(e.recordtypes)
4833 ui.warn(
4832 ui.warn(
4834 _('warning: merge state has unsupported record types: %s\n') % s)
4833 _('warning: merge state has unsupported record types: %s\n') % s)
4835 unresolved = 0
4834 unresolved = 0
4836 else:
4835 else:
4837 unresolved = [f for f in ms if ms[f] == 'u']
4836 unresolved = [f for f in ms if ms[f] == 'u']
4838
4837
4839 for p in parents:
4838 for p in parents:
4840 # label with log.changeset (instead of log.parent) since this
4839 # label with log.changeset (instead of log.parent) since this
4841 # shows a working directory parent *changeset*:
4840 # shows a working directory parent *changeset*:
4842 # i18n: column positioning for "hg summary"
4841 # i18n: column positioning for "hg summary"
4843 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4842 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
4844 label=cmdutil._changesetlabels(p))
4843 label=cmdutil._changesetlabels(p))
4845 ui.write(' '.join(p.tags()), label='log.tag')
4844 ui.write(' '.join(p.tags()), label='log.tag')
4846 if p.bookmarks():
4845 if p.bookmarks():
4847 marks.extend(p.bookmarks())
4846 marks.extend(p.bookmarks())
4848 if p.rev() == -1:
4847 if p.rev() == -1:
4849 if not len(repo):
4848 if not len(repo):
4850 ui.write(_(' (empty repository)'))
4849 ui.write(_(' (empty repository)'))
4851 else:
4850 else:
4852 ui.write(_(' (no revision checked out)'))
4851 ui.write(_(' (no revision checked out)'))
4853 if p.troubled():
4852 if p.troubled():
4854 ui.write(' ('
4853 ui.write(' ('
4855 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4854 + ', '.join(ui.label(trouble, 'trouble.%s' % trouble)
4856 for trouble in p.troubles())
4855 for trouble in p.troubles())
4857 + ')')
4856 + ')')
4858 ui.write('\n')
4857 ui.write('\n')
4859 if p.description():
4858 if p.description():
4860 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4859 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
4861 label='log.summary')
4860 label='log.summary')
4862
4861
4863 branch = ctx.branch()
4862 branch = ctx.branch()
4864 bheads = repo.branchheads(branch)
4863 bheads = repo.branchheads(branch)
4865 # i18n: column positioning for "hg summary"
4864 # i18n: column positioning for "hg summary"
4866 m = _('branch: %s\n') % branch
4865 m = _('branch: %s\n') % branch
4867 if branch != 'default':
4866 if branch != 'default':
4868 ui.write(m, label='log.branch')
4867 ui.write(m, label='log.branch')
4869 else:
4868 else:
4870 ui.status(m, label='log.branch')
4869 ui.status(m, label='log.branch')
4871
4870
4872 if marks:
4871 if marks:
4873 active = repo._activebookmark
4872 active = repo._activebookmark
4874 # i18n: column positioning for "hg summary"
4873 # i18n: column positioning for "hg summary"
4875 ui.write(_('bookmarks:'), label='log.bookmark')
4874 ui.write(_('bookmarks:'), label='log.bookmark')
4876 if active is not None:
4875 if active is not None:
4877 if active in marks:
4876 if active in marks:
4878 ui.write(' *' + active, label=activebookmarklabel)
4877 ui.write(' *' + active, label=activebookmarklabel)
4879 marks.remove(active)
4878 marks.remove(active)
4880 else:
4879 else:
4881 ui.write(' [%s]' % active, label=activebookmarklabel)
4880 ui.write(' [%s]' % active, label=activebookmarklabel)
4882 for m in marks:
4881 for m in marks:
4883 ui.write(' ' + m, label='log.bookmark')
4882 ui.write(' ' + m, label='log.bookmark')
4884 ui.write('\n', label='log.bookmark')
4883 ui.write('\n', label='log.bookmark')
4885
4884
4886 status = repo.status(unknown=True)
4885 status = repo.status(unknown=True)
4887
4886
4888 c = repo.dirstate.copies()
4887 c = repo.dirstate.copies()
4889 copied, renamed = [], []
4888 copied, renamed = [], []
4890 for d, s in c.iteritems():
4889 for d, s in c.iteritems():
4891 if s in status.removed:
4890 if s in status.removed:
4892 status.removed.remove(s)
4891 status.removed.remove(s)
4893 renamed.append(d)
4892 renamed.append(d)
4894 else:
4893 else:
4895 copied.append(d)
4894 copied.append(d)
4896 if d in status.added:
4895 if d in status.added:
4897 status.added.remove(d)
4896 status.added.remove(d)
4898
4897
4899 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4898 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
4900
4899
4901 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4900 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
4902 (ui.label(_('%d added'), 'status.added'), status.added),
4901 (ui.label(_('%d added'), 'status.added'), status.added),
4903 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4902 (ui.label(_('%d removed'), 'status.removed'), status.removed),
4904 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4903 (ui.label(_('%d renamed'), 'status.copied'), renamed),
4905 (ui.label(_('%d copied'), 'status.copied'), copied),
4904 (ui.label(_('%d copied'), 'status.copied'), copied),
4906 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4905 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
4907 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4906 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
4908 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4907 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
4909 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4908 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
4910 t = []
4909 t = []
4911 for l, s in labels:
4910 for l, s in labels:
4912 if s:
4911 if s:
4913 t.append(l % len(s))
4912 t.append(l % len(s))
4914
4913
4915 t = ', '.join(t)
4914 t = ', '.join(t)
4916 cleanworkdir = False
4915 cleanworkdir = False
4917
4916
4918 if repo.vfs.exists('graftstate'):
4917 if repo.vfs.exists('graftstate'):
4919 t += _(' (graft in progress)')
4918 t += _(' (graft in progress)')
4920 if repo.vfs.exists('updatestate'):
4919 if repo.vfs.exists('updatestate'):
4921 t += _(' (interrupted update)')
4920 t += _(' (interrupted update)')
4922 elif len(parents) > 1:
4921 elif len(parents) > 1:
4923 t += _(' (merge)')
4922 t += _(' (merge)')
4924 elif branch != parents[0].branch():
4923 elif branch != parents[0].branch():
4925 t += _(' (new branch)')
4924 t += _(' (new branch)')
4926 elif (parents[0].closesbranch() and
4925 elif (parents[0].closesbranch() and
4927 pnode in repo.branchheads(branch, closed=True)):
4926 pnode in repo.branchheads(branch, closed=True)):
4928 t += _(' (head closed)')
4927 t += _(' (head closed)')
4929 elif not (status.modified or status.added or status.removed or renamed or
4928 elif not (status.modified or status.added or status.removed or renamed or
4930 copied or subs):
4929 copied or subs):
4931 t += _(' (clean)')
4930 t += _(' (clean)')
4932 cleanworkdir = True
4931 cleanworkdir = True
4933 elif pnode not in bheads:
4932 elif pnode not in bheads:
4934 t += _(' (new branch head)')
4933 t += _(' (new branch head)')
4935
4934
4936 if parents:
4935 if parents:
4937 pendingphase = max(p.phase() for p in parents)
4936 pendingphase = max(p.phase() for p in parents)
4938 else:
4937 else:
4939 pendingphase = phases.public
4938 pendingphase = phases.public
4940
4939
4941 if pendingphase > phases.newcommitphase(ui):
4940 if pendingphase > phases.newcommitphase(ui):
4942 t += ' (%s)' % phases.phasenames[pendingphase]
4941 t += ' (%s)' % phases.phasenames[pendingphase]
4943
4942
4944 if cleanworkdir:
4943 if cleanworkdir:
4945 # i18n: column positioning for "hg summary"
4944 # i18n: column positioning for "hg summary"
4946 ui.status(_('commit: %s\n') % t.strip())
4945 ui.status(_('commit: %s\n') % t.strip())
4947 else:
4946 else:
4948 # i18n: column positioning for "hg summary"
4947 # i18n: column positioning for "hg summary"
4949 ui.write(_('commit: %s\n') % t.strip())
4948 ui.write(_('commit: %s\n') % t.strip())
4950
4949
4951 # all ancestors of branch heads - all ancestors of parent = new csets
4950 # all ancestors of branch heads - all ancestors of parent = new csets
4952 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4951 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
4953 bheads))
4952 bheads))
4954
4953
4955 if new == 0:
4954 if new == 0:
4956 # i18n: column positioning for "hg summary"
4955 # i18n: column positioning for "hg summary"
4957 ui.status(_('update: (current)\n'))
4956 ui.status(_('update: (current)\n'))
4958 elif pnode not in bheads:
4957 elif pnode not in bheads:
4959 # i18n: column positioning for "hg summary"
4958 # i18n: column positioning for "hg summary"
4960 ui.write(_('update: %d new changesets (update)\n') % new)
4959 ui.write(_('update: %d new changesets (update)\n') % new)
4961 else:
4960 else:
4962 # i18n: column positioning for "hg summary"
4961 # i18n: column positioning for "hg summary"
4963 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4962 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
4964 (new, len(bheads)))
4963 (new, len(bheads)))
4965
4964
4966 t = []
4965 t = []
4967 draft = len(repo.revs('draft()'))
4966 draft = len(repo.revs('draft()'))
4968 if draft:
4967 if draft:
4969 t.append(_('%d draft') % draft)
4968 t.append(_('%d draft') % draft)
4970 secret = len(repo.revs('secret()'))
4969 secret = len(repo.revs('secret()'))
4971 if secret:
4970 if secret:
4972 t.append(_('%d secret') % secret)
4971 t.append(_('%d secret') % secret)
4973
4972
4974 if draft or secret:
4973 if draft or secret:
4975 ui.status(_('phases: %s\n') % ', '.join(t))
4974 ui.status(_('phases: %s\n') % ', '.join(t))
4976
4975
4977 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4976 if obsolete.isenabled(repo, obsolete.createmarkersopt):
4978 for trouble in ("unstable", "divergent", "bumped"):
4977 for trouble in ("unstable", "divergent", "bumped"):
4979 numtrouble = len(repo.revs(trouble + "()"))
4978 numtrouble = len(repo.revs(trouble + "()"))
4980 # We write all the possibilities to ease translation
4979 # We write all the possibilities to ease translation
4981 troublemsg = {
4980 troublemsg = {
4982 "unstable": _("unstable: %d changesets"),
4981 "unstable": _("unstable: %d changesets"),
4983 "divergent": _("divergent: %d changesets"),
4982 "divergent": _("divergent: %d changesets"),
4984 "bumped": _("bumped: %d changesets"),
4983 "bumped": _("bumped: %d changesets"),
4985 }
4984 }
4986 if numtrouble > 0:
4985 if numtrouble > 0:
4987 ui.status(troublemsg[trouble] % numtrouble + "\n")
4986 ui.status(troublemsg[trouble] % numtrouble + "\n")
4988
4987
4989 cmdutil.summaryhooks(ui, repo)
4988 cmdutil.summaryhooks(ui, repo)
4990
4989
4991 if opts.get('remote'):
4990 if opts.get('remote'):
4992 needsincoming, needsoutgoing = True, True
4991 needsincoming, needsoutgoing = True, True
4993 else:
4992 else:
4994 needsincoming, needsoutgoing = False, False
4993 needsincoming, needsoutgoing = False, False
4995 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4994 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
4996 if i:
4995 if i:
4997 needsincoming = True
4996 needsincoming = True
4998 if o:
4997 if o:
4999 needsoutgoing = True
4998 needsoutgoing = True
5000 if not needsincoming and not needsoutgoing:
4999 if not needsincoming and not needsoutgoing:
5001 return
5000 return
5002
5001
5003 def getincoming():
5002 def getincoming():
5004 source, branches = hg.parseurl(ui.expandpath('default'))
5003 source, branches = hg.parseurl(ui.expandpath('default'))
5005 sbranch = branches[0]
5004 sbranch = branches[0]
5006 try:
5005 try:
5007 other = hg.peer(repo, {}, source)
5006 other = hg.peer(repo, {}, source)
5008 except error.RepoError:
5007 except error.RepoError:
5009 if opts.get('remote'):
5008 if opts.get('remote'):
5010 raise
5009 raise
5011 return source, sbranch, None, None, None
5010 return source, sbranch, None, None, None
5012 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5011 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5013 if revs:
5012 if revs:
5014 revs = [other.lookup(rev) for rev in revs]
5013 revs = [other.lookup(rev) for rev in revs]
5015 ui.debug('comparing with %s\n' % util.hidepassword(source))
5014 ui.debug('comparing with %s\n' % util.hidepassword(source))
5016 repo.ui.pushbuffer()
5015 repo.ui.pushbuffer()
5017 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5016 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5018 repo.ui.popbuffer()
5017 repo.ui.popbuffer()
5019 return source, sbranch, other, commoninc, commoninc[1]
5018 return source, sbranch, other, commoninc, commoninc[1]
5020
5019
5021 if needsincoming:
5020 if needsincoming:
5022 source, sbranch, sother, commoninc, incoming = getincoming()
5021 source, sbranch, sother, commoninc, incoming = getincoming()
5023 else:
5022 else:
5024 source = sbranch = sother = commoninc = incoming = None
5023 source = sbranch = sother = commoninc = incoming = None
5025
5024
5026 def getoutgoing():
5025 def getoutgoing():
5027 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5026 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5028 dbranch = branches[0]
5027 dbranch = branches[0]
5029 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5028 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5030 if source != dest:
5029 if source != dest:
5031 try:
5030 try:
5032 dother = hg.peer(repo, {}, dest)
5031 dother = hg.peer(repo, {}, dest)
5033 except error.RepoError:
5032 except error.RepoError:
5034 if opts.get('remote'):
5033 if opts.get('remote'):
5035 raise
5034 raise
5036 return dest, dbranch, None, None
5035 return dest, dbranch, None, None
5037 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5036 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5038 elif sother is None:
5037 elif sother is None:
5039 # there is no explicit destination peer, but source one is invalid
5038 # there is no explicit destination peer, but source one is invalid
5040 return dest, dbranch, None, None
5039 return dest, dbranch, None, None
5041 else:
5040 else:
5042 dother = sother
5041 dother = sother
5043 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5042 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5044 common = None
5043 common = None
5045 else:
5044 else:
5046 common = commoninc
5045 common = commoninc
5047 if revs:
5046 if revs:
5048 revs = [repo.lookup(rev) for rev in revs]
5047 revs = [repo.lookup(rev) for rev in revs]
5049 repo.ui.pushbuffer()
5048 repo.ui.pushbuffer()
5050 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5049 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5051 commoninc=common)
5050 commoninc=common)
5052 repo.ui.popbuffer()
5051 repo.ui.popbuffer()
5053 return dest, dbranch, dother, outgoing
5052 return dest, dbranch, dother, outgoing
5054
5053
5055 if needsoutgoing:
5054 if needsoutgoing:
5056 dest, dbranch, dother, outgoing = getoutgoing()
5055 dest, dbranch, dother, outgoing = getoutgoing()
5057 else:
5056 else:
5058 dest = dbranch = dother = outgoing = None
5057 dest = dbranch = dother = outgoing = None
5059
5058
5060 if opts.get('remote'):
5059 if opts.get('remote'):
5061 t = []
5060 t = []
5062 if incoming:
5061 if incoming:
5063 t.append(_('1 or more incoming'))
5062 t.append(_('1 or more incoming'))
5064 o = outgoing.missing
5063 o = outgoing.missing
5065 if o:
5064 if o:
5066 t.append(_('%d outgoing') % len(o))
5065 t.append(_('%d outgoing') % len(o))
5067 other = dother or sother
5066 other = dother or sother
5068 if 'bookmarks' in other.listkeys('namespaces'):
5067 if 'bookmarks' in other.listkeys('namespaces'):
5069 counts = bookmarks.summary(repo, other)
5068 counts = bookmarks.summary(repo, other)
5070 if counts[0] > 0:
5069 if counts[0] > 0:
5071 t.append(_('%d incoming bookmarks') % counts[0])
5070 t.append(_('%d incoming bookmarks') % counts[0])
5072 if counts[1] > 0:
5071 if counts[1] > 0:
5073 t.append(_('%d outgoing bookmarks') % counts[1])
5072 t.append(_('%d outgoing bookmarks') % counts[1])
5074
5073
5075 if t:
5074 if t:
5076 # i18n: column positioning for "hg summary"
5075 # i18n: column positioning for "hg summary"
5077 ui.write(_('remote: %s\n') % (', '.join(t)))
5076 ui.write(_('remote: %s\n') % (', '.join(t)))
5078 else:
5077 else:
5079 # i18n: column positioning for "hg summary"
5078 # i18n: column positioning for "hg summary"
5080 ui.status(_('remote: (synced)\n'))
5079 ui.status(_('remote: (synced)\n'))
5081
5080
5082 cmdutil.summaryremotehooks(ui, repo, opts,
5081 cmdutil.summaryremotehooks(ui, repo, opts,
5083 ((source, sbranch, sother, commoninc),
5082 ((source, sbranch, sother, commoninc),
5084 (dest, dbranch, dother, outgoing)))
5083 (dest, dbranch, dother, outgoing)))
5085
5084
5086 @command('tag',
5085 @command('tag',
5087 [('f', 'force', None, _('force tag')),
5086 [('f', 'force', None, _('force tag')),
5088 ('l', 'local', None, _('make the tag local')),
5087 ('l', 'local', None, _('make the tag local')),
5089 ('r', 'rev', '', _('revision to tag'), _('REV')),
5088 ('r', 'rev', '', _('revision to tag'), _('REV')),
5090 ('', 'remove', None, _('remove a tag')),
5089 ('', 'remove', None, _('remove a tag')),
5091 # -l/--local is already there, commitopts cannot be used
5090 # -l/--local is already there, commitopts cannot be used
5092 ('e', 'edit', None, _('invoke editor on commit messages')),
5091 ('e', 'edit', None, _('invoke editor on commit messages')),
5093 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5092 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5094 ] + commitopts2,
5093 ] + commitopts2,
5095 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5094 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5096 def tag(ui, repo, name1, *names, **opts):
5095 def tag(ui, repo, name1, *names, **opts):
5097 """add one or more tags for the current or given revision
5096 """add one or more tags for the current or given revision
5098
5097
5099 Name a particular revision using <name>.
5098 Name a particular revision using <name>.
5100
5099
5101 Tags are used to name particular revisions of the repository and are
5100 Tags are used to name particular revisions of the repository and are
5102 very useful to compare different revisions, to go back to significant
5101 very useful to compare different revisions, to go back to significant
5103 earlier versions or to mark branch points as releases, etc. Changing
5102 earlier versions or to mark branch points as releases, etc. Changing
5104 an existing tag is normally disallowed; use -f/--force to override.
5103 an existing tag is normally disallowed; use -f/--force to override.
5105
5104
5106 If no revision is given, the parent of the working directory is
5105 If no revision is given, the parent of the working directory is
5107 used.
5106 used.
5108
5107
5109 To facilitate version control, distribution, and merging of tags,
5108 To facilitate version control, distribution, and merging of tags,
5110 they are stored as a file named ".hgtags" which is managed similarly
5109 they are stored as a file named ".hgtags" which is managed similarly
5111 to other project files and can be hand-edited if necessary. This
5110 to other project files and can be hand-edited if necessary. This
5112 also means that tagging creates a new commit. The file
5111 also means that tagging creates a new commit. The file
5113 ".hg/localtags" is used for local tags (not shared among
5112 ".hg/localtags" is used for local tags (not shared among
5114 repositories).
5113 repositories).
5115
5114
5116 Tag commits are usually made at the head of a branch. If the parent
5115 Tag commits are usually made at the head of a branch. If the parent
5117 of the working directory is not a branch head, :hg:`tag` aborts; use
5116 of the working directory is not a branch head, :hg:`tag` aborts; use
5118 -f/--force to force the tag commit to be based on a non-head
5117 -f/--force to force the tag commit to be based on a non-head
5119 changeset.
5118 changeset.
5120
5119
5121 See :hg:`help dates` for a list of formats valid for -d/--date.
5120 See :hg:`help dates` for a list of formats valid for -d/--date.
5122
5121
5123 Since tag names have priority over branch names during revision
5122 Since tag names have priority over branch names during revision
5124 lookup, using an existing branch name as a tag name is discouraged.
5123 lookup, using an existing branch name as a tag name is discouraged.
5125
5124
5126 Returns 0 on success.
5125 Returns 0 on success.
5127 """
5126 """
5128 wlock = lock = None
5127 wlock = lock = None
5129 try:
5128 try:
5130 wlock = repo.wlock()
5129 wlock = repo.wlock()
5131 lock = repo.lock()
5130 lock = repo.lock()
5132 rev_ = "."
5131 rev_ = "."
5133 names = [t.strip() for t in (name1,) + names]
5132 names = [t.strip() for t in (name1,) + names]
5134 if len(names) != len(set(names)):
5133 if len(names) != len(set(names)):
5135 raise error.Abort(_('tag names must be unique'))
5134 raise error.Abort(_('tag names must be unique'))
5136 for n in names:
5135 for n in names:
5137 scmutil.checknewlabel(repo, n, 'tag')
5136 scmutil.checknewlabel(repo, n, 'tag')
5138 if not n:
5137 if not n:
5139 raise error.Abort(_('tag names cannot consist entirely of '
5138 raise error.Abort(_('tag names cannot consist entirely of '
5140 'whitespace'))
5139 'whitespace'))
5141 if opts.get('rev') and opts.get('remove'):
5140 if opts.get('rev') and opts.get('remove'):
5142 raise error.Abort(_("--rev and --remove are incompatible"))
5141 raise error.Abort(_("--rev and --remove are incompatible"))
5143 if opts.get('rev'):
5142 if opts.get('rev'):
5144 rev_ = opts['rev']
5143 rev_ = opts['rev']
5145 message = opts.get('message')
5144 message = opts.get('message')
5146 if opts.get('remove'):
5145 if opts.get('remove'):
5147 if opts.get('local'):
5146 if opts.get('local'):
5148 expectedtype = 'local'
5147 expectedtype = 'local'
5149 else:
5148 else:
5150 expectedtype = 'global'
5149 expectedtype = 'global'
5151
5150
5152 for n in names:
5151 for n in names:
5153 if not repo.tagtype(n):
5152 if not repo.tagtype(n):
5154 raise error.Abort(_("tag '%s' does not exist") % n)
5153 raise error.Abort(_("tag '%s' does not exist") % n)
5155 if repo.tagtype(n) != expectedtype:
5154 if repo.tagtype(n) != expectedtype:
5156 if expectedtype == 'global':
5155 if expectedtype == 'global':
5157 raise error.Abort(_("tag '%s' is not a global tag") % n)
5156 raise error.Abort(_("tag '%s' is not a global tag") % n)
5158 else:
5157 else:
5159 raise error.Abort(_("tag '%s' is not a local tag") % n)
5158 raise error.Abort(_("tag '%s' is not a local tag") % n)
5160 rev_ = 'null'
5159 rev_ = 'null'
5161 if not message:
5160 if not message:
5162 # we don't translate commit messages
5161 # we don't translate commit messages
5163 message = 'Removed tag %s' % ', '.join(names)
5162 message = 'Removed tag %s' % ', '.join(names)
5164 elif not opts.get('force'):
5163 elif not opts.get('force'):
5165 for n in names:
5164 for n in names:
5166 if n in repo.tags():
5165 if n in repo.tags():
5167 raise error.Abort(_("tag '%s' already exists "
5166 raise error.Abort(_("tag '%s' already exists "
5168 "(use -f to force)") % n)
5167 "(use -f to force)") % n)
5169 if not opts.get('local'):
5168 if not opts.get('local'):
5170 p1, p2 = repo.dirstate.parents()
5169 p1, p2 = repo.dirstate.parents()
5171 if p2 != nullid:
5170 if p2 != nullid:
5172 raise error.Abort(_('uncommitted merge'))
5171 raise error.Abort(_('uncommitted merge'))
5173 bheads = repo.branchheads()
5172 bheads = repo.branchheads()
5174 if not opts.get('force') and bheads and p1 not in bheads:
5173 if not opts.get('force') and bheads and p1 not in bheads:
5175 raise error.Abort(_('working directory is not at a branch head '
5174 raise error.Abort(_('working directory is not at a branch head '
5176 '(use -f to force)'))
5175 '(use -f to force)'))
5177 r = scmutil.revsingle(repo, rev_).node()
5176 r = scmutil.revsingle(repo, rev_).node()
5178
5177
5179 if not message:
5178 if not message:
5180 # we don't translate commit messages
5179 # we don't translate commit messages
5181 message = ('Added tag %s for changeset %s' %
5180 message = ('Added tag %s for changeset %s' %
5182 (', '.join(names), short(r)))
5181 (', '.join(names), short(r)))
5183
5182
5184 date = opts.get('date')
5183 date = opts.get('date')
5185 if date:
5184 if date:
5186 date = util.parsedate(date)
5185 date = util.parsedate(date)
5187
5186
5188 if opts.get('remove'):
5187 if opts.get('remove'):
5189 editform = 'tag.remove'
5188 editform = 'tag.remove'
5190 else:
5189 else:
5191 editform = 'tag.add'
5190 editform = 'tag.add'
5192 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5191 editor = cmdutil.getcommiteditor(editform=editform, **opts)
5193
5192
5194 # don't allow tagging the null rev
5193 # don't allow tagging the null rev
5195 if (not opts.get('remove') and
5194 if (not opts.get('remove') and
5196 scmutil.revsingle(repo, rev_).rev() == nullrev):
5195 scmutil.revsingle(repo, rev_).rev() == nullrev):
5197 raise error.Abort(_("cannot tag null revision"))
5196 raise error.Abort(_("cannot tag null revision"))
5198
5197
5199 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5198 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
5200 editor=editor)
5199 editor=editor)
5201 finally:
5200 finally:
5202 release(lock, wlock)
5201 release(lock, wlock)
5203
5202
5204 @command('tags', formatteropts, '')
5203 @command('tags', formatteropts, '')
5205 def tags(ui, repo, **opts):
5204 def tags(ui, repo, **opts):
5206 """list repository tags
5205 """list repository tags
5207
5206
5208 This lists both regular and local tags. When the -v/--verbose
5207 This lists both regular and local tags. When the -v/--verbose
5209 switch is used, a third column "local" is printed for local tags.
5208 switch is used, a third column "local" is printed for local tags.
5210 When the -q/--quiet switch is used, only the tag name is printed.
5209 When the -q/--quiet switch is used, only the tag name is printed.
5211
5210
5212 Returns 0 on success.
5211 Returns 0 on success.
5213 """
5212 """
5214
5213
5215 ui.pager('tags')
5214 ui.pager('tags')
5216 fm = ui.formatter('tags', opts)
5215 fm = ui.formatter('tags', opts)
5217 hexfunc = fm.hexfunc
5216 hexfunc = fm.hexfunc
5218 tagtype = ""
5217 tagtype = ""
5219
5218
5220 for t, n in reversed(repo.tagslist()):
5219 for t, n in reversed(repo.tagslist()):
5221 hn = hexfunc(n)
5220 hn = hexfunc(n)
5222 label = 'tags.normal'
5221 label = 'tags.normal'
5223 tagtype = ''
5222 tagtype = ''
5224 if repo.tagtype(t) == 'local':
5223 if repo.tagtype(t) == 'local':
5225 label = 'tags.local'
5224 label = 'tags.local'
5226 tagtype = 'local'
5225 tagtype = 'local'
5227
5226
5228 fm.startitem()
5227 fm.startitem()
5229 fm.write('tag', '%s', t, label=label)
5228 fm.write('tag', '%s', t, label=label)
5230 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5229 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
5231 fm.condwrite(not ui.quiet, 'rev node', fmt,
5230 fm.condwrite(not ui.quiet, 'rev node', fmt,
5232 repo.changelog.rev(n), hn, label=label)
5231 repo.changelog.rev(n), hn, label=label)
5233 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5232 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
5234 tagtype, label=label)
5233 tagtype, label=label)
5235 fm.plain('\n')
5234 fm.plain('\n')
5236 fm.end()
5235 fm.end()
5237
5236
5238 @command('tip',
5237 @command('tip',
5239 [('p', 'patch', None, _('show patch')),
5238 [('p', 'patch', None, _('show patch')),
5240 ('g', 'git', None, _('use git extended diff format')),
5239 ('g', 'git', None, _('use git extended diff format')),
5241 ] + templateopts,
5240 ] + templateopts,
5242 _('[-p] [-g]'))
5241 _('[-p] [-g]'))
5243 def tip(ui, repo, **opts):
5242 def tip(ui, repo, **opts):
5244 """show the tip revision (DEPRECATED)
5243 """show the tip revision (DEPRECATED)
5245
5244
5246 The tip revision (usually just called the tip) is the changeset
5245 The tip revision (usually just called the tip) is the changeset
5247 most recently added to the repository (and therefore the most
5246 most recently added to the repository (and therefore the most
5248 recently changed head).
5247 recently changed head).
5249
5248
5250 If you have just made a commit, that commit will be the tip. If
5249 If you have just made a commit, that commit will be the tip. If
5251 you have just pulled changes from another repository, the tip of
5250 you have just pulled changes from another repository, the tip of
5252 that repository becomes the current tip. The "tip" tag is special
5251 that repository becomes the current tip. The "tip" tag is special
5253 and cannot be renamed or assigned to a different changeset.
5252 and cannot be renamed or assigned to a different changeset.
5254
5253
5255 This command is deprecated, please use :hg:`heads` instead.
5254 This command is deprecated, please use :hg:`heads` instead.
5256
5255
5257 Returns 0 on success.
5256 Returns 0 on success.
5258 """
5257 """
5259 displayer = cmdutil.show_changeset(ui, repo, opts)
5258 displayer = cmdutil.show_changeset(ui, repo, opts)
5260 displayer.show(repo['tip'])
5259 displayer.show(repo['tip'])
5261 displayer.close()
5260 displayer.close()
5262
5261
5263 @command('unbundle',
5262 @command('unbundle',
5264 [('u', 'update', None,
5263 [('u', 'update', None,
5265 _('update to new branch head if changesets were unbundled'))],
5264 _('update to new branch head if changesets were unbundled'))],
5266 _('[-u] FILE...'))
5265 _('[-u] FILE...'))
5267 def unbundle(ui, repo, fname1, *fnames, **opts):
5266 def unbundle(ui, repo, fname1, *fnames, **opts):
5268 """apply one or more changegroup files
5267 """apply one or more changegroup files
5269
5268
5270 Apply one or more compressed changegroup files generated by the
5269 Apply one or more compressed changegroup files generated by the
5271 bundle command.
5270 bundle command.
5272
5271
5273 Returns 0 on success, 1 if an update has unresolved files.
5272 Returns 0 on success, 1 if an update has unresolved files.
5274 """
5273 """
5275 fnames = (fname1,) + fnames
5274 fnames = (fname1,) + fnames
5276
5275
5277 with repo.lock():
5276 with repo.lock():
5278 for fname in fnames:
5277 for fname in fnames:
5279 f = hg.openpath(ui, fname)
5278 f = hg.openpath(ui, fname)
5280 gen = exchange.readbundle(ui, f, fname)
5279 gen = exchange.readbundle(ui, f, fname)
5281 if isinstance(gen, bundle2.unbundle20):
5280 if isinstance(gen, bundle2.unbundle20):
5282 tr = repo.transaction('unbundle')
5281 tr = repo.transaction('unbundle')
5283 try:
5282 try:
5284 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5283 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
5285 url='bundle:' + fname)
5284 url='bundle:' + fname)
5286 tr.close()
5285 tr.close()
5287 except error.BundleUnknownFeatureError as exc:
5286 except error.BundleUnknownFeatureError as exc:
5288 raise error.Abort(_('%s: unknown bundle feature, %s')
5287 raise error.Abort(_('%s: unknown bundle feature, %s')
5289 % (fname, exc),
5288 % (fname, exc),
5290 hint=_("see https://mercurial-scm.org/"
5289 hint=_("see https://mercurial-scm.org/"
5291 "wiki/BundleFeature for more "
5290 "wiki/BundleFeature for more "
5292 "information"))
5291 "information"))
5293 finally:
5292 finally:
5294 if tr:
5293 if tr:
5295 tr.release()
5294 tr.release()
5296 changes = [r.get('return', 0)
5295 changes = [r.get('return', 0)
5297 for r in op.records['changegroup']]
5296 for r in op.records['changegroup']]
5298 modheads = changegroup.combineresults(changes)
5297 modheads = changegroup.combineresults(changes)
5299 elif isinstance(gen, streamclone.streamcloneapplier):
5298 elif isinstance(gen, streamclone.streamcloneapplier):
5300 raise error.Abort(
5299 raise error.Abort(
5301 _('packed bundles cannot be applied with '
5300 _('packed bundles cannot be applied with '
5302 '"hg unbundle"'),
5301 '"hg unbundle"'),
5303 hint=_('use "hg debugapplystreamclonebundle"'))
5302 hint=_('use "hg debugapplystreamclonebundle"'))
5304 else:
5303 else:
5305 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5304 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
5306
5305
5307 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5306 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
5308
5307
5309 @command('^update|up|checkout|co',
5308 @command('^update|up|checkout|co',
5310 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5309 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5311 ('c', 'check', None, _('require clean working directory')),
5310 ('c', 'check', None, _('require clean working directory')),
5312 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5311 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5313 ('r', 'rev', '', _('revision'), _('REV'))
5312 ('r', 'rev', '', _('revision'), _('REV'))
5314 ] + mergetoolopts,
5313 ] + mergetoolopts,
5315 _('[-C|-c] [-d DATE] [[-r] REV]'))
5314 _('[-C|-c] [-d DATE] [[-r] REV]'))
5316 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5315 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
5317 tool=None):
5316 tool=None):
5318 """update working directory (or switch revisions)
5317 """update working directory (or switch revisions)
5319
5318
5320 Update the repository's working directory to the specified
5319 Update the repository's working directory to the specified
5321 changeset. If no changeset is specified, update to the tip of the
5320 changeset. If no changeset is specified, update to the tip of the
5322 current named branch and move the active bookmark (see :hg:`help
5321 current named branch and move the active bookmark (see :hg:`help
5323 bookmarks`).
5322 bookmarks`).
5324
5323
5325 Update sets the working directory's parent revision to the specified
5324 Update sets the working directory's parent revision to the specified
5326 changeset (see :hg:`help parents`).
5325 changeset (see :hg:`help parents`).
5327
5326
5328 If the changeset is not a descendant or ancestor of the working
5327 If the changeset is not a descendant or ancestor of the working
5329 directory's parent and there are uncommitted changes, the update is
5328 directory's parent and there are uncommitted changes, the update is
5330 aborted. With the -c/--check option, the working directory is checked
5329 aborted. With the -c/--check option, the working directory is checked
5331 for uncommitted changes; if none are found, the working directory is
5330 for uncommitted changes; if none are found, the working directory is
5332 updated to the specified changeset.
5331 updated to the specified changeset.
5333
5332
5334 .. container:: verbose
5333 .. container:: verbose
5335
5334
5336 The -C/--clean and -c/--check options control what happens if the
5335 The -C/--clean and -c/--check options control what happens if the
5337 working directory contains uncommitted changes.
5336 working directory contains uncommitted changes.
5338 At most of one of them can be specified.
5337 At most of one of them can be specified.
5339
5338
5340 1. If no option is specified, and if
5339 1. If no option is specified, and if
5341 the requested changeset is an ancestor or descendant of
5340 the requested changeset is an ancestor or descendant of
5342 the working directory's parent, the uncommitted changes
5341 the working directory's parent, the uncommitted changes
5343 are merged into the requested changeset and the merged
5342 are merged into the requested changeset and the merged
5344 result is left uncommitted. If the requested changeset is
5343 result is left uncommitted. If the requested changeset is
5345 not an ancestor or descendant (that is, it is on another
5344 not an ancestor or descendant (that is, it is on another
5346 branch), the update is aborted and the uncommitted changes
5345 branch), the update is aborted and the uncommitted changes
5347 are preserved.
5346 are preserved.
5348
5347
5349 2. With the -c/--check option, the update is aborted and the
5348 2. With the -c/--check option, the update is aborted and the
5350 uncommitted changes are preserved.
5349 uncommitted changes are preserved.
5351
5350
5352 3. With the -C/--clean option, uncommitted changes are discarded and
5351 3. With the -C/--clean option, uncommitted changes are discarded and
5353 the working directory is updated to the requested changeset.
5352 the working directory is updated to the requested changeset.
5354
5353
5355 To cancel an uncommitted merge (and lose your changes), use
5354 To cancel an uncommitted merge (and lose your changes), use
5356 :hg:`update --clean .`.
5355 :hg:`update --clean .`.
5357
5356
5358 Use null as the changeset to remove the working directory (like
5357 Use null as the changeset to remove the working directory (like
5359 :hg:`clone -U`).
5358 :hg:`clone -U`).
5360
5359
5361 If you want to revert just one file to an older revision, use
5360 If you want to revert just one file to an older revision, use
5362 :hg:`revert [-r REV] NAME`.
5361 :hg:`revert [-r REV] NAME`.
5363
5362
5364 See :hg:`help dates` for a list of formats valid for -d/--date.
5363 See :hg:`help dates` for a list of formats valid for -d/--date.
5365
5364
5366 Returns 0 on success, 1 if there are unresolved files.
5365 Returns 0 on success, 1 if there are unresolved files.
5367 """
5366 """
5368 if rev and node:
5367 if rev and node:
5369 raise error.Abort(_("please specify just one revision"))
5368 raise error.Abort(_("please specify just one revision"))
5370
5369
5371 if rev is None or rev == '':
5370 if rev is None or rev == '':
5372 rev = node
5371 rev = node
5373
5372
5374 if date and rev is not None:
5373 if date and rev is not None:
5375 raise error.Abort(_("you can't specify a revision and a date"))
5374 raise error.Abort(_("you can't specify a revision and a date"))
5376
5375
5377 if check and clean:
5376 if check and clean:
5378 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5377 raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
5379
5378
5380 with repo.wlock():
5379 with repo.wlock():
5381 cmdutil.clearunfinished(repo)
5380 cmdutil.clearunfinished(repo)
5382
5381
5383 if date:
5382 if date:
5384 rev = cmdutil.finddate(ui, repo, date)
5383 rev = cmdutil.finddate(ui, repo, date)
5385
5384
5386 # if we defined a bookmark, we have to remember the original name
5385 # if we defined a bookmark, we have to remember the original name
5387 brev = rev
5386 brev = rev
5388 rev = scmutil.revsingle(repo, rev, rev).rev()
5387 rev = scmutil.revsingle(repo, rev, rev).rev()
5389
5388
5390 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5389 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
5391
5390
5392 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5391 return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
5393
5392
5394 @command('verify', [])
5393 @command('verify', [])
5395 def verify(ui, repo):
5394 def verify(ui, repo):
5396 """verify the integrity of the repository
5395 """verify the integrity of the repository
5397
5396
5398 Verify the integrity of the current repository.
5397 Verify the integrity of the current repository.
5399
5398
5400 This will perform an extensive check of the repository's
5399 This will perform an extensive check of the repository's
5401 integrity, validating the hashes and checksums of each entry in
5400 integrity, validating the hashes and checksums of each entry in
5402 the changelog, manifest, and tracked files, as well as the
5401 the changelog, manifest, and tracked files, as well as the
5403 integrity of their crosslinks and indices.
5402 integrity of their crosslinks and indices.
5404
5403
5405 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5404 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
5406 for more information about recovery from corruption of the
5405 for more information about recovery from corruption of the
5407 repository.
5406 repository.
5408
5407
5409 Returns 0 on success, 1 if errors are encountered.
5408 Returns 0 on success, 1 if errors are encountered.
5410 """
5409 """
5411 return hg.verify(repo)
5410 return hg.verify(repo)
5412
5411
5413 @command('version', [] + formatteropts, norepo=True)
5412 @command('version', [] + formatteropts, norepo=True)
5414 def version_(ui, **opts):
5413 def version_(ui, **opts):
5415 """output version and copyright information"""
5414 """output version and copyright information"""
5416 if ui.verbose:
5415 if ui.verbose:
5417 ui.pager('version')
5416 ui.pager('version')
5418 fm = ui.formatter("version", opts)
5417 fm = ui.formatter("version", opts)
5419 fm.startitem()
5418 fm.startitem()
5420 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5419 fm.write("ver", _("Mercurial Distributed SCM (version %s)\n"),
5421 util.version())
5420 util.version())
5422 license = _(
5421 license = _(
5423 "(see https://mercurial-scm.org for more information)\n"
5422 "(see https://mercurial-scm.org for more information)\n"
5424 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5423 "\nCopyright (C) 2005-2017 Matt Mackall and others\n"
5425 "This is free software; see the source for copying conditions. "
5424 "This is free software; see the source for copying conditions. "
5426 "There is NO\nwarranty; "
5425 "There is NO\nwarranty; "
5427 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5426 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5428 )
5427 )
5429 if not ui.quiet:
5428 if not ui.quiet:
5430 fm.plain(license)
5429 fm.plain(license)
5431
5430
5432 if ui.verbose:
5431 if ui.verbose:
5433 fm.plain(_("\nEnabled extensions:\n\n"))
5432 fm.plain(_("\nEnabled extensions:\n\n"))
5434 # format names and versions into columns
5433 # format names and versions into columns
5435 names = []
5434 names = []
5436 vers = []
5435 vers = []
5437 isinternals = []
5436 isinternals = []
5438 for name, module in extensions.extensions():
5437 for name, module in extensions.extensions():
5439 names.append(name)
5438 names.append(name)
5440 vers.append(extensions.moduleversion(module) or None)
5439 vers.append(extensions.moduleversion(module) or None)
5441 isinternals.append(extensions.ismoduleinternal(module))
5440 isinternals.append(extensions.ismoduleinternal(module))
5442 fn = fm.nested("extensions")
5441 fn = fm.nested("extensions")
5443 if names:
5442 if names:
5444 namefmt = " %%-%ds " % max(len(n) for n in names)
5443 namefmt = " %%-%ds " % max(len(n) for n in names)
5445 places = [_("external"), _("internal")]
5444 places = [_("external"), _("internal")]
5446 for n, v, p in zip(names, vers, isinternals):
5445 for n, v, p in zip(names, vers, isinternals):
5447 fn.startitem()
5446 fn.startitem()
5448 fn.condwrite(ui.verbose, "name", namefmt, n)
5447 fn.condwrite(ui.verbose, "name", namefmt, n)
5449 if ui.verbose:
5448 if ui.verbose:
5450 fn.plain("%s " % places[p])
5449 fn.plain("%s " % places[p])
5451 fn.data(bundled=p)
5450 fn.data(bundled=p)
5452 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5451 fn.condwrite(ui.verbose and v, "ver", "%s", v)
5453 if ui.verbose:
5452 if ui.verbose:
5454 fn.plain("\n")
5453 fn.plain("\n")
5455 fn.end()
5454 fn.end()
5456 fm.end()
5455 fm.end()
5457
5456
5458 def loadcmdtable(ui, name, cmdtable):
5457 def loadcmdtable(ui, name, cmdtable):
5459 """Load command functions from specified cmdtable
5458 """Load command functions from specified cmdtable
5460 """
5459 """
5461 overrides = [cmd for cmd in cmdtable if cmd in table]
5460 overrides = [cmd for cmd in cmdtable if cmd in table]
5462 if overrides:
5461 if overrides:
5463 ui.warn(_("extension '%s' overrides commands: %s\n")
5462 ui.warn(_("extension '%s' overrides commands: %s\n")
5464 % (name, " ".join(overrides)))
5463 % (name, " ".join(overrides)))
5465 table.update(cmdtable)
5464 table.update(cmdtable)
@@ -1,1029 +1,1030 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from __future__ import absolute_import
9 from __future__ import absolute_import
10
10
11 import errno
11 import errno
12 import hashlib
12 import hashlib
13 import os
13 import os
14 import shutil
14 import shutil
15
15
16 from .i18n import _
16 from .i18n import _
17 from .node import nullid
17 from .node import nullid
18
18
19 from . import (
19 from . import (
20 bookmarks,
20 bookmarks,
21 bundlerepo,
21 bundlerepo,
22 cmdutil,
22 cmdutil,
23 destutil,
23 destutil,
24 discovery,
24 discovery,
25 error,
25 error,
26 exchange,
26 exchange,
27 extensions,
27 extensions,
28 httppeer,
28 httppeer,
29 localrepo,
29 localrepo,
30 lock,
30 lock,
31 merge as mergemod,
31 merge as mergemod,
32 node,
32 node,
33 phases,
33 phases,
34 repoview,
34 repoview,
35 scmutil,
35 scmutil,
36 sshpeer,
36 sshpeer,
37 statichttprepo,
37 statichttprepo,
38 ui as uimod,
38 ui as uimod,
39 unionrepo,
39 unionrepo,
40 url,
40 url,
41 util,
41 util,
42 verify as verifymod,
42 verify as verifymod,
43 )
43 )
44
44
45 release = lock.release
45 release = lock.release
46
46
47 # shared features
47 # shared features
48 sharedbookmarks = 'bookmarks'
48 sharedbookmarks = 'bookmarks'
49
49
50 def _local(path):
50 def _local(path):
51 path = util.expandpath(util.urllocalpath(path))
51 path = util.expandpath(util.urllocalpath(path))
52 return (os.path.isfile(path) and bundlerepo or localrepo)
52 return (os.path.isfile(path) and bundlerepo or localrepo)
53
53
54 def addbranchrevs(lrepo, other, branches, revs):
54 def addbranchrevs(lrepo, other, branches, revs):
55 peer = other.peer() # a courtesy to callers using a localrepo for other
55 peer = other.peer() # a courtesy to callers using a localrepo for other
56 hashbranch, branches = branches
56 hashbranch, branches = branches
57 if not hashbranch and not branches:
57 if not hashbranch and not branches:
58 x = revs or None
58 x = revs or None
59 if util.safehasattr(revs, 'first'):
59 if util.safehasattr(revs, 'first'):
60 y = revs.first()
60 y = revs.first()
61 elif revs:
61 elif revs:
62 y = revs[0]
62 y = revs[0]
63 else:
63 else:
64 y = None
64 y = None
65 return x, y
65 return x, y
66 if revs:
66 if revs:
67 revs = list(revs)
67 revs = list(revs)
68 else:
68 else:
69 revs = []
69 revs = []
70
70
71 if not peer.capable('branchmap'):
71 if not peer.capable('branchmap'):
72 if branches:
72 if branches:
73 raise error.Abort(_("remote branch lookup not supported"))
73 raise error.Abort(_("remote branch lookup not supported"))
74 revs.append(hashbranch)
74 revs.append(hashbranch)
75 return revs, revs[0]
75 return revs, revs[0]
76 branchmap = peer.branchmap()
76 branchmap = peer.branchmap()
77
77
78 def primary(branch):
78 def primary(branch):
79 if branch == '.':
79 if branch == '.':
80 if not lrepo:
80 if not lrepo:
81 raise error.Abort(_("dirstate branch not accessible"))
81 raise error.Abort(_("dirstate branch not accessible"))
82 branch = lrepo.dirstate.branch()
82 branch = lrepo.dirstate.branch()
83 if branch in branchmap:
83 if branch in branchmap:
84 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
84 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
85 return True
85 return True
86 else:
86 else:
87 return False
87 return False
88
88
89 for branch in branches:
89 for branch in branches:
90 if not primary(branch):
90 if not primary(branch):
91 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
91 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
92 if hashbranch:
92 if hashbranch:
93 if not primary(hashbranch):
93 if not primary(hashbranch):
94 revs.append(hashbranch)
94 revs.append(hashbranch)
95 return revs, revs[0]
95 return revs, revs[0]
96
96
97 def parseurl(path, branches=None):
97 def parseurl(path, branches=None):
98 '''parse url#branch, returning (url, (branch, branches))'''
98 '''parse url#branch, returning (url, (branch, branches))'''
99
99
100 u = util.url(path)
100 u = util.url(path)
101 branch = None
101 branch = None
102 if u.fragment:
102 if u.fragment:
103 branch = u.fragment
103 branch = u.fragment
104 u.fragment = None
104 u.fragment = None
105 return str(u), (branch, branches or [])
105 return str(u), (branch, branches or [])
106
106
107 schemes = {
107 schemes = {
108 'bundle': bundlerepo,
108 'bundle': bundlerepo,
109 'union': unionrepo,
109 'union': unionrepo,
110 'file': _local,
110 'file': _local,
111 'http': httppeer,
111 'http': httppeer,
112 'https': httppeer,
112 'https': httppeer,
113 'ssh': sshpeer,
113 'ssh': sshpeer,
114 'static-http': statichttprepo,
114 'static-http': statichttprepo,
115 }
115 }
116
116
117 def _peerlookup(path):
117 def _peerlookup(path):
118 u = util.url(path)
118 u = util.url(path)
119 scheme = u.scheme or 'file'
119 scheme = u.scheme or 'file'
120 thing = schemes.get(scheme) or schemes['file']
120 thing = schemes.get(scheme) or schemes['file']
121 try:
121 try:
122 return thing(path)
122 return thing(path)
123 except TypeError:
123 except TypeError:
124 # we can't test callable(thing) because 'thing' can be an unloaded
124 # we can't test callable(thing) because 'thing' can be an unloaded
125 # module that implements __call__
125 # module that implements __call__
126 if not util.safehasattr(thing, 'instance'):
126 if not util.safehasattr(thing, 'instance'):
127 raise
127 raise
128 return thing
128 return thing
129
129
130 def islocal(repo):
130 def islocal(repo):
131 '''return true if repo (or path pointing to repo) is local'''
131 '''return true if repo (or path pointing to repo) is local'''
132 if isinstance(repo, str):
132 if isinstance(repo, str):
133 try:
133 try:
134 return _peerlookup(repo).islocal(repo)
134 return _peerlookup(repo).islocal(repo)
135 except AttributeError:
135 except AttributeError:
136 return False
136 return False
137 return repo.local()
137 return repo.local()
138
138
139 def openpath(ui, path):
139 def openpath(ui, path):
140 '''open path with open if local, url.open if remote'''
140 '''open path with open if local, url.open if remote'''
141 pathurl = util.url(path, parsequery=False, parsefragment=False)
141 pathurl = util.url(path, parsequery=False, parsefragment=False)
142 if pathurl.islocal():
142 if pathurl.islocal():
143 return util.posixfile(pathurl.localpath(), 'rb')
143 return util.posixfile(pathurl.localpath(), 'rb')
144 else:
144 else:
145 return url.open(ui, path)
145 return url.open(ui, path)
146
146
147 # a list of (ui, repo) functions called for wire peer initialization
147 # a list of (ui, repo) functions called for wire peer initialization
148 wirepeersetupfuncs = []
148 wirepeersetupfuncs = []
149
149
150 def _peerorrepo(ui, path, create=False):
150 def _peerorrepo(ui, path, create=False):
151 """return a repository object for the specified path"""
151 """return a repository object for the specified path"""
152 obj = _peerlookup(path).instance(ui, path, create)
152 obj = _peerlookup(path).instance(ui, path, create)
153 ui = getattr(obj, "ui", ui)
153 ui = getattr(obj, "ui", ui)
154 for name, module in extensions.extensions(ui):
154 for name, module in extensions.extensions(ui):
155 hook = getattr(module, 'reposetup', None)
155 hook = getattr(module, 'reposetup', None)
156 if hook:
156 if hook:
157 hook(ui, obj)
157 hook(ui, obj)
158 if not obj.local():
158 if not obj.local():
159 for f in wirepeersetupfuncs:
159 for f in wirepeersetupfuncs:
160 f(ui, obj)
160 f(ui, obj)
161 return obj
161 return obj
162
162
163 def repository(ui, path='', create=False):
163 def repository(ui, path='', create=False):
164 """return a repository object for the specified path"""
164 """return a repository object for the specified path"""
165 peer = _peerorrepo(ui, path, create)
165 peer = _peerorrepo(ui, path, create)
166 repo = peer.local()
166 repo = peer.local()
167 if not repo:
167 if not repo:
168 raise error.Abort(_("repository '%s' is not local") %
168 raise error.Abort(_("repository '%s' is not local") %
169 (path or peer.url()))
169 (path or peer.url()))
170 return repo.filtered('visible')
170 return repo.filtered('visible')
171
171
172 def peer(uiorrepo, opts, path, create=False):
172 def peer(uiorrepo, opts, path, create=False):
173 '''return a repository peer for the specified path'''
173 '''return a repository peer for the specified path'''
174 rui = remoteui(uiorrepo, opts)
174 rui = remoteui(uiorrepo, opts)
175 return _peerorrepo(rui, path, create).peer()
175 return _peerorrepo(rui, path, create).peer()
176
176
177 def defaultdest(source):
177 def defaultdest(source):
178 '''return default destination of clone if none is given
178 '''return default destination of clone if none is given
179
179
180 >>> defaultdest('foo')
180 >>> defaultdest('foo')
181 'foo'
181 'foo'
182 >>> defaultdest('/foo/bar')
182 >>> defaultdest('/foo/bar')
183 'bar'
183 'bar'
184 >>> defaultdest('/')
184 >>> defaultdest('/')
185 ''
185 ''
186 >>> defaultdest('')
186 >>> defaultdest('')
187 ''
187 ''
188 >>> defaultdest('http://example.org/')
188 >>> defaultdest('http://example.org/')
189 ''
189 ''
190 >>> defaultdest('http://example.org/foo/')
190 >>> defaultdest('http://example.org/foo/')
191 'foo'
191 'foo'
192 '''
192 '''
193 path = util.url(source).path
193 path = util.url(source).path
194 if not path:
194 if not path:
195 return ''
195 return ''
196 return os.path.basename(os.path.normpath(path))
196 return os.path.basename(os.path.normpath(path))
197
197
198 def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None):
198 def share(ui, source, dest=None, update=True, bookmarks=True, defaultpath=None):
199 '''create a shared repository'''
199 '''create a shared repository'''
200
200
201 if not islocal(source):
201 if not islocal(source):
202 raise error.Abort(_('can only share local repositories'))
202 raise error.Abort(_('can only share local repositories'))
203
203
204 if not dest:
204 if not dest:
205 dest = defaultdest(source)
205 dest = defaultdest(source)
206 else:
206 else:
207 dest = ui.expandpath(dest)
207 dest = ui.expandpath(dest)
208
208
209 if isinstance(source, str):
209 if isinstance(source, str):
210 origsource = ui.expandpath(source)
210 origsource = ui.expandpath(source)
211 source, branches = parseurl(origsource)
211 source, branches = parseurl(origsource)
212 srcrepo = repository(ui, source)
212 srcrepo = repository(ui, source)
213 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
213 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
214 else:
214 else:
215 srcrepo = source.local()
215 srcrepo = source.local()
216 origsource = source = srcrepo.url()
216 origsource = source = srcrepo.url()
217 checkout = None
217 checkout = None
218
218
219 sharedpath = srcrepo.sharedpath # if our source is already sharing
219 sharedpath = srcrepo.sharedpath # if our source is already sharing
220
220
221 destwvfs = scmutil.vfs(dest, realpath=True)
221 destwvfs = scmutil.vfs(dest, realpath=True)
222 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
222 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
223
223
224 if destvfs.lexists():
224 if destvfs.lexists():
225 raise error.Abort(_('destination already exists'))
225 raise error.Abort(_('destination already exists'))
226
226
227 if not destwvfs.isdir():
227 if not destwvfs.isdir():
228 destwvfs.mkdir()
228 destwvfs.mkdir()
229 destvfs.makedir()
229 destvfs.makedir()
230
230
231 requirements = ''
231 requirements = ''
232 try:
232 try:
233 requirements = srcrepo.vfs.read('requires')
233 requirements = srcrepo.vfs.read('requires')
234 except IOError as inst:
234 except IOError as inst:
235 if inst.errno != errno.ENOENT:
235 if inst.errno != errno.ENOENT:
236 raise
236 raise
237
237
238 requirements += 'shared\n'
238 requirements += 'shared\n'
239 destvfs.write('requires', requirements)
239 destvfs.write('requires', requirements)
240 destvfs.write('sharedpath', sharedpath)
240 destvfs.write('sharedpath', sharedpath)
241
241
242 r = repository(ui, destwvfs.base)
242 r = repository(ui, destwvfs.base)
243 postshare(srcrepo, r, bookmarks=bookmarks, defaultpath=defaultpath)
243 postshare(srcrepo, r, bookmarks=bookmarks, defaultpath=defaultpath)
244 _postshareupdate(r, update, checkout=checkout)
244 _postshareupdate(r, update, checkout=checkout)
245
245
246 def postshare(sourcerepo, destrepo, bookmarks=True, defaultpath=None):
246 def postshare(sourcerepo, destrepo, bookmarks=True, defaultpath=None):
247 """Called after a new shared repo is created.
247 """Called after a new shared repo is created.
248
248
249 The new repo only has a requirements file and pointer to the source.
249 The new repo only has a requirements file and pointer to the source.
250 This function configures additional shared data.
250 This function configures additional shared data.
251
251
252 Extensions can wrap this function and write additional entries to
252 Extensions can wrap this function and write additional entries to
253 destrepo/.hg/shared to indicate additional pieces of data to be shared.
253 destrepo/.hg/shared to indicate additional pieces of data to be shared.
254 """
254 """
255 default = defaultpath or sourcerepo.ui.config('paths', 'default')
255 default = defaultpath or sourcerepo.ui.config('paths', 'default')
256 if default:
256 if default:
257 fp = destrepo.vfs("hgrc", "w", text=True)
257 fp = destrepo.vfs("hgrc", "w", text=True)
258 fp.write("[paths]\n")
258 fp.write("[paths]\n")
259 fp.write("default = %s\n" % default)
259 fp.write("default = %s\n" % default)
260 fp.close()
260 fp.close()
261
261
262 with destrepo.wlock():
262 with destrepo.wlock():
263 if bookmarks:
263 if bookmarks:
264 fp = destrepo.vfs('shared', 'w')
264 fp = destrepo.vfs('shared', 'w')
265 fp.write(sharedbookmarks + '\n')
265 fp.write(sharedbookmarks + '\n')
266 fp.close()
266 fp.close()
267
267
268 def _postshareupdate(repo, update, checkout=None):
268 def _postshareupdate(repo, update, checkout=None):
269 """Maybe perform a working directory update after a shared repo is created.
269 """Maybe perform a working directory update after a shared repo is created.
270
270
271 ``update`` can be a boolean or a revision to update to.
271 ``update`` can be a boolean or a revision to update to.
272 """
272 """
273 if not update:
273 if not update:
274 return
274 return
275
275
276 repo.ui.status(_("updating working directory\n"))
276 repo.ui.status(_("updating working directory\n"))
277 if update is not True:
277 if update is not True:
278 checkout = update
278 checkout = update
279 for test in (checkout, 'default', 'tip'):
279 for test in (checkout, 'default', 'tip'):
280 if test is None:
280 if test is None:
281 continue
281 continue
282 try:
282 try:
283 uprev = repo.lookup(test)
283 uprev = repo.lookup(test)
284 break
284 break
285 except error.RepoLookupError:
285 except error.RepoLookupError:
286 continue
286 continue
287 _update(repo, uprev)
287 _update(repo, uprev)
288
288
289 def copystore(ui, srcrepo, destpath):
289 def copystore(ui, srcrepo, destpath):
290 '''copy files from store of srcrepo in destpath
290 '''copy files from store of srcrepo in destpath
291
291
292 returns destlock
292 returns destlock
293 '''
293 '''
294 destlock = None
294 destlock = None
295 try:
295 try:
296 hardlink = None
296 hardlink = None
297 num = 0
297 num = 0
298 closetopic = [None]
298 closetopic = [None]
299 def prog(topic, pos):
299 def prog(topic, pos):
300 if pos is None:
300 if pos is None:
301 closetopic[0] = topic
301 closetopic[0] = topic
302 else:
302 else:
303 ui.progress(topic, pos + num)
303 ui.progress(topic, pos + num)
304 srcpublishing = srcrepo.publishing()
304 srcpublishing = srcrepo.publishing()
305 srcvfs = scmutil.vfs(srcrepo.sharedpath)
305 srcvfs = scmutil.vfs(srcrepo.sharedpath)
306 dstvfs = scmutil.vfs(destpath)
306 dstvfs = scmutil.vfs(destpath)
307 for f in srcrepo.store.copylist():
307 for f in srcrepo.store.copylist():
308 if srcpublishing and f.endswith('phaseroots'):
308 if srcpublishing and f.endswith('phaseroots'):
309 continue
309 continue
310 dstbase = os.path.dirname(f)
310 dstbase = os.path.dirname(f)
311 if dstbase and not dstvfs.exists(dstbase):
311 if dstbase and not dstvfs.exists(dstbase):
312 dstvfs.mkdir(dstbase)
312 dstvfs.mkdir(dstbase)
313 if srcvfs.exists(f):
313 if srcvfs.exists(f):
314 if f.endswith('data'):
314 if f.endswith('data'):
315 # 'dstbase' may be empty (e.g. revlog format 0)
315 # 'dstbase' may be empty (e.g. revlog format 0)
316 lockfile = os.path.join(dstbase, "lock")
316 lockfile = os.path.join(dstbase, "lock")
317 # lock to avoid premature writing to the target
317 # lock to avoid premature writing to the target
318 destlock = lock.lock(dstvfs, lockfile)
318 destlock = lock.lock(dstvfs, lockfile)
319 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
319 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
320 hardlink, progress=prog)
320 hardlink, progress=prog)
321 num += n
321 num += n
322 if hardlink:
322 if hardlink:
323 ui.debug("linked %d files\n" % num)
323 ui.debug("linked %d files\n" % num)
324 if closetopic[0]:
324 if closetopic[0]:
325 ui.progress(closetopic[0], None)
325 ui.progress(closetopic[0], None)
326 else:
326 else:
327 ui.debug("copied %d files\n" % num)
327 ui.debug("copied %d files\n" % num)
328 if closetopic[0]:
328 if closetopic[0]:
329 ui.progress(closetopic[0], None)
329 ui.progress(closetopic[0], None)
330 return destlock
330 return destlock
331 except: # re-raises
331 except: # re-raises
332 release(destlock)
332 release(destlock)
333 raise
333 raise
334
334
335 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
335 def clonewithshare(ui, peeropts, sharepath, source, srcpeer, dest, pull=False,
336 rev=None, update=True, stream=False):
336 rev=None, update=True, stream=False):
337 """Perform a clone using a shared repo.
337 """Perform a clone using a shared repo.
338
338
339 The store for the repository will be located at <sharepath>/.hg. The
339 The store for the repository will be located at <sharepath>/.hg. The
340 specified revisions will be cloned or pulled from "source". A shared repo
340 specified revisions will be cloned or pulled from "source". A shared repo
341 will be created at "dest" and a working copy will be created if "update" is
341 will be created at "dest" and a working copy will be created if "update" is
342 True.
342 True.
343 """
343 """
344 revs = None
344 revs = None
345 if rev:
345 if rev:
346 if not srcpeer.capable('lookup'):
346 if not srcpeer.capable('lookup'):
347 raise error.Abort(_("src repository does not support "
347 raise error.Abort(_("src repository does not support "
348 "revision lookup and so doesn't "
348 "revision lookup and so doesn't "
349 "support clone by revision"))
349 "support clone by revision"))
350 revs = [srcpeer.lookup(r) for r in rev]
350 revs = [srcpeer.lookup(r) for r in rev]
351
351
352 # Obtain a lock before checking for or cloning the pooled repo otherwise
352 # Obtain a lock before checking for or cloning the pooled repo otherwise
353 # 2 clients may race creating or populating it.
353 # 2 clients may race creating or populating it.
354 pooldir = os.path.dirname(sharepath)
354 pooldir = os.path.dirname(sharepath)
355 # lock class requires the directory to exist.
355 # lock class requires the directory to exist.
356 try:
356 try:
357 util.makedir(pooldir, False)
357 util.makedir(pooldir, False)
358 except OSError as e:
358 except OSError as e:
359 if e.errno != errno.EEXIST:
359 if e.errno != errno.EEXIST:
360 raise
360 raise
361
361
362 poolvfs = scmutil.vfs(pooldir)
362 poolvfs = scmutil.vfs(pooldir)
363 basename = os.path.basename(sharepath)
363 basename = os.path.basename(sharepath)
364
364
365 with lock.lock(poolvfs, '%s.lock' % basename):
365 with lock.lock(poolvfs, '%s.lock' % basename):
366 if os.path.exists(sharepath):
366 if os.path.exists(sharepath):
367 ui.status(_('(sharing from existing pooled repository %s)\n') %
367 ui.status(_('(sharing from existing pooled repository %s)\n') %
368 basename)
368 basename)
369 else:
369 else:
370 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
370 ui.status(_('(sharing from new pooled repository %s)\n') % basename)
371 # Always use pull mode because hardlinks in share mode don't work
371 # Always use pull mode because hardlinks in share mode don't work
372 # well. Never update because working copies aren't necessary in
372 # well. Never update because working copies aren't necessary in
373 # share mode.
373 # share mode.
374 clone(ui, peeropts, source, dest=sharepath, pull=True,
374 clone(ui, peeropts, source, dest=sharepath, pull=True,
375 rev=rev, update=False, stream=stream)
375 rev=rev, update=False, stream=stream)
376
376
377 # Resolve the value to put in [paths] section for the source.
377 # Resolve the value to put in [paths] section for the source.
378 if islocal(source):
378 if islocal(source):
379 defaultpath = os.path.abspath(util.urllocalpath(source))
379 defaultpath = os.path.abspath(util.urllocalpath(source))
380 else:
380 else:
381 defaultpath = source
381 defaultpath = source
382
382
383 sharerepo = repository(ui, path=sharepath)
383 sharerepo = repository(ui, path=sharepath)
384 share(ui, sharerepo, dest=dest, update=False, bookmarks=False,
384 share(ui, sharerepo, dest=dest, update=False, bookmarks=False,
385 defaultpath=defaultpath)
385 defaultpath=defaultpath)
386
386
387 # We need to perform a pull against the dest repo to fetch bookmarks
387 # We need to perform a pull against the dest repo to fetch bookmarks
388 # and other non-store data that isn't shared by default. In the case of
388 # and other non-store data that isn't shared by default. In the case of
389 # non-existing shared repo, this means we pull from the remote twice. This
389 # non-existing shared repo, this means we pull from the remote twice. This
390 # is a bit weird. But at the time it was implemented, there wasn't an easy
390 # is a bit weird. But at the time it was implemented, there wasn't an easy
391 # way to pull just non-changegroup data.
391 # way to pull just non-changegroup data.
392 destrepo = repository(ui, path=dest)
392 destrepo = repository(ui, path=dest)
393 exchange.pull(destrepo, srcpeer, heads=revs)
393 exchange.pull(destrepo, srcpeer, heads=revs)
394
394
395 _postshareupdate(destrepo, update)
395 _postshareupdate(destrepo, update)
396
396
397 return srcpeer, peer(ui, peeropts, dest)
397 return srcpeer, peer(ui, peeropts, dest)
398
398
399 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
399 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
400 update=True, stream=False, branch=None, shareopts=None):
400 update=True, stream=False, branch=None, shareopts=None):
401 """Make a copy of an existing repository.
401 """Make a copy of an existing repository.
402
402
403 Create a copy of an existing repository in a new directory. The
403 Create a copy of an existing repository in a new directory. The
404 source and destination are URLs, as passed to the repository
404 source and destination are URLs, as passed to the repository
405 function. Returns a pair of repository peers, the source and
405 function. Returns a pair of repository peers, the source and
406 newly created destination.
406 newly created destination.
407
407
408 The location of the source is added to the new repository's
408 The location of the source is added to the new repository's
409 .hg/hgrc file, as the default to be used for future pulls and
409 .hg/hgrc file, as the default to be used for future pulls and
410 pushes.
410 pushes.
411
411
412 If an exception is raised, the partly cloned/updated destination
412 If an exception is raised, the partly cloned/updated destination
413 repository will be deleted.
413 repository will be deleted.
414
414
415 Arguments:
415 Arguments:
416
416
417 source: repository object or URL
417 source: repository object or URL
418
418
419 dest: URL of destination repository to create (defaults to base
419 dest: URL of destination repository to create (defaults to base
420 name of source repository)
420 name of source repository)
421
421
422 pull: always pull from source repository, even in local case or if the
422 pull: always pull from source repository, even in local case or if the
423 server prefers streaming
423 server prefers streaming
424
424
425 stream: stream raw data uncompressed from repository (fast over
425 stream: stream raw data uncompressed from repository (fast over
426 LAN, slow over WAN)
426 LAN, slow over WAN)
427
427
428 rev: revision to clone up to (implies pull=True)
428 rev: revision to clone up to (implies pull=True)
429
429
430 update: update working directory after clone completes, if
430 update: update working directory after clone completes, if
431 destination is local repository (True means update to default rev,
431 destination is local repository (True means update to default rev,
432 anything else is treated as a revision)
432 anything else is treated as a revision)
433
433
434 branch: branches to clone
434 branch: branches to clone
435
435
436 shareopts: dict of options to control auto sharing behavior. The "pool" key
436 shareopts: dict of options to control auto sharing behavior. The "pool" key
437 activates auto sharing mode and defines the directory for stores. The
437 activates auto sharing mode and defines the directory for stores. The
438 "mode" key determines how to construct the directory name of the shared
438 "mode" key determines how to construct the directory name of the shared
439 repository. "identity" means the name is derived from the node of the first
439 repository. "identity" means the name is derived from the node of the first
440 changeset in the repository. "remote" means the name is derived from the
440 changeset in the repository. "remote" means the name is derived from the
441 remote's path/URL. Defaults to "identity."
441 remote's path/URL. Defaults to "identity."
442 """
442 """
443
443
444 if isinstance(source, str):
444 if isinstance(source, str):
445 origsource = ui.expandpath(source)
445 origsource = ui.expandpath(source)
446 source, branch = parseurl(origsource, branch)
446 source, branch = parseurl(origsource, branch)
447 srcpeer = peer(ui, peeropts, source)
447 srcpeer = peer(ui, peeropts, source)
448 else:
448 else:
449 srcpeer = source.peer() # in case we were called with a localrepo
449 srcpeer = source.peer() # in case we were called with a localrepo
450 branch = (None, branch or [])
450 branch = (None, branch or [])
451 origsource = source = srcpeer.url()
451 origsource = source = srcpeer.url()
452 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
452 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
453
453
454 if dest is None:
454 if dest is None:
455 dest = defaultdest(source)
455 dest = defaultdest(source)
456 if dest:
456 if dest:
457 ui.status(_("destination directory: %s\n") % dest)
457 ui.status(_("destination directory: %s\n") % dest)
458 else:
458 else:
459 dest = ui.expandpath(dest)
459 dest = ui.expandpath(dest)
460
460
461 dest = util.urllocalpath(dest)
461 dest = util.urllocalpath(dest)
462 source = util.urllocalpath(source)
462 source = util.urllocalpath(source)
463
463
464 if not dest:
464 if not dest:
465 raise error.Abort(_("empty destination path is not valid"))
465 raise error.Abort(_("empty destination path is not valid"))
466
466
467 destvfs = scmutil.vfs(dest, expandpath=True)
467 destvfs = scmutil.vfs(dest, expandpath=True)
468 if destvfs.lexists():
468 if destvfs.lexists():
469 if not destvfs.isdir():
469 if not destvfs.isdir():
470 raise error.Abort(_("destination '%s' already exists") % dest)
470 raise error.Abort(_("destination '%s' already exists") % dest)
471 elif destvfs.listdir():
471 elif destvfs.listdir():
472 raise error.Abort(_("destination '%s' is not empty") % dest)
472 raise error.Abort(_("destination '%s' is not empty") % dest)
473
473
474 shareopts = shareopts or {}
474 shareopts = shareopts or {}
475 sharepool = shareopts.get('pool')
475 sharepool = shareopts.get('pool')
476 sharenamemode = shareopts.get('mode')
476 sharenamemode = shareopts.get('mode')
477 if sharepool and islocal(dest):
477 if sharepool and islocal(dest):
478 sharepath = None
478 sharepath = None
479 if sharenamemode == 'identity':
479 if sharenamemode == 'identity':
480 # Resolve the name from the initial changeset in the remote
480 # Resolve the name from the initial changeset in the remote
481 # repository. This returns nullid when the remote is empty. It
481 # repository. This returns nullid when the remote is empty. It
482 # raises RepoLookupError if revision 0 is filtered or otherwise
482 # raises RepoLookupError if revision 0 is filtered or otherwise
483 # not available. If we fail to resolve, sharing is not enabled.
483 # not available. If we fail to resolve, sharing is not enabled.
484 try:
484 try:
485 rootnode = srcpeer.lookup('0')
485 rootnode = srcpeer.lookup('0')
486 if rootnode != node.nullid:
486 if rootnode != node.nullid:
487 sharepath = os.path.join(sharepool, node.hex(rootnode))
487 sharepath = os.path.join(sharepool, node.hex(rootnode))
488 else:
488 else:
489 ui.status(_('(not using pooled storage: '
489 ui.status(_('(not using pooled storage: '
490 'remote appears to be empty)\n'))
490 'remote appears to be empty)\n'))
491 except error.RepoLookupError:
491 except error.RepoLookupError:
492 ui.status(_('(not using pooled storage: '
492 ui.status(_('(not using pooled storage: '
493 'unable to resolve identity of remote)\n'))
493 'unable to resolve identity of remote)\n'))
494 elif sharenamemode == 'remote':
494 elif sharenamemode == 'remote':
495 sharepath = os.path.join(
495 sharepath = os.path.join(
496 sharepool, hashlib.sha1(source).hexdigest())
496 sharepool, hashlib.sha1(source).hexdigest())
497 else:
497 else:
498 raise error.Abort(_('unknown share naming mode: %s') %
498 raise error.Abort(_('unknown share naming mode: %s') %
499 sharenamemode)
499 sharenamemode)
500
500
501 if sharepath:
501 if sharepath:
502 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
502 return clonewithshare(ui, peeropts, sharepath, source, srcpeer,
503 dest, pull=pull, rev=rev, update=update,
503 dest, pull=pull, rev=rev, update=update,
504 stream=stream)
504 stream=stream)
505
505
506 srclock = destlock = cleandir = None
506 srclock = destlock = cleandir = None
507 srcrepo = srcpeer.local()
507 srcrepo = srcpeer.local()
508 try:
508 try:
509 abspath = origsource
509 abspath = origsource
510 if islocal(origsource):
510 if islocal(origsource):
511 abspath = os.path.abspath(util.urllocalpath(origsource))
511 abspath = os.path.abspath(util.urllocalpath(origsource))
512
512
513 if islocal(dest):
513 if islocal(dest):
514 cleandir = dest
514 cleandir = dest
515
515
516 copy = False
516 copy = False
517 if (srcrepo and srcrepo.cancopy() and islocal(dest)
517 if (srcrepo and srcrepo.cancopy() and islocal(dest)
518 and not phases.hassecret(srcrepo)):
518 and not phases.hassecret(srcrepo)):
519 copy = not pull and not rev
519 copy = not pull and not rev
520
520
521 if copy:
521 if copy:
522 try:
522 try:
523 # we use a lock here because if we race with commit, we
523 # we use a lock here because if we race with commit, we
524 # can end up with extra data in the cloned revlogs that's
524 # can end up with extra data in the cloned revlogs that's
525 # not pointed to by changesets, thus causing verify to
525 # not pointed to by changesets, thus causing verify to
526 # fail
526 # fail
527 srclock = srcrepo.lock(wait=False)
527 srclock = srcrepo.lock(wait=False)
528 except error.LockError:
528 except error.LockError:
529 copy = False
529 copy = False
530
530
531 if copy:
531 if copy:
532 srcrepo.hook('preoutgoing', throw=True, source='clone')
532 srcrepo.hook('preoutgoing', throw=True, source='clone')
533 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
533 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
534 if not os.path.exists(dest):
534 if not os.path.exists(dest):
535 os.mkdir(dest)
535 os.mkdir(dest)
536 else:
536 else:
537 # only clean up directories we create ourselves
537 # only clean up directories we create ourselves
538 cleandir = hgdir
538 cleandir = hgdir
539 try:
539 try:
540 destpath = hgdir
540 destpath = hgdir
541 util.makedir(destpath, notindexed=True)
541 util.makedir(destpath, notindexed=True)
542 except OSError as inst:
542 except OSError as inst:
543 if inst.errno == errno.EEXIST:
543 if inst.errno == errno.EEXIST:
544 cleandir = None
544 cleandir = None
545 raise error.Abort(_("destination '%s' already exists")
545 raise error.Abort(_("destination '%s' already exists")
546 % dest)
546 % dest)
547 raise
547 raise
548
548
549 destlock = copystore(ui, srcrepo, destpath)
549 destlock = copystore(ui, srcrepo, destpath)
550 # copy bookmarks over
550 # copy bookmarks over
551 srcbookmarks = srcrepo.join('bookmarks')
551 srcbookmarks = srcrepo.join('bookmarks')
552 dstbookmarks = os.path.join(destpath, 'bookmarks')
552 dstbookmarks = os.path.join(destpath, 'bookmarks')
553 if os.path.exists(srcbookmarks):
553 if os.path.exists(srcbookmarks):
554 util.copyfile(srcbookmarks, dstbookmarks)
554 util.copyfile(srcbookmarks, dstbookmarks)
555
555
556 # Recomputing branch cache might be slow on big repos,
556 # Recomputing branch cache might be slow on big repos,
557 # so just copy it
557 # so just copy it
558 def copybranchcache(fname):
558 def copybranchcache(fname):
559 srcbranchcache = srcrepo.join('cache/%s' % fname)
559 srcbranchcache = srcrepo.join('cache/%s' % fname)
560 dstbranchcache = os.path.join(dstcachedir, fname)
560 dstbranchcache = os.path.join(dstcachedir, fname)
561 if os.path.exists(srcbranchcache):
561 if os.path.exists(srcbranchcache):
562 if not os.path.exists(dstcachedir):
562 if not os.path.exists(dstcachedir):
563 os.mkdir(dstcachedir)
563 os.mkdir(dstcachedir)
564 util.copyfile(srcbranchcache, dstbranchcache)
564 util.copyfile(srcbranchcache, dstbranchcache)
565
565
566 dstcachedir = os.path.join(destpath, 'cache')
566 dstcachedir = os.path.join(destpath, 'cache')
567 # In local clones we're copying all nodes, not just served
567 # In local clones we're copying all nodes, not just served
568 # ones. Therefore copy all branch caches over.
568 # ones. Therefore copy all branch caches over.
569 copybranchcache('branch2')
569 copybranchcache('branch2')
570 for cachename in repoview.filtertable:
570 for cachename in repoview.filtertable:
571 copybranchcache('branch2-%s' % cachename)
571 copybranchcache('branch2-%s' % cachename)
572
572
573 # we need to re-init the repo after manually copying the data
573 # we need to re-init the repo after manually copying the data
574 # into it
574 # into it
575 destpeer = peer(srcrepo, peeropts, dest)
575 destpeer = peer(srcrepo, peeropts, dest)
576 srcrepo.hook('outgoing', source='clone',
576 srcrepo.hook('outgoing', source='clone',
577 node=node.hex(node.nullid))
577 node=node.hex(node.nullid))
578 else:
578 else:
579 try:
579 try:
580 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
580 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
581 # only pass ui when no srcrepo
581 # only pass ui when no srcrepo
582 except OSError as inst:
582 except OSError as inst:
583 if inst.errno == errno.EEXIST:
583 if inst.errno == errno.EEXIST:
584 cleandir = None
584 cleandir = None
585 raise error.Abort(_("destination '%s' already exists")
585 raise error.Abort(_("destination '%s' already exists")
586 % dest)
586 % dest)
587 raise
587 raise
588
588
589 revs = None
589 revs = None
590 if rev:
590 if rev:
591 if not srcpeer.capable('lookup'):
591 if not srcpeer.capable('lookup'):
592 raise error.Abort(_("src repository does not support "
592 raise error.Abort(_("src repository does not support "
593 "revision lookup and so doesn't "
593 "revision lookup and so doesn't "
594 "support clone by revision"))
594 "support clone by revision"))
595 revs = [srcpeer.lookup(r) for r in rev]
595 revs = [srcpeer.lookup(r) for r in rev]
596 checkout = revs[0]
596 checkout = revs[0]
597 local = destpeer.local()
597 local = destpeer.local()
598 if local:
598 if local:
599 if not stream:
599 if not stream:
600 if pull:
600 if pull:
601 stream = False
601 stream = False
602 else:
602 else:
603 stream = None
603 stream = None
604 # internal config: ui.quietbookmarkmove
604 # internal config: ui.quietbookmarkmove
605 quiet = local.ui.backupconfig('ui', 'quietbookmarkmove')
605 quiet = local.ui.backupconfig('ui', 'quietbookmarkmove')
606 try:
606 try:
607 local.ui.setconfig(
607 local.ui.setconfig(
608 'ui', 'quietbookmarkmove', True, 'clone')
608 'ui', 'quietbookmarkmove', True, 'clone')
609 exchange.pull(local, srcpeer, revs,
609 exchange.pull(local, srcpeer, revs,
610 streamclonerequested=stream)
610 streamclonerequested=stream)
611 finally:
611 finally:
612 local.ui.restoreconfig(quiet)
612 local.ui.restoreconfig(quiet)
613 elif srcrepo:
613 elif srcrepo:
614 exchange.push(srcrepo, destpeer, revs=revs,
614 exchange.push(srcrepo, destpeer, revs=revs,
615 bookmarks=srcrepo._bookmarks.keys())
615 bookmarks=srcrepo._bookmarks.keys())
616 else:
616 else:
617 raise error.Abort(_("clone from remote to remote not supported")
617 raise error.Abort(_("clone from remote to remote not supported")
618 )
618 )
619
619
620 cleandir = None
620 cleandir = None
621
621
622 destrepo = destpeer.local()
622 destrepo = destpeer.local()
623 if destrepo:
623 if destrepo:
624 template = uimod.samplehgrcs['cloned']
624 template = uimod.samplehgrcs['cloned']
625 fp = destrepo.vfs("hgrc", "w", text=True)
625 fp = destrepo.vfs("hgrc", "w", text=True)
626 u = util.url(abspath)
626 u = util.url(abspath)
627 u.passwd = None
627 u.passwd = None
628 defaulturl = str(u)
628 defaulturl = str(u)
629 fp.write(template % defaulturl)
629 fp.write(template % defaulturl)
630 fp.close()
630 fp.close()
631
631
632 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
632 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
633
633
634 if update:
634 if update:
635 if update is not True:
635 if update is not True:
636 checkout = srcpeer.lookup(update)
636 checkout = srcpeer.lookup(update)
637 uprev = None
637 uprev = None
638 status = None
638 status = None
639 if checkout is not None:
639 if checkout is not None:
640 try:
640 try:
641 uprev = destrepo.lookup(checkout)
641 uprev = destrepo.lookup(checkout)
642 except error.RepoLookupError:
642 except error.RepoLookupError:
643 if update is not True:
643 if update is not True:
644 try:
644 try:
645 uprev = destrepo.lookup(update)
645 uprev = destrepo.lookup(update)
646 except error.RepoLookupError:
646 except error.RepoLookupError:
647 pass
647 pass
648 if uprev is None:
648 if uprev is None:
649 try:
649 try:
650 uprev = destrepo._bookmarks['@']
650 uprev = destrepo._bookmarks['@']
651 update = '@'
651 update = '@'
652 bn = destrepo[uprev].branch()
652 bn = destrepo[uprev].branch()
653 if bn == 'default':
653 if bn == 'default':
654 status = _("updating to bookmark @\n")
654 status = _("updating to bookmark @\n")
655 else:
655 else:
656 status = (_("updating to bookmark @ on branch %s\n")
656 status = (_("updating to bookmark @ on branch %s\n")
657 % bn)
657 % bn)
658 except KeyError:
658 except KeyError:
659 try:
659 try:
660 uprev = destrepo.branchtip('default')
660 uprev = destrepo.branchtip('default')
661 except error.RepoLookupError:
661 except error.RepoLookupError:
662 uprev = destrepo.lookup('tip')
662 uprev = destrepo.lookup('tip')
663 if not status:
663 if not status:
664 bn = destrepo[uprev].branch()
664 bn = destrepo[uprev].branch()
665 status = _("updating to branch %s\n") % bn
665 status = _("updating to branch %s\n") % bn
666 destrepo.ui.status(status)
666 destrepo.ui.status(status)
667 _update(destrepo, uprev)
667 _update(destrepo, uprev)
668 if update in destrepo._bookmarks:
668 if update in destrepo._bookmarks:
669 bookmarks.activate(destrepo, update)
669 bookmarks.activate(destrepo, update)
670 finally:
670 finally:
671 release(srclock, destlock)
671 release(srclock, destlock)
672 if cleandir is not None:
672 if cleandir is not None:
673 shutil.rmtree(cleandir, True)
673 shutil.rmtree(cleandir, True)
674 if srcpeer is not None:
674 if srcpeer is not None:
675 srcpeer.close()
675 srcpeer.close()
676 return srcpeer, destpeer
676 return srcpeer, destpeer
677
677
678 def _showstats(repo, stats, quietempty=False):
678 def _showstats(repo, stats, quietempty=False):
679 if quietempty and not any(stats):
679 if quietempty and not any(stats):
680 return
680 return
681 repo.ui.status(_("%d files updated, %d files merged, "
681 repo.ui.status(_("%d files updated, %d files merged, "
682 "%d files removed, %d files unresolved\n") % stats)
682 "%d files removed, %d files unresolved\n") % stats)
683
683
684 def updaterepo(repo, node, overwrite):
684 def updaterepo(repo, node, overwrite):
685 """Update the working directory to node.
685 """Update the working directory to node.
686
686
687 When overwrite is set, changes are clobbered, merged else
687 When overwrite is set, changes are clobbered, merged else
688
688
689 returns stats (see pydoc mercurial.merge.applyupdates)"""
689 returns stats (see pydoc mercurial.merge.applyupdates)"""
690 return mergemod.update(repo, node, False, overwrite,
690 return mergemod.update(repo, node, False, overwrite,
691 labels=['working copy', 'destination'])
691 labels=['working copy', 'destination'])
692
692
693 def update(repo, node, quietempty=False):
693 def update(repo, node, quietempty=False):
694 """update the working directory to node, merging linear changes"""
694 """update the working directory to node, merging linear changes"""
695 stats = updaterepo(repo, node, False)
695 stats = updaterepo(repo, node, False)
696 _showstats(repo, stats, quietempty)
696 _showstats(repo, stats, quietempty)
697 if stats[3]:
697 if stats[3]:
698 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
698 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
699 return stats[3] > 0
699 return stats[3] > 0
700
700
701 # naming conflict in clone()
701 # naming conflict in clone()
702 _update = update
702 _update = update
703
703
704 def clean(repo, node, show_stats=True, quietempty=False):
704 def clean(repo, node, show_stats=True, quietempty=False):
705 """forcibly switch the working directory to node, clobbering changes"""
705 """forcibly switch the working directory to node, clobbering changes"""
706 stats = updaterepo(repo, node, True)
706 stats = updaterepo(repo, node, True)
707 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
707 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
708 if show_stats:
708 if show_stats:
709 _showstats(repo, stats, quietempty)
709 _showstats(repo, stats, quietempty)
710 return stats[3] > 0
710 return stats[3] > 0
711
711
712 # naming conflict in updatetotally()
712 # naming conflict in updatetotally()
713 _clean = clean
713 _clean = clean
714
714
715 def updatetotally(ui, repo, checkout, brev, clean=False, check=False):
715 def updatetotally(ui, repo, checkout, brev, clean=False, check=False):
716 """Update the working directory with extra care for non-file components
716 """Update the working directory with extra care for non-file components
717
717
718 This takes care of non-file components below:
718 This takes care of non-file components below:
719
719
720 :bookmark: might be advanced or (in)activated
720 :bookmark: might be advanced or (in)activated
721
721
722 This takes arguments below:
722 This takes arguments below:
723
723
724 :checkout: to which revision the working directory is updated
724 :checkout: to which revision the working directory is updated
725 :brev: a name, which might be a bookmark to be activated after updating
725 :brev: a name, which might be a bookmark to be activated after updating
726 :clean: whether changes in the working directory can be discarded
726 :clean: whether changes in the working directory can be discarded
727 :check: whether changes in the working directory should be checked
727 :check: whether changes in the working directory should be checked
728
728
729 This returns whether conflict is detected at updating or not.
729 This returns whether conflict is detected at updating or not.
730 """
730 """
731 with repo.wlock():
731 with repo.wlock():
732 movemarkfrom = None
732 movemarkfrom = None
733 warndest = False
733 warndest = False
734 if checkout is None:
734 if checkout is None:
735 updata = destutil.destupdate(repo, clean=clean)
735 updata = destutil.destupdate(repo, clean=clean)
736 checkout, movemarkfrom, brev = updata
736 checkout, movemarkfrom, brev = updata
737 warndest = True
737 warndest = True
738
738
739 if clean:
739 if clean:
740 ret = _clean(repo, checkout)
740 ret = _clean(repo, checkout)
741 else:
741 else:
742 if check:
742 if check:
743 cmdutil.bailifchanged(repo, merge=False)
743 cmdutil.bailifchanged(repo, merge=False)
744 ret = _update(repo, checkout)
744 ret = _update(repo, checkout)
745
745
746 if not ret and movemarkfrom:
746 if not ret and movemarkfrom:
747 if movemarkfrom == repo['.'].node():
747 if movemarkfrom == repo['.'].node():
748 pass # no-op update
748 pass # no-op update
749 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
749 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
750 b = ui.label(repo._activebookmark, 'bookmarks.active')
750 b = ui.label(repo._activebookmark, 'bookmarks.active')
751 ui.status(_("updating bookmark %s\n") % b)
751 ui.status(_("updating bookmark %s\n") % b)
752 else:
752 else:
753 # this can happen with a non-linear update
753 # this can happen with a non-linear update
754 b = ui.label(repo._activebookmark, 'bookmarks')
754 b = ui.label(repo._activebookmark, 'bookmarks')
755 ui.status(_("(leaving bookmark %s)\n") % b)
755 ui.status(_("(leaving bookmark %s)\n") % b)
756 bookmarks.deactivate(repo)
756 bookmarks.deactivate(repo)
757 elif brev in repo._bookmarks:
757 elif brev in repo._bookmarks:
758 if brev != repo._activebookmark:
758 if brev != repo._activebookmark:
759 b = ui.label(brev, 'bookmarks.active')
759 b = ui.label(brev, 'bookmarks.active')
760 ui.status(_("(activating bookmark %s)\n") % b)
760 ui.status(_("(activating bookmark %s)\n") % b)
761 bookmarks.activate(repo, brev)
761 bookmarks.activate(repo, brev)
762 elif brev:
762 elif brev:
763 if repo._activebookmark:
763 if repo._activebookmark:
764 b = ui.label(repo._activebookmark, 'bookmarks')
764 b = ui.label(repo._activebookmark, 'bookmarks')
765 ui.status(_("(leaving bookmark %s)\n") % b)
765 ui.status(_("(leaving bookmark %s)\n") % b)
766 bookmarks.deactivate(repo)
766 bookmarks.deactivate(repo)
767
767
768 if warndest:
768 if warndest:
769 destutil.statusotherdests(ui, repo)
769 destutil.statusotherdests(ui, repo)
770
770
771 return ret
771 return ret
772
772
773 def merge(repo, node, force=None, remind=True, mergeforce=False, labels=None):
773 def merge(repo, node, force=None, remind=True, mergeforce=False, labels=None):
774 """Branch merge with node, resolving changes. Return true if any
774 """Branch merge with node, resolving changes. Return true if any
775 unresolved conflicts."""
775 unresolved conflicts."""
776 stats = mergemod.update(repo, node, True, force, mergeforce=mergeforce,
776 stats = mergemod.update(repo, node, True, force, mergeforce=mergeforce,
777 labels=labels)
777 labels=labels)
778 _showstats(repo, stats)
778 _showstats(repo, stats)
779 if stats[3]:
779 if stats[3]:
780 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
780 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
781 "or 'hg update -C .' to abandon\n"))
781 "or 'hg update -C .' to abandon\n"))
782 elif remind:
782 elif remind:
783 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
783 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
784 return stats[3] > 0
784 return stats[3] > 0
785
785
786 def _incoming(displaychlist, subreporecurse, ui, repo, source,
786 def _incoming(displaychlist, subreporecurse, ui, repo, source,
787 opts, buffered=False):
787 opts, buffered=False):
788 """
788 """
789 Helper for incoming / gincoming.
789 Helper for incoming / gincoming.
790 displaychlist gets called with
790 displaychlist gets called with
791 (remoterepo, incomingchangesetlist, displayer) parameters,
791 (remoterepo, incomingchangesetlist, displayer) parameters,
792 and is supposed to contain only code that can't be unified.
792 and is supposed to contain only code that can't be unified.
793 """
793 """
794 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
794 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
795 other = peer(repo, opts, source)
795 other = peer(repo, opts, source)
796 ui.status(_('comparing with %s\n') % util.hidepassword(source))
796 ui.status(_('comparing with %s\n') % util.hidepassword(source))
797 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
797 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
798
798
799 if revs:
799 if revs:
800 revs = [other.lookup(rev) for rev in revs]
800 revs = [other.lookup(rev) for rev in revs]
801 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
801 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
802 revs, opts["bundle"], opts["force"])
802 revs, opts["bundle"], opts["force"])
803 try:
803 try:
804 if not chlist:
804 if not chlist:
805 ui.status(_("no changes found\n"))
805 ui.status(_("no changes found\n"))
806 return subreporecurse()
806 return subreporecurse()
807 ui.pager('incoming')
807 ui.pager('incoming')
808 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
808 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
809 displaychlist(other, chlist, displayer)
809 displaychlist(other, chlist, displayer)
810 displayer.close()
810 displayer.close()
811 finally:
811 finally:
812 cleanupfn()
812 cleanupfn()
813 subreporecurse()
813 subreporecurse()
814 return 0 # exit code is zero since we found incoming changes
814 return 0 # exit code is zero since we found incoming changes
815
815
816 def incoming(ui, repo, source, opts):
816 def incoming(ui, repo, source, opts):
817 def subreporecurse():
817 def subreporecurse():
818 ret = 1
818 ret = 1
819 if opts.get('subrepos'):
819 if opts.get('subrepos'):
820 ctx = repo[None]
820 ctx = repo[None]
821 for subpath in sorted(ctx.substate):
821 for subpath in sorted(ctx.substate):
822 sub = ctx.sub(subpath)
822 sub = ctx.sub(subpath)
823 ret = min(ret, sub.incoming(ui, source, opts))
823 ret = min(ret, sub.incoming(ui, source, opts))
824 return ret
824 return ret
825
825
826 def display(other, chlist, displayer):
826 def display(other, chlist, displayer):
827 limit = cmdutil.loglimit(opts)
827 limit = cmdutil.loglimit(opts)
828 if opts.get('newest_first'):
828 if opts.get('newest_first'):
829 chlist.reverse()
829 chlist.reverse()
830 count = 0
830 count = 0
831 for n in chlist:
831 for n in chlist:
832 if limit is not None and count >= limit:
832 if limit is not None and count >= limit:
833 break
833 break
834 parents = [p for p in other.changelog.parents(n) if p != nullid]
834 parents = [p for p in other.changelog.parents(n) if p != nullid]
835 if opts.get('no_merges') and len(parents) == 2:
835 if opts.get('no_merges') and len(parents) == 2:
836 continue
836 continue
837 count += 1
837 count += 1
838 displayer.show(other[n])
838 displayer.show(other[n])
839 return _incoming(display, subreporecurse, ui, repo, source, opts)
839 return _incoming(display, subreporecurse, ui, repo, source, opts)
840
840
841 def _outgoing(ui, repo, dest, opts):
841 def _outgoing(ui, repo, dest, opts):
842 dest = ui.expandpath(dest or 'default-push', dest or 'default')
842 dest = ui.expandpath(dest or 'default-push', dest or 'default')
843 dest, branches = parseurl(dest, opts.get('branch'))
843 dest, branches = parseurl(dest, opts.get('branch'))
844 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
844 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
845 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
845 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
846 if revs:
846 if revs:
847 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
847 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
848
848
849 other = peer(repo, opts, dest)
849 other = peer(repo, opts, dest)
850 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
850 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
851 force=opts.get('force'))
851 force=opts.get('force'))
852 o = outgoing.missing
852 o = outgoing.missing
853 if not o:
853 if not o:
854 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
854 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
855 return o, other
855 return o, other
856
856
857 def outgoing(ui, repo, dest, opts):
857 def outgoing(ui, repo, dest, opts):
858 def recurse():
858 def recurse():
859 ret = 1
859 ret = 1
860 if opts.get('subrepos'):
860 if opts.get('subrepos'):
861 ctx = repo[None]
861 ctx = repo[None]
862 for subpath in sorted(ctx.substate):
862 for subpath in sorted(ctx.substate):
863 sub = ctx.sub(subpath)
863 sub = ctx.sub(subpath)
864 ret = min(ret, sub.outgoing(ui, dest, opts))
864 ret = min(ret, sub.outgoing(ui, dest, opts))
865 return ret
865 return ret
866
866
867 limit = cmdutil.loglimit(opts)
867 limit = cmdutil.loglimit(opts)
868 o, other = _outgoing(ui, repo, dest, opts)
868 o, other = _outgoing(ui, repo, dest, opts)
869 if not o:
869 if not o:
870 cmdutil.outgoinghooks(ui, repo, other, opts, o)
870 cmdutil.outgoinghooks(ui, repo, other, opts, o)
871 return recurse()
871 return recurse()
872
872
873 if opts.get('newest_first'):
873 if opts.get('newest_first'):
874 o.reverse()
874 o.reverse()
875 ui.pager('outgoing')
875 displayer = cmdutil.show_changeset(ui, repo, opts)
876 displayer = cmdutil.show_changeset(ui, repo, opts)
876 count = 0
877 count = 0
877 for n in o:
878 for n in o:
878 if limit is not None and count >= limit:
879 if limit is not None and count >= limit:
879 break
880 break
880 parents = [p for p in repo.changelog.parents(n) if p != nullid]
881 parents = [p for p in repo.changelog.parents(n) if p != nullid]
881 if opts.get('no_merges') and len(parents) == 2:
882 if opts.get('no_merges') and len(parents) == 2:
882 continue
883 continue
883 count += 1
884 count += 1
884 displayer.show(repo[n])
885 displayer.show(repo[n])
885 displayer.close()
886 displayer.close()
886 cmdutil.outgoinghooks(ui, repo, other, opts, o)
887 cmdutil.outgoinghooks(ui, repo, other, opts, o)
887 recurse()
888 recurse()
888 return 0 # exit code is zero since we found outgoing changes
889 return 0 # exit code is zero since we found outgoing changes
889
890
890 def verify(repo):
891 def verify(repo):
891 """verify the consistency of a repository"""
892 """verify the consistency of a repository"""
892 ret = verifymod.verify(repo)
893 ret = verifymod.verify(repo)
893
894
894 # Broken subrepo references in hidden csets don't seem worth worrying about,
895 # Broken subrepo references in hidden csets don't seem worth worrying about,
895 # since they can't be pushed/pulled, and --hidden can be used if they are a
896 # since they can't be pushed/pulled, and --hidden can be used if they are a
896 # concern.
897 # concern.
897
898
898 # pathto() is needed for -R case
899 # pathto() is needed for -R case
899 revs = repo.revs("filelog(%s)",
900 revs = repo.revs("filelog(%s)",
900 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
901 util.pathto(repo.root, repo.getcwd(), '.hgsubstate'))
901
902
902 if revs:
903 if revs:
903 repo.ui.status(_('checking subrepo links\n'))
904 repo.ui.status(_('checking subrepo links\n'))
904 for rev in revs:
905 for rev in revs:
905 ctx = repo[rev]
906 ctx = repo[rev]
906 try:
907 try:
907 for subpath in ctx.substate:
908 for subpath in ctx.substate:
908 try:
909 try:
909 ret = (ctx.sub(subpath, allowcreate=False).verify()
910 ret = (ctx.sub(subpath, allowcreate=False).verify()
910 or ret)
911 or ret)
911 except error.RepoError as e:
912 except error.RepoError as e:
912 repo.ui.warn(('%s: %s\n') % (rev, e))
913 repo.ui.warn(('%s: %s\n') % (rev, e))
913 except Exception:
914 except Exception:
914 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
915 repo.ui.warn(_('.hgsubstate is corrupt in revision %s\n') %
915 node.short(ctx.node()))
916 node.short(ctx.node()))
916
917
917 return ret
918 return ret
918
919
919 def remoteui(src, opts):
920 def remoteui(src, opts):
920 'build a remote ui from ui or repo and opts'
921 'build a remote ui from ui or repo and opts'
921 if util.safehasattr(src, 'baseui'): # looks like a repository
922 if util.safehasattr(src, 'baseui'): # looks like a repository
922 dst = src.baseui.copy() # drop repo-specific config
923 dst = src.baseui.copy() # drop repo-specific config
923 src = src.ui # copy target options from repo
924 src = src.ui # copy target options from repo
924 else: # assume it's a global ui object
925 else: # assume it's a global ui object
925 dst = src.copy() # keep all global options
926 dst = src.copy() # keep all global options
926
927
927 # copy ssh-specific options
928 # copy ssh-specific options
928 for o in 'ssh', 'remotecmd':
929 for o in 'ssh', 'remotecmd':
929 v = opts.get(o) or src.config('ui', o)
930 v = opts.get(o) or src.config('ui', o)
930 if v:
931 if v:
931 dst.setconfig("ui", o, v, 'copied')
932 dst.setconfig("ui", o, v, 'copied')
932
933
933 # copy bundle-specific options
934 # copy bundle-specific options
934 r = src.config('bundle', 'mainreporoot')
935 r = src.config('bundle', 'mainreporoot')
935 if r:
936 if r:
936 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
937 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
937
938
938 # copy selected local settings to the remote ui
939 # copy selected local settings to the remote ui
939 for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
940 for sect in ('auth', 'hostfingerprints', 'hostsecurity', 'http_proxy'):
940 for key, val in src.configitems(sect):
941 for key, val in src.configitems(sect):
941 dst.setconfig(sect, key, val, 'copied')
942 dst.setconfig(sect, key, val, 'copied')
942 v = src.config('web', 'cacerts')
943 v = src.config('web', 'cacerts')
943 if v:
944 if v:
944 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
945 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
945
946
946 return dst
947 return dst
947
948
948 # Files of interest
949 # Files of interest
949 # Used to check if the repository has changed looking at mtime and size of
950 # Used to check if the repository has changed looking at mtime and size of
950 # these files.
951 # these files.
951 foi = [('spath', '00changelog.i'),
952 foi = [('spath', '00changelog.i'),
952 ('spath', 'phaseroots'), # ! phase can change content at the same size
953 ('spath', 'phaseroots'), # ! phase can change content at the same size
953 ('spath', 'obsstore'),
954 ('spath', 'obsstore'),
954 ('path', 'bookmarks'), # ! bookmark can change content at the same size
955 ('path', 'bookmarks'), # ! bookmark can change content at the same size
955 ]
956 ]
956
957
957 class cachedlocalrepo(object):
958 class cachedlocalrepo(object):
958 """Holds a localrepository that can be cached and reused."""
959 """Holds a localrepository that can be cached and reused."""
959
960
960 def __init__(self, repo):
961 def __init__(self, repo):
961 """Create a new cached repo from an existing repo.
962 """Create a new cached repo from an existing repo.
962
963
963 We assume the passed in repo was recently created. If the
964 We assume the passed in repo was recently created. If the
964 repo has changed between when it was created and when it was
965 repo has changed between when it was created and when it was
965 turned into a cache, it may not refresh properly.
966 turned into a cache, it may not refresh properly.
966 """
967 """
967 assert isinstance(repo, localrepo.localrepository)
968 assert isinstance(repo, localrepo.localrepository)
968 self._repo = repo
969 self._repo = repo
969 self._state, self.mtime = self._repostate()
970 self._state, self.mtime = self._repostate()
970 self._filtername = repo.filtername
971 self._filtername = repo.filtername
971
972
972 def fetch(self):
973 def fetch(self):
973 """Refresh (if necessary) and return a repository.
974 """Refresh (if necessary) and return a repository.
974
975
975 If the cached instance is out of date, it will be recreated
976 If the cached instance is out of date, it will be recreated
976 automatically and returned.
977 automatically and returned.
977
978
978 Returns a tuple of the repo and a boolean indicating whether a new
979 Returns a tuple of the repo and a boolean indicating whether a new
979 repo instance was created.
980 repo instance was created.
980 """
981 """
981 # We compare the mtimes and sizes of some well-known files to
982 # We compare the mtimes and sizes of some well-known files to
982 # determine if the repo changed. This is not precise, as mtimes
983 # determine if the repo changed. This is not precise, as mtimes
983 # are susceptible to clock skew and imprecise filesystems and
984 # are susceptible to clock skew and imprecise filesystems and
984 # file content can change while maintaining the same size.
985 # file content can change while maintaining the same size.
985
986
986 state, mtime = self._repostate()
987 state, mtime = self._repostate()
987 if state == self._state:
988 if state == self._state:
988 return self._repo, False
989 return self._repo, False
989
990
990 repo = repository(self._repo.baseui, self._repo.url())
991 repo = repository(self._repo.baseui, self._repo.url())
991 if self._filtername:
992 if self._filtername:
992 self._repo = repo.filtered(self._filtername)
993 self._repo = repo.filtered(self._filtername)
993 else:
994 else:
994 self._repo = repo.unfiltered()
995 self._repo = repo.unfiltered()
995 self._state = state
996 self._state = state
996 self.mtime = mtime
997 self.mtime = mtime
997
998
998 return self._repo, True
999 return self._repo, True
999
1000
1000 def _repostate(self):
1001 def _repostate(self):
1001 state = []
1002 state = []
1002 maxmtime = -1
1003 maxmtime = -1
1003 for attr, fname in foi:
1004 for attr, fname in foi:
1004 prefix = getattr(self._repo, attr)
1005 prefix = getattr(self._repo, attr)
1005 p = os.path.join(prefix, fname)
1006 p = os.path.join(prefix, fname)
1006 try:
1007 try:
1007 st = os.stat(p)
1008 st = os.stat(p)
1008 except OSError:
1009 except OSError:
1009 st = os.stat(prefix)
1010 st = os.stat(prefix)
1010 state.append((st.st_mtime, st.st_size))
1011 state.append((st.st_mtime, st.st_size))
1011 maxmtime = max(maxmtime, st.st_mtime)
1012 maxmtime = max(maxmtime, st.st_mtime)
1012
1013
1013 return tuple(state), maxmtime
1014 return tuple(state), maxmtime
1014
1015
1015 def copy(self):
1016 def copy(self):
1016 """Obtain a copy of this class instance.
1017 """Obtain a copy of this class instance.
1017
1018
1018 A new localrepository instance is obtained. The new instance should be
1019 A new localrepository instance is obtained. The new instance should be
1019 completely independent of the original.
1020 completely independent of the original.
1020 """
1021 """
1021 repo = repository(self._repo.baseui, self._repo.origroot)
1022 repo = repository(self._repo.baseui, self._repo.origroot)
1022 if self._filtername:
1023 if self._filtername:
1023 repo = repo.filtered(self._filtername)
1024 repo = repo.filtered(self._filtername)
1024 else:
1025 else:
1025 repo = repo.unfiltered()
1026 repo = repo.unfiltered()
1026 c = cachedlocalrepo(repo)
1027 c = cachedlocalrepo(repo)
1027 c._state = self._state
1028 c._state = self._state
1028 c.mtime = self.mtime
1029 c.mtime = self.mtime
1029 return c
1030 return c
General Comments 0
You need to be logged in to leave comments. Login now