##// END OF EJS Templates
paths: use single loop for both search=None|pattern cases...
Yuya Nishihara -
r27726:7e9dc8bb default
parent child Browse files
Show More
@@ -1,7033 +1,7038 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 node import hex, bin, nullhex, nullid, nullrev, short
8 from node import hex, bin, nullhex, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb
16 import sshserver, hgweb
17 import extensions
17 import extensions
18 import merge as mergemod
18 import merge as mergemod
19 import minirst, revset, fileset
19 import minirst, revset, fileset
20 import dagparser, context, simplemerge, graphmod, copies
20 import dagparser, context, simplemerge, graphmod, copies
21 import random, operator
21 import random, operator
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
22 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
23 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import ui as uimod
24 import ui as uimod
25 import streamclone
25 import streamclone
26 import commandserver
26 import commandserver
27
27
28 table = {}
28 table = {}
29
29
30 command = cmdutil.command(table)
30 command = cmdutil.command(table)
31
31
32 # Space delimited list of commands that don't require local repositories.
32 # Space delimited list of commands that don't require local repositories.
33 # This should be populated by passing norepo=True into the @command decorator.
33 # This should be populated by passing norepo=True into the @command decorator.
34 norepo = ''
34 norepo = ''
35 # Space delimited list of commands that optionally require local repositories.
35 # Space delimited list of commands that optionally require local repositories.
36 # This should be populated by passing optionalrepo=True into the @command
36 # This should be populated by passing optionalrepo=True into the @command
37 # decorator.
37 # decorator.
38 optionalrepo = ''
38 optionalrepo = ''
39 # Space delimited list of commands that will examine arguments looking for
39 # Space delimited list of commands that will examine arguments looking for
40 # a repository. This should be populated by passing inferrepo=True into the
40 # a repository. This should be populated by passing inferrepo=True into the
41 # @command decorator.
41 # @command decorator.
42 inferrepo = ''
42 inferrepo = ''
43
43
44 # label constants
44 # label constants
45 # until 3.5, bookmarks.current was the advertised name, not
45 # until 3.5, bookmarks.current was the advertised name, not
46 # bookmarks.active, so we must use both to avoid breaking old
46 # bookmarks.active, so we must use both to avoid breaking old
47 # custom styles
47 # custom styles
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
49
49
50 # common command options
50 # common command options
51
51
52 globalopts = [
52 globalopts = [
53 ('R', 'repository', '',
53 ('R', 'repository', '',
54 _('repository root directory or name of overlay bundle file'),
54 _('repository root directory or name of overlay bundle file'),
55 _('REPO')),
55 _('REPO')),
56 ('', 'cwd', '',
56 ('', 'cwd', '',
57 _('change working directory'), _('DIR')),
57 _('change working directory'), _('DIR')),
58 ('y', 'noninteractive', None,
58 ('y', 'noninteractive', None,
59 _('do not prompt, automatically pick the first choice for all prompts')),
59 _('do not prompt, automatically pick the first choice for all prompts')),
60 ('q', 'quiet', None, _('suppress output')),
60 ('q', 'quiet', None, _('suppress output')),
61 ('v', 'verbose', None, _('enable additional output')),
61 ('v', 'verbose', None, _('enable additional output')),
62 ('', 'config', [],
62 ('', 'config', [],
63 _('set/override config option (use \'section.name=value\')'),
63 _('set/override config option (use \'section.name=value\')'),
64 _('CONFIG')),
64 _('CONFIG')),
65 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debug', None, _('enable debugging output')),
66 ('', 'debugger', None, _('start debugger')),
66 ('', 'debugger', None, _('start debugger')),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
68 _('ENCODE')),
68 _('ENCODE')),
69 ('', 'encodingmode', encoding.encodingmode,
69 ('', 'encodingmode', encoding.encodingmode,
70 _('set the charset encoding mode'), _('MODE')),
70 _('set the charset encoding mode'), _('MODE')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
72 ('', 'time', None, _('time how long the command takes')),
72 ('', 'time', None, _('time how long the command takes')),
73 ('', 'profile', None, _('print command execution profile')),
73 ('', 'profile', None, _('print command execution profile')),
74 ('', 'version', None, _('output version information and exit')),
74 ('', 'version', None, _('output version information and exit')),
75 ('h', 'help', None, _('display help and exit')),
75 ('h', 'help', None, _('display help and exit')),
76 ('', 'hidden', False, _('consider hidden changesets')),
76 ('', 'hidden', False, _('consider hidden changesets')),
77 ]
77 ]
78
78
79 dryrunopts = [('n', 'dry-run', None,
79 dryrunopts = [('n', 'dry-run', None,
80 _('do not perform actions, just print output'))]
80 _('do not perform actions, just print output'))]
81
81
82 remoteopts = [
82 remoteopts = [
83 ('e', 'ssh', '',
83 ('e', 'ssh', '',
84 _('specify ssh command to use'), _('CMD')),
84 _('specify ssh command to use'), _('CMD')),
85 ('', 'remotecmd', '',
85 ('', 'remotecmd', '',
86 _('specify hg command to run on the remote side'), _('CMD')),
86 _('specify hg command to run on the remote side'), _('CMD')),
87 ('', 'insecure', None,
87 ('', 'insecure', None,
88 _('do not verify server certificate (ignoring web.cacerts config)')),
88 _('do not verify server certificate (ignoring web.cacerts config)')),
89 ]
89 ]
90
90
91 walkopts = [
91 walkopts = [
92 ('I', 'include', [],
92 ('I', 'include', [],
93 _('include names matching the given patterns'), _('PATTERN')),
93 _('include names matching the given patterns'), _('PATTERN')),
94 ('X', 'exclude', [],
94 ('X', 'exclude', [],
95 _('exclude names matching the given patterns'), _('PATTERN')),
95 _('exclude names matching the given patterns'), _('PATTERN')),
96 ]
96 ]
97
97
98 commitopts = [
98 commitopts = [
99 ('m', 'message', '',
99 ('m', 'message', '',
100 _('use text as commit message'), _('TEXT')),
100 _('use text as commit message'), _('TEXT')),
101 ('l', 'logfile', '',
101 ('l', 'logfile', '',
102 _('read commit message from file'), _('FILE')),
102 _('read commit message from file'), _('FILE')),
103 ]
103 ]
104
104
105 commitopts2 = [
105 commitopts2 = [
106 ('d', 'date', '',
106 ('d', 'date', '',
107 _('record the specified date as commit date'), _('DATE')),
107 _('record the specified date as commit date'), _('DATE')),
108 ('u', 'user', '',
108 ('u', 'user', '',
109 _('record the specified user as committer'), _('USER')),
109 _('record the specified user as committer'), _('USER')),
110 ]
110 ]
111
111
112 # hidden for now
112 # hidden for now
113 formatteropts = [
113 formatteropts = [
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 templateopts = [
118 templateopts = [
119 ('', 'style', '',
119 ('', 'style', '',
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
121 ('T', 'template', '',
121 ('T', 'template', '',
122 _('display with template'), _('TEMPLATE')),
122 _('display with template'), _('TEMPLATE')),
123 ]
123 ]
124
124
125 logopts = [
125 logopts = [
126 ('p', 'patch', None, _('show patch')),
126 ('p', 'patch', None, _('show patch')),
127 ('g', 'git', None, _('use git extended diff format')),
127 ('g', 'git', None, _('use git extended diff format')),
128 ('l', 'limit', '',
128 ('l', 'limit', '',
129 _('limit number of changes displayed'), _('NUM')),
129 _('limit number of changes displayed'), _('NUM')),
130 ('M', 'no-merges', None, _('do not show merges')),
130 ('M', 'no-merges', None, _('do not show merges')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
132 ('G', 'graph', None, _("show the revision DAG")),
132 ('G', 'graph', None, _("show the revision DAG")),
133 ] + templateopts
133 ] + templateopts
134
134
135 diffopts = [
135 diffopts = [
136 ('a', 'text', None, _('treat all files as text')),
136 ('a', 'text', None, _('treat all files as text')),
137 ('g', 'git', None, _('use git extended diff format')),
137 ('g', 'git', None, _('use git extended diff format')),
138 ('', 'nodates', None, _('omit dates from diff headers'))
138 ('', 'nodates', None, _('omit dates from diff headers'))
139 ]
139 ]
140
140
141 diffwsopts = [
141 diffwsopts = [
142 ('w', 'ignore-all-space', None,
142 ('w', 'ignore-all-space', None,
143 _('ignore white space when comparing lines')),
143 _('ignore white space when comparing lines')),
144 ('b', 'ignore-space-change', None,
144 ('b', 'ignore-space-change', None,
145 _('ignore changes in the amount of white space')),
145 _('ignore changes in the amount of white space')),
146 ('B', 'ignore-blank-lines', None,
146 ('B', 'ignore-blank-lines', None,
147 _('ignore changes whose lines are all blank')),
147 _('ignore changes whose lines are all blank')),
148 ]
148 ]
149
149
150 diffopts2 = [
150 diffopts2 = [
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
152 ('p', 'show-function', None, _('show which function each change is in')),
152 ('p', 'show-function', None, _('show which function each change is in')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
154 ] + diffwsopts + [
154 ] + diffwsopts + [
155 ('U', 'unified', '',
155 ('U', 'unified', '',
156 _('number of lines of context to show'), _('NUM')),
156 _('number of lines of context to show'), _('NUM')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
159 ]
159 ]
160
160
161 mergetoolopts = [
161 mergetoolopts = [
162 ('t', 'tool', '', _('specify merge tool')),
162 ('t', 'tool', '', _('specify merge tool')),
163 ]
163 ]
164
164
165 similarityopts = [
165 similarityopts = [
166 ('s', 'similarity', '',
166 ('s', 'similarity', '',
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
168 ]
168 ]
169
169
170 subrepoopts = [
170 subrepoopts = [
171 ('S', 'subrepos', None,
171 ('S', 'subrepos', None,
172 _('recurse into subrepositories'))
172 _('recurse into subrepositories'))
173 ]
173 ]
174
174
175 debugrevlogopts = [
175 debugrevlogopts = [
176 ('c', 'changelog', False, _('open changelog')),
176 ('c', 'changelog', False, _('open changelog')),
177 ('m', 'manifest', False, _('open manifest')),
177 ('m', 'manifest', False, _('open manifest')),
178 ('', 'dir', False, _('open directory manifest')),
178 ('', 'dir', False, _('open directory manifest')),
179 ]
179 ]
180
180
181 # Commands start here, listed alphabetically
181 # Commands start here, listed alphabetically
182
182
183 @command('^add',
183 @command('^add',
184 walkopts + subrepoopts + dryrunopts,
184 walkopts + subrepoopts + dryrunopts,
185 _('[OPTION]... [FILE]...'),
185 _('[OPTION]... [FILE]...'),
186 inferrepo=True)
186 inferrepo=True)
187 def add(ui, repo, *pats, **opts):
187 def add(ui, repo, *pats, **opts):
188 """add the specified files on the next commit
188 """add the specified files on the next commit
189
189
190 Schedule files to be version controlled and added to the
190 Schedule files to be version controlled and added to the
191 repository.
191 repository.
192
192
193 The files will be added to the repository at the next commit. To
193 The files will be added to the repository at the next commit. To
194 undo an add before that, see :hg:`forget`.
194 undo an add before that, see :hg:`forget`.
195
195
196 If no names are given, add all files to the repository (except
196 If no names are given, add all files to the repository (except
197 files matching ``.hgignore``).
197 files matching ``.hgignore``).
198
198
199 .. container:: verbose
199 .. container:: verbose
200
200
201 Examples:
201 Examples:
202
202
203 - New (unknown) files are added
203 - New (unknown) files are added
204 automatically by :hg:`add`::
204 automatically by :hg:`add`::
205
205
206 $ ls
206 $ ls
207 foo.c
207 foo.c
208 $ hg status
208 $ hg status
209 ? foo.c
209 ? foo.c
210 $ hg add
210 $ hg add
211 adding foo.c
211 adding foo.c
212 $ hg status
212 $ hg status
213 A foo.c
213 A foo.c
214
214
215 - Specific files to be added can be specified::
215 - Specific files to be added can be specified::
216
216
217 $ ls
217 $ ls
218 bar.c foo.c
218 bar.c foo.c
219 $ hg status
219 $ hg status
220 ? bar.c
220 ? bar.c
221 ? foo.c
221 ? foo.c
222 $ hg add bar.c
222 $ hg add bar.c
223 $ hg status
223 $ hg status
224 A bar.c
224 A bar.c
225 ? foo.c
225 ? foo.c
226
226
227 Returns 0 if all files are successfully added.
227 Returns 0 if all files are successfully added.
228 """
228 """
229
229
230 m = scmutil.match(repo[None], pats, opts)
230 m = scmutil.match(repo[None], pats, opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
231 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
232 return rejected and 1 or 0
232 return rejected and 1 or 0
233
233
234 @command('addremove',
234 @command('addremove',
235 similarityopts + subrepoopts + walkopts + dryrunopts,
235 similarityopts + subrepoopts + walkopts + dryrunopts,
236 _('[OPTION]... [FILE]...'),
236 _('[OPTION]... [FILE]...'),
237 inferrepo=True)
237 inferrepo=True)
238 def addremove(ui, repo, *pats, **opts):
238 def addremove(ui, repo, *pats, **opts):
239 """add all new files, delete all missing files
239 """add all new files, delete all missing files
240
240
241 Add all new files and remove all missing files from the
241 Add all new files and remove all missing files from the
242 repository.
242 repository.
243
243
244 Unless names are given, new files are ignored if they match any of
244 Unless names are given, new files are ignored if they match any of
245 the patterns in ``.hgignore``. As with add, these changes take
245 the patterns in ``.hgignore``. As with add, these changes take
246 effect at the next commit.
246 effect at the next commit.
247
247
248 Use the -s/--similarity option to detect renamed files. This
248 Use the -s/--similarity option to detect renamed files. This
249 option takes a percentage between 0 (disabled) and 100 (files must
249 option takes a percentage between 0 (disabled) and 100 (files must
250 be identical) as its parameter. With a parameter greater than 0,
250 be identical) as its parameter. With a parameter greater than 0,
251 this compares every removed file with every added file and records
251 this compares every removed file with every added file and records
252 those similar enough as renames. Detecting renamed files this way
252 those similar enough as renames. Detecting renamed files this way
253 can be expensive. After using this option, :hg:`status -C` can be
253 can be expensive. After using this option, :hg:`status -C` can be
254 used to check which files were identified as moved or renamed. If
254 used to check which files were identified as moved or renamed. If
255 not specified, -s/--similarity defaults to 100 and only renames of
255 not specified, -s/--similarity defaults to 100 and only renames of
256 identical files are detected.
256 identical files are detected.
257
257
258 .. container:: verbose
258 .. container:: verbose
259
259
260 Examples:
260 Examples:
261
261
262 - A number of files (bar.c and foo.c) are new,
262 - A number of files (bar.c and foo.c) are new,
263 while foobar.c has been removed (without using :hg:`remove`)
263 while foobar.c has been removed (without using :hg:`remove`)
264 from the repository::
264 from the repository::
265
265
266 $ ls
266 $ ls
267 bar.c foo.c
267 bar.c foo.c
268 $ hg status
268 $ hg status
269 ! foobar.c
269 ! foobar.c
270 ? bar.c
270 ? bar.c
271 ? foo.c
271 ? foo.c
272 $ hg addremove
272 $ hg addremove
273 adding bar.c
273 adding bar.c
274 adding foo.c
274 adding foo.c
275 removing foobar.c
275 removing foobar.c
276 $ hg status
276 $ hg status
277 A bar.c
277 A bar.c
278 A foo.c
278 A foo.c
279 R foobar.c
279 R foobar.c
280
280
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
281 - A file foobar.c was moved to foo.c without using :hg:`rename`.
282 Afterwards, it was edited slightly::
282 Afterwards, it was edited slightly::
283
283
284 $ ls
284 $ ls
285 foo.c
285 foo.c
286 $ hg status
286 $ hg status
287 ! foobar.c
287 ! foobar.c
288 ? foo.c
288 ? foo.c
289 $ hg addremove --similarity 90
289 $ hg addremove --similarity 90
290 removing foobar.c
290 removing foobar.c
291 adding foo.c
291 adding foo.c
292 recording removal of foobar.c as rename to foo.c (94% similar)
292 recording removal of foobar.c as rename to foo.c (94% similar)
293 $ hg status -C
293 $ hg status -C
294 A foo.c
294 A foo.c
295 foobar.c
295 foobar.c
296 R foobar.c
296 R foobar.c
297
297
298 Returns 0 if all files are successfully added.
298 Returns 0 if all files are successfully added.
299 """
299 """
300 try:
300 try:
301 sim = float(opts.get('similarity') or 100)
301 sim = float(opts.get('similarity') or 100)
302 except ValueError:
302 except ValueError:
303 raise error.Abort(_('similarity must be a number'))
303 raise error.Abort(_('similarity must be a number'))
304 if sim < 0 or sim > 100:
304 if sim < 0 or sim > 100:
305 raise error.Abort(_('similarity must be between 0 and 100'))
305 raise error.Abort(_('similarity must be between 0 and 100'))
306 matcher = scmutil.match(repo[None], pats, opts)
306 matcher = scmutil.match(repo[None], pats, opts)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
307 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
308
308
309 @command('^annotate|blame',
309 @command('^annotate|blame',
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
310 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
311 ('', 'follow', None,
311 ('', 'follow', None,
312 _('follow copies/renames and list the filename (DEPRECATED)')),
312 _('follow copies/renames and list the filename (DEPRECATED)')),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
313 ('', 'no-follow', None, _("don't follow copies and renames")),
314 ('a', 'text', None, _('treat all files as text')),
314 ('a', 'text', None, _('treat all files as text')),
315 ('u', 'user', None, _('list the author (long with -v)')),
315 ('u', 'user', None, _('list the author (long with -v)')),
316 ('f', 'file', None, _('list the filename')),
316 ('f', 'file', None, _('list the filename')),
317 ('d', 'date', None, _('list the date (short with -q)')),
317 ('d', 'date', None, _('list the date (short with -q)')),
318 ('n', 'number', None, _('list the revision number (default)')),
318 ('n', 'number', None, _('list the revision number (default)')),
319 ('c', 'changeset', None, _('list the changeset')),
319 ('c', 'changeset', None, _('list the changeset')),
320 ('l', 'line-number', None, _('show line number at the first appearance'))
320 ('l', 'line-number', None, _('show line number at the first appearance'))
321 ] + diffwsopts + walkopts + formatteropts,
321 ] + diffwsopts + walkopts + formatteropts,
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
322 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
323 inferrepo=True)
323 inferrepo=True)
324 def annotate(ui, repo, *pats, **opts):
324 def annotate(ui, repo, *pats, **opts):
325 """show changeset information by line for each file
325 """show changeset information by line for each file
326
326
327 List changes in files, showing the revision id responsible for
327 List changes in files, showing the revision id responsible for
328 each line.
328 each line.
329
329
330 This command is useful for discovering when a change was made and
330 This command is useful for discovering when a change was made and
331 by whom.
331 by whom.
332
332
333 If you include --file, --user, or --date, the revision number is
333 If you include --file, --user, or --date, the revision number is
334 suppressed unless you also include --number.
334 suppressed unless you also include --number.
335
335
336 Without the -a/--text option, annotate will avoid processing files
336 Without the -a/--text option, annotate will avoid processing files
337 it detects as binary. With -a, annotate will annotate the file
337 it detects as binary. With -a, annotate will annotate the file
338 anyway, although the results will probably be neither useful
338 anyway, although the results will probably be neither useful
339 nor desirable.
339 nor desirable.
340
340
341 Returns 0 on success.
341 Returns 0 on success.
342 """
342 """
343 if not pats:
343 if not pats:
344 raise error.Abort(_('at least one filename or pattern is required'))
344 raise error.Abort(_('at least one filename or pattern is required'))
345
345
346 if opts.get('follow'):
346 if opts.get('follow'):
347 # --follow is deprecated and now just an alias for -f/--file
347 # --follow is deprecated and now just an alias for -f/--file
348 # to mimic the behavior of Mercurial before version 1.5
348 # to mimic the behavior of Mercurial before version 1.5
349 opts['file'] = True
349 opts['file'] = True
350
350
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
351 ctx = scmutil.revsingle(repo, opts.get('rev'))
352
352
353 fm = ui.formatter('annotate', opts)
353 fm = ui.formatter('annotate', opts)
354 if ui.quiet:
354 if ui.quiet:
355 datefunc = util.shortdate
355 datefunc = util.shortdate
356 else:
356 else:
357 datefunc = util.datestr
357 datefunc = util.datestr
358 if ctx.rev() is None:
358 if ctx.rev() is None:
359 def hexfn(node):
359 def hexfn(node):
360 if node is None:
360 if node is None:
361 return None
361 return None
362 else:
362 else:
363 return fm.hexfunc(node)
363 return fm.hexfunc(node)
364 if opts.get('changeset'):
364 if opts.get('changeset'):
365 # omit "+" suffix which is appended to node hex
365 # omit "+" suffix which is appended to node hex
366 def formatrev(rev):
366 def formatrev(rev):
367 if rev is None:
367 if rev is None:
368 return '%d' % ctx.p1().rev()
368 return '%d' % ctx.p1().rev()
369 else:
369 else:
370 return '%d' % rev
370 return '%d' % rev
371 else:
371 else:
372 def formatrev(rev):
372 def formatrev(rev):
373 if rev is None:
373 if rev is None:
374 return '%d+' % ctx.p1().rev()
374 return '%d+' % ctx.p1().rev()
375 else:
375 else:
376 return '%d ' % rev
376 return '%d ' % rev
377 def formathex(hex):
377 def formathex(hex):
378 if hex is None:
378 if hex is None:
379 return '%s+' % fm.hexfunc(ctx.p1().node())
379 return '%s+' % fm.hexfunc(ctx.p1().node())
380 else:
380 else:
381 return '%s ' % hex
381 return '%s ' % hex
382 else:
382 else:
383 hexfn = fm.hexfunc
383 hexfn = fm.hexfunc
384 formatrev = formathex = str
384 formatrev = formathex = str
385
385
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
386 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
387 ('number', ' ', lambda x: x[0].rev(), formatrev),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
388 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
389 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
390 ('file', ' ', lambda x: x[0].path(), str),
390 ('file', ' ', lambda x: x[0].path(), str),
391 ('line_number', ':', lambda x: x[1], str),
391 ('line_number', ':', lambda x: x[1], str),
392 ]
392 ]
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
393 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
394
394
395 if (not opts.get('user') and not opts.get('changeset')
395 if (not opts.get('user') and not opts.get('changeset')
396 and not opts.get('date') and not opts.get('file')):
396 and not opts.get('date') and not opts.get('file')):
397 opts['number'] = True
397 opts['number'] = True
398
398
399 linenumber = opts.get('line_number') is not None
399 linenumber = opts.get('line_number') is not None
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
400 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
401 raise error.Abort(_('at least one of -n/-c is required for -l'))
402
402
403 if fm:
403 if fm:
404 def makefunc(get, fmt):
404 def makefunc(get, fmt):
405 return get
405 return get
406 else:
406 else:
407 def makefunc(get, fmt):
407 def makefunc(get, fmt):
408 return lambda x: fmt(get(x))
408 return lambda x: fmt(get(x))
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
409 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
410 if opts.get(op)]
410 if opts.get(op)]
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
411 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
412 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
413 if opts.get(op))
413 if opts.get(op))
414
414
415 def bad(x, y):
415 def bad(x, y):
416 raise error.Abort("%s: %s" % (x, y))
416 raise error.Abort("%s: %s" % (x, y))
417
417
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
418 m = scmutil.match(ctx, pats, opts, badfn=bad)
419
419
420 follow = not opts.get('no_follow')
420 follow = not opts.get('no_follow')
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
421 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
422 whitespace=True)
422 whitespace=True)
423 for abs in ctx.walk(m):
423 for abs in ctx.walk(m):
424 fctx = ctx[abs]
424 fctx = ctx[abs]
425 if not opts.get('text') and util.binary(fctx.data()):
425 if not opts.get('text') and util.binary(fctx.data()):
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
426 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
427 continue
427 continue
428
428
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
429 lines = fctx.annotate(follow=follow, linenumber=linenumber,
430 diffopts=diffopts)
430 diffopts=diffopts)
431 formats = []
431 formats = []
432 pieces = []
432 pieces = []
433
433
434 for f, sep in funcmap:
434 for f, sep in funcmap:
435 l = [f(n) for n, dummy in lines]
435 l = [f(n) for n, dummy in lines]
436 if l:
436 if l:
437 if fm:
437 if fm:
438 formats.append(['%s' for x in l])
438 formats.append(['%s' for x in l])
439 else:
439 else:
440 sizes = [encoding.colwidth(x) for x in l]
440 sizes = [encoding.colwidth(x) for x in l]
441 ml = max(sizes)
441 ml = max(sizes)
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
442 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
443 pieces.append(l)
443 pieces.append(l)
444
444
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
445 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
446 fm.startitem()
446 fm.startitem()
447 fm.write(fields, "".join(f), *p)
447 fm.write(fields, "".join(f), *p)
448 fm.write('line', ": %s", l[1])
448 fm.write('line', ": %s", l[1])
449
449
450 if lines and not lines[-1][1].endswith('\n'):
450 if lines and not lines[-1][1].endswith('\n'):
451 fm.plain('\n')
451 fm.plain('\n')
452
452
453 fm.end()
453 fm.end()
454
454
455 @command('archive',
455 @command('archive',
456 [('', 'no-decode', None, _('do not pass files through decoders')),
456 [('', 'no-decode', None, _('do not pass files through decoders')),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
457 ('p', 'prefix', '', _('directory prefix for files in archive'),
458 _('PREFIX')),
458 _('PREFIX')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
459 ('r', 'rev', '', _('revision to distribute'), _('REV')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
460 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
461 ] + subrepoopts + walkopts,
461 ] + subrepoopts + walkopts,
462 _('[OPTION]... DEST'))
462 _('[OPTION]... DEST'))
463 def archive(ui, repo, dest, **opts):
463 def archive(ui, repo, dest, **opts):
464 '''create an unversioned archive of a repository revision
464 '''create an unversioned archive of a repository revision
465
465
466 By default, the revision used is the parent of the working
466 By default, the revision used is the parent of the working
467 directory; use -r/--rev to specify a different revision.
467 directory; use -r/--rev to specify a different revision.
468
468
469 The archive type is automatically detected based on file
469 The archive type is automatically detected based on file
470 extension (to override, use -t/--type).
470 extension (to override, use -t/--type).
471
471
472 .. container:: verbose
472 .. container:: verbose
473
473
474 Examples:
474 Examples:
475
475
476 - create a zip file containing the 1.0 release::
476 - create a zip file containing the 1.0 release::
477
477
478 hg archive -r 1.0 project-1.0.zip
478 hg archive -r 1.0 project-1.0.zip
479
479
480 - create a tarball excluding .hg files::
480 - create a tarball excluding .hg files::
481
481
482 hg archive project.tar.gz -X ".hg*"
482 hg archive project.tar.gz -X ".hg*"
483
483
484 Valid types are:
484 Valid types are:
485
485
486 :``files``: a directory full of files (default)
486 :``files``: a directory full of files (default)
487 :``tar``: tar archive, uncompressed
487 :``tar``: tar archive, uncompressed
488 :``tbz2``: tar archive, compressed using bzip2
488 :``tbz2``: tar archive, compressed using bzip2
489 :``tgz``: tar archive, compressed using gzip
489 :``tgz``: tar archive, compressed using gzip
490 :``uzip``: zip archive, uncompressed
490 :``uzip``: zip archive, uncompressed
491 :``zip``: zip archive, compressed using deflate
491 :``zip``: zip archive, compressed using deflate
492
492
493 The exact name of the destination archive or directory is given
493 The exact name of the destination archive or directory is given
494 using a format string; see :hg:`help export` for details.
494 using a format string; see :hg:`help export` for details.
495
495
496 Each member added to an archive file has a directory prefix
496 Each member added to an archive file has a directory prefix
497 prepended. Use -p/--prefix to specify a format string for the
497 prepended. Use -p/--prefix to specify a format string for the
498 prefix. The default is the basename of the archive, with suffixes
498 prefix. The default is the basename of the archive, with suffixes
499 removed.
499 removed.
500
500
501 Returns 0 on success.
501 Returns 0 on success.
502 '''
502 '''
503
503
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
504 ctx = scmutil.revsingle(repo, opts.get('rev'))
505 if not ctx:
505 if not ctx:
506 raise error.Abort(_('no working directory: please specify a revision'))
506 raise error.Abort(_('no working directory: please specify a revision'))
507 node = ctx.node()
507 node = ctx.node()
508 dest = cmdutil.makefilename(repo, dest, node)
508 dest = cmdutil.makefilename(repo, dest, node)
509 if os.path.realpath(dest) == repo.root:
509 if os.path.realpath(dest) == repo.root:
510 raise error.Abort(_('repository root cannot be destination'))
510 raise error.Abort(_('repository root cannot be destination'))
511
511
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
512 kind = opts.get('type') or archival.guesskind(dest) or 'files'
513 prefix = opts.get('prefix')
513 prefix = opts.get('prefix')
514
514
515 if dest == '-':
515 if dest == '-':
516 if kind == 'files':
516 if kind == 'files':
517 raise error.Abort(_('cannot archive plain files to stdout'))
517 raise error.Abort(_('cannot archive plain files to stdout'))
518 dest = cmdutil.makefileobj(repo, dest)
518 dest = cmdutil.makefileobj(repo, dest)
519 if not prefix:
519 if not prefix:
520 prefix = os.path.basename(repo.root) + '-%h'
520 prefix = os.path.basename(repo.root) + '-%h'
521
521
522 prefix = cmdutil.makefilename(repo, prefix, node)
522 prefix = cmdutil.makefilename(repo, prefix, node)
523 matchfn = scmutil.match(ctx, [], opts)
523 matchfn = scmutil.match(ctx, [], opts)
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
524 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
525 matchfn, prefix, subrepos=opts.get('subrepos'))
525 matchfn, prefix, subrepos=opts.get('subrepos'))
526
526
527 @command('backout',
527 @command('backout',
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
528 [('', 'merge', None, _('merge with old dirstate parent after backout')),
529 ('', 'commit', None, _('commit if no conflicts were encountered')),
529 ('', 'commit', None, _('commit if no conflicts were encountered')),
530 ('', 'parent', '',
530 ('', 'parent', '',
531 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
531 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
532 ('r', 'rev', '', _('revision to backout'), _('REV')),
532 ('r', 'rev', '', _('revision to backout'), _('REV')),
533 ('e', 'edit', False, _('invoke editor on commit messages')),
533 ('e', 'edit', False, _('invoke editor on commit messages')),
534 ] + mergetoolopts + walkopts + commitopts + commitopts2,
534 ] + mergetoolopts + walkopts + commitopts + commitopts2,
535 _('[OPTION]... [-r] REV'))
535 _('[OPTION]... [-r] REV'))
536 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
536 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
537 '''reverse effect of earlier changeset
537 '''reverse effect of earlier changeset
538
538
539 Prepare a new changeset with the effect of REV undone in the
539 Prepare a new changeset with the effect of REV undone in the
540 current working directory.
540 current working directory.
541
541
542 If REV is the parent of the working directory, then this new changeset
542 If REV is the parent of the working directory, then this new changeset
543 is committed automatically. Otherwise, hg needs to merge the
543 is committed automatically. Otherwise, hg needs to merge the
544 changes and the merged result is left uncommitted.
544 changes and the merged result is left uncommitted.
545
545
546 .. note::
546 .. note::
547
547
548 :hg:`backout` cannot be used to fix either an unwanted or
548 :hg:`backout` cannot be used to fix either an unwanted or
549 incorrect merge.
549 incorrect merge.
550
550
551 .. container:: verbose
551 .. container:: verbose
552
552
553 Examples:
553 Examples:
554
554
555 - Reverse the effect of the parent of the working directory.
555 - Reverse the effect of the parent of the working directory.
556 This backout will be committed immediately::
556 This backout will be committed immediately::
557
557
558 hg backout -r .
558 hg backout -r .
559
559
560 - Reverse the effect of previous bad revision 23::
560 - Reverse the effect of previous bad revision 23::
561
561
562 hg backout -r 23
562 hg backout -r 23
563 hg commit -m "Backout revision 23"
563 hg commit -m "Backout revision 23"
564
564
565 - Reverse the effect of previous bad revision 23 and
565 - Reverse the effect of previous bad revision 23 and
566 commit the backout immediately::
566 commit the backout immediately::
567
567
568 hg backout -r 23 --commit
568 hg backout -r 23 --commit
569
569
570 By default, the pending changeset will have one parent,
570 By default, the pending changeset will have one parent,
571 maintaining a linear history. With --merge, the pending
571 maintaining a linear history. With --merge, the pending
572 changeset will instead have two parents: the old parent of the
572 changeset will instead have two parents: the old parent of the
573 working directory and a new child of REV that simply undoes REV.
573 working directory and a new child of REV that simply undoes REV.
574
574
575 Before version 1.7, the behavior without --merge was equivalent
575 Before version 1.7, the behavior without --merge was equivalent
576 to specifying --merge followed by :hg:`update --clean .` to
576 to specifying --merge followed by :hg:`update --clean .` to
577 cancel the merge and leave the child of REV as a head to be
577 cancel the merge and leave the child of REV as a head to be
578 merged separately.
578 merged separately.
579
579
580 See :hg:`help dates` for a list of formats valid for -d/--date.
580 See :hg:`help dates` for a list of formats valid for -d/--date.
581
581
582 See :hg:`help revert` for a way to restore files to the state
582 See :hg:`help revert` for a way to restore files to the state
583 of another revision.
583 of another revision.
584
584
585 Returns 0 on success, 1 if nothing to backout or there are unresolved
585 Returns 0 on success, 1 if nothing to backout or there are unresolved
586 files.
586 files.
587 '''
587 '''
588 wlock = lock = None
588 wlock = lock = None
589 try:
589 try:
590 wlock = repo.wlock()
590 wlock = repo.wlock()
591 lock = repo.lock()
591 lock = repo.lock()
592 return _dobackout(ui, repo, node, rev, commit, **opts)
592 return _dobackout(ui, repo, node, rev, commit, **opts)
593 finally:
593 finally:
594 release(lock, wlock)
594 release(lock, wlock)
595
595
596 def _dobackout(ui, repo, node=None, rev=None, commit=False, **opts):
596 def _dobackout(ui, repo, node=None, rev=None, commit=False, **opts):
597 if rev and node:
597 if rev and node:
598 raise error.Abort(_("please specify just one revision"))
598 raise error.Abort(_("please specify just one revision"))
599
599
600 if not rev:
600 if not rev:
601 rev = node
601 rev = node
602
602
603 if not rev:
603 if not rev:
604 raise error.Abort(_("please specify a revision to backout"))
604 raise error.Abort(_("please specify a revision to backout"))
605
605
606 date = opts.get('date')
606 date = opts.get('date')
607 if date:
607 if date:
608 opts['date'] = util.parsedate(date)
608 opts['date'] = util.parsedate(date)
609
609
610 cmdutil.checkunfinished(repo)
610 cmdutil.checkunfinished(repo)
611 cmdutil.bailifchanged(repo)
611 cmdutil.bailifchanged(repo)
612 node = scmutil.revsingle(repo, rev).node()
612 node = scmutil.revsingle(repo, rev).node()
613
613
614 op1, op2 = repo.dirstate.parents()
614 op1, op2 = repo.dirstate.parents()
615 if not repo.changelog.isancestor(node, op1):
615 if not repo.changelog.isancestor(node, op1):
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
616 raise error.Abort(_('cannot backout change that is not an ancestor'))
617
617
618 p1, p2 = repo.changelog.parents(node)
618 p1, p2 = repo.changelog.parents(node)
619 if p1 == nullid:
619 if p1 == nullid:
620 raise error.Abort(_('cannot backout a change with no parents'))
620 raise error.Abort(_('cannot backout a change with no parents'))
621 if p2 != nullid:
621 if p2 != nullid:
622 if not opts.get('parent'):
622 if not opts.get('parent'):
623 raise error.Abort(_('cannot backout a merge changeset'))
623 raise error.Abort(_('cannot backout a merge changeset'))
624 p = repo.lookup(opts['parent'])
624 p = repo.lookup(opts['parent'])
625 if p not in (p1, p2):
625 if p not in (p1, p2):
626 raise error.Abort(_('%s is not a parent of %s') %
626 raise error.Abort(_('%s is not a parent of %s') %
627 (short(p), short(node)))
627 (short(p), short(node)))
628 parent = p
628 parent = p
629 else:
629 else:
630 if opts.get('parent'):
630 if opts.get('parent'):
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
631 raise error.Abort(_('cannot use --parent on non-merge changeset'))
632 parent = p1
632 parent = p1
633
633
634 # the backout should appear on the same branch
634 # the backout should appear on the same branch
635 branch = repo.dirstate.branch()
635 branch = repo.dirstate.branch()
636 bheads = repo.branchheads(branch)
636 bheads = repo.branchheads(branch)
637 rctx = scmutil.revsingle(repo, hex(parent))
637 rctx = scmutil.revsingle(repo, hex(parent))
638 if not opts.get('merge') and op1 != node:
638 if not opts.get('merge') and op1 != node:
639 dsguard = cmdutil.dirstateguard(repo, 'backout')
639 dsguard = cmdutil.dirstateguard(repo, 'backout')
640 try:
640 try:
641 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
641 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
642 'backout')
642 'backout')
643 stats = mergemod.update(repo, parent, True, True, node, False)
643 stats = mergemod.update(repo, parent, True, True, node, False)
644 repo.setparents(op1, op2)
644 repo.setparents(op1, op2)
645 dsguard.close()
645 dsguard.close()
646 hg._showstats(repo, stats)
646 hg._showstats(repo, stats)
647 if stats[3]:
647 if stats[3]:
648 repo.ui.status(_("use 'hg resolve' to retry unresolved "
648 repo.ui.status(_("use 'hg resolve' to retry unresolved "
649 "file merges\n"))
649 "file merges\n"))
650 return 1
650 return 1
651 elif not commit:
651 elif not commit:
652 msg = _("changeset %s backed out, "
652 msg = _("changeset %s backed out, "
653 "don't forget to commit.\n")
653 "don't forget to commit.\n")
654 ui.status(msg % short(node))
654 ui.status(msg % short(node))
655 return 0
655 return 0
656 finally:
656 finally:
657 ui.setconfig('ui', 'forcemerge', '', '')
657 ui.setconfig('ui', 'forcemerge', '', '')
658 lockmod.release(dsguard)
658 lockmod.release(dsguard)
659 else:
659 else:
660 hg.clean(repo, node, show_stats=False)
660 hg.clean(repo, node, show_stats=False)
661 repo.dirstate.setbranch(branch)
661 repo.dirstate.setbranch(branch)
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
662 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
663
663
664
664
665 def commitfunc(ui, repo, message, match, opts):
665 def commitfunc(ui, repo, message, match, opts):
666 editform = 'backout'
666 editform = 'backout'
667 e = cmdutil.getcommiteditor(editform=editform, **opts)
667 e = cmdutil.getcommiteditor(editform=editform, **opts)
668 if not message:
668 if not message:
669 # we don't translate commit messages
669 # we don't translate commit messages
670 message = "Backed out changeset %s" % short(node)
670 message = "Backed out changeset %s" % short(node)
671 e = cmdutil.getcommiteditor(edit=True, editform=editform)
671 e = cmdutil.getcommiteditor(edit=True, editform=editform)
672 return repo.commit(message, opts.get('user'), opts.get('date'),
672 return repo.commit(message, opts.get('user'), opts.get('date'),
673 match, editor=e)
673 match, editor=e)
674 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
674 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
675 if not newnode:
675 if not newnode:
676 ui.status(_("nothing changed\n"))
676 ui.status(_("nothing changed\n"))
677 return 1
677 return 1
678 cmdutil.commitstatus(repo, newnode, branch, bheads)
678 cmdutil.commitstatus(repo, newnode, branch, bheads)
679
679
680 def nice(node):
680 def nice(node):
681 return '%d:%s' % (repo.changelog.rev(node), short(node))
681 return '%d:%s' % (repo.changelog.rev(node), short(node))
682 ui.status(_('changeset %s backs out changeset %s\n') %
682 ui.status(_('changeset %s backs out changeset %s\n') %
683 (nice(repo.changelog.tip()), nice(node)))
683 (nice(repo.changelog.tip()), nice(node)))
684 if opts.get('merge') and op1 != node:
684 if opts.get('merge') and op1 != node:
685 hg.clean(repo, op1, show_stats=False)
685 hg.clean(repo, op1, show_stats=False)
686 ui.status(_('merging with changeset %s\n')
686 ui.status(_('merging with changeset %s\n')
687 % nice(repo.changelog.tip()))
687 % nice(repo.changelog.tip()))
688 try:
688 try:
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
689 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
690 'backout')
690 'backout')
691 return hg.merge(repo, hex(repo.changelog.tip()))
691 return hg.merge(repo, hex(repo.changelog.tip()))
692 finally:
692 finally:
693 ui.setconfig('ui', 'forcemerge', '', '')
693 ui.setconfig('ui', 'forcemerge', '', '')
694 return 0
694 return 0
695
695
696 @command('bisect',
696 @command('bisect',
697 [('r', 'reset', False, _('reset bisect state')),
697 [('r', 'reset', False, _('reset bisect state')),
698 ('g', 'good', False, _('mark changeset good')),
698 ('g', 'good', False, _('mark changeset good')),
699 ('b', 'bad', False, _('mark changeset bad')),
699 ('b', 'bad', False, _('mark changeset bad')),
700 ('s', 'skip', False, _('skip testing changeset')),
700 ('s', 'skip', False, _('skip testing changeset')),
701 ('e', 'extend', False, _('extend the bisect range')),
701 ('e', 'extend', False, _('extend the bisect range')),
702 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
702 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
703 ('U', 'noupdate', False, _('do not update to target'))],
703 ('U', 'noupdate', False, _('do not update to target'))],
704 _("[-gbsr] [-U] [-c CMD] [REV]"))
704 _("[-gbsr] [-U] [-c CMD] [REV]"))
705 def bisect(ui, repo, rev=None, extra=None, command=None,
705 def bisect(ui, repo, rev=None, extra=None, command=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
706 reset=None, good=None, bad=None, skip=None, extend=None,
707 noupdate=None):
707 noupdate=None):
708 """subdivision search of changesets
708 """subdivision search of changesets
709
709
710 This command helps to find changesets which introduce problems. To
710 This command helps to find changesets which introduce problems. To
711 use, mark the earliest changeset you know exhibits the problem as
711 use, mark the earliest changeset you know exhibits the problem as
712 bad, then mark the latest changeset which is free from the problem
712 bad, then mark the latest changeset which is free from the problem
713 as good. Bisect will update your working directory to a revision
713 as good. Bisect will update your working directory to a revision
714 for testing (unless the -U/--noupdate option is specified). Once
714 for testing (unless the -U/--noupdate option is specified). Once
715 you have performed tests, mark the working directory as good or
715 you have performed tests, mark the working directory as good or
716 bad, and bisect will either update to another candidate changeset
716 bad, and bisect will either update to another candidate changeset
717 or announce that it has found the bad revision.
717 or announce that it has found the bad revision.
718
718
719 As a shortcut, you can also use the revision argument to mark a
719 As a shortcut, you can also use the revision argument to mark a
720 revision as good or bad without checking it out first.
720 revision as good or bad without checking it out first.
721
721
722 If you supply a command, it will be used for automatic bisection.
722 If you supply a command, it will be used for automatic bisection.
723 The environment variable HG_NODE will contain the ID of the
723 The environment variable HG_NODE will contain the ID of the
724 changeset being tested. The exit status of the command will be
724 changeset being tested. The exit status of the command will be
725 used to mark revisions as good or bad: status 0 means good, 125
725 used to mark revisions as good or bad: status 0 means good, 125
726 means to skip the revision, 127 (command not found) will abort the
726 means to skip the revision, 127 (command not found) will abort the
727 bisection, and any other non-zero exit status means the revision
727 bisection, and any other non-zero exit status means the revision
728 is bad.
728 is bad.
729
729
730 .. container:: verbose
730 .. container:: verbose
731
731
732 Some examples:
732 Some examples:
733
733
734 - start a bisection with known bad revision 34, and good revision 12::
734 - start a bisection with known bad revision 34, and good revision 12::
735
735
736 hg bisect --bad 34
736 hg bisect --bad 34
737 hg bisect --good 12
737 hg bisect --good 12
738
738
739 - advance the current bisection by marking current revision as good or
739 - advance the current bisection by marking current revision as good or
740 bad::
740 bad::
741
741
742 hg bisect --good
742 hg bisect --good
743 hg bisect --bad
743 hg bisect --bad
744
744
745 - mark the current revision, or a known revision, to be skipped (e.g. if
745 - mark the current revision, or a known revision, to be skipped (e.g. if
746 that revision is not usable because of another issue)::
746 that revision is not usable because of another issue)::
747
747
748 hg bisect --skip
748 hg bisect --skip
749 hg bisect --skip 23
749 hg bisect --skip 23
750
750
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
751 - skip all revisions that do not touch directories ``foo`` or ``bar``::
752
752
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
753 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
754
754
755 - forget the current bisection::
755 - forget the current bisection::
756
756
757 hg bisect --reset
757 hg bisect --reset
758
758
759 - use 'make && make tests' to automatically find the first broken
759 - use 'make && make tests' to automatically find the first broken
760 revision::
760 revision::
761
761
762 hg bisect --reset
762 hg bisect --reset
763 hg bisect --bad 34
763 hg bisect --bad 34
764 hg bisect --good 12
764 hg bisect --good 12
765 hg bisect --command "make && make tests"
765 hg bisect --command "make && make tests"
766
766
767 - see all changesets whose states are already known in the current
767 - see all changesets whose states are already known in the current
768 bisection::
768 bisection::
769
769
770 hg log -r "bisect(pruned)"
770 hg log -r "bisect(pruned)"
771
771
772 - see the changeset currently being bisected (especially useful
772 - see the changeset currently being bisected (especially useful
773 if running with -U/--noupdate)::
773 if running with -U/--noupdate)::
774
774
775 hg log -r "bisect(current)"
775 hg log -r "bisect(current)"
776
776
777 - see all changesets that took part in the current bisection::
777 - see all changesets that took part in the current bisection::
778
778
779 hg log -r "bisect(range)"
779 hg log -r "bisect(range)"
780
780
781 - you can even get a nice graph::
781 - you can even get a nice graph::
782
782
783 hg log --graph -r "bisect(range)"
783 hg log --graph -r "bisect(range)"
784
784
785 See :hg:`help revsets` for more about the `bisect()` keyword.
785 See :hg:`help revsets` for more about the `bisect()` keyword.
786
786
787 Returns 0 on success.
787 Returns 0 on success.
788 """
788 """
789 def extendbisectrange(nodes, good):
789 def extendbisectrange(nodes, good):
790 # bisect is incomplete when it ends on a merge node and
790 # bisect is incomplete when it ends on a merge node and
791 # one of the parent was not checked.
791 # one of the parent was not checked.
792 parents = repo[nodes[0]].parents()
792 parents = repo[nodes[0]].parents()
793 if len(parents) > 1:
793 if len(parents) > 1:
794 if good:
794 if good:
795 side = state['bad']
795 side = state['bad']
796 else:
796 else:
797 side = state['good']
797 side = state['good']
798 num = len(set(i.node() for i in parents) & set(side))
798 num = len(set(i.node() for i in parents) & set(side))
799 if num == 1:
799 if num == 1:
800 return parents[0].ancestor(parents[1])
800 return parents[0].ancestor(parents[1])
801 return None
801 return None
802
802
803 def print_result(nodes, good):
803 def print_result(nodes, good):
804 displayer = cmdutil.show_changeset(ui, repo, {})
804 displayer = cmdutil.show_changeset(ui, repo, {})
805 if len(nodes) == 1:
805 if len(nodes) == 1:
806 # narrowed it down to a single revision
806 # narrowed it down to a single revision
807 if good:
807 if good:
808 ui.write(_("The first good revision is:\n"))
808 ui.write(_("The first good revision is:\n"))
809 else:
809 else:
810 ui.write(_("The first bad revision is:\n"))
810 ui.write(_("The first bad revision is:\n"))
811 displayer.show(repo[nodes[0]])
811 displayer.show(repo[nodes[0]])
812 extendnode = extendbisectrange(nodes, good)
812 extendnode = extendbisectrange(nodes, good)
813 if extendnode is not None:
813 if extendnode is not None:
814 ui.write(_('Not all ancestors of this changeset have been'
814 ui.write(_('Not all ancestors of this changeset have been'
815 ' checked.\nUse bisect --extend to continue the '
815 ' checked.\nUse bisect --extend to continue the '
816 'bisection from\nthe common ancestor, %s.\n')
816 'bisection from\nthe common ancestor, %s.\n')
817 % extendnode)
817 % extendnode)
818 else:
818 else:
819 # multiple possible revisions
819 # multiple possible revisions
820 if good:
820 if good:
821 ui.write(_("Due to skipped revisions, the first "
821 ui.write(_("Due to skipped revisions, the first "
822 "good revision could be any of:\n"))
822 "good revision could be any of:\n"))
823 else:
823 else:
824 ui.write(_("Due to skipped revisions, the first "
824 ui.write(_("Due to skipped revisions, the first "
825 "bad revision could be any of:\n"))
825 "bad revision could be any of:\n"))
826 for n in nodes:
826 for n in nodes:
827 displayer.show(repo[n])
827 displayer.show(repo[n])
828 displayer.close()
828 displayer.close()
829
829
830 def check_state(state, interactive=True):
830 def check_state(state, interactive=True):
831 if not state['good'] or not state['bad']:
831 if not state['good'] or not state['bad']:
832 if (good or bad or skip or reset) and interactive:
832 if (good or bad or skip or reset) and interactive:
833 return
833 return
834 if not state['good']:
834 if not state['good']:
835 raise error.Abort(_('cannot bisect (no known good revisions)'))
835 raise error.Abort(_('cannot bisect (no known good revisions)'))
836 else:
836 else:
837 raise error.Abort(_('cannot bisect (no known bad revisions)'))
837 raise error.Abort(_('cannot bisect (no known bad revisions)'))
838 return True
838 return True
839
839
840 # backward compatibility
840 # backward compatibility
841 if rev in "good bad reset init".split():
841 if rev in "good bad reset init".split():
842 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
842 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
843 cmd, rev, extra = rev, extra, None
843 cmd, rev, extra = rev, extra, None
844 if cmd == "good":
844 if cmd == "good":
845 good = True
845 good = True
846 elif cmd == "bad":
846 elif cmd == "bad":
847 bad = True
847 bad = True
848 else:
848 else:
849 reset = True
849 reset = True
850 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
850 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
851 raise error.Abort(_('incompatible arguments'))
851 raise error.Abort(_('incompatible arguments'))
852
852
853 cmdutil.checkunfinished(repo)
853 cmdutil.checkunfinished(repo)
854
854
855 if reset:
855 if reset:
856 p = repo.join("bisect.state")
856 p = repo.join("bisect.state")
857 if os.path.exists(p):
857 if os.path.exists(p):
858 os.unlink(p)
858 os.unlink(p)
859 return
859 return
860
860
861 state = hbisect.load_state(repo)
861 state = hbisect.load_state(repo)
862
862
863 if command:
863 if command:
864 changesets = 1
864 changesets = 1
865 if noupdate:
865 if noupdate:
866 try:
866 try:
867 node = state['current'][0]
867 node = state['current'][0]
868 except LookupError:
868 except LookupError:
869 raise error.Abort(_('current bisect revision is unknown - '
869 raise error.Abort(_('current bisect revision is unknown - '
870 'start a new bisect to fix'))
870 'start a new bisect to fix'))
871 else:
871 else:
872 node, p2 = repo.dirstate.parents()
872 node, p2 = repo.dirstate.parents()
873 if p2 != nullid:
873 if p2 != nullid:
874 raise error.Abort(_('current bisect revision is a merge'))
874 raise error.Abort(_('current bisect revision is a merge'))
875 try:
875 try:
876 while changesets:
876 while changesets:
877 # update state
877 # update state
878 state['current'] = [node]
878 state['current'] = [node]
879 hbisect.save_state(repo, state)
879 hbisect.save_state(repo, state)
880 status = ui.system(command, environ={'HG_NODE': hex(node)})
880 status = ui.system(command, environ={'HG_NODE': hex(node)})
881 if status == 125:
881 if status == 125:
882 transition = "skip"
882 transition = "skip"
883 elif status == 0:
883 elif status == 0:
884 transition = "good"
884 transition = "good"
885 # status < 0 means process was killed
885 # status < 0 means process was killed
886 elif status == 127:
886 elif status == 127:
887 raise error.Abort(_("failed to execute %s") % command)
887 raise error.Abort(_("failed to execute %s") % command)
888 elif status < 0:
888 elif status < 0:
889 raise error.Abort(_("%s killed") % command)
889 raise error.Abort(_("%s killed") % command)
890 else:
890 else:
891 transition = "bad"
891 transition = "bad"
892 ctx = scmutil.revsingle(repo, rev, node)
892 ctx = scmutil.revsingle(repo, rev, node)
893 rev = None # clear for future iterations
893 rev = None # clear for future iterations
894 state[transition].append(ctx.node())
894 state[transition].append(ctx.node())
895 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
895 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
896 check_state(state, interactive=False)
896 check_state(state, interactive=False)
897 # bisect
897 # bisect
898 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
898 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
899 # update to next check
899 # update to next check
900 node = nodes[0]
900 node = nodes[0]
901 if not noupdate:
901 if not noupdate:
902 cmdutil.bailifchanged(repo)
902 cmdutil.bailifchanged(repo)
903 hg.clean(repo, node, show_stats=False)
903 hg.clean(repo, node, show_stats=False)
904 finally:
904 finally:
905 state['current'] = [node]
905 state['current'] = [node]
906 hbisect.save_state(repo, state)
906 hbisect.save_state(repo, state)
907 print_result(nodes, bgood)
907 print_result(nodes, bgood)
908 return
908 return
909
909
910 # update state
910 # update state
911
911
912 if rev:
912 if rev:
913 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
913 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
914 else:
914 else:
915 nodes = [repo.lookup('.')]
915 nodes = [repo.lookup('.')]
916
916
917 if good or bad or skip:
917 if good or bad or skip:
918 if good:
918 if good:
919 state['good'] += nodes
919 state['good'] += nodes
920 elif bad:
920 elif bad:
921 state['bad'] += nodes
921 state['bad'] += nodes
922 elif skip:
922 elif skip:
923 state['skip'] += nodes
923 state['skip'] += nodes
924 hbisect.save_state(repo, state)
924 hbisect.save_state(repo, state)
925
925
926 if not check_state(state):
926 if not check_state(state):
927 return
927 return
928
928
929 # actually bisect
929 # actually bisect
930 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
930 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
931 if extend:
931 if extend:
932 if not changesets:
932 if not changesets:
933 extendnode = extendbisectrange(nodes, good)
933 extendnode = extendbisectrange(nodes, good)
934 if extendnode is not None:
934 if extendnode is not None:
935 ui.write(_("Extending search to changeset %d:%s\n")
935 ui.write(_("Extending search to changeset %d:%s\n")
936 % (extendnode.rev(), extendnode))
936 % (extendnode.rev(), extendnode))
937 state['current'] = [extendnode.node()]
937 state['current'] = [extendnode.node()]
938 hbisect.save_state(repo, state)
938 hbisect.save_state(repo, state)
939 if noupdate:
939 if noupdate:
940 return
940 return
941 cmdutil.bailifchanged(repo)
941 cmdutil.bailifchanged(repo)
942 return hg.clean(repo, extendnode.node())
942 return hg.clean(repo, extendnode.node())
943 raise error.Abort(_("nothing to extend"))
943 raise error.Abort(_("nothing to extend"))
944
944
945 if changesets == 0:
945 if changesets == 0:
946 print_result(nodes, good)
946 print_result(nodes, good)
947 else:
947 else:
948 assert len(nodes) == 1 # only a single node can be tested next
948 assert len(nodes) == 1 # only a single node can be tested next
949 node = nodes[0]
949 node = nodes[0]
950 # compute the approximate number of remaining tests
950 # compute the approximate number of remaining tests
951 tests, size = 0, 2
951 tests, size = 0, 2
952 while size <= changesets:
952 while size <= changesets:
953 tests, size = tests + 1, size * 2
953 tests, size = tests + 1, size * 2
954 rev = repo.changelog.rev(node)
954 rev = repo.changelog.rev(node)
955 ui.write(_("Testing changeset %d:%s "
955 ui.write(_("Testing changeset %d:%s "
956 "(%d changesets remaining, ~%d tests)\n")
956 "(%d changesets remaining, ~%d tests)\n")
957 % (rev, short(node), changesets, tests))
957 % (rev, short(node), changesets, tests))
958 state['current'] = [node]
958 state['current'] = [node]
959 hbisect.save_state(repo, state)
959 hbisect.save_state(repo, state)
960 if not noupdate:
960 if not noupdate:
961 cmdutil.bailifchanged(repo)
961 cmdutil.bailifchanged(repo)
962 return hg.clean(repo, node)
962 return hg.clean(repo, node)
963
963
964 @command('bookmarks|bookmark',
964 @command('bookmarks|bookmark',
965 [('f', 'force', False, _('force')),
965 [('f', 'force', False, _('force')),
966 ('r', 'rev', '', _('revision'), _('REV')),
966 ('r', 'rev', '', _('revision'), _('REV')),
967 ('d', 'delete', False, _('delete a given bookmark')),
967 ('d', 'delete', False, _('delete a given bookmark')),
968 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
968 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
969 ('i', 'inactive', False, _('mark a bookmark inactive')),
969 ('i', 'inactive', False, _('mark a bookmark inactive')),
970 ] + formatteropts,
970 ] + formatteropts,
971 _('hg bookmarks [OPTIONS]... [NAME]...'))
971 _('hg bookmarks [OPTIONS]... [NAME]...'))
972 def bookmark(ui, repo, *names, **opts):
972 def bookmark(ui, repo, *names, **opts):
973 '''create a new bookmark or list existing bookmarks
973 '''create a new bookmark or list existing bookmarks
974
974
975 Bookmarks are labels on changesets to help track lines of development.
975 Bookmarks are labels on changesets to help track lines of development.
976 Bookmarks are unversioned and can be moved, renamed and deleted.
976 Bookmarks are unversioned and can be moved, renamed and deleted.
977 Deleting or moving a bookmark has no effect on the associated changesets.
977 Deleting or moving a bookmark has no effect on the associated changesets.
978
978
979 Creating or updating to a bookmark causes it to be marked as 'active'.
979 Creating or updating to a bookmark causes it to be marked as 'active'.
980 The active bookmark is indicated with a '*'.
980 The active bookmark is indicated with a '*'.
981 When a commit is made, the active bookmark will advance to the new commit.
981 When a commit is made, the active bookmark will advance to the new commit.
982 A plain :hg:`update` will also advance an active bookmark, if possible.
982 A plain :hg:`update` will also advance an active bookmark, if possible.
983 Updating away from a bookmark will cause it to be deactivated.
983 Updating away from a bookmark will cause it to be deactivated.
984
984
985 Bookmarks can be pushed and pulled between repositories (see
985 Bookmarks can be pushed and pulled between repositories (see
986 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
986 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
987 diverged, a new 'divergent bookmark' of the form 'name@path' will
987 diverged, a new 'divergent bookmark' of the form 'name@path' will
988 be created. Using :hg:`merge` will resolve the divergence.
988 be created. Using :hg:`merge` will resolve the divergence.
989
989
990 A bookmark named '@' has the special property that :hg:`clone` will
990 A bookmark named '@' has the special property that :hg:`clone` will
991 check it out by default if it exists.
991 check it out by default if it exists.
992
992
993 .. container:: verbose
993 .. container:: verbose
994
994
995 Examples:
995 Examples:
996
996
997 - create an active bookmark for a new line of development::
997 - create an active bookmark for a new line of development::
998
998
999 hg book new-feature
999 hg book new-feature
1000
1000
1001 - create an inactive bookmark as a place marker::
1001 - create an inactive bookmark as a place marker::
1002
1002
1003 hg book -i reviewed
1003 hg book -i reviewed
1004
1004
1005 - create an inactive bookmark on another changeset::
1005 - create an inactive bookmark on another changeset::
1006
1006
1007 hg book -r .^ tested
1007 hg book -r .^ tested
1008
1008
1009 - rename bookmark turkey to dinner::
1009 - rename bookmark turkey to dinner::
1010
1010
1011 hg book -m turkey dinner
1011 hg book -m turkey dinner
1012
1012
1013 - move the '@' bookmark from another branch::
1013 - move the '@' bookmark from another branch::
1014
1014
1015 hg book -f @
1015 hg book -f @
1016 '''
1016 '''
1017 force = opts.get('force')
1017 force = opts.get('force')
1018 rev = opts.get('rev')
1018 rev = opts.get('rev')
1019 delete = opts.get('delete')
1019 delete = opts.get('delete')
1020 rename = opts.get('rename')
1020 rename = opts.get('rename')
1021 inactive = opts.get('inactive')
1021 inactive = opts.get('inactive')
1022
1022
1023 def checkformat(mark):
1023 def checkformat(mark):
1024 mark = mark.strip()
1024 mark = mark.strip()
1025 if not mark:
1025 if not mark:
1026 raise error.Abort(_("bookmark names cannot consist entirely of "
1026 raise error.Abort(_("bookmark names cannot consist entirely of "
1027 "whitespace"))
1027 "whitespace"))
1028 scmutil.checknewlabel(repo, mark, 'bookmark')
1028 scmutil.checknewlabel(repo, mark, 'bookmark')
1029 return mark
1029 return mark
1030
1030
1031 def checkconflict(repo, mark, cur, force=False, target=None):
1031 def checkconflict(repo, mark, cur, force=False, target=None):
1032 if mark in marks and not force:
1032 if mark in marks and not force:
1033 if target:
1033 if target:
1034 if marks[mark] == target and target == cur:
1034 if marks[mark] == target and target == cur:
1035 # re-activating a bookmark
1035 # re-activating a bookmark
1036 return
1036 return
1037 anc = repo.changelog.ancestors([repo[target].rev()])
1037 anc = repo.changelog.ancestors([repo[target].rev()])
1038 bmctx = repo[marks[mark]]
1038 bmctx = repo[marks[mark]]
1039 divs = [repo[b].node() for b in marks
1039 divs = [repo[b].node() for b in marks
1040 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1040 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
1041
1041
1042 # allow resolving a single divergent bookmark even if moving
1042 # allow resolving a single divergent bookmark even if moving
1043 # the bookmark across branches when a revision is specified
1043 # the bookmark across branches when a revision is specified
1044 # that contains a divergent bookmark
1044 # that contains a divergent bookmark
1045 if bmctx.rev() not in anc and target in divs:
1045 if bmctx.rev() not in anc and target in divs:
1046 bookmarks.deletedivergent(repo, [target], mark)
1046 bookmarks.deletedivergent(repo, [target], mark)
1047 return
1047 return
1048
1048
1049 deletefrom = [b for b in divs
1049 deletefrom = [b for b in divs
1050 if repo[b].rev() in anc or b == target]
1050 if repo[b].rev() in anc or b == target]
1051 bookmarks.deletedivergent(repo, deletefrom, mark)
1051 bookmarks.deletedivergent(repo, deletefrom, mark)
1052 if bookmarks.validdest(repo, bmctx, repo[target]):
1052 if bookmarks.validdest(repo, bmctx, repo[target]):
1053 ui.status(_("moving bookmark '%s' forward from %s\n") %
1053 ui.status(_("moving bookmark '%s' forward from %s\n") %
1054 (mark, short(bmctx.node())))
1054 (mark, short(bmctx.node())))
1055 return
1055 return
1056 raise error.Abort(_("bookmark '%s' already exists "
1056 raise error.Abort(_("bookmark '%s' already exists "
1057 "(use -f to force)") % mark)
1057 "(use -f to force)") % mark)
1058 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1058 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
1059 and not force):
1059 and not force):
1060 raise error.Abort(
1060 raise error.Abort(
1061 _("a bookmark cannot have the name of an existing branch"))
1061 _("a bookmark cannot have the name of an existing branch"))
1062
1062
1063 if delete and rename:
1063 if delete and rename:
1064 raise error.Abort(_("--delete and --rename are incompatible"))
1064 raise error.Abort(_("--delete and --rename are incompatible"))
1065 if delete and rev:
1065 if delete and rev:
1066 raise error.Abort(_("--rev is incompatible with --delete"))
1066 raise error.Abort(_("--rev is incompatible with --delete"))
1067 if rename and rev:
1067 if rename and rev:
1068 raise error.Abort(_("--rev is incompatible with --rename"))
1068 raise error.Abort(_("--rev is incompatible with --rename"))
1069 if not names and (delete or rev):
1069 if not names and (delete or rev):
1070 raise error.Abort(_("bookmark name required"))
1070 raise error.Abort(_("bookmark name required"))
1071
1071
1072 if delete or rename or names or inactive:
1072 if delete or rename or names or inactive:
1073 wlock = lock = tr = None
1073 wlock = lock = tr = None
1074 try:
1074 try:
1075 wlock = repo.wlock()
1075 wlock = repo.wlock()
1076 lock = repo.lock()
1076 lock = repo.lock()
1077 cur = repo.changectx('.').node()
1077 cur = repo.changectx('.').node()
1078 marks = repo._bookmarks
1078 marks = repo._bookmarks
1079 if delete:
1079 if delete:
1080 tr = repo.transaction('bookmark')
1080 tr = repo.transaction('bookmark')
1081 for mark in names:
1081 for mark in names:
1082 if mark not in marks:
1082 if mark not in marks:
1083 raise error.Abort(_("bookmark '%s' does not exist") %
1083 raise error.Abort(_("bookmark '%s' does not exist") %
1084 mark)
1084 mark)
1085 if mark == repo._activebookmark:
1085 if mark == repo._activebookmark:
1086 bookmarks.deactivate(repo)
1086 bookmarks.deactivate(repo)
1087 del marks[mark]
1087 del marks[mark]
1088
1088
1089 elif rename:
1089 elif rename:
1090 tr = repo.transaction('bookmark')
1090 tr = repo.transaction('bookmark')
1091 if not names:
1091 if not names:
1092 raise error.Abort(_("new bookmark name required"))
1092 raise error.Abort(_("new bookmark name required"))
1093 elif len(names) > 1:
1093 elif len(names) > 1:
1094 raise error.Abort(_("only one new bookmark name allowed"))
1094 raise error.Abort(_("only one new bookmark name allowed"))
1095 mark = checkformat(names[0])
1095 mark = checkformat(names[0])
1096 if rename not in marks:
1096 if rename not in marks:
1097 raise error.Abort(_("bookmark '%s' does not exist")
1097 raise error.Abort(_("bookmark '%s' does not exist")
1098 % rename)
1098 % rename)
1099 checkconflict(repo, mark, cur, force)
1099 checkconflict(repo, mark, cur, force)
1100 marks[mark] = marks[rename]
1100 marks[mark] = marks[rename]
1101 if repo._activebookmark == rename and not inactive:
1101 if repo._activebookmark == rename and not inactive:
1102 bookmarks.activate(repo, mark)
1102 bookmarks.activate(repo, mark)
1103 del marks[rename]
1103 del marks[rename]
1104 elif names:
1104 elif names:
1105 tr = repo.transaction('bookmark')
1105 tr = repo.transaction('bookmark')
1106 newact = None
1106 newact = None
1107 for mark in names:
1107 for mark in names:
1108 mark = checkformat(mark)
1108 mark = checkformat(mark)
1109 if newact is None:
1109 if newact is None:
1110 newact = mark
1110 newact = mark
1111 if inactive and mark == repo._activebookmark:
1111 if inactive and mark == repo._activebookmark:
1112 bookmarks.deactivate(repo)
1112 bookmarks.deactivate(repo)
1113 return
1113 return
1114 tgt = cur
1114 tgt = cur
1115 if rev:
1115 if rev:
1116 tgt = scmutil.revsingle(repo, rev).node()
1116 tgt = scmutil.revsingle(repo, rev).node()
1117 checkconflict(repo, mark, cur, force, tgt)
1117 checkconflict(repo, mark, cur, force, tgt)
1118 marks[mark] = tgt
1118 marks[mark] = tgt
1119 if not inactive and cur == marks[newact] and not rev:
1119 if not inactive and cur == marks[newact] and not rev:
1120 bookmarks.activate(repo, newact)
1120 bookmarks.activate(repo, newact)
1121 elif cur != tgt and newact == repo._activebookmark:
1121 elif cur != tgt and newact == repo._activebookmark:
1122 bookmarks.deactivate(repo)
1122 bookmarks.deactivate(repo)
1123 elif inactive:
1123 elif inactive:
1124 if len(marks) == 0:
1124 if len(marks) == 0:
1125 ui.status(_("no bookmarks set\n"))
1125 ui.status(_("no bookmarks set\n"))
1126 elif not repo._activebookmark:
1126 elif not repo._activebookmark:
1127 ui.status(_("no active bookmark\n"))
1127 ui.status(_("no active bookmark\n"))
1128 else:
1128 else:
1129 bookmarks.deactivate(repo)
1129 bookmarks.deactivate(repo)
1130 if tr is not None:
1130 if tr is not None:
1131 marks.recordchange(tr)
1131 marks.recordchange(tr)
1132 tr.close()
1132 tr.close()
1133 finally:
1133 finally:
1134 lockmod.release(tr, lock, wlock)
1134 lockmod.release(tr, lock, wlock)
1135 else: # show bookmarks
1135 else: # show bookmarks
1136 fm = ui.formatter('bookmarks', opts)
1136 fm = ui.formatter('bookmarks', opts)
1137 hexfn = fm.hexfunc
1137 hexfn = fm.hexfunc
1138 marks = repo._bookmarks
1138 marks = repo._bookmarks
1139 if len(marks) == 0 and not fm:
1139 if len(marks) == 0 and not fm:
1140 ui.status(_("no bookmarks set\n"))
1140 ui.status(_("no bookmarks set\n"))
1141 for bmark, n in sorted(marks.iteritems()):
1141 for bmark, n in sorted(marks.iteritems()):
1142 active = repo._activebookmark
1142 active = repo._activebookmark
1143 if bmark == active:
1143 if bmark == active:
1144 prefix, label = '*', activebookmarklabel
1144 prefix, label = '*', activebookmarklabel
1145 else:
1145 else:
1146 prefix, label = ' ', ''
1146 prefix, label = ' ', ''
1147
1147
1148 fm.startitem()
1148 fm.startitem()
1149 if not ui.quiet:
1149 if not ui.quiet:
1150 fm.plain(' %s ' % prefix, label=label)
1150 fm.plain(' %s ' % prefix, label=label)
1151 fm.write('bookmark', '%s', bmark, label=label)
1151 fm.write('bookmark', '%s', bmark, label=label)
1152 pad = " " * (25 - encoding.colwidth(bmark))
1152 pad = " " * (25 - encoding.colwidth(bmark))
1153 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1153 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1154 repo.changelog.rev(n), hexfn(n), label=label)
1154 repo.changelog.rev(n), hexfn(n), label=label)
1155 fm.data(active=(bmark == active))
1155 fm.data(active=(bmark == active))
1156 fm.plain('\n')
1156 fm.plain('\n')
1157 fm.end()
1157 fm.end()
1158
1158
1159 @command('branch',
1159 @command('branch',
1160 [('f', 'force', None,
1160 [('f', 'force', None,
1161 _('set branch name even if it shadows an existing branch')),
1161 _('set branch name even if it shadows an existing branch')),
1162 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1162 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1163 _('[-fC] [NAME]'))
1163 _('[-fC] [NAME]'))
1164 def branch(ui, repo, label=None, **opts):
1164 def branch(ui, repo, label=None, **opts):
1165 """set or show the current branch name
1165 """set or show the current branch name
1166
1166
1167 .. note::
1167 .. note::
1168
1168
1169 Branch names are permanent and global. Use :hg:`bookmark` to create a
1169 Branch names are permanent and global. Use :hg:`bookmark` to create a
1170 light-weight bookmark instead. See :hg:`help glossary` for more
1170 light-weight bookmark instead. See :hg:`help glossary` for more
1171 information about named branches and bookmarks.
1171 information about named branches and bookmarks.
1172
1172
1173 With no argument, show the current branch name. With one argument,
1173 With no argument, show the current branch name. With one argument,
1174 set the working directory branch name (the branch will not exist
1174 set the working directory branch name (the branch will not exist
1175 in the repository until the next commit). Standard practice
1175 in the repository until the next commit). Standard practice
1176 recommends that primary development take place on the 'default'
1176 recommends that primary development take place on the 'default'
1177 branch.
1177 branch.
1178
1178
1179 Unless -f/--force is specified, branch will not let you set a
1179 Unless -f/--force is specified, branch will not let you set a
1180 branch name that already exists.
1180 branch name that already exists.
1181
1181
1182 Use -C/--clean to reset the working directory branch to that of
1182 Use -C/--clean to reset the working directory branch to that of
1183 the parent of the working directory, negating a previous branch
1183 the parent of the working directory, negating a previous branch
1184 change.
1184 change.
1185
1185
1186 Use the command :hg:`update` to switch to an existing branch. Use
1186 Use the command :hg:`update` to switch to an existing branch. Use
1187 :hg:`commit --close-branch` to mark this branch head as closed.
1187 :hg:`commit --close-branch` to mark this branch head as closed.
1188 When all heads of a branch are closed, the branch will be
1188 When all heads of a branch are closed, the branch will be
1189 considered closed.
1189 considered closed.
1190
1190
1191 Returns 0 on success.
1191 Returns 0 on success.
1192 """
1192 """
1193 if label:
1193 if label:
1194 label = label.strip()
1194 label = label.strip()
1195
1195
1196 if not opts.get('clean') and not label:
1196 if not opts.get('clean') and not label:
1197 ui.write("%s\n" % repo.dirstate.branch())
1197 ui.write("%s\n" % repo.dirstate.branch())
1198 return
1198 return
1199
1199
1200 wlock = repo.wlock()
1200 wlock = repo.wlock()
1201 try:
1201 try:
1202 if opts.get('clean'):
1202 if opts.get('clean'):
1203 label = repo[None].p1().branch()
1203 label = repo[None].p1().branch()
1204 repo.dirstate.setbranch(label)
1204 repo.dirstate.setbranch(label)
1205 ui.status(_('reset working directory to branch %s\n') % label)
1205 ui.status(_('reset working directory to branch %s\n') % label)
1206 elif label:
1206 elif label:
1207 if not opts.get('force') and label in repo.branchmap():
1207 if not opts.get('force') and label in repo.branchmap():
1208 if label not in [p.branch() for p in repo[None].parents()]:
1208 if label not in [p.branch() for p in repo[None].parents()]:
1209 raise error.Abort(_('a branch of the same name already'
1209 raise error.Abort(_('a branch of the same name already'
1210 ' exists'),
1210 ' exists'),
1211 # i18n: "it" refers to an existing branch
1211 # i18n: "it" refers to an existing branch
1212 hint=_("use 'hg update' to switch to it"))
1212 hint=_("use 'hg update' to switch to it"))
1213 scmutil.checknewlabel(repo, label, 'branch')
1213 scmutil.checknewlabel(repo, label, 'branch')
1214 repo.dirstate.setbranch(label)
1214 repo.dirstate.setbranch(label)
1215 ui.status(_('marked working directory as branch %s\n') % label)
1215 ui.status(_('marked working directory as branch %s\n') % label)
1216
1216
1217 # find any open named branches aside from default
1217 # find any open named branches aside from default
1218 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1218 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1219 if n != "default" and not c]
1219 if n != "default" and not c]
1220 if not others:
1220 if not others:
1221 ui.status(_('(branches are permanent and global, '
1221 ui.status(_('(branches are permanent and global, '
1222 'did you want a bookmark?)\n'))
1222 'did you want a bookmark?)\n'))
1223 finally:
1223 finally:
1224 wlock.release()
1224 wlock.release()
1225
1225
1226 @command('branches',
1226 @command('branches',
1227 [('a', 'active', False,
1227 [('a', 'active', False,
1228 _('show only branches that have unmerged heads (DEPRECATED)')),
1228 _('show only branches that have unmerged heads (DEPRECATED)')),
1229 ('c', 'closed', False, _('show normal and closed branches')),
1229 ('c', 'closed', False, _('show normal and closed branches')),
1230 ] + formatteropts,
1230 ] + formatteropts,
1231 _('[-ac]'))
1231 _('[-ac]'))
1232 def branches(ui, repo, active=False, closed=False, **opts):
1232 def branches(ui, repo, active=False, closed=False, **opts):
1233 """list repository named branches
1233 """list repository named branches
1234
1234
1235 List the repository's named branches, indicating which ones are
1235 List the repository's named branches, indicating which ones are
1236 inactive. If -c/--closed is specified, also list branches which have
1236 inactive. If -c/--closed is specified, also list branches which have
1237 been marked closed (see :hg:`commit --close-branch`).
1237 been marked closed (see :hg:`commit --close-branch`).
1238
1238
1239 Use the command :hg:`update` to switch to an existing branch.
1239 Use the command :hg:`update` to switch to an existing branch.
1240
1240
1241 Returns 0.
1241 Returns 0.
1242 """
1242 """
1243
1243
1244 fm = ui.formatter('branches', opts)
1244 fm = ui.formatter('branches', opts)
1245 hexfunc = fm.hexfunc
1245 hexfunc = fm.hexfunc
1246
1246
1247 allheads = set(repo.heads())
1247 allheads = set(repo.heads())
1248 branches = []
1248 branches = []
1249 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1249 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1250 isactive = not isclosed and bool(set(heads) & allheads)
1250 isactive = not isclosed and bool(set(heads) & allheads)
1251 branches.append((tag, repo[tip], isactive, not isclosed))
1251 branches.append((tag, repo[tip], isactive, not isclosed))
1252 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1252 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1253 reverse=True)
1253 reverse=True)
1254
1254
1255 for tag, ctx, isactive, isopen in branches:
1255 for tag, ctx, isactive, isopen in branches:
1256 if active and not isactive:
1256 if active and not isactive:
1257 continue
1257 continue
1258 if isactive:
1258 if isactive:
1259 label = 'branches.active'
1259 label = 'branches.active'
1260 notice = ''
1260 notice = ''
1261 elif not isopen:
1261 elif not isopen:
1262 if not closed:
1262 if not closed:
1263 continue
1263 continue
1264 label = 'branches.closed'
1264 label = 'branches.closed'
1265 notice = _(' (closed)')
1265 notice = _(' (closed)')
1266 else:
1266 else:
1267 label = 'branches.inactive'
1267 label = 'branches.inactive'
1268 notice = _(' (inactive)')
1268 notice = _(' (inactive)')
1269 current = (tag == repo.dirstate.branch())
1269 current = (tag == repo.dirstate.branch())
1270 if current:
1270 if current:
1271 label = 'branches.current'
1271 label = 'branches.current'
1272
1272
1273 fm.startitem()
1273 fm.startitem()
1274 fm.write('branch', '%s', tag, label=label)
1274 fm.write('branch', '%s', tag, label=label)
1275 rev = ctx.rev()
1275 rev = ctx.rev()
1276 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1276 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1277 fmt = ' ' * padsize + ' %d:%s'
1277 fmt = ' ' * padsize + ' %d:%s'
1278 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1278 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1279 label='log.changeset changeset.%s' % ctx.phasestr())
1279 label='log.changeset changeset.%s' % ctx.phasestr())
1280 fm.data(active=isactive, closed=not isopen, current=current)
1280 fm.data(active=isactive, closed=not isopen, current=current)
1281 if not ui.quiet:
1281 if not ui.quiet:
1282 fm.plain(notice)
1282 fm.plain(notice)
1283 fm.plain('\n')
1283 fm.plain('\n')
1284 fm.end()
1284 fm.end()
1285
1285
1286 @command('bundle',
1286 @command('bundle',
1287 [('f', 'force', None, _('run even when the destination is unrelated')),
1287 [('f', 'force', None, _('run even when the destination is unrelated')),
1288 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1288 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1289 _('REV')),
1289 _('REV')),
1290 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1290 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1291 _('BRANCH')),
1291 _('BRANCH')),
1292 ('', 'base', [],
1292 ('', 'base', [],
1293 _('a base changeset assumed to be available at the destination'),
1293 _('a base changeset assumed to be available at the destination'),
1294 _('REV')),
1294 _('REV')),
1295 ('a', 'all', None, _('bundle all changesets in the repository')),
1295 ('a', 'all', None, _('bundle all changesets in the repository')),
1296 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1296 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1297 ] + remoteopts,
1297 ] + remoteopts,
1298 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1298 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1299 def bundle(ui, repo, fname, dest=None, **opts):
1299 def bundle(ui, repo, fname, dest=None, **opts):
1300 """create a changegroup file
1300 """create a changegroup file
1301
1301
1302 Generate a changegroup file collecting changesets to be added
1302 Generate a changegroup file collecting changesets to be added
1303 to a repository.
1303 to a repository.
1304
1304
1305 To create a bundle containing all changesets, use -a/--all
1305 To create a bundle containing all changesets, use -a/--all
1306 (or --base null). Otherwise, hg assumes the destination will have
1306 (or --base null). Otherwise, hg assumes the destination will have
1307 all the nodes you specify with --base parameters. Otherwise, hg
1307 all the nodes you specify with --base parameters. Otherwise, hg
1308 will assume the repository has all the nodes in destination, or
1308 will assume the repository has all the nodes in destination, or
1309 default-push/default if no destination is specified.
1309 default-push/default if no destination is specified.
1310
1310
1311 You can change bundle format with the -t/--type option. You can
1311 You can change bundle format with the -t/--type option. You can
1312 specify a compression, a bundle version or both using a dash
1312 specify a compression, a bundle version or both using a dash
1313 (comp-version). The available compression methods are: none, bzip2,
1313 (comp-version). The available compression methods are: none, bzip2,
1314 and gzip (by default, bundles are compressed using bzip2). The
1314 and gzip (by default, bundles are compressed using bzip2). The
1315 available formats are: v1, v2 (default to most suitable).
1315 available formats are: v1, v2 (default to most suitable).
1316
1316
1317 The bundle file can then be transferred using conventional means
1317 The bundle file can then be transferred using conventional means
1318 and applied to another repository with the unbundle or pull
1318 and applied to another repository with the unbundle or pull
1319 command. This is useful when direct push and pull are not
1319 command. This is useful when direct push and pull are not
1320 available or when exporting an entire repository is undesirable.
1320 available or when exporting an entire repository is undesirable.
1321
1321
1322 Applying bundles preserves all changeset contents including
1322 Applying bundles preserves all changeset contents including
1323 permissions, copy/rename information, and revision history.
1323 permissions, copy/rename information, and revision history.
1324
1324
1325 Returns 0 on success, 1 if no changes found.
1325 Returns 0 on success, 1 if no changes found.
1326 """
1326 """
1327 revs = None
1327 revs = None
1328 if 'rev' in opts:
1328 if 'rev' in opts:
1329 revs = scmutil.revrange(repo, opts['rev'])
1329 revs = scmutil.revrange(repo, opts['rev'])
1330
1330
1331 bundletype = opts.get('type', 'bzip2').lower()
1331 bundletype = opts.get('type', 'bzip2').lower()
1332 try:
1332 try:
1333 bcompression, cgversion, params = exchange.parsebundlespec(
1333 bcompression, cgversion, params = exchange.parsebundlespec(
1334 repo, bundletype, strict=False)
1334 repo, bundletype, strict=False)
1335 except error.UnsupportedBundleSpecification as e:
1335 except error.UnsupportedBundleSpecification as e:
1336 raise error.Abort(str(e),
1336 raise error.Abort(str(e),
1337 hint=_('see "hg help bundle" for supported '
1337 hint=_('see "hg help bundle" for supported '
1338 'values for --type'))
1338 'values for --type'))
1339
1339
1340 # Packed bundles are a pseudo bundle format for now.
1340 # Packed bundles are a pseudo bundle format for now.
1341 if cgversion == 's1':
1341 if cgversion == 's1':
1342 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1342 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1343 hint=_('use "hg debugcreatestreamclonebundle"'))
1343 hint=_('use "hg debugcreatestreamclonebundle"'))
1344
1344
1345 if opts.get('all'):
1345 if opts.get('all'):
1346 if dest:
1346 if dest:
1347 raise error.Abort(_("--all is incompatible with specifying "
1347 raise error.Abort(_("--all is incompatible with specifying "
1348 "a destination"))
1348 "a destination"))
1349 if opts.get('base'):
1349 if opts.get('base'):
1350 ui.warn(_("ignoring --base because --all was specified\n"))
1350 ui.warn(_("ignoring --base because --all was specified\n"))
1351 base = ['null']
1351 base = ['null']
1352 else:
1352 else:
1353 base = scmutil.revrange(repo, opts.get('base'))
1353 base = scmutil.revrange(repo, opts.get('base'))
1354 # TODO: get desired bundlecaps from command line.
1354 # TODO: get desired bundlecaps from command line.
1355 bundlecaps = None
1355 bundlecaps = None
1356 if base:
1356 if base:
1357 if dest:
1357 if dest:
1358 raise error.Abort(_("--base is incompatible with specifying "
1358 raise error.Abort(_("--base is incompatible with specifying "
1359 "a destination"))
1359 "a destination"))
1360 common = [repo.lookup(rev) for rev in base]
1360 common = [repo.lookup(rev) for rev in base]
1361 heads = revs and map(repo.lookup, revs) or revs
1361 heads = revs and map(repo.lookup, revs) or revs
1362 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1362 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1363 common=common, bundlecaps=bundlecaps,
1363 common=common, bundlecaps=bundlecaps,
1364 version=cgversion)
1364 version=cgversion)
1365 outgoing = None
1365 outgoing = None
1366 else:
1366 else:
1367 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1367 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1368 dest, branches = hg.parseurl(dest, opts.get('branch'))
1368 dest, branches = hg.parseurl(dest, opts.get('branch'))
1369 other = hg.peer(repo, opts, dest)
1369 other = hg.peer(repo, opts, dest)
1370 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1370 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1371 heads = revs and map(repo.lookup, revs) or revs
1371 heads = revs and map(repo.lookup, revs) or revs
1372 outgoing = discovery.findcommonoutgoing(repo, other,
1372 outgoing = discovery.findcommonoutgoing(repo, other,
1373 onlyheads=heads,
1373 onlyheads=heads,
1374 force=opts.get('force'),
1374 force=opts.get('force'),
1375 portable=True)
1375 portable=True)
1376 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1376 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1377 bundlecaps, version=cgversion)
1377 bundlecaps, version=cgversion)
1378 if not cg:
1378 if not cg:
1379 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1379 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1380 return 1
1380 return 1
1381
1381
1382 if cgversion == '01': #bundle1
1382 if cgversion == '01': #bundle1
1383 if bcompression is None:
1383 if bcompression is None:
1384 bcompression = 'UN'
1384 bcompression = 'UN'
1385 bversion = 'HG10' + bcompression
1385 bversion = 'HG10' + bcompression
1386 bcompression = None
1386 bcompression = None
1387 else:
1387 else:
1388 assert cgversion == '02'
1388 assert cgversion == '02'
1389 bversion = 'HG20'
1389 bversion = 'HG20'
1390
1390
1391
1391
1392 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1392 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1393
1393
1394 @command('cat',
1394 @command('cat',
1395 [('o', 'output', '',
1395 [('o', 'output', '',
1396 _('print output to file with formatted name'), _('FORMAT')),
1396 _('print output to file with formatted name'), _('FORMAT')),
1397 ('r', 'rev', '', _('print the given revision'), _('REV')),
1397 ('r', 'rev', '', _('print the given revision'), _('REV')),
1398 ('', 'decode', None, _('apply any matching decode filter')),
1398 ('', 'decode', None, _('apply any matching decode filter')),
1399 ] + walkopts,
1399 ] + walkopts,
1400 _('[OPTION]... FILE...'),
1400 _('[OPTION]... FILE...'),
1401 inferrepo=True)
1401 inferrepo=True)
1402 def cat(ui, repo, file1, *pats, **opts):
1402 def cat(ui, repo, file1, *pats, **opts):
1403 """output the current or given revision of files
1403 """output the current or given revision of files
1404
1404
1405 Print the specified files as they were at the given revision. If
1405 Print the specified files as they were at the given revision. If
1406 no revision is given, the parent of the working directory is used.
1406 no revision is given, the parent of the working directory is used.
1407
1407
1408 Output may be to a file, in which case the name of the file is
1408 Output may be to a file, in which case the name of the file is
1409 given using a format string. The formatting rules as follows:
1409 given using a format string. The formatting rules as follows:
1410
1410
1411 :``%%``: literal "%" character
1411 :``%%``: literal "%" character
1412 :``%s``: basename of file being printed
1412 :``%s``: basename of file being printed
1413 :``%d``: dirname of file being printed, or '.' if in repository root
1413 :``%d``: dirname of file being printed, or '.' if in repository root
1414 :``%p``: root-relative path name of file being printed
1414 :``%p``: root-relative path name of file being printed
1415 :``%H``: changeset hash (40 hexadecimal digits)
1415 :``%H``: changeset hash (40 hexadecimal digits)
1416 :``%R``: changeset revision number
1416 :``%R``: changeset revision number
1417 :``%h``: short-form changeset hash (12 hexadecimal digits)
1417 :``%h``: short-form changeset hash (12 hexadecimal digits)
1418 :``%r``: zero-padded changeset revision number
1418 :``%r``: zero-padded changeset revision number
1419 :``%b``: basename of the exporting repository
1419 :``%b``: basename of the exporting repository
1420
1420
1421 Returns 0 on success.
1421 Returns 0 on success.
1422 """
1422 """
1423 ctx = scmutil.revsingle(repo, opts.get('rev'))
1423 ctx = scmutil.revsingle(repo, opts.get('rev'))
1424 m = scmutil.match(ctx, (file1,) + pats, opts)
1424 m = scmutil.match(ctx, (file1,) + pats, opts)
1425
1425
1426 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1426 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1427
1427
1428 @command('^clone',
1428 @command('^clone',
1429 [('U', 'noupdate', None, _('the clone will include an empty working '
1429 [('U', 'noupdate', None, _('the clone will include an empty working '
1430 'directory (only a repository)')),
1430 'directory (only a repository)')),
1431 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1431 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1432 _('REV')),
1432 _('REV')),
1433 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1433 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1434 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1434 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1435 ('', 'pull', None, _('use pull protocol to copy metadata')),
1435 ('', 'pull', None, _('use pull protocol to copy metadata')),
1436 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1436 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1437 ] + remoteopts,
1437 ] + remoteopts,
1438 _('[OPTION]... SOURCE [DEST]'),
1438 _('[OPTION]... SOURCE [DEST]'),
1439 norepo=True)
1439 norepo=True)
1440 def clone(ui, source, dest=None, **opts):
1440 def clone(ui, source, dest=None, **opts):
1441 """make a copy of an existing repository
1441 """make a copy of an existing repository
1442
1442
1443 Create a copy of an existing repository in a new directory.
1443 Create a copy of an existing repository in a new directory.
1444
1444
1445 If no destination directory name is specified, it defaults to the
1445 If no destination directory name is specified, it defaults to the
1446 basename of the source.
1446 basename of the source.
1447
1447
1448 The location of the source is added to the new repository's
1448 The location of the source is added to the new repository's
1449 ``.hg/hgrc`` file, as the default to be used for future pulls.
1449 ``.hg/hgrc`` file, as the default to be used for future pulls.
1450
1450
1451 Only local paths and ``ssh://`` URLs are supported as
1451 Only local paths and ``ssh://`` URLs are supported as
1452 destinations. For ``ssh://`` destinations, no working directory or
1452 destinations. For ``ssh://`` destinations, no working directory or
1453 ``.hg/hgrc`` will be created on the remote side.
1453 ``.hg/hgrc`` will be created on the remote side.
1454
1454
1455 If the source repository has a bookmark called '@' set, that
1455 If the source repository has a bookmark called '@' set, that
1456 revision will be checked out in the new repository by default.
1456 revision will be checked out in the new repository by default.
1457
1457
1458 To check out a particular version, use -u/--update, or
1458 To check out a particular version, use -u/--update, or
1459 -U/--noupdate to create a clone with no working directory.
1459 -U/--noupdate to create a clone with no working directory.
1460
1460
1461 To pull only a subset of changesets, specify one or more revisions
1461 To pull only a subset of changesets, specify one or more revisions
1462 identifiers with -r/--rev or branches with -b/--branch. The
1462 identifiers with -r/--rev or branches with -b/--branch. The
1463 resulting clone will contain only the specified changesets and
1463 resulting clone will contain only the specified changesets and
1464 their ancestors. These options (or 'clone src#rev dest') imply
1464 their ancestors. These options (or 'clone src#rev dest') imply
1465 --pull, even for local source repositories.
1465 --pull, even for local source repositories.
1466
1466
1467 .. note::
1467 .. note::
1468
1468
1469 Specifying a tag will include the tagged changeset but not the
1469 Specifying a tag will include the tagged changeset but not the
1470 changeset containing the tag.
1470 changeset containing the tag.
1471
1471
1472 .. container:: verbose
1472 .. container:: verbose
1473
1473
1474 For efficiency, hardlinks are used for cloning whenever the
1474 For efficiency, hardlinks are used for cloning whenever the
1475 source and destination are on the same filesystem (note this
1475 source and destination are on the same filesystem (note this
1476 applies only to the repository data, not to the working
1476 applies only to the repository data, not to the working
1477 directory). Some filesystems, such as AFS, implement hardlinking
1477 directory). Some filesystems, such as AFS, implement hardlinking
1478 incorrectly, but do not report errors. In these cases, use the
1478 incorrectly, but do not report errors. In these cases, use the
1479 --pull option to avoid hardlinking.
1479 --pull option to avoid hardlinking.
1480
1480
1481 In some cases, you can clone repositories and the working
1481 In some cases, you can clone repositories and the working
1482 directory using full hardlinks with ::
1482 directory using full hardlinks with ::
1483
1483
1484 $ cp -al REPO REPOCLONE
1484 $ cp -al REPO REPOCLONE
1485
1485
1486 This is the fastest way to clone, but it is not always safe. The
1486 This is the fastest way to clone, but it is not always safe. The
1487 operation is not atomic (making sure REPO is not modified during
1487 operation is not atomic (making sure REPO is not modified during
1488 the operation is up to you) and you have to make sure your
1488 the operation is up to you) and you have to make sure your
1489 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1489 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1490 so). Also, this is not compatible with certain extensions that
1490 so). Also, this is not compatible with certain extensions that
1491 place their metadata under the .hg directory, such as mq.
1491 place their metadata under the .hg directory, such as mq.
1492
1492
1493 Mercurial will update the working directory to the first applicable
1493 Mercurial will update the working directory to the first applicable
1494 revision from this list:
1494 revision from this list:
1495
1495
1496 a) null if -U or the source repository has no changesets
1496 a) null if -U or the source repository has no changesets
1497 b) if -u . and the source repository is local, the first parent of
1497 b) if -u . and the source repository is local, the first parent of
1498 the source repository's working directory
1498 the source repository's working directory
1499 c) the changeset specified with -u (if a branch name, this means the
1499 c) the changeset specified with -u (if a branch name, this means the
1500 latest head of that branch)
1500 latest head of that branch)
1501 d) the changeset specified with -r
1501 d) the changeset specified with -r
1502 e) the tipmost head specified with -b
1502 e) the tipmost head specified with -b
1503 f) the tipmost head specified with the url#branch source syntax
1503 f) the tipmost head specified with the url#branch source syntax
1504 g) the revision marked with the '@' bookmark, if present
1504 g) the revision marked with the '@' bookmark, if present
1505 h) the tipmost head of the default branch
1505 h) the tipmost head of the default branch
1506 i) tip
1506 i) tip
1507
1507
1508 Examples:
1508 Examples:
1509
1509
1510 - clone a remote repository to a new directory named hg/::
1510 - clone a remote repository to a new directory named hg/::
1511
1511
1512 hg clone http://selenic.com/hg
1512 hg clone http://selenic.com/hg
1513
1513
1514 - create a lightweight local clone::
1514 - create a lightweight local clone::
1515
1515
1516 hg clone project/ project-feature/
1516 hg clone project/ project-feature/
1517
1517
1518 - clone from an absolute path on an ssh server (note double-slash)::
1518 - clone from an absolute path on an ssh server (note double-slash)::
1519
1519
1520 hg clone ssh://user@server//home/projects/alpha/
1520 hg clone ssh://user@server//home/projects/alpha/
1521
1521
1522 - do a high-speed clone over a LAN while checking out a
1522 - do a high-speed clone over a LAN while checking out a
1523 specified version::
1523 specified version::
1524
1524
1525 hg clone --uncompressed http://server/repo -u 1.5
1525 hg clone --uncompressed http://server/repo -u 1.5
1526
1526
1527 - create a repository without changesets after a particular revision::
1527 - create a repository without changesets after a particular revision::
1528
1528
1529 hg clone -r 04e544 experimental/ good/
1529 hg clone -r 04e544 experimental/ good/
1530
1530
1531 - clone (and track) a particular named branch::
1531 - clone (and track) a particular named branch::
1532
1532
1533 hg clone http://selenic.com/hg#stable
1533 hg clone http://selenic.com/hg#stable
1534
1534
1535 See :hg:`help urls` for details on specifying URLs.
1535 See :hg:`help urls` for details on specifying URLs.
1536
1536
1537 Returns 0 on success.
1537 Returns 0 on success.
1538 """
1538 """
1539 if opts.get('noupdate') and opts.get('updaterev'):
1539 if opts.get('noupdate') and opts.get('updaterev'):
1540 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1540 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1541
1541
1542 r = hg.clone(ui, opts, source, dest,
1542 r = hg.clone(ui, opts, source, dest,
1543 pull=opts.get('pull'),
1543 pull=opts.get('pull'),
1544 stream=opts.get('uncompressed'),
1544 stream=opts.get('uncompressed'),
1545 rev=opts.get('rev'),
1545 rev=opts.get('rev'),
1546 update=opts.get('updaterev') or not opts.get('noupdate'),
1546 update=opts.get('updaterev') or not opts.get('noupdate'),
1547 branch=opts.get('branch'),
1547 branch=opts.get('branch'),
1548 shareopts=opts.get('shareopts'))
1548 shareopts=opts.get('shareopts'))
1549
1549
1550 return r is None
1550 return r is None
1551
1551
1552 @command('^commit|ci',
1552 @command('^commit|ci',
1553 [('A', 'addremove', None,
1553 [('A', 'addremove', None,
1554 _('mark new/missing files as added/removed before committing')),
1554 _('mark new/missing files as added/removed before committing')),
1555 ('', 'close-branch', None,
1555 ('', 'close-branch', None,
1556 _('mark a branch head as closed')),
1556 _('mark a branch head as closed')),
1557 ('', 'amend', None, _('amend the parent of the working directory')),
1557 ('', 'amend', None, _('amend the parent of the working directory')),
1558 ('s', 'secret', None, _('use the secret phase for committing')),
1558 ('s', 'secret', None, _('use the secret phase for committing')),
1559 ('e', 'edit', None, _('invoke editor on commit messages')),
1559 ('e', 'edit', None, _('invoke editor on commit messages')),
1560 ('i', 'interactive', None, _('use interactive mode')),
1560 ('i', 'interactive', None, _('use interactive mode')),
1561 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1561 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1562 _('[OPTION]... [FILE]...'),
1562 _('[OPTION]... [FILE]...'),
1563 inferrepo=True)
1563 inferrepo=True)
1564 def commit(ui, repo, *pats, **opts):
1564 def commit(ui, repo, *pats, **opts):
1565 """commit the specified files or all outstanding changes
1565 """commit the specified files or all outstanding changes
1566
1566
1567 Commit changes to the given files into the repository. Unlike a
1567 Commit changes to the given files into the repository. Unlike a
1568 centralized SCM, this operation is a local operation. See
1568 centralized SCM, this operation is a local operation. See
1569 :hg:`push` for a way to actively distribute your changes.
1569 :hg:`push` for a way to actively distribute your changes.
1570
1570
1571 If a list of files is omitted, all changes reported by :hg:`status`
1571 If a list of files is omitted, all changes reported by :hg:`status`
1572 will be committed.
1572 will be committed.
1573
1573
1574 If you are committing the result of a merge, do not provide any
1574 If you are committing the result of a merge, do not provide any
1575 filenames or -I/-X filters.
1575 filenames or -I/-X filters.
1576
1576
1577 If no commit message is specified, Mercurial starts your
1577 If no commit message is specified, Mercurial starts your
1578 configured editor where you can enter a message. In case your
1578 configured editor where you can enter a message. In case your
1579 commit fails, you will find a backup of your message in
1579 commit fails, you will find a backup of your message in
1580 ``.hg/last-message.txt``.
1580 ``.hg/last-message.txt``.
1581
1581
1582 The --close-branch flag can be used to mark the current branch
1582 The --close-branch flag can be used to mark the current branch
1583 head closed. When all heads of a branch are closed, the branch
1583 head closed. When all heads of a branch are closed, the branch
1584 will be considered closed and no longer listed.
1584 will be considered closed and no longer listed.
1585
1585
1586 The --amend flag can be used to amend the parent of the
1586 The --amend flag can be used to amend the parent of the
1587 working directory with a new commit that contains the changes
1587 working directory with a new commit that contains the changes
1588 in the parent in addition to those currently reported by :hg:`status`,
1588 in the parent in addition to those currently reported by :hg:`status`,
1589 if there are any. The old commit is stored in a backup bundle in
1589 if there are any. The old commit is stored in a backup bundle in
1590 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1590 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1591 on how to restore it).
1591 on how to restore it).
1592
1592
1593 Message, user and date are taken from the amended commit unless
1593 Message, user and date are taken from the amended commit unless
1594 specified. When a message isn't specified on the command line,
1594 specified. When a message isn't specified on the command line,
1595 the editor will open with the message of the amended commit.
1595 the editor will open with the message of the amended commit.
1596
1596
1597 It is not possible to amend public changesets (see :hg:`help phases`)
1597 It is not possible to amend public changesets (see :hg:`help phases`)
1598 or changesets that have children.
1598 or changesets that have children.
1599
1599
1600 See :hg:`help dates` for a list of formats valid for -d/--date.
1600 See :hg:`help dates` for a list of formats valid for -d/--date.
1601
1601
1602 Returns 0 on success, 1 if nothing changed.
1602 Returns 0 on success, 1 if nothing changed.
1603
1603
1604 .. container:: verbose
1604 .. container:: verbose
1605
1605
1606 Examples:
1606 Examples:
1607
1607
1608 - commit all files ending in .py::
1608 - commit all files ending in .py::
1609
1609
1610 hg commit --include "set:**.py"
1610 hg commit --include "set:**.py"
1611
1611
1612 - commit all non-binary files::
1612 - commit all non-binary files::
1613
1613
1614 hg commit --exclude "set:binary()"
1614 hg commit --exclude "set:binary()"
1615
1615
1616 - amend the current commit and set the date to now::
1616 - amend the current commit and set the date to now::
1617
1617
1618 hg commit --amend --date now
1618 hg commit --amend --date now
1619 """
1619 """
1620 wlock = lock = None
1620 wlock = lock = None
1621 try:
1621 try:
1622 wlock = repo.wlock()
1622 wlock = repo.wlock()
1623 lock = repo.lock()
1623 lock = repo.lock()
1624 return _docommit(ui, repo, *pats, **opts)
1624 return _docommit(ui, repo, *pats, **opts)
1625 finally:
1625 finally:
1626 release(lock, wlock)
1626 release(lock, wlock)
1627
1627
1628 def _docommit(ui, repo, *pats, **opts):
1628 def _docommit(ui, repo, *pats, **opts):
1629 if opts.get('interactive'):
1629 if opts.get('interactive'):
1630 opts.pop('interactive')
1630 opts.pop('interactive')
1631 cmdutil.dorecord(ui, repo, commit, None, False,
1631 cmdutil.dorecord(ui, repo, commit, None, False,
1632 cmdutil.recordfilter, *pats, **opts)
1632 cmdutil.recordfilter, *pats, **opts)
1633 return
1633 return
1634
1634
1635 if opts.get('subrepos'):
1635 if opts.get('subrepos'):
1636 if opts.get('amend'):
1636 if opts.get('amend'):
1637 raise error.Abort(_('cannot amend with --subrepos'))
1637 raise error.Abort(_('cannot amend with --subrepos'))
1638 # Let --subrepos on the command line override config setting.
1638 # Let --subrepos on the command line override config setting.
1639 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1639 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1640
1640
1641 cmdutil.checkunfinished(repo, commit=True)
1641 cmdutil.checkunfinished(repo, commit=True)
1642
1642
1643 branch = repo[None].branch()
1643 branch = repo[None].branch()
1644 bheads = repo.branchheads(branch)
1644 bheads = repo.branchheads(branch)
1645
1645
1646 extra = {}
1646 extra = {}
1647 if opts.get('close_branch'):
1647 if opts.get('close_branch'):
1648 extra['close'] = 1
1648 extra['close'] = 1
1649
1649
1650 if not bheads:
1650 if not bheads:
1651 raise error.Abort(_('can only close branch heads'))
1651 raise error.Abort(_('can only close branch heads'))
1652 elif opts.get('amend'):
1652 elif opts.get('amend'):
1653 if repo[None].parents()[0].p1().branch() != branch and \
1653 if repo[None].parents()[0].p1().branch() != branch and \
1654 repo[None].parents()[0].p2().branch() != branch:
1654 repo[None].parents()[0].p2().branch() != branch:
1655 raise error.Abort(_('can only close branch heads'))
1655 raise error.Abort(_('can only close branch heads'))
1656
1656
1657 if opts.get('amend'):
1657 if opts.get('amend'):
1658 if ui.configbool('ui', 'commitsubrepos'):
1658 if ui.configbool('ui', 'commitsubrepos'):
1659 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1659 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1660
1660
1661 old = repo['.']
1661 old = repo['.']
1662 if not old.mutable():
1662 if not old.mutable():
1663 raise error.Abort(_('cannot amend public changesets'))
1663 raise error.Abort(_('cannot amend public changesets'))
1664 if len(repo[None].parents()) > 1:
1664 if len(repo[None].parents()) > 1:
1665 raise error.Abort(_('cannot amend while merging'))
1665 raise error.Abort(_('cannot amend while merging'))
1666 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1666 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1667 if not allowunstable and old.children():
1667 if not allowunstable and old.children():
1668 raise error.Abort(_('cannot amend changeset with children'))
1668 raise error.Abort(_('cannot amend changeset with children'))
1669
1669
1670 newextra = extra.copy()
1670 newextra = extra.copy()
1671 newextra['branch'] = branch
1671 newextra['branch'] = branch
1672 extra = newextra
1672 extra = newextra
1673 # commitfunc is used only for temporary amend commit by cmdutil.amend
1673 # commitfunc is used only for temporary amend commit by cmdutil.amend
1674 def commitfunc(ui, repo, message, match, opts):
1674 def commitfunc(ui, repo, message, match, opts):
1675 return repo.commit(message,
1675 return repo.commit(message,
1676 opts.get('user') or old.user(),
1676 opts.get('user') or old.user(),
1677 opts.get('date') or old.date(),
1677 opts.get('date') or old.date(),
1678 match,
1678 match,
1679 extra=extra)
1679 extra=extra)
1680
1680
1681 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1681 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1682 if node == old.node():
1682 if node == old.node():
1683 ui.status(_("nothing changed\n"))
1683 ui.status(_("nothing changed\n"))
1684 return 1
1684 return 1
1685 else:
1685 else:
1686 def commitfunc(ui, repo, message, match, opts):
1686 def commitfunc(ui, repo, message, match, opts):
1687 backup = ui.backupconfig('phases', 'new-commit')
1687 backup = ui.backupconfig('phases', 'new-commit')
1688 baseui = repo.baseui
1688 baseui = repo.baseui
1689 basebackup = baseui.backupconfig('phases', 'new-commit')
1689 basebackup = baseui.backupconfig('phases', 'new-commit')
1690 try:
1690 try:
1691 if opts.get('secret'):
1691 if opts.get('secret'):
1692 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1692 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1693 # Propagate to subrepos
1693 # Propagate to subrepos
1694 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1694 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1695
1695
1696 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1696 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1697 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1697 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1698 return repo.commit(message, opts.get('user'), opts.get('date'),
1698 return repo.commit(message, opts.get('user'), opts.get('date'),
1699 match,
1699 match,
1700 editor=editor,
1700 editor=editor,
1701 extra=extra)
1701 extra=extra)
1702 finally:
1702 finally:
1703 ui.restoreconfig(backup)
1703 ui.restoreconfig(backup)
1704 repo.baseui.restoreconfig(basebackup)
1704 repo.baseui.restoreconfig(basebackup)
1705
1705
1706
1706
1707 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1707 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1708
1708
1709 if not node:
1709 if not node:
1710 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1710 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1711 if stat[3]:
1711 if stat[3]:
1712 ui.status(_("nothing changed (%d missing files, see "
1712 ui.status(_("nothing changed (%d missing files, see "
1713 "'hg status')\n") % len(stat[3]))
1713 "'hg status')\n") % len(stat[3]))
1714 else:
1714 else:
1715 ui.status(_("nothing changed\n"))
1715 ui.status(_("nothing changed\n"))
1716 return 1
1716 return 1
1717
1717
1718 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1718 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1719
1719
1720 @command('config|showconfig|debugconfig',
1720 @command('config|showconfig|debugconfig',
1721 [('u', 'untrusted', None, _('show untrusted configuration options')),
1721 [('u', 'untrusted', None, _('show untrusted configuration options')),
1722 ('e', 'edit', None, _('edit user config')),
1722 ('e', 'edit', None, _('edit user config')),
1723 ('l', 'local', None, _('edit repository config')),
1723 ('l', 'local', None, _('edit repository config')),
1724 ('g', 'global', None, _('edit global config'))],
1724 ('g', 'global', None, _('edit global config'))],
1725 _('[-u] [NAME]...'),
1725 _('[-u] [NAME]...'),
1726 optionalrepo=True)
1726 optionalrepo=True)
1727 def config(ui, repo, *values, **opts):
1727 def config(ui, repo, *values, **opts):
1728 """show combined config settings from all hgrc files
1728 """show combined config settings from all hgrc files
1729
1729
1730 With no arguments, print names and values of all config items.
1730 With no arguments, print names and values of all config items.
1731
1731
1732 With one argument of the form section.name, print just the value
1732 With one argument of the form section.name, print just the value
1733 of that config item.
1733 of that config item.
1734
1734
1735 With multiple arguments, print names and values of all config
1735 With multiple arguments, print names and values of all config
1736 items with matching section names.
1736 items with matching section names.
1737
1737
1738 With --edit, start an editor on the user-level config file. With
1738 With --edit, start an editor on the user-level config file. With
1739 --global, edit the system-wide config file. With --local, edit the
1739 --global, edit the system-wide config file. With --local, edit the
1740 repository-level config file.
1740 repository-level config file.
1741
1741
1742 With --debug, the source (filename and line number) is printed
1742 With --debug, the source (filename and line number) is printed
1743 for each config item.
1743 for each config item.
1744
1744
1745 See :hg:`help config` for more information about config files.
1745 See :hg:`help config` for more information about config files.
1746
1746
1747 Returns 0 on success, 1 if NAME does not exist.
1747 Returns 0 on success, 1 if NAME does not exist.
1748
1748
1749 """
1749 """
1750
1750
1751 if opts.get('edit') or opts.get('local') or opts.get('global'):
1751 if opts.get('edit') or opts.get('local') or opts.get('global'):
1752 if opts.get('local') and opts.get('global'):
1752 if opts.get('local') and opts.get('global'):
1753 raise error.Abort(_("can't use --local and --global together"))
1753 raise error.Abort(_("can't use --local and --global together"))
1754
1754
1755 if opts.get('local'):
1755 if opts.get('local'):
1756 if not repo:
1756 if not repo:
1757 raise error.Abort(_("can't use --local outside a repository"))
1757 raise error.Abort(_("can't use --local outside a repository"))
1758 paths = [repo.join('hgrc')]
1758 paths = [repo.join('hgrc')]
1759 elif opts.get('global'):
1759 elif opts.get('global'):
1760 paths = scmutil.systemrcpath()
1760 paths = scmutil.systemrcpath()
1761 else:
1761 else:
1762 paths = scmutil.userrcpath()
1762 paths = scmutil.userrcpath()
1763
1763
1764 for f in paths:
1764 for f in paths:
1765 if os.path.exists(f):
1765 if os.path.exists(f):
1766 break
1766 break
1767 else:
1767 else:
1768 if opts.get('global'):
1768 if opts.get('global'):
1769 samplehgrc = uimod.samplehgrcs['global']
1769 samplehgrc = uimod.samplehgrcs['global']
1770 elif opts.get('local'):
1770 elif opts.get('local'):
1771 samplehgrc = uimod.samplehgrcs['local']
1771 samplehgrc = uimod.samplehgrcs['local']
1772 else:
1772 else:
1773 samplehgrc = uimod.samplehgrcs['user']
1773 samplehgrc = uimod.samplehgrcs['user']
1774
1774
1775 f = paths[0]
1775 f = paths[0]
1776 fp = open(f, "w")
1776 fp = open(f, "w")
1777 fp.write(samplehgrc)
1777 fp.write(samplehgrc)
1778 fp.close()
1778 fp.close()
1779
1779
1780 editor = ui.geteditor()
1780 editor = ui.geteditor()
1781 ui.system("%s \"%s\"" % (editor, f),
1781 ui.system("%s \"%s\"" % (editor, f),
1782 onerr=error.Abort, errprefix=_("edit failed"))
1782 onerr=error.Abort, errprefix=_("edit failed"))
1783 return
1783 return
1784
1784
1785 for f in scmutil.rcpath():
1785 for f in scmutil.rcpath():
1786 ui.debug('read config from: %s\n' % f)
1786 ui.debug('read config from: %s\n' % f)
1787 untrusted = bool(opts.get('untrusted'))
1787 untrusted = bool(opts.get('untrusted'))
1788 if values:
1788 if values:
1789 sections = [v for v in values if '.' not in v]
1789 sections = [v for v in values if '.' not in v]
1790 items = [v for v in values if '.' in v]
1790 items = [v for v in values if '.' in v]
1791 if len(items) > 1 or items and sections:
1791 if len(items) > 1 or items and sections:
1792 raise error.Abort(_('only one config item permitted'))
1792 raise error.Abort(_('only one config item permitted'))
1793 matched = False
1793 matched = False
1794 for section, name, value in ui.walkconfig(untrusted=untrusted):
1794 for section, name, value in ui.walkconfig(untrusted=untrusted):
1795 value = str(value).replace('\n', '\\n')
1795 value = str(value).replace('\n', '\\n')
1796 sectname = section + '.' + name
1796 sectname = section + '.' + name
1797 if values:
1797 if values:
1798 for v in values:
1798 for v in values:
1799 if v == section:
1799 if v == section:
1800 ui.debug('%s: ' %
1800 ui.debug('%s: ' %
1801 ui.configsource(section, name, untrusted))
1801 ui.configsource(section, name, untrusted))
1802 ui.write('%s=%s\n' % (sectname, value))
1802 ui.write('%s=%s\n' % (sectname, value))
1803 matched = True
1803 matched = True
1804 elif v == sectname:
1804 elif v == sectname:
1805 ui.debug('%s: ' %
1805 ui.debug('%s: ' %
1806 ui.configsource(section, name, untrusted))
1806 ui.configsource(section, name, untrusted))
1807 ui.write(value, '\n')
1807 ui.write(value, '\n')
1808 matched = True
1808 matched = True
1809 else:
1809 else:
1810 ui.debug('%s: ' %
1810 ui.debug('%s: ' %
1811 ui.configsource(section, name, untrusted))
1811 ui.configsource(section, name, untrusted))
1812 ui.write('%s=%s\n' % (sectname, value))
1812 ui.write('%s=%s\n' % (sectname, value))
1813 matched = True
1813 matched = True
1814 if matched:
1814 if matched:
1815 return 0
1815 return 0
1816 return 1
1816 return 1
1817
1817
1818 @command('copy|cp',
1818 @command('copy|cp',
1819 [('A', 'after', None, _('record a copy that has already occurred')),
1819 [('A', 'after', None, _('record a copy that has already occurred')),
1820 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1820 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1821 ] + walkopts + dryrunopts,
1821 ] + walkopts + dryrunopts,
1822 _('[OPTION]... [SOURCE]... DEST'))
1822 _('[OPTION]... [SOURCE]... DEST'))
1823 def copy(ui, repo, *pats, **opts):
1823 def copy(ui, repo, *pats, **opts):
1824 """mark files as copied for the next commit
1824 """mark files as copied for the next commit
1825
1825
1826 Mark dest as having copies of source files. If dest is a
1826 Mark dest as having copies of source files. If dest is a
1827 directory, copies are put in that directory. If dest is a file,
1827 directory, copies are put in that directory. If dest is a file,
1828 the source must be a single file.
1828 the source must be a single file.
1829
1829
1830 By default, this command copies the contents of files as they
1830 By default, this command copies the contents of files as they
1831 exist in the working directory. If invoked with -A/--after, the
1831 exist in the working directory. If invoked with -A/--after, the
1832 operation is recorded, but no copying is performed.
1832 operation is recorded, but no copying is performed.
1833
1833
1834 This command takes effect with the next commit. To undo a copy
1834 This command takes effect with the next commit. To undo a copy
1835 before that, see :hg:`revert`.
1835 before that, see :hg:`revert`.
1836
1836
1837 Returns 0 on success, 1 if errors are encountered.
1837 Returns 0 on success, 1 if errors are encountered.
1838 """
1838 """
1839 wlock = repo.wlock(False)
1839 wlock = repo.wlock(False)
1840 try:
1840 try:
1841 return cmdutil.copy(ui, repo, pats, opts)
1841 return cmdutil.copy(ui, repo, pats, opts)
1842 finally:
1842 finally:
1843 wlock.release()
1843 wlock.release()
1844
1844
1845 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1845 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1846 def debugancestor(ui, repo, *args):
1846 def debugancestor(ui, repo, *args):
1847 """find the ancestor revision of two revisions in a given index"""
1847 """find the ancestor revision of two revisions in a given index"""
1848 if len(args) == 3:
1848 if len(args) == 3:
1849 index, rev1, rev2 = args
1849 index, rev1, rev2 = args
1850 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1850 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1851 lookup = r.lookup
1851 lookup = r.lookup
1852 elif len(args) == 2:
1852 elif len(args) == 2:
1853 if not repo:
1853 if not repo:
1854 raise error.Abort(_("there is no Mercurial repository here "
1854 raise error.Abort(_("there is no Mercurial repository here "
1855 "(.hg not found)"))
1855 "(.hg not found)"))
1856 rev1, rev2 = args
1856 rev1, rev2 = args
1857 r = repo.changelog
1857 r = repo.changelog
1858 lookup = repo.lookup
1858 lookup = repo.lookup
1859 else:
1859 else:
1860 raise error.Abort(_('either two or three arguments required'))
1860 raise error.Abort(_('either two or three arguments required'))
1861 a = r.ancestor(lookup(rev1), lookup(rev2))
1861 a = r.ancestor(lookup(rev1), lookup(rev2))
1862 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1862 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1863
1863
1864 @command('debugbuilddag',
1864 @command('debugbuilddag',
1865 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1865 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1866 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1866 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1867 ('n', 'new-file', None, _('add new file at each rev'))],
1867 ('n', 'new-file', None, _('add new file at each rev'))],
1868 _('[OPTION]... [TEXT]'))
1868 _('[OPTION]... [TEXT]'))
1869 def debugbuilddag(ui, repo, text=None,
1869 def debugbuilddag(ui, repo, text=None,
1870 mergeable_file=False,
1870 mergeable_file=False,
1871 overwritten_file=False,
1871 overwritten_file=False,
1872 new_file=False):
1872 new_file=False):
1873 """builds a repo with a given DAG from scratch in the current empty repo
1873 """builds a repo with a given DAG from scratch in the current empty repo
1874
1874
1875 The description of the DAG is read from stdin if not given on the
1875 The description of the DAG is read from stdin if not given on the
1876 command line.
1876 command line.
1877
1877
1878 Elements:
1878 Elements:
1879
1879
1880 - "+n" is a linear run of n nodes based on the current default parent
1880 - "+n" is a linear run of n nodes based on the current default parent
1881 - "." is a single node based on the current default parent
1881 - "." is a single node based on the current default parent
1882 - "$" resets the default parent to null (implied at the start);
1882 - "$" resets the default parent to null (implied at the start);
1883 otherwise the default parent is always the last node created
1883 otherwise the default parent is always the last node created
1884 - "<p" sets the default parent to the backref p
1884 - "<p" sets the default parent to the backref p
1885 - "*p" is a fork at parent p, which is a backref
1885 - "*p" is a fork at parent p, which is a backref
1886 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1886 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1887 - "/p2" is a merge of the preceding node and p2
1887 - "/p2" is a merge of the preceding node and p2
1888 - ":tag" defines a local tag for the preceding node
1888 - ":tag" defines a local tag for the preceding node
1889 - "@branch" sets the named branch for subsequent nodes
1889 - "@branch" sets the named branch for subsequent nodes
1890 - "#...\\n" is a comment up to the end of the line
1890 - "#...\\n" is a comment up to the end of the line
1891
1891
1892 Whitespace between the above elements is ignored.
1892 Whitespace between the above elements is ignored.
1893
1893
1894 A backref is either
1894 A backref is either
1895
1895
1896 - a number n, which references the node curr-n, where curr is the current
1896 - a number n, which references the node curr-n, where curr is the current
1897 node, or
1897 node, or
1898 - the name of a local tag you placed earlier using ":tag", or
1898 - the name of a local tag you placed earlier using ":tag", or
1899 - empty to denote the default parent.
1899 - empty to denote the default parent.
1900
1900
1901 All string valued-elements are either strictly alphanumeric, or must
1901 All string valued-elements are either strictly alphanumeric, or must
1902 be enclosed in double quotes ("..."), with "\\" as escape character.
1902 be enclosed in double quotes ("..."), with "\\" as escape character.
1903 """
1903 """
1904
1904
1905 if text is None:
1905 if text is None:
1906 ui.status(_("reading DAG from stdin\n"))
1906 ui.status(_("reading DAG from stdin\n"))
1907 text = ui.fin.read()
1907 text = ui.fin.read()
1908
1908
1909 cl = repo.changelog
1909 cl = repo.changelog
1910 if len(cl) > 0:
1910 if len(cl) > 0:
1911 raise error.Abort(_('repository is not empty'))
1911 raise error.Abort(_('repository is not empty'))
1912
1912
1913 # determine number of revs in DAG
1913 # determine number of revs in DAG
1914 total = 0
1914 total = 0
1915 for type, data in dagparser.parsedag(text):
1915 for type, data in dagparser.parsedag(text):
1916 if type == 'n':
1916 if type == 'n':
1917 total += 1
1917 total += 1
1918
1918
1919 if mergeable_file:
1919 if mergeable_file:
1920 linesperrev = 2
1920 linesperrev = 2
1921 # make a file with k lines per rev
1921 # make a file with k lines per rev
1922 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1922 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1923 initialmergedlines.append("")
1923 initialmergedlines.append("")
1924
1924
1925 tags = []
1925 tags = []
1926
1926
1927 lock = tr = None
1927 lock = tr = None
1928 try:
1928 try:
1929 lock = repo.lock()
1929 lock = repo.lock()
1930 tr = repo.transaction("builddag")
1930 tr = repo.transaction("builddag")
1931
1931
1932 at = -1
1932 at = -1
1933 atbranch = 'default'
1933 atbranch = 'default'
1934 nodeids = []
1934 nodeids = []
1935 id = 0
1935 id = 0
1936 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1936 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1937 for type, data in dagparser.parsedag(text):
1937 for type, data in dagparser.parsedag(text):
1938 if type == 'n':
1938 if type == 'n':
1939 ui.note(('node %s\n' % str(data)))
1939 ui.note(('node %s\n' % str(data)))
1940 id, ps = data
1940 id, ps = data
1941
1941
1942 files = []
1942 files = []
1943 fctxs = {}
1943 fctxs = {}
1944
1944
1945 p2 = None
1945 p2 = None
1946 if mergeable_file:
1946 if mergeable_file:
1947 fn = "mf"
1947 fn = "mf"
1948 p1 = repo[ps[0]]
1948 p1 = repo[ps[0]]
1949 if len(ps) > 1:
1949 if len(ps) > 1:
1950 p2 = repo[ps[1]]
1950 p2 = repo[ps[1]]
1951 pa = p1.ancestor(p2)
1951 pa = p1.ancestor(p2)
1952 base, local, other = [x[fn].data() for x in (pa, p1,
1952 base, local, other = [x[fn].data() for x in (pa, p1,
1953 p2)]
1953 p2)]
1954 m3 = simplemerge.Merge3Text(base, local, other)
1954 m3 = simplemerge.Merge3Text(base, local, other)
1955 ml = [l.strip() for l in m3.merge_lines()]
1955 ml = [l.strip() for l in m3.merge_lines()]
1956 ml.append("")
1956 ml.append("")
1957 elif at > 0:
1957 elif at > 0:
1958 ml = p1[fn].data().split("\n")
1958 ml = p1[fn].data().split("\n")
1959 else:
1959 else:
1960 ml = initialmergedlines
1960 ml = initialmergedlines
1961 ml[id * linesperrev] += " r%i" % id
1961 ml[id * linesperrev] += " r%i" % id
1962 mergedtext = "\n".join(ml)
1962 mergedtext = "\n".join(ml)
1963 files.append(fn)
1963 files.append(fn)
1964 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1964 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1965
1965
1966 if overwritten_file:
1966 if overwritten_file:
1967 fn = "of"
1967 fn = "of"
1968 files.append(fn)
1968 files.append(fn)
1969 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1969 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1970
1970
1971 if new_file:
1971 if new_file:
1972 fn = "nf%i" % id
1972 fn = "nf%i" % id
1973 files.append(fn)
1973 files.append(fn)
1974 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1974 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1975 if len(ps) > 1:
1975 if len(ps) > 1:
1976 if not p2:
1976 if not p2:
1977 p2 = repo[ps[1]]
1977 p2 = repo[ps[1]]
1978 for fn in p2:
1978 for fn in p2:
1979 if fn.startswith("nf"):
1979 if fn.startswith("nf"):
1980 files.append(fn)
1980 files.append(fn)
1981 fctxs[fn] = p2[fn]
1981 fctxs[fn] = p2[fn]
1982
1982
1983 def fctxfn(repo, cx, path):
1983 def fctxfn(repo, cx, path):
1984 return fctxs.get(path)
1984 return fctxs.get(path)
1985
1985
1986 if len(ps) == 0 or ps[0] < 0:
1986 if len(ps) == 0 or ps[0] < 0:
1987 pars = [None, None]
1987 pars = [None, None]
1988 elif len(ps) == 1:
1988 elif len(ps) == 1:
1989 pars = [nodeids[ps[0]], None]
1989 pars = [nodeids[ps[0]], None]
1990 else:
1990 else:
1991 pars = [nodeids[p] for p in ps]
1991 pars = [nodeids[p] for p in ps]
1992 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1992 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1993 date=(id, 0),
1993 date=(id, 0),
1994 user="debugbuilddag",
1994 user="debugbuilddag",
1995 extra={'branch': atbranch})
1995 extra={'branch': atbranch})
1996 nodeid = repo.commitctx(cx)
1996 nodeid = repo.commitctx(cx)
1997 nodeids.append(nodeid)
1997 nodeids.append(nodeid)
1998 at = id
1998 at = id
1999 elif type == 'l':
1999 elif type == 'l':
2000 id, name = data
2000 id, name = data
2001 ui.note(('tag %s\n' % name))
2001 ui.note(('tag %s\n' % name))
2002 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2002 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2003 elif type == 'a':
2003 elif type == 'a':
2004 ui.note(('branch %s\n' % data))
2004 ui.note(('branch %s\n' % data))
2005 atbranch = data
2005 atbranch = data
2006 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2006 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2007 tr.close()
2007 tr.close()
2008
2008
2009 if tags:
2009 if tags:
2010 repo.vfs.write("localtags", "".join(tags))
2010 repo.vfs.write("localtags", "".join(tags))
2011 finally:
2011 finally:
2012 ui.progress(_('building'), None)
2012 ui.progress(_('building'), None)
2013 release(tr, lock)
2013 release(tr, lock)
2014
2014
2015 @command('debugbundle',
2015 @command('debugbundle',
2016 [('a', 'all', None, _('show all details'))],
2016 [('a', 'all', None, _('show all details'))],
2017 _('FILE'),
2017 _('FILE'),
2018 norepo=True)
2018 norepo=True)
2019 def debugbundle(ui, bundlepath, all=None, **opts):
2019 def debugbundle(ui, bundlepath, all=None, **opts):
2020 """lists the contents of a bundle"""
2020 """lists the contents of a bundle"""
2021 f = hg.openpath(ui, bundlepath)
2021 f = hg.openpath(ui, bundlepath)
2022 try:
2022 try:
2023 gen = exchange.readbundle(ui, f, bundlepath)
2023 gen = exchange.readbundle(ui, f, bundlepath)
2024 if isinstance(gen, bundle2.unbundle20):
2024 if isinstance(gen, bundle2.unbundle20):
2025 return _debugbundle2(ui, gen, all=all, **opts)
2025 return _debugbundle2(ui, gen, all=all, **opts)
2026 if all:
2026 if all:
2027 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2027 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2028
2028
2029 def showchunks(named):
2029 def showchunks(named):
2030 ui.write("\n%s\n" % named)
2030 ui.write("\n%s\n" % named)
2031 chain = None
2031 chain = None
2032 while True:
2032 while True:
2033 chunkdata = gen.deltachunk(chain)
2033 chunkdata = gen.deltachunk(chain)
2034 if not chunkdata:
2034 if not chunkdata:
2035 break
2035 break
2036 node = chunkdata['node']
2036 node = chunkdata['node']
2037 p1 = chunkdata['p1']
2037 p1 = chunkdata['p1']
2038 p2 = chunkdata['p2']
2038 p2 = chunkdata['p2']
2039 cs = chunkdata['cs']
2039 cs = chunkdata['cs']
2040 deltabase = chunkdata['deltabase']
2040 deltabase = chunkdata['deltabase']
2041 delta = chunkdata['delta']
2041 delta = chunkdata['delta']
2042 ui.write("%s %s %s %s %s %s\n" %
2042 ui.write("%s %s %s %s %s %s\n" %
2043 (hex(node), hex(p1), hex(p2),
2043 (hex(node), hex(p1), hex(p2),
2044 hex(cs), hex(deltabase), len(delta)))
2044 hex(cs), hex(deltabase), len(delta)))
2045 chain = node
2045 chain = node
2046
2046
2047 chunkdata = gen.changelogheader()
2047 chunkdata = gen.changelogheader()
2048 showchunks("changelog")
2048 showchunks("changelog")
2049 chunkdata = gen.manifestheader()
2049 chunkdata = gen.manifestheader()
2050 showchunks("manifest")
2050 showchunks("manifest")
2051 while True:
2051 while True:
2052 chunkdata = gen.filelogheader()
2052 chunkdata = gen.filelogheader()
2053 if not chunkdata:
2053 if not chunkdata:
2054 break
2054 break
2055 fname = chunkdata['filename']
2055 fname = chunkdata['filename']
2056 showchunks(fname)
2056 showchunks(fname)
2057 else:
2057 else:
2058 if isinstance(gen, bundle2.unbundle20):
2058 if isinstance(gen, bundle2.unbundle20):
2059 raise error.Abort(_('use debugbundle2 for this file'))
2059 raise error.Abort(_('use debugbundle2 for this file'))
2060 chunkdata = gen.changelogheader()
2060 chunkdata = gen.changelogheader()
2061 chain = None
2061 chain = None
2062 while True:
2062 while True:
2063 chunkdata = gen.deltachunk(chain)
2063 chunkdata = gen.deltachunk(chain)
2064 if not chunkdata:
2064 if not chunkdata:
2065 break
2065 break
2066 node = chunkdata['node']
2066 node = chunkdata['node']
2067 ui.write("%s\n" % hex(node))
2067 ui.write("%s\n" % hex(node))
2068 chain = node
2068 chain = node
2069 finally:
2069 finally:
2070 f.close()
2070 f.close()
2071
2071
2072 def _debugbundle2(ui, gen, **opts):
2072 def _debugbundle2(ui, gen, **opts):
2073 """lists the contents of a bundle2"""
2073 """lists the contents of a bundle2"""
2074 if not isinstance(gen, bundle2.unbundle20):
2074 if not isinstance(gen, bundle2.unbundle20):
2075 raise error.Abort(_('not a bundle2 file'))
2075 raise error.Abort(_('not a bundle2 file'))
2076 ui.write(('Stream params: %s\n' % repr(gen.params)))
2076 ui.write(('Stream params: %s\n' % repr(gen.params)))
2077 for part in gen.iterparts():
2077 for part in gen.iterparts():
2078 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2078 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2079 if part.type == 'changegroup':
2079 if part.type == 'changegroup':
2080 version = part.params.get('version', '01')
2080 version = part.params.get('version', '01')
2081 cg = changegroup.packermap[version][1](part, 'UN')
2081 cg = changegroup.packermap[version][1](part, 'UN')
2082 chunkdata = cg.changelogheader()
2082 chunkdata = cg.changelogheader()
2083 chain = None
2083 chain = None
2084 while True:
2084 while True:
2085 chunkdata = cg.deltachunk(chain)
2085 chunkdata = cg.deltachunk(chain)
2086 if not chunkdata:
2086 if not chunkdata:
2087 break
2087 break
2088 node = chunkdata['node']
2088 node = chunkdata['node']
2089 ui.write(" %s\n" % hex(node))
2089 ui.write(" %s\n" % hex(node))
2090 chain = node
2090 chain = node
2091
2091
2092 @command('debugcreatestreamclonebundle', [], 'FILE')
2092 @command('debugcreatestreamclonebundle', [], 'FILE')
2093 def debugcreatestreamclonebundle(ui, repo, fname):
2093 def debugcreatestreamclonebundle(ui, repo, fname):
2094 """create a stream clone bundle file
2094 """create a stream clone bundle file
2095
2095
2096 Stream bundles are special bundles that are essentially archives of
2096 Stream bundles are special bundles that are essentially archives of
2097 revlog files. They are commonly used for cloning very quickly.
2097 revlog files. They are commonly used for cloning very quickly.
2098 """
2098 """
2099 requirements, gen = streamclone.generatebundlev1(repo)
2099 requirements, gen = streamclone.generatebundlev1(repo)
2100 changegroup.writechunks(ui, gen, fname)
2100 changegroup.writechunks(ui, gen, fname)
2101
2101
2102 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2102 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2103
2103
2104 @command('debugapplystreamclonebundle', [], 'FILE')
2104 @command('debugapplystreamclonebundle', [], 'FILE')
2105 def debugapplystreamclonebundle(ui, repo, fname):
2105 def debugapplystreamclonebundle(ui, repo, fname):
2106 """apply a stream clone bundle file"""
2106 """apply a stream clone bundle file"""
2107 f = hg.openpath(ui, fname)
2107 f = hg.openpath(ui, fname)
2108 gen = exchange.readbundle(ui, f, fname)
2108 gen = exchange.readbundle(ui, f, fname)
2109 gen.apply(repo)
2109 gen.apply(repo)
2110
2110
2111 @command('debugcheckstate', [], '')
2111 @command('debugcheckstate', [], '')
2112 def debugcheckstate(ui, repo):
2112 def debugcheckstate(ui, repo):
2113 """validate the correctness of the current dirstate"""
2113 """validate the correctness of the current dirstate"""
2114 parent1, parent2 = repo.dirstate.parents()
2114 parent1, parent2 = repo.dirstate.parents()
2115 m1 = repo[parent1].manifest()
2115 m1 = repo[parent1].manifest()
2116 m2 = repo[parent2].manifest()
2116 m2 = repo[parent2].manifest()
2117 errors = 0
2117 errors = 0
2118 for f in repo.dirstate:
2118 for f in repo.dirstate:
2119 state = repo.dirstate[f]
2119 state = repo.dirstate[f]
2120 if state in "nr" and f not in m1:
2120 if state in "nr" and f not in m1:
2121 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2121 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2122 errors += 1
2122 errors += 1
2123 if state in "a" and f in m1:
2123 if state in "a" and f in m1:
2124 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2124 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2125 errors += 1
2125 errors += 1
2126 if state in "m" and f not in m1 and f not in m2:
2126 if state in "m" and f not in m1 and f not in m2:
2127 ui.warn(_("%s in state %s, but not in either manifest\n") %
2127 ui.warn(_("%s in state %s, but not in either manifest\n") %
2128 (f, state))
2128 (f, state))
2129 errors += 1
2129 errors += 1
2130 for f in m1:
2130 for f in m1:
2131 state = repo.dirstate[f]
2131 state = repo.dirstate[f]
2132 if state not in "nrm":
2132 if state not in "nrm":
2133 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2133 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2134 errors += 1
2134 errors += 1
2135 if errors:
2135 if errors:
2136 error = _(".hg/dirstate inconsistent with current parent's manifest")
2136 error = _(".hg/dirstate inconsistent with current parent's manifest")
2137 raise error.Abort(error)
2137 raise error.Abort(error)
2138
2138
2139 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2139 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2140 def debugcommands(ui, cmd='', *args):
2140 def debugcommands(ui, cmd='', *args):
2141 """list all available commands and options"""
2141 """list all available commands and options"""
2142 for cmd, vals in sorted(table.iteritems()):
2142 for cmd, vals in sorted(table.iteritems()):
2143 cmd = cmd.split('|')[0].strip('^')
2143 cmd = cmd.split('|')[0].strip('^')
2144 opts = ', '.join([i[1] for i in vals[1]])
2144 opts = ', '.join([i[1] for i in vals[1]])
2145 ui.write('%s: %s\n' % (cmd, opts))
2145 ui.write('%s: %s\n' % (cmd, opts))
2146
2146
2147 @command('debugcomplete',
2147 @command('debugcomplete',
2148 [('o', 'options', None, _('show the command options'))],
2148 [('o', 'options', None, _('show the command options'))],
2149 _('[-o] CMD'),
2149 _('[-o] CMD'),
2150 norepo=True)
2150 norepo=True)
2151 def debugcomplete(ui, cmd='', **opts):
2151 def debugcomplete(ui, cmd='', **opts):
2152 """returns the completion list associated with the given command"""
2152 """returns the completion list associated with the given command"""
2153
2153
2154 if opts.get('options'):
2154 if opts.get('options'):
2155 options = []
2155 options = []
2156 otables = [globalopts]
2156 otables = [globalopts]
2157 if cmd:
2157 if cmd:
2158 aliases, entry = cmdutil.findcmd(cmd, table, False)
2158 aliases, entry = cmdutil.findcmd(cmd, table, False)
2159 otables.append(entry[1])
2159 otables.append(entry[1])
2160 for t in otables:
2160 for t in otables:
2161 for o in t:
2161 for o in t:
2162 if "(DEPRECATED)" in o[3]:
2162 if "(DEPRECATED)" in o[3]:
2163 continue
2163 continue
2164 if o[0]:
2164 if o[0]:
2165 options.append('-%s' % o[0])
2165 options.append('-%s' % o[0])
2166 options.append('--%s' % o[1])
2166 options.append('--%s' % o[1])
2167 ui.write("%s\n" % "\n".join(options))
2167 ui.write("%s\n" % "\n".join(options))
2168 return
2168 return
2169
2169
2170 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2170 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2171 if ui.verbose:
2171 if ui.verbose:
2172 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2172 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2173 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2173 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2174
2174
2175 @command('debugdag',
2175 @command('debugdag',
2176 [('t', 'tags', None, _('use tags as labels')),
2176 [('t', 'tags', None, _('use tags as labels')),
2177 ('b', 'branches', None, _('annotate with branch names')),
2177 ('b', 'branches', None, _('annotate with branch names')),
2178 ('', 'dots', None, _('use dots for runs')),
2178 ('', 'dots', None, _('use dots for runs')),
2179 ('s', 'spaces', None, _('separate elements by spaces'))],
2179 ('s', 'spaces', None, _('separate elements by spaces'))],
2180 _('[OPTION]... [FILE [REV]...]'),
2180 _('[OPTION]... [FILE [REV]...]'),
2181 optionalrepo=True)
2181 optionalrepo=True)
2182 def debugdag(ui, repo, file_=None, *revs, **opts):
2182 def debugdag(ui, repo, file_=None, *revs, **opts):
2183 """format the changelog or an index DAG as a concise textual description
2183 """format the changelog or an index DAG as a concise textual description
2184
2184
2185 If you pass a revlog index, the revlog's DAG is emitted. If you list
2185 If you pass a revlog index, the revlog's DAG is emitted. If you list
2186 revision numbers, they get labeled in the output as rN.
2186 revision numbers, they get labeled in the output as rN.
2187
2187
2188 Otherwise, the changelog DAG of the current repo is emitted.
2188 Otherwise, the changelog DAG of the current repo is emitted.
2189 """
2189 """
2190 spaces = opts.get('spaces')
2190 spaces = opts.get('spaces')
2191 dots = opts.get('dots')
2191 dots = opts.get('dots')
2192 if file_:
2192 if file_:
2193 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2193 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2194 revs = set((int(r) for r in revs))
2194 revs = set((int(r) for r in revs))
2195 def events():
2195 def events():
2196 for r in rlog:
2196 for r in rlog:
2197 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2197 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2198 if p != -1))
2198 if p != -1))
2199 if r in revs:
2199 if r in revs:
2200 yield 'l', (r, "r%i" % r)
2200 yield 'l', (r, "r%i" % r)
2201 elif repo:
2201 elif repo:
2202 cl = repo.changelog
2202 cl = repo.changelog
2203 tags = opts.get('tags')
2203 tags = opts.get('tags')
2204 branches = opts.get('branches')
2204 branches = opts.get('branches')
2205 if tags:
2205 if tags:
2206 labels = {}
2206 labels = {}
2207 for l, n in repo.tags().items():
2207 for l, n in repo.tags().items():
2208 labels.setdefault(cl.rev(n), []).append(l)
2208 labels.setdefault(cl.rev(n), []).append(l)
2209 def events():
2209 def events():
2210 b = "default"
2210 b = "default"
2211 for r in cl:
2211 for r in cl:
2212 if branches:
2212 if branches:
2213 newb = cl.read(cl.node(r))[5]['branch']
2213 newb = cl.read(cl.node(r))[5]['branch']
2214 if newb != b:
2214 if newb != b:
2215 yield 'a', newb
2215 yield 'a', newb
2216 b = newb
2216 b = newb
2217 yield 'n', (r, list(p for p in cl.parentrevs(r)
2217 yield 'n', (r, list(p for p in cl.parentrevs(r)
2218 if p != -1))
2218 if p != -1))
2219 if tags:
2219 if tags:
2220 ls = labels.get(r)
2220 ls = labels.get(r)
2221 if ls:
2221 if ls:
2222 for l in ls:
2222 for l in ls:
2223 yield 'l', (r, l)
2223 yield 'l', (r, l)
2224 else:
2224 else:
2225 raise error.Abort(_('need repo for changelog dag'))
2225 raise error.Abort(_('need repo for changelog dag'))
2226
2226
2227 for line in dagparser.dagtextlines(events(),
2227 for line in dagparser.dagtextlines(events(),
2228 addspaces=spaces,
2228 addspaces=spaces,
2229 wraplabels=True,
2229 wraplabels=True,
2230 wrapannotations=True,
2230 wrapannotations=True,
2231 wrapnonlinear=dots,
2231 wrapnonlinear=dots,
2232 usedots=dots,
2232 usedots=dots,
2233 maxlinewidth=70):
2233 maxlinewidth=70):
2234 ui.write(line)
2234 ui.write(line)
2235 ui.write("\n")
2235 ui.write("\n")
2236
2236
2237 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2237 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2238 def debugdata(ui, repo, file_, rev=None, **opts):
2238 def debugdata(ui, repo, file_, rev=None, **opts):
2239 """dump the contents of a data file revision"""
2239 """dump the contents of a data file revision"""
2240 if opts.get('changelog') or opts.get('manifest'):
2240 if opts.get('changelog') or opts.get('manifest'):
2241 file_, rev = None, file_
2241 file_, rev = None, file_
2242 elif rev is None:
2242 elif rev is None:
2243 raise error.CommandError('debugdata', _('invalid arguments'))
2243 raise error.CommandError('debugdata', _('invalid arguments'))
2244 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2244 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2245 try:
2245 try:
2246 ui.write(r.revision(r.lookup(rev)))
2246 ui.write(r.revision(r.lookup(rev)))
2247 except KeyError:
2247 except KeyError:
2248 raise error.Abort(_('invalid revision identifier %s') % rev)
2248 raise error.Abort(_('invalid revision identifier %s') % rev)
2249
2249
2250 @command('debugdate',
2250 @command('debugdate',
2251 [('e', 'extended', None, _('try extended date formats'))],
2251 [('e', 'extended', None, _('try extended date formats'))],
2252 _('[-e] DATE [RANGE]'),
2252 _('[-e] DATE [RANGE]'),
2253 norepo=True, optionalrepo=True)
2253 norepo=True, optionalrepo=True)
2254 def debugdate(ui, date, range=None, **opts):
2254 def debugdate(ui, date, range=None, **opts):
2255 """parse and display a date"""
2255 """parse and display a date"""
2256 if opts["extended"]:
2256 if opts["extended"]:
2257 d = util.parsedate(date, util.extendeddateformats)
2257 d = util.parsedate(date, util.extendeddateformats)
2258 else:
2258 else:
2259 d = util.parsedate(date)
2259 d = util.parsedate(date)
2260 ui.write(("internal: %s %s\n") % d)
2260 ui.write(("internal: %s %s\n") % d)
2261 ui.write(("standard: %s\n") % util.datestr(d))
2261 ui.write(("standard: %s\n") % util.datestr(d))
2262 if range:
2262 if range:
2263 m = util.matchdate(range)
2263 m = util.matchdate(range)
2264 ui.write(("match: %s\n") % m(d[0]))
2264 ui.write(("match: %s\n") % m(d[0]))
2265
2265
2266 @command('debugdiscovery',
2266 @command('debugdiscovery',
2267 [('', 'old', None, _('use old-style discovery')),
2267 [('', 'old', None, _('use old-style discovery')),
2268 ('', 'nonheads', None,
2268 ('', 'nonheads', None,
2269 _('use old-style discovery with non-heads included')),
2269 _('use old-style discovery with non-heads included')),
2270 ] + remoteopts,
2270 ] + remoteopts,
2271 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2271 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2272 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2272 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2273 """runs the changeset discovery protocol in isolation"""
2273 """runs the changeset discovery protocol in isolation"""
2274 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2274 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2275 opts.get('branch'))
2275 opts.get('branch'))
2276 remote = hg.peer(repo, opts, remoteurl)
2276 remote = hg.peer(repo, opts, remoteurl)
2277 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2277 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2278
2278
2279 # make sure tests are repeatable
2279 # make sure tests are repeatable
2280 random.seed(12323)
2280 random.seed(12323)
2281
2281
2282 def doit(localheads, remoteheads, remote=remote):
2282 def doit(localheads, remoteheads, remote=remote):
2283 if opts.get('old'):
2283 if opts.get('old'):
2284 if localheads:
2284 if localheads:
2285 raise error.Abort('cannot use localheads with old style '
2285 raise error.Abort('cannot use localheads with old style '
2286 'discovery')
2286 'discovery')
2287 if not util.safehasattr(remote, 'branches'):
2287 if not util.safehasattr(remote, 'branches'):
2288 # enable in-client legacy support
2288 # enable in-client legacy support
2289 remote = localrepo.locallegacypeer(remote.local())
2289 remote = localrepo.locallegacypeer(remote.local())
2290 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2290 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2291 force=True)
2291 force=True)
2292 common = set(common)
2292 common = set(common)
2293 if not opts.get('nonheads'):
2293 if not opts.get('nonheads'):
2294 ui.write(("unpruned common: %s\n") %
2294 ui.write(("unpruned common: %s\n") %
2295 " ".join(sorted(short(n) for n in common)))
2295 " ".join(sorted(short(n) for n in common)))
2296 dag = dagutil.revlogdag(repo.changelog)
2296 dag = dagutil.revlogdag(repo.changelog)
2297 all = dag.ancestorset(dag.internalizeall(common))
2297 all = dag.ancestorset(dag.internalizeall(common))
2298 common = dag.externalizeall(dag.headsetofconnecteds(all))
2298 common = dag.externalizeall(dag.headsetofconnecteds(all))
2299 else:
2299 else:
2300 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2300 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2301 common = set(common)
2301 common = set(common)
2302 rheads = set(hds)
2302 rheads = set(hds)
2303 lheads = set(repo.heads())
2303 lheads = set(repo.heads())
2304 ui.write(("common heads: %s\n") %
2304 ui.write(("common heads: %s\n") %
2305 " ".join(sorted(short(n) for n in common)))
2305 " ".join(sorted(short(n) for n in common)))
2306 if lheads <= common:
2306 if lheads <= common:
2307 ui.write(("local is subset\n"))
2307 ui.write(("local is subset\n"))
2308 elif rheads <= common:
2308 elif rheads <= common:
2309 ui.write(("remote is subset\n"))
2309 ui.write(("remote is subset\n"))
2310
2310
2311 serverlogs = opts.get('serverlog')
2311 serverlogs = opts.get('serverlog')
2312 if serverlogs:
2312 if serverlogs:
2313 for filename in serverlogs:
2313 for filename in serverlogs:
2314 logfile = open(filename, 'r')
2314 logfile = open(filename, 'r')
2315 try:
2315 try:
2316 line = logfile.readline()
2316 line = logfile.readline()
2317 while line:
2317 while line:
2318 parts = line.strip().split(';')
2318 parts = line.strip().split(';')
2319 op = parts[1]
2319 op = parts[1]
2320 if op == 'cg':
2320 if op == 'cg':
2321 pass
2321 pass
2322 elif op == 'cgss':
2322 elif op == 'cgss':
2323 doit(parts[2].split(' '), parts[3].split(' '))
2323 doit(parts[2].split(' '), parts[3].split(' '))
2324 elif op == 'unb':
2324 elif op == 'unb':
2325 doit(parts[3].split(' '), parts[2].split(' '))
2325 doit(parts[3].split(' '), parts[2].split(' '))
2326 line = logfile.readline()
2326 line = logfile.readline()
2327 finally:
2327 finally:
2328 logfile.close()
2328 logfile.close()
2329
2329
2330 else:
2330 else:
2331 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2331 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2332 opts.get('remote_head'))
2332 opts.get('remote_head'))
2333 localrevs = opts.get('local_head')
2333 localrevs = opts.get('local_head')
2334 doit(localrevs, remoterevs)
2334 doit(localrevs, remoterevs)
2335
2335
2336 @command('debugextensions', formatteropts, [], norepo=True)
2336 @command('debugextensions', formatteropts, [], norepo=True)
2337 def debugextensions(ui, **opts):
2337 def debugextensions(ui, **opts):
2338 '''show information about active extensions'''
2338 '''show information about active extensions'''
2339 exts = extensions.extensions(ui)
2339 exts = extensions.extensions(ui)
2340 fm = ui.formatter('debugextensions', opts)
2340 fm = ui.formatter('debugextensions', opts)
2341 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2341 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2342 extsource = extmod.__file__
2342 extsource = extmod.__file__
2343 exttestedwith = getattr(extmod, 'testedwith', None)
2343 exttestedwith = getattr(extmod, 'testedwith', None)
2344 if exttestedwith is not None:
2344 if exttestedwith is not None:
2345 exttestedwith = exttestedwith.split()
2345 exttestedwith = exttestedwith.split()
2346 extbuglink = getattr(extmod, 'buglink', None)
2346 extbuglink = getattr(extmod, 'buglink', None)
2347
2347
2348 fm.startitem()
2348 fm.startitem()
2349
2349
2350 if ui.quiet or ui.verbose:
2350 if ui.quiet or ui.verbose:
2351 fm.write('name', '%s\n', extname)
2351 fm.write('name', '%s\n', extname)
2352 else:
2352 else:
2353 fm.write('name', '%s', extname)
2353 fm.write('name', '%s', extname)
2354 if not exttestedwith:
2354 if not exttestedwith:
2355 fm.plain(_(' (untested!)\n'))
2355 fm.plain(_(' (untested!)\n'))
2356 else:
2356 else:
2357 if exttestedwith == ['internal'] or \
2357 if exttestedwith == ['internal'] or \
2358 util.version() in exttestedwith:
2358 util.version() in exttestedwith:
2359 fm.plain('\n')
2359 fm.plain('\n')
2360 else:
2360 else:
2361 lasttestedversion = exttestedwith[-1]
2361 lasttestedversion = exttestedwith[-1]
2362 fm.plain(' (%s!)\n' % lasttestedversion)
2362 fm.plain(' (%s!)\n' % lasttestedversion)
2363
2363
2364 fm.condwrite(ui.verbose and extsource, 'source',
2364 fm.condwrite(ui.verbose and extsource, 'source',
2365 _(' location: %s\n'), extsource or "")
2365 _(' location: %s\n'), extsource or "")
2366
2366
2367 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2367 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2368 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2368 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2369
2369
2370 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2370 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2371 _(' bug reporting: %s\n'), extbuglink or "")
2371 _(' bug reporting: %s\n'), extbuglink or "")
2372
2372
2373 fm.end()
2373 fm.end()
2374
2374
2375 @command('debugfileset',
2375 @command('debugfileset',
2376 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2376 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2377 _('[-r REV] FILESPEC'))
2377 _('[-r REV] FILESPEC'))
2378 def debugfileset(ui, repo, expr, **opts):
2378 def debugfileset(ui, repo, expr, **opts):
2379 '''parse and apply a fileset specification'''
2379 '''parse and apply a fileset specification'''
2380 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2380 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2381 if ui.verbose:
2381 if ui.verbose:
2382 tree = fileset.parse(expr)
2382 tree = fileset.parse(expr)
2383 ui.note(fileset.prettyformat(tree), "\n")
2383 ui.note(fileset.prettyformat(tree), "\n")
2384
2384
2385 for f in ctx.getfileset(expr):
2385 for f in ctx.getfileset(expr):
2386 ui.write("%s\n" % f)
2386 ui.write("%s\n" % f)
2387
2387
2388 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2388 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2389 def debugfsinfo(ui, path="."):
2389 def debugfsinfo(ui, path="."):
2390 """show information detected about current filesystem"""
2390 """show information detected about current filesystem"""
2391 util.writefile('.debugfsinfo', '')
2391 util.writefile('.debugfsinfo', '')
2392 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2392 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2393 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2393 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2394 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2394 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2395 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2395 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2396 and 'yes' or 'no'))
2396 and 'yes' or 'no'))
2397 os.unlink('.debugfsinfo')
2397 os.unlink('.debugfsinfo')
2398
2398
2399 @command('debuggetbundle',
2399 @command('debuggetbundle',
2400 [('H', 'head', [], _('id of head node'), _('ID')),
2400 [('H', 'head', [], _('id of head node'), _('ID')),
2401 ('C', 'common', [], _('id of common node'), _('ID')),
2401 ('C', 'common', [], _('id of common node'), _('ID')),
2402 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2402 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2403 _('REPO FILE [-H|-C ID]...'),
2403 _('REPO FILE [-H|-C ID]...'),
2404 norepo=True)
2404 norepo=True)
2405 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2405 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2406 """retrieves a bundle from a repo
2406 """retrieves a bundle from a repo
2407
2407
2408 Every ID must be a full-length hex node id string. Saves the bundle to the
2408 Every ID must be a full-length hex node id string. Saves the bundle to the
2409 given file.
2409 given file.
2410 """
2410 """
2411 repo = hg.peer(ui, opts, repopath)
2411 repo = hg.peer(ui, opts, repopath)
2412 if not repo.capable('getbundle'):
2412 if not repo.capable('getbundle'):
2413 raise error.Abort("getbundle() not supported by target repository")
2413 raise error.Abort("getbundle() not supported by target repository")
2414 args = {}
2414 args = {}
2415 if common:
2415 if common:
2416 args['common'] = [bin(s) for s in common]
2416 args['common'] = [bin(s) for s in common]
2417 if head:
2417 if head:
2418 args['heads'] = [bin(s) for s in head]
2418 args['heads'] = [bin(s) for s in head]
2419 # TODO: get desired bundlecaps from command line.
2419 # TODO: get desired bundlecaps from command line.
2420 args['bundlecaps'] = None
2420 args['bundlecaps'] = None
2421 bundle = repo.getbundle('debug', **args)
2421 bundle = repo.getbundle('debug', **args)
2422
2422
2423 bundletype = opts.get('type', 'bzip2').lower()
2423 bundletype = opts.get('type', 'bzip2').lower()
2424 btypes = {'none': 'HG10UN',
2424 btypes = {'none': 'HG10UN',
2425 'bzip2': 'HG10BZ',
2425 'bzip2': 'HG10BZ',
2426 'gzip': 'HG10GZ',
2426 'gzip': 'HG10GZ',
2427 'bundle2': 'HG20'}
2427 'bundle2': 'HG20'}
2428 bundletype = btypes.get(bundletype)
2428 bundletype = btypes.get(bundletype)
2429 if bundletype not in changegroup.bundletypes:
2429 if bundletype not in changegroup.bundletypes:
2430 raise error.Abort(_('unknown bundle type specified with --type'))
2430 raise error.Abort(_('unknown bundle type specified with --type'))
2431 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2431 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2432
2432
2433 @command('debugignore', [], '[FILE]')
2433 @command('debugignore', [], '[FILE]')
2434 def debugignore(ui, repo, *files, **opts):
2434 def debugignore(ui, repo, *files, **opts):
2435 """display the combined ignore pattern and information about ignored files
2435 """display the combined ignore pattern and information about ignored files
2436
2436
2437 With no argument display the combined ignore pattern.
2437 With no argument display the combined ignore pattern.
2438
2438
2439 Given space separated file names, shows if the given file is ignored and
2439 Given space separated file names, shows if the given file is ignored and
2440 if so, show the ignore rule (file and line number) that matched it.
2440 if so, show the ignore rule (file and line number) that matched it.
2441 """
2441 """
2442 ignore = repo.dirstate._ignore
2442 ignore = repo.dirstate._ignore
2443 if not files:
2443 if not files:
2444 # Show all the patterns
2444 # Show all the patterns
2445 includepat = getattr(ignore, 'includepat', None)
2445 includepat = getattr(ignore, 'includepat', None)
2446 if includepat is not None:
2446 if includepat is not None:
2447 ui.write("%s\n" % includepat)
2447 ui.write("%s\n" % includepat)
2448 else:
2448 else:
2449 raise error.Abort(_("no ignore patterns found"))
2449 raise error.Abort(_("no ignore patterns found"))
2450 else:
2450 else:
2451 for f in files:
2451 for f in files:
2452 ignored = None
2452 ignored = None
2453 ignoredata = None
2453 ignoredata = None
2454 if f != '.':
2454 if f != '.':
2455 if ignore(f):
2455 if ignore(f):
2456 ignored = f
2456 ignored = f
2457 ignoredata = repo.dirstate._ignorefileandline(f)
2457 ignoredata = repo.dirstate._ignorefileandline(f)
2458 else:
2458 else:
2459 for p in util.finddirs(f):
2459 for p in util.finddirs(f):
2460 if ignore(p):
2460 if ignore(p):
2461 ignored = p
2461 ignored = p
2462 ignoredata = repo.dirstate._ignorefileandline(p)
2462 ignoredata = repo.dirstate._ignorefileandline(p)
2463 break
2463 break
2464 if ignored:
2464 if ignored:
2465 if ignored == f:
2465 if ignored == f:
2466 ui.write("%s is ignored\n" % f)
2466 ui.write("%s is ignored\n" % f)
2467 else:
2467 else:
2468 ui.write("%s is ignored because of containing folder %s\n"
2468 ui.write("%s is ignored because of containing folder %s\n"
2469 % (f, ignored))
2469 % (f, ignored))
2470 ignorefile, lineno, line = ignoredata
2470 ignorefile, lineno, line = ignoredata
2471 ui.write("(ignore rule in %s, line %d: '%s')\n"
2471 ui.write("(ignore rule in %s, line %d: '%s')\n"
2472 % (ignorefile, lineno, line))
2472 % (ignorefile, lineno, line))
2473 else:
2473 else:
2474 ui.write("%s is not ignored\n" % f)
2474 ui.write("%s is not ignored\n" % f)
2475
2475
2476 @command('debugindex', debugrevlogopts +
2476 @command('debugindex', debugrevlogopts +
2477 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2477 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2478 _('[-f FORMAT] -c|-m|FILE'),
2478 _('[-f FORMAT] -c|-m|FILE'),
2479 optionalrepo=True)
2479 optionalrepo=True)
2480 def debugindex(ui, repo, file_=None, **opts):
2480 def debugindex(ui, repo, file_=None, **opts):
2481 """dump the contents of an index file"""
2481 """dump the contents of an index file"""
2482 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2482 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2483 format = opts.get('format', 0)
2483 format = opts.get('format', 0)
2484 if format not in (0, 1):
2484 if format not in (0, 1):
2485 raise error.Abort(_("unknown format %d") % format)
2485 raise error.Abort(_("unknown format %d") % format)
2486
2486
2487 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2487 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2488 if generaldelta:
2488 if generaldelta:
2489 basehdr = ' delta'
2489 basehdr = ' delta'
2490 else:
2490 else:
2491 basehdr = ' base'
2491 basehdr = ' base'
2492
2492
2493 if ui.debugflag:
2493 if ui.debugflag:
2494 shortfn = hex
2494 shortfn = hex
2495 else:
2495 else:
2496 shortfn = short
2496 shortfn = short
2497
2497
2498 # There might not be anything in r, so have a sane default
2498 # There might not be anything in r, so have a sane default
2499 idlen = 12
2499 idlen = 12
2500 for i in r:
2500 for i in r:
2501 idlen = len(shortfn(r.node(i)))
2501 idlen = len(shortfn(r.node(i)))
2502 break
2502 break
2503
2503
2504 if format == 0:
2504 if format == 0:
2505 ui.write(" rev offset length " + basehdr + " linkrev"
2505 ui.write(" rev offset length " + basehdr + " linkrev"
2506 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2506 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2507 elif format == 1:
2507 elif format == 1:
2508 ui.write(" rev flag offset length"
2508 ui.write(" rev flag offset length"
2509 " size " + basehdr + " link p1 p2"
2509 " size " + basehdr + " link p1 p2"
2510 " %s\n" % "nodeid".rjust(idlen))
2510 " %s\n" % "nodeid".rjust(idlen))
2511
2511
2512 for i in r:
2512 for i in r:
2513 node = r.node(i)
2513 node = r.node(i)
2514 if generaldelta:
2514 if generaldelta:
2515 base = r.deltaparent(i)
2515 base = r.deltaparent(i)
2516 else:
2516 else:
2517 base = r.chainbase(i)
2517 base = r.chainbase(i)
2518 if format == 0:
2518 if format == 0:
2519 try:
2519 try:
2520 pp = r.parents(node)
2520 pp = r.parents(node)
2521 except Exception:
2521 except Exception:
2522 pp = [nullid, nullid]
2522 pp = [nullid, nullid]
2523 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2523 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2524 i, r.start(i), r.length(i), base, r.linkrev(i),
2524 i, r.start(i), r.length(i), base, r.linkrev(i),
2525 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2525 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2526 elif format == 1:
2526 elif format == 1:
2527 pr = r.parentrevs(i)
2527 pr = r.parentrevs(i)
2528 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2528 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2529 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2529 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2530 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2530 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2531
2531
2532 @command('debugindexdot', debugrevlogopts,
2532 @command('debugindexdot', debugrevlogopts,
2533 _('-c|-m|FILE'), optionalrepo=True)
2533 _('-c|-m|FILE'), optionalrepo=True)
2534 def debugindexdot(ui, repo, file_=None, **opts):
2534 def debugindexdot(ui, repo, file_=None, **opts):
2535 """dump an index DAG as a graphviz dot file"""
2535 """dump an index DAG as a graphviz dot file"""
2536 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2536 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2537 ui.write(("digraph G {\n"))
2537 ui.write(("digraph G {\n"))
2538 for i in r:
2538 for i in r:
2539 node = r.node(i)
2539 node = r.node(i)
2540 pp = r.parents(node)
2540 pp = r.parents(node)
2541 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2541 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2542 if pp[1] != nullid:
2542 if pp[1] != nullid:
2543 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2543 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2544 ui.write("}\n")
2544 ui.write("}\n")
2545
2545
2546 @command('debugdeltachain',
2546 @command('debugdeltachain',
2547 debugrevlogopts + formatteropts,
2547 debugrevlogopts + formatteropts,
2548 _('-c|-m|FILE'),
2548 _('-c|-m|FILE'),
2549 optionalrepo=True)
2549 optionalrepo=True)
2550 def debugdeltachain(ui, repo, file_=None, **opts):
2550 def debugdeltachain(ui, repo, file_=None, **opts):
2551 """dump information about delta chains in a revlog
2551 """dump information about delta chains in a revlog
2552
2552
2553 Output can be templatized. Available template keywords are:
2553 Output can be templatized. Available template keywords are:
2554
2554
2555 rev revision number
2555 rev revision number
2556 chainid delta chain identifier (numbered by unique base)
2556 chainid delta chain identifier (numbered by unique base)
2557 chainlen delta chain length to this revision
2557 chainlen delta chain length to this revision
2558 prevrev previous revision in delta chain
2558 prevrev previous revision in delta chain
2559 deltatype role of delta / how it was computed
2559 deltatype role of delta / how it was computed
2560 compsize compressed size of revision
2560 compsize compressed size of revision
2561 uncompsize uncompressed size of revision
2561 uncompsize uncompressed size of revision
2562 chainsize total size of compressed revisions in chain
2562 chainsize total size of compressed revisions in chain
2563 chainratio total chain size divided by uncompressed revision size
2563 chainratio total chain size divided by uncompressed revision size
2564 (new delta chains typically start at ratio 2.00)
2564 (new delta chains typically start at ratio 2.00)
2565 lindist linear distance from base revision in delta chain to end
2565 lindist linear distance from base revision in delta chain to end
2566 of this revision
2566 of this revision
2567 extradist total size of revisions not part of this delta chain from
2567 extradist total size of revisions not part of this delta chain from
2568 base of delta chain to end of this revision; a measurement
2568 base of delta chain to end of this revision; a measurement
2569 of how much extra data we need to read/seek across to read
2569 of how much extra data we need to read/seek across to read
2570 the delta chain for this revision
2570 the delta chain for this revision
2571 extraratio extradist divided by chainsize; another representation of
2571 extraratio extradist divided by chainsize; another representation of
2572 how much unrelated data is needed to load this delta chain
2572 how much unrelated data is needed to load this delta chain
2573 """
2573 """
2574 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2574 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2575 index = r.index
2575 index = r.index
2576 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2576 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2577
2577
2578 def revinfo(rev):
2578 def revinfo(rev):
2579 e = index[rev]
2579 e = index[rev]
2580 compsize = e[1]
2580 compsize = e[1]
2581 uncompsize = e[2]
2581 uncompsize = e[2]
2582 chainsize = 0
2582 chainsize = 0
2583
2583
2584 if generaldelta:
2584 if generaldelta:
2585 if e[3] == e[5]:
2585 if e[3] == e[5]:
2586 deltatype = 'p1'
2586 deltatype = 'p1'
2587 elif e[3] == e[6]:
2587 elif e[3] == e[6]:
2588 deltatype = 'p2'
2588 deltatype = 'p2'
2589 elif e[3] == rev - 1:
2589 elif e[3] == rev - 1:
2590 deltatype = 'prev'
2590 deltatype = 'prev'
2591 elif e[3] == rev:
2591 elif e[3] == rev:
2592 deltatype = 'base'
2592 deltatype = 'base'
2593 else:
2593 else:
2594 deltatype = 'other'
2594 deltatype = 'other'
2595 else:
2595 else:
2596 if e[3] == rev:
2596 if e[3] == rev:
2597 deltatype = 'base'
2597 deltatype = 'base'
2598 else:
2598 else:
2599 deltatype = 'prev'
2599 deltatype = 'prev'
2600
2600
2601 chain = r._deltachain(rev)[0]
2601 chain = r._deltachain(rev)[0]
2602 for iterrev in chain:
2602 for iterrev in chain:
2603 e = index[iterrev]
2603 e = index[iterrev]
2604 chainsize += e[1]
2604 chainsize += e[1]
2605
2605
2606 return compsize, uncompsize, deltatype, chain, chainsize
2606 return compsize, uncompsize, deltatype, chain, chainsize
2607
2607
2608 fm = ui.formatter('debugdeltachain', opts)
2608 fm = ui.formatter('debugdeltachain', opts)
2609
2609
2610 fm.plain(' rev chain# chainlen prev delta '
2610 fm.plain(' rev chain# chainlen prev delta '
2611 'size rawsize chainsize ratio lindist extradist '
2611 'size rawsize chainsize ratio lindist extradist '
2612 'extraratio\n')
2612 'extraratio\n')
2613
2613
2614 chainbases = {}
2614 chainbases = {}
2615 for rev in r:
2615 for rev in r:
2616 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2616 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2617 chainbase = chain[0]
2617 chainbase = chain[0]
2618 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2618 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2619 basestart = r.start(chainbase)
2619 basestart = r.start(chainbase)
2620 revstart = r.start(rev)
2620 revstart = r.start(rev)
2621 lineardist = revstart + comp - basestart
2621 lineardist = revstart + comp - basestart
2622 extradist = lineardist - chainsize
2622 extradist = lineardist - chainsize
2623 try:
2623 try:
2624 prevrev = chain[-2]
2624 prevrev = chain[-2]
2625 except IndexError:
2625 except IndexError:
2626 prevrev = -1
2626 prevrev = -1
2627
2627
2628 chainratio = float(chainsize) / float(uncomp)
2628 chainratio = float(chainsize) / float(uncomp)
2629 extraratio = float(extradist) / float(chainsize)
2629 extraratio = float(extradist) / float(chainsize)
2630
2630
2631 fm.startitem()
2631 fm.startitem()
2632 fm.write('rev chainid chainlen prevrev deltatype compsize '
2632 fm.write('rev chainid chainlen prevrev deltatype compsize '
2633 'uncompsize chainsize chainratio lindist extradist '
2633 'uncompsize chainsize chainratio lindist extradist '
2634 'extraratio',
2634 'extraratio',
2635 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2635 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2636 rev, chainid, len(chain), prevrev, deltatype, comp,
2636 rev, chainid, len(chain), prevrev, deltatype, comp,
2637 uncomp, chainsize, chainratio, lineardist, extradist,
2637 uncomp, chainsize, chainratio, lineardist, extradist,
2638 extraratio,
2638 extraratio,
2639 rev=rev, chainid=chainid, chainlen=len(chain),
2639 rev=rev, chainid=chainid, chainlen=len(chain),
2640 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2640 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2641 uncompsize=uncomp, chainsize=chainsize,
2641 uncompsize=uncomp, chainsize=chainsize,
2642 chainratio=chainratio, lindist=lineardist,
2642 chainratio=chainratio, lindist=lineardist,
2643 extradist=extradist, extraratio=extraratio)
2643 extradist=extradist, extraratio=extraratio)
2644
2644
2645 fm.end()
2645 fm.end()
2646
2646
2647 @command('debuginstall', [], '', norepo=True)
2647 @command('debuginstall', [], '', norepo=True)
2648 def debuginstall(ui):
2648 def debuginstall(ui):
2649 '''test Mercurial installation
2649 '''test Mercurial installation
2650
2650
2651 Returns 0 on success.
2651 Returns 0 on success.
2652 '''
2652 '''
2653
2653
2654 def writetemp(contents):
2654 def writetemp(contents):
2655 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2655 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2656 f = os.fdopen(fd, "wb")
2656 f = os.fdopen(fd, "wb")
2657 f.write(contents)
2657 f.write(contents)
2658 f.close()
2658 f.close()
2659 return name
2659 return name
2660
2660
2661 problems = 0
2661 problems = 0
2662
2662
2663 # encoding
2663 # encoding
2664 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2664 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2665 try:
2665 try:
2666 encoding.fromlocal("test")
2666 encoding.fromlocal("test")
2667 except error.Abort as inst:
2667 except error.Abort as inst:
2668 ui.write(" %s\n" % inst)
2668 ui.write(" %s\n" % inst)
2669 ui.write(_(" (check that your locale is properly set)\n"))
2669 ui.write(_(" (check that your locale is properly set)\n"))
2670 problems += 1
2670 problems += 1
2671
2671
2672 # Python
2672 # Python
2673 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2673 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2674 ui.status(_("checking Python version (%s)\n")
2674 ui.status(_("checking Python version (%s)\n")
2675 % ("%s.%s.%s" % sys.version_info[:3]))
2675 % ("%s.%s.%s" % sys.version_info[:3]))
2676 ui.status(_("checking Python lib (%s)...\n")
2676 ui.status(_("checking Python lib (%s)...\n")
2677 % os.path.dirname(os.__file__))
2677 % os.path.dirname(os.__file__))
2678
2678
2679 # compiled modules
2679 # compiled modules
2680 ui.status(_("checking installed modules (%s)...\n")
2680 ui.status(_("checking installed modules (%s)...\n")
2681 % os.path.dirname(__file__))
2681 % os.path.dirname(__file__))
2682 try:
2682 try:
2683 import bdiff, mpatch, base85, osutil
2683 import bdiff, mpatch, base85, osutil
2684 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2684 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2685 except Exception as inst:
2685 except Exception as inst:
2686 ui.write(" %s\n" % inst)
2686 ui.write(" %s\n" % inst)
2687 ui.write(_(" One or more extensions could not be found"))
2687 ui.write(_(" One or more extensions could not be found"))
2688 ui.write(_(" (check that you compiled the extensions)\n"))
2688 ui.write(_(" (check that you compiled the extensions)\n"))
2689 problems += 1
2689 problems += 1
2690
2690
2691 # templates
2691 # templates
2692 import templater
2692 import templater
2693 p = templater.templatepaths()
2693 p = templater.templatepaths()
2694 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2694 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2695 if p:
2695 if p:
2696 m = templater.templatepath("map-cmdline.default")
2696 m = templater.templatepath("map-cmdline.default")
2697 if m:
2697 if m:
2698 # template found, check if it is working
2698 # template found, check if it is working
2699 try:
2699 try:
2700 templater.templater(m)
2700 templater.templater(m)
2701 except Exception as inst:
2701 except Exception as inst:
2702 ui.write(" %s\n" % inst)
2702 ui.write(" %s\n" % inst)
2703 p = None
2703 p = None
2704 else:
2704 else:
2705 ui.write(_(" template 'default' not found\n"))
2705 ui.write(_(" template 'default' not found\n"))
2706 p = None
2706 p = None
2707 else:
2707 else:
2708 ui.write(_(" no template directories found\n"))
2708 ui.write(_(" no template directories found\n"))
2709 if not p:
2709 if not p:
2710 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2710 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2711 problems += 1
2711 problems += 1
2712
2712
2713 # editor
2713 # editor
2714 ui.status(_("checking commit editor...\n"))
2714 ui.status(_("checking commit editor...\n"))
2715 editor = ui.geteditor()
2715 editor = ui.geteditor()
2716 editor = util.expandpath(editor)
2716 editor = util.expandpath(editor)
2717 cmdpath = util.findexe(shlex.split(editor)[0])
2717 cmdpath = util.findexe(shlex.split(editor)[0])
2718 if not cmdpath:
2718 if not cmdpath:
2719 if editor == 'vi':
2719 if editor == 'vi':
2720 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2720 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2721 ui.write(_(" (specify a commit editor in your configuration"
2721 ui.write(_(" (specify a commit editor in your configuration"
2722 " file)\n"))
2722 " file)\n"))
2723 else:
2723 else:
2724 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2724 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2725 ui.write(_(" (specify a commit editor in your configuration"
2725 ui.write(_(" (specify a commit editor in your configuration"
2726 " file)\n"))
2726 " file)\n"))
2727 problems += 1
2727 problems += 1
2728
2728
2729 # check username
2729 # check username
2730 ui.status(_("checking username...\n"))
2730 ui.status(_("checking username...\n"))
2731 try:
2731 try:
2732 ui.username()
2732 ui.username()
2733 except error.Abort as e:
2733 except error.Abort as e:
2734 ui.write(" %s\n" % e)
2734 ui.write(" %s\n" % e)
2735 ui.write(_(" (specify a username in your configuration file)\n"))
2735 ui.write(_(" (specify a username in your configuration file)\n"))
2736 problems += 1
2736 problems += 1
2737
2737
2738 if not problems:
2738 if not problems:
2739 ui.status(_("no problems detected\n"))
2739 ui.status(_("no problems detected\n"))
2740 else:
2740 else:
2741 ui.write(_("%s problems detected,"
2741 ui.write(_("%s problems detected,"
2742 " please check your install!\n") % problems)
2742 " please check your install!\n") % problems)
2743
2743
2744 return problems
2744 return problems
2745
2745
2746 @command('debugknown', [], _('REPO ID...'), norepo=True)
2746 @command('debugknown', [], _('REPO ID...'), norepo=True)
2747 def debugknown(ui, repopath, *ids, **opts):
2747 def debugknown(ui, repopath, *ids, **opts):
2748 """test whether node ids are known to a repo
2748 """test whether node ids are known to a repo
2749
2749
2750 Every ID must be a full-length hex node id string. Returns a list of 0s
2750 Every ID must be a full-length hex node id string. Returns a list of 0s
2751 and 1s indicating unknown/known.
2751 and 1s indicating unknown/known.
2752 """
2752 """
2753 repo = hg.peer(ui, opts, repopath)
2753 repo = hg.peer(ui, opts, repopath)
2754 if not repo.capable('known'):
2754 if not repo.capable('known'):
2755 raise error.Abort("known() not supported by target repository")
2755 raise error.Abort("known() not supported by target repository")
2756 flags = repo.known([bin(s) for s in ids])
2756 flags = repo.known([bin(s) for s in ids])
2757 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2757 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2758
2758
2759 @command('debuglabelcomplete', [], _('LABEL...'))
2759 @command('debuglabelcomplete', [], _('LABEL...'))
2760 def debuglabelcomplete(ui, repo, *args):
2760 def debuglabelcomplete(ui, repo, *args):
2761 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2761 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2762 debugnamecomplete(ui, repo, *args)
2762 debugnamecomplete(ui, repo, *args)
2763
2763
2764 @command('debugmergestate', [], '')
2764 @command('debugmergestate', [], '')
2765 def debugmergestate(ui, repo, *args):
2765 def debugmergestate(ui, repo, *args):
2766 """print merge state
2766 """print merge state
2767
2767
2768 Use --verbose to print out information about whether v1 or v2 merge state
2768 Use --verbose to print out information about whether v1 or v2 merge state
2769 was chosen."""
2769 was chosen."""
2770 def _hashornull(h):
2770 def _hashornull(h):
2771 if h == nullhex:
2771 if h == nullhex:
2772 return 'null'
2772 return 'null'
2773 else:
2773 else:
2774 return h
2774 return h
2775
2775
2776 def printrecords(version):
2776 def printrecords(version):
2777 ui.write(('* version %s records\n') % version)
2777 ui.write(('* version %s records\n') % version)
2778 if version == 1:
2778 if version == 1:
2779 records = v1records
2779 records = v1records
2780 else:
2780 else:
2781 records = v2records
2781 records = v2records
2782
2782
2783 for rtype, record in records:
2783 for rtype, record in records:
2784 # pretty print some record types
2784 # pretty print some record types
2785 if rtype == 'L':
2785 if rtype == 'L':
2786 ui.write(('local: %s\n') % record)
2786 ui.write(('local: %s\n') % record)
2787 elif rtype == 'O':
2787 elif rtype == 'O':
2788 ui.write(('other: %s\n') % record)
2788 ui.write(('other: %s\n') % record)
2789 elif rtype == 'm':
2789 elif rtype == 'm':
2790 driver, mdstate = record.split('\0', 1)
2790 driver, mdstate = record.split('\0', 1)
2791 ui.write(('merge driver: %s (state "%s")\n')
2791 ui.write(('merge driver: %s (state "%s")\n')
2792 % (driver, mdstate))
2792 % (driver, mdstate))
2793 elif rtype in 'FDC':
2793 elif rtype in 'FDC':
2794 r = record.split('\0')
2794 r = record.split('\0')
2795 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2795 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2796 if version == 1:
2796 if version == 1:
2797 onode = 'not stored in v1 format'
2797 onode = 'not stored in v1 format'
2798 flags = r[7]
2798 flags = r[7]
2799 else:
2799 else:
2800 onode, flags = r[7:9]
2800 onode, flags = r[7:9]
2801 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2801 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2802 % (f, rtype, state, _hashornull(hash)))
2802 % (f, rtype, state, _hashornull(hash)))
2803 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2803 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2804 ui.write((' ancestor path: %s (node %s)\n')
2804 ui.write((' ancestor path: %s (node %s)\n')
2805 % (afile, _hashornull(anode)))
2805 % (afile, _hashornull(anode)))
2806 ui.write((' other path: %s (node %s)\n')
2806 ui.write((' other path: %s (node %s)\n')
2807 % (ofile, _hashornull(onode)))
2807 % (ofile, _hashornull(onode)))
2808 else:
2808 else:
2809 ui.write(('unrecognized entry: %s\t%s\n')
2809 ui.write(('unrecognized entry: %s\t%s\n')
2810 % (rtype, record.replace('\0', '\t')))
2810 % (rtype, record.replace('\0', '\t')))
2811
2811
2812 # Avoid mergestate.read() since it may raise an exception for unsupported
2812 # Avoid mergestate.read() since it may raise an exception for unsupported
2813 # merge state records. We shouldn't be doing this, but this is OK since this
2813 # merge state records. We shouldn't be doing this, but this is OK since this
2814 # command is pretty low-level.
2814 # command is pretty low-level.
2815 ms = mergemod.mergestate(repo)
2815 ms = mergemod.mergestate(repo)
2816
2816
2817 # sort so that reasonable information is on top
2817 # sort so that reasonable information is on top
2818 v1records = ms._readrecordsv1()
2818 v1records = ms._readrecordsv1()
2819 v2records = ms._readrecordsv2()
2819 v2records = ms._readrecordsv2()
2820 order = 'LOm'
2820 order = 'LOm'
2821 def key(r):
2821 def key(r):
2822 idx = order.find(r[0])
2822 idx = order.find(r[0])
2823 if idx == -1:
2823 if idx == -1:
2824 return (1, r[1])
2824 return (1, r[1])
2825 else:
2825 else:
2826 return (0, idx)
2826 return (0, idx)
2827 v1records.sort(key=key)
2827 v1records.sort(key=key)
2828 v2records.sort(key=key)
2828 v2records.sort(key=key)
2829
2829
2830 if not v1records and not v2records:
2830 if not v1records and not v2records:
2831 ui.write(('no merge state found\n'))
2831 ui.write(('no merge state found\n'))
2832 elif not v2records:
2832 elif not v2records:
2833 ui.note(('no version 2 merge state\n'))
2833 ui.note(('no version 2 merge state\n'))
2834 printrecords(1)
2834 printrecords(1)
2835 elif ms._v1v2match(v1records, v2records):
2835 elif ms._v1v2match(v1records, v2records):
2836 ui.note(('v1 and v2 states match: using v2\n'))
2836 ui.note(('v1 and v2 states match: using v2\n'))
2837 printrecords(2)
2837 printrecords(2)
2838 else:
2838 else:
2839 ui.note(('v1 and v2 states mismatch: using v1\n'))
2839 ui.note(('v1 and v2 states mismatch: using v1\n'))
2840 printrecords(1)
2840 printrecords(1)
2841 if ui.verbose:
2841 if ui.verbose:
2842 printrecords(2)
2842 printrecords(2)
2843
2843
2844 @command('debugnamecomplete', [], _('NAME...'))
2844 @command('debugnamecomplete', [], _('NAME...'))
2845 def debugnamecomplete(ui, repo, *args):
2845 def debugnamecomplete(ui, repo, *args):
2846 '''complete "names" - tags, open branch names, bookmark names'''
2846 '''complete "names" - tags, open branch names, bookmark names'''
2847
2847
2848 names = set()
2848 names = set()
2849 # since we previously only listed open branches, we will handle that
2849 # since we previously only listed open branches, we will handle that
2850 # specially (after this for loop)
2850 # specially (after this for loop)
2851 for name, ns in repo.names.iteritems():
2851 for name, ns in repo.names.iteritems():
2852 if name != 'branches':
2852 if name != 'branches':
2853 names.update(ns.listnames(repo))
2853 names.update(ns.listnames(repo))
2854 names.update(tag for (tag, heads, tip, closed)
2854 names.update(tag for (tag, heads, tip, closed)
2855 in repo.branchmap().iterbranches() if not closed)
2855 in repo.branchmap().iterbranches() if not closed)
2856 completions = set()
2856 completions = set()
2857 if not args:
2857 if not args:
2858 args = ['']
2858 args = ['']
2859 for a in args:
2859 for a in args:
2860 completions.update(n for n in names if n.startswith(a))
2860 completions.update(n for n in names if n.startswith(a))
2861 ui.write('\n'.join(sorted(completions)))
2861 ui.write('\n'.join(sorted(completions)))
2862 ui.write('\n')
2862 ui.write('\n')
2863
2863
2864 @command('debuglocks',
2864 @command('debuglocks',
2865 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2865 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2866 ('W', 'force-wlock', None,
2866 ('W', 'force-wlock', None,
2867 _('free the working state lock (DANGEROUS)'))],
2867 _('free the working state lock (DANGEROUS)'))],
2868 _('[OPTION]...'))
2868 _('[OPTION]...'))
2869 def debuglocks(ui, repo, **opts):
2869 def debuglocks(ui, repo, **opts):
2870 """show or modify state of locks
2870 """show or modify state of locks
2871
2871
2872 By default, this command will show which locks are held. This
2872 By default, this command will show which locks are held. This
2873 includes the user and process holding the lock, the amount of time
2873 includes the user and process holding the lock, the amount of time
2874 the lock has been held, and the machine name where the process is
2874 the lock has been held, and the machine name where the process is
2875 running if it's not local.
2875 running if it's not local.
2876
2876
2877 Locks protect the integrity of Mercurial's data, so should be
2877 Locks protect the integrity of Mercurial's data, so should be
2878 treated with care. System crashes or other interruptions may cause
2878 treated with care. System crashes or other interruptions may cause
2879 locks to not be properly released, though Mercurial will usually
2879 locks to not be properly released, though Mercurial will usually
2880 detect and remove such stale locks automatically.
2880 detect and remove such stale locks automatically.
2881
2881
2882 However, detecting stale locks may not always be possible (for
2882 However, detecting stale locks may not always be possible (for
2883 instance, on a shared filesystem). Removing locks may also be
2883 instance, on a shared filesystem). Removing locks may also be
2884 blocked by filesystem permissions.
2884 blocked by filesystem permissions.
2885
2885
2886 Returns 0 if no locks are held.
2886 Returns 0 if no locks are held.
2887
2887
2888 """
2888 """
2889
2889
2890 if opts.get('force_lock'):
2890 if opts.get('force_lock'):
2891 repo.svfs.unlink('lock')
2891 repo.svfs.unlink('lock')
2892 if opts.get('force_wlock'):
2892 if opts.get('force_wlock'):
2893 repo.vfs.unlink('wlock')
2893 repo.vfs.unlink('wlock')
2894 if opts.get('force_lock') or opts.get('force_lock'):
2894 if opts.get('force_lock') or opts.get('force_lock'):
2895 return 0
2895 return 0
2896
2896
2897 now = time.time()
2897 now = time.time()
2898 held = 0
2898 held = 0
2899
2899
2900 def report(vfs, name, method):
2900 def report(vfs, name, method):
2901 # this causes stale locks to get reaped for more accurate reporting
2901 # this causes stale locks to get reaped for more accurate reporting
2902 try:
2902 try:
2903 l = method(False)
2903 l = method(False)
2904 except error.LockHeld:
2904 except error.LockHeld:
2905 l = None
2905 l = None
2906
2906
2907 if l:
2907 if l:
2908 l.release()
2908 l.release()
2909 else:
2909 else:
2910 try:
2910 try:
2911 stat = vfs.lstat(name)
2911 stat = vfs.lstat(name)
2912 age = now - stat.st_mtime
2912 age = now - stat.st_mtime
2913 user = util.username(stat.st_uid)
2913 user = util.username(stat.st_uid)
2914 locker = vfs.readlock(name)
2914 locker = vfs.readlock(name)
2915 if ":" in locker:
2915 if ":" in locker:
2916 host, pid = locker.split(':')
2916 host, pid = locker.split(':')
2917 if host == socket.gethostname():
2917 if host == socket.gethostname():
2918 locker = 'user %s, process %s' % (user, pid)
2918 locker = 'user %s, process %s' % (user, pid)
2919 else:
2919 else:
2920 locker = 'user %s, process %s, host %s' \
2920 locker = 'user %s, process %s, host %s' \
2921 % (user, pid, host)
2921 % (user, pid, host)
2922 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2922 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2923 return 1
2923 return 1
2924 except OSError as e:
2924 except OSError as e:
2925 if e.errno != errno.ENOENT:
2925 if e.errno != errno.ENOENT:
2926 raise
2926 raise
2927
2927
2928 ui.write("%-6s free\n" % (name + ":"))
2928 ui.write("%-6s free\n" % (name + ":"))
2929 return 0
2929 return 0
2930
2930
2931 held += report(repo.svfs, "lock", repo.lock)
2931 held += report(repo.svfs, "lock", repo.lock)
2932 held += report(repo.vfs, "wlock", repo.wlock)
2932 held += report(repo.vfs, "wlock", repo.wlock)
2933
2933
2934 return held
2934 return held
2935
2935
2936 @command('debugobsolete',
2936 @command('debugobsolete',
2937 [('', 'flags', 0, _('markers flag')),
2937 [('', 'flags', 0, _('markers flag')),
2938 ('', 'record-parents', False,
2938 ('', 'record-parents', False,
2939 _('record parent information for the precursor')),
2939 _('record parent information for the precursor')),
2940 ('r', 'rev', [], _('display markers relevant to REV')),
2940 ('r', 'rev', [], _('display markers relevant to REV')),
2941 ] + commitopts2,
2941 ] + commitopts2,
2942 _('[OBSOLETED [REPLACEMENT ...]]'))
2942 _('[OBSOLETED [REPLACEMENT ...]]'))
2943 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2943 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2944 """create arbitrary obsolete marker
2944 """create arbitrary obsolete marker
2945
2945
2946 With no arguments, displays the list of obsolescence markers."""
2946 With no arguments, displays the list of obsolescence markers."""
2947
2947
2948 def parsenodeid(s):
2948 def parsenodeid(s):
2949 try:
2949 try:
2950 # We do not use revsingle/revrange functions here to accept
2950 # We do not use revsingle/revrange functions here to accept
2951 # arbitrary node identifiers, possibly not present in the
2951 # arbitrary node identifiers, possibly not present in the
2952 # local repository.
2952 # local repository.
2953 n = bin(s)
2953 n = bin(s)
2954 if len(n) != len(nullid):
2954 if len(n) != len(nullid):
2955 raise TypeError()
2955 raise TypeError()
2956 return n
2956 return n
2957 except TypeError:
2957 except TypeError:
2958 raise error.Abort('changeset references must be full hexadecimal '
2958 raise error.Abort('changeset references must be full hexadecimal '
2959 'node identifiers')
2959 'node identifiers')
2960
2960
2961 if precursor is not None:
2961 if precursor is not None:
2962 if opts['rev']:
2962 if opts['rev']:
2963 raise error.Abort('cannot select revision when creating marker')
2963 raise error.Abort('cannot select revision when creating marker')
2964 metadata = {}
2964 metadata = {}
2965 metadata['user'] = opts['user'] or ui.username()
2965 metadata['user'] = opts['user'] or ui.username()
2966 succs = tuple(parsenodeid(succ) for succ in successors)
2966 succs = tuple(parsenodeid(succ) for succ in successors)
2967 l = repo.lock()
2967 l = repo.lock()
2968 try:
2968 try:
2969 tr = repo.transaction('debugobsolete')
2969 tr = repo.transaction('debugobsolete')
2970 try:
2970 try:
2971 date = opts.get('date')
2971 date = opts.get('date')
2972 if date:
2972 if date:
2973 date = util.parsedate(date)
2973 date = util.parsedate(date)
2974 else:
2974 else:
2975 date = None
2975 date = None
2976 prec = parsenodeid(precursor)
2976 prec = parsenodeid(precursor)
2977 parents = None
2977 parents = None
2978 if opts['record_parents']:
2978 if opts['record_parents']:
2979 if prec not in repo.unfiltered():
2979 if prec not in repo.unfiltered():
2980 raise error.Abort('cannot used --record-parents on '
2980 raise error.Abort('cannot used --record-parents on '
2981 'unknown changesets')
2981 'unknown changesets')
2982 parents = repo.unfiltered()[prec].parents()
2982 parents = repo.unfiltered()[prec].parents()
2983 parents = tuple(p.node() for p in parents)
2983 parents = tuple(p.node() for p in parents)
2984 repo.obsstore.create(tr, prec, succs, opts['flags'],
2984 repo.obsstore.create(tr, prec, succs, opts['flags'],
2985 parents=parents, date=date,
2985 parents=parents, date=date,
2986 metadata=metadata)
2986 metadata=metadata)
2987 tr.close()
2987 tr.close()
2988 except ValueError as exc:
2988 except ValueError as exc:
2989 raise error.Abort(_('bad obsmarker input: %s') % exc)
2989 raise error.Abort(_('bad obsmarker input: %s') % exc)
2990 finally:
2990 finally:
2991 tr.release()
2991 tr.release()
2992 finally:
2992 finally:
2993 l.release()
2993 l.release()
2994 else:
2994 else:
2995 if opts['rev']:
2995 if opts['rev']:
2996 revs = scmutil.revrange(repo, opts['rev'])
2996 revs = scmutil.revrange(repo, opts['rev'])
2997 nodes = [repo[r].node() for r in revs]
2997 nodes = [repo[r].node() for r in revs]
2998 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2998 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2999 markers.sort(key=lambda x: x._data)
2999 markers.sort(key=lambda x: x._data)
3000 else:
3000 else:
3001 markers = obsolete.getmarkers(repo)
3001 markers = obsolete.getmarkers(repo)
3002
3002
3003 for m in markers:
3003 for m in markers:
3004 cmdutil.showmarker(ui, m)
3004 cmdutil.showmarker(ui, m)
3005
3005
3006 @command('debugpathcomplete',
3006 @command('debugpathcomplete',
3007 [('f', 'full', None, _('complete an entire path')),
3007 [('f', 'full', None, _('complete an entire path')),
3008 ('n', 'normal', None, _('show only normal files')),
3008 ('n', 'normal', None, _('show only normal files')),
3009 ('a', 'added', None, _('show only added files')),
3009 ('a', 'added', None, _('show only added files')),
3010 ('r', 'removed', None, _('show only removed files'))],
3010 ('r', 'removed', None, _('show only removed files'))],
3011 _('FILESPEC...'))
3011 _('FILESPEC...'))
3012 def debugpathcomplete(ui, repo, *specs, **opts):
3012 def debugpathcomplete(ui, repo, *specs, **opts):
3013 '''complete part or all of a tracked path
3013 '''complete part or all of a tracked path
3014
3014
3015 This command supports shells that offer path name completion. It
3015 This command supports shells that offer path name completion. It
3016 currently completes only files already known to the dirstate.
3016 currently completes only files already known to the dirstate.
3017
3017
3018 Completion extends only to the next path segment unless
3018 Completion extends only to the next path segment unless
3019 --full is specified, in which case entire paths are used.'''
3019 --full is specified, in which case entire paths are used.'''
3020
3020
3021 def complete(path, acceptable):
3021 def complete(path, acceptable):
3022 dirstate = repo.dirstate
3022 dirstate = repo.dirstate
3023 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3023 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3024 rootdir = repo.root + os.sep
3024 rootdir = repo.root + os.sep
3025 if spec != repo.root and not spec.startswith(rootdir):
3025 if spec != repo.root and not spec.startswith(rootdir):
3026 return [], []
3026 return [], []
3027 if os.path.isdir(spec):
3027 if os.path.isdir(spec):
3028 spec += '/'
3028 spec += '/'
3029 spec = spec[len(rootdir):]
3029 spec = spec[len(rootdir):]
3030 fixpaths = os.sep != '/'
3030 fixpaths = os.sep != '/'
3031 if fixpaths:
3031 if fixpaths:
3032 spec = spec.replace(os.sep, '/')
3032 spec = spec.replace(os.sep, '/')
3033 speclen = len(spec)
3033 speclen = len(spec)
3034 fullpaths = opts['full']
3034 fullpaths = opts['full']
3035 files, dirs = set(), set()
3035 files, dirs = set(), set()
3036 adddir, addfile = dirs.add, files.add
3036 adddir, addfile = dirs.add, files.add
3037 for f, st in dirstate.iteritems():
3037 for f, st in dirstate.iteritems():
3038 if f.startswith(spec) and st[0] in acceptable:
3038 if f.startswith(spec) and st[0] in acceptable:
3039 if fixpaths:
3039 if fixpaths:
3040 f = f.replace('/', os.sep)
3040 f = f.replace('/', os.sep)
3041 if fullpaths:
3041 if fullpaths:
3042 addfile(f)
3042 addfile(f)
3043 continue
3043 continue
3044 s = f.find(os.sep, speclen)
3044 s = f.find(os.sep, speclen)
3045 if s >= 0:
3045 if s >= 0:
3046 adddir(f[:s])
3046 adddir(f[:s])
3047 else:
3047 else:
3048 addfile(f)
3048 addfile(f)
3049 return files, dirs
3049 return files, dirs
3050
3050
3051 acceptable = ''
3051 acceptable = ''
3052 if opts['normal']:
3052 if opts['normal']:
3053 acceptable += 'nm'
3053 acceptable += 'nm'
3054 if opts['added']:
3054 if opts['added']:
3055 acceptable += 'a'
3055 acceptable += 'a'
3056 if opts['removed']:
3056 if opts['removed']:
3057 acceptable += 'r'
3057 acceptable += 'r'
3058 cwd = repo.getcwd()
3058 cwd = repo.getcwd()
3059 if not specs:
3059 if not specs:
3060 specs = ['.']
3060 specs = ['.']
3061
3061
3062 files, dirs = set(), set()
3062 files, dirs = set(), set()
3063 for spec in specs:
3063 for spec in specs:
3064 f, d = complete(spec, acceptable or 'nmar')
3064 f, d = complete(spec, acceptable or 'nmar')
3065 files.update(f)
3065 files.update(f)
3066 dirs.update(d)
3066 dirs.update(d)
3067 files.update(dirs)
3067 files.update(dirs)
3068 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3068 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3069 ui.write('\n')
3069 ui.write('\n')
3070
3070
3071 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3071 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3072 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3072 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3073 '''access the pushkey key/value protocol
3073 '''access the pushkey key/value protocol
3074
3074
3075 With two args, list the keys in the given namespace.
3075 With two args, list the keys in the given namespace.
3076
3076
3077 With five args, set a key to new if it currently is set to old.
3077 With five args, set a key to new if it currently is set to old.
3078 Reports success or failure.
3078 Reports success or failure.
3079 '''
3079 '''
3080
3080
3081 target = hg.peer(ui, {}, repopath)
3081 target = hg.peer(ui, {}, repopath)
3082 if keyinfo:
3082 if keyinfo:
3083 key, old, new = keyinfo
3083 key, old, new = keyinfo
3084 r = target.pushkey(namespace, key, old, new)
3084 r = target.pushkey(namespace, key, old, new)
3085 ui.status(str(r) + '\n')
3085 ui.status(str(r) + '\n')
3086 return not r
3086 return not r
3087 else:
3087 else:
3088 for k, v in sorted(target.listkeys(namespace).iteritems()):
3088 for k, v in sorted(target.listkeys(namespace).iteritems()):
3089 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3089 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3090 v.encode('string-escape')))
3090 v.encode('string-escape')))
3091
3091
3092 @command('debugpvec', [], _('A B'))
3092 @command('debugpvec', [], _('A B'))
3093 def debugpvec(ui, repo, a, b=None):
3093 def debugpvec(ui, repo, a, b=None):
3094 ca = scmutil.revsingle(repo, a)
3094 ca = scmutil.revsingle(repo, a)
3095 cb = scmutil.revsingle(repo, b)
3095 cb = scmutil.revsingle(repo, b)
3096 pa = pvec.ctxpvec(ca)
3096 pa = pvec.ctxpvec(ca)
3097 pb = pvec.ctxpvec(cb)
3097 pb = pvec.ctxpvec(cb)
3098 if pa == pb:
3098 if pa == pb:
3099 rel = "="
3099 rel = "="
3100 elif pa > pb:
3100 elif pa > pb:
3101 rel = ">"
3101 rel = ">"
3102 elif pa < pb:
3102 elif pa < pb:
3103 rel = "<"
3103 rel = "<"
3104 elif pa | pb:
3104 elif pa | pb:
3105 rel = "|"
3105 rel = "|"
3106 ui.write(_("a: %s\n") % pa)
3106 ui.write(_("a: %s\n") % pa)
3107 ui.write(_("b: %s\n") % pb)
3107 ui.write(_("b: %s\n") % pb)
3108 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3108 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3109 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3109 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3110 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3110 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3111 pa.distance(pb), rel))
3111 pa.distance(pb), rel))
3112
3112
3113 @command('debugrebuilddirstate|debugrebuildstate',
3113 @command('debugrebuilddirstate|debugrebuildstate',
3114 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3114 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3115 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3115 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3116 'the working copy parent')),
3116 'the working copy parent')),
3117 ],
3117 ],
3118 _('[-r REV]'))
3118 _('[-r REV]'))
3119 def debugrebuilddirstate(ui, repo, rev, **opts):
3119 def debugrebuilddirstate(ui, repo, rev, **opts):
3120 """rebuild the dirstate as it would look like for the given revision
3120 """rebuild the dirstate as it would look like for the given revision
3121
3121
3122 If no revision is specified the first current parent will be used.
3122 If no revision is specified the first current parent will be used.
3123
3123
3124 The dirstate will be set to the files of the given revision.
3124 The dirstate will be set to the files of the given revision.
3125 The actual working directory content or existing dirstate
3125 The actual working directory content or existing dirstate
3126 information such as adds or removes is not considered.
3126 information such as adds or removes is not considered.
3127
3127
3128 ``minimal`` will only rebuild the dirstate status for files that claim to be
3128 ``minimal`` will only rebuild the dirstate status for files that claim to be
3129 tracked but are not in the parent manifest, or that exist in the parent
3129 tracked but are not in the parent manifest, or that exist in the parent
3130 manifest but are not in the dirstate. It will not change adds, removes, or
3130 manifest but are not in the dirstate. It will not change adds, removes, or
3131 modified files that are in the working copy parent.
3131 modified files that are in the working copy parent.
3132
3132
3133 One use of this command is to make the next :hg:`status` invocation
3133 One use of this command is to make the next :hg:`status` invocation
3134 check the actual file content.
3134 check the actual file content.
3135 """
3135 """
3136 ctx = scmutil.revsingle(repo, rev)
3136 ctx = scmutil.revsingle(repo, rev)
3137 wlock = repo.wlock()
3137 wlock = repo.wlock()
3138 try:
3138 try:
3139 dirstate = repo.dirstate
3139 dirstate = repo.dirstate
3140 changedfiles = None
3140 changedfiles = None
3141 # See command doc for what minimal does.
3141 # See command doc for what minimal does.
3142 if opts.get('minimal'):
3142 if opts.get('minimal'):
3143 manifestfiles = set(ctx.manifest().keys())
3143 manifestfiles = set(ctx.manifest().keys())
3144 dirstatefiles = set(dirstate)
3144 dirstatefiles = set(dirstate)
3145 manifestonly = manifestfiles - dirstatefiles
3145 manifestonly = manifestfiles - dirstatefiles
3146 dsonly = dirstatefiles - manifestfiles
3146 dsonly = dirstatefiles - manifestfiles
3147 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3147 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3148 changedfiles = manifestonly | dsnotadded
3148 changedfiles = manifestonly | dsnotadded
3149
3149
3150 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3150 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3151 finally:
3151 finally:
3152 wlock.release()
3152 wlock.release()
3153
3153
3154 @command('debugrebuildfncache', [], '')
3154 @command('debugrebuildfncache', [], '')
3155 def debugrebuildfncache(ui, repo):
3155 def debugrebuildfncache(ui, repo):
3156 """rebuild the fncache file"""
3156 """rebuild the fncache file"""
3157 repair.rebuildfncache(ui, repo)
3157 repair.rebuildfncache(ui, repo)
3158
3158
3159 @command('debugrename',
3159 @command('debugrename',
3160 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3160 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3161 _('[-r REV] FILE'))
3161 _('[-r REV] FILE'))
3162 def debugrename(ui, repo, file1, *pats, **opts):
3162 def debugrename(ui, repo, file1, *pats, **opts):
3163 """dump rename information"""
3163 """dump rename information"""
3164
3164
3165 ctx = scmutil.revsingle(repo, opts.get('rev'))
3165 ctx = scmutil.revsingle(repo, opts.get('rev'))
3166 m = scmutil.match(ctx, (file1,) + pats, opts)
3166 m = scmutil.match(ctx, (file1,) + pats, opts)
3167 for abs in ctx.walk(m):
3167 for abs in ctx.walk(m):
3168 fctx = ctx[abs]
3168 fctx = ctx[abs]
3169 o = fctx.filelog().renamed(fctx.filenode())
3169 o = fctx.filelog().renamed(fctx.filenode())
3170 rel = m.rel(abs)
3170 rel = m.rel(abs)
3171 if o:
3171 if o:
3172 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3172 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3173 else:
3173 else:
3174 ui.write(_("%s not renamed\n") % rel)
3174 ui.write(_("%s not renamed\n") % rel)
3175
3175
3176 @command('debugrevlog', debugrevlogopts +
3176 @command('debugrevlog', debugrevlogopts +
3177 [('d', 'dump', False, _('dump index data'))],
3177 [('d', 'dump', False, _('dump index data'))],
3178 _('-c|-m|FILE'),
3178 _('-c|-m|FILE'),
3179 optionalrepo=True)
3179 optionalrepo=True)
3180 def debugrevlog(ui, repo, file_=None, **opts):
3180 def debugrevlog(ui, repo, file_=None, **opts):
3181 """show data and statistics about a revlog"""
3181 """show data and statistics about a revlog"""
3182 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3182 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3183
3183
3184 if opts.get("dump"):
3184 if opts.get("dump"):
3185 numrevs = len(r)
3185 numrevs = len(r)
3186 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3186 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3187 " rawsize totalsize compression heads chainlen\n")
3187 " rawsize totalsize compression heads chainlen\n")
3188 ts = 0
3188 ts = 0
3189 heads = set()
3189 heads = set()
3190
3190
3191 for rev in xrange(numrevs):
3191 for rev in xrange(numrevs):
3192 dbase = r.deltaparent(rev)
3192 dbase = r.deltaparent(rev)
3193 if dbase == -1:
3193 if dbase == -1:
3194 dbase = rev
3194 dbase = rev
3195 cbase = r.chainbase(rev)
3195 cbase = r.chainbase(rev)
3196 clen = r.chainlen(rev)
3196 clen = r.chainlen(rev)
3197 p1, p2 = r.parentrevs(rev)
3197 p1, p2 = r.parentrevs(rev)
3198 rs = r.rawsize(rev)
3198 rs = r.rawsize(rev)
3199 ts = ts + rs
3199 ts = ts + rs
3200 heads -= set(r.parentrevs(rev))
3200 heads -= set(r.parentrevs(rev))
3201 heads.add(rev)
3201 heads.add(rev)
3202 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3202 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3203 "%11d %5d %8d\n" %
3203 "%11d %5d %8d\n" %
3204 (rev, p1, p2, r.start(rev), r.end(rev),
3204 (rev, p1, p2, r.start(rev), r.end(rev),
3205 r.start(dbase), r.start(cbase),
3205 r.start(dbase), r.start(cbase),
3206 r.start(p1), r.start(p2),
3206 r.start(p1), r.start(p2),
3207 rs, ts, ts / r.end(rev), len(heads), clen))
3207 rs, ts, ts / r.end(rev), len(heads), clen))
3208 return 0
3208 return 0
3209
3209
3210 v = r.version
3210 v = r.version
3211 format = v & 0xFFFF
3211 format = v & 0xFFFF
3212 flags = []
3212 flags = []
3213 gdelta = False
3213 gdelta = False
3214 if v & revlog.REVLOGNGINLINEDATA:
3214 if v & revlog.REVLOGNGINLINEDATA:
3215 flags.append('inline')
3215 flags.append('inline')
3216 if v & revlog.REVLOGGENERALDELTA:
3216 if v & revlog.REVLOGGENERALDELTA:
3217 gdelta = True
3217 gdelta = True
3218 flags.append('generaldelta')
3218 flags.append('generaldelta')
3219 if not flags:
3219 if not flags:
3220 flags = ['(none)']
3220 flags = ['(none)']
3221
3221
3222 nummerges = 0
3222 nummerges = 0
3223 numfull = 0
3223 numfull = 0
3224 numprev = 0
3224 numprev = 0
3225 nump1 = 0
3225 nump1 = 0
3226 nump2 = 0
3226 nump2 = 0
3227 numother = 0
3227 numother = 0
3228 nump1prev = 0
3228 nump1prev = 0
3229 nump2prev = 0
3229 nump2prev = 0
3230 chainlengths = []
3230 chainlengths = []
3231
3231
3232 datasize = [None, 0, 0L]
3232 datasize = [None, 0, 0L]
3233 fullsize = [None, 0, 0L]
3233 fullsize = [None, 0, 0L]
3234 deltasize = [None, 0, 0L]
3234 deltasize = [None, 0, 0L]
3235
3235
3236 def addsize(size, l):
3236 def addsize(size, l):
3237 if l[0] is None or size < l[0]:
3237 if l[0] is None or size < l[0]:
3238 l[0] = size
3238 l[0] = size
3239 if size > l[1]:
3239 if size > l[1]:
3240 l[1] = size
3240 l[1] = size
3241 l[2] += size
3241 l[2] += size
3242
3242
3243 numrevs = len(r)
3243 numrevs = len(r)
3244 for rev in xrange(numrevs):
3244 for rev in xrange(numrevs):
3245 p1, p2 = r.parentrevs(rev)
3245 p1, p2 = r.parentrevs(rev)
3246 delta = r.deltaparent(rev)
3246 delta = r.deltaparent(rev)
3247 if format > 0:
3247 if format > 0:
3248 addsize(r.rawsize(rev), datasize)
3248 addsize(r.rawsize(rev), datasize)
3249 if p2 != nullrev:
3249 if p2 != nullrev:
3250 nummerges += 1
3250 nummerges += 1
3251 size = r.length(rev)
3251 size = r.length(rev)
3252 if delta == nullrev:
3252 if delta == nullrev:
3253 chainlengths.append(0)
3253 chainlengths.append(0)
3254 numfull += 1
3254 numfull += 1
3255 addsize(size, fullsize)
3255 addsize(size, fullsize)
3256 else:
3256 else:
3257 chainlengths.append(chainlengths[delta] + 1)
3257 chainlengths.append(chainlengths[delta] + 1)
3258 addsize(size, deltasize)
3258 addsize(size, deltasize)
3259 if delta == rev - 1:
3259 if delta == rev - 1:
3260 numprev += 1
3260 numprev += 1
3261 if delta == p1:
3261 if delta == p1:
3262 nump1prev += 1
3262 nump1prev += 1
3263 elif delta == p2:
3263 elif delta == p2:
3264 nump2prev += 1
3264 nump2prev += 1
3265 elif delta == p1:
3265 elif delta == p1:
3266 nump1 += 1
3266 nump1 += 1
3267 elif delta == p2:
3267 elif delta == p2:
3268 nump2 += 1
3268 nump2 += 1
3269 elif delta != nullrev:
3269 elif delta != nullrev:
3270 numother += 1
3270 numother += 1
3271
3271
3272 # Adjust size min value for empty cases
3272 # Adjust size min value for empty cases
3273 for size in (datasize, fullsize, deltasize):
3273 for size in (datasize, fullsize, deltasize):
3274 if size[0] is None:
3274 if size[0] is None:
3275 size[0] = 0
3275 size[0] = 0
3276
3276
3277 numdeltas = numrevs - numfull
3277 numdeltas = numrevs - numfull
3278 numoprev = numprev - nump1prev - nump2prev
3278 numoprev = numprev - nump1prev - nump2prev
3279 totalrawsize = datasize[2]
3279 totalrawsize = datasize[2]
3280 datasize[2] /= numrevs
3280 datasize[2] /= numrevs
3281 fulltotal = fullsize[2]
3281 fulltotal = fullsize[2]
3282 fullsize[2] /= numfull
3282 fullsize[2] /= numfull
3283 deltatotal = deltasize[2]
3283 deltatotal = deltasize[2]
3284 if numrevs - numfull > 0:
3284 if numrevs - numfull > 0:
3285 deltasize[2] /= numrevs - numfull
3285 deltasize[2] /= numrevs - numfull
3286 totalsize = fulltotal + deltatotal
3286 totalsize = fulltotal + deltatotal
3287 avgchainlen = sum(chainlengths) / numrevs
3287 avgchainlen = sum(chainlengths) / numrevs
3288 maxchainlen = max(chainlengths)
3288 maxchainlen = max(chainlengths)
3289 compratio = 1
3289 compratio = 1
3290 if totalsize:
3290 if totalsize:
3291 compratio = totalrawsize / totalsize
3291 compratio = totalrawsize / totalsize
3292
3292
3293 basedfmtstr = '%%%dd\n'
3293 basedfmtstr = '%%%dd\n'
3294 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3294 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3295
3295
3296 def dfmtstr(max):
3296 def dfmtstr(max):
3297 return basedfmtstr % len(str(max))
3297 return basedfmtstr % len(str(max))
3298 def pcfmtstr(max, padding=0):
3298 def pcfmtstr(max, padding=0):
3299 return basepcfmtstr % (len(str(max)), ' ' * padding)
3299 return basepcfmtstr % (len(str(max)), ' ' * padding)
3300
3300
3301 def pcfmt(value, total):
3301 def pcfmt(value, total):
3302 if total:
3302 if total:
3303 return (value, 100 * float(value) / total)
3303 return (value, 100 * float(value) / total)
3304 else:
3304 else:
3305 return value, 100.0
3305 return value, 100.0
3306
3306
3307 ui.write(('format : %d\n') % format)
3307 ui.write(('format : %d\n') % format)
3308 ui.write(('flags : %s\n') % ', '.join(flags))
3308 ui.write(('flags : %s\n') % ', '.join(flags))
3309
3309
3310 ui.write('\n')
3310 ui.write('\n')
3311 fmt = pcfmtstr(totalsize)
3311 fmt = pcfmtstr(totalsize)
3312 fmt2 = dfmtstr(totalsize)
3312 fmt2 = dfmtstr(totalsize)
3313 ui.write(('revisions : ') + fmt2 % numrevs)
3313 ui.write(('revisions : ') + fmt2 % numrevs)
3314 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3314 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3315 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3315 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3316 ui.write(('revisions : ') + fmt2 % numrevs)
3316 ui.write(('revisions : ') + fmt2 % numrevs)
3317 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3317 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3318 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3318 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3319 ui.write(('revision size : ') + fmt2 % totalsize)
3319 ui.write(('revision size : ') + fmt2 % totalsize)
3320 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3320 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3321 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3321 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3322
3322
3323 ui.write('\n')
3323 ui.write('\n')
3324 fmt = dfmtstr(max(avgchainlen, compratio))
3324 fmt = dfmtstr(max(avgchainlen, compratio))
3325 ui.write(('avg chain length : ') + fmt % avgchainlen)
3325 ui.write(('avg chain length : ') + fmt % avgchainlen)
3326 ui.write(('max chain length : ') + fmt % maxchainlen)
3326 ui.write(('max chain length : ') + fmt % maxchainlen)
3327 ui.write(('compression ratio : ') + fmt % compratio)
3327 ui.write(('compression ratio : ') + fmt % compratio)
3328
3328
3329 if format > 0:
3329 if format > 0:
3330 ui.write('\n')
3330 ui.write('\n')
3331 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3331 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3332 % tuple(datasize))
3332 % tuple(datasize))
3333 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3333 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3334 % tuple(fullsize))
3334 % tuple(fullsize))
3335 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3335 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3336 % tuple(deltasize))
3336 % tuple(deltasize))
3337
3337
3338 if numdeltas > 0:
3338 if numdeltas > 0:
3339 ui.write('\n')
3339 ui.write('\n')
3340 fmt = pcfmtstr(numdeltas)
3340 fmt = pcfmtstr(numdeltas)
3341 fmt2 = pcfmtstr(numdeltas, 4)
3341 fmt2 = pcfmtstr(numdeltas, 4)
3342 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3342 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3343 if numprev > 0:
3343 if numprev > 0:
3344 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3344 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3345 numprev))
3345 numprev))
3346 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3346 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3347 numprev))
3347 numprev))
3348 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3348 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3349 numprev))
3349 numprev))
3350 if gdelta:
3350 if gdelta:
3351 ui.write(('deltas against p1 : ')
3351 ui.write(('deltas against p1 : ')
3352 + fmt % pcfmt(nump1, numdeltas))
3352 + fmt % pcfmt(nump1, numdeltas))
3353 ui.write(('deltas against p2 : ')
3353 ui.write(('deltas against p2 : ')
3354 + fmt % pcfmt(nump2, numdeltas))
3354 + fmt % pcfmt(nump2, numdeltas))
3355 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3355 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3356 numdeltas))
3356 numdeltas))
3357
3357
3358 @command('debugrevspec',
3358 @command('debugrevspec',
3359 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3359 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3360 ('REVSPEC'))
3360 ('REVSPEC'))
3361 def debugrevspec(ui, repo, expr, **opts):
3361 def debugrevspec(ui, repo, expr, **opts):
3362 """parse and apply a revision specification
3362 """parse and apply a revision specification
3363
3363
3364 Use --verbose to print the parsed tree before and after aliases
3364 Use --verbose to print the parsed tree before and after aliases
3365 expansion.
3365 expansion.
3366 """
3366 """
3367 if ui.verbose:
3367 if ui.verbose:
3368 tree = revset.parse(expr, lookup=repo.__contains__)
3368 tree = revset.parse(expr, lookup=repo.__contains__)
3369 ui.note(revset.prettyformat(tree), "\n")
3369 ui.note(revset.prettyformat(tree), "\n")
3370 newtree = revset.findaliases(ui, tree)
3370 newtree = revset.findaliases(ui, tree)
3371 if newtree != tree:
3371 if newtree != tree:
3372 ui.note(revset.prettyformat(newtree), "\n")
3372 ui.note(revset.prettyformat(newtree), "\n")
3373 tree = newtree
3373 tree = newtree
3374 newtree = revset.foldconcat(tree)
3374 newtree = revset.foldconcat(tree)
3375 if newtree != tree:
3375 if newtree != tree:
3376 ui.note(revset.prettyformat(newtree), "\n")
3376 ui.note(revset.prettyformat(newtree), "\n")
3377 if opts["optimize"]:
3377 if opts["optimize"]:
3378 weight, optimizedtree = revset.optimize(newtree, True)
3378 weight, optimizedtree = revset.optimize(newtree, True)
3379 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3379 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3380 func = revset.match(ui, expr, repo)
3380 func = revset.match(ui, expr, repo)
3381 revs = func(repo)
3381 revs = func(repo)
3382 if ui.verbose:
3382 if ui.verbose:
3383 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3383 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3384 for c in revs:
3384 for c in revs:
3385 ui.write("%s\n" % c)
3385 ui.write("%s\n" % c)
3386
3386
3387 @command('debugsetparents', [], _('REV1 [REV2]'))
3387 @command('debugsetparents', [], _('REV1 [REV2]'))
3388 def debugsetparents(ui, repo, rev1, rev2=None):
3388 def debugsetparents(ui, repo, rev1, rev2=None):
3389 """manually set the parents of the current working directory
3389 """manually set the parents of the current working directory
3390
3390
3391 This is useful for writing repository conversion tools, but should
3391 This is useful for writing repository conversion tools, but should
3392 be used with care. For example, neither the working directory nor the
3392 be used with care. For example, neither the working directory nor the
3393 dirstate is updated, so file status may be incorrect after running this
3393 dirstate is updated, so file status may be incorrect after running this
3394 command.
3394 command.
3395
3395
3396 Returns 0 on success.
3396 Returns 0 on success.
3397 """
3397 """
3398
3398
3399 r1 = scmutil.revsingle(repo, rev1).node()
3399 r1 = scmutil.revsingle(repo, rev1).node()
3400 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3400 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3401
3401
3402 wlock = repo.wlock()
3402 wlock = repo.wlock()
3403 try:
3403 try:
3404 repo.dirstate.beginparentchange()
3404 repo.dirstate.beginparentchange()
3405 repo.setparents(r1, r2)
3405 repo.setparents(r1, r2)
3406 repo.dirstate.endparentchange()
3406 repo.dirstate.endparentchange()
3407 finally:
3407 finally:
3408 wlock.release()
3408 wlock.release()
3409
3409
3410 @command('debugdirstate|debugstate',
3410 @command('debugdirstate|debugstate',
3411 [('', 'nodates', None, _('do not display the saved mtime')),
3411 [('', 'nodates', None, _('do not display the saved mtime')),
3412 ('', 'datesort', None, _('sort by saved mtime'))],
3412 ('', 'datesort', None, _('sort by saved mtime'))],
3413 _('[OPTION]...'))
3413 _('[OPTION]...'))
3414 def debugstate(ui, repo, **opts):
3414 def debugstate(ui, repo, **opts):
3415 """show the contents of the current dirstate"""
3415 """show the contents of the current dirstate"""
3416
3416
3417 nodates = opts.get('nodates')
3417 nodates = opts.get('nodates')
3418 datesort = opts.get('datesort')
3418 datesort = opts.get('datesort')
3419
3419
3420 timestr = ""
3420 timestr = ""
3421 if datesort:
3421 if datesort:
3422 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3422 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3423 else:
3423 else:
3424 keyfunc = None # sort by filename
3424 keyfunc = None # sort by filename
3425 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3425 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3426 if ent[3] == -1:
3426 if ent[3] == -1:
3427 timestr = 'unset '
3427 timestr = 'unset '
3428 elif nodates:
3428 elif nodates:
3429 timestr = 'set '
3429 timestr = 'set '
3430 else:
3430 else:
3431 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3431 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3432 time.localtime(ent[3]))
3432 time.localtime(ent[3]))
3433 if ent[1] & 0o20000:
3433 if ent[1] & 0o20000:
3434 mode = 'lnk'
3434 mode = 'lnk'
3435 else:
3435 else:
3436 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3436 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3437 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3437 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3438 for f in repo.dirstate.copies():
3438 for f in repo.dirstate.copies():
3439 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3439 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3440
3440
3441 @command('debugsub',
3441 @command('debugsub',
3442 [('r', 'rev', '',
3442 [('r', 'rev', '',
3443 _('revision to check'), _('REV'))],
3443 _('revision to check'), _('REV'))],
3444 _('[-r REV] [REV]'))
3444 _('[-r REV] [REV]'))
3445 def debugsub(ui, repo, rev=None):
3445 def debugsub(ui, repo, rev=None):
3446 ctx = scmutil.revsingle(repo, rev, None)
3446 ctx = scmutil.revsingle(repo, rev, None)
3447 for k, v in sorted(ctx.substate.items()):
3447 for k, v in sorted(ctx.substate.items()):
3448 ui.write(('path %s\n') % k)
3448 ui.write(('path %s\n') % k)
3449 ui.write((' source %s\n') % v[0])
3449 ui.write((' source %s\n') % v[0])
3450 ui.write((' revision %s\n') % v[1])
3450 ui.write((' revision %s\n') % v[1])
3451
3451
3452 @command('debugsuccessorssets',
3452 @command('debugsuccessorssets',
3453 [],
3453 [],
3454 _('[REV]'))
3454 _('[REV]'))
3455 def debugsuccessorssets(ui, repo, *revs):
3455 def debugsuccessorssets(ui, repo, *revs):
3456 """show set of successors for revision
3456 """show set of successors for revision
3457
3457
3458 A successors set of changeset A is a consistent group of revisions that
3458 A successors set of changeset A is a consistent group of revisions that
3459 succeed A. It contains non-obsolete changesets only.
3459 succeed A. It contains non-obsolete changesets only.
3460
3460
3461 In most cases a changeset A has a single successors set containing a single
3461 In most cases a changeset A has a single successors set containing a single
3462 successor (changeset A replaced by A').
3462 successor (changeset A replaced by A').
3463
3463
3464 A changeset that is made obsolete with no successors are called "pruned".
3464 A changeset that is made obsolete with no successors are called "pruned".
3465 Such changesets have no successors sets at all.
3465 Such changesets have no successors sets at all.
3466
3466
3467 A changeset that has been "split" will have a successors set containing
3467 A changeset that has been "split" will have a successors set containing
3468 more than one successor.
3468 more than one successor.
3469
3469
3470 A changeset that has been rewritten in multiple different ways is called
3470 A changeset that has been rewritten in multiple different ways is called
3471 "divergent". Such changesets have multiple successor sets (each of which
3471 "divergent". Such changesets have multiple successor sets (each of which
3472 may also be split, i.e. have multiple successors).
3472 may also be split, i.e. have multiple successors).
3473
3473
3474 Results are displayed as follows::
3474 Results are displayed as follows::
3475
3475
3476 <rev1>
3476 <rev1>
3477 <successors-1A>
3477 <successors-1A>
3478 <rev2>
3478 <rev2>
3479 <successors-2A>
3479 <successors-2A>
3480 <successors-2B1> <successors-2B2> <successors-2B3>
3480 <successors-2B1> <successors-2B2> <successors-2B3>
3481
3481
3482 Here rev2 has two possible (i.e. divergent) successors sets. The first
3482 Here rev2 has two possible (i.e. divergent) successors sets. The first
3483 holds one element, whereas the second holds three (i.e. the changeset has
3483 holds one element, whereas the second holds three (i.e. the changeset has
3484 been split).
3484 been split).
3485 """
3485 """
3486 # passed to successorssets caching computation from one call to another
3486 # passed to successorssets caching computation from one call to another
3487 cache = {}
3487 cache = {}
3488 ctx2str = str
3488 ctx2str = str
3489 node2str = short
3489 node2str = short
3490 if ui.debug():
3490 if ui.debug():
3491 def ctx2str(ctx):
3491 def ctx2str(ctx):
3492 return ctx.hex()
3492 return ctx.hex()
3493 node2str = hex
3493 node2str = hex
3494 for rev in scmutil.revrange(repo, revs):
3494 for rev in scmutil.revrange(repo, revs):
3495 ctx = repo[rev]
3495 ctx = repo[rev]
3496 ui.write('%s\n'% ctx2str(ctx))
3496 ui.write('%s\n'% ctx2str(ctx))
3497 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3497 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3498 if succsset:
3498 if succsset:
3499 ui.write(' ')
3499 ui.write(' ')
3500 ui.write(node2str(succsset[0]))
3500 ui.write(node2str(succsset[0]))
3501 for node in succsset[1:]:
3501 for node in succsset[1:]:
3502 ui.write(' ')
3502 ui.write(' ')
3503 ui.write(node2str(node))
3503 ui.write(node2str(node))
3504 ui.write('\n')
3504 ui.write('\n')
3505
3505
3506 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3506 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3507 def debugwalk(ui, repo, *pats, **opts):
3507 def debugwalk(ui, repo, *pats, **opts):
3508 """show how files match on given patterns"""
3508 """show how files match on given patterns"""
3509 m = scmutil.match(repo[None], pats, opts)
3509 m = scmutil.match(repo[None], pats, opts)
3510 items = list(repo.walk(m))
3510 items = list(repo.walk(m))
3511 if not items:
3511 if not items:
3512 return
3512 return
3513 f = lambda fn: fn
3513 f = lambda fn: fn
3514 if ui.configbool('ui', 'slash') and os.sep != '/':
3514 if ui.configbool('ui', 'slash') and os.sep != '/':
3515 f = lambda fn: util.normpath(fn)
3515 f = lambda fn: util.normpath(fn)
3516 fmt = 'f %%-%ds %%-%ds %%s' % (
3516 fmt = 'f %%-%ds %%-%ds %%s' % (
3517 max([len(abs) for abs in items]),
3517 max([len(abs) for abs in items]),
3518 max([len(m.rel(abs)) for abs in items]))
3518 max([len(m.rel(abs)) for abs in items]))
3519 for abs in items:
3519 for abs in items:
3520 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3520 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3521 ui.write("%s\n" % line.rstrip())
3521 ui.write("%s\n" % line.rstrip())
3522
3522
3523 @command('debugwireargs',
3523 @command('debugwireargs',
3524 [('', 'three', '', 'three'),
3524 [('', 'three', '', 'three'),
3525 ('', 'four', '', 'four'),
3525 ('', 'four', '', 'four'),
3526 ('', 'five', '', 'five'),
3526 ('', 'five', '', 'five'),
3527 ] + remoteopts,
3527 ] + remoteopts,
3528 _('REPO [OPTIONS]... [ONE [TWO]]'),
3528 _('REPO [OPTIONS]... [ONE [TWO]]'),
3529 norepo=True)
3529 norepo=True)
3530 def debugwireargs(ui, repopath, *vals, **opts):
3530 def debugwireargs(ui, repopath, *vals, **opts):
3531 repo = hg.peer(ui, opts, repopath)
3531 repo = hg.peer(ui, opts, repopath)
3532 for opt in remoteopts:
3532 for opt in remoteopts:
3533 del opts[opt[1]]
3533 del opts[opt[1]]
3534 args = {}
3534 args = {}
3535 for k, v in opts.iteritems():
3535 for k, v in opts.iteritems():
3536 if v:
3536 if v:
3537 args[k] = v
3537 args[k] = v
3538 # run twice to check that we don't mess up the stream for the next command
3538 # run twice to check that we don't mess up the stream for the next command
3539 res1 = repo.debugwireargs(*vals, **args)
3539 res1 = repo.debugwireargs(*vals, **args)
3540 res2 = repo.debugwireargs(*vals, **args)
3540 res2 = repo.debugwireargs(*vals, **args)
3541 ui.write("%s\n" % res1)
3541 ui.write("%s\n" % res1)
3542 if res1 != res2:
3542 if res1 != res2:
3543 ui.warn("%s\n" % res2)
3543 ui.warn("%s\n" % res2)
3544
3544
3545 @command('^diff',
3545 @command('^diff',
3546 [('r', 'rev', [], _('revision'), _('REV')),
3546 [('r', 'rev', [], _('revision'), _('REV')),
3547 ('c', 'change', '', _('change made by revision'), _('REV'))
3547 ('c', 'change', '', _('change made by revision'), _('REV'))
3548 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3548 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3549 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3549 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3550 inferrepo=True)
3550 inferrepo=True)
3551 def diff(ui, repo, *pats, **opts):
3551 def diff(ui, repo, *pats, **opts):
3552 """diff repository (or selected files)
3552 """diff repository (or selected files)
3553
3553
3554 Show differences between revisions for the specified files.
3554 Show differences between revisions for the specified files.
3555
3555
3556 Differences between files are shown using the unified diff format.
3556 Differences between files are shown using the unified diff format.
3557
3557
3558 .. note::
3558 .. note::
3559
3559
3560 :hg:`diff` may generate unexpected results for merges, as it will
3560 :hg:`diff` may generate unexpected results for merges, as it will
3561 default to comparing against the working directory's first
3561 default to comparing against the working directory's first
3562 parent changeset if no revisions are specified.
3562 parent changeset if no revisions are specified.
3563
3563
3564 When two revision arguments are given, then changes are shown
3564 When two revision arguments are given, then changes are shown
3565 between those revisions. If only one revision is specified then
3565 between those revisions. If only one revision is specified then
3566 that revision is compared to the working directory, and, when no
3566 that revision is compared to the working directory, and, when no
3567 revisions are specified, the working directory files are compared
3567 revisions are specified, the working directory files are compared
3568 to its first parent.
3568 to its first parent.
3569
3569
3570 Alternatively you can specify -c/--change with a revision to see
3570 Alternatively you can specify -c/--change with a revision to see
3571 the changes in that changeset relative to its first parent.
3571 the changes in that changeset relative to its first parent.
3572
3572
3573 Without the -a/--text option, diff will avoid generating diffs of
3573 Without the -a/--text option, diff will avoid generating diffs of
3574 files it detects as binary. With -a, diff will generate a diff
3574 files it detects as binary. With -a, diff will generate a diff
3575 anyway, probably with undesirable results.
3575 anyway, probably with undesirable results.
3576
3576
3577 Use the -g/--git option to generate diffs in the git extended diff
3577 Use the -g/--git option to generate diffs in the git extended diff
3578 format. For more information, read :hg:`help diffs`.
3578 format. For more information, read :hg:`help diffs`.
3579
3579
3580 .. container:: verbose
3580 .. container:: verbose
3581
3581
3582 Examples:
3582 Examples:
3583
3583
3584 - compare a file in the current working directory to its parent::
3584 - compare a file in the current working directory to its parent::
3585
3585
3586 hg diff foo.c
3586 hg diff foo.c
3587
3587
3588 - compare two historical versions of a directory, with rename info::
3588 - compare two historical versions of a directory, with rename info::
3589
3589
3590 hg diff --git -r 1.0:1.2 lib/
3590 hg diff --git -r 1.0:1.2 lib/
3591
3591
3592 - get change stats relative to the last change on some date::
3592 - get change stats relative to the last change on some date::
3593
3593
3594 hg diff --stat -r "date('may 2')"
3594 hg diff --stat -r "date('may 2')"
3595
3595
3596 - diff all newly-added files that contain a keyword::
3596 - diff all newly-added files that contain a keyword::
3597
3597
3598 hg diff "set:added() and grep(GNU)"
3598 hg diff "set:added() and grep(GNU)"
3599
3599
3600 - compare a revision and its parents::
3600 - compare a revision and its parents::
3601
3601
3602 hg diff -c 9353 # compare against first parent
3602 hg diff -c 9353 # compare against first parent
3603 hg diff -r 9353^:9353 # same using revset syntax
3603 hg diff -r 9353^:9353 # same using revset syntax
3604 hg diff -r 9353^2:9353 # compare against the second parent
3604 hg diff -r 9353^2:9353 # compare against the second parent
3605
3605
3606 Returns 0 on success.
3606 Returns 0 on success.
3607 """
3607 """
3608
3608
3609 revs = opts.get('rev')
3609 revs = opts.get('rev')
3610 change = opts.get('change')
3610 change = opts.get('change')
3611 stat = opts.get('stat')
3611 stat = opts.get('stat')
3612 reverse = opts.get('reverse')
3612 reverse = opts.get('reverse')
3613
3613
3614 if revs and change:
3614 if revs and change:
3615 msg = _('cannot specify --rev and --change at the same time')
3615 msg = _('cannot specify --rev and --change at the same time')
3616 raise error.Abort(msg)
3616 raise error.Abort(msg)
3617 elif change:
3617 elif change:
3618 node2 = scmutil.revsingle(repo, change, None).node()
3618 node2 = scmutil.revsingle(repo, change, None).node()
3619 node1 = repo[node2].p1().node()
3619 node1 = repo[node2].p1().node()
3620 else:
3620 else:
3621 node1, node2 = scmutil.revpair(repo, revs)
3621 node1, node2 = scmutil.revpair(repo, revs)
3622
3622
3623 if reverse:
3623 if reverse:
3624 node1, node2 = node2, node1
3624 node1, node2 = node2, node1
3625
3625
3626 diffopts = patch.diffallopts(ui, opts)
3626 diffopts = patch.diffallopts(ui, opts)
3627 m = scmutil.match(repo[node2], pats, opts)
3627 m = scmutil.match(repo[node2], pats, opts)
3628 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3628 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3629 listsubrepos=opts.get('subrepos'),
3629 listsubrepos=opts.get('subrepos'),
3630 root=opts.get('root'))
3630 root=opts.get('root'))
3631
3631
3632 @command('^export',
3632 @command('^export',
3633 [('o', 'output', '',
3633 [('o', 'output', '',
3634 _('print output to file with formatted name'), _('FORMAT')),
3634 _('print output to file with formatted name'), _('FORMAT')),
3635 ('', 'switch-parent', None, _('diff against the second parent')),
3635 ('', 'switch-parent', None, _('diff against the second parent')),
3636 ('r', 'rev', [], _('revisions to export'), _('REV')),
3636 ('r', 'rev', [], _('revisions to export'), _('REV')),
3637 ] + diffopts,
3637 ] + diffopts,
3638 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3638 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3639 def export(ui, repo, *changesets, **opts):
3639 def export(ui, repo, *changesets, **opts):
3640 """dump the header and diffs for one or more changesets
3640 """dump the header and diffs for one or more changesets
3641
3641
3642 Print the changeset header and diffs for one or more revisions.
3642 Print the changeset header and diffs for one or more revisions.
3643 If no revision is given, the parent of the working directory is used.
3643 If no revision is given, the parent of the working directory is used.
3644
3644
3645 The information shown in the changeset header is: author, date,
3645 The information shown in the changeset header is: author, date,
3646 branch name (if non-default), changeset hash, parent(s) and commit
3646 branch name (if non-default), changeset hash, parent(s) and commit
3647 comment.
3647 comment.
3648
3648
3649 .. note::
3649 .. note::
3650
3650
3651 :hg:`export` may generate unexpected diff output for merge
3651 :hg:`export` may generate unexpected diff output for merge
3652 changesets, as it will compare the merge changeset against its
3652 changesets, as it will compare the merge changeset against its
3653 first parent only.
3653 first parent only.
3654
3654
3655 Output may be to a file, in which case the name of the file is
3655 Output may be to a file, in which case the name of the file is
3656 given using a format string. The formatting rules are as follows:
3656 given using a format string. The formatting rules are as follows:
3657
3657
3658 :``%%``: literal "%" character
3658 :``%%``: literal "%" character
3659 :``%H``: changeset hash (40 hexadecimal digits)
3659 :``%H``: changeset hash (40 hexadecimal digits)
3660 :``%N``: number of patches being generated
3660 :``%N``: number of patches being generated
3661 :``%R``: changeset revision number
3661 :``%R``: changeset revision number
3662 :``%b``: basename of the exporting repository
3662 :``%b``: basename of the exporting repository
3663 :``%h``: short-form changeset hash (12 hexadecimal digits)
3663 :``%h``: short-form changeset hash (12 hexadecimal digits)
3664 :``%m``: first line of the commit message (only alphanumeric characters)
3664 :``%m``: first line of the commit message (only alphanumeric characters)
3665 :``%n``: zero-padded sequence number, starting at 1
3665 :``%n``: zero-padded sequence number, starting at 1
3666 :``%r``: zero-padded changeset revision number
3666 :``%r``: zero-padded changeset revision number
3667
3667
3668 Without the -a/--text option, export will avoid generating diffs
3668 Without the -a/--text option, export will avoid generating diffs
3669 of files it detects as binary. With -a, export will generate a
3669 of files it detects as binary. With -a, export will generate a
3670 diff anyway, probably with undesirable results.
3670 diff anyway, probably with undesirable results.
3671
3671
3672 Use the -g/--git option to generate diffs in the git extended diff
3672 Use the -g/--git option to generate diffs in the git extended diff
3673 format. See :hg:`help diffs` for more information.
3673 format. See :hg:`help diffs` for more information.
3674
3674
3675 With the --switch-parent option, the diff will be against the
3675 With the --switch-parent option, the diff will be against the
3676 second parent. It can be useful to review a merge.
3676 second parent. It can be useful to review a merge.
3677
3677
3678 .. container:: verbose
3678 .. container:: verbose
3679
3679
3680 Examples:
3680 Examples:
3681
3681
3682 - use export and import to transplant a bugfix to the current
3682 - use export and import to transplant a bugfix to the current
3683 branch::
3683 branch::
3684
3684
3685 hg export -r 9353 | hg import -
3685 hg export -r 9353 | hg import -
3686
3686
3687 - export all the changesets between two revisions to a file with
3687 - export all the changesets between two revisions to a file with
3688 rename information::
3688 rename information::
3689
3689
3690 hg export --git -r 123:150 > changes.txt
3690 hg export --git -r 123:150 > changes.txt
3691
3691
3692 - split outgoing changes into a series of patches with
3692 - split outgoing changes into a series of patches with
3693 descriptive names::
3693 descriptive names::
3694
3694
3695 hg export -r "outgoing()" -o "%n-%m.patch"
3695 hg export -r "outgoing()" -o "%n-%m.patch"
3696
3696
3697 Returns 0 on success.
3697 Returns 0 on success.
3698 """
3698 """
3699 changesets += tuple(opts.get('rev', []))
3699 changesets += tuple(opts.get('rev', []))
3700 if not changesets:
3700 if not changesets:
3701 changesets = ['.']
3701 changesets = ['.']
3702 revs = scmutil.revrange(repo, changesets)
3702 revs = scmutil.revrange(repo, changesets)
3703 if not revs:
3703 if not revs:
3704 raise error.Abort(_("export requires at least one changeset"))
3704 raise error.Abort(_("export requires at least one changeset"))
3705 if len(revs) > 1:
3705 if len(revs) > 1:
3706 ui.note(_('exporting patches:\n'))
3706 ui.note(_('exporting patches:\n'))
3707 else:
3707 else:
3708 ui.note(_('exporting patch:\n'))
3708 ui.note(_('exporting patch:\n'))
3709 cmdutil.export(repo, revs, template=opts.get('output'),
3709 cmdutil.export(repo, revs, template=opts.get('output'),
3710 switch_parent=opts.get('switch_parent'),
3710 switch_parent=opts.get('switch_parent'),
3711 opts=patch.diffallopts(ui, opts))
3711 opts=patch.diffallopts(ui, opts))
3712
3712
3713 @command('files',
3713 @command('files',
3714 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3714 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3715 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3715 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3716 ] + walkopts + formatteropts + subrepoopts,
3716 ] + walkopts + formatteropts + subrepoopts,
3717 _('[OPTION]... [PATTERN]...'))
3717 _('[OPTION]... [PATTERN]...'))
3718 def files(ui, repo, *pats, **opts):
3718 def files(ui, repo, *pats, **opts):
3719 """list tracked files
3719 """list tracked files
3720
3720
3721 Print files under Mercurial control in the working directory or
3721 Print files under Mercurial control in the working directory or
3722 specified revision whose names match the given patterns (excluding
3722 specified revision whose names match the given patterns (excluding
3723 removed files).
3723 removed files).
3724
3724
3725 If no patterns are given to match, this command prints the names
3725 If no patterns are given to match, this command prints the names
3726 of all files under Mercurial control in the working directory.
3726 of all files under Mercurial control in the working directory.
3727
3727
3728 .. container:: verbose
3728 .. container:: verbose
3729
3729
3730 Examples:
3730 Examples:
3731
3731
3732 - list all files under the current directory::
3732 - list all files under the current directory::
3733
3733
3734 hg files .
3734 hg files .
3735
3735
3736 - shows sizes and flags for current revision::
3736 - shows sizes and flags for current revision::
3737
3737
3738 hg files -vr .
3738 hg files -vr .
3739
3739
3740 - list all files named README::
3740 - list all files named README::
3741
3741
3742 hg files -I "**/README"
3742 hg files -I "**/README"
3743
3743
3744 - list all binary files::
3744 - list all binary files::
3745
3745
3746 hg files "set:binary()"
3746 hg files "set:binary()"
3747
3747
3748 - find files containing a regular expression::
3748 - find files containing a regular expression::
3749
3749
3750 hg files "set:grep('bob')"
3750 hg files "set:grep('bob')"
3751
3751
3752 - search tracked file contents with xargs and grep::
3752 - search tracked file contents with xargs and grep::
3753
3753
3754 hg files -0 | xargs -0 grep foo
3754 hg files -0 | xargs -0 grep foo
3755
3755
3756 See :hg:`help patterns` and :hg:`help filesets` for more information
3756 See :hg:`help patterns` and :hg:`help filesets` for more information
3757 on specifying file patterns.
3757 on specifying file patterns.
3758
3758
3759 Returns 0 if a match is found, 1 otherwise.
3759 Returns 0 if a match is found, 1 otherwise.
3760
3760
3761 """
3761 """
3762 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3762 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3763
3763
3764 end = '\n'
3764 end = '\n'
3765 if opts.get('print0'):
3765 if opts.get('print0'):
3766 end = '\0'
3766 end = '\0'
3767 fm = ui.formatter('files', opts)
3767 fm = ui.formatter('files', opts)
3768 fmt = '%s' + end
3768 fmt = '%s' + end
3769
3769
3770 m = scmutil.match(ctx, pats, opts)
3770 m = scmutil.match(ctx, pats, opts)
3771 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3771 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3772
3772
3773 fm.end()
3773 fm.end()
3774
3774
3775 return ret
3775 return ret
3776
3776
3777 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3777 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3778 def forget(ui, repo, *pats, **opts):
3778 def forget(ui, repo, *pats, **opts):
3779 """forget the specified files on the next commit
3779 """forget the specified files on the next commit
3780
3780
3781 Mark the specified files so they will no longer be tracked
3781 Mark the specified files so they will no longer be tracked
3782 after the next commit.
3782 after the next commit.
3783
3783
3784 This only removes files from the current branch, not from the
3784 This only removes files from the current branch, not from the
3785 entire project history, and it does not delete them from the
3785 entire project history, and it does not delete them from the
3786 working directory.
3786 working directory.
3787
3787
3788 To delete the file from the working directory, see :hg:`remove`.
3788 To delete the file from the working directory, see :hg:`remove`.
3789
3789
3790 To undo a forget before the next commit, see :hg:`add`.
3790 To undo a forget before the next commit, see :hg:`add`.
3791
3791
3792 .. container:: verbose
3792 .. container:: verbose
3793
3793
3794 Examples:
3794 Examples:
3795
3795
3796 - forget newly-added binary files::
3796 - forget newly-added binary files::
3797
3797
3798 hg forget "set:added() and binary()"
3798 hg forget "set:added() and binary()"
3799
3799
3800 - forget files that would be excluded by .hgignore::
3800 - forget files that would be excluded by .hgignore::
3801
3801
3802 hg forget "set:hgignore()"
3802 hg forget "set:hgignore()"
3803
3803
3804 Returns 0 on success.
3804 Returns 0 on success.
3805 """
3805 """
3806
3806
3807 if not pats:
3807 if not pats:
3808 raise error.Abort(_('no files specified'))
3808 raise error.Abort(_('no files specified'))
3809
3809
3810 m = scmutil.match(repo[None], pats, opts)
3810 m = scmutil.match(repo[None], pats, opts)
3811 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3811 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3812 return rejected and 1 or 0
3812 return rejected and 1 or 0
3813
3813
3814 @command(
3814 @command(
3815 'graft',
3815 'graft',
3816 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3816 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3817 ('c', 'continue', False, _('resume interrupted graft')),
3817 ('c', 'continue', False, _('resume interrupted graft')),
3818 ('e', 'edit', False, _('invoke editor on commit messages')),
3818 ('e', 'edit', False, _('invoke editor on commit messages')),
3819 ('', 'log', None, _('append graft info to log message')),
3819 ('', 'log', None, _('append graft info to log message')),
3820 ('f', 'force', False, _('force graft')),
3820 ('f', 'force', False, _('force graft')),
3821 ('D', 'currentdate', False,
3821 ('D', 'currentdate', False,
3822 _('record the current date as commit date')),
3822 _('record the current date as commit date')),
3823 ('U', 'currentuser', False,
3823 ('U', 'currentuser', False,
3824 _('record the current user as committer'), _('DATE'))]
3824 _('record the current user as committer'), _('DATE'))]
3825 + commitopts2 + mergetoolopts + dryrunopts,
3825 + commitopts2 + mergetoolopts + dryrunopts,
3826 _('[OPTION]... [-r] REV...'))
3826 _('[OPTION]... [-r] REV...'))
3827 def graft(ui, repo, *revs, **opts):
3827 def graft(ui, repo, *revs, **opts):
3828 '''copy changes from other branches onto the current branch
3828 '''copy changes from other branches onto the current branch
3829
3829
3830 This command uses Mercurial's merge logic to copy individual
3830 This command uses Mercurial's merge logic to copy individual
3831 changes from other branches without merging branches in the
3831 changes from other branches without merging branches in the
3832 history graph. This is sometimes known as 'backporting' or
3832 history graph. This is sometimes known as 'backporting' or
3833 'cherry-picking'. By default, graft will copy user, date, and
3833 'cherry-picking'. By default, graft will copy user, date, and
3834 description from the source changesets.
3834 description from the source changesets.
3835
3835
3836 Changesets that are ancestors of the current revision, that have
3836 Changesets that are ancestors of the current revision, that have
3837 already been grafted, or that are merges will be skipped.
3837 already been grafted, or that are merges will be skipped.
3838
3838
3839 If --log is specified, log messages will have a comment appended
3839 If --log is specified, log messages will have a comment appended
3840 of the form::
3840 of the form::
3841
3841
3842 (grafted from CHANGESETHASH)
3842 (grafted from CHANGESETHASH)
3843
3843
3844 If --force is specified, revisions will be grafted even if they
3844 If --force is specified, revisions will be grafted even if they
3845 are already ancestors of or have been grafted to the destination.
3845 are already ancestors of or have been grafted to the destination.
3846 This is useful when the revisions have since been backed out.
3846 This is useful when the revisions have since been backed out.
3847
3847
3848 If a graft merge results in conflicts, the graft process is
3848 If a graft merge results in conflicts, the graft process is
3849 interrupted so that the current merge can be manually resolved.
3849 interrupted so that the current merge can be manually resolved.
3850 Once all conflicts are addressed, the graft process can be
3850 Once all conflicts are addressed, the graft process can be
3851 continued with the -c/--continue option.
3851 continued with the -c/--continue option.
3852
3852
3853 .. note::
3853 .. note::
3854
3854
3855 The -c/--continue option does not reapply earlier options, except
3855 The -c/--continue option does not reapply earlier options, except
3856 for --force.
3856 for --force.
3857
3857
3858 .. container:: verbose
3858 .. container:: verbose
3859
3859
3860 Examples:
3860 Examples:
3861
3861
3862 - copy a single change to the stable branch and edit its description::
3862 - copy a single change to the stable branch and edit its description::
3863
3863
3864 hg update stable
3864 hg update stable
3865 hg graft --edit 9393
3865 hg graft --edit 9393
3866
3866
3867 - graft a range of changesets with one exception, updating dates::
3867 - graft a range of changesets with one exception, updating dates::
3868
3868
3869 hg graft -D "2085::2093 and not 2091"
3869 hg graft -D "2085::2093 and not 2091"
3870
3870
3871 - continue a graft after resolving conflicts::
3871 - continue a graft after resolving conflicts::
3872
3872
3873 hg graft -c
3873 hg graft -c
3874
3874
3875 - show the source of a grafted changeset::
3875 - show the source of a grafted changeset::
3876
3876
3877 hg log --debug -r .
3877 hg log --debug -r .
3878
3878
3879 - show revisions sorted by date::
3879 - show revisions sorted by date::
3880
3880
3881 hg log -r 'sort(all(), date)'
3881 hg log -r 'sort(all(), date)'
3882
3882
3883 See :hg:`help revisions` and :hg:`help revsets` for more about
3883 See :hg:`help revisions` and :hg:`help revsets` for more about
3884 specifying revisions.
3884 specifying revisions.
3885
3885
3886 Returns 0 on successful completion.
3886 Returns 0 on successful completion.
3887 '''
3887 '''
3888 wlock = None
3888 wlock = None
3889 try:
3889 try:
3890 wlock = repo.wlock()
3890 wlock = repo.wlock()
3891 return _dograft(ui, repo, *revs, **opts)
3891 return _dograft(ui, repo, *revs, **opts)
3892 finally:
3892 finally:
3893 release(wlock)
3893 release(wlock)
3894
3894
3895 def _dograft(ui, repo, *revs, **opts):
3895 def _dograft(ui, repo, *revs, **opts):
3896 revs = list(revs)
3896 revs = list(revs)
3897 revs.extend(opts['rev'])
3897 revs.extend(opts['rev'])
3898
3898
3899 if not opts.get('user') and opts.get('currentuser'):
3899 if not opts.get('user') and opts.get('currentuser'):
3900 opts['user'] = ui.username()
3900 opts['user'] = ui.username()
3901 if not opts.get('date') and opts.get('currentdate'):
3901 if not opts.get('date') and opts.get('currentdate'):
3902 opts['date'] = "%d %d" % util.makedate()
3902 opts['date'] = "%d %d" % util.makedate()
3903
3903
3904 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3904 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3905
3905
3906 cont = False
3906 cont = False
3907 if opts['continue']:
3907 if opts['continue']:
3908 cont = True
3908 cont = True
3909 if revs:
3909 if revs:
3910 raise error.Abort(_("can't specify --continue and revisions"))
3910 raise error.Abort(_("can't specify --continue and revisions"))
3911 # read in unfinished revisions
3911 # read in unfinished revisions
3912 try:
3912 try:
3913 nodes = repo.vfs.read('graftstate').splitlines()
3913 nodes = repo.vfs.read('graftstate').splitlines()
3914 revs = [repo[node].rev() for node in nodes]
3914 revs = [repo[node].rev() for node in nodes]
3915 except IOError as inst:
3915 except IOError as inst:
3916 if inst.errno != errno.ENOENT:
3916 if inst.errno != errno.ENOENT:
3917 raise
3917 raise
3918 raise error.Abort(_("no graft state found, can't continue"))
3918 raise error.Abort(_("no graft state found, can't continue"))
3919 else:
3919 else:
3920 cmdutil.checkunfinished(repo)
3920 cmdutil.checkunfinished(repo)
3921 cmdutil.bailifchanged(repo)
3921 cmdutil.bailifchanged(repo)
3922 if not revs:
3922 if not revs:
3923 raise error.Abort(_('no revisions specified'))
3923 raise error.Abort(_('no revisions specified'))
3924 revs = scmutil.revrange(repo, revs)
3924 revs = scmutil.revrange(repo, revs)
3925
3925
3926 skipped = set()
3926 skipped = set()
3927 # check for merges
3927 # check for merges
3928 for rev in repo.revs('%ld and merge()', revs):
3928 for rev in repo.revs('%ld and merge()', revs):
3929 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3929 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3930 skipped.add(rev)
3930 skipped.add(rev)
3931 revs = [r for r in revs if r not in skipped]
3931 revs = [r for r in revs if r not in skipped]
3932 if not revs:
3932 if not revs:
3933 return -1
3933 return -1
3934
3934
3935 # Don't check in the --continue case, in effect retaining --force across
3935 # Don't check in the --continue case, in effect retaining --force across
3936 # --continues. That's because without --force, any revisions we decided to
3936 # --continues. That's because without --force, any revisions we decided to
3937 # skip would have been filtered out here, so they wouldn't have made their
3937 # skip would have been filtered out here, so they wouldn't have made their
3938 # way to the graftstate. With --force, any revisions we would have otherwise
3938 # way to the graftstate. With --force, any revisions we would have otherwise
3939 # skipped would not have been filtered out, and if they hadn't been applied
3939 # skipped would not have been filtered out, and if they hadn't been applied
3940 # already, they'd have been in the graftstate.
3940 # already, they'd have been in the graftstate.
3941 if not (cont or opts.get('force')):
3941 if not (cont or opts.get('force')):
3942 # check for ancestors of dest branch
3942 # check for ancestors of dest branch
3943 crev = repo['.'].rev()
3943 crev = repo['.'].rev()
3944 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3944 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3945 # Cannot use x.remove(y) on smart set, this has to be a list.
3945 # Cannot use x.remove(y) on smart set, this has to be a list.
3946 # XXX make this lazy in the future
3946 # XXX make this lazy in the future
3947 revs = list(revs)
3947 revs = list(revs)
3948 # don't mutate while iterating, create a copy
3948 # don't mutate while iterating, create a copy
3949 for rev in list(revs):
3949 for rev in list(revs):
3950 if rev in ancestors:
3950 if rev in ancestors:
3951 ui.warn(_('skipping ancestor revision %d:%s\n') %
3951 ui.warn(_('skipping ancestor revision %d:%s\n') %
3952 (rev, repo[rev]))
3952 (rev, repo[rev]))
3953 # XXX remove on list is slow
3953 # XXX remove on list is slow
3954 revs.remove(rev)
3954 revs.remove(rev)
3955 if not revs:
3955 if not revs:
3956 return -1
3956 return -1
3957
3957
3958 # analyze revs for earlier grafts
3958 # analyze revs for earlier grafts
3959 ids = {}
3959 ids = {}
3960 for ctx in repo.set("%ld", revs):
3960 for ctx in repo.set("%ld", revs):
3961 ids[ctx.hex()] = ctx.rev()
3961 ids[ctx.hex()] = ctx.rev()
3962 n = ctx.extra().get('source')
3962 n = ctx.extra().get('source')
3963 if n:
3963 if n:
3964 ids[n] = ctx.rev()
3964 ids[n] = ctx.rev()
3965
3965
3966 # check ancestors for earlier grafts
3966 # check ancestors for earlier grafts
3967 ui.debug('scanning for duplicate grafts\n')
3967 ui.debug('scanning for duplicate grafts\n')
3968
3968
3969 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3969 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3970 ctx = repo[rev]
3970 ctx = repo[rev]
3971 n = ctx.extra().get('source')
3971 n = ctx.extra().get('source')
3972 if n in ids:
3972 if n in ids:
3973 try:
3973 try:
3974 r = repo[n].rev()
3974 r = repo[n].rev()
3975 except error.RepoLookupError:
3975 except error.RepoLookupError:
3976 r = None
3976 r = None
3977 if r in revs:
3977 if r in revs:
3978 ui.warn(_('skipping revision %d:%s '
3978 ui.warn(_('skipping revision %d:%s '
3979 '(already grafted to %d:%s)\n')
3979 '(already grafted to %d:%s)\n')
3980 % (r, repo[r], rev, ctx))
3980 % (r, repo[r], rev, ctx))
3981 revs.remove(r)
3981 revs.remove(r)
3982 elif ids[n] in revs:
3982 elif ids[n] in revs:
3983 if r is None:
3983 if r is None:
3984 ui.warn(_('skipping already grafted revision %d:%s '
3984 ui.warn(_('skipping already grafted revision %d:%s '
3985 '(%d:%s also has unknown origin %s)\n')
3985 '(%d:%s also has unknown origin %s)\n')
3986 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3986 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3987 else:
3987 else:
3988 ui.warn(_('skipping already grafted revision %d:%s '
3988 ui.warn(_('skipping already grafted revision %d:%s '
3989 '(%d:%s also has origin %d:%s)\n')
3989 '(%d:%s also has origin %d:%s)\n')
3990 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3990 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3991 revs.remove(ids[n])
3991 revs.remove(ids[n])
3992 elif ctx.hex() in ids:
3992 elif ctx.hex() in ids:
3993 r = ids[ctx.hex()]
3993 r = ids[ctx.hex()]
3994 ui.warn(_('skipping already grafted revision %d:%s '
3994 ui.warn(_('skipping already grafted revision %d:%s '
3995 '(was grafted from %d:%s)\n') %
3995 '(was grafted from %d:%s)\n') %
3996 (r, repo[r], rev, ctx))
3996 (r, repo[r], rev, ctx))
3997 revs.remove(r)
3997 revs.remove(r)
3998 if not revs:
3998 if not revs:
3999 return -1
3999 return -1
4000
4000
4001 for pos, ctx in enumerate(repo.set("%ld", revs)):
4001 for pos, ctx in enumerate(repo.set("%ld", revs)):
4002 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4002 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
4003 ctx.description().split('\n', 1)[0])
4003 ctx.description().split('\n', 1)[0])
4004 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4004 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
4005 if names:
4005 if names:
4006 desc += ' (%s)' % ' '.join(names)
4006 desc += ' (%s)' % ' '.join(names)
4007 ui.status(_('grafting %s\n') % desc)
4007 ui.status(_('grafting %s\n') % desc)
4008 if opts.get('dry_run'):
4008 if opts.get('dry_run'):
4009 continue
4009 continue
4010
4010
4011 extra = ctx.extra().copy()
4011 extra = ctx.extra().copy()
4012 del extra['branch']
4012 del extra['branch']
4013 source = extra.get('source')
4013 source = extra.get('source')
4014 if source:
4014 if source:
4015 extra['intermediate-source'] = ctx.hex()
4015 extra['intermediate-source'] = ctx.hex()
4016 else:
4016 else:
4017 extra['source'] = ctx.hex()
4017 extra['source'] = ctx.hex()
4018 user = ctx.user()
4018 user = ctx.user()
4019 if opts.get('user'):
4019 if opts.get('user'):
4020 user = opts['user']
4020 user = opts['user']
4021 date = ctx.date()
4021 date = ctx.date()
4022 if opts.get('date'):
4022 if opts.get('date'):
4023 date = opts['date']
4023 date = opts['date']
4024 message = ctx.description()
4024 message = ctx.description()
4025 if opts.get('log'):
4025 if opts.get('log'):
4026 message += '\n(grafted from %s)' % ctx.hex()
4026 message += '\n(grafted from %s)' % ctx.hex()
4027
4027
4028 # we don't merge the first commit when continuing
4028 # we don't merge the first commit when continuing
4029 if not cont:
4029 if not cont:
4030 # perform the graft merge with p1(rev) as 'ancestor'
4030 # perform the graft merge with p1(rev) as 'ancestor'
4031 try:
4031 try:
4032 # ui.forcemerge is an internal variable, do not document
4032 # ui.forcemerge is an internal variable, do not document
4033 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4033 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4034 'graft')
4034 'graft')
4035 stats = mergemod.graft(repo, ctx, ctx.p1(),
4035 stats = mergemod.graft(repo, ctx, ctx.p1(),
4036 ['local', 'graft'])
4036 ['local', 'graft'])
4037 finally:
4037 finally:
4038 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4038 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4039 # report any conflicts
4039 # report any conflicts
4040 if stats and stats[3] > 0:
4040 if stats and stats[3] > 0:
4041 # write out state for --continue
4041 # write out state for --continue
4042 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4042 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4043 repo.vfs.write('graftstate', ''.join(nodelines))
4043 repo.vfs.write('graftstate', ''.join(nodelines))
4044 extra = ''
4044 extra = ''
4045 if opts.get('user'):
4045 if opts.get('user'):
4046 extra += ' --user %s' % opts['user']
4046 extra += ' --user %s' % opts['user']
4047 if opts.get('date'):
4047 if opts.get('date'):
4048 extra += ' --date %s' % opts['date']
4048 extra += ' --date %s' % opts['date']
4049 if opts.get('log'):
4049 if opts.get('log'):
4050 extra += ' --log'
4050 extra += ' --log'
4051 hint=_('use hg resolve and hg graft --continue%s') % extra
4051 hint=_('use hg resolve and hg graft --continue%s') % extra
4052 raise error.Abort(
4052 raise error.Abort(
4053 _("unresolved conflicts, can't continue"),
4053 _("unresolved conflicts, can't continue"),
4054 hint=hint)
4054 hint=hint)
4055 else:
4055 else:
4056 cont = False
4056 cont = False
4057
4057
4058 # commit
4058 # commit
4059 node = repo.commit(text=message, user=user,
4059 node = repo.commit(text=message, user=user,
4060 date=date, extra=extra, editor=editor)
4060 date=date, extra=extra, editor=editor)
4061 if node is None:
4061 if node is None:
4062 ui.warn(
4062 ui.warn(
4063 _('note: graft of %d:%s created no changes to commit\n') %
4063 _('note: graft of %d:%s created no changes to commit\n') %
4064 (ctx.rev(), ctx))
4064 (ctx.rev(), ctx))
4065
4065
4066 # remove state when we complete successfully
4066 # remove state when we complete successfully
4067 if not opts.get('dry_run'):
4067 if not opts.get('dry_run'):
4068 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4068 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4069
4069
4070 return 0
4070 return 0
4071
4071
4072 @command('grep',
4072 @command('grep',
4073 [('0', 'print0', None, _('end fields with NUL')),
4073 [('0', 'print0', None, _('end fields with NUL')),
4074 ('', 'all', None, _('print all revisions that match')),
4074 ('', 'all', None, _('print all revisions that match')),
4075 ('a', 'text', None, _('treat all files as text')),
4075 ('a', 'text', None, _('treat all files as text')),
4076 ('f', 'follow', None,
4076 ('f', 'follow', None,
4077 _('follow changeset history,'
4077 _('follow changeset history,'
4078 ' or file history across copies and renames')),
4078 ' or file history across copies and renames')),
4079 ('i', 'ignore-case', None, _('ignore case when matching')),
4079 ('i', 'ignore-case', None, _('ignore case when matching')),
4080 ('l', 'files-with-matches', None,
4080 ('l', 'files-with-matches', None,
4081 _('print only filenames and revisions that match')),
4081 _('print only filenames and revisions that match')),
4082 ('n', 'line-number', None, _('print matching line numbers')),
4082 ('n', 'line-number', None, _('print matching line numbers')),
4083 ('r', 'rev', [],
4083 ('r', 'rev', [],
4084 _('only search files changed within revision range'), _('REV')),
4084 _('only search files changed within revision range'), _('REV')),
4085 ('u', 'user', None, _('list the author (long with -v)')),
4085 ('u', 'user', None, _('list the author (long with -v)')),
4086 ('d', 'date', None, _('list the date (short with -q)')),
4086 ('d', 'date', None, _('list the date (short with -q)')),
4087 ] + walkopts,
4087 ] + walkopts,
4088 _('[OPTION]... PATTERN [FILE]...'),
4088 _('[OPTION]... PATTERN [FILE]...'),
4089 inferrepo=True)
4089 inferrepo=True)
4090 def grep(ui, repo, pattern, *pats, **opts):
4090 def grep(ui, repo, pattern, *pats, **opts):
4091 """search for a pattern in specified files and revisions
4091 """search for a pattern in specified files and revisions
4092
4092
4093 Search revisions of files for a regular expression.
4093 Search revisions of files for a regular expression.
4094
4094
4095 This command behaves differently than Unix grep. It only accepts
4095 This command behaves differently than Unix grep. It only accepts
4096 Python/Perl regexps. It searches repository history, not the
4096 Python/Perl regexps. It searches repository history, not the
4097 working directory. It always prints the revision number in which a
4097 working directory. It always prints the revision number in which a
4098 match appears.
4098 match appears.
4099
4099
4100 By default, grep only prints output for the first revision of a
4100 By default, grep only prints output for the first revision of a
4101 file in which it finds a match. To get it to print every revision
4101 file in which it finds a match. To get it to print every revision
4102 that contains a change in match status ("-" for a match that
4102 that contains a change in match status ("-" for a match that
4103 becomes a non-match, or "+" for a non-match that becomes a match),
4103 becomes a non-match, or "+" for a non-match that becomes a match),
4104 use the --all flag.
4104 use the --all flag.
4105
4105
4106 Returns 0 if a match is found, 1 otherwise.
4106 Returns 0 if a match is found, 1 otherwise.
4107 """
4107 """
4108 reflags = re.M
4108 reflags = re.M
4109 if opts.get('ignore_case'):
4109 if opts.get('ignore_case'):
4110 reflags |= re.I
4110 reflags |= re.I
4111 try:
4111 try:
4112 regexp = util.re.compile(pattern, reflags)
4112 regexp = util.re.compile(pattern, reflags)
4113 except re.error as inst:
4113 except re.error as inst:
4114 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4114 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4115 return 1
4115 return 1
4116 sep, eol = ':', '\n'
4116 sep, eol = ':', '\n'
4117 if opts.get('print0'):
4117 if opts.get('print0'):
4118 sep = eol = '\0'
4118 sep = eol = '\0'
4119
4119
4120 getfile = util.lrucachefunc(repo.file)
4120 getfile = util.lrucachefunc(repo.file)
4121
4121
4122 def matchlines(body):
4122 def matchlines(body):
4123 begin = 0
4123 begin = 0
4124 linenum = 0
4124 linenum = 0
4125 while begin < len(body):
4125 while begin < len(body):
4126 match = regexp.search(body, begin)
4126 match = regexp.search(body, begin)
4127 if not match:
4127 if not match:
4128 break
4128 break
4129 mstart, mend = match.span()
4129 mstart, mend = match.span()
4130 linenum += body.count('\n', begin, mstart) + 1
4130 linenum += body.count('\n', begin, mstart) + 1
4131 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4131 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4132 begin = body.find('\n', mend) + 1 or len(body) + 1
4132 begin = body.find('\n', mend) + 1 or len(body) + 1
4133 lend = begin - 1
4133 lend = begin - 1
4134 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4134 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4135
4135
4136 class linestate(object):
4136 class linestate(object):
4137 def __init__(self, line, linenum, colstart, colend):
4137 def __init__(self, line, linenum, colstart, colend):
4138 self.line = line
4138 self.line = line
4139 self.linenum = linenum
4139 self.linenum = linenum
4140 self.colstart = colstart
4140 self.colstart = colstart
4141 self.colend = colend
4141 self.colend = colend
4142
4142
4143 def __hash__(self):
4143 def __hash__(self):
4144 return hash((self.linenum, self.line))
4144 return hash((self.linenum, self.line))
4145
4145
4146 def __eq__(self, other):
4146 def __eq__(self, other):
4147 return self.line == other.line
4147 return self.line == other.line
4148
4148
4149 def __iter__(self):
4149 def __iter__(self):
4150 yield (self.line[:self.colstart], '')
4150 yield (self.line[:self.colstart], '')
4151 yield (self.line[self.colstart:self.colend], 'grep.match')
4151 yield (self.line[self.colstart:self.colend], 'grep.match')
4152 rest = self.line[self.colend:]
4152 rest = self.line[self.colend:]
4153 while rest != '':
4153 while rest != '':
4154 match = regexp.search(rest)
4154 match = regexp.search(rest)
4155 if not match:
4155 if not match:
4156 yield (rest, '')
4156 yield (rest, '')
4157 break
4157 break
4158 mstart, mend = match.span()
4158 mstart, mend = match.span()
4159 yield (rest[:mstart], '')
4159 yield (rest[:mstart], '')
4160 yield (rest[mstart:mend], 'grep.match')
4160 yield (rest[mstart:mend], 'grep.match')
4161 rest = rest[mend:]
4161 rest = rest[mend:]
4162
4162
4163 matches = {}
4163 matches = {}
4164 copies = {}
4164 copies = {}
4165 def grepbody(fn, rev, body):
4165 def grepbody(fn, rev, body):
4166 matches[rev].setdefault(fn, [])
4166 matches[rev].setdefault(fn, [])
4167 m = matches[rev][fn]
4167 m = matches[rev][fn]
4168 for lnum, cstart, cend, line in matchlines(body):
4168 for lnum, cstart, cend, line in matchlines(body):
4169 s = linestate(line, lnum, cstart, cend)
4169 s = linestate(line, lnum, cstart, cend)
4170 m.append(s)
4170 m.append(s)
4171
4171
4172 def difflinestates(a, b):
4172 def difflinestates(a, b):
4173 sm = difflib.SequenceMatcher(None, a, b)
4173 sm = difflib.SequenceMatcher(None, a, b)
4174 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4174 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4175 if tag == 'insert':
4175 if tag == 'insert':
4176 for i in xrange(blo, bhi):
4176 for i in xrange(blo, bhi):
4177 yield ('+', b[i])
4177 yield ('+', b[i])
4178 elif tag == 'delete':
4178 elif tag == 'delete':
4179 for i in xrange(alo, ahi):
4179 for i in xrange(alo, ahi):
4180 yield ('-', a[i])
4180 yield ('-', a[i])
4181 elif tag == 'replace':
4181 elif tag == 'replace':
4182 for i in xrange(alo, ahi):
4182 for i in xrange(alo, ahi):
4183 yield ('-', a[i])
4183 yield ('-', a[i])
4184 for i in xrange(blo, bhi):
4184 for i in xrange(blo, bhi):
4185 yield ('+', b[i])
4185 yield ('+', b[i])
4186
4186
4187 def display(fn, ctx, pstates, states):
4187 def display(fn, ctx, pstates, states):
4188 rev = ctx.rev()
4188 rev = ctx.rev()
4189 if ui.quiet:
4189 if ui.quiet:
4190 datefunc = util.shortdate
4190 datefunc = util.shortdate
4191 else:
4191 else:
4192 datefunc = util.datestr
4192 datefunc = util.datestr
4193 found = False
4193 found = False
4194 @util.cachefunc
4194 @util.cachefunc
4195 def binary():
4195 def binary():
4196 flog = getfile(fn)
4196 flog = getfile(fn)
4197 return util.binary(flog.read(ctx.filenode(fn)))
4197 return util.binary(flog.read(ctx.filenode(fn)))
4198
4198
4199 if opts.get('all'):
4199 if opts.get('all'):
4200 iter = difflinestates(pstates, states)
4200 iter = difflinestates(pstates, states)
4201 else:
4201 else:
4202 iter = [('', l) for l in states]
4202 iter = [('', l) for l in states]
4203 for change, l in iter:
4203 for change, l in iter:
4204 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4204 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4205
4205
4206 if opts.get('line_number'):
4206 if opts.get('line_number'):
4207 cols.append((str(l.linenum), 'grep.linenumber'))
4207 cols.append((str(l.linenum), 'grep.linenumber'))
4208 if opts.get('all'):
4208 if opts.get('all'):
4209 cols.append((change, 'grep.change'))
4209 cols.append((change, 'grep.change'))
4210 if opts.get('user'):
4210 if opts.get('user'):
4211 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4211 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4212 if opts.get('date'):
4212 if opts.get('date'):
4213 cols.append((datefunc(ctx.date()), 'grep.date'))
4213 cols.append((datefunc(ctx.date()), 'grep.date'))
4214 for col, label in cols[:-1]:
4214 for col, label in cols[:-1]:
4215 ui.write(col, label=label)
4215 ui.write(col, label=label)
4216 ui.write(sep, label='grep.sep')
4216 ui.write(sep, label='grep.sep')
4217 ui.write(cols[-1][0], label=cols[-1][1])
4217 ui.write(cols[-1][0], label=cols[-1][1])
4218 if not opts.get('files_with_matches'):
4218 if not opts.get('files_with_matches'):
4219 ui.write(sep, label='grep.sep')
4219 ui.write(sep, label='grep.sep')
4220 if not opts.get('text') and binary():
4220 if not opts.get('text') and binary():
4221 ui.write(" Binary file matches")
4221 ui.write(" Binary file matches")
4222 else:
4222 else:
4223 for s, label in l:
4223 for s, label in l:
4224 ui.write(s, label=label)
4224 ui.write(s, label=label)
4225 ui.write(eol)
4225 ui.write(eol)
4226 found = True
4226 found = True
4227 if opts.get('files_with_matches'):
4227 if opts.get('files_with_matches'):
4228 break
4228 break
4229 return found
4229 return found
4230
4230
4231 skip = {}
4231 skip = {}
4232 revfiles = {}
4232 revfiles = {}
4233 matchfn = scmutil.match(repo[None], pats, opts)
4233 matchfn = scmutil.match(repo[None], pats, opts)
4234 found = False
4234 found = False
4235 follow = opts.get('follow')
4235 follow = opts.get('follow')
4236
4236
4237 def prep(ctx, fns):
4237 def prep(ctx, fns):
4238 rev = ctx.rev()
4238 rev = ctx.rev()
4239 pctx = ctx.p1()
4239 pctx = ctx.p1()
4240 parent = pctx.rev()
4240 parent = pctx.rev()
4241 matches.setdefault(rev, {})
4241 matches.setdefault(rev, {})
4242 matches.setdefault(parent, {})
4242 matches.setdefault(parent, {})
4243 files = revfiles.setdefault(rev, [])
4243 files = revfiles.setdefault(rev, [])
4244 for fn in fns:
4244 for fn in fns:
4245 flog = getfile(fn)
4245 flog = getfile(fn)
4246 try:
4246 try:
4247 fnode = ctx.filenode(fn)
4247 fnode = ctx.filenode(fn)
4248 except error.LookupError:
4248 except error.LookupError:
4249 continue
4249 continue
4250
4250
4251 copied = flog.renamed(fnode)
4251 copied = flog.renamed(fnode)
4252 copy = follow and copied and copied[0]
4252 copy = follow and copied and copied[0]
4253 if copy:
4253 if copy:
4254 copies.setdefault(rev, {})[fn] = copy
4254 copies.setdefault(rev, {})[fn] = copy
4255 if fn in skip:
4255 if fn in skip:
4256 if copy:
4256 if copy:
4257 skip[copy] = True
4257 skip[copy] = True
4258 continue
4258 continue
4259 files.append(fn)
4259 files.append(fn)
4260
4260
4261 if fn not in matches[rev]:
4261 if fn not in matches[rev]:
4262 grepbody(fn, rev, flog.read(fnode))
4262 grepbody(fn, rev, flog.read(fnode))
4263
4263
4264 pfn = copy or fn
4264 pfn = copy or fn
4265 if pfn not in matches[parent]:
4265 if pfn not in matches[parent]:
4266 try:
4266 try:
4267 fnode = pctx.filenode(pfn)
4267 fnode = pctx.filenode(pfn)
4268 grepbody(pfn, parent, flog.read(fnode))
4268 grepbody(pfn, parent, flog.read(fnode))
4269 except error.LookupError:
4269 except error.LookupError:
4270 pass
4270 pass
4271
4271
4272 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4272 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4273 rev = ctx.rev()
4273 rev = ctx.rev()
4274 parent = ctx.p1().rev()
4274 parent = ctx.p1().rev()
4275 for fn in sorted(revfiles.get(rev, [])):
4275 for fn in sorted(revfiles.get(rev, [])):
4276 states = matches[rev][fn]
4276 states = matches[rev][fn]
4277 copy = copies.get(rev, {}).get(fn)
4277 copy = copies.get(rev, {}).get(fn)
4278 if fn in skip:
4278 if fn in skip:
4279 if copy:
4279 if copy:
4280 skip[copy] = True
4280 skip[copy] = True
4281 continue
4281 continue
4282 pstates = matches.get(parent, {}).get(copy or fn, [])
4282 pstates = matches.get(parent, {}).get(copy or fn, [])
4283 if pstates or states:
4283 if pstates or states:
4284 r = display(fn, ctx, pstates, states)
4284 r = display(fn, ctx, pstates, states)
4285 found = found or r
4285 found = found or r
4286 if r and not opts.get('all'):
4286 if r and not opts.get('all'):
4287 skip[fn] = True
4287 skip[fn] = True
4288 if copy:
4288 if copy:
4289 skip[copy] = True
4289 skip[copy] = True
4290 del matches[rev]
4290 del matches[rev]
4291 del revfiles[rev]
4291 del revfiles[rev]
4292
4292
4293 return not found
4293 return not found
4294
4294
4295 @command('heads',
4295 @command('heads',
4296 [('r', 'rev', '',
4296 [('r', 'rev', '',
4297 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4297 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4298 ('t', 'topo', False, _('show topological heads only')),
4298 ('t', 'topo', False, _('show topological heads only')),
4299 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4299 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4300 ('c', 'closed', False, _('show normal and closed branch heads')),
4300 ('c', 'closed', False, _('show normal and closed branch heads')),
4301 ] + templateopts,
4301 ] + templateopts,
4302 _('[-ct] [-r STARTREV] [REV]...'))
4302 _('[-ct] [-r STARTREV] [REV]...'))
4303 def heads(ui, repo, *branchrevs, **opts):
4303 def heads(ui, repo, *branchrevs, **opts):
4304 """show branch heads
4304 """show branch heads
4305
4305
4306 With no arguments, show all open branch heads in the repository.
4306 With no arguments, show all open branch heads in the repository.
4307 Branch heads are changesets that have no descendants on the
4307 Branch heads are changesets that have no descendants on the
4308 same branch. They are where development generally takes place and
4308 same branch. They are where development generally takes place and
4309 are the usual targets for update and merge operations.
4309 are the usual targets for update and merge operations.
4310
4310
4311 If one or more REVs are given, only open branch heads on the
4311 If one or more REVs are given, only open branch heads on the
4312 branches associated with the specified changesets are shown. This
4312 branches associated with the specified changesets are shown. This
4313 means that you can use :hg:`heads .` to see the heads on the
4313 means that you can use :hg:`heads .` to see the heads on the
4314 currently checked-out branch.
4314 currently checked-out branch.
4315
4315
4316 If -c/--closed is specified, also show branch heads marked closed
4316 If -c/--closed is specified, also show branch heads marked closed
4317 (see :hg:`commit --close-branch`).
4317 (see :hg:`commit --close-branch`).
4318
4318
4319 If STARTREV is specified, only those heads that are descendants of
4319 If STARTREV is specified, only those heads that are descendants of
4320 STARTREV will be displayed.
4320 STARTREV will be displayed.
4321
4321
4322 If -t/--topo is specified, named branch mechanics will be ignored and only
4322 If -t/--topo is specified, named branch mechanics will be ignored and only
4323 topological heads (changesets with no children) will be shown.
4323 topological heads (changesets with no children) will be shown.
4324
4324
4325 Returns 0 if matching heads are found, 1 if not.
4325 Returns 0 if matching heads are found, 1 if not.
4326 """
4326 """
4327
4327
4328 start = None
4328 start = None
4329 if 'rev' in opts:
4329 if 'rev' in opts:
4330 start = scmutil.revsingle(repo, opts['rev'], None).node()
4330 start = scmutil.revsingle(repo, opts['rev'], None).node()
4331
4331
4332 if opts.get('topo'):
4332 if opts.get('topo'):
4333 heads = [repo[h] for h in repo.heads(start)]
4333 heads = [repo[h] for h in repo.heads(start)]
4334 else:
4334 else:
4335 heads = []
4335 heads = []
4336 for branch in repo.branchmap():
4336 for branch in repo.branchmap():
4337 heads += repo.branchheads(branch, start, opts.get('closed'))
4337 heads += repo.branchheads(branch, start, opts.get('closed'))
4338 heads = [repo[h] for h in heads]
4338 heads = [repo[h] for h in heads]
4339
4339
4340 if branchrevs:
4340 if branchrevs:
4341 branches = set(repo[br].branch() for br in branchrevs)
4341 branches = set(repo[br].branch() for br in branchrevs)
4342 heads = [h for h in heads if h.branch() in branches]
4342 heads = [h for h in heads if h.branch() in branches]
4343
4343
4344 if opts.get('active') and branchrevs:
4344 if opts.get('active') and branchrevs:
4345 dagheads = repo.heads(start)
4345 dagheads = repo.heads(start)
4346 heads = [h for h in heads if h.node() in dagheads]
4346 heads = [h for h in heads if h.node() in dagheads]
4347
4347
4348 if branchrevs:
4348 if branchrevs:
4349 haveheads = set(h.branch() for h in heads)
4349 haveheads = set(h.branch() for h in heads)
4350 if branches - haveheads:
4350 if branches - haveheads:
4351 headless = ', '.join(b for b in branches - haveheads)
4351 headless = ', '.join(b for b in branches - haveheads)
4352 msg = _('no open branch heads found on branches %s')
4352 msg = _('no open branch heads found on branches %s')
4353 if opts.get('rev'):
4353 if opts.get('rev'):
4354 msg += _(' (started at %s)') % opts['rev']
4354 msg += _(' (started at %s)') % opts['rev']
4355 ui.warn((msg + '\n') % headless)
4355 ui.warn((msg + '\n') % headless)
4356
4356
4357 if not heads:
4357 if not heads:
4358 return 1
4358 return 1
4359
4359
4360 heads = sorted(heads, key=lambda x: -x.rev())
4360 heads = sorted(heads, key=lambda x: -x.rev())
4361 displayer = cmdutil.show_changeset(ui, repo, opts)
4361 displayer = cmdutil.show_changeset(ui, repo, opts)
4362 for ctx in heads:
4362 for ctx in heads:
4363 displayer.show(ctx)
4363 displayer.show(ctx)
4364 displayer.close()
4364 displayer.close()
4365
4365
4366 @command('help',
4366 @command('help',
4367 [('e', 'extension', None, _('show only help for extensions')),
4367 [('e', 'extension', None, _('show only help for extensions')),
4368 ('c', 'command', None, _('show only help for commands')),
4368 ('c', 'command', None, _('show only help for commands')),
4369 ('k', 'keyword', None, _('show topics matching keyword')),
4369 ('k', 'keyword', None, _('show topics matching keyword')),
4370 ],
4370 ],
4371 _('[-eck] [TOPIC]'),
4371 _('[-eck] [TOPIC]'),
4372 norepo=True)
4372 norepo=True)
4373 def help_(ui, name=None, **opts):
4373 def help_(ui, name=None, **opts):
4374 """show help for a given topic or a help overview
4374 """show help for a given topic or a help overview
4375
4375
4376 With no arguments, print a list of commands with short help messages.
4376 With no arguments, print a list of commands with short help messages.
4377
4377
4378 Given a topic, extension, or command name, print help for that
4378 Given a topic, extension, or command name, print help for that
4379 topic.
4379 topic.
4380
4380
4381 Returns 0 if successful.
4381 Returns 0 if successful.
4382 """
4382 """
4383
4383
4384 textwidth = min(ui.termwidth(), 80) - 2
4384 textwidth = min(ui.termwidth(), 80) - 2
4385
4385
4386 keep = []
4386 keep = []
4387 if ui.verbose:
4387 if ui.verbose:
4388 keep.append('verbose')
4388 keep.append('verbose')
4389 if sys.platform.startswith('win'):
4389 if sys.platform.startswith('win'):
4390 keep.append('windows')
4390 keep.append('windows')
4391 elif sys.platform == 'OpenVMS':
4391 elif sys.platform == 'OpenVMS':
4392 keep.append('vms')
4392 keep.append('vms')
4393 elif sys.platform == 'plan9':
4393 elif sys.platform == 'plan9':
4394 keep.append('plan9')
4394 keep.append('plan9')
4395 else:
4395 else:
4396 keep.append('unix')
4396 keep.append('unix')
4397 keep.append(sys.platform.lower())
4397 keep.append(sys.platform.lower())
4398
4398
4399 section = None
4399 section = None
4400 subtopic = None
4400 subtopic = None
4401 if name and '.' in name:
4401 if name and '.' in name:
4402 name, section = name.split('.', 1)
4402 name, section = name.split('.', 1)
4403 section = section.lower()
4403 section = section.lower()
4404 if '.' in section:
4404 if '.' in section:
4405 subtopic, section = section.split('.', 1)
4405 subtopic, section = section.split('.', 1)
4406 else:
4406 else:
4407 subtopic = section
4407 subtopic = section
4408
4408
4409 text = help.help_(ui, name, subtopic=subtopic, **opts)
4409 text = help.help_(ui, name, subtopic=subtopic, **opts)
4410
4410
4411 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4411 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4412 section=section)
4412 section=section)
4413
4413
4414 # We could have been given a weird ".foo" section without a name
4414 # We could have been given a weird ".foo" section without a name
4415 # to look for, or we could have simply failed to found "foo.bar"
4415 # to look for, or we could have simply failed to found "foo.bar"
4416 # because bar isn't a section of foo
4416 # because bar isn't a section of foo
4417 if section and not (formatted and name):
4417 if section and not (formatted and name):
4418 raise error.Abort(_("help section not found"))
4418 raise error.Abort(_("help section not found"))
4419
4419
4420 if 'verbose' in pruned:
4420 if 'verbose' in pruned:
4421 keep.append('omitted')
4421 keep.append('omitted')
4422 else:
4422 else:
4423 keep.append('notomitted')
4423 keep.append('notomitted')
4424 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4424 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4425 section=section)
4425 section=section)
4426 ui.write(formatted)
4426 ui.write(formatted)
4427
4427
4428
4428
4429 @command('identify|id',
4429 @command('identify|id',
4430 [('r', 'rev', '',
4430 [('r', 'rev', '',
4431 _('identify the specified revision'), _('REV')),
4431 _('identify the specified revision'), _('REV')),
4432 ('n', 'num', None, _('show local revision number')),
4432 ('n', 'num', None, _('show local revision number')),
4433 ('i', 'id', None, _('show global revision id')),
4433 ('i', 'id', None, _('show global revision id')),
4434 ('b', 'branch', None, _('show branch')),
4434 ('b', 'branch', None, _('show branch')),
4435 ('t', 'tags', None, _('show tags')),
4435 ('t', 'tags', None, _('show tags')),
4436 ('B', 'bookmarks', None, _('show bookmarks')),
4436 ('B', 'bookmarks', None, _('show bookmarks')),
4437 ] + remoteopts,
4437 ] + remoteopts,
4438 _('[-nibtB] [-r REV] [SOURCE]'),
4438 _('[-nibtB] [-r REV] [SOURCE]'),
4439 optionalrepo=True)
4439 optionalrepo=True)
4440 def identify(ui, repo, source=None, rev=None,
4440 def identify(ui, repo, source=None, rev=None,
4441 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4441 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4442 """identify the working directory or specified revision
4442 """identify the working directory or specified revision
4443
4443
4444 Print a summary identifying the repository state at REV using one or
4444 Print a summary identifying the repository state at REV using one or
4445 two parent hash identifiers, followed by a "+" if the working
4445 two parent hash identifiers, followed by a "+" if the working
4446 directory has uncommitted changes, the branch name (if not default),
4446 directory has uncommitted changes, the branch name (if not default),
4447 a list of tags, and a list of bookmarks.
4447 a list of tags, and a list of bookmarks.
4448
4448
4449 When REV is not given, print a summary of the current state of the
4449 When REV is not given, print a summary of the current state of the
4450 repository.
4450 repository.
4451
4451
4452 Specifying a path to a repository root or Mercurial bundle will
4452 Specifying a path to a repository root or Mercurial bundle will
4453 cause lookup to operate on that repository/bundle.
4453 cause lookup to operate on that repository/bundle.
4454
4454
4455 .. container:: verbose
4455 .. container:: verbose
4456
4456
4457 Examples:
4457 Examples:
4458
4458
4459 - generate a build identifier for the working directory::
4459 - generate a build identifier for the working directory::
4460
4460
4461 hg id --id > build-id.dat
4461 hg id --id > build-id.dat
4462
4462
4463 - find the revision corresponding to a tag::
4463 - find the revision corresponding to a tag::
4464
4464
4465 hg id -n -r 1.3
4465 hg id -n -r 1.3
4466
4466
4467 - check the most recent revision of a remote repository::
4467 - check the most recent revision of a remote repository::
4468
4468
4469 hg id -r tip http://selenic.com/hg/
4469 hg id -r tip http://selenic.com/hg/
4470
4470
4471 See :hg:`log` for generating more information about specific revisions,
4471 See :hg:`log` for generating more information about specific revisions,
4472 including full hash identifiers.
4472 including full hash identifiers.
4473
4473
4474 Returns 0 if successful.
4474 Returns 0 if successful.
4475 """
4475 """
4476
4476
4477 if not repo and not source:
4477 if not repo and not source:
4478 raise error.Abort(_("there is no Mercurial repository here "
4478 raise error.Abort(_("there is no Mercurial repository here "
4479 "(.hg not found)"))
4479 "(.hg not found)"))
4480
4480
4481 if ui.debugflag:
4481 if ui.debugflag:
4482 hexfunc = hex
4482 hexfunc = hex
4483 else:
4483 else:
4484 hexfunc = short
4484 hexfunc = short
4485 default = not (num or id or branch or tags or bookmarks)
4485 default = not (num or id or branch or tags or bookmarks)
4486 output = []
4486 output = []
4487 revs = []
4487 revs = []
4488
4488
4489 if source:
4489 if source:
4490 source, branches = hg.parseurl(ui.expandpath(source))
4490 source, branches = hg.parseurl(ui.expandpath(source))
4491 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4491 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4492 repo = peer.local()
4492 repo = peer.local()
4493 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4493 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4494
4494
4495 if not repo:
4495 if not repo:
4496 if num or branch or tags:
4496 if num or branch or tags:
4497 raise error.Abort(
4497 raise error.Abort(
4498 _("can't query remote revision number, branch, or tags"))
4498 _("can't query remote revision number, branch, or tags"))
4499 if not rev and revs:
4499 if not rev and revs:
4500 rev = revs[0]
4500 rev = revs[0]
4501 if not rev:
4501 if not rev:
4502 rev = "tip"
4502 rev = "tip"
4503
4503
4504 remoterev = peer.lookup(rev)
4504 remoterev = peer.lookup(rev)
4505 if default or id:
4505 if default or id:
4506 output = [hexfunc(remoterev)]
4506 output = [hexfunc(remoterev)]
4507
4507
4508 def getbms():
4508 def getbms():
4509 bms = []
4509 bms = []
4510
4510
4511 if 'bookmarks' in peer.listkeys('namespaces'):
4511 if 'bookmarks' in peer.listkeys('namespaces'):
4512 hexremoterev = hex(remoterev)
4512 hexremoterev = hex(remoterev)
4513 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4513 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4514 if bmr == hexremoterev]
4514 if bmr == hexremoterev]
4515
4515
4516 return sorted(bms)
4516 return sorted(bms)
4517
4517
4518 if bookmarks:
4518 if bookmarks:
4519 output.extend(getbms())
4519 output.extend(getbms())
4520 elif default and not ui.quiet:
4520 elif default and not ui.quiet:
4521 # multiple bookmarks for a single parent separated by '/'
4521 # multiple bookmarks for a single parent separated by '/'
4522 bm = '/'.join(getbms())
4522 bm = '/'.join(getbms())
4523 if bm:
4523 if bm:
4524 output.append(bm)
4524 output.append(bm)
4525 else:
4525 else:
4526 ctx = scmutil.revsingle(repo, rev, None)
4526 ctx = scmutil.revsingle(repo, rev, None)
4527
4527
4528 if ctx.rev() is None:
4528 if ctx.rev() is None:
4529 ctx = repo[None]
4529 ctx = repo[None]
4530 parents = ctx.parents()
4530 parents = ctx.parents()
4531 taglist = []
4531 taglist = []
4532 for p in parents:
4532 for p in parents:
4533 taglist.extend(p.tags())
4533 taglist.extend(p.tags())
4534
4534
4535 changed = ""
4535 changed = ""
4536 if default or id or num:
4536 if default or id or num:
4537 if (any(repo.status())
4537 if (any(repo.status())
4538 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4538 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4539 changed = '+'
4539 changed = '+'
4540 if default or id:
4540 if default or id:
4541 output = ["%s%s" %
4541 output = ["%s%s" %
4542 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4542 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4543 if num:
4543 if num:
4544 output.append("%s%s" %
4544 output.append("%s%s" %
4545 ('+'.join([str(p.rev()) for p in parents]), changed))
4545 ('+'.join([str(p.rev()) for p in parents]), changed))
4546 else:
4546 else:
4547 if default or id:
4547 if default or id:
4548 output = [hexfunc(ctx.node())]
4548 output = [hexfunc(ctx.node())]
4549 if num:
4549 if num:
4550 output.append(str(ctx.rev()))
4550 output.append(str(ctx.rev()))
4551 taglist = ctx.tags()
4551 taglist = ctx.tags()
4552
4552
4553 if default and not ui.quiet:
4553 if default and not ui.quiet:
4554 b = ctx.branch()
4554 b = ctx.branch()
4555 if b != 'default':
4555 if b != 'default':
4556 output.append("(%s)" % b)
4556 output.append("(%s)" % b)
4557
4557
4558 # multiple tags for a single parent separated by '/'
4558 # multiple tags for a single parent separated by '/'
4559 t = '/'.join(taglist)
4559 t = '/'.join(taglist)
4560 if t:
4560 if t:
4561 output.append(t)
4561 output.append(t)
4562
4562
4563 # multiple bookmarks for a single parent separated by '/'
4563 # multiple bookmarks for a single parent separated by '/'
4564 bm = '/'.join(ctx.bookmarks())
4564 bm = '/'.join(ctx.bookmarks())
4565 if bm:
4565 if bm:
4566 output.append(bm)
4566 output.append(bm)
4567 else:
4567 else:
4568 if branch:
4568 if branch:
4569 output.append(ctx.branch())
4569 output.append(ctx.branch())
4570
4570
4571 if tags:
4571 if tags:
4572 output.extend(taglist)
4572 output.extend(taglist)
4573
4573
4574 if bookmarks:
4574 if bookmarks:
4575 output.extend(ctx.bookmarks())
4575 output.extend(ctx.bookmarks())
4576
4576
4577 ui.write("%s\n" % ' '.join(output))
4577 ui.write("%s\n" % ' '.join(output))
4578
4578
4579 @command('import|patch',
4579 @command('import|patch',
4580 [('p', 'strip', 1,
4580 [('p', 'strip', 1,
4581 _('directory strip option for patch. This has the same '
4581 _('directory strip option for patch. This has the same '
4582 'meaning as the corresponding patch option'), _('NUM')),
4582 'meaning as the corresponding patch option'), _('NUM')),
4583 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4583 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4584 ('e', 'edit', False, _('invoke editor on commit messages')),
4584 ('e', 'edit', False, _('invoke editor on commit messages')),
4585 ('f', 'force', None,
4585 ('f', 'force', None,
4586 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4586 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4587 ('', 'no-commit', None,
4587 ('', 'no-commit', None,
4588 _("don't commit, just update the working directory")),
4588 _("don't commit, just update the working directory")),
4589 ('', 'bypass', None,
4589 ('', 'bypass', None,
4590 _("apply patch without touching the working directory")),
4590 _("apply patch without touching the working directory")),
4591 ('', 'partial', None,
4591 ('', 'partial', None,
4592 _('commit even if some hunks fail')),
4592 _('commit even if some hunks fail')),
4593 ('', 'exact', None,
4593 ('', 'exact', None,
4594 _('apply patch to the nodes from which it was generated')),
4594 _('apply patch to the nodes from which it was generated')),
4595 ('', 'prefix', '',
4595 ('', 'prefix', '',
4596 _('apply patch to subdirectory'), _('DIR')),
4596 _('apply patch to subdirectory'), _('DIR')),
4597 ('', 'import-branch', None,
4597 ('', 'import-branch', None,
4598 _('use any branch information in patch (implied by --exact)'))] +
4598 _('use any branch information in patch (implied by --exact)'))] +
4599 commitopts + commitopts2 + similarityopts,
4599 commitopts + commitopts2 + similarityopts,
4600 _('[OPTION]... PATCH...'))
4600 _('[OPTION]... PATCH...'))
4601 def import_(ui, repo, patch1=None, *patches, **opts):
4601 def import_(ui, repo, patch1=None, *patches, **opts):
4602 """import an ordered set of patches
4602 """import an ordered set of patches
4603
4603
4604 Import a list of patches and commit them individually (unless
4604 Import a list of patches and commit them individually (unless
4605 --no-commit is specified).
4605 --no-commit is specified).
4606
4606
4607 To read a patch from standard input, use "-" as the patch name. If
4607 To read a patch from standard input, use "-" as the patch name. If
4608 a URL is specified, the patch will be downloaded from there.
4608 a URL is specified, the patch will be downloaded from there.
4609
4609
4610 Import first applies changes to the working directory (unless
4610 Import first applies changes to the working directory (unless
4611 --bypass is specified), import will abort if there are outstanding
4611 --bypass is specified), import will abort if there are outstanding
4612 changes.
4612 changes.
4613
4613
4614 Use --bypass to apply and commit patches directly to the
4614 Use --bypass to apply and commit patches directly to the
4615 repository, without affecting the working directory. Without
4615 repository, without affecting the working directory. Without
4616 --exact, patches will be applied on top of the working directory
4616 --exact, patches will be applied on top of the working directory
4617 parent revision.
4617 parent revision.
4618
4618
4619 You can import a patch straight from a mail message. Even patches
4619 You can import a patch straight from a mail message. Even patches
4620 as attachments work (to use the body part, it must have type
4620 as attachments work (to use the body part, it must have type
4621 text/plain or text/x-patch). From and Subject headers of email
4621 text/plain or text/x-patch). From and Subject headers of email
4622 message are used as default committer and commit message. All
4622 message are used as default committer and commit message. All
4623 text/plain body parts before first diff are added to the commit
4623 text/plain body parts before first diff are added to the commit
4624 message.
4624 message.
4625
4625
4626 If the imported patch was generated by :hg:`export`, user and
4626 If the imported patch was generated by :hg:`export`, user and
4627 description from patch override values from message headers and
4627 description from patch override values from message headers and
4628 body. Values given on command line with -m/--message and -u/--user
4628 body. Values given on command line with -m/--message and -u/--user
4629 override these.
4629 override these.
4630
4630
4631 If --exact is specified, import will set the working directory to
4631 If --exact is specified, import will set the working directory to
4632 the parent of each patch before applying it, and will abort if the
4632 the parent of each patch before applying it, and will abort if the
4633 resulting changeset has a different ID than the one recorded in
4633 resulting changeset has a different ID than the one recorded in
4634 the patch. This may happen due to character set problems or other
4634 the patch. This may happen due to character set problems or other
4635 deficiencies in the text patch format.
4635 deficiencies in the text patch format.
4636
4636
4637 Use --partial to ensure a changeset will be created from the patch
4637 Use --partial to ensure a changeset will be created from the patch
4638 even if some hunks fail to apply. Hunks that fail to apply will be
4638 even if some hunks fail to apply. Hunks that fail to apply will be
4639 written to a <target-file>.rej file. Conflicts can then be resolved
4639 written to a <target-file>.rej file. Conflicts can then be resolved
4640 by hand before :hg:`commit --amend` is run to update the created
4640 by hand before :hg:`commit --amend` is run to update the created
4641 changeset. This flag exists to let people import patches that
4641 changeset. This flag exists to let people import patches that
4642 partially apply without losing the associated metadata (author,
4642 partially apply without losing the associated metadata (author,
4643 date, description, ...).
4643 date, description, ...).
4644
4644
4645 .. note::
4645 .. note::
4646
4646
4647 When no hunks apply cleanly, :hg:`import --partial` will create
4647 When no hunks apply cleanly, :hg:`import --partial` will create
4648 an empty changeset, importing only the patch metadata.
4648 an empty changeset, importing only the patch metadata.
4649
4649
4650 With -s/--similarity, hg will attempt to discover renames and
4650 With -s/--similarity, hg will attempt to discover renames and
4651 copies in the patch in the same way as :hg:`addremove`.
4651 copies in the patch in the same way as :hg:`addremove`.
4652
4652
4653 It is possible to use external patch programs to perform the patch
4653 It is possible to use external patch programs to perform the patch
4654 by setting the ``ui.patch`` configuration option. For the default
4654 by setting the ``ui.patch`` configuration option. For the default
4655 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4655 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4656 See :hg:`help config` for more information about configuration
4656 See :hg:`help config` for more information about configuration
4657 files and how to use these options.
4657 files and how to use these options.
4658
4658
4659 See :hg:`help dates` for a list of formats valid for -d/--date.
4659 See :hg:`help dates` for a list of formats valid for -d/--date.
4660
4660
4661 .. container:: verbose
4661 .. container:: verbose
4662
4662
4663 Examples:
4663 Examples:
4664
4664
4665 - import a traditional patch from a website and detect renames::
4665 - import a traditional patch from a website and detect renames::
4666
4666
4667 hg import -s 80 http://example.com/bugfix.patch
4667 hg import -s 80 http://example.com/bugfix.patch
4668
4668
4669 - import a changeset from an hgweb server::
4669 - import a changeset from an hgweb server::
4670
4670
4671 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4671 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4672
4672
4673 - import all the patches in an Unix-style mbox::
4673 - import all the patches in an Unix-style mbox::
4674
4674
4675 hg import incoming-patches.mbox
4675 hg import incoming-patches.mbox
4676
4676
4677 - attempt to exactly restore an exported changeset (not always
4677 - attempt to exactly restore an exported changeset (not always
4678 possible)::
4678 possible)::
4679
4679
4680 hg import --exact proposed-fix.patch
4680 hg import --exact proposed-fix.patch
4681
4681
4682 - use an external tool to apply a patch which is too fuzzy for
4682 - use an external tool to apply a patch which is too fuzzy for
4683 the default internal tool.
4683 the default internal tool.
4684
4684
4685 hg import --config ui.patch="patch --merge" fuzzy.patch
4685 hg import --config ui.patch="patch --merge" fuzzy.patch
4686
4686
4687 - change the default fuzzing from 2 to a less strict 7
4687 - change the default fuzzing from 2 to a less strict 7
4688
4688
4689 hg import --config ui.fuzz=7 fuzz.patch
4689 hg import --config ui.fuzz=7 fuzz.patch
4690
4690
4691 Returns 0 on success, 1 on partial success (see --partial).
4691 Returns 0 on success, 1 on partial success (see --partial).
4692 """
4692 """
4693
4693
4694 if not patch1:
4694 if not patch1:
4695 raise error.Abort(_('need at least one patch to import'))
4695 raise error.Abort(_('need at least one patch to import'))
4696
4696
4697 patches = (patch1,) + patches
4697 patches = (patch1,) + patches
4698
4698
4699 date = opts.get('date')
4699 date = opts.get('date')
4700 if date:
4700 if date:
4701 opts['date'] = util.parsedate(date)
4701 opts['date'] = util.parsedate(date)
4702
4702
4703 exact = opts.get('exact')
4703 exact = opts.get('exact')
4704 update = not opts.get('bypass')
4704 update = not opts.get('bypass')
4705 if not update and opts.get('no_commit'):
4705 if not update and opts.get('no_commit'):
4706 raise error.Abort(_('cannot use --no-commit with --bypass'))
4706 raise error.Abort(_('cannot use --no-commit with --bypass'))
4707 try:
4707 try:
4708 sim = float(opts.get('similarity') or 0)
4708 sim = float(opts.get('similarity') or 0)
4709 except ValueError:
4709 except ValueError:
4710 raise error.Abort(_('similarity must be a number'))
4710 raise error.Abort(_('similarity must be a number'))
4711 if sim < 0 or sim > 100:
4711 if sim < 0 or sim > 100:
4712 raise error.Abort(_('similarity must be between 0 and 100'))
4712 raise error.Abort(_('similarity must be between 0 and 100'))
4713 if sim and not update:
4713 if sim and not update:
4714 raise error.Abort(_('cannot use --similarity with --bypass'))
4714 raise error.Abort(_('cannot use --similarity with --bypass'))
4715 if exact:
4715 if exact:
4716 if opts.get('edit'):
4716 if opts.get('edit'):
4717 raise error.Abort(_('cannot use --exact with --edit'))
4717 raise error.Abort(_('cannot use --exact with --edit'))
4718 if opts.get('prefix'):
4718 if opts.get('prefix'):
4719 raise error.Abort(_('cannot use --exact with --prefix'))
4719 raise error.Abort(_('cannot use --exact with --prefix'))
4720
4720
4721 base = opts["base"]
4721 base = opts["base"]
4722 wlock = dsguard = lock = tr = None
4722 wlock = dsguard = lock = tr = None
4723 msgs = []
4723 msgs = []
4724 ret = 0
4724 ret = 0
4725
4725
4726
4726
4727 try:
4727 try:
4728 wlock = repo.wlock()
4728 wlock = repo.wlock()
4729
4729
4730 if update:
4730 if update:
4731 cmdutil.checkunfinished(repo)
4731 cmdutil.checkunfinished(repo)
4732 if (exact or not opts.get('force')):
4732 if (exact or not opts.get('force')):
4733 cmdutil.bailifchanged(repo)
4733 cmdutil.bailifchanged(repo)
4734
4734
4735 if not opts.get('no_commit'):
4735 if not opts.get('no_commit'):
4736 lock = repo.lock()
4736 lock = repo.lock()
4737 tr = repo.transaction('import')
4737 tr = repo.transaction('import')
4738 else:
4738 else:
4739 dsguard = cmdutil.dirstateguard(repo, 'import')
4739 dsguard = cmdutil.dirstateguard(repo, 'import')
4740 parents = repo[None].parents()
4740 parents = repo[None].parents()
4741 for patchurl in patches:
4741 for patchurl in patches:
4742 if patchurl == '-':
4742 if patchurl == '-':
4743 ui.status(_('applying patch from stdin\n'))
4743 ui.status(_('applying patch from stdin\n'))
4744 patchfile = ui.fin
4744 patchfile = ui.fin
4745 patchurl = 'stdin' # for error message
4745 patchurl = 'stdin' # for error message
4746 else:
4746 else:
4747 patchurl = os.path.join(base, patchurl)
4747 patchurl = os.path.join(base, patchurl)
4748 ui.status(_('applying %s\n') % patchurl)
4748 ui.status(_('applying %s\n') % patchurl)
4749 patchfile = hg.openpath(ui, patchurl)
4749 patchfile = hg.openpath(ui, patchurl)
4750
4750
4751 haspatch = False
4751 haspatch = False
4752 for hunk in patch.split(patchfile):
4752 for hunk in patch.split(patchfile):
4753 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4753 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4754 parents, opts,
4754 parents, opts,
4755 msgs, hg.clean)
4755 msgs, hg.clean)
4756 if msg:
4756 if msg:
4757 haspatch = True
4757 haspatch = True
4758 ui.note(msg + '\n')
4758 ui.note(msg + '\n')
4759 if update or exact:
4759 if update or exact:
4760 parents = repo[None].parents()
4760 parents = repo[None].parents()
4761 else:
4761 else:
4762 parents = [repo[node]]
4762 parents = [repo[node]]
4763 if rej:
4763 if rej:
4764 ui.write_err(_("patch applied partially\n"))
4764 ui.write_err(_("patch applied partially\n"))
4765 ui.write_err(_("(fix the .rej files and run "
4765 ui.write_err(_("(fix the .rej files and run "
4766 "`hg commit --amend`)\n"))
4766 "`hg commit --amend`)\n"))
4767 ret = 1
4767 ret = 1
4768 break
4768 break
4769
4769
4770 if not haspatch:
4770 if not haspatch:
4771 raise error.Abort(_('%s: no diffs found') % patchurl)
4771 raise error.Abort(_('%s: no diffs found') % patchurl)
4772
4772
4773 if tr:
4773 if tr:
4774 tr.close()
4774 tr.close()
4775 if msgs:
4775 if msgs:
4776 repo.savecommitmessage('\n* * *\n'.join(msgs))
4776 repo.savecommitmessage('\n* * *\n'.join(msgs))
4777 if dsguard:
4777 if dsguard:
4778 dsguard.close()
4778 dsguard.close()
4779 return ret
4779 return ret
4780 finally:
4780 finally:
4781 if tr:
4781 if tr:
4782 tr.release()
4782 tr.release()
4783 release(lock, dsguard, wlock)
4783 release(lock, dsguard, wlock)
4784
4784
4785 @command('incoming|in',
4785 @command('incoming|in',
4786 [('f', 'force', None,
4786 [('f', 'force', None,
4787 _('run even if remote repository is unrelated')),
4787 _('run even if remote repository is unrelated')),
4788 ('n', 'newest-first', None, _('show newest record first')),
4788 ('n', 'newest-first', None, _('show newest record first')),
4789 ('', 'bundle', '',
4789 ('', 'bundle', '',
4790 _('file to store the bundles into'), _('FILE')),
4790 _('file to store the bundles into'), _('FILE')),
4791 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4791 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4792 ('B', 'bookmarks', False, _("compare bookmarks")),
4792 ('B', 'bookmarks', False, _("compare bookmarks")),
4793 ('b', 'branch', [],
4793 ('b', 'branch', [],
4794 _('a specific branch you would like to pull'), _('BRANCH')),
4794 _('a specific branch you would like to pull'), _('BRANCH')),
4795 ] + logopts + remoteopts + subrepoopts,
4795 ] + logopts + remoteopts + subrepoopts,
4796 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4796 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4797 def incoming(ui, repo, source="default", **opts):
4797 def incoming(ui, repo, source="default", **opts):
4798 """show new changesets found in source
4798 """show new changesets found in source
4799
4799
4800 Show new changesets found in the specified path/URL or the default
4800 Show new changesets found in the specified path/URL or the default
4801 pull location. These are the changesets that would have been pulled
4801 pull location. These are the changesets that would have been pulled
4802 if a pull at the time you issued this command.
4802 if a pull at the time you issued this command.
4803
4803
4804 See pull for valid source format details.
4804 See pull for valid source format details.
4805
4805
4806 .. container:: verbose
4806 .. container:: verbose
4807
4807
4808 With -B/--bookmarks, the result of bookmark comparison between
4808 With -B/--bookmarks, the result of bookmark comparison between
4809 local and remote repositories is displayed. With -v/--verbose,
4809 local and remote repositories is displayed. With -v/--verbose,
4810 status is also displayed for each bookmark like below::
4810 status is also displayed for each bookmark like below::
4811
4811
4812 BM1 01234567890a added
4812 BM1 01234567890a added
4813 BM2 1234567890ab advanced
4813 BM2 1234567890ab advanced
4814 BM3 234567890abc diverged
4814 BM3 234567890abc diverged
4815 BM4 34567890abcd changed
4815 BM4 34567890abcd changed
4816
4816
4817 The action taken locally when pulling depends on the
4817 The action taken locally when pulling depends on the
4818 status of each bookmark:
4818 status of each bookmark:
4819
4819
4820 :``added``: pull will create it
4820 :``added``: pull will create it
4821 :``advanced``: pull will update it
4821 :``advanced``: pull will update it
4822 :``diverged``: pull will create a divergent bookmark
4822 :``diverged``: pull will create a divergent bookmark
4823 :``changed``: result depends on remote changesets
4823 :``changed``: result depends on remote changesets
4824
4824
4825 From the point of view of pulling behavior, bookmark
4825 From the point of view of pulling behavior, bookmark
4826 existing only in the remote repository are treated as ``added``,
4826 existing only in the remote repository are treated as ``added``,
4827 even if it is in fact locally deleted.
4827 even if it is in fact locally deleted.
4828
4828
4829 .. container:: verbose
4829 .. container:: verbose
4830
4830
4831 For remote repository, using --bundle avoids downloading the
4831 For remote repository, using --bundle avoids downloading the
4832 changesets twice if the incoming is followed by a pull.
4832 changesets twice if the incoming is followed by a pull.
4833
4833
4834 Examples:
4834 Examples:
4835
4835
4836 - show incoming changes with patches and full description::
4836 - show incoming changes with patches and full description::
4837
4837
4838 hg incoming -vp
4838 hg incoming -vp
4839
4839
4840 - show incoming changes excluding merges, store a bundle::
4840 - show incoming changes excluding merges, store a bundle::
4841
4841
4842 hg in -vpM --bundle incoming.hg
4842 hg in -vpM --bundle incoming.hg
4843 hg pull incoming.hg
4843 hg pull incoming.hg
4844
4844
4845 - briefly list changes inside a bundle::
4845 - briefly list changes inside a bundle::
4846
4846
4847 hg in changes.hg -T "{desc|firstline}\\n"
4847 hg in changes.hg -T "{desc|firstline}\\n"
4848
4848
4849 Returns 0 if there are incoming changes, 1 otherwise.
4849 Returns 0 if there are incoming changes, 1 otherwise.
4850 """
4850 """
4851 if opts.get('graph'):
4851 if opts.get('graph'):
4852 cmdutil.checkunsupportedgraphflags([], opts)
4852 cmdutil.checkunsupportedgraphflags([], opts)
4853 def display(other, chlist, displayer):
4853 def display(other, chlist, displayer):
4854 revdag = cmdutil.graphrevs(other, chlist, opts)
4854 revdag = cmdutil.graphrevs(other, chlist, opts)
4855 cmdutil.displaygraph(ui, repo, revdag, displayer,
4855 cmdutil.displaygraph(ui, repo, revdag, displayer,
4856 graphmod.asciiedges)
4856 graphmod.asciiedges)
4857
4857
4858 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4858 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4859 return 0
4859 return 0
4860
4860
4861 if opts.get('bundle') and opts.get('subrepos'):
4861 if opts.get('bundle') and opts.get('subrepos'):
4862 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4862 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4863
4863
4864 if opts.get('bookmarks'):
4864 if opts.get('bookmarks'):
4865 source, branches = hg.parseurl(ui.expandpath(source),
4865 source, branches = hg.parseurl(ui.expandpath(source),
4866 opts.get('branch'))
4866 opts.get('branch'))
4867 other = hg.peer(repo, opts, source)
4867 other = hg.peer(repo, opts, source)
4868 if 'bookmarks' not in other.listkeys('namespaces'):
4868 if 'bookmarks' not in other.listkeys('namespaces'):
4869 ui.warn(_("remote doesn't support bookmarks\n"))
4869 ui.warn(_("remote doesn't support bookmarks\n"))
4870 return 0
4870 return 0
4871 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4871 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4872 return bookmarks.incoming(ui, repo, other)
4872 return bookmarks.incoming(ui, repo, other)
4873
4873
4874 repo._subtoppath = ui.expandpath(source)
4874 repo._subtoppath = ui.expandpath(source)
4875 try:
4875 try:
4876 return hg.incoming(ui, repo, source, opts)
4876 return hg.incoming(ui, repo, source, opts)
4877 finally:
4877 finally:
4878 del repo._subtoppath
4878 del repo._subtoppath
4879
4879
4880
4880
4881 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4881 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4882 norepo=True)
4882 norepo=True)
4883 def init(ui, dest=".", **opts):
4883 def init(ui, dest=".", **opts):
4884 """create a new repository in the given directory
4884 """create a new repository in the given directory
4885
4885
4886 Initialize a new repository in the given directory. If the given
4886 Initialize a new repository in the given directory. If the given
4887 directory does not exist, it will be created.
4887 directory does not exist, it will be created.
4888
4888
4889 If no directory is given, the current directory is used.
4889 If no directory is given, the current directory is used.
4890
4890
4891 It is possible to specify an ``ssh://`` URL as the destination.
4891 It is possible to specify an ``ssh://`` URL as the destination.
4892 See :hg:`help urls` for more information.
4892 See :hg:`help urls` for more information.
4893
4893
4894 Returns 0 on success.
4894 Returns 0 on success.
4895 """
4895 """
4896 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4896 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4897
4897
4898 @command('locate',
4898 @command('locate',
4899 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4899 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4900 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4900 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4901 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4901 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4902 ] + walkopts,
4902 ] + walkopts,
4903 _('[OPTION]... [PATTERN]...'))
4903 _('[OPTION]... [PATTERN]...'))
4904 def locate(ui, repo, *pats, **opts):
4904 def locate(ui, repo, *pats, **opts):
4905 """locate files matching specific patterns (DEPRECATED)
4905 """locate files matching specific patterns (DEPRECATED)
4906
4906
4907 Print files under Mercurial control in the working directory whose
4907 Print files under Mercurial control in the working directory whose
4908 names match the given patterns.
4908 names match the given patterns.
4909
4909
4910 By default, this command searches all directories in the working
4910 By default, this command searches all directories in the working
4911 directory. To search just the current directory and its
4911 directory. To search just the current directory and its
4912 subdirectories, use "--include .".
4912 subdirectories, use "--include .".
4913
4913
4914 If no patterns are given to match, this command prints the names
4914 If no patterns are given to match, this command prints the names
4915 of all files under Mercurial control in the working directory.
4915 of all files under Mercurial control in the working directory.
4916
4916
4917 If you want to feed the output of this command into the "xargs"
4917 If you want to feed the output of this command into the "xargs"
4918 command, use the -0 option to both this command and "xargs". This
4918 command, use the -0 option to both this command and "xargs". This
4919 will avoid the problem of "xargs" treating single filenames that
4919 will avoid the problem of "xargs" treating single filenames that
4920 contain whitespace as multiple filenames.
4920 contain whitespace as multiple filenames.
4921
4921
4922 See :hg:`help files` for a more versatile command.
4922 See :hg:`help files` for a more versatile command.
4923
4923
4924 Returns 0 if a match is found, 1 otherwise.
4924 Returns 0 if a match is found, 1 otherwise.
4925 """
4925 """
4926 if opts.get('print0'):
4926 if opts.get('print0'):
4927 end = '\0'
4927 end = '\0'
4928 else:
4928 else:
4929 end = '\n'
4929 end = '\n'
4930 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4930 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4931
4931
4932 ret = 1
4932 ret = 1
4933 ctx = repo[rev]
4933 ctx = repo[rev]
4934 m = scmutil.match(ctx, pats, opts, default='relglob',
4934 m = scmutil.match(ctx, pats, opts, default='relglob',
4935 badfn=lambda x, y: False)
4935 badfn=lambda x, y: False)
4936
4936
4937 for abs in ctx.matches(m):
4937 for abs in ctx.matches(m):
4938 if opts.get('fullpath'):
4938 if opts.get('fullpath'):
4939 ui.write(repo.wjoin(abs), end)
4939 ui.write(repo.wjoin(abs), end)
4940 else:
4940 else:
4941 ui.write(((pats and m.rel(abs)) or abs), end)
4941 ui.write(((pats and m.rel(abs)) or abs), end)
4942 ret = 0
4942 ret = 0
4943
4943
4944 return ret
4944 return ret
4945
4945
4946 @command('^log|history',
4946 @command('^log|history',
4947 [('f', 'follow', None,
4947 [('f', 'follow', None,
4948 _('follow changeset history, or file history across copies and renames')),
4948 _('follow changeset history, or file history across copies and renames')),
4949 ('', 'follow-first', None,
4949 ('', 'follow-first', None,
4950 _('only follow the first parent of merge changesets (DEPRECATED)')),
4950 _('only follow the first parent of merge changesets (DEPRECATED)')),
4951 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4951 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4952 ('C', 'copies', None, _('show copied files')),
4952 ('C', 'copies', None, _('show copied files')),
4953 ('k', 'keyword', [],
4953 ('k', 'keyword', [],
4954 _('do case-insensitive search for a given text'), _('TEXT')),
4954 _('do case-insensitive search for a given text'), _('TEXT')),
4955 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4955 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4956 ('', 'removed', None, _('include revisions where files were removed')),
4956 ('', 'removed', None, _('include revisions where files were removed')),
4957 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4957 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4958 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4958 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4959 ('', 'only-branch', [],
4959 ('', 'only-branch', [],
4960 _('show only changesets within the given named branch (DEPRECATED)'),
4960 _('show only changesets within the given named branch (DEPRECATED)'),
4961 _('BRANCH')),
4961 _('BRANCH')),
4962 ('b', 'branch', [],
4962 ('b', 'branch', [],
4963 _('show changesets within the given named branch'), _('BRANCH')),
4963 _('show changesets within the given named branch'), _('BRANCH')),
4964 ('P', 'prune', [],
4964 ('P', 'prune', [],
4965 _('do not display revision or any of its ancestors'), _('REV')),
4965 _('do not display revision or any of its ancestors'), _('REV')),
4966 ] + logopts + walkopts,
4966 ] + logopts + walkopts,
4967 _('[OPTION]... [FILE]'),
4967 _('[OPTION]... [FILE]'),
4968 inferrepo=True)
4968 inferrepo=True)
4969 def log(ui, repo, *pats, **opts):
4969 def log(ui, repo, *pats, **opts):
4970 """show revision history of entire repository or files
4970 """show revision history of entire repository or files
4971
4971
4972 Print the revision history of the specified files or the entire
4972 Print the revision history of the specified files or the entire
4973 project.
4973 project.
4974
4974
4975 If no revision range is specified, the default is ``tip:0`` unless
4975 If no revision range is specified, the default is ``tip:0`` unless
4976 --follow is set, in which case the working directory parent is
4976 --follow is set, in which case the working directory parent is
4977 used as the starting revision.
4977 used as the starting revision.
4978
4978
4979 File history is shown without following rename or copy history of
4979 File history is shown without following rename or copy history of
4980 files. Use -f/--follow with a filename to follow history across
4980 files. Use -f/--follow with a filename to follow history across
4981 renames and copies. --follow without a filename will only show
4981 renames and copies. --follow without a filename will only show
4982 ancestors or descendants of the starting revision.
4982 ancestors or descendants of the starting revision.
4983
4983
4984 By default this command prints revision number and changeset id,
4984 By default this command prints revision number and changeset id,
4985 tags, non-trivial parents, user, date and time, and a summary for
4985 tags, non-trivial parents, user, date and time, and a summary for
4986 each commit. When the -v/--verbose switch is used, the list of
4986 each commit. When the -v/--verbose switch is used, the list of
4987 changed files and full commit message are shown.
4987 changed files and full commit message are shown.
4988
4988
4989 With --graph the revisions are shown as an ASCII art DAG with the most
4989 With --graph the revisions are shown as an ASCII art DAG with the most
4990 recent changeset at the top.
4990 recent changeset at the top.
4991 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4991 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4992 and '+' represents a fork where the changeset from the lines below is a
4992 and '+' represents a fork where the changeset from the lines below is a
4993 parent of the 'o' merge on the same line.
4993 parent of the 'o' merge on the same line.
4994
4994
4995 .. note::
4995 .. note::
4996
4996
4997 :hg:`log --patch` may generate unexpected diff output for merge
4997 :hg:`log --patch` may generate unexpected diff output for merge
4998 changesets, as it will only compare the merge changeset against
4998 changesets, as it will only compare the merge changeset against
4999 its first parent. Also, only files different from BOTH parents
4999 its first parent. Also, only files different from BOTH parents
5000 will appear in files:.
5000 will appear in files:.
5001
5001
5002 .. note::
5002 .. note::
5003
5003
5004 For performance reasons, :hg:`log FILE` may omit duplicate changes
5004 For performance reasons, :hg:`log FILE` may omit duplicate changes
5005 made on branches and will not show removals or mode changes. To
5005 made on branches and will not show removals or mode changes. To
5006 see all such changes, use the --removed switch.
5006 see all such changes, use the --removed switch.
5007
5007
5008 .. container:: verbose
5008 .. container:: verbose
5009
5009
5010 Some examples:
5010 Some examples:
5011
5011
5012 - changesets with full descriptions and file lists::
5012 - changesets with full descriptions and file lists::
5013
5013
5014 hg log -v
5014 hg log -v
5015
5015
5016 - changesets ancestral to the working directory::
5016 - changesets ancestral to the working directory::
5017
5017
5018 hg log -f
5018 hg log -f
5019
5019
5020 - last 10 commits on the current branch::
5020 - last 10 commits on the current branch::
5021
5021
5022 hg log -l 10 -b .
5022 hg log -l 10 -b .
5023
5023
5024 - changesets showing all modifications of a file, including removals::
5024 - changesets showing all modifications of a file, including removals::
5025
5025
5026 hg log --removed file.c
5026 hg log --removed file.c
5027
5027
5028 - all changesets that touch a directory, with diffs, excluding merges::
5028 - all changesets that touch a directory, with diffs, excluding merges::
5029
5029
5030 hg log -Mp lib/
5030 hg log -Mp lib/
5031
5031
5032 - all revision numbers that match a keyword::
5032 - all revision numbers that match a keyword::
5033
5033
5034 hg log -k bug --template "{rev}\\n"
5034 hg log -k bug --template "{rev}\\n"
5035
5035
5036 - the full hash identifier of the working directory parent::
5036 - the full hash identifier of the working directory parent::
5037
5037
5038 hg log -r . --template "{node}\\n"
5038 hg log -r . --template "{node}\\n"
5039
5039
5040 - list available log templates::
5040 - list available log templates::
5041
5041
5042 hg log -T list
5042 hg log -T list
5043
5043
5044 - check if a given changeset is included in a tagged release::
5044 - check if a given changeset is included in a tagged release::
5045
5045
5046 hg log -r "a21ccf and ancestor(1.9)"
5046 hg log -r "a21ccf and ancestor(1.9)"
5047
5047
5048 - find all changesets by some user in a date range::
5048 - find all changesets by some user in a date range::
5049
5049
5050 hg log -k alice -d "may 2008 to jul 2008"
5050 hg log -k alice -d "may 2008 to jul 2008"
5051
5051
5052 - summary of all changesets after the last tag::
5052 - summary of all changesets after the last tag::
5053
5053
5054 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5054 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5055
5055
5056 See :hg:`help dates` for a list of formats valid for -d/--date.
5056 See :hg:`help dates` for a list of formats valid for -d/--date.
5057
5057
5058 See :hg:`help revisions` and :hg:`help revsets` for more about
5058 See :hg:`help revisions` and :hg:`help revsets` for more about
5059 specifying and ordering revisions.
5059 specifying and ordering revisions.
5060
5060
5061 See :hg:`help templates` for more about pre-packaged styles and
5061 See :hg:`help templates` for more about pre-packaged styles and
5062 specifying custom templates.
5062 specifying custom templates.
5063
5063
5064 Returns 0 on success.
5064 Returns 0 on success.
5065
5065
5066 """
5066 """
5067 if opts.get('follow') and opts.get('rev'):
5067 if opts.get('follow') and opts.get('rev'):
5068 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5068 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5069 del opts['follow']
5069 del opts['follow']
5070
5070
5071 if opts.get('graph'):
5071 if opts.get('graph'):
5072 return cmdutil.graphlog(ui, repo, *pats, **opts)
5072 return cmdutil.graphlog(ui, repo, *pats, **opts)
5073
5073
5074 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5074 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5075 limit = cmdutil.loglimit(opts)
5075 limit = cmdutil.loglimit(opts)
5076 count = 0
5076 count = 0
5077
5077
5078 getrenamed = None
5078 getrenamed = None
5079 if opts.get('copies'):
5079 if opts.get('copies'):
5080 endrev = None
5080 endrev = None
5081 if opts.get('rev'):
5081 if opts.get('rev'):
5082 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5082 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5083 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5083 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5084
5084
5085 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5085 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5086 for rev in revs:
5086 for rev in revs:
5087 if count == limit:
5087 if count == limit:
5088 break
5088 break
5089 ctx = repo[rev]
5089 ctx = repo[rev]
5090 copies = None
5090 copies = None
5091 if getrenamed is not None and rev:
5091 if getrenamed is not None and rev:
5092 copies = []
5092 copies = []
5093 for fn in ctx.files():
5093 for fn in ctx.files():
5094 rename = getrenamed(fn, rev)
5094 rename = getrenamed(fn, rev)
5095 if rename:
5095 if rename:
5096 copies.append((fn, rename[0]))
5096 copies.append((fn, rename[0]))
5097 if filematcher:
5097 if filematcher:
5098 revmatchfn = filematcher(ctx.rev())
5098 revmatchfn = filematcher(ctx.rev())
5099 else:
5099 else:
5100 revmatchfn = None
5100 revmatchfn = None
5101 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5101 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5102 if displayer.flush(ctx):
5102 if displayer.flush(ctx):
5103 count += 1
5103 count += 1
5104
5104
5105 displayer.close()
5105 displayer.close()
5106
5106
5107 @command('manifest',
5107 @command('manifest',
5108 [('r', 'rev', '', _('revision to display'), _('REV')),
5108 [('r', 'rev', '', _('revision to display'), _('REV')),
5109 ('', 'all', False, _("list files from all revisions"))]
5109 ('', 'all', False, _("list files from all revisions"))]
5110 + formatteropts,
5110 + formatteropts,
5111 _('[-r REV]'))
5111 _('[-r REV]'))
5112 def manifest(ui, repo, node=None, rev=None, **opts):
5112 def manifest(ui, repo, node=None, rev=None, **opts):
5113 """output the current or given revision of the project manifest
5113 """output the current or given revision of the project manifest
5114
5114
5115 Print a list of version controlled files for the given revision.
5115 Print a list of version controlled files for the given revision.
5116 If no revision is given, the first parent of the working directory
5116 If no revision is given, the first parent of the working directory
5117 is used, or the null revision if no revision is checked out.
5117 is used, or the null revision if no revision is checked out.
5118
5118
5119 With -v, print file permissions, symlink and executable bits.
5119 With -v, print file permissions, symlink and executable bits.
5120 With --debug, print file revision hashes.
5120 With --debug, print file revision hashes.
5121
5121
5122 If option --all is specified, the list of all files from all revisions
5122 If option --all is specified, the list of all files from all revisions
5123 is printed. This includes deleted and renamed files.
5123 is printed. This includes deleted and renamed files.
5124
5124
5125 Returns 0 on success.
5125 Returns 0 on success.
5126 """
5126 """
5127
5127
5128 fm = ui.formatter('manifest', opts)
5128 fm = ui.formatter('manifest', opts)
5129
5129
5130 if opts.get('all'):
5130 if opts.get('all'):
5131 if rev or node:
5131 if rev or node:
5132 raise error.Abort(_("can't specify a revision with --all"))
5132 raise error.Abort(_("can't specify a revision with --all"))
5133
5133
5134 res = []
5134 res = []
5135 prefix = "data/"
5135 prefix = "data/"
5136 suffix = ".i"
5136 suffix = ".i"
5137 plen = len(prefix)
5137 plen = len(prefix)
5138 slen = len(suffix)
5138 slen = len(suffix)
5139 lock = repo.lock()
5139 lock = repo.lock()
5140 try:
5140 try:
5141 for fn, b, size in repo.store.datafiles():
5141 for fn, b, size in repo.store.datafiles():
5142 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5142 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5143 res.append(fn[plen:-slen])
5143 res.append(fn[plen:-slen])
5144 finally:
5144 finally:
5145 lock.release()
5145 lock.release()
5146 for f in res:
5146 for f in res:
5147 fm.startitem()
5147 fm.startitem()
5148 fm.write("path", '%s\n', f)
5148 fm.write("path", '%s\n', f)
5149 fm.end()
5149 fm.end()
5150 return
5150 return
5151
5151
5152 if rev and node:
5152 if rev and node:
5153 raise error.Abort(_("please specify just one revision"))
5153 raise error.Abort(_("please specify just one revision"))
5154
5154
5155 if not node:
5155 if not node:
5156 node = rev
5156 node = rev
5157
5157
5158 char = {'l': '@', 'x': '*', '': ''}
5158 char = {'l': '@', 'x': '*', '': ''}
5159 mode = {'l': '644', 'x': '755', '': '644'}
5159 mode = {'l': '644', 'x': '755', '': '644'}
5160 ctx = scmutil.revsingle(repo, node)
5160 ctx = scmutil.revsingle(repo, node)
5161 mf = ctx.manifest()
5161 mf = ctx.manifest()
5162 for f in ctx:
5162 for f in ctx:
5163 fm.startitem()
5163 fm.startitem()
5164 fl = ctx[f].flags()
5164 fl = ctx[f].flags()
5165 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5165 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5166 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5166 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5167 fm.write('path', '%s\n', f)
5167 fm.write('path', '%s\n', f)
5168 fm.end()
5168 fm.end()
5169
5169
5170 @command('^merge',
5170 @command('^merge',
5171 [('f', 'force', None,
5171 [('f', 'force', None,
5172 _('force a merge including outstanding changes (DEPRECATED)')),
5172 _('force a merge including outstanding changes (DEPRECATED)')),
5173 ('r', 'rev', '', _('revision to merge'), _('REV')),
5173 ('r', 'rev', '', _('revision to merge'), _('REV')),
5174 ('P', 'preview', None,
5174 ('P', 'preview', None,
5175 _('review revisions to merge (no merge is performed)'))
5175 _('review revisions to merge (no merge is performed)'))
5176 ] + mergetoolopts,
5176 ] + mergetoolopts,
5177 _('[-P] [-f] [[-r] REV]'))
5177 _('[-P] [-f] [[-r] REV]'))
5178 def merge(ui, repo, node=None, **opts):
5178 def merge(ui, repo, node=None, **opts):
5179 """merge another revision into working directory
5179 """merge another revision into working directory
5180
5180
5181 The current working directory is updated with all changes made in
5181 The current working directory is updated with all changes made in
5182 the requested revision since the last common predecessor revision.
5182 the requested revision since the last common predecessor revision.
5183
5183
5184 Files that changed between either parent are marked as changed for
5184 Files that changed between either parent are marked as changed for
5185 the next commit and a commit must be performed before any further
5185 the next commit and a commit must be performed before any further
5186 updates to the repository are allowed. The next commit will have
5186 updates to the repository are allowed. The next commit will have
5187 two parents.
5187 two parents.
5188
5188
5189 ``--tool`` can be used to specify the merge tool used for file
5189 ``--tool`` can be used to specify the merge tool used for file
5190 merges. It overrides the HGMERGE environment variable and your
5190 merges. It overrides the HGMERGE environment variable and your
5191 configuration files. See :hg:`help merge-tools` for options.
5191 configuration files. See :hg:`help merge-tools` for options.
5192
5192
5193 If no revision is specified, the working directory's parent is a
5193 If no revision is specified, the working directory's parent is a
5194 head revision, and the current branch contains exactly one other
5194 head revision, and the current branch contains exactly one other
5195 head, the other head is merged with by default. Otherwise, an
5195 head, the other head is merged with by default. Otherwise, an
5196 explicit revision with which to merge with must be provided.
5196 explicit revision with which to merge with must be provided.
5197
5197
5198 See :hg:`help resolve` for information on handling file conflicts.
5198 See :hg:`help resolve` for information on handling file conflicts.
5199
5199
5200 To undo an uncommitted merge, use :hg:`update --clean .` which
5200 To undo an uncommitted merge, use :hg:`update --clean .` which
5201 will check out a clean copy of the original merge parent, losing
5201 will check out a clean copy of the original merge parent, losing
5202 all changes.
5202 all changes.
5203
5203
5204 Returns 0 on success, 1 if there are unresolved files.
5204 Returns 0 on success, 1 if there are unresolved files.
5205 """
5205 """
5206
5206
5207 if opts.get('rev') and node:
5207 if opts.get('rev') and node:
5208 raise error.Abort(_("please specify just one revision"))
5208 raise error.Abort(_("please specify just one revision"))
5209 if not node:
5209 if not node:
5210 node = opts.get('rev')
5210 node = opts.get('rev')
5211
5211
5212 if node:
5212 if node:
5213 node = scmutil.revsingle(repo, node).node()
5213 node = scmutil.revsingle(repo, node).node()
5214
5214
5215 if not node:
5215 if not node:
5216 node = repo[destutil.destmerge(repo)].node()
5216 node = repo[destutil.destmerge(repo)].node()
5217
5217
5218 if opts.get('preview'):
5218 if opts.get('preview'):
5219 # find nodes that are ancestors of p2 but not of p1
5219 # find nodes that are ancestors of p2 but not of p1
5220 p1 = repo.lookup('.')
5220 p1 = repo.lookup('.')
5221 p2 = repo.lookup(node)
5221 p2 = repo.lookup(node)
5222 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5222 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5223
5223
5224 displayer = cmdutil.show_changeset(ui, repo, opts)
5224 displayer = cmdutil.show_changeset(ui, repo, opts)
5225 for node in nodes:
5225 for node in nodes:
5226 displayer.show(repo[node])
5226 displayer.show(repo[node])
5227 displayer.close()
5227 displayer.close()
5228 return 0
5228 return 0
5229
5229
5230 try:
5230 try:
5231 # ui.forcemerge is an internal variable, do not document
5231 # ui.forcemerge is an internal variable, do not document
5232 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5232 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5233 return hg.merge(repo, node, force=opts.get('force'))
5233 return hg.merge(repo, node, force=opts.get('force'))
5234 finally:
5234 finally:
5235 ui.setconfig('ui', 'forcemerge', '', 'merge')
5235 ui.setconfig('ui', 'forcemerge', '', 'merge')
5236
5236
5237 @command('outgoing|out',
5237 @command('outgoing|out',
5238 [('f', 'force', None, _('run even when the destination is unrelated')),
5238 [('f', 'force', None, _('run even when the destination is unrelated')),
5239 ('r', 'rev', [],
5239 ('r', 'rev', [],
5240 _('a changeset intended to be included in the destination'), _('REV')),
5240 _('a changeset intended to be included in the destination'), _('REV')),
5241 ('n', 'newest-first', None, _('show newest record first')),
5241 ('n', 'newest-first', None, _('show newest record first')),
5242 ('B', 'bookmarks', False, _('compare bookmarks')),
5242 ('B', 'bookmarks', False, _('compare bookmarks')),
5243 ('b', 'branch', [], _('a specific branch you would like to push'),
5243 ('b', 'branch', [], _('a specific branch you would like to push'),
5244 _('BRANCH')),
5244 _('BRANCH')),
5245 ] + logopts + remoteopts + subrepoopts,
5245 ] + logopts + remoteopts + subrepoopts,
5246 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5246 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5247 def outgoing(ui, repo, dest=None, **opts):
5247 def outgoing(ui, repo, dest=None, **opts):
5248 """show changesets not found in the destination
5248 """show changesets not found in the destination
5249
5249
5250 Show changesets not found in the specified destination repository
5250 Show changesets not found in the specified destination repository
5251 or the default push location. These are the changesets that would
5251 or the default push location. These are the changesets that would
5252 be pushed if a push was requested.
5252 be pushed if a push was requested.
5253
5253
5254 See pull for details of valid destination formats.
5254 See pull for details of valid destination formats.
5255
5255
5256 .. container:: verbose
5256 .. container:: verbose
5257
5257
5258 With -B/--bookmarks, the result of bookmark comparison between
5258 With -B/--bookmarks, the result of bookmark comparison between
5259 local and remote repositories is displayed. With -v/--verbose,
5259 local and remote repositories is displayed. With -v/--verbose,
5260 status is also displayed for each bookmark like below::
5260 status is also displayed for each bookmark like below::
5261
5261
5262 BM1 01234567890a added
5262 BM1 01234567890a added
5263 BM2 deleted
5263 BM2 deleted
5264 BM3 234567890abc advanced
5264 BM3 234567890abc advanced
5265 BM4 34567890abcd diverged
5265 BM4 34567890abcd diverged
5266 BM5 4567890abcde changed
5266 BM5 4567890abcde changed
5267
5267
5268 The action taken when pushing depends on the
5268 The action taken when pushing depends on the
5269 status of each bookmark:
5269 status of each bookmark:
5270
5270
5271 :``added``: push with ``-B`` will create it
5271 :``added``: push with ``-B`` will create it
5272 :``deleted``: push with ``-B`` will delete it
5272 :``deleted``: push with ``-B`` will delete it
5273 :``advanced``: push will update it
5273 :``advanced``: push will update it
5274 :``diverged``: push with ``-B`` will update it
5274 :``diverged``: push with ``-B`` will update it
5275 :``changed``: push with ``-B`` will update it
5275 :``changed``: push with ``-B`` will update it
5276
5276
5277 From the point of view of pushing behavior, bookmarks
5277 From the point of view of pushing behavior, bookmarks
5278 existing only in the remote repository are treated as
5278 existing only in the remote repository are treated as
5279 ``deleted``, even if it is in fact added remotely.
5279 ``deleted``, even if it is in fact added remotely.
5280
5280
5281 Returns 0 if there are outgoing changes, 1 otherwise.
5281 Returns 0 if there are outgoing changes, 1 otherwise.
5282 """
5282 """
5283 if opts.get('graph'):
5283 if opts.get('graph'):
5284 cmdutil.checkunsupportedgraphflags([], opts)
5284 cmdutil.checkunsupportedgraphflags([], opts)
5285 o, other = hg._outgoing(ui, repo, dest, opts)
5285 o, other = hg._outgoing(ui, repo, dest, opts)
5286 if not o:
5286 if not o:
5287 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5287 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5288 return
5288 return
5289
5289
5290 revdag = cmdutil.graphrevs(repo, o, opts)
5290 revdag = cmdutil.graphrevs(repo, o, opts)
5291 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5291 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5292 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5292 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5293 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5293 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5294 return 0
5294 return 0
5295
5295
5296 if opts.get('bookmarks'):
5296 if opts.get('bookmarks'):
5297 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5297 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5298 dest, branches = hg.parseurl(dest, opts.get('branch'))
5298 dest, branches = hg.parseurl(dest, opts.get('branch'))
5299 other = hg.peer(repo, opts, dest)
5299 other = hg.peer(repo, opts, dest)
5300 if 'bookmarks' not in other.listkeys('namespaces'):
5300 if 'bookmarks' not in other.listkeys('namespaces'):
5301 ui.warn(_("remote doesn't support bookmarks\n"))
5301 ui.warn(_("remote doesn't support bookmarks\n"))
5302 return 0
5302 return 0
5303 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5303 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5304 return bookmarks.outgoing(ui, repo, other)
5304 return bookmarks.outgoing(ui, repo, other)
5305
5305
5306 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5306 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5307 try:
5307 try:
5308 return hg.outgoing(ui, repo, dest, opts)
5308 return hg.outgoing(ui, repo, dest, opts)
5309 finally:
5309 finally:
5310 del repo._subtoppath
5310 del repo._subtoppath
5311
5311
5312 @command('parents',
5312 @command('parents',
5313 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5313 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5314 ] + templateopts,
5314 ] + templateopts,
5315 _('[-r REV] [FILE]'),
5315 _('[-r REV] [FILE]'),
5316 inferrepo=True)
5316 inferrepo=True)
5317 def parents(ui, repo, file_=None, **opts):
5317 def parents(ui, repo, file_=None, **opts):
5318 """show the parents of the working directory or revision (DEPRECATED)
5318 """show the parents of the working directory or revision (DEPRECATED)
5319
5319
5320 Print the working directory's parent revisions. If a revision is
5320 Print the working directory's parent revisions. If a revision is
5321 given via -r/--rev, the parent of that revision will be printed.
5321 given via -r/--rev, the parent of that revision will be printed.
5322 If a file argument is given, the revision in which the file was
5322 If a file argument is given, the revision in which the file was
5323 last changed (before the working directory revision or the
5323 last changed (before the working directory revision or the
5324 argument to --rev if given) is printed.
5324 argument to --rev if given) is printed.
5325
5325
5326 This command is equivalent to::
5326 This command is equivalent to::
5327
5327
5328 hg log -r "p1()+p2()" or
5328 hg log -r "p1()+p2()" or
5329 hg log -r "p1(REV)+p2(REV)" or
5329 hg log -r "p1(REV)+p2(REV)" or
5330 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5330 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5331 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5331 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5332
5332
5333 See :hg:`summary` and :hg:`help revsets` for related information.
5333 See :hg:`summary` and :hg:`help revsets` for related information.
5334
5334
5335 Returns 0 on success.
5335 Returns 0 on success.
5336 """
5336 """
5337
5337
5338 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5338 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5339
5339
5340 if file_:
5340 if file_:
5341 m = scmutil.match(ctx, (file_,), opts)
5341 m = scmutil.match(ctx, (file_,), opts)
5342 if m.anypats() or len(m.files()) != 1:
5342 if m.anypats() or len(m.files()) != 1:
5343 raise error.Abort(_('can only specify an explicit filename'))
5343 raise error.Abort(_('can only specify an explicit filename'))
5344 file_ = m.files()[0]
5344 file_ = m.files()[0]
5345 filenodes = []
5345 filenodes = []
5346 for cp in ctx.parents():
5346 for cp in ctx.parents():
5347 if not cp:
5347 if not cp:
5348 continue
5348 continue
5349 try:
5349 try:
5350 filenodes.append(cp.filenode(file_))
5350 filenodes.append(cp.filenode(file_))
5351 except error.LookupError:
5351 except error.LookupError:
5352 pass
5352 pass
5353 if not filenodes:
5353 if not filenodes:
5354 raise error.Abort(_("'%s' not found in manifest!") % file_)
5354 raise error.Abort(_("'%s' not found in manifest!") % file_)
5355 p = []
5355 p = []
5356 for fn in filenodes:
5356 for fn in filenodes:
5357 fctx = repo.filectx(file_, fileid=fn)
5357 fctx = repo.filectx(file_, fileid=fn)
5358 p.append(fctx.node())
5358 p.append(fctx.node())
5359 else:
5359 else:
5360 p = [cp.node() for cp in ctx.parents()]
5360 p = [cp.node() for cp in ctx.parents()]
5361
5361
5362 displayer = cmdutil.show_changeset(ui, repo, opts)
5362 displayer = cmdutil.show_changeset(ui, repo, opts)
5363 for n in p:
5363 for n in p:
5364 if n != nullid:
5364 if n != nullid:
5365 displayer.show(repo[n])
5365 displayer.show(repo[n])
5366 displayer.close()
5366 displayer.close()
5367
5367
5368 @command('paths', [], _('[NAME]'), optionalrepo=True)
5368 @command('paths', [], _('[NAME]'), optionalrepo=True)
5369 def paths(ui, repo, search=None):
5369 def paths(ui, repo, search=None):
5370 """show aliases for remote repositories
5370 """show aliases for remote repositories
5371
5371
5372 Show definition of symbolic path name NAME. If no name is given,
5372 Show definition of symbolic path name NAME. If no name is given,
5373 show definition of all available names.
5373 show definition of all available names.
5374
5374
5375 Option -q/--quiet suppresses all output when searching for NAME
5375 Option -q/--quiet suppresses all output when searching for NAME
5376 and shows only the path names when listing all definitions.
5376 and shows only the path names when listing all definitions.
5377
5377
5378 Path names are defined in the [paths] section of your
5378 Path names are defined in the [paths] section of your
5379 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5379 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5380 repository, ``.hg/hgrc`` is used, too.
5380 repository, ``.hg/hgrc`` is used, too.
5381
5381
5382 The path names ``default`` and ``default-push`` have a special
5382 The path names ``default`` and ``default-push`` have a special
5383 meaning. When performing a push or pull operation, they are used
5383 meaning. When performing a push or pull operation, they are used
5384 as fallbacks if no location is specified on the command-line.
5384 as fallbacks if no location is specified on the command-line.
5385 When ``default-push`` is set, it will be used for push and
5385 When ``default-push`` is set, it will be used for push and
5386 ``default`` will be used for pull; otherwise ``default`` is used
5386 ``default`` will be used for pull; otherwise ``default`` is used
5387 as the fallback for both. When cloning a repository, the clone
5387 as the fallback for both. When cloning a repository, the clone
5388 source is written as ``default`` in ``.hg/hgrc``.
5388 source is written as ``default`` in ``.hg/hgrc``.
5389
5389
5390 .. note::
5390 .. note::
5391
5391
5392 ``default`` and ``default-push`` apply to all inbound (e.g.
5392 ``default`` and ``default-push`` apply to all inbound (e.g.
5393 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5393 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5394 and :hg:`bundle`) operations.
5394 and :hg:`bundle`) operations.
5395
5395
5396 See :hg:`help urls` for more information.
5396 See :hg:`help urls` for more information.
5397
5397
5398 Returns 0 on success.
5398 Returns 0 on success.
5399 """
5399 """
5400 if search:
5400 if search:
5401 for name, path in sorted(ui.paths.iteritems()):
5401 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5402 if name == search:
5402 if name == search]
5403 if not ui.quiet:
5404 ui.write("%s\n" % util.hidepassword(path.rawloc))
5405 return
5406 if not ui.quiet:
5407 ui.warn(_("not found!\n"))
5408 return 1
5409 else:
5403 else:
5410 pathitems = sorted(ui.paths.iteritems())
5404 pathitems = sorted(ui.paths.iteritems())
5411
5405
5412 for name, path in pathitems:
5406 for name, path in pathitems:
5407 if search and not ui.quiet:
5408 ui.write("%s\n" % util.hidepassword(path.rawloc))
5409 if search:
5410 continue
5413 if ui.quiet:
5411 if ui.quiet:
5414 ui.write("%s\n" % name)
5412 ui.write("%s\n" % name)
5415 else:
5413 else:
5416 ui.write("%s = %s\n" % (name, util.hidepassword(path.rawloc)))
5414 ui.write("%s = %s\n" % (name, util.hidepassword(path.rawloc)))
5417 for subopt, value in sorted(path.suboptions.items()):
5415 for subopt, value in sorted(path.suboptions.items()):
5418 ui.write('%s:%s = %s\n' % (name, subopt, value))
5416 ui.write('%s:%s = %s\n' % (name, subopt, value))
5419
5417
5418 if search and not pathitems:
5419 if not ui.quiet:
5420 ui.warn(_("not found!\n"))
5421 return 1
5422 else:
5423 return 0
5424
5420 @command('phase',
5425 @command('phase',
5421 [('p', 'public', False, _('set changeset phase to public')),
5426 [('p', 'public', False, _('set changeset phase to public')),
5422 ('d', 'draft', False, _('set changeset phase to draft')),
5427 ('d', 'draft', False, _('set changeset phase to draft')),
5423 ('s', 'secret', False, _('set changeset phase to secret')),
5428 ('s', 'secret', False, _('set changeset phase to secret')),
5424 ('f', 'force', False, _('allow to move boundary backward')),
5429 ('f', 'force', False, _('allow to move boundary backward')),
5425 ('r', 'rev', [], _('target revision'), _('REV')),
5430 ('r', 'rev', [], _('target revision'), _('REV')),
5426 ],
5431 ],
5427 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5432 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5428 def phase(ui, repo, *revs, **opts):
5433 def phase(ui, repo, *revs, **opts):
5429 """set or show the current phase name
5434 """set or show the current phase name
5430
5435
5431 With no argument, show the phase name of the current revision(s).
5436 With no argument, show the phase name of the current revision(s).
5432
5437
5433 With one of -p/--public, -d/--draft or -s/--secret, change the
5438 With one of -p/--public, -d/--draft or -s/--secret, change the
5434 phase value of the specified revisions.
5439 phase value of the specified revisions.
5435
5440
5436 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5441 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5437 lower phase to an higher phase. Phases are ordered as follows::
5442 lower phase to an higher phase. Phases are ordered as follows::
5438
5443
5439 public < draft < secret
5444 public < draft < secret
5440
5445
5441 Returns 0 on success, 1 if some phases could not be changed.
5446 Returns 0 on success, 1 if some phases could not be changed.
5442
5447
5443 (For more information about the phases concept, see :hg:`help phases`.)
5448 (For more information about the phases concept, see :hg:`help phases`.)
5444 """
5449 """
5445 # search for a unique phase argument
5450 # search for a unique phase argument
5446 targetphase = None
5451 targetphase = None
5447 for idx, name in enumerate(phases.phasenames):
5452 for idx, name in enumerate(phases.phasenames):
5448 if opts[name]:
5453 if opts[name]:
5449 if targetphase is not None:
5454 if targetphase is not None:
5450 raise error.Abort(_('only one phase can be specified'))
5455 raise error.Abort(_('only one phase can be specified'))
5451 targetphase = idx
5456 targetphase = idx
5452
5457
5453 # look for specified revision
5458 # look for specified revision
5454 revs = list(revs)
5459 revs = list(revs)
5455 revs.extend(opts['rev'])
5460 revs.extend(opts['rev'])
5456 if not revs:
5461 if not revs:
5457 # display both parents as the second parent phase can influence
5462 # display both parents as the second parent phase can influence
5458 # the phase of a merge commit
5463 # the phase of a merge commit
5459 revs = [c.rev() for c in repo[None].parents()]
5464 revs = [c.rev() for c in repo[None].parents()]
5460
5465
5461 revs = scmutil.revrange(repo, revs)
5466 revs = scmutil.revrange(repo, revs)
5462
5467
5463 lock = None
5468 lock = None
5464 ret = 0
5469 ret = 0
5465 if targetphase is None:
5470 if targetphase is None:
5466 # display
5471 # display
5467 for r in revs:
5472 for r in revs:
5468 ctx = repo[r]
5473 ctx = repo[r]
5469 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5474 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5470 else:
5475 else:
5471 tr = None
5476 tr = None
5472 lock = repo.lock()
5477 lock = repo.lock()
5473 try:
5478 try:
5474 tr = repo.transaction("phase")
5479 tr = repo.transaction("phase")
5475 # set phase
5480 # set phase
5476 if not revs:
5481 if not revs:
5477 raise error.Abort(_('empty revision set'))
5482 raise error.Abort(_('empty revision set'))
5478 nodes = [repo[r].node() for r in revs]
5483 nodes = [repo[r].node() for r in revs]
5479 # moving revision from public to draft may hide them
5484 # moving revision from public to draft may hide them
5480 # We have to check result on an unfiltered repository
5485 # We have to check result on an unfiltered repository
5481 unfi = repo.unfiltered()
5486 unfi = repo.unfiltered()
5482 getphase = unfi._phasecache.phase
5487 getphase = unfi._phasecache.phase
5483 olddata = [getphase(unfi, r) for r in unfi]
5488 olddata = [getphase(unfi, r) for r in unfi]
5484 phases.advanceboundary(repo, tr, targetphase, nodes)
5489 phases.advanceboundary(repo, tr, targetphase, nodes)
5485 if opts['force']:
5490 if opts['force']:
5486 phases.retractboundary(repo, tr, targetphase, nodes)
5491 phases.retractboundary(repo, tr, targetphase, nodes)
5487 tr.close()
5492 tr.close()
5488 finally:
5493 finally:
5489 if tr is not None:
5494 if tr is not None:
5490 tr.release()
5495 tr.release()
5491 lock.release()
5496 lock.release()
5492 getphase = unfi._phasecache.phase
5497 getphase = unfi._phasecache.phase
5493 newdata = [getphase(unfi, r) for r in unfi]
5498 newdata = [getphase(unfi, r) for r in unfi]
5494 changes = sum(newdata[r] != olddata[r] for r in unfi)
5499 changes = sum(newdata[r] != olddata[r] for r in unfi)
5495 cl = unfi.changelog
5500 cl = unfi.changelog
5496 rejected = [n for n in nodes
5501 rejected = [n for n in nodes
5497 if newdata[cl.rev(n)] < targetphase]
5502 if newdata[cl.rev(n)] < targetphase]
5498 if rejected:
5503 if rejected:
5499 ui.warn(_('cannot move %i changesets to a higher '
5504 ui.warn(_('cannot move %i changesets to a higher '
5500 'phase, use --force\n') % len(rejected))
5505 'phase, use --force\n') % len(rejected))
5501 ret = 1
5506 ret = 1
5502 if changes:
5507 if changes:
5503 msg = _('phase changed for %i changesets\n') % changes
5508 msg = _('phase changed for %i changesets\n') % changes
5504 if ret:
5509 if ret:
5505 ui.status(msg)
5510 ui.status(msg)
5506 else:
5511 else:
5507 ui.note(msg)
5512 ui.note(msg)
5508 else:
5513 else:
5509 ui.warn(_('no phases changed\n'))
5514 ui.warn(_('no phases changed\n'))
5510 return ret
5515 return ret
5511
5516
5512 def postincoming(ui, repo, modheads, optupdate, checkout):
5517 def postincoming(ui, repo, modheads, optupdate, checkout):
5513 if modheads == 0:
5518 if modheads == 0:
5514 return
5519 return
5515 if optupdate:
5520 if optupdate:
5516 try:
5521 try:
5517 brev = checkout
5522 brev = checkout
5518 movemarkfrom = None
5523 movemarkfrom = None
5519 if not checkout:
5524 if not checkout:
5520 updata = destutil.destupdate(repo)
5525 updata = destutil.destupdate(repo)
5521 checkout, movemarkfrom, brev = updata
5526 checkout, movemarkfrom, brev = updata
5522 ret = hg.update(repo, checkout)
5527 ret = hg.update(repo, checkout)
5523 except error.UpdateAbort as inst:
5528 except error.UpdateAbort as inst:
5524 msg = _("not updating: %s") % str(inst)
5529 msg = _("not updating: %s") % str(inst)
5525 hint = inst.hint
5530 hint = inst.hint
5526 raise error.UpdateAbort(msg, hint=hint)
5531 raise error.UpdateAbort(msg, hint=hint)
5527 if not ret and not checkout:
5532 if not ret and not checkout:
5528 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5533 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5529 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5534 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5530 return ret
5535 return ret
5531 if modheads > 1:
5536 if modheads > 1:
5532 currentbranchheads = len(repo.branchheads())
5537 currentbranchheads = len(repo.branchheads())
5533 if currentbranchheads == modheads:
5538 if currentbranchheads == modheads:
5534 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5539 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5535 elif currentbranchheads > 1:
5540 elif currentbranchheads > 1:
5536 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5541 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5537 "merge)\n"))
5542 "merge)\n"))
5538 else:
5543 else:
5539 ui.status(_("(run 'hg heads' to see heads)\n"))
5544 ui.status(_("(run 'hg heads' to see heads)\n"))
5540 else:
5545 else:
5541 ui.status(_("(run 'hg update' to get a working copy)\n"))
5546 ui.status(_("(run 'hg update' to get a working copy)\n"))
5542
5547
5543 @command('^pull',
5548 @command('^pull',
5544 [('u', 'update', None,
5549 [('u', 'update', None,
5545 _('update to new branch head if changesets were pulled')),
5550 _('update to new branch head if changesets were pulled')),
5546 ('f', 'force', None, _('run even when remote repository is unrelated')),
5551 ('f', 'force', None, _('run even when remote repository is unrelated')),
5547 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5552 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5548 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5553 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5549 ('b', 'branch', [], _('a specific branch you would like to pull'),
5554 ('b', 'branch', [], _('a specific branch you would like to pull'),
5550 _('BRANCH')),
5555 _('BRANCH')),
5551 ] + remoteopts,
5556 ] + remoteopts,
5552 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5557 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5553 def pull(ui, repo, source="default", **opts):
5558 def pull(ui, repo, source="default", **opts):
5554 """pull changes from the specified source
5559 """pull changes from the specified source
5555
5560
5556 Pull changes from a remote repository to a local one.
5561 Pull changes from a remote repository to a local one.
5557
5562
5558 This finds all changes from the repository at the specified path
5563 This finds all changes from the repository at the specified path
5559 or URL and adds them to a local repository (the current one unless
5564 or URL and adds them to a local repository (the current one unless
5560 -R is specified). By default, this does not update the copy of the
5565 -R is specified). By default, this does not update the copy of the
5561 project in the working directory.
5566 project in the working directory.
5562
5567
5563 Use :hg:`incoming` if you want to see what would have been added
5568 Use :hg:`incoming` if you want to see what would have been added
5564 by a pull at the time you issued this command. If you then decide
5569 by a pull at the time you issued this command. If you then decide
5565 to add those changes to the repository, you should use :hg:`pull
5570 to add those changes to the repository, you should use :hg:`pull
5566 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5571 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5567
5572
5568 If SOURCE is omitted, the 'default' path will be used.
5573 If SOURCE is omitted, the 'default' path will be used.
5569 See :hg:`help urls` for more information.
5574 See :hg:`help urls` for more information.
5570
5575
5571 Returns 0 on success, 1 if an update had unresolved files.
5576 Returns 0 on success, 1 if an update had unresolved files.
5572 """
5577 """
5573 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5578 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5574 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5579 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5575 other = hg.peer(repo, opts, source)
5580 other = hg.peer(repo, opts, source)
5576 try:
5581 try:
5577 revs, checkout = hg.addbranchrevs(repo, other, branches,
5582 revs, checkout = hg.addbranchrevs(repo, other, branches,
5578 opts.get('rev'))
5583 opts.get('rev'))
5579
5584
5580
5585
5581 pullopargs = {}
5586 pullopargs = {}
5582 if opts.get('bookmark'):
5587 if opts.get('bookmark'):
5583 if not revs:
5588 if not revs:
5584 revs = []
5589 revs = []
5585 # The list of bookmark used here is not the one used to actually
5590 # The list of bookmark used here is not the one used to actually
5586 # update the bookmark name. This can result in the revision pulled
5591 # update the bookmark name. This can result in the revision pulled
5587 # not ending up with the name of the bookmark because of a race
5592 # not ending up with the name of the bookmark because of a race
5588 # condition on the server. (See issue 4689 for details)
5593 # condition on the server. (See issue 4689 for details)
5589 remotebookmarks = other.listkeys('bookmarks')
5594 remotebookmarks = other.listkeys('bookmarks')
5590 pullopargs['remotebookmarks'] = remotebookmarks
5595 pullopargs['remotebookmarks'] = remotebookmarks
5591 for b in opts['bookmark']:
5596 for b in opts['bookmark']:
5592 if b not in remotebookmarks:
5597 if b not in remotebookmarks:
5593 raise error.Abort(_('remote bookmark %s not found!') % b)
5598 raise error.Abort(_('remote bookmark %s not found!') % b)
5594 revs.append(remotebookmarks[b])
5599 revs.append(remotebookmarks[b])
5595
5600
5596 if revs:
5601 if revs:
5597 try:
5602 try:
5598 # When 'rev' is a bookmark name, we cannot guarantee that it
5603 # When 'rev' is a bookmark name, we cannot guarantee that it
5599 # will be updated with that name because of a race condition
5604 # will be updated with that name because of a race condition
5600 # server side. (See issue 4689 for details)
5605 # server side. (See issue 4689 for details)
5601 oldrevs = revs
5606 oldrevs = revs
5602 revs = [] # actually, nodes
5607 revs = [] # actually, nodes
5603 for r in oldrevs:
5608 for r in oldrevs:
5604 node = other.lookup(r)
5609 node = other.lookup(r)
5605 revs.append(node)
5610 revs.append(node)
5606 if r == checkout:
5611 if r == checkout:
5607 checkout = node
5612 checkout = node
5608 except error.CapabilityError:
5613 except error.CapabilityError:
5609 err = _("other repository doesn't support revision lookup, "
5614 err = _("other repository doesn't support revision lookup, "
5610 "so a rev cannot be specified.")
5615 "so a rev cannot be specified.")
5611 raise error.Abort(err)
5616 raise error.Abort(err)
5612
5617
5613 pullopargs.update(opts.get('opargs', {}))
5618 pullopargs.update(opts.get('opargs', {}))
5614 modheads = exchange.pull(repo, other, heads=revs,
5619 modheads = exchange.pull(repo, other, heads=revs,
5615 force=opts.get('force'),
5620 force=opts.get('force'),
5616 bookmarks=opts.get('bookmark', ()),
5621 bookmarks=opts.get('bookmark', ()),
5617 opargs=pullopargs).cgresult
5622 opargs=pullopargs).cgresult
5618 if checkout:
5623 if checkout:
5619 checkout = str(repo.changelog.rev(checkout))
5624 checkout = str(repo.changelog.rev(checkout))
5620 repo._subtoppath = source
5625 repo._subtoppath = source
5621 try:
5626 try:
5622 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5627 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5623
5628
5624 finally:
5629 finally:
5625 del repo._subtoppath
5630 del repo._subtoppath
5626
5631
5627 finally:
5632 finally:
5628 other.close()
5633 other.close()
5629 return ret
5634 return ret
5630
5635
5631 @command('^push',
5636 @command('^push',
5632 [('f', 'force', None, _('force push')),
5637 [('f', 'force', None, _('force push')),
5633 ('r', 'rev', [],
5638 ('r', 'rev', [],
5634 _('a changeset intended to be included in the destination'),
5639 _('a changeset intended to be included in the destination'),
5635 _('REV')),
5640 _('REV')),
5636 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5641 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5637 ('b', 'branch', [],
5642 ('b', 'branch', [],
5638 _('a specific branch you would like to push'), _('BRANCH')),
5643 _('a specific branch you would like to push'), _('BRANCH')),
5639 ('', 'new-branch', False, _('allow pushing a new branch')),
5644 ('', 'new-branch', False, _('allow pushing a new branch')),
5640 ] + remoteopts,
5645 ] + remoteopts,
5641 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5646 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5642 def push(ui, repo, dest=None, **opts):
5647 def push(ui, repo, dest=None, **opts):
5643 """push changes to the specified destination
5648 """push changes to the specified destination
5644
5649
5645 Push changesets from the local repository to the specified
5650 Push changesets from the local repository to the specified
5646 destination.
5651 destination.
5647
5652
5648 This operation is symmetrical to pull: it is identical to a pull
5653 This operation is symmetrical to pull: it is identical to a pull
5649 in the destination repository from the current one.
5654 in the destination repository from the current one.
5650
5655
5651 By default, push will not allow creation of new heads at the
5656 By default, push will not allow creation of new heads at the
5652 destination, since multiple heads would make it unclear which head
5657 destination, since multiple heads would make it unclear which head
5653 to use. In this situation, it is recommended to pull and merge
5658 to use. In this situation, it is recommended to pull and merge
5654 before pushing.
5659 before pushing.
5655
5660
5656 Use --new-branch if you want to allow push to create a new named
5661 Use --new-branch if you want to allow push to create a new named
5657 branch that is not present at the destination. This allows you to
5662 branch that is not present at the destination. This allows you to
5658 only create a new branch without forcing other changes.
5663 only create a new branch without forcing other changes.
5659
5664
5660 .. note::
5665 .. note::
5661
5666
5662 Extra care should be taken with the -f/--force option,
5667 Extra care should be taken with the -f/--force option,
5663 which will push all new heads on all branches, an action which will
5668 which will push all new heads on all branches, an action which will
5664 almost always cause confusion for collaborators.
5669 almost always cause confusion for collaborators.
5665
5670
5666 If -r/--rev is used, the specified revision and all its ancestors
5671 If -r/--rev is used, the specified revision and all its ancestors
5667 will be pushed to the remote repository.
5672 will be pushed to the remote repository.
5668
5673
5669 If -B/--bookmark is used, the specified bookmarked revision, its
5674 If -B/--bookmark is used, the specified bookmarked revision, its
5670 ancestors, and the bookmark will be pushed to the remote
5675 ancestors, and the bookmark will be pushed to the remote
5671 repository.
5676 repository.
5672
5677
5673 Please see :hg:`help urls` for important details about ``ssh://``
5678 Please see :hg:`help urls` for important details about ``ssh://``
5674 URLs. If DESTINATION is omitted, a default path will be used.
5679 URLs. If DESTINATION is omitted, a default path will be used.
5675
5680
5676 Returns 0 if push was successful, 1 if nothing to push.
5681 Returns 0 if push was successful, 1 if nothing to push.
5677 """
5682 """
5678
5683
5679 if opts.get('bookmark'):
5684 if opts.get('bookmark'):
5680 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5685 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5681 for b in opts['bookmark']:
5686 for b in opts['bookmark']:
5682 # translate -B options to -r so changesets get pushed
5687 # translate -B options to -r so changesets get pushed
5683 if b in repo._bookmarks:
5688 if b in repo._bookmarks:
5684 opts.setdefault('rev', []).append(b)
5689 opts.setdefault('rev', []).append(b)
5685 else:
5690 else:
5686 # if we try to push a deleted bookmark, translate it to null
5691 # if we try to push a deleted bookmark, translate it to null
5687 # this lets simultaneous -r, -b options continue working
5692 # this lets simultaneous -r, -b options continue working
5688 opts.setdefault('rev', []).append("null")
5693 opts.setdefault('rev', []).append("null")
5689
5694
5690 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5695 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5691 if not path:
5696 if not path:
5692 raise error.Abort(_('default repository not configured!'),
5697 raise error.Abort(_('default repository not configured!'),
5693 hint=_('see the "path" section in "hg help config"'))
5698 hint=_('see the "path" section in "hg help config"'))
5694 dest = path.pushloc or path.loc
5699 dest = path.pushloc or path.loc
5695 branches = (path.branch, opts.get('branch') or [])
5700 branches = (path.branch, opts.get('branch') or [])
5696 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5701 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5697 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5702 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5698 other = hg.peer(repo, opts, dest)
5703 other = hg.peer(repo, opts, dest)
5699
5704
5700 if revs:
5705 if revs:
5701 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5706 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5702 if not revs:
5707 if not revs:
5703 raise error.Abort(_("specified revisions evaluate to an empty set"),
5708 raise error.Abort(_("specified revisions evaluate to an empty set"),
5704 hint=_("use different revision arguments"))
5709 hint=_("use different revision arguments"))
5705
5710
5706 repo._subtoppath = dest
5711 repo._subtoppath = dest
5707 try:
5712 try:
5708 # push subrepos depth-first for coherent ordering
5713 # push subrepos depth-first for coherent ordering
5709 c = repo['']
5714 c = repo['']
5710 subs = c.substate # only repos that are committed
5715 subs = c.substate # only repos that are committed
5711 for s in sorted(subs):
5716 for s in sorted(subs):
5712 result = c.sub(s).push(opts)
5717 result = c.sub(s).push(opts)
5713 if result == 0:
5718 if result == 0:
5714 return not result
5719 return not result
5715 finally:
5720 finally:
5716 del repo._subtoppath
5721 del repo._subtoppath
5717 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5722 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5718 newbranch=opts.get('new_branch'),
5723 newbranch=opts.get('new_branch'),
5719 bookmarks=opts.get('bookmark', ()),
5724 bookmarks=opts.get('bookmark', ()),
5720 opargs=opts.get('opargs'))
5725 opargs=opts.get('opargs'))
5721
5726
5722 result = not pushop.cgresult
5727 result = not pushop.cgresult
5723
5728
5724 if pushop.bkresult is not None:
5729 if pushop.bkresult is not None:
5725 if pushop.bkresult == 2:
5730 if pushop.bkresult == 2:
5726 result = 2
5731 result = 2
5727 elif not result and pushop.bkresult:
5732 elif not result and pushop.bkresult:
5728 result = 2
5733 result = 2
5729
5734
5730 return result
5735 return result
5731
5736
5732 @command('recover', [])
5737 @command('recover', [])
5733 def recover(ui, repo):
5738 def recover(ui, repo):
5734 """roll back an interrupted transaction
5739 """roll back an interrupted transaction
5735
5740
5736 Recover from an interrupted commit or pull.
5741 Recover from an interrupted commit or pull.
5737
5742
5738 This command tries to fix the repository status after an
5743 This command tries to fix the repository status after an
5739 interrupted operation. It should only be necessary when Mercurial
5744 interrupted operation. It should only be necessary when Mercurial
5740 suggests it.
5745 suggests it.
5741
5746
5742 Returns 0 if successful, 1 if nothing to recover or verify fails.
5747 Returns 0 if successful, 1 if nothing to recover or verify fails.
5743 """
5748 """
5744 if repo.recover():
5749 if repo.recover():
5745 return hg.verify(repo)
5750 return hg.verify(repo)
5746 return 1
5751 return 1
5747
5752
5748 @command('^remove|rm',
5753 @command('^remove|rm',
5749 [('A', 'after', None, _('record delete for missing files')),
5754 [('A', 'after', None, _('record delete for missing files')),
5750 ('f', 'force', None,
5755 ('f', 'force', None,
5751 _('remove (and delete) file even if added or modified')),
5756 _('remove (and delete) file even if added or modified')),
5752 ] + subrepoopts + walkopts,
5757 ] + subrepoopts + walkopts,
5753 _('[OPTION]... FILE...'),
5758 _('[OPTION]... FILE...'),
5754 inferrepo=True)
5759 inferrepo=True)
5755 def remove(ui, repo, *pats, **opts):
5760 def remove(ui, repo, *pats, **opts):
5756 """remove the specified files on the next commit
5761 """remove the specified files on the next commit
5757
5762
5758 Schedule the indicated files for removal from the current branch.
5763 Schedule the indicated files for removal from the current branch.
5759
5764
5760 This command schedules the files to be removed at the next commit.
5765 This command schedules the files to be removed at the next commit.
5761 To undo a remove before that, see :hg:`revert`. To undo added
5766 To undo a remove before that, see :hg:`revert`. To undo added
5762 files, see :hg:`forget`.
5767 files, see :hg:`forget`.
5763
5768
5764 .. container:: verbose
5769 .. container:: verbose
5765
5770
5766 -A/--after can be used to remove only files that have already
5771 -A/--after can be used to remove only files that have already
5767 been deleted, -f/--force can be used to force deletion, and -Af
5772 been deleted, -f/--force can be used to force deletion, and -Af
5768 can be used to remove files from the next revision without
5773 can be used to remove files from the next revision without
5769 deleting them from the working directory.
5774 deleting them from the working directory.
5770
5775
5771 The following table details the behavior of remove for different
5776 The following table details the behavior of remove for different
5772 file states (columns) and option combinations (rows). The file
5777 file states (columns) and option combinations (rows). The file
5773 states are Added [A], Clean [C], Modified [M] and Missing [!]
5778 states are Added [A], Clean [C], Modified [M] and Missing [!]
5774 (as reported by :hg:`status`). The actions are Warn, Remove
5779 (as reported by :hg:`status`). The actions are Warn, Remove
5775 (from branch) and Delete (from disk):
5780 (from branch) and Delete (from disk):
5776
5781
5777 ========= == == == ==
5782 ========= == == == ==
5778 opt/state A C M !
5783 opt/state A C M !
5779 ========= == == == ==
5784 ========= == == == ==
5780 none W RD W R
5785 none W RD W R
5781 -f R RD RD R
5786 -f R RD RD R
5782 -A W W W R
5787 -A W W W R
5783 -Af R R R R
5788 -Af R R R R
5784 ========= == == == ==
5789 ========= == == == ==
5785
5790
5786 .. note::
5791 .. note::
5787
5792
5788 :hg:`remove` never deletes files in Added [A] state from the
5793 :hg:`remove` never deletes files in Added [A] state from the
5789 working directory, not even if ``--force`` is specified.
5794 working directory, not even if ``--force`` is specified.
5790
5795
5791 Returns 0 on success, 1 if any warnings encountered.
5796 Returns 0 on success, 1 if any warnings encountered.
5792 """
5797 """
5793
5798
5794 after, force = opts.get('after'), opts.get('force')
5799 after, force = opts.get('after'), opts.get('force')
5795 if not pats and not after:
5800 if not pats and not after:
5796 raise error.Abort(_('no files specified'))
5801 raise error.Abort(_('no files specified'))
5797
5802
5798 m = scmutil.match(repo[None], pats, opts)
5803 m = scmutil.match(repo[None], pats, opts)
5799 subrepos = opts.get('subrepos')
5804 subrepos = opts.get('subrepos')
5800 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5805 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5801
5806
5802 @command('rename|move|mv',
5807 @command('rename|move|mv',
5803 [('A', 'after', None, _('record a rename that has already occurred')),
5808 [('A', 'after', None, _('record a rename that has already occurred')),
5804 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5809 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5805 ] + walkopts + dryrunopts,
5810 ] + walkopts + dryrunopts,
5806 _('[OPTION]... SOURCE... DEST'))
5811 _('[OPTION]... SOURCE... DEST'))
5807 def rename(ui, repo, *pats, **opts):
5812 def rename(ui, repo, *pats, **opts):
5808 """rename files; equivalent of copy + remove
5813 """rename files; equivalent of copy + remove
5809
5814
5810 Mark dest as copies of sources; mark sources for deletion. If dest
5815 Mark dest as copies of sources; mark sources for deletion. If dest
5811 is a directory, copies are put in that directory. If dest is a
5816 is a directory, copies are put in that directory. If dest is a
5812 file, there can only be one source.
5817 file, there can only be one source.
5813
5818
5814 By default, this command copies the contents of files as they
5819 By default, this command copies the contents of files as they
5815 exist in the working directory. If invoked with -A/--after, the
5820 exist in the working directory. If invoked with -A/--after, the
5816 operation is recorded, but no copying is performed.
5821 operation is recorded, but no copying is performed.
5817
5822
5818 This command takes effect at the next commit. To undo a rename
5823 This command takes effect at the next commit. To undo a rename
5819 before that, see :hg:`revert`.
5824 before that, see :hg:`revert`.
5820
5825
5821 Returns 0 on success, 1 if errors are encountered.
5826 Returns 0 on success, 1 if errors are encountered.
5822 """
5827 """
5823 wlock = repo.wlock(False)
5828 wlock = repo.wlock(False)
5824 try:
5829 try:
5825 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5830 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5826 finally:
5831 finally:
5827 wlock.release()
5832 wlock.release()
5828
5833
5829 @command('resolve',
5834 @command('resolve',
5830 [('a', 'all', None, _('select all unresolved files')),
5835 [('a', 'all', None, _('select all unresolved files')),
5831 ('l', 'list', None, _('list state of files needing merge')),
5836 ('l', 'list', None, _('list state of files needing merge')),
5832 ('m', 'mark', None, _('mark files as resolved')),
5837 ('m', 'mark', None, _('mark files as resolved')),
5833 ('u', 'unmark', None, _('mark files as unresolved')),
5838 ('u', 'unmark', None, _('mark files as unresolved')),
5834 ('n', 'no-status', None, _('hide status prefix'))]
5839 ('n', 'no-status', None, _('hide status prefix'))]
5835 + mergetoolopts + walkopts + formatteropts,
5840 + mergetoolopts + walkopts + formatteropts,
5836 _('[OPTION]... [FILE]...'),
5841 _('[OPTION]... [FILE]...'),
5837 inferrepo=True)
5842 inferrepo=True)
5838 def resolve(ui, repo, *pats, **opts):
5843 def resolve(ui, repo, *pats, **opts):
5839 """redo merges or set/view the merge status of files
5844 """redo merges or set/view the merge status of files
5840
5845
5841 Merges with unresolved conflicts are often the result of
5846 Merges with unresolved conflicts are often the result of
5842 non-interactive merging using the ``internal:merge`` configuration
5847 non-interactive merging using the ``internal:merge`` configuration
5843 setting, or a command-line merge tool like ``diff3``. The resolve
5848 setting, or a command-line merge tool like ``diff3``. The resolve
5844 command is used to manage the files involved in a merge, after
5849 command is used to manage the files involved in a merge, after
5845 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5850 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5846 working directory must have two parents). See :hg:`help
5851 working directory must have two parents). See :hg:`help
5847 merge-tools` for information on configuring merge tools.
5852 merge-tools` for information on configuring merge tools.
5848
5853
5849 The resolve command can be used in the following ways:
5854 The resolve command can be used in the following ways:
5850
5855
5851 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5856 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5852 files, discarding any previous merge attempts. Re-merging is not
5857 files, discarding any previous merge attempts. Re-merging is not
5853 performed for files already marked as resolved. Use ``--all/-a``
5858 performed for files already marked as resolved. Use ``--all/-a``
5854 to select all unresolved files. ``--tool`` can be used to specify
5859 to select all unresolved files. ``--tool`` can be used to specify
5855 the merge tool used for the given files. It overrides the HGMERGE
5860 the merge tool used for the given files. It overrides the HGMERGE
5856 environment variable and your configuration files. Previous file
5861 environment variable and your configuration files. Previous file
5857 contents are saved with a ``.orig`` suffix.
5862 contents are saved with a ``.orig`` suffix.
5858
5863
5859 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5864 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5860 (e.g. after having manually fixed-up the files). The default is
5865 (e.g. after having manually fixed-up the files). The default is
5861 to mark all unresolved files.
5866 to mark all unresolved files.
5862
5867
5863 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5868 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5864 default is to mark all resolved files.
5869 default is to mark all resolved files.
5865
5870
5866 - :hg:`resolve -l`: list files which had or still have conflicts.
5871 - :hg:`resolve -l`: list files which had or still have conflicts.
5867 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5872 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5868
5873
5869 .. note::
5874 .. note::
5870
5875
5871 Mercurial will not let you commit files with unresolved merge
5876 Mercurial will not let you commit files with unresolved merge
5872 conflicts. You must use :hg:`resolve -m ...` before you can
5877 conflicts. You must use :hg:`resolve -m ...` before you can
5873 commit after a conflicting merge.
5878 commit after a conflicting merge.
5874
5879
5875 Returns 0 on success, 1 if any files fail a resolve attempt.
5880 Returns 0 on success, 1 if any files fail a resolve attempt.
5876 """
5881 """
5877
5882
5878 all, mark, unmark, show, nostatus = \
5883 all, mark, unmark, show, nostatus = \
5879 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5884 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5880
5885
5881 if (show and (mark or unmark)) or (mark and unmark):
5886 if (show and (mark or unmark)) or (mark and unmark):
5882 raise error.Abort(_("too many options specified"))
5887 raise error.Abort(_("too many options specified"))
5883 if pats and all:
5888 if pats and all:
5884 raise error.Abort(_("can't specify --all and patterns"))
5889 raise error.Abort(_("can't specify --all and patterns"))
5885 if not (all or pats or show or mark or unmark):
5890 if not (all or pats or show or mark or unmark):
5886 raise error.Abort(_('no files or directories specified'),
5891 raise error.Abort(_('no files or directories specified'),
5887 hint=('use --all to re-merge all unresolved files'))
5892 hint=('use --all to re-merge all unresolved files'))
5888
5893
5889 if show:
5894 if show:
5890 fm = ui.formatter('resolve', opts)
5895 fm = ui.formatter('resolve', opts)
5891 ms = mergemod.mergestate.read(repo)
5896 ms = mergemod.mergestate.read(repo)
5892 m = scmutil.match(repo[None], pats, opts)
5897 m = scmutil.match(repo[None], pats, opts)
5893 for f in ms:
5898 for f in ms:
5894 if not m(f):
5899 if not m(f):
5895 continue
5900 continue
5896 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5901 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5897 'd': 'driverresolved'}[ms[f]]
5902 'd': 'driverresolved'}[ms[f]]
5898 fm.startitem()
5903 fm.startitem()
5899 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5904 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5900 fm.write('path', '%s\n', f, label=l)
5905 fm.write('path', '%s\n', f, label=l)
5901 fm.end()
5906 fm.end()
5902 return 0
5907 return 0
5903
5908
5904 wlock = repo.wlock()
5909 wlock = repo.wlock()
5905 try:
5910 try:
5906 ms = mergemod.mergestate.read(repo)
5911 ms = mergemod.mergestate.read(repo)
5907
5912
5908 if not (ms.active() or repo.dirstate.p2() != nullid):
5913 if not (ms.active() or repo.dirstate.p2() != nullid):
5909 raise error.Abort(
5914 raise error.Abort(
5910 _('resolve command not applicable when not merging'))
5915 _('resolve command not applicable when not merging'))
5911
5916
5912 wctx = repo[None]
5917 wctx = repo[None]
5913
5918
5914 if ms.mergedriver and ms.mdstate() == 'u':
5919 if ms.mergedriver and ms.mdstate() == 'u':
5915 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5920 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5916 ms.commit()
5921 ms.commit()
5917 # allow mark and unmark to go through
5922 # allow mark and unmark to go through
5918 if not mark and not unmark and not proceed:
5923 if not mark and not unmark and not proceed:
5919 return 1
5924 return 1
5920
5925
5921 m = scmutil.match(wctx, pats, opts)
5926 m = scmutil.match(wctx, pats, opts)
5922 ret = 0
5927 ret = 0
5923 didwork = False
5928 didwork = False
5924 runconclude = False
5929 runconclude = False
5925
5930
5926 tocomplete = []
5931 tocomplete = []
5927 for f in ms:
5932 for f in ms:
5928 if not m(f):
5933 if not m(f):
5929 continue
5934 continue
5930
5935
5931 didwork = True
5936 didwork = True
5932
5937
5933 # don't let driver-resolved files be marked, and run the conclude
5938 # don't let driver-resolved files be marked, and run the conclude
5934 # step if asked to resolve
5939 # step if asked to resolve
5935 if ms[f] == "d":
5940 if ms[f] == "d":
5936 exact = m.exact(f)
5941 exact = m.exact(f)
5937 if mark:
5942 if mark:
5938 if exact:
5943 if exact:
5939 ui.warn(_('not marking %s as it is driver-resolved\n')
5944 ui.warn(_('not marking %s as it is driver-resolved\n')
5940 % f)
5945 % f)
5941 elif unmark:
5946 elif unmark:
5942 if exact:
5947 if exact:
5943 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5948 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5944 % f)
5949 % f)
5945 else:
5950 else:
5946 runconclude = True
5951 runconclude = True
5947 continue
5952 continue
5948
5953
5949 if mark:
5954 if mark:
5950 ms.mark(f, "r")
5955 ms.mark(f, "r")
5951 elif unmark:
5956 elif unmark:
5952 ms.mark(f, "u")
5957 ms.mark(f, "u")
5953 else:
5958 else:
5954 # backup pre-resolve (merge uses .orig for its own purposes)
5959 # backup pre-resolve (merge uses .orig for its own purposes)
5955 a = repo.wjoin(f)
5960 a = repo.wjoin(f)
5956 try:
5961 try:
5957 util.copyfile(a, a + ".resolve")
5962 util.copyfile(a, a + ".resolve")
5958 except (IOError, OSError) as inst:
5963 except (IOError, OSError) as inst:
5959 if inst.errno != errno.ENOENT:
5964 if inst.errno != errno.ENOENT:
5960 raise
5965 raise
5961
5966
5962 try:
5967 try:
5963 # preresolve file
5968 # preresolve file
5964 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5969 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5965 'resolve')
5970 'resolve')
5966 complete, r = ms.preresolve(f, wctx)
5971 complete, r = ms.preresolve(f, wctx)
5967 if not complete:
5972 if not complete:
5968 tocomplete.append(f)
5973 tocomplete.append(f)
5969 elif r:
5974 elif r:
5970 ret = 1
5975 ret = 1
5971 finally:
5976 finally:
5972 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5977 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5973 ms.commit()
5978 ms.commit()
5974
5979
5975 # replace filemerge's .orig file with our resolve file, but only
5980 # replace filemerge's .orig file with our resolve file, but only
5976 # for merges that are complete
5981 # for merges that are complete
5977 if complete:
5982 if complete:
5978 try:
5983 try:
5979 util.rename(a + ".resolve",
5984 util.rename(a + ".resolve",
5980 scmutil.origpath(ui, repo, a))
5985 scmutil.origpath(ui, repo, a))
5981 except OSError as inst:
5986 except OSError as inst:
5982 if inst.errno != errno.ENOENT:
5987 if inst.errno != errno.ENOENT:
5983 raise
5988 raise
5984
5989
5985 for f in tocomplete:
5990 for f in tocomplete:
5986 try:
5991 try:
5987 # resolve file
5992 # resolve file
5988 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5993 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5989 'resolve')
5994 'resolve')
5990 r = ms.resolve(f, wctx)
5995 r = ms.resolve(f, wctx)
5991 if r:
5996 if r:
5992 ret = 1
5997 ret = 1
5993 finally:
5998 finally:
5994 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5999 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5995 ms.commit()
6000 ms.commit()
5996
6001
5997 # replace filemerge's .orig file with our resolve file
6002 # replace filemerge's .orig file with our resolve file
5998 a = repo.wjoin(f)
6003 a = repo.wjoin(f)
5999 try:
6004 try:
6000 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6005 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6001 except OSError as inst:
6006 except OSError as inst:
6002 if inst.errno != errno.ENOENT:
6007 if inst.errno != errno.ENOENT:
6003 raise
6008 raise
6004
6009
6005 ms.commit()
6010 ms.commit()
6006 ms.recordactions()
6011 ms.recordactions()
6007
6012
6008 if not didwork and pats:
6013 if not didwork and pats:
6009 ui.warn(_("arguments do not match paths that need resolving\n"))
6014 ui.warn(_("arguments do not match paths that need resolving\n"))
6010 elif ms.mergedriver and ms.mdstate() != 's':
6015 elif ms.mergedriver and ms.mdstate() != 's':
6011 # run conclude step when either a driver-resolved file is requested
6016 # run conclude step when either a driver-resolved file is requested
6012 # or there are no driver-resolved files
6017 # or there are no driver-resolved files
6013 # we can't use 'ret' to determine whether any files are unresolved
6018 # we can't use 'ret' to determine whether any files are unresolved
6014 # because we might not have tried to resolve some
6019 # because we might not have tried to resolve some
6015 if ((runconclude or not list(ms.driverresolved()))
6020 if ((runconclude or not list(ms.driverresolved()))
6016 and not list(ms.unresolved())):
6021 and not list(ms.unresolved())):
6017 proceed = mergemod.driverconclude(repo, ms, wctx)
6022 proceed = mergemod.driverconclude(repo, ms, wctx)
6018 ms.commit()
6023 ms.commit()
6019 if not proceed:
6024 if not proceed:
6020 return 1
6025 return 1
6021
6026
6022 finally:
6027 finally:
6023 wlock.release()
6028 wlock.release()
6024
6029
6025 # Nudge users into finishing an unfinished operation
6030 # Nudge users into finishing an unfinished operation
6026 unresolvedf = list(ms.unresolved())
6031 unresolvedf = list(ms.unresolved())
6027 driverresolvedf = list(ms.driverresolved())
6032 driverresolvedf = list(ms.driverresolved())
6028 if not unresolvedf and not driverresolvedf:
6033 if not unresolvedf and not driverresolvedf:
6029 ui.status(_('(no more unresolved files)\n'))
6034 ui.status(_('(no more unresolved files)\n'))
6030 cmdutil.checkafterresolved(repo)
6035 cmdutil.checkafterresolved(repo)
6031 elif not unresolvedf:
6036 elif not unresolvedf:
6032 ui.status(_('(no more unresolved files -- '
6037 ui.status(_('(no more unresolved files -- '
6033 'run "hg resolve --all" to conclude)\n'))
6038 'run "hg resolve --all" to conclude)\n'))
6034
6039
6035 return ret
6040 return ret
6036
6041
6037 @command('revert',
6042 @command('revert',
6038 [('a', 'all', None, _('revert all changes when no arguments given')),
6043 [('a', 'all', None, _('revert all changes when no arguments given')),
6039 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6044 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6040 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6045 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6041 ('C', 'no-backup', None, _('do not save backup copies of files')),
6046 ('C', 'no-backup', None, _('do not save backup copies of files')),
6042 ('i', 'interactive', None,
6047 ('i', 'interactive', None,
6043 _('interactively select the changes (EXPERIMENTAL)')),
6048 _('interactively select the changes (EXPERIMENTAL)')),
6044 ] + walkopts + dryrunopts,
6049 ] + walkopts + dryrunopts,
6045 _('[OPTION]... [-r REV] [NAME]...'))
6050 _('[OPTION]... [-r REV] [NAME]...'))
6046 def revert(ui, repo, *pats, **opts):
6051 def revert(ui, repo, *pats, **opts):
6047 """restore files to their checkout state
6052 """restore files to their checkout state
6048
6053
6049 .. note::
6054 .. note::
6050
6055
6051 To check out earlier revisions, you should use :hg:`update REV`.
6056 To check out earlier revisions, you should use :hg:`update REV`.
6052 To cancel an uncommitted merge (and lose your changes),
6057 To cancel an uncommitted merge (and lose your changes),
6053 use :hg:`update --clean .`.
6058 use :hg:`update --clean .`.
6054
6059
6055 With no revision specified, revert the specified files or directories
6060 With no revision specified, revert the specified files or directories
6056 to the contents they had in the parent of the working directory.
6061 to the contents they had in the parent of the working directory.
6057 This restores the contents of files to an unmodified
6062 This restores the contents of files to an unmodified
6058 state and unschedules adds, removes, copies, and renames. If the
6063 state and unschedules adds, removes, copies, and renames. If the
6059 working directory has two parents, you must explicitly specify a
6064 working directory has two parents, you must explicitly specify a
6060 revision.
6065 revision.
6061
6066
6062 Using the -r/--rev or -d/--date options, revert the given files or
6067 Using the -r/--rev or -d/--date options, revert the given files or
6063 directories to their states as of a specific revision. Because
6068 directories to their states as of a specific revision. Because
6064 revert does not change the working directory parents, this will
6069 revert does not change the working directory parents, this will
6065 cause these files to appear modified. This can be helpful to "back
6070 cause these files to appear modified. This can be helpful to "back
6066 out" some or all of an earlier change. See :hg:`backout` for a
6071 out" some or all of an earlier change. See :hg:`backout` for a
6067 related method.
6072 related method.
6068
6073
6069 Modified files are saved with a .orig suffix before reverting.
6074 Modified files are saved with a .orig suffix before reverting.
6070 To disable these backups, use --no-backup.
6075 To disable these backups, use --no-backup.
6071
6076
6072 See :hg:`help dates` for a list of formats valid for -d/--date.
6077 See :hg:`help dates` for a list of formats valid for -d/--date.
6073
6078
6074 See :hg:`help backout` for a way to reverse the effect of an
6079 See :hg:`help backout` for a way to reverse the effect of an
6075 earlier changeset.
6080 earlier changeset.
6076
6081
6077 Returns 0 on success.
6082 Returns 0 on success.
6078 """
6083 """
6079
6084
6080 if opts.get("date"):
6085 if opts.get("date"):
6081 if opts.get("rev"):
6086 if opts.get("rev"):
6082 raise error.Abort(_("you can't specify a revision and a date"))
6087 raise error.Abort(_("you can't specify a revision and a date"))
6083 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6088 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6084
6089
6085 parent, p2 = repo.dirstate.parents()
6090 parent, p2 = repo.dirstate.parents()
6086 if not opts.get('rev') and p2 != nullid:
6091 if not opts.get('rev') and p2 != nullid:
6087 # revert after merge is a trap for new users (issue2915)
6092 # revert after merge is a trap for new users (issue2915)
6088 raise error.Abort(_('uncommitted merge with no revision specified'),
6093 raise error.Abort(_('uncommitted merge with no revision specified'),
6089 hint=_('use "hg update" or see "hg help revert"'))
6094 hint=_('use "hg update" or see "hg help revert"'))
6090
6095
6091 ctx = scmutil.revsingle(repo, opts.get('rev'))
6096 ctx = scmutil.revsingle(repo, opts.get('rev'))
6092
6097
6093 if (not (pats or opts.get('include') or opts.get('exclude') or
6098 if (not (pats or opts.get('include') or opts.get('exclude') or
6094 opts.get('all') or opts.get('interactive'))):
6099 opts.get('all') or opts.get('interactive'))):
6095 msg = _("no files or directories specified")
6100 msg = _("no files or directories specified")
6096 if p2 != nullid:
6101 if p2 != nullid:
6097 hint = _("uncommitted merge, use --all to discard all changes,"
6102 hint = _("uncommitted merge, use --all to discard all changes,"
6098 " or 'hg update -C .' to abort the merge")
6103 " or 'hg update -C .' to abort the merge")
6099 raise error.Abort(msg, hint=hint)
6104 raise error.Abort(msg, hint=hint)
6100 dirty = any(repo.status())
6105 dirty = any(repo.status())
6101 node = ctx.node()
6106 node = ctx.node()
6102 if node != parent:
6107 if node != parent:
6103 if dirty:
6108 if dirty:
6104 hint = _("uncommitted changes, use --all to discard all"
6109 hint = _("uncommitted changes, use --all to discard all"
6105 " changes, or 'hg update %s' to update") % ctx.rev()
6110 " changes, or 'hg update %s' to update") % ctx.rev()
6106 else:
6111 else:
6107 hint = _("use --all to revert all files,"
6112 hint = _("use --all to revert all files,"
6108 " or 'hg update %s' to update") % ctx.rev()
6113 " or 'hg update %s' to update") % ctx.rev()
6109 elif dirty:
6114 elif dirty:
6110 hint = _("uncommitted changes, use --all to discard all changes")
6115 hint = _("uncommitted changes, use --all to discard all changes")
6111 else:
6116 else:
6112 hint = _("use --all to revert all files")
6117 hint = _("use --all to revert all files")
6113 raise error.Abort(msg, hint=hint)
6118 raise error.Abort(msg, hint=hint)
6114
6119
6115 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6120 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6116
6121
6117 @command('rollback', dryrunopts +
6122 @command('rollback', dryrunopts +
6118 [('f', 'force', False, _('ignore safety measures'))])
6123 [('f', 'force', False, _('ignore safety measures'))])
6119 def rollback(ui, repo, **opts):
6124 def rollback(ui, repo, **opts):
6120 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6125 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6121
6126
6122 Please use :hg:`commit --amend` instead of rollback to correct
6127 Please use :hg:`commit --amend` instead of rollback to correct
6123 mistakes in the last commit.
6128 mistakes in the last commit.
6124
6129
6125 This command should be used with care. There is only one level of
6130 This command should be used with care. There is only one level of
6126 rollback, and there is no way to undo a rollback. It will also
6131 rollback, and there is no way to undo a rollback. It will also
6127 restore the dirstate at the time of the last transaction, losing
6132 restore the dirstate at the time of the last transaction, losing
6128 any dirstate changes since that time. This command does not alter
6133 any dirstate changes since that time. This command does not alter
6129 the working directory.
6134 the working directory.
6130
6135
6131 Transactions are used to encapsulate the effects of all commands
6136 Transactions are used to encapsulate the effects of all commands
6132 that create new changesets or propagate existing changesets into a
6137 that create new changesets or propagate existing changesets into a
6133 repository.
6138 repository.
6134
6139
6135 .. container:: verbose
6140 .. container:: verbose
6136
6141
6137 For example, the following commands are transactional, and their
6142 For example, the following commands are transactional, and their
6138 effects can be rolled back:
6143 effects can be rolled back:
6139
6144
6140 - commit
6145 - commit
6141 - import
6146 - import
6142 - pull
6147 - pull
6143 - push (with this repository as the destination)
6148 - push (with this repository as the destination)
6144 - unbundle
6149 - unbundle
6145
6150
6146 To avoid permanent data loss, rollback will refuse to rollback a
6151 To avoid permanent data loss, rollback will refuse to rollback a
6147 commit transaction if it isn't checked out. Use --force to
6152 commit transaction if it isn't checked out. Use --force to
6148 override this protection.
6153 override this protection.
6149
6154
6150 This command is not intended for use on public repositories. Once
6155 This command is not intended for use on public repositories. Once
6151 changes are visible for pull by other users, rolling a transaction
6156 changes are visible for pull by other users, rolling a transaction
6152 back locally is ineffective (someone else may already have pulled
6157 back locally is ineffective (someone else may already have pulled
6153 the changes). Furthermore, a race is possible with readers of the
6158 the changes). Furthermore, a race is possible with readers of the
6154 repository; for example an in-progress pull from the repository
6159 repository; for example an in-progress pull from the repository
6155 may fail if a rollback is performed.
6160 may fail if a rollback is performed.
6156
6161
6157 Returns 0 on success, 1 if no rollback data is available.
6162 Returns 0 on success, 1 if no rollback data is available.
6158 """
6163 """
6159 return repo.rollback(dryrun=opts.get('dry_run'),
6164 return repo.rollback(dryrun=opts.get('dry_run'),
6160 force=opts.get('force'))
6165 force=opts.get('force'))
6161
6166
6162 @command('root', [])
6167 @command('root', [])
6163 def root(ui, repo):
6168 def root(ui, repo):
6164 """print the root (top) of the current working directory
6169 """print the root (top) of the current working directory
6165
6170
6166 Print the root directory of the current repository.
6171 Print the root directory of the current repository.
6167
6172
6168 Returns 0 on success.
6173 Returns 0 on success.
6169 """
6174 """
6170 ui.write(repo.root + "\n")
6175 ui.write(repo.root + "\n")
6171
6176
6172 @command('^serve',
6177 @command('^serve',
6173 [('A', 'accesslog', '', _('name of access log file to write to'),
6178 [('A', 'accesslog', '', _('name of access log file to write to'),
6174 _('FILE')),
6179 _('FILE')),
6175 ('d', 'daemon', None, _('run server in background')),
6180 ('d', 'daemon', None, _('run server in background')),
6176 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6181 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6177 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6182 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6178 # use string type, then we can check if something was passed
6183 # use string type, then we can check if something was passed
6179 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6184 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6180 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6185 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6181 _('ADDR')),
6186 _('ADDR')),
6182 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6187 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6183 _('PREFIX')),
6188 _('PREFIX')),
6184 ('n', 'name', '',
6189 ('n', 'name', '',
6185 _('name to show in web pages (default: working directory)'), _('NAME')),
6190 _('name to show in web pages (default: working directory)'), _('NAME')),
6186 ('', 'web-conf', '',
6191 ('', 'web-conf', '',
6187 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6192 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6188 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6193 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6189 _('FILE')),
6194 _('FILE')),
6190 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6195 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6191 ('', 'stdio', None, _('for remote clients')),
6196 ('', 'stdio', None, _('for remote clients')),
6192 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6197 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6193 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6198 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6194 ('', 'style', '', _('template style to use'), _('STYLE')),
6199 ('', 'style', '', _('template style to use'), _('STYLE')),
6195 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6200 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6196 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6201 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6197 _('[OPTION]...'),
6202 _('[OPTION]...'),
6198 optionalrepo=True)
6203 optionalrepo=True)
6199 def serve(ui, repo, **opts):
6204 def serve(ui, repo, **opts):
6200 """start stand-alone webserver
6205 """start stand-alone webserver
6201
6206
6202 Start a local HTTP repository browser and pull server. You can use
6207 Start a local HTTP repository browser and pull server. You can use
6203 this for ad-hoc sharing and browsing of repositories. It is
6208 this for ad-hoc sharing and browsing of repositories. It is
6204 recommended to use a real web server to serve a repository for
6209 recommended to use a real web server to serve a repository for
6205 longer periods of time.
6210 longer periods of time.
6206
6211
6207 Please note that the server does not implement access control.
6212 Please note that the server does not implement access control.
6208 This means that, by default, anybody can read from the server and
6213 This means that, by default, anybody can read from the server and
6209 nobody can write to it by default. Set the ``web.allow_push``
6214 nobody can write to it by default. Set the ``web.allow_push``
6210 option to ``*`` to allow everybody to push to the server. You
6215 option to ``*`` to allow everybody to push to the server. You
6211 should use a real web server if you need to authenticate users.
6216 should use a real web server if you need to authenticate users.
6212
6217
6213 By default, the server logs accesses to stdout and errors to
6218 By default, the server logs accesses to stdout and errors to
6214 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6219 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6215 files.
6220 files.
6216
6221
6217 To have the server choose a free port number to listen on, specify
6222 To have the server choose a free port number to listen on, specify
6218 a port number of 0; in this case, the server will print the port
6223 a port number of 0; in this case, the server will print the port
6219 number it uses.
6224 number it uses.
6220
6225
6221 Returns 0 on success.
6226 Returns 0 on success.
6222 """
6227 """
6223
6228
6224 if opts["stdio"] and opts["cmdserver"]:
6229 if opts["stdio"] and opts["cmdserver"]:
6225 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6230 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6226
6231
6227 if opts["stdio"]:
6232 if opts["stdio"]:
6228 if repo is None:
6233 if repo is None:
6229 raise error.RepoError(_("there is no Mercurial repository here"
6234 raise error.RepoError(_("there is no Mercurial repository here"
6230 " (.hg not found)"))
6235 " (.hg not found)"))
6231 s = sshserver.sshserver(ui, repo)
6236 s = sshserver.sshserver(ui, repo)
6232 s.serve_forever()
6237 s.serve_forever()
6233
6238
6234 if opts["cmdserver"]:
6239 if opts["cmdserver"]:
6235 service = commandserver.createservice(ui, repo, opts)
6240 service = commandserver.createservice(ui, repo, opts)
6236 else:
6241 else:
6237 service = hgweb.createservice(ui, repo, opts)
6242 service = hgweb.createservice(ui, repo, opts)
6238 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6243 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6239
6244
6240 @command('^status|st',
6245 @command('^status|st',
6241 [('A', 'all', None, _('show status of all files')),
6246 [('A', 'all', None, _('show status of all files')),
6242 ('m', 'modified', None, _('show only modified files')),
6247 ('m', 'modified', None, _('show only modified files')),
6243 ('a', 'added', None, _('show only added files')),
6248 ('a', 'added', None, _('show only added files')),
6244 ('r', 'removed', None, _('show only removed files')),
6249 ('r', 'removed', None, _('show only removed files')),
6245 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6250 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6246 ('c', 'clean', None, _('show only files without changes')),
6251 ('c', 'clean', None, _('show only files without changes')),
6247 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6252 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6248 ('i', 'ignored', None, _('show only ignored files')),
6253 ('i', 'ignored', None, _('show only ignored files')),
6249 ('n', 'no-status', None, _('hide status prefix')),
6254 ('n', 'no-status', None, _('hide status prefix')),
6250 ('C', 'copies', None, _('show source of copied files')),
6255 ('C', 'copies', None, _('show source of copied files')),
6251 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6256 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6252 ('', 'rev', [], _('show difference from revision'), _('REV')),
6257 ('', 'rev', [], _('show difference from revision'), _('REV')),
6253 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6258 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6254 ] + walkopts + subrepoopts + formatteropts,
6259 ] + walkopts + subrepoopts + formatteropts,
6255 _('[OPTION]... [FILE]...'),
6260 _('[OPTION]... [FILE]...'),
6256 inferrepo=True)
6261 inferrepo=True)
6257 def status(ui, repo, *pats, **opts):
6262 def status(ui, repo, *pats, **opts):
6258 """show changed files in the working directory
6263 """show changed files in the working directory
6259
6264
6260 Show status of files in the repository. If names are given, only
6265 Show status of files in the repository. If names are given, only
6261 files that match are shown. Files that are clean or ignored or
6266 files that match are shown. Files that are clean or ignored or
6262 the source of a copy/move operation, are not listed unless
6267 the source of a copy/move operation, are not listed unless
6263 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6268 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6264 Unless options described with "show only ..." are given, the
6269 Unless options described with "show only ..." are given, the
6265 options -mardu are used.
6270 options -mardu are used.
6266
6271
6267 Option -q/--quiet hides untracked (unknown and ignored) files
6272 Option -q/--quiet hides untracked (unknown and ignored) files
6268 unless explicitly requested with -u/--unknown or -i/--ignored.
6273 unless explicitly requested with -u/--unknown or -i/--ignored.
6269
6274
6270 .. note::
6275 .. note::
6271
6276
6272 :hg:`status` may appear to disagree with diff if permissions have
6277 :hg:`status` may appear to disagree with diff if permissions have
6273 changed or a merge has occurred. The standard diff format does
6278 changed or a merge has occurred. The standard diff format does
6274 not report permission changes and diff only reports changes
6279 not report permission changes and diff only reports changes
6275 relative to one merge parent.
6280 relative to one merge parent.
6276
6281
6277 If one revision is given, it is used as the base revision.
6282 If one revision is given, it is used as the base revision.
6278 If two revisions are given, the differences between them are
6283 If two revisions are given, the differences between them are
6279 shown. The --change option can also be used as a shortcut to list
6284 shown. The --change option can also be used as a shortcut to list
6280 the changed files of a revision from its first parent.
6285 the changed files of a revision from its first parent.
6281
6286
6282 The codes used to show the status of files are::
6287 The codes used to show the status of files are::
6283
6288
6284 M = modified
6289 M = modified
6285 A = added
6290 A = added
6286 R = removed
6291 R = removed
6287 C = clean
6292 C = clean
6288 ! = missing (deleted by non-hg command, but still tracked)
6293 ! = missing (deleted by non-hg command, but still tracked)
6289 ? = not tracked
6294 ? = not tracked
6290 I = ignored
6295 I = ignored
6291 = origin of the previous file (with --copies)
6296 = origin of the previous file (with --copies)
6292
6297
6293 .. container:: verbose
6298 .. container:: verbose
6294
6299
6295 Examples:
6300 Examples:
6296
6301
6297 - show changes in the working directory relative to a
6302 - show changes in the working directory relative to a
6298 changeset::
6303 changeset::
6299
6304
6300 hg status --rev 9353
6305 hg status --rev 9353
6301
6306
6302 - show changes in the working directory relative to the
6307 - show changes in the working directory relative to the
6303 current directory (see :hg:`help patterns` for more information)::
6308 current directory (see :hg:`help patterns` for more information)::
6304
6309
6305 hg status re:
6310 hg status re:
6306
6311
6307 - show all changes including copies in an existing changeset::
6312 - show all changes including copies in an existing changeset::
6308
6313
6309 hg status --copies --change 9353
6314 hg status --copies --change 9353
6310
6315
6311 - get a NUL separated list of added files, suitable for xargs::
6316 - get a NUL separated list of added files, suitable for xargs::
6312
6317
6313 hg status -an0
6318 hg status -an0
6314
6319
6315 Returns 0 on success.
6320 Returns 0 on success.
6316 """
6321 """
6317
6322
6318 revs = opts.get('rev')
6323 revs = opts.get('rev')
6319 change = opts.get('change')
6324 change = opts.get('change')
6320
6325
6321 if revs and change:
6326 if revs and change:
6322 msg = _('cannot specify --rev and --change at the same time')
6327 msg = _('cannot specify --rev and --change at the same time')
6323 raise error.Abort(msg)
6328 raise error.Abort(msg)
6324 elif change:
6329 elif change:
6325 node2 = scmutil.revsingle(repo, change, None).node()
6330 node2 = scmutil.revsingle(repo, change, None).node()
6326 node1 = repo[node2].p1().node()
6331 node1 = repo[node2].p1().node()
6327 else:
6332 else:
6328 node1, node2 = scmutil.revpair(repo, revs)
6333 node1, node2 = scmutil.revpair(repo, revs)
6329
6334
6330 if pats:
6335 if pats:
6331 cwd = repo.getcwd()
6336 cwd = repo.getcwd()
6332 else:
6337 else:
6333 cwd = ''
6338 cwd = ''
6334
6339
6335 if opts.get('print0'):
6340 if opts.get('print0'):
6336 end = '\0'
6341 end = '\0'
6337 else:
6342 else:
6338 end = '\n'
6343 end = '\n'
6339 copy = {}
6344 copy = {}
6340 states = 'modified added removed deleted unknown ignored clean'.split()
6345 states = 'modified added removed deleted unknown ignored clean'.split()
6341 show = [k for k in states if opts.get(k)]
6346 show = [k for k in states if opts.get(k)]
6342 if opts.get('all'):
6347 if opts.get('all'):
6343 show += ui.quiet and (states[:4] + ['clean']) or states
6348 show += ui.quiet and (states[:4] + ['clean']) or states
6344 if not show:
6349 if not show:
6345 if ui.quiet:
6350 if ui.quiet:
6346 show = states[:4]
6351 show = states[:4]
6347 else:
6352 else:
6348 show = states[:5]
6353 show = states[:5]
6349
6354
6350 m = scmutil.match(repo[node2], pats, opts)
6355 m = scmutil.match(repo[node2], pats, opts)
6351 stat = repo.status(node1, node2, m,
6356 stat = repo.status(node1, node2, m,
6352 'ignored' in show, 'clean' in show, 'unknown' in show,
6357 'ignored' in show, 'clean' in show, 'unknown' in show,
6353 opts.get('subrepos'))
6358 opts.get('subrepos'))
6354 changestates = zip(states, 'MAR!?IC', stat)
6359 changestates = zip(states, 'MAR!?IC', stat)
6355
6360
6356 if (opts.get('all') or opts.get('copies')
6361 if (opts.get('all') or opts.get('copies')
6357 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6362 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6358 copy = copies.pathcopies(repo[node1], repo[node2], m)
6363 copy = copies.pathcopies(repo[node1], repo[node2], m)
6359
6364
6360 fm = ui.formatter('status', opts)
6365 fm = ui.formatter('status', opts)
6361 fmt = '%s' + end
6366 fmt = '%s' + end
6362 showchar = not opts.get('no_status')
6367 showchar = not opts.get('no_status')
6363
6368
6364 for state, char, files in changestates:
6369 for state, char, files in changestates:
6365 if state in show:
6370 if state in show:
6366 label = 'status.' + state
6371 label = 'status.' + state
6367 for f in files:
6372 for f in files:
6368 fm.startitem()
6373 fm.startitem()
6369 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6374 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6370 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6375 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6371 if f in copy:
6376 if f in copy:
6372 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6377 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6373 label='status.copied')
6378 label='status.copied')
6374 fm.end()
6379 fm.end()
6375
6380
6376 @command('^summary|sum',
6381 @command('^summary|sum',
6377 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6382 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6378 def summary(ui, repo, **opts):
6383 def summary(ui, repo, **opts):
6379 """summarize working directory state
6384 """summarize working directory state
6380
6385
6381 This generates a brief summary of the working directory state,
6386 This generates a brief summary of the working directory state,
6382 including parents, branch, commit status, phase and available updates.
6387 including parents, branch, commit status, phase and available updates.
6383
6388
6384 With the --remote option, this will check the default paths for
6389 With the --remote option, this will check the default paths for
6385 incoming and outgoing changes. This can be time-consuming.
6390 incoming and outgoing changes. This can be time-consuming.
6386
6391
6387 Returns 0 on success.
6392 Returns 0 on success.
6388 """
6393 """
6389
6394
6390 ctx = repo[None]
6395 ctx = repo[None]
6391 parents = ctx.parents()
6396 parents = ctx.parents()
6392 pnode = parents[0].node()
6397 pnode = parents[0].node()
6393 marks = []
6398 marks = []
6394
6399
6395 for p in parents:
6400 for p in parents:
6396 # label with log.changeset (instead of log.parent) since this
6401 # label with log.changeset (instead of log.parent) since this
6397 # shows a working directory parent *changeset*:
6402 # shows a working directory parent *changeset*:
6398 # i18n: column positioning for "hg summary"
6403 # i18n: column positioning for "hg summary"
6399 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6404 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6400 label='log.changeset changeset.%s' % p.phasestr())
6405 label='log.changeset changeset.%s' % p.phasestr())
6401 ui.write(' '.join(p.tags()), label='log.tag')
6406 ui.write(' '.join(p.tags()), label='log.tag')
6402 if p.bookmarks():
6407 if p.bookmarks():
6403 marks.extend(p.bookmarks())
6408 marks.extend(p.bookmarks())
6404 if p.rev() == -1:
6409 if p.rev() == -1:
6405 if not len(repo):
6410 if not len(repo):
6406 ui.write(_(' (empty repository)'))
6411 ui.write(_(' (empty repository)'))
6407 else:
6412 else:
6408 ui.write(_(' (no revision checked out)'))
6413 ui.write(_(' (no revision checked out)'))
6409 ui.write('\n')
6414 ui.write('\n')
6410 if p.description():
6415 if p.description():
6411 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6416 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6412 label='log.summary')
6417 label='log.summary')
6413
6418
6414 branch = ctx.branch()
6419 branch = ctx.branch()
6415 bheads = repo.branchheads(branch)
6420 bheads = repo.branchheads(branch)
6416 # i18n: column positioning for "hg summary"
6421 # i18n: column positioning for "hg summary"
6417 m = _('branch: %s\n') % branch
6422 m = _('branch: %s\n') % branch
6418 if branch != 'default':
6423 if branch != 'default':
6419 ui.write(m, label='log.branch')
6424 ui.write(m, label='log.branch')
6420 else:
6425 else:
6421 ui.status(m, label='log.branch')
6426 ui.status(m, label='log.branch')
6422
6427
6423 if marks:
6428 if marks:
6424 active = repo._activebookmark
6429 active = repo._activebookmark
6425 # i18n: column positioning for "hg summary"
6430 # i18n: column positioning for "hg summary"
6426 ui.write(_('bookmarks:'), label='log.bookmark')
6431 ui.write(_('bookmarks:'), label='log.bookmark')
6427 if active is not None:
6432 if active is not None:
6428 if active in marks:
6433 if active in marks:
6429 ui.write(' *' + active, label=activebookmarklabel)
6434 ui.write(' *' + active, label=activebookmarklabel)
6430 marks.remove(active)
6435 marks.remove(active)
6431 else:
6436 else:
6432 ui.write(' [%s]' % active, label=activebookmarklabel)
6437 ui.write(' [%s]' % active, label=activebookmarklabel)
6433 for m in marks:
6438 for m in marks:
6434 ui.write(' ' + m, label='log.bookmark')
6439 ui.write(' ' + m, label='log.bookmark')
6435 ui.write('\n', label='log.bookmark')
6440 ui.write('\n', label='log.bookmark')
6436
6441
6437 status = repo.status(unknown=True)
6442 status = repo.status(unknown=True)
6438
6443
6439 c = repo.dirstate.copies()
6444 c = repo.dirstate.copies()
6440 copied, renamed = [], []
6445 copied, renamed = [], []
6441 for d, s in c.iteritems():
6446 for d, s in c.iteritems():
6442 if s in status.removed:
6447 if s in status.removed:
6443 status.removed.remove(s)
6448 status.removed.remove(s)
6444 renamed.append(d)
6449 renamed.append(d)
6445 else:
6450 else:
6446 copied.append(d)
6451 copied.append(d)
6447 if d in status.added:
6452 if d in status.added:
6448 status.added.remove(d)
6453 status.added.remove(d)
6449
6454
6450 try:
6455 try:
6451 ms = mergemod.mergestate.read(repo)
6456 ms = mergemod.mergestate.read(repo)
6452 except error.UnsupportedMergeRecords as e:
6457 except error.UnsupportedMergeRecords as e:
6453 s = ' '.join(e.recordtypes)
6458 s = ' '.join(e.recordtypes)
6454 ui.warn(
6459 ui.warn(
6455 _('warning: merge state has unsupported record types: %s\n') % s)
6460 _('warning: merge state has unsupported record types: %s\n') % s)
6456 unresolved = 0
6461 unresolved = 0
6457 else:
6462 else:
6458 unresolved = [f for f in ms if ms[f] == 'u']
6463 unresolved = [f for f in ms if ms[f] == 'u']
6459
6464
6460 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6465 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6461
6466
6462 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6467 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6463 (ui.label(_('%d added'), 'status.added'), status.added),
6468 (ui.label(_('%d added'), 'status.added'), status.added),
6464 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6469 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6465 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6470 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6466 (ui.label(_('%d copied'), 'status.copied'), copied),
6471 (ui.label(_('%d copied'), 'status.copied'), copied),
6467 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6472 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6468 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6473 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6469 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6474 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6470 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6475 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6471 t = []
6476 t = []
6472 for l, s in labels:
6477 for l, s in labels:
6473 if s:
6478 if s:
6474 t.append(l % len(s))
6479 t.append(l % len(s))
6475
6480
6476 t = ', '.join(t)
6481 t = ', '.join(t)
6477 cleanworkdir = False
6482 cleanworkdir = False
6478
6483
6479 if repo.vfs.exists('graftstate'):
6484 if repo.vfs.exists('graftstate'):
6480 t += _(' (graft in progress)')
6485 t += _(' (graft in progress)')
6481 if repo.vfs.exists('updatestate'):
6486 if repo.vfs.exists('updatestate'):
6482 t += _(' (interrupted update)')
6487 t += _(' (interrupted update)')
6483 elif len(parents) > 1:
6488 elif len(parents) > 1:
6484 t += _(' (merge)')
6489 t += _(' (merge)')
6485 elif branch != parents[0].branch():
6490 elif branch != parents[0].branch():
6486 t += _(' (new branch)')
6491 t += _(' (new branch)')
6487 elif (parents[0].closesbranch() and
6492 elif (parents[0].closesbranch() and
6488 pnode in repo.branchheads(branch, closed=True)):
6493 pnode in repo.branchheads(branch, closed=True)):
6489 t += _(' (head closed)')
6494 t += _(' (head closed)')
6490 elif not (status.modified or status.added or status.removed or renamed or
6495 elif not (status.modified or status.added or status.removed or renamed or
6491 copied or subs):
6496 copied or subs):
6492 t += _(' (clean)')
6497 t += _(' (clean)')
6493 cleanworkdir = True
6498 cleanworkdir = True
6494 elif pnode not in bheads:
6499 elif pnode not in bheads:
6495 t += _(' (new branch head)')
6500 t += _(' (new branch head)')
6496
6501
6497 if parents:
6502 if parents:
6498 pendingphase = max(p.phase() for p in parents)
6503 pendingphase = max(p.phase() for p in parents)
6499 else:
6504 else:
6500 pendingphase = phases.public
6505 pendingphase = phases.public
6501
6506
6502 if pendingphase > phases.newcommitphase(ui):
6507 if pendingphase > phases.newcommitphase(ui):
6503 t += ' (%s)' % phases.phasenames[pendingphase]
6508 t += ' (%s)' % phases.phasenames[pendingphase]
6504
6509
6505 if cleanworkdir:
6510 if cleanworkdir:
6506 # i18n: column positioning for "hg summary"
6511 # i18n: column positioning for "hg summary"
6507 ui.status(_('commit: %s\n') % t.strip())
6512 ui.status(_('commit: %s\n') % t.strip())
6508 else:
6513 else:
6509 # i18n: column positioning for "hg summary"
6514 # i18n: column positioning for "hg summary"
6510 ui.write(_('commit: %s\n') % t.strip())
6515 ui.write(_('commit: %s\n') % t.strip())
6511
6516
6512 # all ancestors of branch heads - all ancestors of parent = new csets
6517 # all ancestors of branch heads - all ancestors of parent = new csets
6513 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6518 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6514 bheads))
6519 bheads))
6515
6520
6516 if new == 0:
6521 if new == 0:
6517 # i18n: column positioning for "hg summary"
6522 # i18n: column positioning for "hg summary"
6518 ui.status(_('update: (current)\n'))
6523 ui.status(_('update: (current)\n'))
6519 elif pnode not in bheads:
6524 elif pnode not in bheads:
6520 # i18n: column positioning for "hg summary"
6525 # i18n: column positioning for "hg summary"
6521 ui.write(_('update: %d new changesets (update)\n') % new)
6526 ui.write(_('update: %d new changesets (update)\n') % new)
6522 else:
6527 else:
6523 # i18n: column positioning for "hg summary"
6528 # i18n: column positioning for "hg summary"
6524 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6529 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6525 (new, len(bheads)))
6530 (new, len(bheads)))
6526
6531
6527 t = []
6532 t = []
6528 draft = len(repo.revs('draft()'))
6533 draft = len(repo.revs('draft()'))
6529 if draft:
6534 if draft:
6530 t.append(_('%d draft') % draft)
6535 t.append(_('%d draft') % draft)
6531 secret = len(repo.revs('secret()'))
6536 secret = len(repo.revs('secret()'))
6532 if secret:
6537 if secret:
6533 t.append(_('%d secret') % secret)
6538 t.append(_('%d secret') % secret)
6534
6539
6535 if draft or secret:
6540 if draft or secret:
6536 ui.status(_('phases: %s\n') % ', '.join(t))
6541 ui.status(_('phases: %s\n') % ', '.join(t))
6537
6542
6538 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6543 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6539 for trouble in ("unstable", "divergent", "bumped"):
6544 for trouble in ("unstable", "divergent", "bumped"):
6540 numtrouble = len(repo.revs(trouble + "()"))
6545 numtrouble = len(repo.revs(trouble + "()"))
6541 # We write all the possibilities to ease translation
6546 # We write all the possibilities to ease translation
6542 troublemsg = {
6547 troublemsg = {
6543 "unstable": _("unstable: %d changesets"),
6548 "unstable": _("unstable: %d changesets"),
6544 "divergent": _("divergent: %d changesets"),
6549 "divergent": _("divergent: %d changesets"),
6545 "bumped": _("bumped: %d changesets"),
6550 "bumped": _("bumped: %d changesets"),
6546 }
6551 }
6547 if numtrouble > 0:
6552 if numtrouble > 0:
6548 ui.status(troublemsg[trouble] % numtrouble + "\n")
6553 ui.status(troublemsg[trouble] % numtrouble + "\n")
6549
6554
6550 cmdutil.summaryhooks(ui, repo)
6555 cmdutil.summaryhooks(ui, repo)
6551
6556
6552 if opts.get('remote'):
6557 if opts.get('remote'):
6553 needsincoming, needsoutgoing = True, True
6558 needsincoming, needsoutgoing = True, True
6554 else:
6559 else:
6555 needsincoming, needsoutgoing = False, False
6560 needsincoming, needsoutgoing = False, False
6556 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6561 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6557 if i:
6562 if i:
6558 needsincoming = True
6563 needsincoming = True
6559 if o:
6564 if o:
6560 needsoutgoing = True
6565 needsoutgoing = True
6561 if not needsincoming and not needsoutgoing:
6566 if not needsincoming and not needsoutgoing:
6562 return
6567 return
6563
6568
6564 def getincoming():
6569 def getincoming():
6565 source, branches = hg.parseurl(ui.expandpath('default'))
6570 source, branches = hg.parseurl(ui.expandpath('default'))
6566 sbranch = branches[0]
6571 sbranch = branches[0]
6567 try:
6572 try:
6568 other = hg.peer(repo, {}, source)
6573 other = hg.peer(repo, {}, source)
6569 except error.RepoError:
6574 except error.RepoError:
6570 if opts.get('remote'):
6575 if opts.get('remote'):
6571 raise
6576 raise
6572 return source, sbranch, None, None, None
6577 return source, sbranch, None, None, None
6573 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6578 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6574 if revs:
6579 if revs:
6575 revs = [other.lookup(rev) for rev in revs]
6580 revs = [other.lookup(rev) for rev in revs]
6576 ui.debug('comparing with %s\n' % util.hidepassword(source))
6581 ui.debug('comparing with %s\n' % util.hidepassword(source))
6577 repo.ui.pushbuffer()
6582 repo.ui.pushbuffer()
6578 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6583 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6579 repo.ui.popbuffer()
6584 repo.ui.popbuffer()
6580 return source, sbranch, other, commoninc, commoninc[1]
6585 return source, sbranch, other, commoninc, commoninc[1]
6581
6586
6582 if needsincoming:
6587 if needsincoming:
6583 source, sbranch, sother, commoninc, incoming = getincoming()
6588 source, sbranch, sother, commoninc, incoming = getincoming()
6584 else:
6589 else:
6585 source = sbranch = sother = commoninc = incoming = None
6590 source = sbranch = sother = commoninc = incoming = None
6586
6591
6587 def getoutgoing():
6592 def getoutgoing():
6588 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6593 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6589 dbranch = branches[0]
6594 dbranch = branches[0]
6590 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6595 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6591 if source != dest:
6596 if source != dest:
6592 try:
6597 try:
6593 dother = hg.peer(repo, {}, dest)
6598 dother = hg.peer(repo, {}, dest)
6594 except error.RepoError:
6599 except error.RepoError:
6595 if opts.get('remote'):
6600 if opts.get('remote'):
6596 raise
6601 raise
6597 return dest, dbranch, None, None
6602 return dest, dbranch, None, None
6598 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6603 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6599 elif sother is None:
6604 elif sother is None:
6600 # there is no explicit destination peer, but source one is invalid
6605 # there is no explicit destination peer, but source one is invalid
6601 return dest, dbranch, None, None
6606 return dest, dbranch, None, None
6602 else:
6607 else:
6603 dother = sother
6608 dother = sother
6604 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6609 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6605 common = None
6610 common = None
6606 else:
6611 else:
6607 common = commoninc
6612 common = commoninc
6608 if revs:
6613 if revs:
6609 revs = [repo.lookup(rev) for rev in revs]
6614 revs = [repo.lookup(rev) for rev in revs]
6610 repo.ui.pushbuffer()
6615 repo.ui.pushbuffer()
6611 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6616 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6612 commoninc=common)
6617 commoninc=common)
6613 repo.ui.popbuffer()
6618 repo.ui.popbuffer()
6614 return dest, dbranch, dother, outgoing
6619 return dest, dbranch, dother, outgoing
6615
6620
6616 if needsoutgoing:
6621 if needsoutgoing:
6617 dest, dbranch, dother, outgoing = getoutgoing()
6622 dest, dbranch, dother, outgoing = getoutgoing()
6618 else:
6623 else:
6619 dest = dbranch = dother = outgoing = None
6624 dest = dbranch = dother = outgoing = None
6620
6625
6621 if opts.get('remote'):
6626 if opts.get('remote'):
6622 t = []
6627 t = []
6623 if incoming:
6628 if incoming:
6624 t.append(_('1 or more incoming'))
6629 t.append(_('1 or more incoming'))
6625 o = outgoing.missing
6630 o = outgoing.missing
6626 if o:
6631 if o:
6627 t.append(_('%d outgoing') % len(o))
6632 t.append(_('%d outgoing') % len(o))
6628 other = dother or sother
6633 other = dother or sother
6629 if 'bookmarks' in other.listkeys('namespaces'):
6634 if 'bookmarks' in other.listkeys('namespaces'):
6630 counts = bookmarks.summary(repo, other)
6635 counts = bookmarks.summary(repo, other)
6631 if counts[0] > 0:
6636 if counts[0] > 0:
6632 t.append(_('%d incoming bookmarks') % counts[0])
6637 t.append(_('%d incoming bookmarks') % counts[0])
6633 if counts[1] > 0:
6638 if counts[1] > 0:
6634 t.append(_('%d outgoing bookmarks') % counts[1])
6639 t.append(_('%d outgoing bookmarks') % counts[1])
6635
6640
6636 if t:
6641 if t:
6637 # i18n: column positioning for "hg summary"
6642 # i18n: column positioning for "hg summary"
6638 ui.write(_('remote: %s\n') % (', '.join(t)))
6643 ui.write(_('remote: %s\n') % (', '.join(t)))
6639 else:
6644 else:
6640 # i18n: column positioning for "hg summary"
6645 # i18n: column positioning for "hg summary"
6641 ui.status(_('remote: (synced)\n'))
6646 ui.status(_('remote: (synced)\n'))
6642
6647
6643 cmdutil.summaryremotehooks(ui, repo, opts,
6648 cmdutil.summaryremotehooks(ui, repo, opts,
6644 ((source, sbranch, sother, commoninc),
6649 ((source, sbranch, sother, commoninc),
6645 (dest, dbranch, dother, outgoing)))
6650 (dest, dbranch, dother, outgoing)))
6646
6651
6647 @command('tag',
6652 @command('tag',
6648 [('f', 'force', None, _('force tag')),
6653 [('f', 'force', None, _('force tag')),
6649 ('l', 'local', None, _('make the tag local')),
6654 ('l', 'local', None, _('make the tag local')),
6650 ('r', 'rev', '', _('revision to tag'), _('REV')),
6655 ('r', 'rev', '', _('revision to tag'), _('REV')),
6651 ('', 'remove', None, _('remove a tag')),
6656 ('', 'remove', None, _('remove a tag')),
6652 # -l/--local is already there, commitopts cannot be used
6657 # -l/--local is already there, commitopts cannot be used
6653 ('e', 'edit', None, _('invoke editor on commit messages')),
6658 ('e', 'edit', None, _('invoke editor on commit messages')),
6654 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6659 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6655 ] + commitopts2,
6660 ] + commitopts2,
6656 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6661 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6657 def tag(ui, repo, name1, *names, **opts):
6662 def tag(ui, repo, name1, *names, **opts):
6658 """add one or more tags for the current or given revision
6663 """add one or more tags for the current or given revision
6659
6664
6660 Name a particular revision using <name>.
6665 Name a particular revision using <name>.
6661
6666
6662 Tags are used to name particular revisions of the repository and are
6667 Tags are used to name particular revisions of the repository and are
6663 very useful to compare different revisions, to go back to significant
6668 very useful to compare different revisions, to go back to significant
6664 earlier versions or to mark branch points as releases, etc. Changing
6669 earlier versions or to mark branch points as releases, etc. Changing
6665 an existing tag is normally disallowed; use -f/--force to override.
6670 an existing tag is normally disallowed; use -f/--force to override.
6666
6671
6667 If no revision is given, the parent of the working directory is
6672 If no revision is given, the parent of the working directory is
6668 used.
6673 used.
6669
6674
6670 To facilitate version control, distribution, and merging of tags,
6675 To facilitate version control, distribution, and merging of tags,
6671 they are stored as a file named ".hgtags" which is managed similarly
6676 they are stored as a file named ".hgtags" which is managed similarly
6672 to other project files and can be hand-edited if necessary. This
6677 to other project files and can be hand-edited if necessary. This
6673 also means that tagging creates a new commit. The file
6678 also means that tagging creates a new commit. The file
6674 ".hg/localtags" is used for local tags (not shared among
6679 ".hg/localtags" is used for local tags (not shared among
6675 repositories).
6680 repositories).
6676
6681
6677 Tag commits are usually made at the head of a branch. If the parent
6682 Tag commits are usually made at the head of a branch. If the parent
6678 of the working directory is not a branch head, :hg:`tag` aborts; use
6683 of the working directory is not a branch head, :hg:`tag` aborts; use
6679 -f/--force to force the tag commit to be based on a non-head
6684 -f/--force to force the tag commit to be based on a non-head
6680 changeset.
6685 changeset.
6681
6686
6682 See :hg:`help dates` for a list of formats valid for -d/--date.
6687 See :hg:`help dates` for a list of formats valid for -d/--date.
6683
6688
6684 Since tag names have priority over branch names during revision
6689 Since tag names have priority over branch names during revision
6685 lookup, using an existing branch name as a tag name is discouraged.
6690 lookup, using an existing branch name as a tag name is discouraged.
6686
6691
6687 Returns 0 on success.
6692 Returns 0 on success.
6688 """
6693 """
6689 wlock = lock = None
6694 wlock = lock = None
6690 try:
6695 try:
6691 wlock = repo.wlock()
6696 wlock = repo.wlock()
6692 lock = repo.lock()
6697 lock = repo.lock()
6693 rev_ = "."
6698 rev_ = "."
6694 names = [t.strip() for t in (name1,) + names]
6699 names = [t.strip() for t in (name1,) + names]
6695 if len(names) != len(set(names)):
6700 if len(names) != len(set(names)):
6696 raise error.Abort(_('tag names must be unique'))
6701 raise error.Abort(_('tag names must be unique'))
6697 for n in names:
6702 for n in names:
6698 scmutil.checknewlabel(repo, n, 'tag')
6703 scmutil.checknewlabel(repo, n, 'tag')
6699 if not n:
6704 if not n:
6700 raise error.Abort(_('tag names cannot consist entirely of '
6705 raise error.Abort(_('tag names cannot consist entirely of '
6701 'whitespace'))
6706 'whitespace'))
6702 if opts.get('rev') and opts.get('remove'):
6707 if opts.get('rev') and opts.get('remove'):
6703 raise error.Abort(_("--rev and --remove are incompatible"))
6708 raise error.Abort(_("--rev and --remove are incompatible"))
6704 if opts.get('rev'):
6709 if opts.get('rev'):
6705 rev_ = opts['rev']
6710 rev_ = opts['rev']
6706 message = opts.get('message')
6711 message = opts.get('message')
6707 if opts.get('remove'):
6712 if opts.get('remove'):
6708 if opts.get('local'):
6713 if opts.get('local'):
6709 expectedtype = 'local'
6714 expectedtype = 'local'
6710 else:
6715 else:
6711 expectedtype = 'global'
6716 expectedtype = 'global'
6712
6717
6713 for n in names:
6718 for n in names:
6714 if not repo.tagtype(n):
6719 if not repo.tagtype(n):
6715 raise error.Abort(_("tag '%s' does not exist") % n)
6720 raise error.Abort(_("tag '%s' does not exist") % n)
6716 if repo.tagtype(n) != expectedtype:
6721 if repo.tagtype(n) != expectedtype:
6717 if expectedtype == 'global':
6722 if expectedtype == 'global':
6718 raise error.Abort(_("tag '%s' is not a global tag") % n)
6723 raise error.Abort(_("tag '%s' is not a global tag") % n)
6719 else:
6724 else:
6720 raise error.Abort(_("tag '%s' is not a local tag") % n)
6725 raise error.Abort(_("tag '%s' is not a local tag") % n)
6721 rev_ = 'null'
6726 rev_ = 'null'
6722 if not message:
6727 if not message:
6723 # we don't translate commit messages
6728 # we don't translate commit messages
6724 message = 'Removed tag %s' % ', '.join(names)
6729 message = 'Removed tag %s' % ', '.join(names)
6725 elif not opts.get('force'):
6730 elif not opts.get('force'):
6726 for n in names:
6731 for n in names:
6727 if n in repo.tags():
6732 if n in repo.tags():
6728 raise error.Abort(_("tag '%s' already exists "
6733 raise error.Abort(_("tag '%s' already exists "
6729 "(use -f to force)") % n)
6734 "(use -f to force)") % n)
6730 if not opts.get('local'):
6735 if not opts.get('local'):
6731 p1, p2 = repo.dirstate.parents()
6736 p1, p2 = repo.dirstate.parents()
6732 if p2 != nullid:
6737 if p2 != nullid:
6733 raise error.Abort(_('uncommitted merge'))
6738 raise error.Abort(_('uncommitted merge'))
6734 bheads = repo.branchheads()
6739 bheads = repo.branchheads()
6735 if not opts.get('force') and bheads and p1 not in bheads:
6740 if not opts.get('force') and bheads and p1 not in bheads:
6736 raise error.Abort(_('not at a branch head (use -f to force)'))
6741 raise error.Abort(_('not at a branch head (use -f to force)'))
6737 r = scmutil.revsingle(repo, rev_).node()
6742 r = scmutil.revsingle(repo, rev_).node()
6738
6743
6739 if not message:
6744 if not message:
6740 # we don't translate commit messages
6745 # we don't translate commit messages
6741 message = ('Added tag %s for changeset %s' %
6746 message = ('Added tag %s for changeset %s' %
6742 (', '.join(names), short(r)))
6747 (', '.join(names), short(r)))
6743
6748
6744 date = opts.get('date')
6749 date = opts.get('date')
6745 if date:
6750 if date:
6746 date = util.parsedate(date)
6751 date = util.parsedate(date)
6747
6752
6748 if opts.get('remove'):
6753 if opts.get('remove'):
6749 editform = 'tag.remove'
6754 editform = 'tag.remove'
6750 else:
6755 else:
6751 editform = 'tag.add'
6756 editform = 'tag.add'
6752 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6757 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6753
6758
6754 # don't allow tagging the null rev
6759 # don't allow tagging the null rev
6755 if (not opts.get('remove') and
6760 if (not opts.get('remove') and
6756 scmutil.revsingle(repo, rev_).rev() == nullrev):
6761 scmutil.revsingle(repo, rev_).rev() == nullrev):
6757 raise error.Abort(_("cannot tag null revision"))
6762 raise error.Abort(_("cannot tag null revision"))
6758
6763
6759 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6764 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6760 editor=editor)
6765 editor=editor)
6761 finally:
6766 finally:
6762 release(lock, wlock)
6767 release(lock, wlock)
6763
6768
6764 @command('tags', formatteropts, '')
6769 @command('tags', formatteropts, '')
6765 def tags(ui, repo, **opts):
6770 def tags(ui, repo, **opts):
6766 """list repository tags
6771 """list repository tags
6767
6772
6768 This lists both regular and local tags. When the -v/--verbose
6773 This lists both regular and local tags. When the -v/--verbose
6769 switch is used, a third column "local" is printed for local tags.
6774 switch is used, a third column "local" is printed for local tags.
6770 When the -q/--quiet switch is used, only the tag name is printed.
6775 When the -q/--quiet switch is used, only the tag name is printed.
6771
6776
6772 Returns 0 on success.
6777 Returns 0 on success.
6773 """
6778 """
6774
6779
6775 fm = ui.formatter('tags', opts)
6780 fm = ui.formatter('tags', opts)
6776 hexfunc = fm.hexfunc
6781 hexfunc = fm.hexfunc
6777 tagtype = ""
6782 tagtype = ""
6778
6783
6779 for t, n in reversed(repo.tagslist()):
6784 for t, n in reversed(repo.tagslist()):
6780 hn = hexfunc(n)
6785 hn = hexfunc(n)
6781 label = 'tags.normal'
6786 label = 'tags.normal'
6782 tagtype = ''
6787 tagtype = ''
6783 if repo.tagtype(t) == 'local':
6788 if repo.tagtype(t) == 'local':
6784 label = 'tags.local'
6789 label = 'tags.local'
6785 tagtype = 'local'
6790 tagtype = 'local'
6786
6791
6787 fm.startitem()
6792 fm.startitem()
6788 fm.write('tag', '%s', t, label=label)
6793 fm.write('tag', '%s', t, label=label)
6789 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6794 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6790 fm.condwrite(not ui.quiet, 'rev node', fmt,
6795 fm.condwrite(not ui.quiet, 'rev node', fmt,
6791 repo.changelog.rev(n), hn, label=label)
6796 repo.changelog.rev(n), hn, label=label)
6792 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6797 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6793 tagtype, label=label)
6798 tagtype, label=label)
6794 fm.plain('\n')
6799 fm.plain('\n')
6795 fm.end()
6800 fm.end()
6796
6801
6797 @command('tip',
6802 @command('tip',
6798 [('p', 'patch', None, _('show patch')),
6803 [('p', 'patch', None, _('show patch')),
6799 ('g', 'git', None, _('use git extended diff format')),
6804 ('g', 'git', None, _('use git extended diff format')),
6800 ] + templateopts,
6805 ] + templateopts,
6801 _('[-p] [-g]'))
6806 _('[-p] [-g]'))
6802 def tip(ui, repo, **opts):
6807 def tip(ui, repo, **opts):
6803 """show the tip revision (DEPRECATED)
6808 """show the tip revision (DEPRECATED)
6804
6809
6805 The tip revision (usually just called the tip) is the changeset
6810 The tip revision (usually just called the tip) is the changeset
6806 most recently added to the repository (and therefore the most
6811 most recently added to the repository (and therefore the most
6807 recently changed head).
6812 recently changed head).
6808
6813
6809 If you have just made a commit, that commit will be the tip. If
6814 If you have just made a commit, that commit will be the tip. If
6810 you have just pulled changes from another repository, the tip of
6815 you have just pulled changes from another repository, the tip of
6811 that repository becomes the current tip. The "tip" tag is special
6816 that repository becomes the current tip. The "tip" tag is special
6812 and cannot be renamed or assigned to a different changeset.
6817 and cannot be renamed or assigned to a different changeset.
6813
6818
6814 This command is deprecated, please use :hg:`heads` instead.
6819 This command is deprecated, please use :hg:`heads` instead.
6815
6820
6816 Returns 0 on success.
6821 Returns 0 on success.
6817 """
6822 """
6818 displayer = cmdutil.show_changeset(ui, repo, opts)
6823 displayer = cmdutil.show_changeset(ui, repo, opts)
6819 displayer.show(repo['tip'])
6824 displayer.show(repo['tip'])
6820 displayer.close()
6825 displayer.close()
6821
6826
6822 @command('unbundle',
6827 @command('unbundle',
6823 [('u', 'update', None,
6828 [('u', 'update', None,
6824 _('update to new branch head if changesets were unbundled'))],
6829 _('update to new branch head if changesets were unbundled'))],
6825 _('[-u] FILE...'))
6830 _('[-u] FILE...'))
6826 def unbundle(ui, repo, fname1, *fnames, **opts):
6831 def unbundle(ui, repo, fname1, *fnames, **opts):
6827 """apply one or more changegroup files
6832 """apply one or more changegroup files
6828
6833
6829 Apply one or more compressed changegroup files generated by the
6834 Apply one or more compressed changegroup files generated by the
6830 bundle command.
6835 bundle command.
6831
6836
6832 Returns 0 on success, 1 if an update has unresolved files.
6837 Returns 0 on success, 1 if an update has unresolved files.
6833 """
6838 """
6834 fnames = (fname1,) + fnames
6839 fnames = (fname1,) + fnames
6835
6840
6836 lock = repo.lock()
6841 lock = repo.lock()
6837 try:
6842 try:
6838 for fname in fnames:
6843 for fname in fnames:
6839 f = hg.openpath(ui, fname)
6844 f = hg.openpath(ui, fname)
6840 gen = exchange.readbundle(ui, f, fname)
6845 gen = exchange.readbundle(ui, f, fname)
6841 if isinstance(gen, bundle2.unbundle20):
6846 if isinstance(gen, bundle2.unbundle20):
6842 tr = repo.transaction('unbundle')
6847 tr = repo.transaction('unbundle')
6843 try:
6848 try:
6844 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6849 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6845 url='bundle:' + fname)
6850 url='bundle:' + fname)
6846 tr.close()
6851 tr.close()
6847 except error.BundleUnknownFeatureError as exc:
6852 except error.BundleUnknownFeatureError as exc:
6848 raise error.Abort(_('%s: unknown bundle feature, %s')
6853 raise error.Abort(_('%s: unknown bundle feature, %s')
6849 % (fname, exc),
6854 % (fname, exc),
6850 hint=_("see https://mercurial-scm.org/"
6855 hint=_("see https://mercurial-scm.org/"
6851 "wiki/BundleFeature for more "
6856 "wiki/BundleFeature for more "
6852 "information"))
6857 "information"))
6853 finally:
6858 finally:
6854 if tr:
6859 if tr:
6855 tr.release()
6860 tr.release()
6856 changes = [r.get('return', 0)
6861 changes = [r.get('return', 0)
6857 for r in op.records['changegroup']]
6862 for r in op.records['changegroup']]
6858 modheads = changegroup.combineresults(changes)
6863 modheads = changegroup.combineresults(changes)
6859 elif isinstance(gen, streamclone.streamcloneapplier):
6864 elif isinstance(gen, streamclone.streamcloneapplier):
6860 raise error.Abort(
6865 raise error.Abort(
6861 _('packed bundles cannot be applied with '
6866 _('packed bundles cannot be applied with '
6862 '"hg unbundle"'),
6867 '"hg unbundle"'),
6863 hint=_('use "hg debugapplystreamclonebundle"'))
6868 hint=_('use "hg debugapplystreamclonebundle"'))
6864 else:
6869 else:
6865 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6870 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6866 finally:
6871 finally:
6867 lock.release()
6872 lock.release()
6868
6873
6869 return postincoming(ui, repo, modheads, opts.get('update'), None)
6874 return postincoming(ui, repo, modheads, opts.get('update'), None)
6870
6875
6871 @command('^update|up|checkout|co',
6876 @command('^update|up|checkout|co',
6872 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6877 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6873 ('c', 'check', None,
6878 ('c', 'check', None,
6874 _('update across branches if no uncommitted changes')),
6879 _('update across branches if no uncommitted changes')),
6875 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6880 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6876 ('r', 'rev', '', _('revision'), _('REV'))
6881 ('r', 'rev', '', _('revision'), _('REV'))
6877 ] + mergetoolopts,
6882 ] + mergetoolopts,
6878 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6883 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6879 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6884 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6880 tool=None):
6885 tool=None):
6881 """update working directory (or switch revisions)
6886 """update working directory (or switch revisions)
6882
6887
6883 Update the repository's working directory to the specified
6888 Update the repository's working directory to the specified
6884 changeset. If no changeset is specified, update to the tip of the
6889 changeset. If no changeset is specified, update to the tip of the
6885 current named branch and move the active bookmark (see :hg:`help
6890 current named branch and move the active bookmark (see :hg:`help
6886 bookmarks`).
6891 bookmarks`).
6887
6892
6888 Update sets the working directory's parent revision to the specified
6893 Update sets the working directory's parent revision to the specified
6889 changeset (see :hg:`help parents`).
6894 changeset (see :hg:`help parents`).
6890
6895
6891 If the changeset is not a descendant or ancestor of the working
6896 If the changeset is not a descendant or ancestor of the working
6892 directory's parent, the update is aborted. With the -c/--check
6897 directory's parent, the update is aborted. With the -c/--check
6893 option, the working directory is checked for uncommitted changes; if
6898 option, the working directory is checked for uncommitted changes; if
6894 none are found, the working directory is updated to the specified
6899 none are found, the working directory is updated to the specified
6895 changeset.
6900 changeset.
6896
6901
6897 .. container:: verbose
6902 .. container:: verbose
6898
6903
6899 The following rules apply when the working directory contains
6904 The following rules apply when the working directory contains
6900 uncommitted changes:
6905 uncommitted changes:
6901
6906
6902 1. If neither -c/--check nor -C/--clean is specified, and if
6907 1. If neither -c/--check nor -C/--clean is specified, and if
6903 the requested changeset is an ancestor or descendant of
6908 the requested changeset is an ancestor or descendant of
6904 the working directory's parent, the uncommitted changes
6909 the working directory's parent, the uncommitted changes
6905 are merged into the requested changeset and the merged
6910 are merged into the requested changeset and the merged
6906 result is left uncommitted. If the requested changeset is
6911 result is left uncommitted. If the requested changeset is
6907 not an ancestor or descendant (that is, it is on another
6912 not an ancestor or descendant (that is, it is on another
6908 branch), the update is aborted and the uncommitted changes
6913 branch), the update is aborted and the uncommitted changes
6909 are preserved.
6914 are preserved.
6910
6915
6911 2. With the -c/--check option, the update is aborted and the
6916 2. With the -c/--check option, the update is aborted and the
6912 uncommitted changes are preserved.
6917 uncommitted changes are preserved.
6913
6918
6914 3. With the -C/--clean option, uncommitted changes are discarded and
6919 3. With the -C/--clean option, uncommitted changes are discarded and
6915 the working directory is updated to the requested changeset.
6920 the working directory is updated to the requested changeset.
6916
6921
6917 To cancel an uncommitted merge (and lose your changes), use
6922 To cancel an uncommitted merge (and lose your changes), use
6918 :hg:`update --clean .`.
6923 :hg:`update --clean .`.
6919
6924
6920 Use null as the changeset to remove the working directory (like
6925 Use null as the changeset to remove the working directory (like
6921 :hg:`clone -U`).
6926 :hg:`clone -U`).
6922
6927
6923 If you want to revert just one file to an older revision, use
6928 If you want to revert just one file to an older revision, use
6924 :hg:`revert [-r REV] NAME`.
6929 :hg:`revert [-r REV] NAME`.
6925
6930
6926 See :hg:`help dates` for a list of formats valid for -d/--date.
6931 See :hg:`help dates` for a list of formats valid for -d/--date.
6927
6932
6928 Returns 0 on success, 1 if there are unresolved files.
6933 Returns 0 on success, 1 if there are unresolved files.
6929 """
6934 """
6930 movemarkfrom = None
6935 movemarkfrom = None
6931 if rev and node:
6936 if rev and node:
6932 raise error.Abort(_("please specify just one revision"))
6937 raise error.Abort(_("please specify just one revision"))
6933
6938
6934 if rev is None or rev == '':
6939 if rev is None or rev == '':
6935 rev = node
6940 rev = node
6936
6941
6937 wlock = repo.wlock()
6942 wlock = repo.wlock()
6938 try:
6943 try:
6939 cmdutil.clearunfinished(repo)
6944 cmdutil.clearunfinished(repo)
6940
6945
6941 if date:
6946 if date:
6942 if rev is not None:
6947 if rev is not None:
6943 raise error.Abort(_("you can't specify a revision and a date"))
6948 raise error.Abort(_("you can't specify a revision and a date"))
6944 rev = cmdutil.finddate(ui, repo, date)
6949 rev = cmdutil.finddate(ui, repo, date)
6945
6950
6946 # if we defined a bookmark, we have to remember the original name
6951 # if we defined a bookmark, we have to remember the original name
6947 brev = rev
6952 brev = rev
6948 rev = scmutil.revsingle(repo, rev, rev).rev()
6953 rev = scmutil.revsingle(repo, rev, rev).rev()
6949
6954
6950 if check and clean:
6955 if check and clean:
6951 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6956 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6952 )
6957 )
6953
6958
6954 if check:
6959 if check:
6955 cmdutil.bailifchanged(repo, merge=False)
6960 cmdutil.bailifchanged(repo, merge=False)
6956 if rev is None:
6961 if rev is None:
6957 updata = destutil.destupdate(repo, clean=clean, check=check)
6962 updata = destutil.destupdate(repo, clean=clean, check=check)
6958 rev, movemarkfrom, brev = updata
6963 rev, movemarkfrom, brev = updata
6959
6964
6960 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6965 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6961
6966
6962 if clean:
6967 if clean:
6963 ret = hg.clean(repo, rev)
6968 ret = hg.clean(repo, rev)
6964 else:
6969 else:
6965 ret = hg.update(repo, rev)
6970 ret = hg.update(repo, rev)
6966
6971
6967 if not ret and movemarkfrom:
6972 if not ret and movemarkfrom:
6968 if movemarkfrom == repo['.'].node():
6973 if movemarkfrom == repo['.'].node():
6969 pass # no-op update
6974 pass # no-op update
6970 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6975 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6971 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6976 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6972 else:
6977 else:
6973 # this can happen with a non-linear update
6978 # this can happen with a non-linear update
6974 ui.status(_("(leaving bookmark %s)\n") %
6979 ui.status(_("(leaving bookmark %s)\n") %
6975 repo._activebookmark)
6980 repo._activebookmark)
6976 bookmarks.deactivate(repo)
6981 bookmarks.deactivate(repo)
6977 elif brev in repo._bookmarks:
6982 elif brev in repo._bookmarks:
6978 bookmarks.activate(repo, brev)
6983 bookmarks.activate(repo, brev)
6979 ui.status(_("(activating bookmark %s)\n") % brev)
6984 ui.status(_("(activating bookmark %s)\n") % brev)
6980 elif brev:
6985 elif brev:
6981 if repo._activebookmark:
6986 if repo._activebookmark:
6982 ui.status(_("(leaving bookmark %s)\n") %
6987 ui.status(_("(leaving bookmark %s)\n") %
6983 repo._activebookmark)
6988 repo._activebookmark)
6984 bookmarks.deactivate(repo)
6989 bookmarks.deactivate(repo)
6985 finally:
6990 finally:
6986 wlock.release()
6991 wlock.release()
6987
6992
6988 return ret
6993 return ret
6989
6994
6990 @command('verify', [])
6995 @command('verify', [])
6991 def verify(ui, repo):
6996 def verify(ui, repo):
6992 """verify the integrity of the repository
6997 """verify the integrity of the repository
6993
6998
6994 Verify the integrity of the current repository.
6999 Verify the integrity of the current repository.
6995
7000
6996 This will perform an extensive check of the repository's
7001 This will perform an extensive check of the repository's
6997 integrity, validating the hashes and checksums of each entry in
7002 integrity, validating the hashes and checksums of each entry in
6998 the changelog, manifest, and tracked files, as well as the
7003 the changelog, manifest, and tracked files, as well as the
6999 integrity of their crosslinks and indices.
7004 integrity of their crosslinks and indices.
7000
7005
7001 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7006 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7002 for more information about recovery from corruption of the
7007 for more information about recovery from corruption of the
7003 repository.
7008 repository.
7004
7009
7005 Returns 0 on success, 1 if errors are encountered.
7010 Returns 0 on success, 1 if errors are encountered.
7006 """
7011 """
7007 return hg.verify(repo)
7012 return hg.verify(repo)
7008
7013
7009 @command('version', [], norepo=True)
7014 @command('version', [], norepo=True)
7010 def version_(ui):
7015 def version_(ui):
7011 """output version and copyright information"""
7016 """output version and copyright information"""
7012 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7017 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7013 % util.version())
7018 % util.version())
7014 ui.status(_(
7019 ui.status(_(
7015 "(see https://mercurial-scm.org for more information)\n"
7020 "(see https://mercurial-scm.org for more information)\n"
7016 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
7021 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
7017 "This is free software; see the source for copying conditions. "
7022 "This is free software; see the source for copying conditions. "
7018 "There is NO\nwarranty; "
7023 "There is NO\nwarranty; "
7019 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7024 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7020 ))
7025 ))
7021
7026
7022 ui.note(_("\nEnabled extensions:\n\n"))
7027 ui.note(_("\nEnabled extensions:\n\n"))
7023 if ui.verbose:
7028 if ui.verbose:
7024 # format names and versions into columns
7029 # format names and versions into columns
7025 names = []
7030 names = []
7026 vers = []
7031 vers = []
7027 for name, module in extensions.extensions():
7032 for name, module in extensions.extensions():
7028 names.append(name)
7033 names.append(name)
7029 vers.append(extensions.moduleversion(module))
7034 vers.append(extensions.moduleversion(module))
7030 if names:
7035 if names:
7031 maxnamelen = max(len(n) for n in names)
7036 maxnamelen = max(len(n) for n in names)
7032 for i, name in enumerate(names):
7037 for i, name in enumerate(names):
7033 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
7038 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,118 +1,128 b''
1 $ hg init a
1 $ hg init a
2 $ hg clone a b
2 $ hg clone a b
3 updating to branch default
3 updating to branch default
4 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
5 $ cd a
5 $ cd a
6
7 with no paths:
8
9 $ hg paths
10 $ hg paths unknown
11 not found!
12 [1]
13
14 with paths:
15
6 $ echo '[paths]' >> .hg/hgrc
16 $ echo '[paths]' >> .hg/hgrc
7 $ echo 'dupe = ../b#tip' >> .hg/hgrc
17 $ echo 'dupe = ../b#tip' >> .hg/hgrc
8 $ echo 'expand = $SOMETHING/bar' >> .hg/hgrc
18 $ echo 'expand = $SOMETHING/bar' >> .hg/hgrc
9 $ hg in dupe
19 $ hg in dupe
10 comparing with $TESTTMP/b (glob)
20 comparing with $TESTTMP/b (glob)
11 no changes found
21 no changes found
12 [1]
22 [1]
13 $ cd ..
23 $ cd ..
14 $ hg -R a in dupe
24 $ hg -R a in dupe
15 comparing with $TESTTMP/b (glob)
25 comparing with $TESTTMP/b (glob)
16 no changes found
26 no changes found
17 [1]
27 [1]
18 $ cd a
28 $ cd a
19 $ hg paths
29 $ hg paths
20 dupe = $TESTTMP/b#tip (glob)
30 dupe = $TESTTMP/b#tip (glob)
21 expand = $TESTTMP/a/$SOMETHING/bar (glob)
31 expand = $TESTTMP/a/$SOMETHING/bar (glob)
22 $ SOMETHING=foo hg paths
32 $ SOMETHING=foo hg paths
23 dupe = $TESTTMP/b#tip (glob)
33 dupe = $TESTTMP/b#tip (glob)
24 expand = $TESTTMP/a/foo/bar (glob)
34 expand = $TESTTMP/a/foo/bar (glob)
25 #if msys
35 #if msys
26 $ SOMETHING=//foo hg paths
36 $ SOMETHING=//foo hg paths
27 dupe = $TESTTMP/b#tip (glob)
37 dupe = $TESTTMP/b#tip (glob)
28 expand = /foo/bar
38 expand = /foo/bar
29 #else
39 #else
30 $ SOMETHING=/foo hg paths
40 $ SOMETHING=/foo hg paths
31 dupe = $TESTTMP/b#tip (glob)
41 dupe = $TESTTMP/b#tip (glob)
32 expand = /foo/bar
42 expand = /foo/bar
33 #endif
43 #endif
34 $ hg paths -q
44 $ hg paths -q
35 dupe
45 dupe
36 expand
46 expand
37 $ hg paths dupe
47 $ hg paths dupe
38 $TESTTMP/b#tip (glob)
48 $TESTTMP/b#tip (glob)
39 $ hg paths -q dupe
49 $ hg paths -q dupe
40 $ hg paths unknown
50 $ hg paths unknown
41 not found!
51 not found!
42 [1]
52 [1]
43 $ hg paths -q unknown
53 $ hg paths -q unknown
44 [1]
54 [1]
45 $ cd ..
55 $ cd ..
46
56
47 sub-options for an undeclared path are ignored
57 sub-options for an undeclared path are ignored
48
58
49 $ hg init suboptions
59 $ hg init suboptions
50 $ cd suboptions
60 $ cd suboptions
51
61
52 $ cat > .hg/hgrc << EOF
62 $ cat > .hg/hgrc << EOF
53 > [paths]
63 > [paths]
54 > path0 = https://example.com/path0
64 > path0 = https://example.com/path0
55 > path1:pushurl = https://example.com/path1
65 > path1:pushurl = https://example.com/path1
56 > EOF
66 > EOF
57 $ hg paths
67 $ hg paths
58 path0 = https://example.com/path0
68 path0 = https://example.com/path0
59
69
60 unknown sub-options aren't displayed
70 unknown sub-options aren't displayed
61
71
62 $ cat > .hg/hgrc << EOF
72 $ cat > .hg/hgrc << EOF
63 > [paths]
73 > [paths]
64 > path0 = https://example.com/path0
74 > path0 = https://example.com/path0
65 > path0:foo = https://example.com/path1
75 > path0:foo = https://example.com/path1
66 > EOF
76 > EOF
67
77
68 $ hg paths
78 $ hg paths
69 path0 = https://example.com/path0
79 path0 = https://example.com/path0
70
80
71 :pushurl must be a URL
81 :pushurl must be a URL
72
82
73 $ cat > .hg/hgrc << EOF
83 $ cat > .hg/hgrc << EOF
74 > [paths]
84 > [paths]
75 > default = /path/to/nothing
85 > default = /path/to/nothing
76 > default:pushurl = /not/a/url
86 > default:pushurl = /not/a/url
77 > EOF
87 > EOF
78
88
79 $ hg paths
89 $ hg paths
80 (paths.default:pushurl not a URL; ignoring)
90 (paths.default:pushurl not a URL; ignoring)
81 default = /path/to/nothing
91 default = /path/to/nothing
82
92
83 #fragment is not allowed in :pushurl
93 #fragment is not allowed in :pushurl
84
94
85 $ cat > .hg/hgrc << EOF
95 $ cat > .hg/hgrc << EOF
86 > [paths]
96 > [paths]
87 > default = https://example.com/repo
97 > default = https://example.com/repo
88 > invalid = https://example.com/repo
98 > invalid = https://example.com/repo
89 > invalid:pushurl = https://example.com/repo#branch
99 > invalid:pushurl = https://example.com/repo#branch
90 > EOF
100 > EOF
91
101
92 $ hg paths
102 $ hg paths
93 ("#fragment" in paths.invalid:pushurl not supported; ignoring)
103 ("#fragment" in paths.invalid:pushurl not supported; ignoring)
94 default = https://example.com/repo
104 default = https://example.com/repo
95 invalid = https://example.com/repo
105 invalid = https://example.com/repo
96 invalid:pushurl = https://example.com/repo
106 invalid:pushurl = https://example.com/repo
97
107
98 $ cd ..
108 $ cd ..
99
109
100 'file:' disables [paths] entries for clone destination
110 'file:' disables [paths] entries for clone destination
101
111
102 $ cat >> $HGRCPATH <<EOF
112 $ cat >> $HGRCPATH <<EOF
103 > [paths]
113 > [paths]
104 > gpath1 = http://hg.example.com
114 > gpath1 = http://hg.example.com
105 > EOF
115 > EOF
106
116
107 $ hg clone a gpath1
117 $ hg clone a gpath1
108 abort: cannot create new http repository
118 abort: cannot create new http repository
109 [255]
119 [255]
110
120
111 $ hg clone a file:gpath1
121 $ hg clone a file:gpath1
112 updating to branch default
122 updating to branch default
113 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
114 $ cd gpath1
124 $ cd gpath1
115 $ hg -q id
125 $ hg -q id
116 000000000000
126 000000000000
117
127
118 $ cd ..
128 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now