##// END OF EJS Templates
with: use context manager for wlock in copy
Bryan O'Sullivan -
r27805:bdaf4331 default
parent child Browse files
Show More
@@ -1,7044 +1,7041
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 with repo.wlock():
1200 with repo.wlock():
1201 if opts.get('clean'):
1201 if opts.get('clean'):
1202 label = repo[None].p1().branch()
1202 label = repo[None].p1().branch()
1203 repo.dirstate.setbranch(label)
1203 repo.dirstate.setbranch(label)
1204 ui.status(_('reset working directory to branch %s\n') % label)
1204 ui.status(_('reset working directory to branch %s\n') % label)
1205 elif label:
1205 elif label:
1206 if not opts.get('force') and label in repo.branchmap():
1206 if not opts.get('force') and label in repo.branchmap():
1207 if label not in [p.branch() for p in repo[None].parents()]:
1207 if label not in [p.branch() for p in repo[None].parents()]:
1208 raise error.Abort(_('a branch of the same name already'
1208 raise error.Abort(_('a branch of the same name already'
1209 ' exists'),
1209 ' exists'),
1210 # i18n: "it" refers to an existing branch
1210 # i18n: "it" refers to an existing branch
1211 hint=_("use 'hg update' to switch to it"))
1211 hint=_("use 'hg update' to switch to it"))
1212 scmutil.checknewlabel(repo, label, 'branch')
1212 scmutil.checknewlabel(repo, label, 'branch')
1213 repo.dirstate.setbranch(label)
1213 repo.dirstate.setbranch(label)
1214 ui.status(_('marked working directory as branch %s\n') % label)
1214 ui.status(_('marked working directory as branch %s\n') % label)
1215
1215
1216 # find any open named branches aside from default
1216 # find any open named branches aside from default
1217 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1217 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1218 if n != "default" and not c]
1218 if n != "default" and not c]
1219 if not others:
1219 if not others:
1220 ui.status(_('(branches are permanent and global, '
1220 ui.status(_('(branches are permanent and global, '
1221 'did you want a bookmark?)\n'))
1221 'did you want a bookmark?)\n'))
1222
1222
1223 @command('branches',
1223 @command('branches',
1224 [('a', 'active', False,
1224 [('a', 'active', False,
1225 _('show only branches that have unmerged heads (DEPRECATED)')),
1225 _('show only branches that have unmerged heads (DEPRECATED)')),
1226 ('c', 'closed', False, _('show normal and closed branches')),
1226 ('c', 'closed', False, _('show normal and closed branches')),
1227 ] + formatteropts,
1227 ] + formatteropts,
1228 _('[-ac]'))
1228 _('[-ac]'))
1229 def branches(ui, repo, active=False, closed=False, **opts):
1229 def branches(ui, repo, active=False, closed=False, **opts):
1230 """list repository named branches
1230 """list repository named branches
1231
1231
1232 List the repository's named branches, indicating which ones are
1232 List the repository's named branches, indicating which ones are
1233 inactive. If -c/--closed is specified, also list branches which have
1233 inactive. If -c/--closed is specified, also list branches which have
1234 been marked closed (see :hg:`commit --close-branch`).
1234 been marked closed (see :hg:`commit --close-branch`).
1235
1235
1236 Use the command :hg:`update` to switch to an existing branch.
1236 Use the command :hg:`update` to switch to an existing branch.
1237
1237
1238 Returns 0.
1238 Returns 0.
1239 """
1239 """
1240
1240
1241 fm = ui.formatter('branches', opts)
1241 fm = ui.formatter('branches', opts)
1242 hexfunc = fm.hexfunc
1242 hexfunc = fm.hexfunc
1243
1243
1244 allheads = set(repo.heads())
1244 allheads = set(repo.heads())
1245 branches = []
1245 branches = []
1246 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1246 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1247 isactive = not isclosed and bool(set(heads) & allheads)
1247 isactive = not isclosed and bool(set(heads) & allheads)
1248 branches.append((tag, repo[tip], isactive, not isclosed))
1248 branches.append((tag, repo[tip], isactive, not isclosed))
1249 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1249 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1250 reverse=True)
1250 reverse=True)
1251
1251
1252 for tag, ctx, isactive, isopen in branches:
1252 for tag, ctx, isactive, isopen in branches:
1253 if active and not isactive:
1253 if active and not isactive:
1254 continue
1254 continue
1255 if isactive:
1255 if isactive:
1256 label = 'branches.active'
1256 label = 'branches.active'
1257 notice = ''
1257 notice = ''
1258 elif not isopen:
1258 elif not isopen:
1259 if not closed:
1259 if not closed:
1260 continue
1260 continue
1261 label = 'branches.closed'
1261 label = 'branches.closed'
1262 notice = _(' (closed)')
1262 notice = _(' (closed)')
1263 else:
1263 else:
1264 label = 'branches.inactive'
1264 label = 'branches.inactive'
1265 notice = _(' (inactive)')
1265 notice = _(' (inactive)')
1266 current = (tag == repo.dirstate.branch())
1266 current = (tag == repo.dirstate.branch())
1267 if current:
1267 if current:
1268 label = 'branches.current'
1268 label = 'branches.current'
1269
1269
1270 fm.startitem()
1270 fm.startitem()
1271 fm.write('branch', '%s', tag, label=label)
1271 fm.write('branch', '%s', tag, label=label)
1272 rev = ctx.rev()
1272 rev = ctx.rev()
1273 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1273 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1274 fmt = ' ' * padsize + ' %d:%s'
1274 fmt = ' ' * padsize + ' %d:%s'
1275 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1275 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1276 label='log.changeset changeset.%s' % ctx.phasestr())
1276 label='log.changeset changeset.%s' % ctx.phasestr())
1277 fm.data(active=isactive, closed=not isopen, current=current)
1277 fm.data(active=isactive, closed=not isopen, current=current)
1278 if not ui.quiet:
1278 if not ui.quiet:
1279 fm.plain(notice)
1279 fm.plain(notice)
1280 fm.plain('\n')
1280 fm.plain('\n')
1281 fm.end()
1281 fm.end()
1282
1282
1283 @command('bundle',
1283 @command('bundle',
1284 [('f', 'force', None, _('run even when the destination is unrelated')),
1284 [('f', 'force', None, _('run even when the destination is unrelated')),
1285 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1285 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1286 _('REV')),
1286 _('REV')),
1287 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1287 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1288 _('BRANCH')),
1288 _('BRANCH')),
1289 ('', 'base', [],
1289 ('', 'base', [],
1290 _('a base changeset assumed to be available at the destination'),
1290 _('a base changeset assumed to be available at the destination'),
1291 _('REV')),
1291 _('REV')),
1292 ('a', 'all', None, _('bundle all changesets in the repository')),
1292 ('a', 'all', None, _('bundle all changesets in the repository')),
1293 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1293 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1294 ] + remoteopts,
1294 ] + remoteopts,
1295 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1295 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1296 def bundle(ui, repo, fname, dest=None, **opts):
1296 def bundle(ui, repo, fname, dest=None, **opts):
1297 """create a changegroup file
1297 """create a changegroup file
1298
1298
1299 Generate a changegroup file collecting changesets to be added
1299 Generate a changegroup file collecting changesets to be added
1300 to a repository.
1300 to a repository.
1301
1301
1302 To create a bundle containing all changesets, use -a/--all
1302 To create a bundle containing all changesets, use -a/--all
1303 (or --base null). Otherwise, hg assumes the destination will have
1303 (or --base null). Otherwise, hg assumes the destination will have
1304 all the nodes you specify with --base parameters. Otherwise, hg
1304 all the nodes you specify with --base parameters. Otherwise, hg
1305 will assume the repository has all the nodes in destination, or
1305 will assume the repository has all the nodes in destination, or
1306 default-push/default if no destination is specified.
1306 default-push/default if no destination is specified.
1307
1307
1308 You can change bundle format with the -t/--type option. You can
1308 You can change bundle format with the -t/--type option. You can
1309 specify a compression, a bundle version or both using a dash
1309 specify a compression, a bundle version or both using a dash
1310 (comp-version). The available compression methods are: none, bzip2,
1310 (comp-version). The available compression methods are: none, bzip2,
1311 and gzip (by default, bundles are compressed using bzip2). The
1311 and gzip (by default, bundles are compressed using bzip2). The
1312 available formats are: v1, v2 (default to most suitable).
1312 available formats are: v1, v2 (default to most suitable).
1313
1313
1314 The bundle file can then be transferred using conventional means
1314 The bundle file can then be transferred using conventional means
1315 and applied to another repository with the unbundle or pull
1315 and applied to another repository with the unbundle or pull
1316 command. This is useful when direct push and pull are not
1316 command. This is useful when direct push and pull are not
1317 available or when exporting an entire repository is undesirable.
1317 available or when exporting an entire repository is undesirable.
1318
1318
1319 Applying bundles preserves all changeset contents including
1319 Applying bundles preserves all changeset contents including
1320 permissions, copy/rename information, and revision history.
1320 permissions, copy/rename information, and revision history.
1321
1321
1322 Returns 0 on success, 1 if no changes found.
1322 Returns 0 on success, 1 if no changes found.
1323 """
1323 """
1324 revs = None
1324 revs = None
1325 if 'rev' in opts:
1325 if 'rev' in opts:
1326 revs = scmutil.revrange(repo, opts['rev'])
1326 revs = scmutil.revrange(repo, opts['rev'])
1327
1327
1328 bundletype = opts.get('type', 'bzip2').lower()
1328 bundletype = opts.get('type', 'bzip2').lower()
1329 try:
1329 try:
1330 bcompression, cgversion, params = exchange.parsebundlespec(
1330 bcompression, cgversion, params = exchange.parsebundlespec(
1331 repo, bundletype, strict=False)
1331 repo, bundletype, strict=False)
1332 except error.UnsupportedBundleSpecification as e:
1332 except error.UnsupportedBundleSpecification as e:
1333 raise error.Abort(str(e),
1333 raise error.Abort(str(e),
1334 hint=_('see "hg help bundle" for supported '
1334 hint=_('see "hg help bundle" for supported '
1335 'values for --type'))
1335 'values for --type'))
1336
1336
1337 # Packed bundles are a pseudo bundle format for now.
1337 # Packed bundles are a pseudo bundle format for now.
1338 if cgversion == 's1':
1338 if cgversion == 's1':
1339 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1339 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1340 hint=_('use "hg debugcreatestreamclonebundle"'))
1340 hint=_('use "hg debugcreatestreamclonebundle"'))
1341
1341
1342 if opts.get('all'):
1342 if opts.get('all'):
1343 if dest:
1343 if dest:
1344 raise error.Abort(_("--all is incompatible with specifying "
1344 raise error.Abort(_("--all is incompatible with specifying "
1345 "a destination"))
1345 "a destination"))
1346 if opts.get('base'):
1346 if opts.get('base'):
1347 ui.warn(_("ignoring --base because --all was specified\n"))
1347 ui.warn(_("ignoring --base because --all was specified\n"))
1348 base = ['null']
1348 base = ['null']
1349 else:
1349 else:
1350 base = scmutil.revrange(repo, opts.get('base'))
1350 base = scmutil.revrange(repo, opts.get('base'))
1351 # TODO: get desired bundlecaps from command line.
1351 # TODO: get desired bundlecaps from command line.
1352 bundlecaps = None
1352 bundlecaps = None
1353 if base:
1353 if base:
1354 if dest:
1354 if dest:
1355 raise error.Abort(_("--base is incompatible with specifying "
1355 raise error.Abort(_("--base is incompatible with specifying "
1356 "a destination"))
1356 "a destination"))
1357 common = [repo.lookup(rev) for rev in base]
1357 common = [repo.lookup(rev) for rev in base]
1358 heads = revs and map(repo.lookup, revs) or revs
1358 heads = revs and map(repo.lookup, revs) or revs
1359 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1359 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1360 common=common, bundlecaps=bundlecaps,
1360 common=common, bundlecaps=bundlecaps,
1361 version=cgversion)
1361 version=cgversion)
1362 outgoing = None
1362 outgoing = None
1363 else:
1363 else:
1364 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1364 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1365 dest, branches = hg.parseurl(dest, opts.get('branch'))
1365 dest, branches = hg.parseurl(dest, opts.get('branch'))
1366 other = hg.peer(repo, opts, dest)
1366 other = hg.peer(repo, opts, dest)
1367 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1367 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1368 heads = revs and map(repo.lookup, revs) or revs
1368 heads = revs and map(repo.lookup, revs) or revs
1369 outgoing = discovery.findcommonoutgoing(repo, other,
1369 outgoing = discovery.findcommonoutgoing(repo, other,
1370 onlyheads=heads,
1370 onlyheads=heads,
1371 force=opts.get('force'),
1371 force=opts.get('force'),
1372 portable=True)
1372 portable=True)
1373 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1373 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1374 bundlecaps, version=cgversion)
1374 bundlecaps, version=cgversion)
1375 if not cg:
1375 if not cg:
1376 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1376 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1377 return 1
1377 return 1
1378
1378
1379 if cgversion == '01': #bundle1
1379 if cgversion == '01': #bundle1
1380 if bcompression is None:
1380 if bcompression is None:
1381 bcompression = 'UN'
1381 bcompression = 'UN'
1382 bversion = 'HG10' + bcompression
1382 bversion = 'HG10' + bcompression
1383 bcompression = None
1383 bcompression = None
1384 else:
1384 else:
1385 assert cgversion == '02'
1385 assert cgversion == '02'
1386 bversion = 'HG20'
1386 bversion = 'HG20'
1387
1387
1388
1388
1389 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1389 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1390
1390
1391 @command('cat',
1391 @command('cat',
1392 [('o', 'output', '',
1392 [('o', 'output', '',
1393 _('print output to file with formatted name'), _('FORMAT')),
1393 _('print output to file with formatted name'), _('FORMAT')),
1394 ('r', 'rev', '', _('print the given revision'), _('REV')),
1394 ('r', 'rev', '', _('print the given revision'), _('REV')),
1395 ('', 'decode', None, _('apply any matching decode filter')),
1395 ('', 'decode', None, _('apply any matching decode filter')),
1396 ] + walkopts,
1396 ] + walkopts,
1397 _('[OPTION]... FILE...'),
1397 _('[OPTION]... FILE...'),
1398 inferrepo=True)
1398 inferrepo=True)
1399 def cat(ui, repo, file1, *pats, **opts):
1399 def cat(ui, repo, file1, *pats, **opts):
1400 """output the current or given revision of files
1400 """output the current or given revision of files
1401
1401
1402 Print the specified files as they were at the given revision. If
1402 Print the specified files as they were at the given revision. If
1403 no revision is given, the parent of the working directory is used.
1403 no revision is given, the parent of the working directory is used.
1404
1404
1405 Output may be to a file, in which case the name of the file is
1405 Output may be to a file, in which case the name of the file is
1406 given using a format string. The formatting rules as follows:
1406 given using a format string. The formatting rules as follows:
1407
1407
1408 :``%%``: literal "%" character
1408 :``%%``: literal "%" character
1409 :``%s``: basename of file being printed
1409 :``%s``: basename of file being printed
1410 :``%d``: dirname of file being printed, or '.' if in repository root
1410 :``%d``: dirname of file being printed, or '.' if in repository root
1411 :``%p``: root-relative path name of file being printed
1411 :``%p``: root-relative path name of file being printed
1412 :``%H``: changeset hash (40 hexadecimal digits)
1412 :``%H``: changeset hash (40 hexadecimal digits)
1413 :``%R``: changeset revision number
1413 :``%R``: changeset revision number
1414 :``%h``: short-form changeset hash (12 hexadecimal digits)
1414 :``%h``: short-form changeset hash (12 hexadecimal digits)
1415 :``%r``: zero-padded changeset revision number
1415 :``%r``: zero-padded changeset revision number
1416 :``%b``: basename of the exporting repository
1416 :``%b``: basename of the exporting repository
1417
1417
1418 Returns 0 on success.
1418 Returns 0 on success.
1419 """
1419 """
1420 ctx = scmutil.revsingle(repo, opts.get('rev'))
1420 ctx = scmutil.revsingle(repo, opts.get('rev'))
1421 m = scmutil.match(ctx, (file1,) + pats, opts)
1421 m = scmutil.match(ctx, (file1,) + pats, opts)
1422
1422
1423 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1423 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1424
1424
1425 @command('^clone',
1425 @command('^clone',
1426 [('U', 'noupdate', None, _('the clone will include an empty working '
1426 [('U', 'noupdate', None, _('the clone will include an empty working '
1427 'directory (only a repository)')),
1427 'directory (only a repository)')),
1428 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1428 ('u', 'updaterev', '', _('revision, tag, or branch to check out'),
1429 _('REV')),
1429 _('REV')),
1430 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1430 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1431 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1431 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1432 ('', 'pull', None, _('use pull protocol to copy metadata')),
1432 ('', 'pull', None, _('use pull protocol to copy metadata')),
1433 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1433 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1434 ] + remoteopts,
1434 ] + remoteopts,
1435 _('[OPTION]... SOURCE [DEST]'),
1435 _('[OPTION]... SOURCE [DEST]'),
1436 norepo=True)
1436 norepo=True)
1437 def clone(ui, source, dest=None, **opts):
1437 def clone(ui, source, dest=None, **opts):
1438 """make a copy of an existing repository
1438 """make a copy of an existing repository
1439
1439
1440 Create a copy of an existing repository in a new directory.
1440 Create a copy of an existing repository in a new directory.
1441
1441
1442 If no destination directory name is specified, it defaults to the
1442 If no destination directory name is specified, it defaults to the
1443 basename of the source.
1443 basename of the source.
1444
1444
1445 The location of the source is added to the new repository's
1445 The location of the source is added to the new repository's
1446 ``.hg/hgrc`` file, as the default to be used for future pulls.
1446 ``.hg/hgrc`` file, as the default to be used for future pulls.
1447
1447
1448 Only local paths and ``ssh://`` URLs are supported as
1448 Only local paths and ``ssh://`` URLs are supported as
1449 destinations. For ``ssh://`` destinations, no working directory or
1449 destinations. For ``ssh://`` destinations, no working directory or
1450 ``.hg/hgrc`` will be created on the remote side.
1450 ``.hg/hgrc`` will be created on the remote side.
1451
1451
1452 If the source repository has a bookmark called '@' set, that
1452 If the source repository has a bookmark called '@' set, that
1453 revision will be checked out in the new repository by default.
1453 revision will be checked out in the new repository by default.
1454
1454
1455 To check out a particular version, use -u/--update, or
1455 To check out a particular version, use -u/--update, or
1456 -U/--noupdate to create a clone with no working directory.
1456 -U/--noupdate to create a clone with no working directory.
1457
1457
1458 To pull only a subset of changesets, specify one or more revisions
1458 To pull only a subset of changesets, specify one or more revisions
1459 identifiers with -r/--rev or branches with -b/--branch. The
1459 identifiers with -r/--rev or branches with -b/--branch. The
1460 resulting clone will contain only the specified changesets and
1460 resulting clone will contain only the specified changesets and
1461 their ancestors. These options (or 'clone src#rev dest') imply
1461 their ancestors. These options (or 'clone src#rev dest') imply
1462 --pull, even for local source repositories.
1462 --pull, even for local source repositories.
1463
1463
1464 .. note::
1464 .. note::
1465
1465
1466 Specifying a tag will include the tagged changeset but not the
1466 Specifying a tag will include the tagged changeset but not the
1467 changeset containing the tag.
1467 changeset containing the tag.
1468
1468
1469 .. container:: verbose
1469 .. container:: verbose
1470
1470
1471 For efficiency, hardlinks are used for cloning whenever the
1471 For efficiency, hardlinks are used for cloning whenever the
1472 source and destination are on the same filesystem (note this
1472 source and destination are on the same filesystem (note this
1473 applies only to the repository data, not to the working
1473 applies only to the repository data, not to the working
1474 directory). Some filesystems, such as AFS, implement hardlinking
1474 directory). Some filesystems, such as AFS, implement hardlinking
1475 incorrectly, but do not report errors. In these cases, use the
1475 incorrectly, but do not report errors. In these cases, use the
1476 --pull option to avoid hardlinking.
1476 --pull option to avoid hardlinking.
1477
1477
1478 In some cases, you can clone repositories and the working
1478 In some cases, you can clone repositories and the working
1479 directory using full hardlinks with ::
1479 directory using full hardlinks with ::
1480
1480
1481 $ cp -al REPO REPOCLONE
1481 $ cp -al REPO REPOCLONE
1482
1482
1483 This is the fastest way to clone, but it is not always safe. The
1483 This is the fastest way to clone, but it is not always safe. The
1484 operation is not atomic (making sure REPO is not modified during
1484 operation is not atomic (making sure REPO is not modified during
1485 the operation is up to you) and you have to make sure your
1485 the operation is up to you) and you have to make sure your
1486 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1486 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1487 so). Also, this is not compatible with certain extensions that
1487 so). Also, this is not compatible with certain extensions that
1488 place their metadata under the .hg directory, such as mq.
1488 place their metadata under the .hg directory, such as mq.
1489
1489
1490 Mercurial will update the working directory to the first applicable
1490 Mercurial will update the working directory to the first applicable
1491 revision from this list:
1491 revision from this list:
1492
1492
1493 a) null if -U or the source repository has no changesets
1493 a) null if -U or the source repository has no changesets
1494 b) if -u . and the source repository is local, the first parent of
1494 b) if -u . and the source repository is local, the first parent of
1495 the source repository's working directory
1495 the source repository's working directory
1496 c) the changeset specified with -u (if a branch name, this means the
1496 c) the changeset specified with -u (if a branch name, this means the
1497 latest head of that branch)
1497 latest head of that branch)
1498 d) the changeset specified with -r
1498 d) the changeset specified with -r
1499 e) the tipmost head specified with -b
1499 e) the tipmost head specified with -b
1500 f) the tipmost head specified with the url#branch source syntax
1500 f) the tipmost head specified with the url#branch source syntax
1501 g) the revision marked with the '@' bookmark, if present
1501 g) the revision marked with the '@' bookmark, if present
1502 h) the tipmost head of the default branch
1502 h) the tipmost head of the default branch
1503 i) tip
1503 i) tip
1504
1504
1505 Examples:
1505 Examples:
1506
1506
1507 - clone a remote repository to a new directory named hg/::
1507 - clone a remote repository to a new directory named hg/::
1508
1508
1509 hg clone http://selenic.com/hg
1509 hg clone http://selenic.com/hg
1510
1510
1511 - create a lightweight local clone::
1511 - create a lightweight local clone::
1512
1512
1513 hg clone project/ project-feature/
1513 hg clone project/ project-feature/
1514
1514
1515 - clone from an absolute path on an ssh server (note double-slash)::
1515 - clone from an absolute path on an ssh server (note double-slash)::
1516
1516
1517 hg clone ssh://user@server//home/projects/alpha/
1517 hg clone ssh://user@server//home/projects/alpha/
1518
1518
1519 - do a high-speed clone over a LAN while checking out a
1519 - do a high-speed clone over a LAN while checking out a
1520 specified version::
1520 specified version::
1521
1521
1522 hg clone --uncompressed http://server/repo -u 1.5
1522 hg clone --uncompressed http://server/repo -u 1.5
1523
1523
1524 - create a repository without changesets after a particular revision::
1524 - create a repository without changesets after a particular revision::
1525
1525
1526 hg clone -r 04e544 experimental/ good/
1526 hg clone -r 04e544 experimental/ good/
1527
1527
1528 - clone (and track) a particular named branch::
1528 - clone (and track) a particular named branch::
1529
1529
1530 hg clone http://selenic.com/hg#stable
1530 hg clone http://selenic.com/hg#stable
1531
1531
1532 See :hg:`help urls` for details on specifying URLs.
1532 See :hg:`help urls` for details on specifying URLs.
1533
1533
1534 Returns 0 on success.
1534 Returns 0 on success.
1535 """
1535 """
1536 if opts.get('noupdate') and opts.get('updaterev'):
1536 if opts.get('noupdate') and opts.get('updaterev'):
1537 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1537 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1538
1538
1539 r = hg.clone(ui, opts, source, dest,
1539 r = hg.clone(ui, opts, source, dest,
1540 pull=opts.get('pull'),
1540 pull=opts.get('pull'),
1541 stream=opts.get('uncompressed'),
1541 stream=opts.get('uncompressed'),
1542 rev=opts.get('rev'),
1542 rev=opts.get('rev'),
1543 update=opts.get('updaterev') or not opts.get('noupdate'),
1543 update=opts.get('updaterev') or not opts.get('noupdate'),
1544 branch=opts.get('branch'),
1544 branch=opts.get('branch'),
1545 shareopts=opts.get('shareopts'))
1545 shareopts=opts.get('shareopts'))
1546
1546
1547 return r is None
1547 return r is None
1548
1548
1549 @command('^commit|ci',
1549 @command('^commit|ci',
1550 [('A', 'addremove', None,
1550 [('A', 'addremove', None,
1551 _('mark new/missing files as added/removed before committing')),
1551 _('mark new/missing files as added/removed before committing')),
1552 ('', 'close-branch', None,
1552 ('', 'close-branch', None,
1553 _('mark a branch head as closed')),
1553 _('mark a branch head as closed')),
1554 ('', 'amend', None, _('amend the parent of the working directory')),
1554 ('', 'amend', None, _('amend the parent of the working directory')),
1555 ('s', 'secret', None, _('use the secret phase for committing')),
1555 ('s', 'secret', None, _('use the secret phase for committing')),
1556 ('e', 'edit', None, _('invoke editor on commit messages')),
1556 ('e', 'edit', None, _('invoke editor on commit messages')),
1557 ('i', 'interactive', None, _('use interactive mode')),
1557 ('i', 'interactive', None, _('use interactive mode')),
1558 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1558 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1559 _('[OPTION]... [FILE]...'),
1559 _('[OPTION]... [FILE]...'),
1560 inferrepo=True)
1560 inferrepo=True)
1561 def commit(ui, repo, *pats, **opts):
1561 def commit(ui, repo, *pats, **opts):
1562 """commit the specified files or all outstanding changes
1562 """commit the specified files or all outstanding changes
1563
1563
1564 Commit changes to the given files into the repository. Unlike a
1564 Commit changes to the given files into the repository. Unlike a
1565 centralized SCM, this operation is a local operation. See
1565 centralized SCM, this operation is a local operation. See
1566 :hg:`push` for a way to actively distribute your changes.
1566 :hg:`push` for a way to actively distribute your changes.
1567
1567
1568 If a list of files is omitted, all changes reported by :hg:`status`
1568 If a list of files is omitted, all changes reported by :hg:`status`
1569 will be committed.
1569 will be committed.
1570
1570
1571 If you are committing the result of a merge, do not provide any
1571 If you are committing the result of a merge, do not provide any
1572 filenames or -I/-X filters.
1572 filenames or -I/-X filters.
1573
1573
1574 If no commit message is specified, Mercurial starts your
1574 If no commit message is specified, Mercurial starts your
1575 configured editor where you can enter a message. In case your
1575 configured editor where you can enter a message. In case your
1576 commit fails, you will find a backup of your message in
1576 commit fails, you will find a backup of your message in
1577 ``.hg/last-message.txt``.
1577 ``.hg/last-message.txt``.
1578
1578
1579 The --close-branch flag can be used to mark the current branch
1579 The --close-branch flag can be used to mark the current branch
1580 head closed. When all heads of a branch are closed, the branch
1580 head closed. When all heads of a branch are closed, the branch
1581 will be considered closed and no longer listed.
1581 will be considered closed and no longer listed.
1582
1582
1583 The --amend flag can be used to amend the parent of the
1583 The --amend flag can be used to amend the parent of the
1584 working directory with a new commit that contains the changes
1584 working directory with a new commit that contains the changes
1585 in the parent in addition to those currently reported by :hg:`status`,
1585 in the parent in addition to those currently reported by :hg:`status`,
1586 if there are any. The old commit is stored in a backup bundle in
1586 if there are any. The old commit is stored in a backup bundle in
1587 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1587 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1588 on how to restore it).
1588 on how to restore it).
1589
1589
1590 Message, user and date are taken from the amended commit unless
1590 Message, user and date are taken from the amended commit unless
1591 specified. When a message isn't specified on the command line,
1591 specified. When a message isn't specified on the command line,
1592 the editor will open with the message of the amended commit.
1592 the editor will open with the message of the amended commit.
1593
1593
1594 It is not possible to amend public changesets (see :hg:`help phases`)
1594 It is not possible to amend public changesets (see :hg:`help phases`)
1595 or changesets that have children.
1595 or changesets that have children.
1596
1596
1597 See :hg:`help dates` for a list of formats valid for -d/--date.
1597 See :hg:`help dates` for a list of formats valid for -d/--date.
1598
1598
1599 Returns 0 on success, 1 if nothing changed.
1599 Returns 0 on success, 1 if nothing changed.
1600
1600
1601 .. container:: verbose
1601 .. container:: verbose
1602
1602
1603 Examples:
1603 Examples:
1604
1604
1605 - commit all files ending in .py::
1605 - commit all files ending in .py::
1606
1606
1607 hg commit --include "set:**.py"
1607 hg commit --include "set:**.py"
1608
1608
1609 - commit all non-binary files::
1609 - commit all non-binary files::
1610
1610
1611 hg commit --exclude "set:binary()"
1611 hg commit --exclude "set:binary()"
1612
1612
1613 - amend the current commit and set the date to now::
1613 - amend the current commit and set the date to now::
1614
1614
1615 hg commit --amend --date now
1615 hg commit --amend --date now
1616 """
1616 """
1617 wlock = lock = None
1617 wlock = lock = None
1618 try:
1618 try:
1619 wlock = repo.wlock()
1619 wlock = repo.wlock()
1620 lock = repo.lock()
1620 lock = repo.lock()
1621 return _docommit(ui, repo, *pats, **opts)
1621 return _docommit(ui, repo, *pats, **opts)
1622 finally:
1622 finally:
1623 release(lock, wlock)
1623 release(lock, wlock)
1624
1624
1625 def _docommit(ui, repo, *pats, **opts):
1625 def _docommit(ui, repo, *pats, **opts):
1626 if opts.get('interactive'):
1626 if opts.get('interactive'):
1627 opts.pop('interactive')
1627 opts.pop('interactive')
1628 cmdutil.dorecord(ui, repo, commit, None, False,
1628 cmdutil.dorecord(ui, repo, commit, None, False,
1629 cmdutil.recordfilter, *pats, **opts)
1629 cmdutil.recordfilter, *pats, **opts)
1630 return
1630 return
1631
1631
1632 if opts.get('subrepos'):
1632 if opts.get('subrepos'):
1633 if opts.get('amend'):
1633 if opts.get('amend'):
1634 raise error.Abort(_('cannot amend with --subrepos'))
1634 raise error.Abort(_('cannot amend with --subrepos'))
1635 # Let --subrepos on the command line override config setting.
1635 # Let --subrepos on the command line override config setting.
1636 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1636 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1637
1637
1638 cmdutil.checkunfinished(repo, commit=True)
1638 cmdutil.checkunfinished(repo, commit=True)
1639
1639
1640 branch = repo[None].branch()
1640 branch = repo[None].branch()
1641 bheads = repo.branchheads(branch)
1641 bheads = repo.branchheads(branch)
1642
1642
1643 extra = {}
1643 extra = {}
1644 if opts.get('close_branch'):
1644 if opts.get('close_branch'):
1645 extra['close'] = 1
1645 extra['close'] = 1
1646
1646
1647 if not bheads:
1647 if not bheads:
1648 raise error.Abort(_('can only close branch heads'))
1648 raise error.Abort(_('can only close branch heads'))
1649 elif opts.get('amend'):
1649 elif opts.get('amend'):
1650 if repo[None].parents()[0].p1().branch() != branch and \
1650 if repo[None].parents()[0].p1().branch() != branch and \
1651 repo[None].parents()[0].p2().branch() != branch:
1651 repo[None].parents()[0].p2().branch() != branch:
1652 raise error.Abort(_('can only close branch heads'))
1652 raise error.Abort(_('can only close branch heads'))
1653
1653
1654 if opts.get('amend'):
1654 if opts.get('amend'):
1655 if ui.configbool('ui', 'commitsubrepos'):
1655 if ui.configbool('ui', 'commitsubrepos'):
1656 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1656 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1657
1657
1658 old = repo['.']
1658 old = repo['.']
1659 if not old.mutable():
1659 if not old.mutable():
1660 raise error.Abort(_('cannot amend public changesets'))
1660 raise error.Abort(_('cannot amend public changesets'))
1661 if len(repo[None].parents()) > 1:
1661 if len(repo[None].parents()) > 1:
1662 raise error.Abort(_('cannot amend while merging'))
1662 raise error.Abort(_('cannot amend while merging'))
1663 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1663 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1664 if not allowunstable and old.children():
1664 if not allowunstable and old.children():
1665 raise error.Abort(_('cannot amend changeset with children'))
1665 raise error.Abort(_('cannot amend changeset with children'))
1666
1666
1667 newextra = extra.copy()
1667 newextra = extra.copy()
1668 newextra['branch'] = branch
1668 newextra['branch'] = branch
1669 extra = newextra
1669 extra = newextra
1670 # commitfunc is used only for temporary amend commit by cmdutil.amend
1670 # commitfunc is used only for temporary amend commit by cmdutil.amend
1671 def commitfunc(ui, repo, message, match, opts):
1671 def commitfunc(ui, repo, message, match, opts):
1672 return repo.commit(message,
1672 return repo.commit(message,
1673 opts.get('user') or old.user(),
1673 opts.get('user') or old.user(),
1674 opts.get('date') or old.date(),
1674 opts.get('date') or old.date(),
1675 match,
1675 match,
1676 extra=extra)
1676 extra=extra)
1677
1677
1678 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1678 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1679 if node == old.node():
1679 if node == old.node():
1680 ui.status(_("nothing changed\n"))
1680 ui.status(_("nothing changed\n"))
1681 return 1
1681 return 1
1682 else:
1682 else:
1683 def commitfunc(ui, repo, message, match, opts):
1683 def commitfunc(ui, repo, message, match, opts):
1684 backup = ui.backupconfig('phases', 'new-commit')
1684 backup = ui.backupconfig('phases', 'new-commit')
1685 baseui = repo.baseui
1685 baseui = repo.baseui
1686 basebackup = baseui.backupconfig('phases', 'new-commit')
1686 basebackup = baseui.backupconfig('phases', 'new-commit')
1687 try:
1687 try:
1688 if opts.get('secret'):
1688 if opts.get('secret'):
1689 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1689 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1690 # Propagate to subrepos
1690 # Propagate to subrepos
1691 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1691 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1692
1692
1693 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1693 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1694 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1694 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1695 return repo.commit(message, opts.get('user'), opts.get('date'),
1695 return repo.commit(message, opts.get('user'), opts.get('date'),
1696 match,
1696 match,
1697 editor=editor,
1697 editor=editor,
1698 extra=extra)
1698 extra=extra)
1699 finally:
1699 finally:
1700 ui.restoreconfig(backup)
1700 ui.restoreconfig(backup)
1701 repo.baseui.restoreconfig(basebackup)
1701 repo.baseui.restoreconfig(basebackup)
1702
1702
1703
1703
1704 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1704 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1705
1705
1706 if not node:
1706 if not node:
1707 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1707 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1708 if stat[3]:
1708 if stat[3]:
1709 ui.status(_("nothing changed (%d missing files, see "
1709 ui.status(_("nothing changed (%d missing files, see "
1710 "'hg status')\n") % len(stat[3]))
1710 "'hg status')\n") % len(stat[3]))
1711 else:
1711 else:
1712 ui.status(_("nothing changed\n"))
1712 ui.status(_("nothing changed\n"))
1713 return 1
1713 return 1
1714
1714
1715 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1715 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1716
1716
1717 @command('config|showconfig|debugconfig',
1717 @command('config|showconfig|debugconfig',
1718 [('u', 'untrusted', None, _('show untrusted configuration options')),
1718 [('u', 'untrusted', None, _('show untrusted configuration options')),
1719 ('e', 'edit', None, _('edit user config')),
1719 ('e', 'edit', None, _('edit user config')),
1720 ('l', 'local', None, _('edit repository config')),
1720 ('l', 'local', None, _('edit repository config')),
1721 ('g', 'global', None, _('edit global config'))],
1721 ('g', 'global', None, _('edit global config'))],
1722 _('[-u] [NAME]...'),
1722 _('[-u] [NAME]...'),
1723 optionalrepo=True)
1723 optionalrepo=True)
1724 def config(ui, repo, *values, **opts):
1724 def config(ui, repo, *values, **opts):
1725 """show combined config settings from all hgrc files
1725 """show combined config settings from all hgrc files
1726
1726
1727 With no arguments, print names and values of all config items.
1727 With no arguments, print names and values of all config items.
1728
1728
1729 With one argument of the form section.name, print just the value
1729 With one argument of the form section.name, print just the value
1730 of that config item.
1730 of that config item.
1731
1731
1732 With multiple arguments, print names and values of all config
1732 With multiple arguments, print names and values of all config
1733 items with matching section names.
1733 items with matching section names.
1734
1734
1735 With --edit, start an editor on the user-level config file. With
1735 With --edit, start an editor on the user-level config file. With
1736 --global, edit the system-wide config file. With --local, edit the
1736 --global, edit the system-wide config file. With --local, edit the
1737 repository-level config file.
1737 repository-level config file.
1738
1738
1739 With --debug, the source (filename and line number) is printed
1739 With --debug, the source (filename and line number) is printed
1740 for each config item.
1740 for each config item.
1741
1741
1742 See :hg:`help config` for more information about config files.
1742 See :hg:`help config` for more information about config files.
1743
1743
1744 Returns 0 on success, 1 if NAME does not exist.
1744 Returns 0 on success, 1 if NAME does not exist.
1745
1745
1746 """
1746 """
1747
1747
1748 if opts.get('edit') or opts.get('local') or opts.get('global'):
1748 if opts.get('edit') or opts.get('local') or opts.get('global'):
1749 if opts.get('local') and opts.get('global'):
1749 if opts.get('local') and opts.get('global'):
1750 raise error.Abort(_("can't use --local and --global together"))
1750 raise error.Abort(_("can't use --local and --global together"))
1751
1751
1752 if opts.get('local'):
1752 if opts.get('local'):
1753 if not repo:
1753 if not repo:
1754 raise error.Abort(_("can't use --local outside a repository"))
1754 raise error.Abort(_("can't use --local outside a repository"))
1755 paths = [repo.join('hgrc')]
1755 paths = [repo.join('hgrc')]
1756 elif opts.get('global'):
1756 elif opts.get('global'):
1757 paths = scmutil.systemrcpath()
1757 paths = scmutil.systemrcpath()
1758 else:
1758 else:
1759 paths = scmutil.userrcpath()
1759 paths = scmutil.userrcpath()
1760
1760
1761 for f in paths:
1761 for f in paths:
1762 if os.path.exists(f):
1762 if os.path.exists(f):
1763 break
1763 break
1764 else:
1764 else:
1765 if opts.get('global'):
1765 if opts.get('global'):
1766 samplehgrc = uimod.samplehgrcs['global']
1766 samplehgrc = uimod.samplehgrcs['global']
1767 elif opts.get('local'):
1767 elif opts.get('local'):
1768 samplehgrc = uimod.samplehgrcs['local']
1768 samplehgrc = uimod.samplehgrcs['local']
1769 else:
1769 else:
1770 samplehgrc = uimod.samplehgrcs['user']
1770 samplehgrc = uimod.samplehgrcs['user']
1771
1771
1772 f = paths[0]
1772 f = paths[0]
1773 fp = open(f, "w")
1773 fp = open(f, "w")
1774 fp.write(samplehgrc)
1774 fp.write(samplehgrc)
1775 fp.close()
1775 fp.close()
1776
1776
1777 editor = ui.geteditor()
1777 editor = ui.geteditor()
1778 ui.system("%s \"%s\"" % (editor, f),
1778 ui.system("%s \"%s\"" % (editor, f),
1779 onerr=error.Abort, errprefix=_("edit failed"))
1779 onerr=error.Abort, errprefix=_("edit failed"))
1780 return
1780 return
1781
1781
1782 for f in scmutil.rcpath():
1782 for f in scmutil.rcpath():
1783 ui.debug('read config from: %s\n' % f)
1783 ui.debug('read config from: %s\n' % f)
1784 untrusted = bool(opts.get('untrusted'))
1784 untrusted = bool(opts.get('untrusted'))
1785 if values:
1785 if values:
1786 sections = [v for v in values if '.' not in v]
1786 sections = [v for v in values if '.' not in v]
1787 items = [v for v in values if '.' in v]
1787 items = [v for v in values if '.' in v]
1788 if len(items) > 1 or items and sections:
1788 if len(items) > 1 or items and sections:
1789 raise error.Abort(_('only one config item permitted'))
1789 raise error.Abort(_('only one config item permitted'))
1790 matched = False
1790 matched = False
1791 for section, name, value in ui.walkconfig(untrusted=untrusted):
1791 for section, name, value in ui.walkconfig(untrusted=untrusted):
1792 value = str(value).replace('\n', '\\n')
1792 value = str(value).replace('\n', '\\n')
1793 sectname = section + '.' + name
1793 sectname = section + '.' + name
1794 if values:
1794 if values:
1795 for v in values:
1795 for v in values:
1796 if v == section:
1796 if v == section:
1797 ui.debug('%s: ' %
1797 ui.debug('%s: ' %
1798 ui.configsource(section, name, untrusted))
1798 ui.configsource(section, name, untrusted))
1799 ui.write('%s=%s\n' % (sectname, value))
1799 ui.write('%s=%s\n' % (sectname, value))
1800 matched = True
1800 matched = True
1801 elif v == sectname:
1801 elif v == sectname:
1802 ui.debug('%s: ' %
1802 ui.debug('%s: ' %
1803 ui.configsource(section, name, untrusted))
1803 ui.configsource(section, name, untrusted))
1804 ui.write(value, '\n')
1804 ui.write(value, '\n')
1805 matched = True
1805 matched = True
1806 else:
1806 else:
1807 ui.debug('%s: ' %
1807 ui.debug('%s: ' %
1808 ui.configsource(section, name, untrusted))
1808 ui.configsource(section, name, untrusted))
1809 ui.write('%s=%s\n' % (sectname, value))
1809 ui.write('%s=%s\n' % (sectname, value))
1810 matched = True
1810 matched = True
1811 if matched:
1811 if matched:
1812 return 0
1812 return 0
1813 return 1
1813 return 1
1814
1814
1815 @command('copy|cp',
1815 @command('copy|cp',
1816 [('A', 'after', None, _('record a copy that has already occurred')),
1816 [('A', 'after', None, _('record a copy that has already occurred')),
1817 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1817 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1818 ] + walkopts + dryrunopts,
1818 ] + walkopts + dryrunopts,
1819 _('[OPTION]... [SOURCE]... DEST'))
1819 _('[OPTION]... [SOURCE]... DEST'))
1820 def copy(ui, repo, *pats, **opts):
1820 def copy(ui, repo, *pats, **opts):
1821 """mark files as copied for the next commit
1821 """mark files as copied for the next commit
1822
1822
1823 Mark dest as having copies of source files. If dest is a
1823 Mark dest as having copies of source files. If dest is a
1824 directory, copies are put in that directory. If dest is a file,
1824 directory, copies are put in that directory. If dest is a file,
1825 the source must be a single file.
1825 the source must be a single file.
1826
1826
1827 By default, this command copies the contents of files as they
1827 By default, this command copies the contents of files as they
1828 exist in the working directory. If invoked with -A/--after, the
1828 exist in the working directory. If invoked with -A/--after, the
1829 operation is recorded, but no copying is performed.
1829 operation is recorded, but no copying is performed.
1830
1830
1831 This command takes effect with the next commit. To undo a copy
1831 This command takes effect with the next commit. To undo a copy
1832 before that, see :hg:`revert`.
1832 before that, see :hg:`revert`.
1833
1833
1834 Returns 0 on success, 1 if errors are encountered.
1834 Returns 0 on success, 1 if errors are encountered.
1835 """
1835 """
1836 wlock = repo.wlock(False)
1836 with repo.wlock(False):
1837 try:
1838 return cmdutil.copy(ui, repo, pats, opts)
1837 return cmdutil.copy(ui, repo, pats, opts)
1839 finally:
1840 wlock.release()
1841
1838
1842 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1839 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1843 def debugancestor(ui, repo, *args):
1840 def debugancestor(ui, repo, *args):
1844 """find the ancestor revision of two revisions in a given index"""
1841 """find the ancestor revision of two revisions in a given index"""
1845 if len(args) == 3:
1842 if len(args) == 3:
1846 index, rev1, rev2 = args
1843 index, rev1, rev2 = args
1847 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1844 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1848 lookup = r.lookup
1845 lookup = r.lookup
1849 elif len(args) == 2:
1846 elif len(args) == 2:
1850 if not repo:
1847 if not repo:
1851 raise error.Abort(_("there is no Mercurial repository here "
1848 raise error.Abort(_("there is no Mercurial repository here "
1852 "(.hg not found)"))
1849 "(.hg not found)"))
1853 rev1, rev2 = args
1850 rev1, rev2 = args
1854 r = repo.changelog
1851 r = repo.changelog
1855 lookup = repo.lookup
1852 lookup = repo.lookup
1856 else:
1853 else:
1857 raise error.Abort(_('either two or three arguments required'))
1854 raise error.Abort(_('either two or three arguments required'))
1858 a = r.ancestor(lookup(rev1), lookup(rev2))
1855 a = r.ancestor(lookup(rev1), lookup(rev2))
1859 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1856 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1860
1857
1861 @command('debugbuilddag',
1858 @command('debugbuilddag',
1862 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1859 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1863 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1860 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1864 ('n', 'new-file', None, _('add new file at each rev'))],
1861 ('n', 'new-file', None, _('add new file at each rev'))],
1865 _('[OPTION]... [TEXT]'))
1862 _('[OPTION]... [TEXT]'))
1866 def debugbuilddag(ui, repo, text=None,
1863 def debugbuilddag(ui, repo, text=None,
1867 mergeable_file=False,
1864 mergeable_file=False,
1868 overwritten_file=False,
1865 overwritten_file=False,
1869 new_file=False):
1866 new_file=False):
1870 """builds a repo with a given DAG from scratch in the current empty repo
1867 """builds a repo with a given DAG from scratch in the current empty repo
1871
1868
1872 The description of the DAG is read from stdin if not given on the
1869 The description of the DAG is read from stdin if not given on the
1873 command line.
1870 command line.
1874
1871
1875 Elements:
1872 Elements:
1876
1873
1877 - "+n" is a linear run of n nodes based on the current default parent
1874 - "+n" is a linear run of n nodes based on the current default parent
1878 - "." is a single node based on the current default parent
1875 - "." is a single node based on the current default parent
1879 - "$" resets the default parent to null (implied at the start);
1876 - "$" resets the default parent to null (implied at the start);
1880 otherwise the default parent is always the last node created
1877 otherwise the default parent is always the last node created
1881 - "<p" sets the default parent to the backref p
1878 - "<p" sets the default parent to the backref p
1882 - "*p" is a fork at parent p, which is a backref
1879 - "*p" is a fork at parent p, which is a backref
1883 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1880 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1884 - "/p2" is a merge of the preceding node and p2
1881 - "/p2" is a merge of the preceding node and p2
1885 - ":tag" defines a local tag for the preceding node
1882 - ":tag" defines a local tag for the preceding node
1886 - "@branch" sets the named branch for subsequent nodes
1883 - "@branch" sets the named branch for subsequent nodes
1887 - "#...\\n" is a comment up to the end of the line
1884 - "#...\\n" is a comment up to the end of the line
1888
1885
1889 Whitespace between the above elements is ignored.
1886 Whitespace between the above elements is ignored.
1890
1887
1891 A backref is either
1888 A backref is either
1892
1889
1893 - a number n, which references the node curr-n, where curr is the current
1890 - a number n, which references the node curr-n, where curr is the current
1894 node, or
1891 node, or
1895 - the name of a local tag you placed earlier using ":tag", or
1892 - the name of a local tag you placed earlier using ":tag", or
1896 - empty to denote the default parent.
1893 - empty to denote the default parent.
1897
1894
1898 All string valued-elements are either strictly alphanumeric, or must
1895 All string valued-elements are either strictly alphanumeric, or must
1899 be enclosed in double quotes ("..."), with "\\" as escape character.
1896 be enclosed in double quotes ("..."), with "\\" as escape character.
1900 """
1897 """
1901
1898
1902 if text is None:
1899 if text is None:
1903 ui.status(_("reading DAG from stdin\n"))
1900 ui.status(_("reading DAG from stdin\n"))
1904 text = ui.fin.read()
1901 text = ui.fin.read()
1905
1902
1906 cl = repo.changelog
1903 cl = repo.changelog
1907 if len(cl) > 0:
1904 if len(cl) > 0:
1908 raise error.Abort(_('repository is not empty'))
1905 raise error.Abort(_('repository is not empty'))
1909
1906
1910 # determine number of revs in DAG
1907 # determine number of revs in DAG
1911 total = 0
1908 total = 0
1912 for type, data in dagparser.parsedag(text):
1909 for type, data in dagparser.parsedag(text):
1913 if type == 'n':
1910 if type == 'n':
1914 total += 1
1911 total += 1
1915
1912
1916 if mergeable_file:
1913 if mergeable_file:
1917 linesperrev = 2
1914 linesperrev = 2
1918 # make a file with k lines per rev
1915 # make a file with k lines per rev
1919 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1916 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1920 initialmergedlines.append("")
1917 initialmergedlines.append("")
1921
1918
1922 tags = []
1919 tags = []
1923
1920
1924 lock = tr = None
1921 lock = tr = None
1925 try:
1922 try:
1926 lock = repo.lock()
1923 lock = repo.lock()
1927 tr = repo.transaction("builddag")
1924 tr = repo.transaction("builddag")
1928
1925
1929 at = -1
1926 at = -1
1930 atbranch = 'default'
1927 atbranch = 'default'
1931 nodeids = []
1928 nodeids = []
1932 id = 0
1929 id = 0
1933 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1930 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1934 for type, data in dagparser.parsedag(text):
1931 for type, data in dagparser.parsedag(text):
1935 if type == 'n':
1932 if type == 'n':
1936 ui.note(('node %s\n' % str(data)))
1933 ui.note(('node %s\n' % str(data)))
1937 id, ps = data
1934 id, ps = data
1938
1935
1939 files = []
1936 files = []
1940 fctxs = {}
1937 fctxs = {}
1941
1938
1942 p2 = None
1939 p2 = None
1943 if mergeable_file:
1940 if mergeable_file:
1944 fn = "mf"
1941 fn = "mf"
1945 p1 = repo[ps[0]]
1942 p1 = repo[ps[0]]
1946 if len(ps) > 1:
1943 if len(ps) > 1:
1947 p2 = repo[ps[1]]
1944 p2 = repo[ps[1]]
1948 pa = p1.ancestor(p2)
1945 pa = p1.ancestor(p2)
1949 base, local, other = [x[fn].data() for x in (pa, p1,
1946 base, local, other = [x[fn].data() for x in (pa, p1,
1950 p2)]
1947 p2)]
1951 m3 = simplemerge.Merge3Text(base, local, other)
1948 m3 = simplemerge.Merge3Text(base, local, other)
1952 ml = [l.strip() for l in m3.merge_lines()]
1949 ml = [l.strip() for l in m3.merge_lines()]
1953 ml.append("")
1950 ml.append("")
1954 elif at > 0:
1951 elif at > 0:
1955 ml = p1[fn].data().split("\n")
1952 ml = p1[fn].data().split("\n")
1956 else:
1953 else:
1957 ml = initialmergedlines
1954 ml = initialmergedlines
1958 ml[id * linesperrev] += " r%i" % id
1955 ml[id * linesperrev] += " r%i" % id
1959 mergedtext = "\n".join(ml)
1956 mergedtext = "\n".join(ml)
1960 files.append(fn)
1957 files.append(fn)
1961 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1958 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1962
1959
1963 if overwritten_file:
1960 if overwritten_file:
1964 fn = "of"
1961 fn = "of"
1965 files.append(fn)
1962 files.append(fn)
1966 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1963 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1967
1964
1968 if new_file:
1965 if new_file:
1969 fn = "nf%i" % id
1966 fn = "nf%i" % id
1970 files.append(fn)
1967 files.append(fn)
1971 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1968 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1972 if len(ps) > 1:
1969 if len(ps) > 1:
1973 if not p2:
1970 if not p2:
1974 p2 = repo[ps[1]]
1971 p2 = repo[ps[1]]
1975 for fn in p2:
1972 for fn in p2:
1976 if fn.startswith("nf"):
1973 if fn.startswith("nf"):
1977 files.append(fn)
1974 files.append(fn)
1978 fctxs[fn] = p2[fn]
1975 fctxs[fn] = p2[fn]
1979
1976
1980 def fctxfn(repo, cx, path):
1977 def fctxfn(repo, cx, path):
1981 return fctxs.get(path)
1978 return fctxs.get(path)
1982
1979
1983 if len(ps) == 0 or ps[0] < 0:
1980 if len(ps) == 0 or ps[0] < 0:
1984 pars = [None, None]
1981 pars = [None, None]
1985 elif len(ps) == 1:
1982 elif len(ps) == 1:
1986 pars = [nodeids[ps[0]], None]
1983 pars = [nodeids[ps[0]], None]
1987 else:
1984 else:
1988 pars = [nodeids[p] for p in ps]
1985 pars = [nodeids[p] for p in ps]
1989 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1986 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1990 date=(id, 0),
1987 date=(id, 0),
1991 user="debugbuilddag",
1988 user="debugbuilddag",
1992 extra={'branch': atbranch})
1989 extra={'branch': atbranch})
1993 nodeid = repo.commitctx(cx)
1990 nodeid = repo.commitctx(cx)
1994 nodeids.append(nodeid)
1991 nodeids.append(nodeid)
1995 at = id
1992 at = id
1996 elif type == 'l':
1993 elif type == 'l':
1997 id, name = data
1994 id, name = data
1998 ui.note(('tag %s\n' % name))
1995 ui.note(('tag %s\n' % name))
1999 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1996 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
2000 elif type == 'a':
1997 elif type == 'a':
2001 ui.note(('branch %s\n' % data))
1998 ui.note(('branch %s\n' % data))
2002 atbranch = data
1999 atbranch = data
2003 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2000 ui.progress(_('building'), id, unit=_('revisions'), total=total)
2004 tr.close()
2001 tr.close()
2005
2002
2006 if tags:
2003 if tags:
2007 repo.vfs.write("localtags", "".join(tags))
2004 repo.vfs.write("localtags", "".join(tags))
2008 finally:
2005 finally:
2009 ui.progress(_('building'), None)
2006 ui.progress(_('building'), None)
2010 release(tr, lock)
2007 release(tr, lock)
2011
2008
2012 @command('debugbundle',
2009 @command('debugbundle',
2013 [('a', 'all', None, _('show all details'))],
2010 [('a', 'all', None, _('show all details'))],
2014 _('FILE'),
2011 _('FILE'),
2015 norepo=True)
2012 norepo=True)
2016 def debugbundle(ui, bundlepath, all=None, **opts):
2013 def debugbundle(ui, bundlepath, all=None, **opts):
2017 """lists the contents of a bundle"""
2014 """lists the contents of a bundle"""
2018 f = hg.openpath(ui, bundlepath)
2015 f = hg.openpath(ui, bundlepath)
2019 try:
2016 try:
2020 gen = exchange.readbundle(ui, f, bundlepath)
2017 gen = exchange.readbundle(ui, f, bundlepath)
2021 if isinstance(gen, bundle2.unbundle20):
2018 if isinstance(gen, bundle2.unbundle20):
2022 return _debugbundle2(ui, gen, all=all, **opts)
2019 return _debugbundle2(ui, gen, all=all, **opts)
2023 if all:
2020 if all:
2024 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2021 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
2025
2022
2026 def showchunks(named):
2023 def showchunks(named):
2027 ui.write("\n%s\n" % named)
2024 ui.write("\n%s\n" % named)
2028 chain = None
2025 chain = None
2029 while True:
2026 while True:
2030 chunkdata = gen.deltachunk(chain)
2027 chunkdata = gen.deltachunk(chain)
2031 if not chunkdata:
2028 if not chunkdata:
2032 break
2029 break
2033 node = chunkdata['node']
2030 node = chunkdata['node']
2034 p1 = chunkdata['p1']
2031 p1 = chunkdata['p1']
2035 p2 = chunkdata['p2']
2032 p2 = chunkdata['p2']
2036 cs = chunkdata['cs']
2033 cs = chunkdata['cs']
2037 deltabase = chunkdata['deltabase']
2034 deltabase = chunkdata['deltabase']
2038 delta = chunkdata['delta']
2035 delta = chunkdata['delta']
2039 ui.write("%s %s %s %s %s %s\n" %
2036 ui.write("%s %s %s %s %s %s\n" %
2040 (hex(node), hex(p1), hex(p2),
2037 (hex(node), hex(p1), hex(p2),
2041 hex(cs), hex(deltabase), len(delta)))
2038 hex(cs), hex(deltabase), len(delta)))
2042 chain = node
2039 chain = node
2043
2040
2044 chunkdata = gen.changelogheader()
2041 chunkdata = gen.changelogheader()
2045 showchunks("changelog")
2042 showchunks("changelog")
2046 chunkdata = gen.manifestheader()
2043 chunkdata = gen.manifestheader()
2047 showchunks("manifest")
2044 showchunks("manifest")
2048 while True:
2045 while True:
2049 chunkdata = gen.filelogheader()
2046 chunkdata = gen.filelogheader()
2050 if not chunkdata:
2047 if not chunkdata:
2051 break
2048 break
2052 fname = chunkdata['filename']
2049 fname = chunkdata['filename']
2053 showchunks(fname)
2050 showchunks(fname)
2054 else:
2051 else:
2055 if isinstance(gen, bundle2.unbundle20):
2052 if isinstance(gen, bundle2.unbundle20):
2056 raise error.Abort(_('use debugbundle2 for this file'))
2053 raise error.Abort(_('use debugbundle2 for this file'))
2057 chunkdata = gen.changelogheader()
2054 chunkdata = gen.changelogheader()
2058 chain = None
2055 chain = None
2059 while True:
2056 while True:
2060 chunkdata = gen.deltachunk(chain)
2057 chunkdata = gen.deltachunk(chain)
2061 if not chunkdata:
2058 if not chunkdata:
2062 break
2059 break
2063 node = chunkdata['node']
2060 node = chunkdata['node']
2064 ui.write("%s\n" % hex(node))
2061 ui.write("%s\n" % hex(node))
2065 chain = node
2062 chain = node
2066 finally:
2063 finally:
2067 f.close()
2064 f.close()
2068
2065
2069 def _debugbundle2(ui, gen, **opts):
2066 def _debugbundle2(ui, gen, **opts):
2070 """lists the contents of a bundle2"""
2067 """lists the contents of a bundle2"""
2071 if not isinstance(gen, bundle2.unbundle20):
2068 if not isinstance(gen, bundle2.unbundle20):
2072 raise error.Abort(_('not a bundle2 file'))
2069 raise error.Abort(_('not a bundle2 file'))
2073 ui.write(('Stream params: %s\n' % repr(gen.params)))
2070 ui.write(('Stream params: %s\n' % repr(gen.params)))
2074 for part in gen.iterparts():
2071 for part in gen.iterparts():
2075 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2072 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
2076 if part.type == 'changegroup':
2073 if part.type == 'changegroup':
2077 version = part.params.get('version', '01')
2074 version = part.params.get('version', '01')
2078 cg = changegroup.getunbundler(version, part, 'UN')
2075 cg = changegroup.getunbundler(version, part, 'UN')
2079 chunkdata = cg.changelogheader()
2076 chunkdata = cg.changelogheader()
2080 chain = None
2077 chain = None
2081 while True:
2078 while True:
2082 chunkdata = cg.deltachunk(chain)
2079 chunkdata = cg.deltachunk(chain)
2083 if not chunkdata:
2080 if not chunkdata:
2084 break
2081 break
2085 node = chunkdata['node']
2082 node = chunkdata['node']
2086 ui.write(" %s\n" % hex(node))
2083 ui.write(" %s\n" % hex(node))
2087 chain = node
2084 chain = node
2088
2085
2089 @command('debugcreatestreamclonebundle', [], 'FILE')
2086 @command('debugcreatestreamclonebundle', [], 'FILE')
2090 def debugcreatestreamclonebundle(ui, repo, fname):
2087 def debugcreatestreamclonebundle(ui, repo, fname):
2091 """create a stream clone bundle file
2088 """create a stream clone bundle file
2092
2089
2093 Stream bundles are special bundles that are essentially archives of
2090 Stream bundles are special bundles that are essentially archives of
2094 revlog files. They are commonly used for cloning very quickly.
2091 revlog files. They are commonly used for cloning very quickly.
2095 """
2092 """
2096 requirements, gen = streamclone.generatebundlev1(repo)
2093 requirements, gen = streamclone.generatebundlev1(repo)
2097 changegroup.writechunks(ui, gen, fname)
2094 changegroup.writechunks(ui, gen, fname)
2098
2095
2099 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2096 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
2100
2097
2101 @command('debugapplystreamclonebundle', [], 'FILE')
2098 @command('debugapplystreamclonebundle', [], 'FILE')
2102 def debugapplystreamclonebundle(ui, repo, fname):
2099 def debugapplystreamclonebundle(ui, repo, fname):
2103 """apply a stream clone bundle file"""
2100 """apply a stream clone bundle file"""
2104 f = hg.openpath(ui, fname)
2101 f = hg.openpath(ui, fname)
2105 gen = exchange.readbundle(ui, f, fname)
2102 gen = exchange.readbundle(ui, f, fname)
2106 gen.apply(repo)
2103 gen.apply(repo)
2107
2104
2108 @command('debugcheckstate', [], '')
2105 @command('debugcheckstate', [], '')
2109 def debugcheckstate(ui, repo):
2106 def debugcheckstate(ui, repo):
2110 """validate the correctness of the current dirstate"""
2107 """validate the correctness of the current dirstate"""
2111 parent1, parent2 = repo.dirstate.parents()
2108 parent1, parent2 = repo.dirstate.parents()
2112 m1 = repo[parent1].manifest()
2109 m1 = repo[parent1].manifest()
2113 m2 = repo[parent2].manifest()
2110 m2 = repo[parent2].manifest()
2114 errors = 0
2111 errors = 0
2115 for f in repo.dirstate:
2112 for f in repo.dirstate:
2116 state = repo.dirstate[f]
2113 state = repo.dirstate[f]
2117 if state in "nr" and f not in m1:
2114 if state in "nr" and f not in m1:
2118 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2115 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
2119 errors += 1
2116 errors += 1
2120 if state in "a" and f in m1:
2117 if state in "a" and f in m1:
2121 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2118 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2122 errors += 1
2119 errors += 1
2123 if state in "m" and f not in m1 and f not in m2:
2120 if state in "m" and f not in m1 and f not in m2:
2124 ui.warn(_("%s in state %s, but not in either manifest\n") %
2121 ui.warn(_("%s in state %s, but not in either manifest\n") %
2125 (f, state))
2122 (f, state))
2126 errors += 1
2123 errors += 1
2127 for f in m1:
2124 for f in m1:
2128 state = repo.dirstate[f]
2125 state = repo.dirstate[f]
2129 if state not in "nrm":
2126 if state not in "nrm":
2130 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2127 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2131 errors += 1
2128 errors += 1
2132 if errors:
2129 if errors:
2133 error = _(".hg/dirstate inconsistent with current parent's manifest")
2130 error = _(".hg/dirstate inconsistent with current parent's manifest")
2134 raise error.Abort(error)
2131 raise error.Abort(error)
2135
2132
2136 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2133 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2137 def debugcommands(ui, cmd='', *args):
2134 def debugcommands(ui, cmd='', *args):
2138 """list all available commands and options"""
2135 """list all available commands and options"""
2139 for cmd, vals in sorted(table.iteritems()):
2136 for cmd, vals in sorted(table.iteritems()):
2140 cmd = cmd.split('|')[0].strip('^')
2137 cmd = cmd.split('|')[0].strip('^')
2141 opts = ', '.join([i[1] for i in vals[1]])
2138 opts = ', '.join([i[1] for i in vals[1]])
2142 ui.write('%s: %s\n' % (cmd, opts))
2139 ui.write('%s: %s\n' % (cmd, opts))
2143
2140
2144 @command('debugcomplete',
2141 @command('debugcomplete',
2145 [('o', 'options', None, _('show the command options'))],
2142 [('o', 'options', None, _('show the command options'))],
2146 _('[-o] CMD'),
2143 _('[-o] CMD'),
2147 norepo=True)
2144 norepo=True)
2148 def debugcomplete(ui, cmd='', **opts):
2145 def debugcomplete(ui, cmd='', **opts):
2149 """returns the completion list associated with the given command"""
2146 """returns the completion list associated with the given command"""
2150
2147
2151 if opts.get('options'):
2148 if opts.get('options'):
2152 options = []
2149 options = []
2153 otables = [globalopts]
2150 otables = [globalopts]
2154 if cmd:
2151 if cmd:
2155 aliases, entry = cmdutil.findcmd(cmd, table, False)
2152 aliases, entry = cmdutil.findcmd(cmd, table, False)
2156 otables.append(entry[1])
2153 otables.append(entry[1])
2157 for t in otables:
2154 for t in otables:
2158 for o in t:
2155 for o in t:
2159 if "(DEPRECATED)" in o[3]:
2156 if "(DEPRECATED)" in o[3]:
2160 continue
2157 continue
2161 if o[0]:
2158 if o[0]:
2162 options.append('-%s' % o[0])
2159 options.append('-%s' % o[0])
2163 options.append('--%s' % o[1])
2160 options.append('--%s' % o[1])
2164 ui.write("%s\n" % "\n".join(options))
2161 ui.write("%s\n" % "\n".join(options))
2165 return
2162 return
2166
2163
2167 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2164 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2168 if ui.verbose:
2165 if ui.verbose:
2169 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2166 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2170 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2167 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2171
2168
2172 @command('debugdag',
2169 @command('debugdag',
2173 [('t', 'tags', None, _('use tags as labels')),
2170 [('t', 'tags', None, _('use tags as labels')),
2174 ('b', 'branches', None, _('annotate with branch names')),
2171 ('b', 'branches', None, _('annotate with branch names')),
2175 ('', 'dots', None, _('use dots for runs')),
2172 ('', 'dots', None, _('use dots for runs')),
2176 ('s', 'spaces', None, _('separate elements by spaces'))],
2173 ('s', 'spaces', None, _('separate elements by spaces'))],
2177 _('[OPTION]... [FILE [REV]...]'),
2174 _('[OPTION]... [FILE [REV]...]'),
2178 optionalrepo=True)
2175 optionalrepo=True)
2179 def debugdag(ui, repo, file_=None, *revs, **opts):
2176 def debugdag(ui, repo, file_=None, *revs, **opts):
2180 """format the changelog or an index DAG as a concise textual description
2177 """format the changelog or an index DAG as a concise textual description
2181
2178
2182 If you pass a revlog index, the revlog's DAG is emitted. If you list
2179 If you pass a revlog index, the revlog's DAG is emitted. If you list
2183 revision numbers, they get labeled in the output as rN.
2180 revision numbers, they get labeled in the output as rN.
2184
2181
2185 Otherwise, the changelog DAG of the current repo is emitted.
2182 Otherwise, the changelog DAG of the current repo is emitted.
2186 """
2183 """
2187 spaces = opts.get('spaces')
2184 spaces = opts.get('spaces')
2188 dots = opts.get('dots')
2185 dots = opts.get('dots')
2189 if file_:
2186 if file_:
2190 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2187 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2191 revs = set((int(r) for r in revs))
2188 revs = set((int(r) for r in revs))
2192 def events():
2189 def events():
2193 for r in rlog:
2190 for r in rlog:
2194 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2191 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2195 if p != -1))
2192 if p != -1))
2196 if r in revs:
2193 if r in revs:
2197 yield 'l', (r, "r%i" % r)
2194 yield 'l', (r, "r%i" % r)
2198 elif repo:
2195 elif repo:
2199 cl = repo.changelog
2196 cl = repo.changelog
2200 tags = opts.get('tags')
2197 tags = opts.get('tags')
2201 branches = opts.get('branches')
2198 branches = opts.get('branches')
2202 if tags:
2199 if tags:
2203 labels = {}
2200 labels = {}
2204 for l, n in repo.tags().items():
2201 for l, n in repo.tags().items():
2205 labels.setdefault(cl.rev(n), []).append(l)
2202 labels.setdefault(cl.rev(n), []).append(l)
2206 def events():
2203 def events():
2207 b = "default"
2204 b = "default"
2208 for r in cl:
2205 for r in cl:
2209 if branches:
2206 if branches:
2210 newb = cl.read(cl.node(r))[5]['branch']
2207 newb = cl.read(cl.node(r))[5]['branch']
2211 if newb != b:
2208 if newb != b:
2212 yield 'a', newb
2209 yield 'a', newb
2213 b = newb
2210 b = newb
2214 yield 'n', (r, list(p for p in cl.parentrevs(r)
2211 yield 'n', (r, list(p for p in cl.parentrevs(r)
2215 if p != -1))
2212 if p != -1))
2216 if tags:
2213 if tags:
2217 ls = labels.get(r)
2214 ls = labels.get(r)
2218 if ls:
2215 if ls:
2219 for l in ls:
2216 for l in ls:
2220 yield 'l', (r, l)
2217 yield 'l', (r, l)
2221 else:
2218 else:
2222 raise error.Abort(_('need repo for changelog dag'))
2219 raise error.Abort(_('need repo for changelog dag'))
2223
2220
2224 for line in dagparser.dagtextlines(events(),
2221 for line in dagparser.dagtextlines(events(),
2225 addspaces=spaces,
2222 addspaces=spaces,
2226 wraplabels=True,
2223 wraplabels=True,
2227 wrapannotations=True,
2224 wrapannotations=True,
2228 wrapnonlinear=dots,
2225 wrapnonlinear=dots,
2229 usedots=dots,
2226 usedots=dots,
2230 maxlinewidth=70):
2227 maxlinewidth=70):
2231 ui.write(line)
2228 ui.write(line)
2232 ui.write("\n")
2229 ui.write("\n")
2233
2230
2234 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2231 @command('debugdata', debugrevlogopts, _('-c|-m|FILE REV'))
2235 def debugdata(ui, repo, file_, rev=None, **opts):
2232 def debugdata(ui, repo, file_, rev=None, **opts):
2236 """dump the contents of a data file revision"""
2233 """dump the contents of a data file revision"""
2237 if opts.get('changelog') or opts.get('manifest'):
2234 if opts.get('changelog') or opts.get('manifest'):
2238 file_, rev = None, file_
2235 file_, rev = None, file_
2239 elif rev is None:
2236 elif rev is None:
2240 raise error.CommandError('debugdata', _('invalid arguments'))
2237 raise error.CommandError('debugdata', _('invalid arguments'))
2241 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2238 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2242 try:
2239 try:
2243 ui.write(r.revision(r.lookup(rev)))
2240 ui.write(r.revision(r.lookup(rev)))
2244 except KeyError:
2241 except KeyError:
2245 raise error.Abort(_('invalid revision identifier %s') % rev)
2242 raise error.Abort(_('invalid revision identifier %s') % rev)
2246
2243
2247 @command('debugdate',
2244 @command('debugdate',
2248 [('e', 'extended', None, _('try extended date formats'))],
2245 [('e', 'extended', None, _('try extended date formats'))],
2249 _('[-e] DATE [RANGE]'),
2246 _('[-e] DATE [RANGE]'),
2250 norepo=True, optionalrepo=True)
2247 norepo=True, optionalrepo=True)
2251 def debugdate(ui, date, range=None, **opts):
2248 def debugdate(ui, date, range=None, **opts):
2252 """parse and display a date"""
2249 """parse and display a date"""
2253 if opts["extended"]:
2250 if opts["extended"]:
2254 d = util.parsedate(date, util.extendeddateformats)
2251 d = util.parsedate(date, util.extendeddateformats)
2255 else:
2252 else:
2256 d = util.parsedate(date)
2253 d = util.parsedate(date)
2257 ui.write(("internal: %s %s\n") % d)
2254 ui.write(("internal: %s %s\n") % d)
2258 ui.write(("standard: %s\n") % util.datestr(d))
2255 ui.write(("standard: %s\n") % util.datestr(d))
2259 if range:
2256 if range:
2260 m = util.matchdate(range)
2257 m = util.matchdate(range)
2261 ui.write(("match: %s\n") % m(d[0]))
2258 ui.write(("match: %s\n") % m(d[0]))
2262
2259
2263 @command('debugdiscovery',
2260 @command('debugdiscovery',
2264 [('', 'old', None, _('use old-style discovery')),
2261 [('', 'old', None, _('use old-style discovery')),
2265 ('', 'nonheads', None,
2262 ('', 'nonheads', None,
2266 _('use old-style discovery with non-heads included')),
2263 _('use old-style discovery with non-heads included')),
2267 ] + remoteopts,
2264 ] + remoteopts,
2268 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2265 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2269 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2266 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2270 """runs the changeset discovery protocol in isolation"""
2267 """runs the changeset discovery protocol in isolation"""
2271 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2268 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2272 opts.get('branch'))
2269 opts.get('branch'))
2273 remote = hg.peer(repo, opts, remoteurl)
2270 remote = hg.peer(repo, opts, remoteurl)
2274 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2271 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2275
2272
2276 # make sure tests are repeatable
2273 # make sure tests are repeatable
2277 random.seed(12323)
2274 random.seed(12323)
2278
2275
2279 def doit(localheads, remoteheads, remote=remote):
2276 def doit(localheads, remoteheads, remote=remote):
2280 if opts.get('old'):
2277 if opts.get('old'):
2281 if localheads:
2278 if localheads:
2282 raise error.Abort('cannot use localheads with old style '
2279 raise error.Abort('cannot use localheads with old style '
2283 'discovery')
2280 'discovery')
2284 if not util.safehasattr(remote, 'branches'):
2281 if not util.safehasattr(remote, 'branches'):
2285 # enable in-client legacy support
2282 # enable in-client legacy support
2286 remote = localrepo.locallegacypeer(remote.local())
2283 remote = localrepo.locallegacypeer(remote.local())
2287 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2284 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2288 force=True)
2285 force=True)
2289 common = set(common)
2286 common = set(common)
2290 if not opts.get('nonheads'):
2287 if not opts.get('nonheads'):
2291 ui.write(("unpruned common: %s\n") %
2288 ui.write(("unpruned common: %s\n") %
2292 " ".join(sorted(short(n) for n in common)))
2289 " ".join(sorted(short(n) for n in common)))
2293 dag = dagutil.revlogdag(repo.changelog)
2290 dag = dagutil.revlogdag(repo.changelog)
2294 all = dag.ancestorset(dag.internalizeall(common))
2291 all = dag.ancestorset(dag.internalizeall(common))
2295 common = dag.externalizeall(dag.headsetofconnecteds(all))
2292 common = dag.externalizeall(dag.headsetofconnecteds(all))
2296 else:
2293 else:
2297 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2294 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2298 common = set(common)
2295 common = set(common)
2299 rheads = set(hds)
2296 rheads = set(hds)
2300 lheads = set(repo.heads())
2297 lheads = set(repo.heads())
2301 ui.write(("common heads: %s\n") %
2298 ui.write(("common heads: %s\n") %
2302 " ".join(sorted(short(n) for n in common)))
2299 " ".join(sorted(short(n) for n in common)))
2303 if lheads <= common:
2300 if lheads <= common:
2304 ui.write(("local is subset\n"))
2301 ui.write(("local is subset\n"))
2305 elif rheads <= common:
2302 elif rheads <= common:
2306 ui.write(("remote is subset\n"))
2303 ui.write(("remote is subset\n"))
2307
2304
2308 serverlogs = opts.get('serverlog')
2305 serverlogs = opts.get('serverlog')
2309 if serverlogs:
2306 if serverlogs:
2310 for filename in serverlogs:
2307 for filename in serverlogs:
2311 with open(filename, 'r') as logfile:
2308 with open(filename, 'r') as logfile:
2312 line = logfile.readline()
2309 line = logfile.readline()
2313 while line:
2310 while line:
2314 parts = line.strip().split(';')
2311 parts = line.strip().split(';')
2315 op = parts[1]
2312 op = parts[1]
2316 if op == 'cg':
2313 if op == 'cg':
2317 pass
2314 pass
2318 elif op == 'cgss':
2315 elif op == 'cgss':
2319 doit(parts[2].split(' '), parts[3].split(' '))
2316 doit(parts[2].split(' '), parts[3].split(' '))
2320 elif op == 'unb':
2317 elif op == 'unb':
2321 doit(parts[3].split(' '), parts[2].split(' '))
2318 doit(parts[3].split(' '), parts[2].split(' '))
2322 line = logfile.readline()
2319 line = logfile.readline()
2323 else:
2320 else:
2324 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2321 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2325 opts.get('remote_head'))
2322 opts.get('remote_head'))
2326 localrevs = opts.get('local_head')
2323 localrevs = opts.get('local_head')
2327 doit(localrevs, remoterevs)
2324 doit(localrevs, remoterevs)
2328
2325
2329 @command('debugextensions', formatteropts, [], norepo=True)
2326 @command('debugextensions', formatteropts, [], norepo=True)
2330 def debugextensions(ui, **opts):
2327 def debugextensions(ui, **opts):
2331 '''show information about active extensions'''
2328 '''show information about active extensions'''
2332 exts = extensions.extensions(ui)
2329 exts = extensions.extensions(ui)
2333 fm = ui.formatter('debugextensions', opts)
2330 fm = ui.formatter('debugextensions', opts)
2334 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2331 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2335 extsource = extmod.__file__
2332 extsource = extmod.__file__
2336 exttestedwith = getattr(extmod, 'testedwith', None)
2333 exttestedwith = getattr(extmod, 'testedwith', None)
2337 if exttestedwith is not None:
2334 if exttestedwith is not None:
2338 exttestedwith = exttestedwith.split()
2335 exttestedwith = exttestedwith.split()
2339 extbuglink = getattr(extmod, 'buglink', None)
2336 extbuglink = getattr(extmod, 'buglink', None)
2340
2337
2341 fm.startitem()
2338 fm.startitem()
2342
2339
2343 if ui.quiet or ui.verbose:
2340 if ui.quiet or ui.verbose:
2344 fm.write('name', '%s\n', extname)
2341 fm.write('name', '%s\n', extname)
2345 else:
2342 else:
2346 fm.write('name', '%s', extname)
2343 fm.write('name', '%s', extname)
2347 if not exttestedwith:
2344 if not exttestedwith:
2348 fm.plain(_(' (untested!)\n'))
2345 fm.plain(_(' (untested!)\n'))
2349 else:
2346 else:
2350 if exttestedwith == ['internal'] or \
2347 if exttestedwith == ['internal'] or \
2351 util.version() in exttestedwith:
2348 util.version() in exttestedwith:
2352 fm.plain('\n')
2349 fm.plain('\n')
2353 else:
2350 else:
2354 lasttestedversion = exttestedwith[-1]
2351 lasttestedversion = exttestedwith[-1]
2355 fm.plain(' (%s!)\n' % lasttestedversion)
2352 fm.plain(' (%s!)\n' % lasttestedversion)
2356
2353
2357 fm.condwrite(ui.verbose and extsource, 'source',
2354 fm.condwrite(ui.verbose and extsource, 'source',
2358 _(' location: %s\n'), extsource or "")
2355 _(' location: %s\n'), extsource or "")
2359
2356
2360 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2357 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2361 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2358 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2362
2359
2363 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2360 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2364 _(' bug reporting: %s\n'), extbuglink or "")
2361 _(' bug reporting: %s\n'), extbuglink or "")
2365
2362
2366 fm.end()
2363 fm.end()
2367
2364
2368 @command('debugfileset',
2365 @command('debugfileset',
2369 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2366 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2370 _('[-r REV] FILESPEC'))
2367 _('[-r REV] FILESPEC'))
2371 def debugfileset(ui, repo, expr, **opts):
2368 def debugfileset(ui, repo, expr, **opts):
2372 '''parse and apply a fileset specification'''
2369 '''parse and apply a fileset specification'''
2373 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2370 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2374 if ui.verbose:
2371 if ui.verbose:
2375 tree = fileset.parse(expr)
2372 tree = fileset.parse(expr)
2376 ui.note(fileset.prettyformat(tree), "\n")
2373 ui.note(fileset.prettyformat(tree), "\n")
2377
2374
2378 for f in ctx.getfileset(expr):
2375 for f in ctx.getfileset(expr):
2379 ui.write("%s\n" % f)
2376 ui.write("%s\n" % f)
2380
2377
2381 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2378 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2382 def debugfsinfo(ui, path="."):
2379 def debugfsinfo(ui, path="."):
2383 """show information detected about current filesystem"""
2380 """show information detected about current filesystem"""
2384 util.writefile('.debugfsinfo', '')
2381 util.writefile('.debugfsinfo', '')
2385 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2382 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2386 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2383 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2387 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2384 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2388 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2385 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2389 and 'yes' or 'no'))
2386 and 'yes' or 'no'))
2390 os.unlink('.debugfsinfo')
2387 os.unlink('.debugfsinfo')
2391
2388
2392 @command('debuggetbundle',
2389 @command('debuggetbundle',
2393 [('H', 'head', [], _('id of head node'), _('ID')),
2390 [('H', 'head', [], _('id of head node'), _('ID')),
2394 ('C', 'common', [], _('id of common node'), _('ID')),
2391 ('C', 'common', [], _('id of common node'), _('ID')),
2395 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2392 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2396 _('REPO FILE [-H|-C ID]...'),
2393 _('REPO FILE [-H|-C ID]...'),
2397 norepo=True)
2394 norepo=True)
2398 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2395 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2399 """retrieves a bundle from a repo
2396 """retrieves a bundle from a repo
2400
2397
2401 Every ID must be a full-length hex node id string. Saves the bundle to the
2398 Every ID must be a full-length hex node id string. Saves the bundle to the
2402 given file.
2399 given file.
2403 """
2400 """
2404 repo = hg.peer(ui, opts, repopath)
2401 repo = hg.peer(ui, opts, repopath)
2405 if not repo.capable('getbundle'):
2402 if not repo.capable('getbundle'):
2406 raise error.Abort("getbundle() not supported by target repository")
2403 raise error.Abort("getbundle() not supported by target repository")
2407 args = {}
2404 args = {}
2408 if common:
2405 if common:
2409 args['common'] = [bin(s) for s in common]
2406 args['common'] = [bin(s) for s in common]
2410 if head:
2407 if head:
2411 args['heads'] = [bin(s) for s in head]
2408 args['heads'] = [bin(s) for s in head]
2412 # TODO: get desired bundlecaps from command line.
2409 # TODO: get desired bundlecaps from command line.
2413 args['bundlecaps'] = None
2410 args['bundlecaps'] = None
2414 bundle = repo.getbundle('debug', **args)
2411 bundle = repo.getbundle('debug', **args)
2415
2412
2416 bundletype = opts.get('type', 'bzip2').lower()
2413 bundletype = opts.get('type', 'bzip2').lower()
2417 btypes = {'none': 'HG10UN',
2414 btypes = {'none': 'HG10UN',
2418 'bzip2': 'HG10BZ',
2415 'bzip2': 'HG10BZ',
2419 'gzip': 'HG10GZ',
2416 'gzip': 'HG10GZ',
2420 'bundle2': 'HG20'}
2417 'bundle2': 'HG20'}
2421 bundletype = btypes.get(bundletype)
2418 bundletype = btypes.get(bundletype)
2422 if bundletype not in changegroup.bundletypes:
2419 if bundletype not in changegroup.bundletypes:
2423 raise error.Abort(_('unknown bundle type specified with --type'))
2420 raise error.Abort(_('unknown bundle type specified with --type'))
2424 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2421 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2425
2422
2426 @command('debugignore', [], '[FILE]')
2423 @command('debugignore', [], '[FILE]')
2427 def debugignore(ui, repo, *files, **opts):
2424 def debugignore(ui, repo, *files, **opts):
2428 """display the combined ignore pattern and information about ignored files
2425 """display the combined ignore pattern and information about ignored files
2429
2426
2430 With no argument display the combined ignore pattern.
2427 With no argument display the combined ignore pattern.
2431
2428
2432 Given space separated file names, shows if the given file is ignored and
2429 Given space separated file names, shows if the given file is ignored and
2433 if so, show the ignore rule (file and line number) that matched it.
2430 if so, show the ignore rule (file and line number) that matched it.
2434 """
2431 """
2435 ignore = repo.dirstate._ignore
2432 ignore = repo.dirstate._ignore
2436 if not files:
2433 if not files:
2437 # Show all the patterns
2434 # Show all the patterns
2438 includepat = getattr(ignore, 'includepat', None)
2435 includepat = getattr(ignore, 'includepat', None)
2439 if includepat is not None:
2436 if includepat is not None:
2440 ui.write("%s\n" % includepat)
2437 ui.write("%s\n" % includepat)
2441 else:
2438 else:
2442 raise error.Abort(_("no ignore patterns found"))
2439 raise error.Abort(_("no ignore patterns found"))
2443 else:
2440 else:
2444 for f in files:
2441 for f in files:
2445 ignored = None
2442 ignored = None
2446 ignoredata = None
2443 ignoredata = None
2447 if f != '.':
2444 if f != '.':
2448 if ignore(f):
2445 if ignore(f):
2449 ignored = f
2446 ignored = f
2450 ignoredata = repo.dirstate._ignorefileandline(f)
2447 ignoredata = repo.dirstate._ignorefileandline(f)
2451 else:
2448 else:
2452 for p in util.finddirs(f):
2449 for p in util.finddirs(f):
2453 if ignore(p):
2450 if ignore(p):
2454 ignored = p
2451 ignored = p
2455 ignoredata = repo.dirstate._ignorefileandline(p)
2452 ignoredata = repo.dirstate._ignorefileandline(p)
2456 break
2453 break
2457 if ignored:
2454 if ignored:
2458 if ignored == f:
2455 if ignored == f:
2459 ui.write("%s is ignored\n" % f)
2456 ui.write("%s is ignored\n" % f)
2460 else:
2457 else:
2461 ui.write("%s is ignored because of containing folder %s\n"
2458 ui.write("%s is ignored because of containing folder %s\n"
2462 % (f, ignored))
2459 % (f, ignored))
2463 ignorefile, lineno, line = ignoredata
2460 ignorefile, lineno, line = ignoredata
2464 ui.write("(ignore rule in %s, line %d: '%s')\n"
2461 ui.write("(ignore rule in %s, line %d: '%s')\n"
2465 % (ignorefile, lineno, line))
2462 % (ignorefile, lineno, line))
2466 else:
2463 else:
2467 ui.write("%s is not ignored\n" % f)
2464 ui.write("%s is not ignored\n" % f)
2468
2465
2469 @command('debugindex', debugrevlogopts +
2466 @command('debugindex', debugrevlogopts +
2470 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2467 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2471 _('[-f FORMAT] -c|-m|FILE'),
2468 _('[-f FORMAT] -c|-m|FILE'),
2472 optionalrepo=True)
2469 optionalrepo=True)
2473 def debugindex(ui, repo, file_=None, **opts):
2470 def debugindex(ui, repo, file_=None, **opts):
2474 """dump the contents of an index file"""
2471 """dump the contents of an index file"""
2475 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2472 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2476 format = opts.get('format', 0)
2473 format = opts.get('format', 0)
2477 if format not in (0, 1):
2474 if format not in (0, 1):
2478 raise error.Abort(_("unknown format %d") % format)
2475 raise error.Abort(_("unknown format %d") % format)
2479
2476
2480 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2477 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2481 if generaldelta:
2478 if generaldelta:
2482 basehdr = ' delta'
2479 basehdr = ' delta'
2483 else:
2480 else:
2484 basehdr = ' base'
2481 basehdr = ' base'
2485
2482
2486 if ui.debugflag:
2483 if ui.debugflag:
2487 shortfn = hex
2484 shortfn = hex
2488 else:
2485 else:
2489 shortfn = short
2486 shortfn = short
2490
2487
2491 # There might not be anything in r, so have a sane default
2488 # There might not be anything in r, so have a sane default
2492 idlen = 12
2489 idlen = 12
2493 for i in r:
2490 for i in r:
2494 idlen = len(shortfn(r.node(i)))
2491 idlen = len(shortfn(r.node(i)))
2495 break
2492 break
2496
2493
2497 if format == 0:
2494 if format == 0:
2498 ui.write(" rev offset length " + basehdr + " linkrev"
2495 ui.write(" rev offset length " + basehdr + " linkrev"
2499 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2496 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2500 elif format == 1:
2497 elif format == 1:
2501 ui.write(" rev flag offset length"
2498 ui.write(" rev flag offset length"
2502 " size " + basehdr + " link p1 p2"
2499 " size " + basehdr + " link p1 p2"
2503 " %s\n" % "nodeid".rjust(idlen))
2500 " %s\n" % "nodeid".rjust(idlen))
2504
2501
2505 for i in r:
2502 for i in r:
2506 node = r.node(i)
2503 node = r.node(i)
2507 if generaldelta:
2504 if generaldelta:
2508 base = r.deltaparent(i)
2505 base = r.deltaparent(i)
2509 else:
2506 else:
2510 base = r.chainbase(i)
2507 base = r.chainbase(i)
2511 if format == 0:
2508 if format == 0:
2512 try:
2509 try:
2513 pp = r.parents(node)
2510 pp = r.parents(node)
2514 except Exception:
2511 except Exception:
2515 pp = [nullid, nullid]
2512 pp = [nullid, nullid]
2516 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2513 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2517 i, r.start(i), r.length(i), base, r.linkrev(i),
2514 i, r.start(i), r.length(i), base, r.linkrev(i),
2518 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2515 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2519 elif format == 1:
2516 elif format == 1:
2520 pr = r.parentrevs(i)
2517 pr = r.parentrevs(i)
2521 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2518 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2522 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2519 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2523 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2520 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2524
2521
2525 @command('debugindexdot', debugrevlogopts,
2522 @command('debugindexdot', debugrevlogopts,
2526 _('-c|-m|FILE'), optionalrepo=True)
2523 _('-c|-m|FILE'), optionalrepo=True)
2527 def debugindexdot(ui, repo, file_=None, **opts):
2524 def debugindexdot(ui, repo, file_=None, **opts):
2528 """dump an index DAG as a graphviz dot file"""
2525 """dump an index DAG as a graphviz dot file"""
2529 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2526 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
2530 ui.write(("digraph G {\n"))
2527 ui.write(("digraph G {\n"))
2531 for i in r:
2528 for i in r:
2532 node = r.node(i)
2529 node = r.node(i)
2533 pp = r.parents(node)
2530 pp = r.parents(node)
2534 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2531 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2535 if pp[1] != nullid:
2532 if pp[1] != nullid:
2536 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2533 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2537 ui.write("}\n")
2534 ui.write("}\n")
2538
2535
2539 @command('debugdeltachain',
2536 @command('debugdeltachain',
2540 debugrevlogopts + formatteropts,
2537 debugrevlogopts + formatteropts,
2541 _('-c|-m|FILE'),
2538 _('-c|-m|FILE'),
2542 optionalrepo=True)
2539 optionalrepo=True)
2543 def debugdeltachain(ui, repo, file_=None, **opts):
2540 def debugdeltachain(ui, repo, file_=None, **opts):
2544 """dump information about delta chains in a revlog
2541 """dump information about delta chains in a revlog
2545
2542
2546 Output can be templatized. Available template keywords are:
2543 Output can be templatized. Available template keywords are:
2547
2544
2548 rev revision number
2545 rev revision number
2549 chainid delta chain identifier (numbered by unique base)
2546 chainid delta chain identifier (numbered by unique base)
2550 chainlen delta chain length to this revision
2547 chainlen delta chain length to this revision
2551 prevrev previous revision in delta chain
2548 prevrev previous revision in delta chain
2552 deltatype role of delta / how it was computed
2549 deltatype role of delta / how it was computed
2553 compsize compressed size of revision
2550 compsize compressed size of revision
2554 uncompsize uncompressed size of revision
2551 uncompsize uncompressed size of revision
2555 chainsize total size of compressed revisions in chain
2552 chainsize total size of compressed revisions in chain
2556 chainratio total chain size divided by uncompressed revision size
2553 chainratio total chain size divided by uncompressed revision size
2557 (new delta chains typically start at ratio 2.00)
2554 (new delta chains typically start at ratio 2.00)
2558 lindist linear distance from base revision in delta chain to end
2555 lindist linear distance from base revision in delta chain to end
2559 of this revision
2556 of this revision
2560 extradist total size of revisions not part of this delta chain from
2557 extradist total size of revisions not part of this delta chain from
2561 base of delta chain to end of this revision; a measurement
2558 base of delta chain to end of this revision; a measurement
2562 of how much extra data we need to read/seek across to read
2559 of how much extra data we need to read/seek across to read
2563 the delta chain for this revision
2560 the delta chain for this revision
2564 extraratio extradist divided by chainsize; another representation of
2561 extraratio extradist divided by chainsize; another representation of
2565 how much unrelated data is needed to load this delta chain
2562 how much unrelated data is needed to load this delta chain
2566 """
2563 """
2567 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2564 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
2568 index = r.index
2565 index = r.index
2569 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2566 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2570
2567
2571 def revinfo(rev):
2568 def revinfo(rev):
2572 e = index[rev]
2569 e = index[rev]
2573 compsize = e[1]
2570 compsize = e[1]
2574 uncompsize = e[2]
2571 uncompsize = e[2]
2575 chainsize = 0
2572 chainsize = 0
2576
2573
2577 if generaldelta:
2574 if generaldelta:
2578 if e[3] == e[5]:
2575 if e[3] == e[5]:
2579 deltatype = 'p1'
2576 deltatype = 'p1'
2580 elif e[3] == e[6]:
2577 elif e[3] == e[6]:
2581 deltatype = 'p2'
2578 deltatype = 'p2'
2582 elif e[3] == rev - 1:
2579 elif e[3] == rev - 1:
2583 deltatype = 'prev'
2580 deltatype = 'prev'
2584 elif e[3] == rev:
2581 elif e[3] == rev:
2585 deltatype = 'base'
2582 deltatype = 'base'
2586 else:
2583 else:
2587 deltatype = 'other'
2584 deltatype = 'other'
2588 else:
2585 else:
2589 if e[3] == rev:
2586 if e[3] == rev:
2590 deltatype = 'base'
2587 deltatype = 'base'
2591 else:
2588 else:
2592 deltatype = 'prev'
2589 deltatype = 'prev'
2593
2590
2594 chain = r._deltachain(rev)[0]
2591 chain = r._deltachain(rev)[0]
2595 for iterrev in chain:
2592 for iterrev in chain:
2596 e = index[iterrev]
2593 e = index[iterrev]
2597 chainsize += e[1]
2594 chainsize += e[1]
2598
2595
2599 return compsize, uncompsize, deltatype, chain, chainsize
2596 return compsize, uncompsize, deltatype, chain, chainsize
2600
2597
2601 fm = ui.formatter('debugdeltachain', opts)
2598 fm = ui.formatter('debugdeltachain', opts)
2602
2599
2603 fm.plain(' rev chain# chainlen prev delta '
2600 fm.plain(' rev chain# chainlen prev delta '
2604 'size rawsize chainsize ratio lindist extradist '
2601 'size rawsize chainsize ratio lindist extradist '
2605 'extraratio\n')
2602 'extraratio\n')
2606
2603
2607 chainbases = {}
2604 chainbases = {}
2608 for rev in r:
2605 for rev in r:
2609 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2606 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
2610 chainbase = chain[0]
2607 chainbase = chain[0]
2611 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2608 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
2612 basestart = r.start(chainbase)
2609 basestart = r.start(chainbase)
2613 revstart = r.start(rev)
2610 revstart = r.start(rev)
2614 lineardist = revstart + comp - basestart
2611 lineardist = revstart + comp - basestart
2615 extradist = lineardist - chainsize
2612 extradist = lineardist - chainsize
2616 try:
2613 try:
2617 prevrev = chain[-2]
2614 prevrev = chain[-2]
2618 except IndexError:
2615 except IndexError:
2619 prevrev = -1
2616 prevrev = -1
2620
2617
2621 chainratio = float(chainsize) / float(uncomp)
2618 chainratio = float(chainsize) / float(uncomp)
2622 extraratio = float(extradist) / float(chainsize)
2619 extraratio = float(extradist) / float(chainsize)
2623
2620
2624 fm.startitem()
2621 fm.startitem()
2625 fm.write('rev chainid chainlen prevrev deltatype compsize '
2622 fm.write('rev chainid chainlen prevrev deltatype compsize '
2626 'uncompsize chainsize chainratio lindist extradist '
2623 'uncompsize chainsize chainratio lindist extradist '
2627 'extraratio',
2624 'extraratio',
2628 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2625 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f\n',
2629 rev, chainid, len(chain), prevrev, deltatype, comp,
2626 rev, chainid, len(chain), prevrev, deltatype, comp,
2630 uncomp, chainsize, chainratio, lineardist, extradist,
2627 uncomp, chainsize, chainratio, lineardist, extradist,
2631 extraratio,
2628 extraratio,
2632 rev=rev, chainid=chainid, chainlen=len(chain),
2629 rev=rev, chainid=chainid, chainlen=len(chain),
2633 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2630 prevrev=prevrev, deltatype=deltatype, compsize=comp,
2634 uncompsize=uncomp, chainsize=chainsize,
2631 uncompsize=uncomp, chainsize=chainsize,
2635 chainratio=chainratio, lindist=lineardist,
2632 chainratio=chainratio, lindist=lineardist,
2636 extradist=extradist, extraratio=extraratio)
2633 extradist=extradist, extraratio=extraratio)
2637
2634
2638 fm.end()
2635 fm.end()
2639
2636
2640 @command('debuginstall', [], '', norepo=True)
2637 @command('debuginstall', [], '', norepo=True)
2641 def debuginstall(ui):
2638 def debuginstall(ui):
2642 '''test Mercurial installation
2639 '''test Mercurial installation
2643
2640
2644 Returns 0 on success.
2641 Returns 0 on success.
2645 '''
2642 '''
2646
2643
2647 def writetemp(contents):
2644 def writetemp(contents):
2648 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2645 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2649 f = os.fdopen(fd, "wb")
2646 f = os.fdopen(fd, "wb")
2650 f.write(contents)
2647 f.write(contents)
2651 f.close()
2648 f.close()
2652 return name
2649 return name
2653
2650
2654 problems = 0
2651 problems = 0
2655
2652
2656 # encoding
2653 # encoding
2657 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2654 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2658 try:
2655 try:
2659 encoding.fromlocal("test")
2656 encoding.fromlocal("test")
2660 except error.Abort as inst:
2657 except error.Abort as inst:
2661 ui.write(" %s\n" % inst)
2658 ui.write(" %s\n" % inst)
2662 ui.write(_(" (check that your locale is properly set)\n"))
2659 ui.write(_(" (check that your locale is properly set)\n"))
2663 problems += 1
2660 problems += 1
2664
2661
2665 # Python
2662 # Python
2666 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2663 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2667 ui.status(_("checking Python version (%s)\n")
2664 ui.status(_("checking Python version (%s)\n")
2668 % ("%s.%s.%s" % sys.version_info[:3]))
2665 % ("%s.%s.%s" % sys.version_info[:3]))
2669 ui.status(_("checking Python lib (%s)...\n")
2666 ui.status(_("checking Python lib (%s)...\n")
2670 % os.path.dirname(os.__file__))
2667 % os.path.dirname(os.__file__))
2671
2668
2672 # compiled modules
2669 # compiled modules
2673 ui.status(_("checking installed modules (%s)...\n")
2670 ui.status(_("checking installed modules (%s)...\n")
2674 % os.path.dirname(__file__))
2671 % os.path.dirname(__file__))
2675 try:
2672 try:
2676 import bdiff, mpatch, base85, osutil
2673 import bdiff, mpatch, base85, osutil
2677 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2674 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2678 except Exception as inst:
2675 except Exception as inst:
2679 ui.write(" %s\n" % inst)
2676 ui.write(" %s\n" % inst)
2680 ui.write(_(" One or more extensions could not be found"))
2677 ui.write(_(" One or more extensions could not be found"))
2681 ui.write(_(" (check that you compiled the extensions)\n"))
2678 ui.write(_(" (check that you compiled the extensions)\n"))
2682 problems += 1
2679 problems += 1
2683
2680
2684 # templates
2681 # templates
2685 import templater
2682 import templater
2686 p = templater.templatepaths()
2683 p = templater.templatepaths()
2687 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2684 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2688 if p:
2685 if p:
2689 m = templater.templatepath("map-cmdline.default")
2686 m = templater.templatepath("map-cmdline.default")
2690 if m:
2687 if m:
2691 # template found, check if it is working
2688 # template found, check if it is working
2692 try:
2689 try:
2693 templater.templater(m)
2690 templater.templater(m)
2694 except Exception as inst:
2691 except Exception as inst:
2695 ui.write(" %s\n" % inst)
2692 ui.write(" %s\n" % inst)
2696 p = None
2693 p = None
2697 else:
2694 else:
2698 ui.write(_(" template 'default' not found\n"))
2695 ui.write(_(" template 'default' not found\n"))
2699 p = None
2696 p = None
2700 else:
2697 else:
2701 ui.write(_(" no template directories found\n"))
2698 ui.write(_(" no template directories found\n"))
2702 if not p:
2699 if not p:
2703 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2700 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2704 problems += 1
2701 problems += 1
2705
2702
2706 # editor
2703 # editor
2707 ui.status(_("checking commit editor...\n"))
2704 ui.status(_("checking commit editor...\n"))
2708 editor = ui.geteditor()
2705 editor = ui.geteditor()
2709 editor = util.expandpath(editor)
2706 editor = util.expandpath(editor)
2710 cmdpath = util.findexe(shlex.split(editor)[0])
2707 cmdpath = util.findexe(shlex.split(editor)[0])
2711 if not cmdpath:
2708 if not cmdpath:
2712 if editor == 'vi':
2709 if editor == 'vi':
2713 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2710 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2714 ui.write(_(" (specify a commit editor in your configuration"
2711 ui.write(_(" (specify a commit editor in your configuration"
2715 " file)\n"))
2712 " file)\n"))
2716 else:
2713 else:
2717 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2714 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2718 ui.write(_(" (specify a commit editor in your configuration"
2715 ui.write(_(" (specify a commit editor in your configuration"
2719 " file)\n"))
2716 " file)\n"))
2720 problems += 1
2717 problems += 1
2721
2718
2722 # check username
2719 # check username
2723 ui.status(_("checking username...\n"))
2720 ui.status(_("checking username...\n"))
2724 try:
2721 try:
2725 ui.username()
2722 ui.username()
2726 except error.Abort as e:
2723 except error.Abort as e:
2727 ui.write(" %s\n" % e)
2724 ui.write(" %s\n" % e)
2728 ui.write(_(" (specify a username in your configuration file)\n"))
2725 ui.write(_(" (specify a username in your configuration file)\n"))
2729 problems += 1
2726 problems += 1
2730
2727
2731 if not problems:
2728 if not problems:
2732 ui.status(_("no problems detected\n"))
2729 ui.status(_("no problems detected\n"))
2733 else:
2730 else:
2734 ui.write(_("%s problems detected,"
2731 ui.write(_("%s problems detected,"
2735 " please check your install!\n") % problems)
2732 " please check your install!\n") % problems)
2736
2733
2737 return problems
2734 return problems
2738
2735
2739 @command('debugknown', [], _('REPO ID...'), norepo=True)
2736 @command('debugknown', [], _('REPO ID...'), norepo=True)
2740 def debugknown(ui, repopath, *ids, **opts):
2737 def debugknown(ui, repopath, *ids, **opts):
2741 """test whether node ids are known to a repo
2738 """test whether node ids are known to a repo
2742
2739
2743 Every ID must be a full-length hex node id string. Returns a list of 0s
2740 Every ID must be a full-length hex node id string. Returns a list of 0s
2744 and 1s indicating unknown/known.
2741 and 1s indicating unknown/known.
2745 """
2742 """
2746 repo = hg.peer(ui, opts, repopath)
2743 repo = hg.peer(ui, opts, repopath)
2747 if not repo.capable('known'):
2744 if not repo.capable('known'):
2748 raise error.Abort("known() not supported by target repository")
2745 raise error.Abort("known() not supported by target repository")
2749 flags = repo.known([bin(s) for s in ids])
2746 flags = repo.known([bin(s) for s in ids])
2750 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2747 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2751
2748
2752 @command('debuglabelcomplete', [], _('LABEL...'))
2749 @command('debuglabelcomplete', [], _('LABEL...'))
2753 def debuglabelcomplete(ui, repo, *args):
2750 def debuglabelcomplete(ui, repo, *args):
2754 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2751 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2755 debugnamecomplete(ui, repo, *args)
2752 debugnamecomplete(ui, repo, *args)
2756
2753
2757 @command('debugmergestate', [], '')
2754 @command('debugmergestate', [], '')
2758 def debugmergestate(ui, repo, *args):
2755 def debugmergestate(ui, repo, *args):
2759 """print merge state
2756 """print merge state
2760
2757
2761 Use --verbose to print out information about whether v1 or v2 merge state
2758 Use --verbose to print out information about whether v1 or v2 merge state
2762 was chosen."""
2759 was chosen."""
2763 def _hashornull(h):
2760 def _hashornull(h):
2764 if h == nullhex:
2761 if h == nullhex:
2765 return 'null'
2762 return 'null'
2766 else:
2763 else:
2767 return h
2764 return h
2768
2765
2769 def printrecords(version):
2766 def printrecords(version):
2770 ui.write(('* version %s records\n') % version)
2767 ui.write(('* version %s records\n') % version)
2771 if version == 1:
2768 if version == 1:
2772 records = v1records
2769 records = v1records
2773 else:
2770 else:
2774 records = v2records
2771 records = v2records
2775
2772
2776 for rtype, record in records:
2773 for rtype, record in records:
2777 # pretty print some record types
2774 # pretty print some record types
2778 if rtype == 'L':
2775 if rtype == 'L':
2779 ui.write(('local: %s\n') % record)
2776 ui.write(('local: %s\n') % record)
2780 elif rtype == 'O':
2777 elif rtype == 'O':
2781 ui.write(('other: %s\n') % record)
2778 ui.write(('other: %s\n') % record)
2782 elif rtype == 'm':
2779 elif rtype == 'm':
2783 driver, mdstate = record.split('\0', 1)
2780 driver, mdstate = record.split('\0', 1)
2784 ui.write(('merge driver: %s (state "%s")\n')
2781 ui.write(('merge driver: %s (state "%s")\n')
2785 % (driver, mdstate))
2782 % (driver, mdstate))
2786 elif rtype in 'FDC':
2783 elif rtype in 'FDC':
2787 r = record.split('\0')
2784 r = record.split('\0')
2788 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2785 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2789 if version == 1:
2786 if version == 1:
2790 onode = 'not stored in v1 format'
2787 onode = 'not stored in v1 format'
2791 flags = r[7]
2788 flags = r[7]
2792 else:
2789 else:
2793 onode, flags = r[7:9]
2790 onode, flags = r[7:9]
2794 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2791 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
2795 % (f, rtype, state, _hashornull(hash)))
2792 % (f, rtype, state, _hashornull(hash)))
2796 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2793 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2797 ui.write((' ancestor path: %s (node %s)\n')
2794 ui.write((' ancestor path: %s (node %s)\n')
2798 % (afile, _hashornull(anode)))
2795 % (afile, _hashornull(anode)))
2799 ui.write((' other path: %s (node %s)\n')
2796 ui.write((' other path: %s (node %s)\n')
2800 % (ofile, _hashornull(onode)))
2797 % (ofile, _hashornull(onode)))
2801 else:
2798 else:
2802 ui.write(('unrecognized entry: %s\t%s\n')
2799 ui.write(('unrecognized entry: %s\t%s\n')
2803 % (rtype, record.replace('\0', '\t')))
2800 % (rtype, record.replace('\0', '\t')))
2804
2801
2805 # Avoid mergestate.read() since it may raise an exception for unsupported
2802 # Avoid mergestate.read() since it may raise an exception for unsupported
2806 # merge state records. We shouldn't be doing this, but this is OK since this
2803 # merge state records. We shouldn't be doing this, but this is OK since this
2807 # command is pretty low-level.
2804 # command is pretty low-level.
2808 ms = mergemod.mergestate(repo)
2805 ms = mergemod.mergestate(repo)
2809
2806
2810 # sort so that reasonable information is on top
2807 # sort so that reasonable information is on top
2811 v1records = ms._readrecordsv1()
2808 v1records = ms._readrecordsv1()
2812 v2records = ms._readrecordsv2()
2809 v2records = ms._readrecordsv2()
2813 order = 'LOm'
2810 order = 'LOm'
2814 def key(r):
2811 def key(r):
2815 idx = order.find(r[0])
2812 idx = order.find(r[0])
2816 if idx == -1:
2813 if idx == -1:
2817 return (1, r[1])
2814 return (1, r[1])
2818 else:
2815 else:
2819 return (0, idx)
2816 return (0, idx)
2820 v1records.sort(key=key)
2817 v1records.sort(key=key)
2821 v2records.sort(key=key)
2818 v2records.sort(key=key)
2822
2819
2823 if not v1records and not v2records:
2820 if not v1records and not v2records:
2824 ui.write(('no merge state found\n'))
2821 ui.write(('no merge state found\n'))
2825 elif not v2records:
2822 elif not v2records:
2826 ui.note(('no version 2 merge state\n'))
2823 ui.note(('no version 2 merge state\n'))
2827 printrecords(1)
2824 printrecords(1)
2828 elif ms._v1v2match(v1records, v2records):
2825 elif ms._v1v2match(v1records, v2records):
2829 ui.note(('v1 and v2 states match: using v2\n'))
2826 ui.note(('v1 and v2 states match: using v2\n'))
2830 printrecords(2)
2827 printrecords(2)
2831 else:
2828 else:
2832 ui.note(('v1 and v2 states mismatch: using v1\n'))
2829 ui.note(('v1 and v2 states mismatch: using v1\n'))
2833 printrecords(1)
2830 printrecords(1)
2834 if ui.verbose:
2831 if ui.verbose:
2835 printrecords(2)
2832 printrecords(2)
2836
2833
2837 @command('debugnamecomplete', [], _('NAME...'))
2834 @command('debugnamecomplete', [], _('NAME...'))
2838 def debugnamecomplete(ui, repo, *args):
2835 def debugnamecomplete(ui, repo, *args):
2839 '''complete "names" - tags, open branch names, bookmark names'''
2836 '''complete "names" - tags, open branch names, bookmark names'''
2840
2837
2841 names = set()
2838 names = set()
2842 # since we previously only listed open branches, we will handle that
2839 # since we previously only listed open branches, we will handle that
2843 # specially (after this for loop)
2840 # specially (after this for loop)
2844 for name, ns in repo.names.iteritems():
2841 for name, ns in repo.names.iteritems():
2845 if name != 'branches':
2842 if name != 'branches':
2846 names.update(ns.listnames(repo))
2843 names.update(ns.listnames(repo))
2847 names.update(tag for (tag, heads, tip, closed)
2844 names.update(tag for (tag, heads, tip, closed)
2848 in repo.branchmap().iterbranches() if not closed)
2845 in repo.branchmap().iterbranches() if not closed)
2849 completions = set()
2846 completions = set()
2850 if not args:
2847 if not args:
2851 args = ['']
2848 args = ['']
2852 for a in args:
2849 for a in args:
2853 completions.update(n for n in names if n.startswith(a))
2850 completions.update(n for n in names if n.startswith(a))
2854 ui.write('\n'.join(sorted(completions)))
2851 ui.write('\n'.join(sorted(completions)))
2855 ui.write('\n')
2852 ui.write('\n')
2856
2853
2857 @command('debuglocks',
2854 @command('debuglocks',
2858 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2855 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2859 ('W', 'force-wlock', None,
2856 ('W', 'force-wlock', None,
2860 _('free the working state lock (DANGEROUS)'))],
2857 _('free the working state lock (DANGEROUS)'))],
2861 _('[OPTION]...'))
2858 _('[OPTION]...'))
2862 def debuglocks(ui, repo, **opts):
2859 def debuglocks(ui, repo, **opts):
2863 """show or modify state of locks
2860 """show or modify state of locks
2864
2861
2865 By default, this command will show which locks are held. This
2862 By default, this command will show which locks are held. This
2866 includes the user and process holding the lock, the amount of time
2863 includes the user and process holding the lock, the amount of time
2867 the lock has been held, and the machine name where the process is
2864 the lock has been held, and the machine name where the process is
2868 running if it's not local.
2865 running if it's not local.
2869
2866
2870 Locks protect the integrity of Mercurial's data, so should be
2867 Locks protect the integrity of Mercurial's data, so should be
2871 treated with care. System crashes or other interruptions may cause
2868 treated with care. System crashes or other interruptions may cause
2872 locks to not be properly released, though Mercurial will usually
2869 locks to not be properly released, though Mercurial will usually
2873 detect and remove such stale locks automatically.
2870 detect and remove such stale locks automatically.
2874
2871
2875 However, detecting stale locks may not always be possible (for
2872 However, detecting stale locks may not always be possible (for
2876 instance, on a shared filesystem). Removing locks may also be
2873 instance, on a shared filesystem). Removing locks may also be
2877 blocked by filesystem permissions.
2874 blocked by filesystem permissions.
2878
2875
2879 Returns 0 if no locks are held.
2876 Returns 0 if no locks are held.
2880
2877
2881 """
2878 """
2882
2879
2883 if opts.get('force_lock'):
2880 if opts.get('force_lock'):
2884 repo.svfs.unlink('lock')
2881 repo.svfs.unlink('lock')
2885 if opts.get('force_wlock'):
2882 if opts.get('force_wlock'):
2886 repo.vfs.unlink('wlock')
2883 repo.vfs.unlink('wlock')
2887 if opts.get('force_lock') or opts.get('force_lock'):
2884 if opts.get('force_lock') or opts.get('force_lock'):
2888 return 0
2885 return 0
2889
2886
2890 now = time.time()
2887 now = time.time()
2891 held = 0
2888 held = 0
2892
2889
2893 def report(vfs, name, method):
2890 def report(vfs, name, method):
2894 # this causes stale locks to get reaped for more accurate reporting
2891 # this causes stale locks to get reaped for more accurate reporting
2895 try:
2892 try:
2896 l = method(False)
2893 l = method(False)
2897 except error.LockHeld:
2894 except error.LockHeld:
2898 l = None
2895 l = None
2899
2896
2900 if l:
2897 if l:
2901 l.release()
2898 l.release()
2902 else:
2899 else:
2903 try:
2900 try:
2904 stat = vfs.lstat(name)
2901 stat = vfs.lstat(name)
2905 age = now - stat.st_mtime
2902 age = now - stat.st_mtime
2906 user = util.username(stat.st_uid)
2903 user = util.username(stat.st_uid)
2907 locker = vfs.readlock(name)
2904 locker = vfs.readlock(name)
2908 if ":" in locker:
2905 if ":" in locker:
2909 host, pid = locker.split(':')
2906 host, pid = locker.split(':')
2910 if host == socket.gethostname():
2907 if host == socket.gethostname():
2911 locker = 'user %s, process %s' % (user, pid)
2908 locker = 'user %s, process %s' % (user, pid)
2912 else:
2909 else:
2913 locker = 'user %s, process %s, host %s' \
2910 locker = 'user %s, process %s, host %s' \
2914 % (user, pid, host)
2911 % (user, pid, host)
2915 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2912 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2916 return 1
2913 return 1
2917 except OSError as e:
2914 except OSError as e:
2918 if e.errno != errno.ENOENT:
2915 if e.errno != errno.ENOENT:
2919 raise
2916 raise
2920
2917
2921 ui.write("%-6s free\n" % (name + ":"))
2918 ui.write("%-6s free\n" % (name + ":"))
2922 return 0
2919 return 0
2923
2920
2924 held += report(repo.svfs, "lock", repo.lock)
2921 held += report(repo.svfs, "lock", repo.lock)
2925 held += report(repo.vfs, "wlock", repo.wlock)
2922 held += report(repo.vfs, "wlock", repo.wlock)
2926
2923
2927 return held
2924 return held
2928
2925
2929 @command('debugobsolete',
2926 @command('debugobsolete',
2930 [('', 'flags', 0, _('markers flag')),
2927 [('', 'flags', 0, _('markers flag')),
2931 ('', 'record-parents', False,
2928 ('', 'record-parents', False,
2932 _('record parent information for the precursor')),
2929 _('record parent information for the precursor')),
2933 ('r', 'rev', [], _('display markers relevant to REV')),
2930 ('r', 'rev', [], _('display markers relevant to REV')),
2934 ] + commitopts2,
2931 ] + commitopts2,
2935 _('[OBSOLETED [REPLACEMENT ...]]'))
2932 _('[OBSOLETED [REPLACEMENT ...]]'))
2936 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2933 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2937 """create arbitrary obsolete marker
2934 """create arbitrary obsolete marker
2938
2935
2939 With no arguments, displays the list of obsolescence markers."""
2936 With no arguments, displays the list of obsolescence markers."""
2940
2937
2941 def parsenodeid(s):
2938 def parsenodeid(s):
2942 try:
2939 try:
2943 # We do not use revsingle/revrange functions here to accept
2940 # We do not use revsingle/revrange functions here to accept
2944 # arbitrary node identifiers, possibly not present in the
2941 # arbitrary node identifiers, possibly not present in the
2945 # local repository.
2942 # local repository.
2946 n = bin(s)
2943 n = bin(s)
2947 if len(n) != len(nullid):
2944 if len(n) != len(nullid):
2948 raise TypeError()
2945 raise TypeError()
2949 return n
2946 return n
2950 except TypeError:
2947 except TypeError:
2951 raise error.Abort('changeset references must be full hexadecimal '
2948 raise error.Abort('changeset references must be full hexadecimal '
2952 'node identifiers')
2949 'node identifiers')
2953
2950
2954 if precursor is not None:
2951 if precursor is not None:
2955 if opts['rev']:
2952 if opts['rev']:
2956 raise error.Abort('cannot select revision when creating marker')
2953 raise error.Abort('cannot select revision when creating marker')
2957 metadata = {}
2954 metadata = {}
2958 metadata['user'] = opts['user'] or ui.username()
2955 metadata['user'] = opts['user'] or ui.username()
2959 succs = tuple(parsenodeid(succ) for succ in successors)
2956 succs = tuple(parsenodeid(succ) for succ in successors)
2960 l = repo.lock()
2957 l = repo.lock()
2961 try:
2958 try:
2962 tr = repo.transaction('debugobsolete')
2959 tr = repo.transaction('debugobsolete')
2963 try:
2960 try:
2964 date = opts.get('date')
2961 date = opts.get('date')
2965 if date:
2962 if date:
2966 date = util.parsedate(date)
2963 date = util.parsedate(date)
2967 else:
2964 else:
2968 date = None
2965 date = None
2969 prec = parsenodeid(precursor)
2966 prec = parsenodeid(precursor)
2970 parents = None
2967 parents = None
2971 if opts['record_parents']:
2968 if opts['record_parents']:
2972 if prec not in repo.unfiltered():
2969 if prec not in repo.unfiltered():
2973 raise error.Abort('cannot used --record-parents on '
2970 raise error.Abort('cannot used --record-parents on '
2974 'unknown changesets')
2971 'unknown changesets')
2975 parents = repo.unfiltered()[prec].parents()
2972 parents = repo.unfiltered()[prec].parents()
2976 parents = tuple(p.node() for p in parents)
2973 parents = tuple(p.node() for p in parents)
2977 repo.obsstore.create(tr, prec, succs, opts['flags'],
2974 repo.obsstore.create(tr, prec, succs, opts['flags'],
2978 parents=parents, date=date,
2975 parents=parents, date=date,
2979 metadata=metadata)
2976 metadata=metadata)
2980 tr.close()
2977 tr.close()
2981 except ValueError as exc:
2978 except ValueError as exc:
2982 raise error.Abort(_('bad obsmarker input: %s') % exc)
2979 raise error.Abort(_('bad obsmarker input: %s') % exc)
2983 finally:
2980 finally:
2984 tr.release()
2981 tr.release()
2985 finally:
2982 finally:
2986 l.release()
2983 l.release()
2987 else:
2984 else:
2988 if opts['rev']:
2985 if opts['rev']:
2989 revs = scmutil.revrange(repo, opts['rev'])
2986 revs = scmutil.revrange(repo, opts['rev'])
2990 nodes = [repo[r].node() for r in revs]
2987 nodes = [repo[r].node() for r in revs]
2991 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2988 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2992 markers.sort(key=lambda x: x._data)
2989 markers.sort(key=lambda x: x._data)
2993 else:
2990 else:
2994 markers = obsolete.getmarkers(repo)
2991 markers = obsolete.getmarkers(repo)
2995
2992
2996 for m in markers:
2993 for m in markers:
2997 cmdutil.showmarker(ui, m)
2994 cmdutil.showmarker(ui, m)
2998
2995
2999 @command('debugpathcomplete',
2996 @command('debugpathcomplete',
3000 [('f', 'full', None, _('complete an entire path')),
2997 [('f', 'full', None, _('complete an entire path')),
3001 ('n', 'normal', None, _('show only normal files')),
2998 ('n', 'normal', None, _('show only normal files')),
3002 ('a', 'added', None, _('show only added files')),
2999 ('a', 'added', None, _('show only added files')),
3003 ('r', 'removed', None, _('show only removed files'))],
3000 ('r', 'removed', None, _('show only removed files'))],
3004 _('FILESPEC...'))
3001 _('FILESPEC...'))
3005 def debugpathcomplete(ui, repo, *specs, **opts):
3002 def debugpathcomplete(ui, repo, *specs, **opts):
3006 '''complete part or all of a tracked path
3003 '''complete part or all of a tracked path
3007
3004
3008 This command supports shells that offer path name completion. It
3005 This command supports shells that offer path name completion. It
3009 currently completes only files already known to the dirstate.
3006 currently completes only files already known to the dirstate.
3010
3007
3011 Completion extends only to the next path segment unless
3008 Completion extends only to the next path segment unless
3012 --full is specified, in which case entire paths are used.'''
3009 --full is specified, in which case entire paths are used.'''
3013
3010
3014 def complete(path, acceptable):
3011 def complete(path, acceptable):
3015 dirstate = repo.dirstate
3012 dirstate = repo.dirstate
3016 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3013 spec = os.path.normpath(os.path.join(os.getcwd(), path))
3017 rootdir = repo.root + os.sep
3014 rootdir = repo.root + os.sep
3018 if spec != repo.root and not spec.startswith(rootdir):
3015 if spec != repo.root and not spec.startswith(rootdir):
3019 return [], []
3016 return [], []
3020 if os.path.isdir(spec):
3017 if os.path.isdir(spec):
3021 spec += '/'
3018 spec += '/'
3022 spec = spec[len(rootdir):]
3019 spec = spec[len(rootdir):]
3023 fixpaths = os.sep != '/'
3020 fixpaths = os.sep != '/'
3024 if fixpaths:
3021 if fixpaths:
3025 spec = spec.replace(os.sep, '/')
3022 spec = spec.replace(os.sep, '/')
3026 speclen = len(spec)
3023 speclen = len(spec)
3027 fullpaths = opts['full']
3024 fullpaths = opts['full']
3028 files, dirs = set(), set()
3025 files, dirs = set(), set()
3029 adddir, addfile = dirs.add, files.add
3026 adddir, addfile = dirs.add, files.add
3030 for f, st in dirstate.iteritems():
3027 for f, st in dirstate.iteritems():
3031 if f.startswith(spec) and st[0] in acceptable:
3028 if f.startswith(spec) and st[0] in acceptable:
3032 if fixpaths:
3029 if fixpaths:
3033 f = f.replace('/', os.sep)
3030 f = f.replace('/', os.sep)
3034 if fullpaths:
3031 if fullpaths:
3035 addfile(f)
3032 addfile(f)
3036 continue
3033 continue
3037 s = f.find(os.sep, speclen)
3034 s = f.find(os.sep, speclen)
3038 if s >= 0:
3035 if s >= 0:
3039 adddir(f[:s])
3036 adddir(f[:s])
3040 else:
3037 else:
3041 addfile(f)
3038 addfile(f)
3042 return files, dirs
3039 return files, dirs
3043
3040
3044 acceptable = ''
3041 acceptable = ''
3045 if opts['normal']:
3042 if opts['normal']:
3046 acceptable += 'nm'
3043 acceptable += 'nm'
3047 if opts['added']:
3044 if opts['added']:
3048 acceptable += 'a'
3045 acceptable += 'a'
3049 if opts['removed']:
3046 if opts['removed']:
3050 acceptable += 'r'
3047 acceptable += 'r'
3051 cwd = repo.getcwd()
3048 cwd = repo.getcwd()
3052 if not specs:
3049 if not specs:
3053 specs = ['.']
3050 specs = ['.']
3054
3051
3055 files, dirs = set(), set()
3052 files, dirs = set(), set()
3056 for spec in specs:
3053 for spec in specs:
3057 f, d = complete(spec, acceptable or 'nmar')
3054 f, d = complete(spec, acceptable or 'nmar')
3058 files.update(f)
3055 files.update(f)
3059 dirs.update(d)
3056 dirs.update(d)
3060 files.update(dirs)
3057 files.update(dirs)
3061 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3058 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
3062 ui.write('\n')
3059 ui.write('\n')
3063
3060
3064 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3061 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
3065 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3062 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
3066 '''access the pushkey key/value protocol
3063 '''access the pushkey key/value protocol
3067
3064
3068 With two args, list the keys in the given namespace.
3065 With two args, list the keys in the given namespace.
3069
3066
3070 With five args, set a key to new if it currently is set to old.
3067 With five args, set a key to new if it currently is set to old.
3071 Reports success or failure.
3068 Reports success or failure.
3072 '''
3069 '''
3073
3070
3074 target = hg.peer(ui, {}, repopath)
3071 target = hg.peer(ui, {}, repopath)
3075 if keyinfo:
3072 if keyinfo:
3076 key, old, new = keyinfo
3073 key, old, new = keyinfo
3077 r = target.pushkey(namespace, key, old, new)
3074 r = target.pushkey(namespace, key, old, new)
3078 ui.status(str(r) + '\n')
3075 ui.status(str(r) + '\n')
3079 return not r
3076 return not r
3080 else:
3077 else:
3081 for k, v in sorted(target.listkeys(namespace).iteritems()):
3078 for k, v in sorted(target.listkeys(namespace).iteritems()):
3082 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3079 ui.write("%s\t%s\n" % (k.encode('string-escape'),
3083 v.encode('string-escape')))
3080 v.encode('string-escape')))
3084
3081
3085 @command('debugpvec', [], _('A B'))
3082 @command('debugpvec', [], _('A B'))
3086 def debugpvec(ui, repo, a, b=None):
3083 def debugpvec(ui, repo, a, b=None):
3087 ca = scmutil.revsingle(repo, a)
3084 ca = scmutil.revsingle(repo, a)
3088 cb = scmutil.revsingle(repo, b)
3085 cb = scmutil.revsingle(repo, b)
3089 pa = pvec.ctxpvec(ca)
3086 pa = pvec.ctxpvec(ca)
3090 pb = pvec.ctxpvec(cb)
3087 pb = pvec.ctxpvec(cb)
3091 if pa == pb:
3088 if pa == pb:
3092 rel = "="
3089 rel = "="
3093 elif pa > pb:
3090 elif pa > pb:
3094 rel = ">"
3091 rel = ">"
3095 elif pa < pb:
3092 elif pa < pb:
3096 rel = "<"
3093 rel = "<"
3097 elif pa | pb:
3094 elif pa | pb:
3098 rel = "|"
3095 rel = "|"
3099 ui.write(_("a: %s\n") % pa)
3096 ui.write(_("a: %s\n") % pa)
3100 ui.write(_("b: %s\n") % pb)
3097 ui.write(_("b: %s\n") % pb)
3101 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3098 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
3102 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3099 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
3103 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3100 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
3104 pa.distance(pb), rel))
3101 pa.distance(pb), rel))
3105
3102
3106 @command('debugrebuilddirstate|debugrebuildstate',
3103 @command('debugrebuilddirstate|debugrebuildstate',
3107 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3104 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
3108 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3105 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
3109 'the working copy parent')),
3106 'the working copy parent')),
3110 ],
3107 ],
3111 _('[-r REV]'))
3108 _('[-r REV]'))
3112 def debugrebuilddirstate(ui, repo, rev, **opts):
3109 def debugrebuilddirstate(ui, repo, rev, **opts):
3113 """rebuild the dirstate as it would look like for the given revision
3110 """rebuild the dirstate as it would look like for the given revision
3114
3111
3115 If no revision is specified the first current parent will be used.
3112 If no revision is specified the first current parent will be used.
3116
3113
3117 The dirstate will be set to the files of the given revision.
3114 The dirstate will be set to the files of the given revision.
3118 The actual working directory content or existing dirstate
3115 The actual working directory content or existing dirstate
3119 information such as adds or removes is not considered.
3116 information such as adds or removes is not considered.
3120
3117
3121 ``minimal`` will only rebuild the dirstate status for files that claim to be
3118 ``minimal`` will only rebuild the dirstate status for files that claim to be
3122 tracked but are not in the parent manifest, or that exist in the parent
3119 tracked but are not in the parent manifest, or that exist in the parent
3123 manifest but are not in the dirstate. It will not change adds, removes, or
3120 manifest but are not in the dirstate. It will not change adds, removes, or
3124 modified files that are in the working copy parent.
3121 modified files that are in the working copy parent.
3125
3122
3126 One use of this command is to make the next :hg:`status` invocation
3123 One use of this command is to make the next :hg:`status` invocation
3127 check the actual file content.
3124 check the actual file content.
3128 """
3125 """
3129 ctx = scmutil.revsingle(repo, rev)
3126 ctx = scmutil.revsingle(repo, rev)
3130 wlock = repo.wlock()
3127 wlock = repo.wlock()
3131 try:
3128 try:
3132 dirstate = repo.dirstate
3129 dirstate = repo.dirstate
3133 changedfiles = None
3130 changedfiles = None
3134 # See command doc for what minimal does.
3131 # See command doc for what minimal does.
3135 if opts.get('minimal'):
3132 if opts.get('minimal'):
3136 manifestfiles = set(ctx.manifest().keys())
3133 manifestfiles = set(ctx.manifest().keys())
3137 dirstatefiles = set(dirstate)
3134 dirstatefiles = set(dirstate)
3138 manifestonly = manifestfiles - dirstatefiles
3135 manifestonly = manifestfiles - dirstatefiles
3139 dsonly = dirstatefiles - manifestfiles
3136 dsonly = dirstatefiles - manifestfiles
3140 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3137 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
3141 changedfiles = manifestonly | dsnotadded
3138 changedfiles = manifestonly | dsnotadded
3142
3139
3143 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3140 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
3144 finally:
3141 finally:
3145 wlock.release()
3142 wlock.release()
3146
3143
3147 @command('debugrebuildfncache', [], '')
3144 @command('debugrebuildfncache', [], '')
3148 def debugrebuildfncache(ui, repo):
3145 def debugrebuildfncache(ui, repo):
3149 """rebuild the fncache file"""
3146 """rebuild the fncache file"""
3150 repair.rebuildfncache(ui, repo)
3147 repair.rebuildfncache(ui, repo)
3151
3148
3152 @command('debugrename',
3149 @command('debugrename',
3153 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3150 [('r', 'rev', '', _('revision to debug'), _('REV'))],
3154 _('[-r REV] FILE'))
3151 _('[-r REV] FILE'))
3155 def debugrename(ui, repo, file1, *pats, **opts):
3152 def debugrename(ui, repo, file1, *pats, **opts):
3156 """dump rename information"""
3153 """dump rename information"""
3157
3154
3158 ctx = scmutil.revsingle(repo, opts.get('rev'))
3155 ctx = scmutil.revsingle(repo, opts.get('rev'))
3159 m = scmutil.match(ctx, (file1,) + pats, opts)
3156 m = scmutil.match(ctx, (file1,) + pats, opts)
3160 for abs in ctx.walk(m):
3157 for abs in ctx.walk(m):
3161 fctx = ctx[abs]
3158 fctx = ctx[abs]
3162 o = fctx.filelog().renamed(fctx.filenode())
3159 o = fctx.filelog().renamed(fctx.filenode())
3163 rel = m.rel(abs)
3160 rel = m.rel(abs)
3164 if o:
3161 if o:
3165 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3162 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
3166 else:
3163 else:
3167 ui.write(_("%s not renamed\n") % rel)
3164 ui.write(_("%s not renamed\n") % rel)
3168
3165
3169 @command('debugrevlog', debugrevlogopts +
3166 @command('debugrevlog', debugrevlogopts +
3170 [('d', 'dump', False, _('dump index data'))],
3167 [('d', 'dump', False, _('dump index data'))],
3171 _('-c|-m|FILE'),
3168 _('-c|-m|FILE'),
3172 optionalrepo=True)
3169 optionalrepo=True)
3173 def debugrevlog(ui, repo, file_=None, **opts):
3170 def debugrevlog(ui, repo, file_=None, **opts):
3174 """show data and statistics about a revlog"""
3171 """show data and statistics about a revlog"""
3175 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3172 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
3176
3173
3177 if opts.get("dump"):
3174 if opts.get("dump"):
3178 numrevs = len(r)
3175 numrevs = len(r)
3179 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3176 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
3180 " rawsize totalsize compression heads chainlen\n")
3177 " rawsize totalsize compression heads chainlen\n")
3181 ts = 0
3178 ts = 0
3182 heads = set()
3179 heads = set()
3183
3180
3184 for rev in xrange(numrevs):
3181 for rev in xrange(numrevs):
3185 dbase = r.deltaparent(rev)
3182 dbase = r.deltaparent(rev)
3186 if dbase == -1:
3183 if dbase == -1:
3187 dbase = rev
3184 dbase = rev
3188 cbase = r.chainbase(rev)
3185 cbase = r.chainbase(rev)
3189 clen = r.chainlen(rev)
3186 clen = r.chainlen(rev)
3190 p1, p2 = r.parentrevs(rev)
3187 p1, p2 = r.parentrevs(rev)
3191 rs = r.rawsize(rev)
3188 rs = r.rawsize(rev)
3192 ts = ts + rs
3189 ts = ts + rs
3193 heads -= set(r.parentrevs(rev))
3190 heads -= set(r.parentrevs(rev))
3194 heads.add(rev)
3191 heads.add(rev)
3195 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3192 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
3196 "%11d %5d %8d\n" %
3193 "%11d %5d %8d\n" %
3197 (rev, p1, p2, r.start(rev), r.end(rev),
3194 (rev, p1, p2, r.start(rev), r.end(rev),
3198 r.start(dbase), r.start(cbase),
3195 r.start(dbase), r.start(cbase),
3199 r.start(p1), r.start(p2),
3196 r.start(p1), r.start(p2),
3200 rs, ts, ts / r.end(rev), len(heads), clen))
3197 rs, ts, ts / r.end(rev), len(heads), clen))
3201 return 0
3198 return 0
3202
3199
3203 v = r.version
3200 v = r.version
3204 format = v & 0xFFFF
3201 format = v & 0xFFFF
3205 flags = []
3202 flags = []
3206 gdelta = False
3203 gdelta = False
3207 if v & revlog.REVLOGNGINLINEDATA:
3204 if v & revlog.REVLOGNGINLINEDATA:
3208 flags.append('inline')
3205 flags.append('inline')
3209 if v & revlog.REVLOGGENERALDELTA:
3206 if v & revlog.REVLOGGENERALDELTA:
3210 gdelta = True
3207 gdelta = True
3211 flags.append('generaldelta')
3208 flags.append('generaldelta')
3212 if not flags:
3209 if not flags:
3213 flags = ['(none)']
3210 flags = ['(none)']
3214
3211
3215 nummerges = 0
3212 nummerges = 0
3216 numfull = 0
3213 numfull = 0
3217 numprev = 0
3214 numprev = 0
3218 nump1 = 0
3215 nump1 = 0
3219 nump2 = 0
3216 nump2 = 0
3220 numother = 0
3217 numother = 0
3221 nump1prev = 0
3218 nump1prev = 0
3222 nump2prev = 0
3219 nump2prev = 0
3223 chainlengths = []
3220 chainlengths = []
3224
3221
3225 datasize = [None, 0, 0L]
3222 datasize = [None, 0, 0L]
3226 fullsize = [None, 0, 0L]
3223 fullsize = [None, 0, 0L]
3227 deltasize = [None, 0, 0L]
3224 deltasize = [None, 0, 0L]
3228
3225
3229 def addsize(size, l):
3226 def addsize(size, l):
3230 if l[0] is None or size < l[0]:
3227 if l[0] is None or size < l[0]:
3231 l[0] = size
3228 l[0] = size
3232 if size > l[1]:
3229 if size > l[1]:
3233 l[1] = size
3230 l[1] = size
3234 l[2] += size
3231 l[2] += size
3235
3232
3236 numrevs = len(r)
3233 numrevs = len(r)
3237 for rev in xrange(numrevs):
3234 for rev in xrange(numrevs):
3238 p1, p2 = r.parentrevs(rev)
3235 p1, p2 = r.parentrevs(rev)
3239 delta = r.deltaparent(rev)
3236 delta = r.deltaparent(rev)
3240 if format > 0:
3237 if format > 0:
3241 addsize(r.rawsize(rev), datasize)
3238 addsize(r.rawsize(rev), datasize)
3242 if p2 != nullrev:
3239 if p2 != nullrev:
3243 nummerges += 1
3240 nummerges += 1
3244 size = r.length(rev)
3241 size = r.length(rev)
3245 if delta == nullrev:
3242 if delta == nullrev:
3246 chainlengths.append(0)
3243 chainlengths.append(0)
3247 numfull += 1
3244 numfull += 1
3248 addsize(size, fullsize)
3245 addsize(size, fullsize)
3249 else:
3246 else:
3250 chainlengths.append(chainlengths[delta] + 1)
3247 chainlengths.append(chainlengths[delta] + 1)
3251 addsize(size, deltasize)
3248 addsize(size, deltasize)
3252 if delta == rev - 1:
3249 if delta == rev - 1:
3253 numprev += 1
3250 numprev += 1
3254 if delta == p1:
3251 if delta == p1:
3255 nump1prev += 1
3252 nump1prev += 1
3256 elif delta == p2:
3253 elif delta == p2:
3257 nump2prev += 1
3254 nump2prev += 1
3258 elif delta == p1:
3255 elif delta == p1:
3259 nump1 += 1
3256 nump1 += 1
3260 elif delta == p2:
3257 elif delta == p2:
3261 nump2 += 1
3258 nump2 += 1
3262 elif delta != nullrev:
3259 elif delta != nullrev:
3263 numother += 1
3260 numother += 1
3264
3261
3265 # Adjust size min value for empty cases
3262 # Adjust size min value for empty cases
3266 for size in (datasize, fullsize, deltasize):
3263 for size in (datasize, fullsize, deltasize):
3267 if size[0] is None:
3264 if size[0] is None:
3268 size[0] = 0
3265 size[0] = 0
3269
3266
3270 numdeltas = numrevs - numfull
3267 numdeltas = numrevs - numfull
3271 numoprev = numprev - nump1prev - nump2prev
3268 numoprev = numprev - nump1prev - nump2prev
3272 totalrawsize = datasize[2]
3269 totalrawsize = datasize[2]
3273 datasize[2] /= numrevs
3270 datasize[2] /= numrevs
3274 fulltotal = fullsize[2]
3271 fulltotal = fullsize[2]
3275 fullsize[2] /= numfull
3272 fullsize[2] /= numfull
3276 deltatotal = deltasize[2]
3273 deltatotal = deltasize[2]
3277 if numrevs - numfull > 0:
3274 if numrevs - numfull > 0:
3278 deltasize[2] /= numrevs - numfull
3275 deltasize[2] /= numrevs - numfull
3279 totalsize = fulltotal + deltatotal
3276 totalsize = fulltotal + deltatotal
3280 avgchainlen = sum(chainlengths) / numrevs
3277 avgchainlen = sum(chainlengths) / numrevs
3281 maxchainlen = max(chainlengths)
3278 maxchainlen = max(chainlengths)
3282 compratio = 1
3279 compratio = 1
3283 if totalsize:
3280 if totalsize:
3284 compratio = totalrawsize / totalsize
3281 compratio = totalrawsize / totalsize
3285
3282
3286 basedfmtstr = '%%%dd\n'
3283 basedfmtstr = '%%%dd\n'
3287 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3284 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3288
3285
3289 def dfmtstr(max):
3286 def dfmtstr(max):
3290 return basedfmtstr % len(str(max))
3287 return basedfmtstr % len(str(max))
3291 def pcfmtstr(max, padding=0):
3288 def pcfmtstr(max, padding=0):
3292 return basepcfmtstr % (len(str(max)), ' ' * padding)
3289 return basepcfmtstr % (len(str(max)), ' ' * padding)
3293
3290
3294 def pcfmt(value, total):
3291 def pcfmt(value, total):
3295 if total:
3292 if total:
3296 return (value, 100 * float(value) / total)
3293 return (value, 100 * float(value) / total)
3297 else:
3294 else:
3298 return value, 100.0
3295 return value, 100.0
3299
3296
3300 ui.write(('format : %d\n') % format)
3297 ui.write(('format : %d\n') % format)
3301 ui.write(('flags : %s\n') % ', '.join(flags))
3298 ui.write(('flags : %s\n') % ', '.join(flags))
3302
3299
3303 ui.write('\n')
3300 ui.write('\n')
3304 fmt = pcfmtstr(totalsize)
3301 fmt = pcfmtstr(totalsize)
3305 fmt2 = dfmtstr(totalsize)
3302 fmt2 = dfmtstr(totalsize)
3306 ui.write(('revisions : ') + fmt2 % numrevs)
3303 ui.write(('revisions : ') + fmt2 % numrevs)
3307 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3304 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3308 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3305 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3309 ui.write(('revisions : ') + fmt2 % numrevs)
3306 ui.write(('revisions : ') + fmt2 % numrevs)
3310 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3307 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3311 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3308 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3312 ui.write(('revision size : ') + fmt2 % totalsize)
3309 ui.write(('revision size : ') + fmt2 % totalsize)
3313 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3310 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3314 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3311 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3315
3312
3316 ui.write('\n')
3313 ui.write('\n')
3317 fmt = dfmtstr(max(avgchainlen, compratio))
3314 fmt = dfmtstr(max(avgchainlen, compratio))
3318 ui.write(('avg chain length : ') + fmt % avgchainlen)
3315 ui.write(('avg chain length : ') + fmt % avgchainlen)
3319 ui.write(('max chain length : ') + fmt % maxchainlen)
3316 ui.write(('max chain length : ') + fmt % maxchainlen)
3320 ui.write(('compression ratio : ') + fmt % compratio)
3317 ui.write(('compression ratio : ') + fmt % compratio)
3321
3318
3322 if format > 0:
3319 if format > 0:
3323 ui.write('\n')
3320 ui.write('\n')
3324 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3321 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3325 % tuple(datasize))
3322 % tuple(datasize))
3326 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3323 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3327 % tuple(fullsize))
3324 % tuple(fullsize))
3328 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3325 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3329 % tuple(deltasize))
3326 % tuple(deltasize))
3330
3327
3331 if numdeltas > 0:
3328 if numdeltas > 0:
3332 ui.write('\n')
3329 ui.write('\n')
3333 fmt = pcfmtstr(numdeltas)
3330 fmt = pcfmtstr(numdeltas)
3334 fmt2 = pcfmtstr(numdeltas, 4)
3331 fmt2 = pcfmtstr(numdeltas, 4)
3335 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3332 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3336 if numprev > 0:
3333 if numprev > 0:
3337 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3334 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3338 numprev))
3335 numprev))
3339 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3336 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3340 numprev))
3337 numprev))
3341 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3338 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3342 numprev))
3339 numprev))
3343 if gdelta:
3340 if gdelta:
3344 ui.write(('deltas against p1 : ')
3341 ui.write(('deltas against p1 : ')
3345 + fmt % pcfmt(nump1, numdeltas))
3342 + fmt % pcfmt(nump1, numdeltas))
3346 ui.write(('deltas against p2 : ')
3343 ui.write(('deltas against p2 : ')
3347 + fmt % pcfmt(nump2, numdeltas))
3344 + fmt % pcfmt(nump2, numdeltas))
3348 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3345 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3349 numdeltas))
3346 numdeltas))
3350
3347
3351 @command('debugrevspec',
3348 @command('debugrevspec',
3352 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3349 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3353 ('REVSPEC'))
3350 ('REVSPEC'))
3354 def debugrevspec(ui, repo, expr, **opts):
3351 def debugrevspec(ui, repo, expr, **opts):
3355 """parse and apply a revision specification
3352 """parse and apply a revision specification
3356
3353
3357 Use --verbose to print the parsed tree before and after aliases
3354 Use --verbose to print the parsed tree before and after aliases
3358 expansion.
3355 expansion.
3359 """
3356 """
3360 if ui.verbose:
3357 if ui.verbose:
3361 tree = revset.parse(expr, lookup=repo.__contains__)
3358 tree = revset.parse(expr, lookup=repo.__contains__)
3362 ui.note(revset.prettyformat(tree), "\n")
3359 ui.note(revset.prettyformat(tree), "\n")
3363 newtree = revset.findaliases(ui, tree)
3360 newtree = revset.findaliases(ui, tree)
3364 if newtree != tree:
3361 if newtree != tree:
3365 ui.note(revset.prettyformat(newtree), "\n")
3362 ui.note(revset.prettyformat(newtree), "\n")
3366 tree = newtree
3363 tree = newtree
3367 newtree = revset.foldconcat(tree)
3364 newtree = revset.foldconcat(tree)
3368 if newtree != tree:
3365 if newtree != tree:
3369 ui.note(revset.prettyformat(newtree), "\n")
3366 ui.note(revset.prettyformat(newtree), "\n")
3370 if opts["optimize"]:
3367 if opts["optimize"]:
3371 weight, optimizedtree = revset.optimize(newtree, True)
3368 weight, optimizedtree = revset.optimize(newtree, True)
3372 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3369 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3373 func = revset.match(ui, expr, repo)
3370 func = revset.match(ui, expr, repo)
3374 revs = func(repo)
3371 revs = func(repo)
3375 if ui.verbose:
3372 if ui.verbose:
3376 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3373 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3377 for c in revs:
3374 for c in revs:
3378 ui.write("%s\n" % c)
3375 ui.write("%s\n" % c)
3379
3376
3380 @command('debugsetparents', [], _('REV1 [REV2]'))
3377 @command('debugsetparents', [], _('REV1 [REV2]'))
3381 def debugsetparents(ui, repo, rev1, rev2=None):
3378 def debugsetparents(ui, repo, rev1, rev2=None):
3382 """manually set the parents of the current working directory
3379 """manually set the parents of the current working directory
3383
3380
3384 This is useful for writing repository conversion tools, but should
3381 This is useful for writing repository conversion tools, but should
3385 be used with care. For example, neither the working directory nor the
3382 be used with care. For example, neither the working directory nor the
3386 dirstate is updated, so file status may be incorrect after running this
3383 dirstate is updated, so file status may be incorrect after running this
3387 command.
3384 command.
3388
3385
3389 Returns 0 on success.
3386 Returns 0 on success.
3390 """
3387 """
3391
3388
3392 r1 = scmutil.revsingle(repo, rev1).node()
3389 r1 = scmutil.revsingle(repo, rev1).node()
3393 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3390 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3394
3391
3395 wlock = repo.wlock()
3392 wlock = repo.wlock()
3396 try:
3393 try:
3397 repo.dirstate.beginparentchange()
3394 repo.dirstate.beginparentchange()
3398 repo.setparents(r1, r2)
3395 repo.setparents(r1, r2)
3399 repo.dirstate.endparentchange()
3396 repo.dirstate.endparentchange()
3400 finally:
3397 finally:
3401 wlock.release()
3398 wlock.release()
3402
3399
3403 @command('debugdirstate|debugstate',
3400 @command('debugdirstate|debugstate',
3404 [('', 'nodates', None, _('do not display the saved mtime')),
3401 [('', 'nodates', None, _('do not display the saved mtime')),
3405 ('', 'datesort', None, _('sort by saved mtime'))],
3402 ('', 'datesort', None, _('sort by saved mtime'))],
3406 _('[OPTION]...'))
3403 _('[OPTION]...'))
3407 def debugstate(ui, repo, **opts):
3404 def debugstate(ui, repo, **opts):
3408 """show the contents of the current dirstate"""
3405 """show the contents of the current dirstate"""
3409
3406
3410 nodates = opts.get('nodates')
3407 nodates = opts.get('nodates')
3411 datesort = opts.get('datesort')
3408 datesort = opts.get('datesort')
3412
3409
3413 timestr = ""
3410 timestr = ""
3414 if datesort:
3411 if datesort:
3415 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3412 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3416 else:
3413 else:
3417 keyfunc = None # sort by filename
3414 keyfunc = None # sort by filename
3418 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3415 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3419 if ent[3] == -1:
3416 if ent[3] == -1:
3420 timestr = 'unset '
3417 timestr = 'unset '
3421 elif nodates:
3418 elif nodates:
3422 timestr = 'set '
3419 timestr = 'set '
3423 else:
3420 else:
3424 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3421 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3425 time.localtime(ent[3]))
3422 time.localtime(ent[3]))
3426 if ent[1] & 0o20000:
3423 if ent[1] & 0o20000:
3427 mode = 'lnk'
3424 mode = 'lnk'
3428 else:
3425 else:
3429 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3426 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3430 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3427 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3431 for f in repo.dirstate.copies():
3428 for f in repo.dirstate.copies():
3432 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3429 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3433
3430
3434 @command('debugsub',
3431 @command('debugsub',
3435 [('r', 'rev', '',
3432 [('r', 'rev', '',
3436 _('revision to check'), _('REV'))],
3433 _('revision to check'), _('REV'))],
3437 _('[-r REV] [REV]'))
3434 _('[-r REV] [REV]'))
3438 def debugsub(ui, repo, rev=None):
3435 def debugsub(ui, repo, rev=None):
3439 ctx = scmutil.revsingle(repo, rev, None)
3436 ctx = scmutil.revsingle(repo, rev, None)
3440 for k, v in sorted(ctx.substate.items()):
3437 for k, v in sorted(ctx.substate.items()):
3441 ui.write(('path %s\n') % k)
3438 ui.write(('path %s\n') % k)
3442 ui.write((' source %s\n') % v[0])
3439 ui.write((' source %s\n') % v[0])
3443 ui.write((' revision %s\n') % v[1])
3440 ui.write((' revision %s\n') % v[1])
3444
3441
3445 @command('debugsuccessorssets',
3442 @command('debugsuccessorssets',
3446 [],
3443 [],
3447 _('[REV]'))
3444 _('[REV]'))
3448 def debugsuccessorssets(ui, repo, *revs):
3445 def debugsuccessorssets(ui, repo, *revs):
3449 """show set of successors for revision
3446 """show set of successors for revision
3450
3447
3451 A successors set of changeset A is a consistent group of revisions that
3448 A successors set of changeset A is a consistent group of revisions that
3452 succeed A. It contains non-obsolete changesets only.
3449 succeed A. It contains non-obsolete changesets only.
3453
3450
3454 In most cases a changeset A has a single successors set containing a single
3451 In most cases a changeset A has a single successors set containing a single
3455 successor (changeset A replaced by A').
3452 successor (changeset A replaced by A').
3456
3453
3457 A changeset that is made obsolete with no successors are called "pruned".
3454 A changeset that is made obsolete with no successors are called "pruned".
3458 Such changesets have no successors sets at all.
3455 Such changesets have no successors sets at all.
3459
3456
3460 A changeset that has been "split" will have a successors set containing
3457 A changeset that has been "split" will have a successors set containing
3461 more than one successor.
3458 more than one successor.
3462
3459
3463 A changeset that has been rewritten in multiple different ways is called
3460 A changeset that has been rewritten in multiple different ways is called
3464 "divergent". Such changesets have multiple successor sets (each of which
3461 "divergent". Such changesets have multiple successor sets (each of which
3465 may also be split, i.e. have multiple successors).
3462 may also be split, i.e. have multiple successors).
3466
3463
3467 Results are displayed as follows::
3464 Results are displayed as follows::
3468
3465
3469 <rev1>
3466 <rev1>
3470 <successors-1A>
3467 <successors-1A>
3471 <rev2>
3468 <rev2>
3472 <successors-2A>
3469 <successors-2A>
3473 <successors-2B1> <successors-2B2> <successors-2B3>
3470 <successors-2B1> <successors-2B2> <successors-2B3>
3474
3471
3475 Here rev2 has two possible (i.e. divergent) successors sets. The first
3472 Here rev2 has two possible (i.e. divergent) successors sets. The first
3476 holds one element, whereas the second holds three (i.e. the changeset has
3473 holds one element, whereas the second holds three (i.e. the changeset has
3477 been split).
3474 been split).
3478 """
3475 """
3479 # passed to successorssets caching computation from one call to another
3476 # passed to successorssets caching computation from one call to another
3480 cache = {}
3477 cache = {}
3481 ctx2str = str
3478 ctx2str = str
3482 node2str = short
3479 node2str = short
3483 if ui.debug():
3480 if ui.debug():
3484 def ctx2str(ctx):
3481 def ctx2str(ctx):
3485 return ctx.hex()
3482 return ctx.hex()
3486 node2str = hex
3483 node2str = hex
3487 for rev in scmutil.revrange(repo, revs):
3484 for rev in scmutil.revrange(repo, revs):
3488 ctx = repo[rev]
3485 ctx = repo[rev]
3489 ui.write('%s\n'% ctx2str(ctx))
3486 ui.write('%s\n'% ctx2str(ctx))
3490 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3487 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3491 if succsset:
3488 if succsset:
3492 ui.write(' ')
3489 ui.write(' ')
3493 ui.write(node2str(succsset[0]))
3490 ui.write(node2str(succsset[0]))
3494 for node in succsset[1:]:
3491 for node in succsset[1:]:
3495 ui.write(' ')
3492 ui.write(' ')
3496 ui.write(node2str(node))
3493 ui.write(node2str(node))
3497 ui.write('\n')
3494 ui.write('\n')
3498
3495
3499 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3496 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3500 def debugwalk(ui, repo, *pats, **opts):
3497 def debugwalk(ui, repo, *pats, **opts):
3501 """show how files match on given patterns"""
3498 """show how files match on given patterns"""
3502 m = scmutil.match(repo[None], pats, opts)
3499 m = scmutil.match(repo[None], pats, opts)
3503 items = list(repo.walk(m))
3500 items = list(repo.walk(m))
3504 if not items:
3501 if not items:
3505 return
3502 return
3506 f = lambda fn: fn
3503 f = lambda fn: fn
3507 if ui.configbool('ui', 'slash') and os.sep != '/':
3504 if ui.configbool('ui', 'slash') and os.sep != '/':
3508 f = lambda fn: util.normpath(fn)
3505 f = lambda fn: util.normpath(fn)
3509 fmt = 'f %%-%ds %%-%ds %%s' % (
3506 fmt = 'f %%-%ds %%-%ds %%s' % (
3510 max([len(abs) for abs in items]),
3507 max([len(abs) for abs in items]),
3511 max([len(m.rel(abs)) for abs in items]))
3508 max([len(m.rel(abs)) for abs in items]))
3512 for abs in items:
3509 for abs in items:
3513 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3510 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3514 ui.write("%s\n" % line.rstrip())
3511 ui.write("%s\n" % line.rstrip())
3515
3512
3516 @command('debugwireargs',
3513 @command('debugwireargs',
3517 [('', 'three', '', 'three'),
3514 [('', 'three', '', 'three'),
3518 ('', 'four', '', 'four'),
3515 ('', 'four', '', 'four'),
3519 ('', 'five', '', 'five'),
3516 ('', 'five', '', 'five'),
3520 ] + remoteopts,
3517 ] + remoteopts,
3521 _('REPO [OPTIONS]... [ONE [TWO]]'),
3518 _('REPO [OPTIONS]... [ONE [TWO]]'),
3522 norepo=True)
3519 norepo=True)
3523 def debugwireargs(ui, repopath, *vals, **opts):
3520 def debugwireargs(ui, repopath, *vals, **opts):
3524 repo = hg.peer(ui, opts, repopath)
3521 repo = hg.peer(ui, opts, repopath)
3525 for opt in remoteopts:
3522 for opt in remoteopts:
3526 del opts[opt[1]]
3523 del opts[opt[1]]
3527 args = {}
3524 args = {}
3528 for k, v in opts.iteritems():
3525 for k, v in opts.iteritems():
3529 if v:
3526 if v:
3530 args[k] = v
3527 args[k] = v
3531 # run twice to check that we don't mess up the stream for the next command
3528 # run twice to check that we don't mess up the stream for the next command
3532 res1 = repo.debugwireargs(*vals, **args)
3529 res1 = repo.debugwireargs(*vals, **args)
3533 res2 = repo.debugwireargs(*vals, **args)
3530 res2 = repo.debugwireargs(*vals, **args)
3534 ui.write("%s\n" % res1)
3531 ui.write("%s\n" % res1)
3535 if res1 != res2:
3532 if res1 != res2:
3536 ui.warn("%s\n" % res2)
3533 ui.warn("%s\n" % res2)
3537
3534
3538 @command('^diff',
3535 @command('^diff',
3539 [('r', 'rev', [], _('revision'), _('REV')),
3536 [('r', 'rev', [], _('revision'), _('REV')),
3540 ('c', 'change', '', _('change made by revision'), _('REV'))
3537 ('c', 'change', '', _('change made by revision'), _('REV'))
3541 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3538 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3542 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3539 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3543 inferrepo=True)
3540 inferrepo=True)
3544 def diff(ui, repo, *pats, **opts):
3541 def diff(ui, repo, *pats, **opts):
3545 """diff repository (or selected files)
3542 """diff repository (or selected files)
3546
3543
3547 Show differences between revisions for the specified files.
3544 Show differences between revisions for the specified files.
3548
3545
3549 Differences between files are shown using the unified diff format.
3546 Differences between files are shown using the unified diff format.
3550
3547
3551 .. note::
3548 .. note::
3552
3549
3553 :hg:`diff` may generate unexpected results for merges, as it will
3550 :hg:`diff` may generate unexpected results for merges, as it will
3554 default to comparing against the working directory's first
3551 default to comparing against the working directory's first
3555 parent changeset if no revisions are specified.
3552 parent changeset if no revisions are specified.
3556
3553
3557 When two revision arguments are given, then changes are shown
3554 When two revision arguments are given, then changes are shown
3558 between those revisions. If only one revision is specified then
3555 between those revisions. If only one revision is specified then
3559 that revision is compared to the working directory, and, when no
3556 that revision is compared to the working directory, and, when no
3560 revisions are specified, the working directory files are compared
3557 revisions are specified, the working directory files are compared
3561 to its first parent.
3558 to its first parent.
3562
3559
3563 Alternatively you can specify -c/--change with a revision to see
3560 Alternatively you can specify -c/--change with a revision to see
3564 the changes in that changeset relative to its first parent.
3561 the changes in that changeset relative to its first parent.
3565
3562
3566 Without the -a/--text option, diff will avoid generating diffs of
3563 Without the -a/--text option, diff will avoid generating diffs of
3567 files it detects as binary. With -a, diff will generate a diff
3564 files it detects as binary. With -a, diff will generate a diff
3568 anyway, probably with undesirable results.
3565 anyway, probably with undesirable results.
3569
3566
3570 Use the -g/--git option to generate diffs in the git extended diff
3567 Use the -g/--git option to generate diffs in the git extended diff
3571 format. For more information, read :hg:`help diffs`.
3568 format. For more information, read :hg:`help diffs`.
3572
3569
3573 .. container:: verbose
3570 .. container:: verbose
3574
3571
3575 Examples:
3572 Examples:
3576
3573
3577 - compare a file in the current working directory to its parent::
3574 - compare a file in the current working directory to its parent::
3578
3575
3579 hg diff foo.c
3576 hg diff foo.c
3580
3577
3581 - compare two historical versions of a directory, with rename info::
3578 - compare two historical versions of a directory, with rename info::
3582
3579
3583 hg diff --git -r 1.0:1.2 lib/
3580 hg diff --git -r 1.0:1.2 lib/
3584
3581
3585 - get change stats relative to the last change on some date::
3582 - get change stats relative to the last change on some date::
3586
3583
3587 hg diff --stat -r "date('may 2')"
3584 hg diff --stat -r "date('may 2')"
3588
3585
3589 - diff all newly-added files that contain a keyword::
3586 - diff all newly-added files that contain a keyword::
3590
3587
3591 hg diff "set:added() and grep(GNU)"
3588 hg diff "set:added() and grep(GNU)"
3592
3589
3593 - compare a revision and its parents::
3590 - compare a revision and its parents::
3594
3591
3595 hg diff -c 9353 # compare against first parent
3592 hg diff -c 9353 # compare against first parent
3596 hg diff -r 9353^:9353 # same using revset syntax
3593 hg diff -r 9353^:9353 # same using revset syntax
3597 hg diff -r 9353^2:9353 # compare against the second parent
3594 hg diff -r 9353^2:9353 # compare against the second parent
3598
3595
3599 Returns 0 on success.
3596 Returns 0 on success.
3600 """
3597 """
3601
3598
3602 revs = opts.get('rev')
3599 revs = opts.get('rev')
3603 change = opts.get('change')
3600 change = opts.get('change')
3604 stat = opts.get('stat')
3601 stat = opts.get('stat')
3605 reverse = opts.get('reverse')
3602 reverse = opts.get('reverse')
3606
3603
3607 if revs and change:
3604 if revs and change:
3608 msg = _('cannot specify --rev and --change at the same time')
3605 msg = _('cannot specify --rev and --change at the same time')
3609 raise error.Abort(msg)
3606 raise error.Abort(msg)
3610 elif change:
3607 elif change:
3611 node2 = scmutil.revsingle(repo, change, None).node()
3608 node2 = scmutil.revsingle(repo, change, None).node()
3612 node1 = repo[node2].p1().node()
3609 node1 = repo[node2].p1().node()
3613 else:
3610 else:
3614 node1, node2 = scmutil.revpair(repo, revs)
3611 node1, node2 = scmutil.revpair(repo, revs)
3615
3612
3616 if reverse:
3613 if reverse:
3617 node1, node2 = node2, node1
3614 node1, node2 = node2, node1
3618
3615
3619 diffopts = patch.diffallopts(ui, opts)
3616 diffopts = patch.diffallopts(ui, opts)
3620 m = scmutil.match(repo[node2], pats, opts)
3617 m = scmutil.match(repo[node2], pats, opts)
3621 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3618 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3622 listsubrepos=opts.get('subrepos'),
3619 listsubrepos=opts.get('subrepos'),
3623 root=opts.get('root'))
3620 root=opts.get('root'))
3624
3621
3625 @command('^export',
3622 @command('^export',
3626 [('o', 'output', '',
3623 [('o', 'output', '',
3627 _('print output to file with formatted name'), _('FORMAT')),
3624 _('print output to file with formatted name'), _('FORMAT')),
3628 ('', 'switch-parent', None, _('diff against the second parent')),
3625 ('', 'switch-parent', None, _('diff against the second parent')),
3629 ('r', 'rev', [], _('revisions to export'), _('REV')),
3626 ('r', 'rev', [], _('revisions to export'), _('REV')),
3630 ] + diffopts,
3627 ] + diffopts,
3631 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3628 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3632 def export(ui, repo, *changesets, **opts):
3629 def export(ui, repo, *changesets, **opts):
3633 """dump the header and diffs for one or more changesets
3630 """dump the header and diffs for one or more changesets
3634
3631
3635 Print the changeset header and diffs for one or more revisions.
3632 Print the changeset header and diffs for one or more revisions.
3636 If no revision is given, the parent of the working directory is used.
3633 If no revision is given, the parent of the working directory is used.
3637
3634
3638 The information shown in the changeset header is: author, date,
3635 The information shown in the changeset header is: author, date,
3639 branch name (if non-default), changeset hash, parent(s) and commit
3636 branch name (if non-default), changeset hash, parent(s) and commit
3640 comment.
3637 comment.
3641
3638
3642 .. note::
3639 .. note::
3643
3640
3644 :hg:`export` may generate unexpected diff output for merge
3641 :hg:`export` may generate unexpected diff output for merge
3645 changesets, as it will compare the merge changeset against its
3642 changesets, as it will compare the merge changeset against its
3646 first parent only.
3643 first parent only.
3647
3644
3648 Output may be to a file, in which case the name of the file is
3645 Output may be to a file, in which case the name of the file is
3649 given using a format string. The formatting rules are as follows:
3646 given using a format string. The formatting rules are as follows:
3650
3647
3651 :``%%``: literal "%" character
3648 :``%%``: literal "%" character
3652 :``%H``: changeset hash (40 hexadecimal digits)
3649 :``%H``: changeset hash (40 hexadecimal digits)
3653 :``%N``: number of patches being generated
3650 :``%N``: number of patches being generated
3654 :``%R``: changeset revision number
3651 :``%R``: changeset revision number
3655 :``%b``: basename of the exporting repository
3652 :``%b``: basename of the exporting repository
3656 :``%h``: short-form changeset hash (12 hexadecimal digits)
3653 :``%h``: short-form changeset hash (12 hexadecimal digits)
3657 :``%m``: first line of the commit message (only alphanumeric characters)
3654 :``%m``: first line of the commit message (only alphanumeric characters)
3658 :``%n``: zero-padded sequence number, starting at 1
3655 :``%n``: zero-padded sequence number, starting at 1
3659 :``%r``: zero-padded changeset revision number
3656 :``%r``: zero-padded changeset revision number
3660
3657
3661 Without the -a/--text option, export will avoid generating diffs
3658 Without the -a/--text option, export will avoid generating diffs
3662 of files it detects as binary. With -a, export will generate a
3659 of files it detects as binary. With -a, export will generate a
3663 diff anyway, probably with undesirable results.
3660 diff anyway, probably with undesirable results.
3664
3661
3665 Use the -g/--git option to generate diffs in the git extended diff
3662 Use the -g/--git option to generate diffs in the git extended diff
3666 format. See :hg:`help diffs` for more information.
3663 format. See :hg:`help diffs` for more information.
3667
3664
3668 With the --switch-parent option, the diff will be against the
3665 With the --switch-parent option, the diff will be against the
3669 second parent. It can be useful to review a merge.
3666 second parent. It can be useful to review a merge.
3670
3667
3671 .. container:: verbose
3668 .. container:: verbose
3672
3669
3673 Examples:
3670 Examples:
3674
3671
3675 - use export and import to transplant a bugfix to the current
3672 - use export and import to transplant a bugfix to the current
3676 branch::
3673 branch::
3677
3674
3678 hg export -r 9353 | hg import -
3675 hg export -r 9353 | hg import -
3679
3676
3680 - export all the changesets between two revisions to a file with
3677 - export all the changesets between two revisions to a file with
3681 rename information::
3678 rename information::
3682
3679
3683 hg export --git -r 123:150 > changes.txt
3680 hg export --git -r 123:150 > changes.txt
3684
3681
3685 - split outgoing changes into a series of patches with
3682 - split outgoing changes into a series of patches with
3686 descriptive names::
3683 descriptive names::
3687
3684
3688 hg export -r "outgoing()" -o "%n-%m.patch"
3685 hg export -r "outgoing()" -o "%n-%m.patch"
3689
3686
3690 Returns 0 on success.
3687 Returns 0 on success.
3691 """
3688 """
3692 changesets += tuple(opts.get('rev', []))
3689 changesets += tuple(opts.get('rev', []))
3693 if not changesets:
3690 if not changesets:
3694 changesets = ['.']
3691 changesets = ['.']
3695 revs = scmutil.revrange(repo, changesets)
3692 revs = scmutil.revrange(repo, changesets)
3696 if not revs:
3693 if not revs:
3697 raise error.Abort(_("export requires at least one changeset"))
3694 raise error.Abort(_("export requires at least one changeset"))
3698 if len(revs) > 1:
3695 if len(revs) > 1:
3699 ui.note(_('exporting patches:\n'))
3696 ui.note(_('exporting patches:\n'))
3700 else:
3697 else:
3701 ui.note(_('exporting patch:\n'))
3698 ui.note(_('exporting patch:\n'))
3702 cmdutil.export(repo, revs, template=opts.get('output'),
3699 cmdutil.export(repo, revs, template=opts.get('output'),
3703 switch_parent=opts.get('switch_parent'),
3700 switch_parent=opts.get('switch_parent'),
3704 opts=patch.diffallopts(ui, opts))
3701 opts=patch.diffallopts(ui, opts))
3705
3702
3706 @command('files',
3703 @command('files',
3707 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3704 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3708 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3705 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3709 ] + walkopts + formatteropts + subrepoopts,
3706 ] + walkopts + formatteropts + subrepoopts,
3710 _('[OPTION]... [PATTERN]...'))
3707 _('[OPTION]... [PATTERN]...'))
3711 def files(ui, repo, *pats, **opts):
3708 def files(ui, repo, *pats, **opts):
3712 """list tracked files
3709 """list tracked files
3713
3710
3714 Print files under Mercurial control in the working directory or
3711 Print files under Mercurial control in the working directory or
3715 specified revision whose names match the given patterns (excluding
3712 specified revision whose names match the given patterns (excluding
3716 removed files).
3713 removed files).
3717
3714
3718 If no patterns are given to match, this command prints the names
3715 If no patterns are given to match, this command prints the names
3719 of all files under Mercurial control in the working directory.
3716 of all files under Mercurial control in the working directory.
3720
3717
3721 .. container:: verbose
3718 .. container:: verbose
3722
3719
3723 Examples:
3720 Examples:
3724
3721
3725 - list all files under the current directory::
3722 - list all files under the current directory::
3726
3723
3727 hg files .
3724 hg files .
3728
3725
3729 - shows sizes and flags for current revision::
3726 - shows sizes and flags for current revision::
3730
3727
3731 hg files -vr .
3728 hg files -vr .
3732
3729
3733 - list all files named README::
3730 - list all files named README::
3734
3731
3735 hg files -I "**/README"
3732 hg files -I "**/README"
3736
3733
3737 - list all binary files::
3734 - list all binary files::
3738
3735
3739 hg files "set:binary()"
3736 hg files "set:binary()"
3740
3737
3741 - find files containing a regular expression::
3738 - find files containing a regular expression::
3742
3739
3743 hg files "set:grep('bob')"
3740 hg files "set:grep('bob')"
3744
3741
3745 - search tracked file contents with xargs and grep::
3742 - search tracked file contents with xargs and grep::
3746
3743
3747 hg files -0 | xargs -0 grep foo
3744 hg files -0 | xargs -0 grep foo
3748
3745
3749 See :hg:`help patterns` and :hg:`help filesets` for more information
3746 See :hg:`help patterns` and :hg:`help filesets` for more information
3750 on specifying file patterns.
3747 on specifying file patterns.
3751
3748
3752 Returns 0 if a match is found, 1 otherwise.
3749 Returns 0 if a match is found, 1 otherwise.
3753
3750
3754 """
3751 """
3755 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3752 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3756
3753
3757 end = '\n'
3754 end = '\n'
3758 if opts.get('print0'):
3755 if opts.get('print0'):
3759 end = '\0'
3756 end = '\0'
3760 fm = ui.formatter('files', opts)
3757 fm = ui.formatter('files', opts)
3761 fmt = '%s' + end
3758 fmt = '%s' + end
3762
3759
3763 m = scmutil.match(ctx, pats, opts)
3760 m = scmutil.match(ctx, pats, opts)
3764 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3761 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3765
3762
3766 fm.end()
3763 fm.end()
3767
3764
3768 return ret
3765 return ret
3769
3766
3770 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3767 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3771 def forget(ui, repo, *pats, **opts):
3768 def forget(ui, repo, *pats, **opts):
3772 """forget the specified files on the next commit
3769 """forget the specified files on the next commit
3773
3770
3774 Mark the specified files so they will no longer be tracked
3771 Mark the specified files so they will no longer be tracked
3775 after the next commit.
3772 after the next commit.
3776
3773
3777 This only removes files from the current branch, not from the
3774 This only removes files from the current branch, not from the
3778 entire project history, and it does not delete them from the
3775 entire project history, and it does not delete them from the
3779 working directory.
3776 working directory.
3780
3777
3781 To delete the file from the working directory, see :hg:`remove`.
3778 To delete the file from the working directory, see :hg:`remove`.
3782
3779
3783 To undo a forget before the next commit, see :hg:`add`.
3780 To undo a forget before the next commit, see :hg:`add`.
3784
3781
3785 .. container:: verbose
3782 .. container:: verbose
3786
3783
3787 Examples:
3784 Examples:
3788
3785
3789 - forget newly-added binary files::
3786 - forget newly-added binary files::
3790
3787
3791 hg forget "set:added() and binary()"
3788 hg forget "set:added() and binary()"
3792
3789
3793 - forget files that would be excluded by .hgignore::
3790 - forget files that would be excluded by .hgignore::
3794
3791
3795 hg forget "set:hgignore()"
3792 hg forget "set:hgignore()"
3796
3793
3797 Returns 0 on success.
3794 Returns 0 on success.
3798 """
3795 """
3799
3796
3800 if not pats:
3797 if not pats:
3801 raise error.Abort(_('no files specified'))
3798 raise error.Abort(_('no files specified'))
3802
3799
3803 m = scmutil.match(repo[None], pats, opts)
3800 m = scmutil.match(repo[None], pats, opts)
3804 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3801 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3805 return rejected and 1 or 0
3802 return rejected and 1 or 0
3806
3803
3807 @command(
3804 @command(
3808 'graft',
3805 'graft',
3809 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3806 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3810 ('c', 'continue', False, _('resume interrupted graft')),
3807 ('c', 'continue', False, _('resume interrupted graft')),
3811 ('e', 'edit', False, _('invoke editor on commit messages')),
3808 ('e', 'edit', False, _('invoke editor on commit messages')),
3812 ('', 'log', None, _('append graft info to log message')),
3809 ('', 'log', None, _('append graft info to log message')),
3813 ('f', 'force', False, _('force graft')),
3810 ('f', 'force', False, _('force graft')),
3814 ('D', 'currentdate', False,
3811 ('D', 'currentdate', False,
3815 _('record the current date as commit date')),
3812 _('record the current date as commit date')),
3816 ('U', 'currentuser', False,
3813 ('U', 'currentuser', False,
3817 _('record the current user as committer'), _('DATE'))]
3814 _('record the current user as committer'), _('DATE'))]
3818 + commitopts2 + mergetoolopts + dryrunopts,
3815 + commitopts2 + mergetoolopts + dryrunopts,
3819 _('[OPTION]... [-r] REV...'))
3816 _('[OPTION]... [-r] REV...'))
3820 def graft(ui, repo, *revs, **opts):
3817 def graft(ui, repo, *revs, **opts):
3821 '''copy changes from other branches onto the current branch
3818 '''copy changes from other branches onto the current branch
3822
3819
3823 This command uses Mercurial's merge logic to copy individual
3820 This command uses Mercurial's merge logic to copy individual
3824 changes from other branches without merging branches in the
3821 changes from other branches without merging branches in the
3825 history graph. This is sometimes known as 'backporting' or
3822 history graph. This is sometimes known as 'backporting' or
3826 'cherry-picking'. By default, graft will copy user, date, and
3823 'cherry-picking'. By default, graft will copy user, date, and
3827 description from the source changesets.
3824 description from the source changesets.
3828
3825
3829 Changesets that are ancestors of the current revision, that have
3826 Changesets that are ancestors of the current revision, that have
3830 already been grafted, or that are merges will be skipped.
3827 already been grafted, or that are merges will be skipped.
3831
3828
3832 If --log is specified, log messages will have a comment appended
3829 If --log is specified, log messages will have a comment appended
3833 of the form::
3830 of the form::
3834
3831
3835 (grafted from CHANGESETHASH)
3832 (grafted from CHANGESETHASH)
3836
3833
3837 If --force is specified, revisions will be grafted even if they
3834 If --force is specified, revisions will be grafted even if they
3838 are already ancestors of or have been grafted to the destination.
3835 are already ancestors of or have been grafted to the destination.
3839 This is useful when the revisions have since been backed out.
3836 This is useful when the revisions have since been backed out.
3840
3837
3841 If a graft merge results in conflicts, the graft process is
3838 If a graft merge results in conflicts, the graft process is
3842 interrupted so that the current merge can be manually resolved.
3839 interrupted so that the current merge can be manually resolved.
3843 Once all conflicts are addressed, the graft process can be
3840 Once all conflicts are addressed, the graft process can be
3844 continued with the -c/--continue option.
3841 continued with the -c/--continue option.
3845
3842
3846 .. note::
3843 .. note::
3847
3844
3848 The -c/--continue option does not reapply earlier options, except
3845 The -c/--continue option does not reapply earlier options, except
3849 for --force.
3846 for --force.
3850
3847
3851 .. container:: verbose
3848 .. container:: verbose
3852
3849
3853 Examples:
3850 Examples:
3854
3851
3855 - copy a single change to the stable branch and edit its description::
3852 - copy a single change to the stable branch and edit its description::
3856
3853
3857 hg update stable
3854 hg update stable
3858 hg graft --edit 9393
3855 hg graft --edit 9393
3859
3856
3860 - graft a range of changesets with one exception, updating dates::
3857 - graft a range of changesets with one exception, updating dates::
3861
3858
3862 hg graft -D "2085::2093 and not 2091"
3859 hg graft -D "2085::2093 and not 2091"
3863
3860
3864 - continue a graft after resolving conflicts::
3861 - continue a graft after resolving conflicts::
3865
3862
3866 hg graft -c
3863 hg graft -c
3867
3864
3868 - show the source of a grafted changeset::
3865 - show the source of a grafted changeset::
3869
3866
3870 hg log --debug -r .
3867 hg log --debug -r .
3871
3868
3872 - show revisions sorted by date::
3869 - show revisions sorted by date::
3873
3870
3874 hg log -r 'sort(all(), date)'
3871 hg log -r 'sort(all(), date)'
3875
3872
3876 See :hg:`help revisions` and :hg:`help revsets` for more about
3873 See :hg:`help revisions` and :hg:`help revsets` for more about
3877 specifying revisions.
3874 specifying revisions.
3878
3875
3879 Returns 0 on successful completion.
3876 Returns 0 on successful completion.
3880 '''
3877 '''
3881 wlock = None
3878 wlock = None
3882 try:
3879 try:
3883 wlock = repo.wlock()
3880 wlock = repo.wlock()
3884 return _dograft(ui, repo, *revs, **opts)
3881 return _dograft(ui, repo, *revs, **opts)
3885 finally:
3882 finally:
3886 release(wlock)
3883 release(wlock)
3887
3884
3888 def _dograft(ui, repo, *revs, **opts):
3885 def _dograft(ui, repo, *revs, **opts):
3889 revs = list(revs)
3886 revs = list(revs)
3890 revs.extend(opts['rev'])
3887 revs.extend(opts['rev'])
3891
3888
3892 if not opts.get('user') and opts.get('currentuser'):
3889 if not opts.get('user') and opts.get('currentuser'):
3893 opts['user'] = ui.username()
3890 opts['user'] = ui.username()
3894 if not opts.get('date') and opts.get('currentdate'):
3891 if not opts.get('date') and opts.get('currentdate'):
3895 opts['date'] = "%d %d" % util.makedate()
3892 opts['date'] = "%d %d" % util.makedate()
3896
3893
3897 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3894 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3898
3895
3899 cont = False
3896 cont = False
3900 if opts['continue']:
3897 if opts['continue']:
3901 cont = True
3898 cont = True
3902 if revs:
3899 if revs:
3903 raise error.Abort(_("can't specify --continue and revisions"))
3900 raise error.Abort(_("can't specify --continue and revisions"))
3904 # read in unfinished revisions
3901 # read in unfinished revisions
3905 try:
3902 try:
3906 nodes = repo.vfs.read('graftstate').splitlines()
3903 nodes = repo.vfs.read('graftstate').splitlines()
3907 revs = [repo[node].rev() for node in nodes]
3904 revs = [repo[node].rev() for node in nodes]
3908 except IOError as inst:
3905 except IOError as inst:
3909 if inst.errno != errno.ENOENT:
3906 if inst.errno != errno.ENOENT:
3910 raise
3907 raise
3911 raise error.Abort(_("no graft state found, can't continue"))
3908 raise error.Abort(_("no graft state found, can't continue"))
3912 else:
3909 else:
3913 cmdutil.checkunfinished(repo)
3910 cmdutil.checkunfinished(repo)
3914 cmdutil.bailifchanged(repo)
3911 cmdutil.bailifchanged(repo)
3915 if not revs:
3912 if not revs:
3916 raise error.Abort(_('no revisions specified'))
3913 raise error.Abort(_('no revisions specified'))
3917 revs = scmutil.revrange(repo, revs)
3914 revs = scmutil.revrange(repo, revs)
3918
3915
3919 skipped = set()
3916 skipped = set()
3920 # check for merges
3917 # check for merges
3921 for rev in repo.revs('%ld and merge()', revs):
3918 for rev in repo.revs('%ld and merge()', revs):
3922 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3919 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3923 skipped.add(rev)
3920 skipped.add(rev)
3924 revs = [r for r in revs if r not in skipped]
3921 revs = [r for r in revs if r not in skipped]
3925 if not revs:
3922 if not revs:
3926 return -1
3923 return -1
3927
3924
3928 # Don't check in the --continue case, in effect retaining --force across
3925 # Don't check in the --continue case, in effect retaining --force across
3929 # --continues. That's because without --force, any revisions we decided to
3926 # --continues. That's because without --force, any revisions we decided to
3930 # skip would have been filtered out here, so they wouldn't have made their
3927 # skip would have been filtered out here, so they wouldn't have made their
3931 # way to the graftstate. With --force, any revisions we would have otherwise
3928 # way to the graftstate. With --force, any revisions we would have otherwise
3932 # skipped would not have been filtered out, and if they hadn't been applied
3929 # skipped would not have been filtered out, and if they hadn't been applied
3933 # already, they'd have been in the graftstate.
3930 # already, they'd have been in the graftstate.
3934 if not (cont or opts.get('force')):
3931 if not (cont or opts.get('force')):
3935 # check for ancestors of dest branch
3932 # check for ancestors of dest branch
3936 crev = repo['.'].rev()
3933 crev = repo['.'].rev()
3937 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3934 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3938 # Cannot use x.remove(y) on smart set, this has to be a list.
3935 # Cannot use x.remove(y) on smart set, this has to be a list.
3939 # XXX make this lazy in the future
3936 # XXX make this lazy in the future
3940 revs = list(revs)
3937 revs = list(revs)
3941 # don't mutate while iterating, create a copy
3938 # don't mutate while iterating, create a copy
3942 for rev in list(revs):
3939 for rev in list(revs):
3943 if rev in ancestors:
3940 if rev in ancestors:
3944 ui.warn(_('skipping ancestor revision %d:%s\n') %
3941 ui.warn(_('skipping ancestor revision %d:%s\n') %
3945 (rev, repo[rev]))
3942 (rev, repo[rev]))
3946 # XXX remove on list is slow
3943 # XXX remove on list is slow
3947 revs.remove(rev)
3944 revs.remove(rev)
3948 if not revs:
3945 if not revs:
3949 return -1
3946 return -1
3950
3947
3951 # analyze revs for earlier grafts
3948 # analyze revs for earlier grafts
3952 ids = {}
3949 ids = {}
3953 for ctx in repo.set("%ld", revs):
3950 for ctx in repo.set("%ld", revs):
3954 ids[ctx.hex()] = ctx.rev()
3951 ids[ctx.hex()] = ctx.rev()
3955 n = ctx.extra().get('source')
3952 n = ctx.extra().get('source')
3956 if n:
3953 if n:
3957 ids[n] = ctx.rev()
3954 ids[n] = ctx.rev()
3958
3955
3959 # check ancestors for earlier grafts
3956 # check ancestors for earlier grafts
3960 ui.debug('scanning for duplicate grafts\n')
3957 ui.debug('scanning for duplicate grafts\n')
3961
3958
3962 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3959 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3963 ctx = repo[rev]
3960 ctx = repo[rev]
3964 n = ctx.extra().get('source')
3961 n = ctx.extra().get('source')
3965 if n in ids:
3962 if n in ids:
3966 try:
3963 try:
3967 r = repo[n].rev()
3964 r = repo[n].rev()
3968 except error.RepoLookupError:
3965 except error.RepoLookupError:
3969 r = None
3966 r = None
3970 if r in revs:
3967 if r in revs:
3971 ui.warn(_('skipping revision %d:%s '
3968 ui.warn(_('skipping revision %d:%s '
3972 '(already grafted to %d:%s)\n')
3969 '(already grafted to %d:%s)\n')
3973 % (r, repo[r], rev, ctx))
3970 % (r, repo[r], rev, ctx))
3974 revs.remove(r)
3971 revs.remove(r)
3975 elif ids[n] in revs:
3972 elif ids[n] in revs:
3976 if r is None:
3973 if r is None:
3977 ui.warn(_('skipping already grafted revision %d:%s '
3974 ui.warn(_('skipping already grafted revision %d:%s '
3978 '(%d:%s also has unknown origin %s)\n')
3975 '(%d:%s also has unknown origin %s)\n')
3979 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3976 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3980 else:
3977 else:
3981 ui.warn(_('skipping already grafted revision %d:%s '
3978 ui.warn(_('skipping already grafted revision %d:%s '
3982 '(%d:%s also has origin %d:%s)\n')
3979 '(%d:%s also has origin %d:%s)\n')
3983 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3980 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3984 revs.remove(ids[n])
3981 revs.remove(ids[n])
3985 elif ctx.hex() in ids:
3982 elif ctx.hex() in ids:
3986 r = ids[ctx.hex()]
3983 r = ids[ctx.hex()]
3987 ui.warn(_('skipping already grafted revision %d:%s '
3984 ui.warn(_('skipping already grafted revision %d:%s '
3988 '(was grafted from %d:%s)\n') %
3985 '(was grafted from %d:%s)\n') %
3989 (r, repo[r], rev, ctx))
3986 (r, repo[r], rev, ctx))
3990 revs.remove(r)
3987 revs.remove(r)
3991 if not revs:
3988 if not revs:
3992 return -1
3989 return -1
3993
3990
3994 for pos, ctx in enumerate(repo.set("%ld", revs)):
3991 for pos, ctx in enumerate(repo.set("%ld", revs)):
3995 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3992 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3996 ctx.description().split('\n', 1)[0])
3993 ctx.description().split('\n', 1)[0])
3997 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3994 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3998 if names:
3995 if names:
3999 desc += ' (%s)' % ' '.join(names)
3996 desc += ' (%s)' % ' '.join(names)
4000 ui.status(_('grafting %s\n') % desc)
3997 ui.status(_('grafting %s\n') % desc)
4001 if opts.get('dry_run'):
3998 if opts.get('dry_run'):
4002 continue
3999 continue
4003
4000
4004 extra = ctx.extra().copy()
4001 extra = ctx.extra().copy()
4005 del extra['branch']
4002 del extra['branch']
4006 source = extra.get('source')
4003 source = extra.get('source')
4007 if source:
4004 if source:
4008 extra['intermediate-source'] = ctx.hex()
4005 extra['intermediate-source'] = ctx.hex()
4009 else:
4006 else:
4010 extra['source'] = ctx.hex()
4007 extra['source'] = ctx.hex()
4011 user = ctx.user()
4008 user = ctx.user()
4012 if opts.get('user'):
4009 if opts.get('user'):
4013 user = opts['user']
4010 user = opts['user']
4014 date = ctx.date()
4011 date = ctx.date()
4015 if opts.get('date'):
4012 if opts.get('date'):
4016 date = opts['date']
4013 date = opts['date']
4017 message = ctx.description()
4014 message = ctx.description()
4018 if opts.get('log'):
4015 if opts.get('log'):
4019 message += '\n(grafted from %s)' % ctx.hex()
4016 message += '\n(grafted from %s)' % ctx.hex()
4020
4017
4021 # we don't merge the first commit when continuing
4018 # we don't merge the first commit when continuing
4022 if not cont:
4019 if not cont:
4023 # perform the graft merge with p1(rev) as 'ancestor'
4020 # perform the graft merge with p1(rev) as 'ancestor'
4024 try:
4021 try:
4025 # ui.forcemerge is an internal variable, do not document
4022 # ui.forcemerge is an internal variable, do not document
4026 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4023 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
4027 'graft')
4024 'graft')
4028 stats = mergemod.graft(repo, ctx, ctx.p1(),
4025 stats = mergemod.graft(repo, ctx, ctx.p1(),
4029 ['local', 'graft'])
4026 ['local', 'graft'])
4030 finally:
4027 finally:
4031 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4028 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
4032 # report any conflicts
4029 # report any conflicts
4033 if stats and stats[3] > 0:
4030 if stats and stats[3] > 0:
4034 # write out state for --continue
4031 # write out state for --continue
4035 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4032 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
4036 repo.vfs.write('graftstate', ''.join(nodelines))
4033 repo.vfs.write('graftstate', ''.join(nodelines))
4037 extra = ''
4034 extra = ''
4038 if opts.get('user'):
4035 if opts.get('user'):
4039 extra += ' --user %s' % opts['user']
4036 extra += ' --user %s' % opts['user']
4040 if opts.get('date'):
4037 if opts.get('date'):
4041 extra += ' --date %s' % opts['date']
4038 extra += ' --date %s' % opts['date']
4042 if opts.get('log'):
4039 if opts.get('log'):
4043 extra += ' --log'
4040 extra += ' --log'
4044 hint=_('use hg resolve and hg graft --continue%s') % extra
4041 hint=_('use hg resolve and hg graft --continue%s') % extra
4045 raise error.Abort(
4042 raise error.Abort(
4046 _("unresolved conflicts, can't continue"),
4043 _("unresolved conflicts, can't continue"),
4047 hint=hint)
4044 hint=hint)
4048 else:
4045 else:
4049 cont = False
4046 cont = False
4050
4047
4051 # commit
4048 # commit
4052 node = repo.commit(text=message, user=user,
4049 node = repo.commit(text=message, user=user,
4053 date=date, extra=extra, editor=editor)
4050 date=date, extra=extra, editor=editor)
4054 if node is None:
4051 if node is None:
4055 ui.warn(
4052 ui.warn(
4056 _('note: graft of %d:%s created no changes to commit\n') %
4053 _('note: graft of %d:%s created no changes to commit\n') %
4057 (ctx.rev(), ctx))
4054 (ctx.rev(), ctx))
4058
4055
4059 # remove state when we complete successfully
4056 # remove state when we complete successfully
4060 if not opts.get('dry_run'):
4057 if not opts.get('dry_run'):
4061 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4058 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
4062
4059
4063 return 0
4060 return 0
4064
4061
4065 @command('grep',
4062 @command('grep',
4066 [('0', 'print0', None, _('end fields with NUL')),
4063 [('0', 'print0', None, _('end fields with NUL')),
4067 ('', 'all', None, _('print all revisions that match')),
4064 ('', 'all', None, _('print all revisions that match')),
4068 ('a', 'text', None, _('treat all files as text')),
4065 ('a', 'text', None, _('treat all files as text')),
4069 ('f', 'follow', None,
4066 ('f', 'follow', None,
4070 _('follow changeset history,'
4067 _('follow changeset history,'
4071 ' or file history across copies and renames')),
4068 ' or file history across copies and renames')),
4072 ('i', 'ignore-case', None, _('ignore case when matching')),
4069 ('i', 'ignore-case', None, _('ignore case when matching')),
4073 ('l', 'files-with-matches', None,
4070 ('l', 'files-with-matches', None,
4074 _('print only filenames and revisions that match')),
4071 _('print only filenames and revisions that match')),
4075 ('n', 'line-number', None, _('print matching line numbers')),
4072 ('n', 'line-number', None, _('print matching line numbers')),
4076 ('r', 'rev', [],
4073 ('r', 'rev', [],
4077 _('only search files changed within revision range'), _('REV')),
4074 _('only search files changed within revision range'), _('REV')),
4078 ('u', 'user', None, _('list the author (long with -v)')),
4075 ('u', 'user', None, _('list the author (long with -v)')),
4079 ('d', 'date', None, _('list the date (short with -q)')),
4076 ('d', 'date', None, _('list the date (short with -q)')),
4080 ] + walkopts,
4077 ] + walkopts,
4081 _('[OPTION]... PATTERN [FILE]...'),
4078 _('[OPTION]... PATTERN [FILE]...'),
4082 inferrepo=True)
4079 inferrepo=True)
4083 def grep(ui, repo, pattern, *pats, **opts):
4080 def grep(ui, repo, pattern, *pats, **opts):
4084 """search for a pattern in specified files and revisions
4081 """search for a pattern in specified files and revisions
4085
4082
4086 Search revisions of files for a regular expression.
4083 Search revisions of files for a regular expression.
4087
4084
4088 This command behaves differently than Unix grep. It only accepts
4085 This command behaves differently than Unix grep. It only accepts
4089 Python/Perl regexps. It searches repository history, not the
4086 Python/Perl regexps. It searches repository history, not the
4090 working directory. It always prints the revision number in which a
4087 working directory. It always prints the revision number in which a
4091 match appears.
4088 match appears.
4092
4089
4093 By default, grep only prints output for the first revision of a
4090 By default, grep only prints output for the first revision of a
4094 file in which it finds a match. To get it to print every revision
4091 file in which it finds a match. To get it to print every revision
4095 that contains a change in match status ("-" for a match that
4092 that contains a change in match status ("-" for a match that
4096 becomes a non-match, or "+" for a non-match that becomes a match),
4093 becomes a non-match, or "+" for a non-match that becomes a match),
4097 use the --all flag.
4094 use the --all flag.
4098
4095
4099 Returns 0 if a match is found, 1 otherwise.
4096 Returns 0 if a match is found, 1 otherwise.
4100 """
4097 """
4101 reflags = re.M
4098 reflags = re.M
4102 if opts.get('ignore_case'):
4099 if opts.get('ignore_case'):
4103 reflags |= re.I
4100 reflags |= re.I
4104 try:
4101 try:
4105 regexp = util.re.compile(pattern, reflags)
4102 regexp = util.re.compile(pattern, reflags)
4106 except re.error as inst:
4103 except re.error as inst:
4107 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4104 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
4108 return 1
4105 return 1
4109 sep, eol = ':', '\n'
4106 sep, eol = ':', '\n'
4110 if opts.get('print0'):
4107 if opts.get('print0'):
4111 sep = eol = '\0'
4108 sep = eol = '\0'
4112
4109
4113 getfile = util.lrucachefunc(repo.file)
4110 getfile = util.lrucachefunc(repo.file)
4114
4111
4115 def matchlines(body):
4112 def matchlines(body):
4116 begin = 0
4113 begin = 0
4117 linenum = 0
4114 linenum = 0
4118 while begin < len(body):
4115 while begin < len(body):
4119 match = regexp.search(body, begin)
4116 match = regexp.search(body, begin)
4120 if not match:
4117 if not match:
4121 break
4118 break
4122 mstart, mend = match.span()
4119 mstart, mend = match.span()
4123 linenum += body.count('\n', begin, mstart) + 1
4120 linenum += body.count('\n', begin, mstart) + 1
4124 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4121 lstart = body.rfind('\n', begin, mstart) + 1 or begin
4125 begin = body.find('\n', mend) + 1 or len(body) + 1
4122 begin = body.find('\n', mend) + 1 or len(body) + 1
4126 lend = begin - 1
4123 lend = begin - 1
4127 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4124 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
4128
4125
4129 class linestate(object):
4126 class linestate(object):
4130 def __init__(self, line, linenum, colstart, colend):
4127 def __init__(self, line, linenum, colstart, colend):
4131 self.line = line
4128 self.line = line
4132 self.linenum = linenum
4129 self.linenum = linenum
4133 self.colstart = colstart
4130 self.colstart = colstart
4134 self.colend = colend
4131 self.colend = colend
4135
4132
4136 def __hash__(self):
4133 def __hash__(self):
4137 return hash((self.linenum, self.line))
4134 return hash((self.linenum, self.line))
4138
4135
4139 def __eq__(self, other):
4136 def __eq__(self, other):
4140 return self.line == other.line
4137 return self.line == other.line
4141
4138
4142 def __iter__(self):
4139 def __iter__(self):
4143 yield (self.line[:self.colstart], '')
4140 yield (self.line[:self.colstart], '')
4144 yield (self.line[self.colstart:self.colend], 'grep.match')
4141 yield (self.line[self.colstart:self.colend], 'grep.match')
4145 rest = self.line[self.colend:]
4142 rest = self.line[self.colend:]
4146 while rest != '':
4143 while rest != '':
4147 match = regexp.search(rest)
4144 match = regexp.search(rest)
4148 if not match:
4145 if not match:
4149 yield (rest, '')
4146 yield (rest, '')
4150 break
4147 break
4151 mstart, mend = match.span()
4148 mstart, mend = match.span()
4152 yield (rest[:mstart], '')
4149 yield (rest[:mstart], '')
4153 yield (rest[mstart:mend], 'grep.match')
4150 yield (rest[mstart:mend], 'grep.match')
4154 rest = rest[mend:]
4151 rest = rest[mend:]
4155
4152
4156 matches = {}
4153 matches = {}
4157 copies = {}
4154 copies = {}
4158 def grepbody(fn, rev, body):
4155 def grepbody(fn, rev, body):
4159 matches[rev].setdefault(fn, [])
4156 matches[rev].setdefault(fn, [])
4160 m = matches[rev][fn]
4157 m = matches[rev][fn]
4161 for lnum, cstart, cend, line in matchlines(body):
4158 for lnum, cstart, cend, line in matchlines(body):
4162 s = linestate(line, lnum, cstart, cend)
4159 s = linestate(line, lnum, cstart, cend)
4163 m.append(s)
4160 m.append(s)
4164
4161
4165 def difflinestates(a, b):
4162 def difflinestates(a, b):
4166 sm = difflib.SequenceMatcher(None, a, b)
4163 sm = difflib.SequenceMatcher(None, a, b)
4167 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4164 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
4168 if tag == 'insert':
4165 if tag == 'insert':
4169 for i in xrange(blo, bhi):
4166 for i in xrange(blo, bhi):
4170 yield ('+', b[i])
4167 yield ('+', b[i])
4171 elif tag == 'delete':
4168 elif tag == 'delete':
4172 for i in xrange(alo, ahi):
4169 for i in xrange(alo, ahi):
4173 yield ('-', a[i])
4170 yield ('-', a[i])
4174 elif tag == 'replace':
4171 elif tag == 'replace':
4175 for i in xrange(alo, ahi):
4172 for i in xrange(alo, ahi):
4176 yield ('-', a[i])
4173 yield ('-', a[i])
4177 for i in xrange(blo, bhi):
4174 for i in xrange(blo, bhi):
4178 yield ('+', b[i])
4175 yield ('+', b[i])
4179
4176
4180 def display(fn, ctx, pstates, states):
4177 def display(fn, ctx, pstates, states):
4181 rev = ctx.rev()
4178 rev = ctx.rev()
4182 if ui.quiet:
4179 if ui.quiet:
4183 datefunc = util.shortdate
4180 datefunc = util.shortdate
4184 else:
4181 else:
4185 datefunc = util.datestr
4182 datefunc = util.datestr
4186 found = False
4183 found = False
4187 @util.cachefunc
4184 @util.cachefunc
4188 def binary():
4185 def binary():
4189 flog = getfile(fn)
4186 flog = getfile(fn)
4190 return util.binary(flog.read(ctx.filenode(fn)))
4187 return util.binary(flog.read(ctx.filenode(fn)))
4191
4188
4192 if opts.get('all'):
4189 if opts.get('all'):
4193 iter = difflinestates(pstates, states)
4190 iter = difflinestates(pstates, states)
4194 else:
4191 else:
4195 iter = [('', l) for l in states]
4192 iter = [('', l) for l in states]
4196 for change, l in iter:
4193 for change, l in iter:
4197 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4194 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
4198
4195
4199 if opts.get('line_number'):
4196 if opts.get('line_number'):
4200 cols.append((str(l.linenum), 'grep.linenumber'))
4197 cols.append((str(l.linenum), 'grep.linenumber'))
4201 if opts.get('all'):
4198 if opts.get('all'):
4202 cols.append((change, 'grep.change'))
4199 cols.append((change, 'grep.change'))
4203 if opts.get('user'):
4200 if opts.get('user'):
4204 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4201 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
4205 if opts.get('date'):
4202 if opts.get('date'):
4206 cols.append((datefunc(ctx.date()), 'grep.date'))
4203 cols.append((datefunc(ctx.date()), 'grep.date'))
4207 for col, label in cols[:-1]:
4204 for col, label in cols[:-1]:
4208 ui.write(col, label=label)
4205 ui.write(col, label=label)
4209 ui.write(sep, label='grep.sep')
4206 ui.write(sep, label='grep.sep')
4210 ui.write(cols[-1][0], label=cols[-1][1])
4207 ui.write(cols[-1][0], label=cols[-1][1])
4211 if not opts.get('files_with_matches'):
4208 if not opts.get('files_with_matches'):
4212 ui.write(sep, label='grep.sep')
4209 ui.write(sep, label='grep.sep')
4213 if not opts.get('text') and binary():
4210 if not opts.get('text') and binary():
4214 ui.write(" Binary file matches")
4211 ui.write(" Binary file matches")
4215 else:
4212 else:
4216 for s, label in l:
4213 for s, label in l:
4217 ui.write(s, label=label)
4214 ui.write(s, label=label)
4218 ui.write(eol)
4215 ui.write(eol)
4219 found = True
4216 found = True
4220 if opts.get('files_with_matches'):
4217 if opts.get('files_with_matches'):
4221 break
4218 break
4222 return found
4219 return found
4223
4220
4224 skip = {}
4221 skip = {}
4225 revfiles = {}
4222 revfiles = {}
4226 matchfn = scmutil.match(repo[None], pats, opts)
4223 matchfn = scmutil.match(repo[None], pats, opts)
4227 found = False
4224 found = False
4228 follow = opts.get('follow')
4225 follow = opts.get('follow')
4229
4226
4230 def prep(ctx, fns):
4227 def prep(ctx, fns):
4231 rev = ctx.rev()
4228 rev = ctx.rev()
4232 pctx = ctx.p1()
4229 pctx = ctx.p1()
4233 parent = pctx.rev()
4230 parent = pctx.rev()
4234 matches.setdefault(rev, {})
4231 matches.setdefault(rev, {})
4235 matches.setdefault(parent, {})
4232 matches.setdefault(parent, {})
4236 files = revfiles.setdefault(rev, [])
4233 files = revfiles.setdefault(rev, [])
4237 for fn in fns:
4234 for fn in fns:
4238 flog = getfile(fn)
4235 flog = getfile(fn)
4239 try:
4236 try:
4240 fnode = ctx.filenode(fn)
4237 fnode = ctx.filenode(fn)
4241 except error.LookupError:
4238 except error.LookupError:
4242 continue
4239 continue
4243
4240
4244 copied = flog.renamed(fnode)
4241 copied = flog.renamed(fnode)
4245 copy = follow and copied and copied[0]
4242 copy = follow and copied and copied[0]
4246 if copy:
4243 if copy:
4247 copies.setdefault(rev, {})[fn] = copy
4244 copies.setdefault(rev, {})[fn] = copy
4248 if fn in skip:
4245 if fn in skip:
4249 if copy:
4246 if copy:
4250 skip[copy] = True
4247 skip[copy] = True
4251 continue
4248 continue
4252 files.append(fn)
4249 files.append(fn)
4253
4250
4254 if fn not in matches[rev]:
4251 if fn not in matches[rev]:
4255 grepbody(fn, rev, flog.read(fnode))
4252 grepbody(fn, rev, flog.read(fnode))
4256
4253
4257 pfn = copy or fn
4254 pfn = copy or fn
4258 if pfn not in matches[parent]:
4255 if pfn not in matches[parent]:
4259 try:
4256 try:
4260 fnode = pctx.filenode(pfn)
4257 fnode = pctx.filenode(pfn)
4261 grepbody(pfn, parent, flog.read(fnode))
4258 grepbody(pfn, parent, flog.read(fnode))
4262 except error.LookupError:
4259 except error.LookupError:
4263 pass
4260 pass
4264
4261
4265 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4262 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4266 rev = ctx.rev()
4263 rev = ctx.rev()
4267 parent = ctx.p1().rev()
4264 parent = ctx.p1().rev()
4268 for fn in sorted(revfiles.get(rev, [])):
4265 for fn in sorted(revfiles.get(rev, [])):
4269 states = matches[rev][fn]
4266 states = matches[rev][fn]
4270 copy = copies.get(rev, {}).get(fn)
4267 copy = copies.get(rev, {}).get(fn)
4271 if fn in skip:
4268 if fn in skip:
4272 if copy:
4269 if copy:
4273 skip[copy] = True
4270 skip[copy] = True
4274 continue
4271 continue
4275 pstates = matches.get(parent, {}).get(copy or fn, [])
4272 pstates = matches.get(parent, {}).get(copy or fn, [])
4276 if pstates or states:
4273 if pstates or states:
4277 r = display(fn, ctx, pstates, states)
4274 r = display(fn, ctx, pstates, states)
4278 found = found or r
4275 found = found or r
4279 if r and not opts.get('all'):
4276 if r and not opts.get('all'):
4280 skip[fn] = True
4277 skip[fn] = True
4281 if copy:
4278 if copy:
4282 skip[copy] = True
4279 skip[copy] = True
4283 del matches[rev]
4280 del matches[rev]
4284 del revfiles[rev]
4281 del revfiles[rev]
4285
4282
4286 return not found
4283 return not found
4287
4284
4288 @command('heads',
4285 @command('heads',
4289 [('r', 'rev', '',
4286 [('r', 'rev', '',
4290 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4287 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4291 ('t', 'topo', False, _('show topological heads only')),
4288 ('t', 'topo', False, _('show topological heads only')),
4292 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4289 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4293 ('c', 'closed', False, _('show normal and closed branch heads')),
4290 ('c', 'closed', False, _('show normal and closed branch heads')),
4294 ] + templateopts,
4291 ] + templateopts,
4295 _('[-ct] [-r STARTREV] [REV]...'))
4292 _('[-ct] [-r STARTREV] [REV]...'))
4296 def heads(ui, repo, *branchrevs, **opts):
4293 def heads(ui, repo, *branchrevs, **opts):
4297 """show branch heads
4294 """show branch heads
4298
4295
4299 With no arguments, show all open branch heads in the repository.
4296 With no arguments, show all open branch heads in the repository.
4300 Branch heads are changesets that have no descendants on the
4297 Branch heads are changesets that have no descendants on the
4301 same branch. They are where development generally takes place and
4298 same branch. They are where development generally takes place and
4302 are the usual targets for update and merge operations.
4299 are the usual targets for update and merge operations.
4303
4300
4304 If one or more REVs are given, only open branch heads on the
4301 If one or more REVs are given, only open branch heads on the
4305 branches associated with the specified changesets are shown. This
4302 branches associated with the specified changesets are shown. This
4306 means that you can use :hg:`heads .` to see the heads on the
4303 means that you can use :hg:`heads .` to see the heads on the
4307 currently checked-out branch.
4304 currently checked-out branch.
4308
4305
4309 If -c/--closed is specified, also show branch heads marked closed
4306 If -c/--closed is specified, also show branch heads marked closed
4310 (see :hg:`commit --close-branch`).
4307 (see :hg:`commit --close-branch`).
4311
4308
4312 If STARTREV is specified, only those heads that are descendants of
4309 If STARTREV is specified, only those heads that are descendants of
4313 STARTREV will be displayed.
4310 STARTREV will be displayed.
4314
4311
4315 If -t/--topo is specified, named branch mechanics will be ignored and only
4312 If -t/--topo is specified, named branch mechanics will be ignored and only
4316 topological heads (changesets with no children) will be shown.
4313 topological heads (changesets with no children) will be shown.
4317
4314
4318 Returns 0 if matching heads are found, 1 if not.
4315 Returns 0 if matching heads are found, 1 if not.
4319 """
4316 """
4320
4317
4321 start = None
4318 start = None
4322 if 'rev' in opts:
4319 if 'rev' in opts:
4323 start = scmutil.revsingle(repo, opts['rev'], None).node()
4320 start = scmutil.revsingle(repo, opts['rev'], None).node()
4324
4321
4325 if opts.get('topo'):
4322 if opts.get('topo'):
4326 heads = [repo[h] for h in repo.heads(start)]
4323 heads = [repo[h] for h in repo.heads(start)]
4327 else:
4324 else:
4328 heads = []
4325 heads = []
4329 for branch in repo.branchmap():
4326 for branch in repo.branchmap():
4330 heads += repo.branchheads(branch, start, opts.get('closed'))
4327 heads += repo.branchheads(branch, start, opts.get('closed'))
4331 heads = [repo[h] for h in heads]
4328 heads = [repo[h] for h in heads]
4332
4329
4333 if branchrevs:
4330 if branchrevs:
4334 branches = set(repo[br].branch() for br in branchrevs)
4331 branches = set(repo[br].branch() for br in branchrevs)
4335 heads = [h for h in heads if h.branch() in branches]
4332 heads = [h for h in heads if h.branch() in branches]
4336
4333
4337 if opts.get('active') and branchrevs:
4334 if opts.get('active') and branchrevs:
4338 dagheads = repo.heads(start)
4335 dagheads = repo.heads(start)
4339 heads = [h for h in heads if h.node() in dagheads]
4336 heads = [h for h in heads if h.node() in dagheads]
4340
4337
4341 if branchrevs:
4338 if branchrevs:
4342 haveheads = set(h.branch() for h in heads)
4339 haveheads = set(h.branch() for h in heads)
4343 if branches - haveheads:
4340 if branches - haveheads:
4344 headless = ', '.join(b for b in branches - haveheads)
4341 headless = ', '.join(b for b in branches - haveheads)
4345 msg = _('no open branch heads found on branches %s')
4342 msg = _('no open branch heads found on branches %s')
4346 if opts.get('rev'):
4343 if opts.get('rev'):
4347 msg += _(' (started at %s)') % opts['rev']
4344 msg += _(' (started at %s)') % opts['rev']
4348 ui.warn((msg + '\n') % headless)
4345 ui.warn((msg + '\n') % headless)
4349
4346
4350 if not heads:
4347 if not heads:
4351 return 1
4348 return 1
4352
4349
4353 heads = sorted(heads, key=lambda x: -x.rev())
4350 heads = sorted(heads, key=lambda x: -x.rev())
4354 displayer = cmdutil.show_changeset(ui, repo, opts)
4351 displayer = cmdutil.show_changeset(ui, repo, opts)
4355 for ctx in heads:
4352 for ctx in heads:
4356 displayer.show(ctx)
4353 displayer.show(ctx)
4357 displayer.close()
4354 displayer.close()
4358
4355
4359 @command('help',
4356 @command('help',
4360 [('e', 'extension', None, _('show only help for extensions')),
4357 [('e', 'extension', None, _('show only help for extensions')),
4361 ('c', 'command', None, _('show only help for commands')),
4358 ('c', 'command', None, _('show only help for commands')),
4362 ('k', 'keyword', None, _('show topics matching keyword')),
4359 ('k', 'keyword', None, _('show topics matching keyword')),
4363 ('s', 'system', [], _('show help for specific platform(s)')),
4360 ('s', 'system', [], _('show help for specific platform(s)')),
4364 ],
4361 ],
4365 _('[-ecks] [TOPIC]'),
4362 _('[-ecks] [TOPIC]'),
4366 norepo=True)
4363 norepo=True)
4367 def help_(ui, name=None, **opts):
4364 def help_(ui, name=None, **opts):
4368 """show help for a given topic or a help overview
4365 """show help for a given topic or a help overview
4369
4366
4370 With no arguments, print a list of commands with short help messages.
4367 With no arguments, print a list of commands with short help messages.
4371
4368
4372 Given a topic, extension, or command name, print help for that
4369 Given a topic, extension, or command name, print help for that
4373 topic.
4370 topic.
4374
4371
4375 Returns 0 if successful.
4372 Returns 0 if successful.
4376 """
4373 """
4377
4374
4378 textwidth = min(ui.termwidth(), 80) - 2
4375 textwidth = min(ui.termwidth(), 80) - 2
4379
4376
4380 keep = opts.get('system') or []
4377 keep = opts.get('system') or []
4381 if len(keep) == 0:
4378 if len(keep) == 0:
4382 if sys.platform.startswith('win'):
4379 if sys.platform.startswith('win'):
4383 keep.append('windows')
4380 keep.append('windows')
4384 elif sys.platform == 'OpenVMS':
4381 elif sys.platform == 'OpenVMS':
4385 keep.append('vms')
4382 keep.append('vms')
4386 elif sys.platform == 'plan9':
4383 elif sys.platform == 'plan9':
4387 keep.append('plan9')
4384 keep.append('plan9')
4388 else:
4385 else:
4389 keep.append('unix')
4386 keep.append('unix')
4390 keep.append(sys.platform.lower())
4387 keep.append(sys.platform.lower())
4391 if ui.verbose:
4388 if ui.verbose:
4392 keep.append('verbose')
4389 keep.append('verbose')
4393
4390
4394 section = None
4391 section = None
4395 subtopic = None
4392 subtopic = None
4396 if name and '.' in name:
4393 if name and '.' in name:
4397 name, section = name.split('.', 1)
4394 name, section = name.split('.', 1)
4398 section = section.lower()
4395 section = section.lower()
4399 if '.' in section:
4396 if '.' in section:
4400 subtopic, section = section.split('.', 1)
4397 subtopic, section = section.split('.', 1)
4401 else:
4398 else:
4402 subtopic = section
4399 subtopic = section
4403
4400
4404 text = help.help_(ui, name, subtopic=subtopic, **opts)
4401 text = help.help_(ui, name, subtopic=subtopic, **opts)
4405
4402
4406 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4403 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4407 section=section)
4404 section=section)
4408
4405
4409 # We could have been given a weird ".foo" section without a name
4406 # We could have been given a weird ".foo" section without a name
4410 # to look for, or we could have simply failed to found "foo.bar"
4407 # to look for, or we could have simply failed to found "foo.bar"
4411 # because bar isn't a section of foo
4408 # because bar isn't a section of foo
4412 if section and not (formatted and name):
4409 if section and not (formatted and name):
4413 raise error.Abort(_("help section not found"))
4410 raise error.Abort(_("help section not found"))
4414
4411
4415 if 'verbose' in pruned:
4412 if 'verbose' in pruned:
4416 keep.append('omitted')
4413 keep.append('omitted')
4417 else:
4414 else:
4418 keep.append('notomitted')
4415 keep.append('notomitted')
4419 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4416 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4420 section=section)
4417 section=section)
4421 ui.write(formatted)
4418 ui.write(formatted)
4422
4419
4423
4420
4424 @command('identify|id',
4421 @command('identify|id',
4425 [('r', 'rev', '',
4422 [('r', 'rev', '',
4426 _('identify the specified revision'), _('REV')),
4423 _('identify the specified revision'), _('REV')),
4427 ('n', 'num', None, _('show local revision number')),
4424 ('n', 'num', None, _('show local revision number')),
4428 ('i', 'id', None, _('show global revision id')),
4425 ('i', 'id', None, _('show global revision id')),
4429 ('b', 'branch', None, _('show branch')),
4426 ('b', 'branch', None, _('show branch')),
4430 ('t', 'tags', None, _('show tags')),
4427 ('t', 'tags', None, _('show tags')),
4431 ('B', 'bookmarks', None, _('show bookmarks')),
4428 ('B', 'bookmarks', None, _('show bookmarks')),
4432 ] + remoteopts,
4429 ] + remoteopts,
4433 _('[-nibtB] [-r REV] [SOURCE]'),
4430 _('[-nibtB] [-r REV] [SOURCE]'),
4434 optionalrepo=True)
4431 optionalrepo=True)
4435 def identify(ui, repo, source=None, rev=None,
4432 def identify(ui, repo, source=None, rev=None,
4436 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4433 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4437 """identify the working directory or specified revision
4434 """identify the working directory or specified revision
4438
4435
4439 Print a summary identifying the repository state at REV using one or
4436 Print a summary identifying the repository state at REV using one or
4440 two parent hash identifiers, followed by a "+" if the working
4437 two parent hash identifiers, followed by a "+" if the working
4441 directory has uncommitted changes, the branch name (if not default),
4438 directory has uncommitted changes, the branch name (if not default),
4442 a list of tags, and a list of bookmarks.
4439 a list of tags, and a list of bookmarks.
4443
4440
4444 When REV is not given, print a summary of the current state of the
4441 When REV is not given, print a summary of the current state of the
4445 repository.
4442 repository.
4446
4443
4447 Specifying a path to a repository root or Mercurial bundle will
4444 Specifying a path to a repository root or Mercurial bundle will
4448 cause lookup to operate on that repository/bundle.
4445 cause lookup to operate on that repository/bundle.
4449
4446
4450 .. container:: verbose
4447 .. container:: verbose
4451
4448
4452 Examples:
4449 Examples:
4453
4450
4454 - generate a build identifier for the working directory::
4451 - generate a build identifier for the working directory::
4455
4452
4456 hg id --id > build-id.dat
4453 hg id --id > build-id.dat
4457
4454
4458 - find the revision corresponding to a tag::
4455 - find the revision corresponding to a tag::
4459
4456
4460 hg id -n -r 1.3
4457 hg id -n -r 1.3
4461
4458
4462 - check the most recent revision of a remote repository::
4459 - check the most recent revision of a remote repository::
4463
4460
4464 hg id -r tip http://selenic.com/hg/
4461 hg id -r tip http://selenic.com/hg/
4465
4462
4466 See :hg:`log` for generating more information about specific revisions,
4463 See :hg:`log` for generating more information about specific revisions,
4467 including full hash identifiers.
4464 including full hash identifiers.
4468
4465
4469 Returns 0 if successful.
4466 Returns 0 if successful.
4470 """
4467 """
4471
4468
4472 if not repo and not source:
4469 if not repo and not source:
4473 raise error.Abort(_("there is no Mercurial repository here "
4470 raise error.Abort(_("there is no Mercurial repository here "
4474 "(.hg not found)"))
4471 "(.hg not found)"))
4475
4472
4476 if ui.debugflag:
4473 if ui.debugflag:
4477 hexfunc = hex
4474 hexfunc = hex
4478 else:
4475 else:
4479 hexfunc = short
4476 hexfunc = short
4480 default = not (num or id or branch or tags or bookmarks)
4477 default = not (num or id or branch or tags or bookmarks)
4481 output = []
4478 output = []
4482 revs = []
4479 revs = []
4483
4480
4484 if source:
4481 if source:
4485 source, branches = hg.parseurl(ui.expandpath(source))
4482 source, branches = hg.parseurl(ui.expandpath(source))
4486 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4483 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4487 repo = peer.local()
4484 repo = peer.local()
4488 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4485 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4489
4486
4490 if not repo:
4487 if not repo:
4491 if num or branch or tags:
4488 if num or branch or tags:
4492 raise error.Abort(
4489 raise error.Abort(
4493 _("can't query remote revision number, branch, or tags"))
4490 _("can't query remote revision number, branch, or tags"))
4494 if not rev and revs:
4491 if not rev and revs:
4495 rev = revs[0]
4492 rev = revs[0]
4496 if not rev:
4493 if not rev:
4497 rev = "tip"
4494 rev = "tip"
4498
4495
4499 remoterev = peer.lookup(rev)
4496 remoterev = peer.lookup(rev)
4500 if default or id:
4497 if default or id:
4501 output = [hexfunc(remoterev)]
4498 output = [hexfunc(remoterev)]
4502
4499
4503 def getbms():
4500 def getbms():
4504 bms = []
4501 bms = []
4505
4502
4506 if 'bookmarks' in peer.listkeys('namespaces'):
4503 if 'bookmarks' in peer.listkeys('namespaces'):
4507 hexremoterev = hex(remoterev)
4504 hexremoterev = hex(remoterev)
4508 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4505 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4509 if bmr == hexremoterev]
4506 if bmr == hexremoterev]
4510
4507
4511 return sorted(bms)
4508 return sorted(bms)
4512
4509
4513 if bookmarks:
4510 if bookmarks:
4514 output.extend(getbms())
4511 output.extend(getbms())
4515 elif default and not ui.quiet:
4512 elif default and not ui.quiet:
4516 # multiple bookmarks for a single parent separated by '/'
4513 # multiple bookmarks for a single parent separated by '/'
4517 bm = '/'.join(getbms())
4514 bm = '/'.join(getbms())
4518 if bm:
4515 if bm:
4519 output.append(bm)
4516 output.append(bm)
4520 else:
4517 else:
4521 ctx = scmutil.revsingle(repo, rev, None)
4518 ctx = scmutil.revsingle(repo, rev, None)
4522
4519
4523 if ctx.rev() is None:
4520 if ctx.rev() is None:
4524 ctx = repo[None]
4521 ctx = repo[None]
4525 parents = ctx.parents()
4522 parents = ctx.parents()
4526 taglist = []
4523 taglist = []
4527 for p in parents:
4524 for p in parents:
4528 taglist.extend(p.tags())
4525 taglist.extend(p.tags())
4529
4526
4530 changed = ""
4527 changed = ""
4531 if default or id or num:
4528 if default or id or num:
4532 if (any(repo.status())
4529 if (any(repo.status())
4533 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4530 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4534 changed = '+'
4531 changed = '+'
4535 if default or id:
4532 if default or id:
4536 output = ["%s%s" %
4533 output = ["%s%s" %
4537 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4534 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4538 if num:
4535 if num:
4539 output.append("%s%s" %
4536 output.append("%s%s" %
4540 ('+'.join([str(p.rev()) for p in parents]), changed))
4537 ('+'.join([str(p.rev()) for p in parents]), changed))
4541 else:
4538 else:
4542 if default or id:
4539 if default or id:
4543 output = [hexfunc(ctx.node())]
4540 output = [hexfunc(ctx.node())]
4544 if num:
4541 if num:
4545 output.append(str(ctx.rev()))
4542 output.append(str(ctx.rev()))
4546 taglist = ctx.tags()
4543 taglist = ctx.tags()
4547
4544
4548 if default and not ui.quiet:
4545 if default and not ui.quiet:
4549 b = ctx.branch()
4546 b = ctx.branch()
4550 if b != 'default':
4547 if b != 'default':
4551 output.append("(%s)" % b)
4548 output.append("(%s)" % b)
4552
4549
4553 # multiple tags for a single parent separated by '/'
4550 # multiple tags for a single parent separated by '/'
4554 t = '/'.join(taglist)
4551 t = '/'.join(taglist)
4555 if t:
4552 if t:
4556 output.append(t)
4553 output.append(t)
4557
4554
4558 # multiple bookmarks for a single parent separated by '/'
4555 # multiple bookmarks for a single parent separated by '/'
4559 bm = '/'.join(ctx.bookmarks())
4556 bm = '/'.join(ctx.bookmarks())
4560 if bm:
4557 if bm:
4561 output.append(bm)
4558 output.append(bm)
4562 else:
4559 else:
4563 if branch:
4560 if branch:
4564 output.append(ctx.branch())
4561 output.append(ctx.branch())
4565
4562
4566 if tags:
4563 if tags:
4567 output.extend(taglist)
4564 output.extend(taglist)
4568
4565
4569 if bookmarks:
4566 if bookmarks:
4570 output.extend(ctx.bookmarks())
4567 output.extend(ctx.bookmarks())
4571
4568
4572 ui.write("%s\n" % ' '.join(output))
4569 ui.write("%s\n" % ' '.join(output))
4573
4570
4574 @command('import|patch',
4571 @command('import|patch',
4575 [('p', 'strip', 1,
4572 [('p', 'strip', 1,
4576 _('directory strip option for patch. This has the same '
4573 _('directory strip option for patch. This has the same '
4577 'meaning as the corresponding patch option'), _('NUM')),
4574 'meaning as the corresponding patch option'), _('NUM')),
4578 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4575 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4579 ('e', 'edit', False, _('invoke editor on commit messages')),
4576 ('e', 'edit', False, _('invoke editor on commit messages')),
4580 ('f', 'force', None,
4577 ('f', 'force', None,
4581 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4578 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4582 ('', 'no-commit', None,
4579 ('', 'no-commit', None,
4583 _("don't commit, just update the working directory")),
4580 _("don't commit, just update the working directory")),
4584 ('', 'bypass', None,
4581 ('', 'bypass', None,
4585 _("apply patch without touching the working directory")),
4582 _("apply patch without touching the working directory")),
4586 ('', 'partial', None,
4583 ('', 'partial', None,
4587 _('commit even if some hunks fail')),
4584 _('commit even if some hunks fail')),
4588 ('', 'exact', None,
4585 ('', 'exact', None,
4589 _('apply patch to the nodes from which it was generated')),
4586 _('apply patch to the nodes from which it was generated')),
4590 ('', 'prefix', '',
4587 ('', 'prefix', '',
4591 _('apply patch to subdirectory'), _('DIR')),
4588 _('apply patch to subdirectory'), _('DIR')),
4592 ('', 'import-branch', None,
4589 ('', 'import-branch', None,
4593 _('use any branch information in patch (implied by --exact)'))] +
4590 _('use any branch information in patch (implied by --exact)'))] +
4594 commitopts + commitopts2 + similarityopts,
4591 commitopts + commitopts2 + similarityopts,
4595 _('[OPTION]... PATCH...'))
4592 _('[OPTION]... PATCH...'))
4596 def import_(ui, repo, patch1=None, *patches, **opts):
4593 def import_(ui, repo, patch1=None, *patches, **opts):
4597 """import an ordered set of patches
4594 """import an ordered set of patches
4598
4595
4599 Import a list of patches and commit them individually (unless
4596 Import a list of patches and commit them individually (unless
4600 --no-commit is specified).
4597 --no-commit is specified).
4601
4598
4602 To read a patch from standard input, use "-" as the patch name. If
4599 To read a patch from standard input, use "-" as the patch name. If
4603 a URL is specified, the patch will be downloaded from there.
4600 a URL is specified, the patch will be downloaded from there.
4604
4601
4605 Import first applies changes to the working directory (unless
4602 Import first applies changes to the working directory (unless
4606 --bypass is specified), import will abort if there are outstanding
4603 --bypass is specified), import will abort if there are outstanding
4607 changes.
4604 changes.
4608
4605
4609 Use --bypass to apply and commit patches directly to the
4606 Use --bypass to apply and commit patches directly to the
4610 repository, without affecting the working directory. Without
4607 repository, without affecting the working directory. Without
4611 --exact, patches will be applied on top of the working directory
4608 --exact, patches will be applied on top of the working directory
4612 parent revision.
4609 parent revision.
4613
4610
4614 You can import a patch straight from a mail message. Even patches
4611 You can import a patch straight from a mail message. Even patches
4615 as attachments work (to use the body part, it must have type
4612 as attachments work (to use the body part, it must have type
4616 text/plain or text/x-patch). From and Subject headers of email
4613 text/plain or text/x-patch). From and Subject headers of email
4617 message are used as default committer and commit message. All
4614 message are used as default committer and commit message. All
4618 text/plain body parts before first diff are added to the commit
4615 text/plain body parts before first diff are added to the commit
4619 message.
4616 message.
4620
4617
4621 If the imported patch was generated by :hg:`export`, user and
4618 If the imported patch was generated by :hg:`export`, user and
4622 description from patch override values from message headers and
4619 description from patch override values from message headers and
4623 body. Values given on command line with -m/--message and -u/--user
4620 body. Values given on command line with -m/--message and -u/--user
4624 override these.
4621 override these.
4625
4622
4626 If --exact is specified, import will set the working directory to
4623 If --exact is specified, import will set the working directory to
4627 the parent of each patch before applying it, and will abort if the
4624 the parent of each patch before applying it, and will abort if the
4628 resulting changeset has a different ID than the one recorded in
4625 resulting changeset has a different ID than the one recorded in
4629 the patch. This may happen due to character set problems or other
4626 the patch. This may happen due to character set problems or other
4630 deficiencies in the text patch format.
4627 deficiencies in the text patch format.
4631
4628
4632 Use --partial to ensure a changeset will be created from the patch
4629 Use --partial to ensure a changeset will be created from the patch
4633 even if some hunks fail to apply. Hunks that fail to apply will be
4630 even if some hunks fail to apply. Hunks that fail to apply will be
4634 written to a <target-file>.rej file. Conflicts can then be resolved
4631 written to a <target-file>.rej file. Conflicts can then be resolved
4635 by hand before :hg:`commit --amend` is run to update the created
4632 by hand before :hg:`commit --amend` is run to update the created
4636 changeset. This flag exists to let people import patches that
4633 changeset. This flag exists to let people import patches that
4637 partially apply without losing the associated metadata (author,
4634 partially apply without losing the associated metadata (author,
4638 date, description, ...).
4635 date, description, ...).
4639
4636
4640 .. note::
4637 .. note::
4641
4638
4642 When no hunks apply cleanly, :hg:`import --partial` will create
4639 When no hunks apply cleanly, :hg:`import --partial` will create
4643 an empty changeset, importing only the patch metadata.
4640 an empty changeset, importing only the patch metadata.
4644
4641
4645 With -s/--similarity, hg will attempt to discover renames and
4642 With -s/--similarity, hg will attempt to discover renames and
4646 copies in the patch in the same way as :hg:`addremove`.
4643 copies in the patch in the same way as :hg:`addremove`.
4647
4644
4648 It is possible to use external patch programs to perform the patch
4645 It is possible to use external patch programs to perform the patch
4649 by setting the ``ui.patch`` configuration option. For the default
4646 by setting the ``ui.patch`` configuration option. For the default
4650 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4647 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4651 See :hg:`help config` for more information about configuration
4648 See :hg:`help config` for more information about configuration
4652 files and how to use these options.
4649 files and how to use these options.
4653
4650
4654 See :hg:`help dates` for a list of formats valid for -d/--date.
4651 See :hg:`help dates` for a list of formats valid for -d/--date.
4655
4652
4656 .. container:: verbose
4653 .. container:: verbose
4657
4654
4658 Examples:
4655 Examples:
4659
4656
4660 - import a traditional patch from a website and detect renames::
4657 - import a traditional patch from a website and detect renames::
4661
4658
4662 hg import -s 80 http://example.com/bugfix.patch
4659 hg import -s 80 http://example.com/bugfix.patch
4663
4660
4664 - import a changeset from an hgweb server::
4661 - import a changeset from an hgweb server::
4665
4662
4666 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4663 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4667
4664
4668 - import all the patches in an Unix-style mbox::
4665 - import all the patches in an Unix-style mbox::
4669
4666
4670 hg import incoming-patches.mbox
4667 hg import incoming-patches.mbox
4671
4668
4672 - attempt to exactly restore an exported changeset (not always
4669 - attempt to exactly restore an exported changeset (not always
4673 possible)::
4670 possible)::
4674
4671
4675 hg import --exact proposed-fix.patch
4672 hg import --exact proposed-fix.patch
4676
4673
4677 - use an external tool to apply a patch which is too fuzzy for
4674 - use an external tool to apply a patch which is too fuzzy for
4678 the default internal tool.
4675 the default internal tool.
4679
4676
4680 hg import --config ui.patch="patch --merge" fuzzy.patch
4677 hg import --config ui.patch="patch --merge" fuzzy.patch
4681
4678
4682 - change the default fuzzing from 2 to a less strict 7
4679 - change the default fuzzing from 2 to a less strict 7
4683
4680
4684 hg import --config ui.fuzz=7 fuzz.patch
4681 hg import --config ui.fuzz=7 fuzz.patch
4685
4682
4686 Returns 0 on success, 1 on partial success (see --partial).
4683 Returns 0 on success, 1 on partial success (see --partial).
4687 """
4684 """
4688
4685
4689 if not patch1:
4686 if not patch1:
4690 raise error.Abort(_('need at least one patch to import'))
4687 raise error.Abort(_('need at least one patch to import'))
4691
4688
4692 patches = (patch1,) + patches
4689 patches = (patch1,) + patches
4693
4690
4694 date = opts.get('date')
4691 date = opts.get('date')
4695 if date:
4692 if date:
4696 opts['date'] = util.parsedate(date)
4693 opts['date'] = util.parsedate(date)
4697
4694
4698 exact = opts.get('exact')
4695 exact = opts.get('exact')
4699 update = not opts.get('bypass')
4696 update = not opts.get('bypass')
4700 if not update and opts.get('no_commit'):
4697 if not update and opts.get('no_commit'):
4701 raise error.Abort(_('cannot use --no-commit with --bypass'))
4698 raise error.Abort(_('cannot use --no-commit with --bypass'))
4702 try:
4699 try:
4703 sim = float(opts.get('similarity') or 0)
4700 sim = float(opts.get('similarity') or 0)
4704 except ValueError:
4701 except ValueError:
4705 raise error.Abort(_('similarity must be a number'))
4702 raise error.Abort(_('similarity must be a number'))
4706 if sim < 0 or sim > 100:
4703 if sim < 0 or sim > 100:
4707 raise error.Abort(_('similarity must be between 0 and 100'))
4704 raise error.Abort(_('similarity must be between 0 and 100'))
4708 if sim and not update:
4705 if sim and not update:
4709 raise error.Abort(_('cannot use --similarity with --bypass'))
4706 raise error.Abort(_('cannot use --similarity with --bypass'))
4710 if exact:
4707 if exact:
4711 if opts.get('edit'):
4708 if opts.get('edit'):
4712 raise error.Abort(_('cannot use --exact with --edit'))
4709 raise error.Abort(_('cannot use --exact with --edit'))
4713 if opts.get('prefix'):
4710 if opts.get('prefix'):
4714 raise error.Abort(_('cannot use --exact with --prefix'))
4711 raise error.Abort(_('cannot use --exact with --prefix'))
4715
4712
4716 base = opts["base"]
4713 base = opts["base"]
4717 wlock = dsguard = lock = tr = None
4714 wlock = dsguard = lock = tr = None
4718 msgs = []
4715 msgs = []
4719 ret = 0
4716 ret = 0
4720
4717
4721
4718
4722 try:
4719 try:
4723 wlock = repo.wlock()
4720 wlock = repo.wlock()
4724
4721
4725 if update:
4722 if update:
4726 cmdutil.checkunfinished(repo)
4723 cmdutil.checkunfinished(repo)
4727 if (exact or not opts.get('force')):
4724 if (exact or not opts.get('force')):
4728 cmdutil.bailifchanged(repo)
4725 cmdutil.bailifchanged(repo)
4729
4726
4730 if not opts.get('no_commit'):
4727 if not opts.get('no_commit'):
4731 lock = repo.lock()
4728 lock = repo.lock()
4732 tr = repo.transaction('import')
4729 tr = repo.transaction('import')
4733 else:
4730 else:
4734 dsguard = cmdutil.dirstateguard(repo, 'import')
4731 dsguard = cmdutil.dirstateguard(repo, 'import')
4735 parents = repo[None].parents()
4732 parents = repo[None].parents()
4736 for patchurl in patches:
4733 for patchurl in patches:
4737 if patchurl == '-':
4734 if patchurl == '-':
4738 ui.status(_('applying patch from stdin\n'))
4735 ui.status(_('applying patch from stdin\n'))
4739 patchfile = ui.fin
4736 patchfile = ui.fin
4740 patchurl = 'stdin' # for error message
4737 patchurl = 'stdin' # for error message
4741 else:
4738 else:
4742 patchurl = os.path.join(base, patchurl)
4739 patchurl = os.path.join(base, patchurl)
4743 ui.status(_('applying %s\n') % patchurl)
4740 ui.status(_('applying %s\n') % patchurl)
4744 patchfile = hg.openpath(ui, patchurl)
4741 patchfile = hg.openpath(ui, patchurl)
4745
4742
4746 haspatch = False
4743 haspatch = False
4747 for hunk in patch.split(patchfile):
4744 for hunk in patch.split(patchfile):
4748 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4745 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4749 parents, opts,
4746 parents, opts,
4750 msgs, hg.clean)
4747 msgs, hg.clean)
4751 if msg:
4748 if msg:
4752 haspatch = True
4749 haspatch = True
4753 ui.note(msg + '\n')
4750 ui.note(msg + '\n')
4754 if update or exact:
4751 if update or exact:
4755 parents = repo[None].parents()
4752 parents = repo[None].parents()
4756 else:
4753 else:
4757 parents = [repo[node]]
4754 parents = [repo[node]]
4758 if rej:
4755 if rej:
4759 ui.write_err(_("patch applied partially\n"))
4756 ui.write_err(_("patch applied partially\n"))
4760 ui.write_err(_("(fix the .rej files and run "
4757 ui.write_err(_("(fix the .rej files and run "
4761 "`hg commit --amend`)\n"))
4758 "`hg commit --amend`)\n"))
4762 ret = 1
4759 ret = 1
4763 break
4760 break
4764
4761
4765 if not haspatch:
4762 if not haspatch:
4766 raise error.Abort(_('%s: no diffs found') % patchurl)
4763 raise error.Abort(_('%s: no diffs found') % patchurl)
4767
4764
4768 if tr:
4765 if tr:
4769 tr.close()
4766 tr.close()
4770 if msgs:
4767 if msgs:
4771 repo.savecommitmessage('\n* * *\n'.join(msgs))
4768 repo.savecommitmessage('\n* * *\n'.join(msgs))
4772 if dsguard:
4769 if dsguard:
4773 dsguard.close()
4770 dsguard.close()
4774 return ret
4771 return ret
4775 finally:
4772 finally:
4776 if tr:
4773 if tr:
4777 tr.release()
4774 tr.release()
4778 release(lock, dsguard, wlock)
4775 release(lock, dsguard, wlock)
4779
4776
4780 @command('incoming|in',
4777 @command('incoming|in',
4781 [('f', 'force', None,
4778 [('f', 'force', None,
4782 _('run even if remote repository is unrelated')),
4779 _('run even if remote repository is unrelated')),
4783 ('n', 'newest-first', None, _('show newest record first')),
4780 ('n', 'newest-first', None, _('show newest record first')),
4784 ('', 'bundle', '',
4781 ('', 'bundle', '',
4785 _('file to store the bundles into'), _('FILE')),
4782 _('file to store the bundles into'), _('FILE')),
4786 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4783 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4787 ('B', 'bookmarks', False, _("compare bookmarks")),
4784 ('B', 'bookmarks', False, _("compare bookmarks")),
4788 ('b', 'branch', [],
4785 ('b', 'branch', [],
4789 _('a specific branch you would like to pull'), _('BRANCH')),
4786 _('a specific branch you would like to pull'), _('BRANCH')),
4790 ] + logopts + remoteopts + subrepoopts,
4787 ] + logopts + remoteopts + subrepoopts,
4791 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4788 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4792 def incoming(ui, repo, source="default", **opts):
4789 def incoming(ui, repo, source="default", **opts):
4793 """show new changesets found in source
4790 """show new changesets found in source
4794
4791
4795 Show new changesets found in the specified path/URL or the default
4792 Show new changesets found in the specified path/URL or the default
4796 pull location. These are the changesets that would have been pulled
4793 pull location. These are the changesets that would have been pulled
4797 if a pull at the time you issued this command.
4794 if a pull at the time you issued this command.
4798
4795
4799 See pull for valid source format details.
4796 See pull for valid source format details.
4800
4797
4801 .. container:: verbose
4798 .. container:: verbose
4802
4799
4803 With -B/--bookmarks, the result of bookmark comparison between
4800 With -B/--bookmarks, the result of bookmark comparison between
4804 local and remote repositories is displayed. With -v/--verbose,
4801 local and remote repositories is displayed. With -v/--verbose,
4805 status is also displayed for each bookmark like below::
4802 status is also displayed for each bookmark like below::
4806
4803
4807 BM1 01234567890a added
4804 BM1 01234567890a added
4808 BM2 1234567890ab advanced
4805 BM2 1234567890ab advanced
4809 BM3 234567890abc diverged
4806 BM3 234567890abc diverged
4810 BM4 34567890abcd changed
4807 BM4 34567890abcd changed
4811
4808
4812 The action taken locally when pulling depends on the
4809 The action taken locally when pulling depends on the
4813 status of each bookmark:
4810 status of each bookmark:
4814
4811
4815 :``added``: pull will create it
4812 :``added``: pull will create it
4816 :``advanced``: pull will update it
4813 :``advanced``: pull will update it
4817 :``diverged``: pull will create a divergent bookmark
4814 :``diverged``: pull will create a divergent bookmark
4818 :``changed``: result depends on remote changesets
4815 :``changed``: result depends on remote changesets
4819
4816
4820 From the point of view of pulling behavior, bookmark
4817 From the point of view of pulling behavior, bookmark
4821 existing only in the remote repository are treated as ``added``,
4818 existing only in the remote repository are treated as ``added``,
4822 even if it is in fact locally deleted.
4819 even if it is in fact locally deleted.
4823
4820
4824 .. container:: verbose
4821 .. container:: verbose
4825
4822
4826 For remote repository, using --bundle avoids downloading the
4823 For remote repository, using --bundle avoids downloading the
4827 changesets twice if the incoming is followed by a pull.
4824 changesets twice if the incoming is followed by a pull.
4828
4825
4829 Examples:
4826 Examples:
4830
4827
4831 - show incoming changes with patches and full description::
4828 - show incoming changes with patches and full description::
4832
4829
4833 hg incoming -vp
4830 hg incoming -vp
4834
4831
4835 - show incoming changes excluding merges, store a bundle::
4832 - show incoming changes excluding merges, store a bundle::
4836
4833
4837 hg in -vpM --bundle incoming.hg
4834 hg in -vpM --bundle incoming.hg
4838 hg pull incoming.hg
4835 hg pull incoming.hg
4839
4836
4840 - briefly list changes inside a bundle::
4837 - briefly list changes inside a bundle::
4841
4838
4842 hg in changes.hg -T "{desc|firstline}\\n"
4839 hg in changes.hg -T "{desc|firstline}\\n"
4843
4840
4844 Returns 0 if there are incoming changes, 1 otherwise.
4841 Returns 0 if there are incoming changes, 1 otherwise.
4845 """
4842 """
4846 if opts.get('graph'):
4843 if opts.get('graph'):
4847 cmdutil.checkunsupportedgraphflags([], opts)
4844 cmdutil.checkunsupportedgraphflags([], opts)
4848 def display(other, chlist, displayer):
4845 def display(other, chlist, displayer):
4849 revdag = cmdutil.graphrevs(other, chlist, opts)
4846 revdag = cmdutil.graphrevs(other, chlist, opts)
4850 cmdutil.displaygraph(ui, repo, revdag, displayer,
4847 cmdutil.displaygraph(ui, repo, revdag, displayer,
4851 graphmod.asciiedges)
4848 graphmod.asciiedges)
4852
4849
4853 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4850 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4854 return 0
4851 return 0
4855
4852
4856 if opts.get('bundle') and opts.get('subrepos'):
4853 if opts.get('bundle') and opts.get('subrepos'):
4857 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4854 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4858
4855
4859 if opts.get('bookmarks'):
4856 if opts.get('bookmarks'):
4860 source, branches = hg.parseurl(ui.expandpath(source),
4857 source, branches = hg.parseurl(ui.expandpath(source),
4861 opts.get('branch'))
4858 opts.get('branch'))
4862 other = hg.peer(repo, opts, source)
4859 other = hg.peer(repo, opts, source)
4863 if 'bookmarks' not in other.listkeys('namespaces'):
4860 if 'bookmarks' not in other.listkeys('namespaces'):
4864 ui.warn(_("remote doesn't support bookmarks\n"))
4861 ui.warn(_("remote doesn't support bookmarks\n"))
4865 return 0
4862 return 0
4866 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4863 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4867 return bookmarks.incoming(ui, repo, other)
4864 return bookmarks.incoming(ui, repo, other)
4868
4865
4869 repo._subtoppath = ui.expandpath(source)
4866 repo._subtoppath = ui.expandpath(source)
4870 try:
4867 try:
4871 return hg.incoming(ui, repo, source, opts)
4868 return hg.incoming(ui, repo, source, opts)
4872 finally:
4869 finally:
4873 del repo._subtoppath
4870 del repo._subtoppath
4874
4871
4875
4872
4876 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4873 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4877 norepo=True)
4874 norepo=True)
4878 def init(ui, dest=".", **opts):
4875 def init(ui, dest=".", **opts):
4879 """create a new repository in the given directory
4876 """create a new repository in the given directory
4880
4877
4881 Initialize a new repository in the given directory. If the given
4878 Initialize a new repository in the given directory. If the given
4882 directory does not exist, it will be created.
4879 directory does not exist, it will be created.
4883
4880
4884 If no directory is given, the current directory is used.
4881 If no directory is given, the current directory is used.
4885
4882
4886 It is possible to specify an ``ssh://`` URL as the destination.
4883 It is possible to specify an ``ssh://`` URL as the destination.
4887 See :hg:`help urls` for more information.
4884 See :hg:`help urls` for more information.
4888
4885
4889 Returns 0 on success.
4886 Returns 0 on success.
4890 """
4887 """
4891 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4888 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4892
4889
4893 @command('locate',
4890 @command('locate',
4894 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4891 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4895 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4892 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4896 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4893 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4897 ] + walkopts,
4894 ] + walkopts,
4898 _('[OPTION]... [PATTERN]...'))
4895 _('[OPTION]... [PATTERN]...'))
4899 def locate(ui, repo, *pats, **opts):
4896 def locate(ui, repo, *pats, **opts):
4900 """locate files matching specific patterns (DEPRECATED)
4897 """locate files matching specific patterns (DEPRECATED)
4901
4898
4902 Print files under Mercurial control in the working directory whose
4899 Print files under Mercurial control in the working directory whose
4903 names match the given patterns.
4900 names match the given patterns.
4904
4901
4905 By default, this command searches all directories in the working
4902 By default, this command searches all directories in the working
4906 directory. To search just the current directory and its
4903 directory. To search just the current directory and its
4907 subdirectories, use "--include .".
4904 subdirectories, use "--include .".
4908
4905
4909 If no patterns are given to match, this command prints the names
4906 If no patterns are given to match, this command prints the names
4910 of all files under Mercurial control in the working directory.
4907 of all files under Mercurial control in the working directory.
4911
4908
4912 If you want to feed the output of this command into the "xargs"
4909 If you want to feed the output of this command into the "xargs"
4913 command, use the -0 option to both this command and "xargs". This
4910 command, use the -0 option to both this command and "xargs". This
4914 will avoid the problem of "xargs" treating single filenames that
4911 will avoid the problem of "xargs" treating single filenames that
4915 contain whitespace as multiple filenames.
4912 contain whitespace as multiple filenames.
4916
4913
4917 See :hg:`help files` for a more versatile command.
4914 See :hg:`help files` for a more versatile command.
4918
4915
4919 Returns 0 if a match is found, 1 otherwise.
4916 Returns 0 if a match is found, 1 otherwise.
4920 """
4917 """
4921 if opts.get('print0'):
4918 if opts.get('print0'):
4922 end = '\0'
4919 end = '\0'
4923 else:
4920 else:
4924 end = '\n'
4921 end = '\n'
4925 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4922 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4926
4923
4927 ret = 1
4924 ret = 1
4928 ctx = repo[rev]
4925 ctx = repo[rev]
4929 m = scmutil.match(ctx, pats, opts, default='relglob',
4926 m = scmutil.match(ctx, pats, opts, default='relglob',
4930 badfn=lambda x, y: False)
4927 badfn=lambda x, y: False)
4931
4928
4932 for abs in ctx.matches(m):
4929 for abs in ctx.matches(m):
4933 if opts.get('fullpath'):
4930 if opts.get('fullpath'):
4934 ui.write(repo.wjoin(abs), end)
4931 ui.write(repo.wjoin(abs), end)
4935 else:
4932 else:
4936 ui.write(((pats and m.rel(abs)) or abs), end)
4933 ui.write(((pats and m.rel(abs)) or abs), end)
4937 ret = 0
4934 ret = 0
4938
4935
4939 return ret
4936 return ret
4940
4937
4941 @command('^log|history',
4938 @command('^log|history',
4942 [('f', 'follow', None,
4939 [('f', 'follow', None,
4943 _('follow changeset history, or file history across copies and renames')),
4940 _('follow changeset history, or file history across copies and renames')),
4944 ('', 'follow-first', None,
4941 ('', 'follow-first', None,
4945 _('only follow the first parent of merge changesets (DEPRECATED)')),
4942 _('only follow the first parent of merge changesets (DEPRECATED)')),
4946 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4943 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4947 ('C', 'copies', None, _('show copied files')),
4944 ('C', 'copies', None, _('show copied files')),
4948 ('k', 'keyword', [],
4945 ('k', 'keyword', [],
4949 _('do case-insensitive search for a given text'), _('TEXT')),
4946 _('do case-insensitive search for a given text'), _('TEXT')),
4950 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4947 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4951 ('', 'removed', None, _('include revisions where files were removed')),
4948 ('', 'removed', None, _('include revisions where files were removed')),
4952 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4949 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4953 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4950 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4954 ('', 'only-branch', [],
4951 ('', 'only-branch', [],
4955 _('show only changesets within the given named branch (DEPRECATED)'),
4952 _('show only changesets within the given named branch (DEPRECATED)'),
4956 _('BRANCH')),
4953 _('BRANCH')),
4957 ('b', 'branch', [],
4954 ('b', 'branch', [],
4958 _('show changesets within the given named branch'), _('BRANCH')),
4955 _('show changesets within the given named branch'), _('BRANCH')),
4959 ('P', 'prune', [],
4956 ('P', 'prune', [],
4960 _('do not display revision or any of its ancestors'), _('REV')),
4957 _('do not display revision or any of its ancestors'), _('REV')),
4961 ] + logopts + walkopts,
4958 ] + logopts + walkopts,
4962 _('[OPTION]... [FILE]'),
4959 _('[OPTION]... [FILE]'),
4963 inferrepo=True)
4960 inferrepo=True)
4964 def log(ui, repo, *pats, **opts):
4961 def log(ui, repo, *pats, **opts):
4965 """show revision history of entire repository or files
4962 """show revision history of entire repository or files
4966
4963
4967 Print the revision history of the specified files or the entire
4964 Print the revision history of the specified files or the entire
4968 project.
4965 project.
4969
4966
4970 If no revision range is specified, the default is ``tip:0`` unless
4967 If no revision range is specified, the default is ``tip:0`` unless
4971 --follow is set, in which case the working directory parent is
4968 --follow is set, in which case the working directory parent is
4972 used as the starting revision.
4969 used as the starting revision.
4973
4970
4974 File history is shown without following rename or copy history of
4971 File history is shown without following rename or copy history of
4975 files. Use -f/--follow with a filename to follow history across
4972 files. Use -f/--follow with a filename to follow history across
4976 renames and copies. --follow without a filename will only show
4973 renames and copies. --follow without a filename will only show
4977 ancestors or descendants of the starting revision.
4974 ancestors or descendants of the starting revision.
4978
4975
4979 By default this command prints revision number and changeset id,
4976 By default this command prints revision number and changeset id,
4980 tags, non-trivial parents, user, date and time, and a summary for
4977 tags, non-trivial parents, user, date and time, and a summary for
4981 each commit. When the -v/--verbose switch is used, the list of
4978 each commit. When the -v/--verbose switch is used, the list of
4982 changed files and full commit message are shown.
4979 changed files and full commit message are shown.
4983
4980
4984 With --graph the revisions are shown as an ASCII art DAG with the most
4981 With --graph the revisions are shown as an ASCII art DAG with the most
4985 recent changeset at the top.
4982 recent changeset at the top.
4986 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4983 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4987 and '+' represents a fork where the changeset from the lines below is a
4984 and '+' represents a fork where the changeset from the lines below is a
4988 parent of the 'o' merge on the same line.
4985 parent of the 'o' merge on the same line.
4989
4986
4990 .. note::
4987 .. note::
4991
4988
4992 :hg:`log --patch` may generate unexpected diff output for merge
4989 :hg:`log --patch` may generate unexpected diff output for merge
4993 changesets, as it will only compare the merge changeset against
4990 changesets, as it will only compare the merge changeset against
4994 its first parent. Also, only files different from BOTH parents
4991 its first parent. Also, only files different from BOTH parents
4995 will appear in files:.
4992 will appear in files:.
4996
4993
4997 .. note::
4994 .. note::
4998
4995
4999 For performance reasons, :hg:`log FILE` may omit duplicate changes
4996 For performance reasons, :hg:`log FILE` may omit duplicate changes
5000 made on branches and will not show removals or mode changes. To
4997 made on branches and will not show removals or mode changes. To
5001 see all such changes, use the --removed switch.
4998 see all such changes, use the --removed switch.
5002
4999
5003 .. container:: verbose
5000 .. container:: verbose
5004
5001
5005 Some examples:
5002 Some examples:
5006
5003
5007 - changesets with full descriptions and file lists::
5004 - changesets with full descriptions and file lists::
5008
5005
5009 hg log -v
5006 hg log -v
5010
5007
5011 - changesets ancestral to the working directory::
5008 - changesets ancestral to the working directory::
5012
5009
5013 hg log -f
5010 hg log -f
5014
5011
5015 - last 10 commits on the current branch::
5012 - last 10 commits on the current branch::
5016
5013
5017 hg log -l 10 -b .
5014 hg log -l 10 -b .
5018
5015
5019 - changesets showing all modifications of a file, including removals::
5016 - changesets showing all modifications of a file, including removals::
5020
5017
5021 hg log --removed file.c
5018 hg log --removed file.c
5022
5019
5023 - all changesets that touch a directory, with diffs, excluding merges::
5020 - all changesets that touch a directory, with diffs, excluding merges::
5024
5021
5025 hg log -Mp lib/
5022 hg log -Mp lib/
5026
5023
5027 - all revision numbers that match a keyword::
5024 - all revision numbers that match a keyword::
5028
5025
5029 hg log -k bug --template "{rev}\\n"
5026 hg log -k bug --template "{rev}\\n"
5030
5027
5031 - the full hash identifier of the working directory parent::
5028 - the full hash identifier of the working directory parent::
5032
5029
5033 hg log -r . --template "{node}\\n"
5030 hg log -r . --template "{node}\\n"
5034
5031
5035 - list available log templates::
5032 - list available log templates::
5036
5033
5037 hg log -T list
5034 hg log -T list
5038
5035
5039 - check if a given changeset is included in a tagged release::
5036 - check if a given changeset is included in a tagged release::
5040
5037
5041 hg log -r "a21ccf and ancestor(1.9)"
5038 hg log -r "a21ccf and ancestor(1.9)"
5042
5039
5043 - find all changesets by some user in a date range::
5040 - find all changesets by some user in a date range::
5044
5041
5045 hg log -k alice -d "may 2008 to jul 2008"
5042 hg log -k alice -d "may 2008 to jul 2008"
5046
5043
5047 - summary of all changesets after the last tag::
5044 - summary of all changesets after the last tag::
5048
5045
5049 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5046 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
5050
5047
5051 See :hg:`help dates` for a list of formats valid for -d/--date.
5048 See :hg:`help dates` for a list of formats valid for -d/--date.
5052
5049
5053 See :hg:`help revisions` and :hg:`help revsets` for more about
5050 See :hg:`help revisions` and :hg:`help revsets` for more about
5054 specifying and ordering revisions.
5051 specifying and ordering revisions.
5055
5052
5056 See :hg:`help templates` for more about pre-packaged styles and
5053 See :hg:`help templates` for more about pre-packaged styles and
5057 specifying custom templates.
5054 specifying custom templates.
5058
5055
5059 Returns 0 on success.
5056 Returns 0 on success.
5060
5057
5061 """
5058 """
5062 if opts.get('follow') and opts.get('rev'):
5059 if opts.get('follow') and opts.get('rev'):
5063 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5060 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
5064 del opts['follow']
5061 del opts['follow']
5065
5062
5066 if opts.get('graph'):
5063 if opts.get('graph'):
5067 return cmdutil.graphlog(ui, repo, *pats, **opts)
5064 return cmdutil.graphlog(ui, repo, *pats, **opts)
5068
5065
5069 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5066 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
5070 limit = cmdutil.loglimit(opts)
5067 limit = cmdutil.loglimit(opts)
5071 count = 0
5068 count = 0
5072
5069
5073 getrenamed = None
5070 getrenamed = None
5074 if opts.get('copies'):
5071 if opts.get('copies'):
5075 endrev = None
5072 endrev = None
5076 if opts.get('rev'):
5073 if opts.get('rev'):
5077 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5074 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
5078 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5075 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
5079
5076
5080 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5077 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5081 for rev in revs:
5078 for rev in revs:
5082 if count == limit:
5079 if count == limit:
5083 break
5080 break
5084 ctx = repo[rev]
5081 ctx = repo[rev]
5085 copies = None
5082 copies = None
5086 if getrenamed is not None and rev:
5083 if getrenamed is not None and rev:
5087 copies = []
5084 copies = []
5088 for fn in ctx.files():
5085 for fn in ctx.files():
5089 rename = getrenamed(fn, rev)
5086 rename = getrenamed(fn, rev)
5090 if rename:
5087 if rename:
5091 copies.append((fn, rename[0]))
5088 copies.append((fn, rename[0]))
5092 if filematcher:
5089 if filematcher:
5093 revmatchfn = filematcher(ctx.rev())
5090 revmatchfn = filematcher(ctx.rev())
5094 else:
5091 else:
5095 revmatchfn = None
5092 revmatchfn = None
5096 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5093 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
5097 if displayer.flush(ctx):
5094 if displayer.flush(ctx):
5098 count += 1
5095 count += 1
5099
5096
5100 displayer.close()
5097 displayer.close()
5101
5098
5102 @command('manifest',
5099 @command('manifest',
5103 [('r', 'rev', '', _('revision to display'), _('REV')),
5100 [('r', 'rev', '', _('revision to display'), _('REV')),
5104 ('', 'all', False, _("list files from all revisions"))]
5101 ('', 'all', False, _("list files from all revisions"))]
5105 + formatteropts,
5102 + formatteropts,
5106 _('[-r REV]'))
5103 _('[-r REV]'))
5107 def manifest(ui, repo, node=None, rev=None, **opts):
5104 def manifest(ui, repo, node=None, rev=None, **opts):
5108 """output the current or given revision of the project manifest
5105 """output the current or given revision of the project manifest
5109
5106
5110 Print a list of version controlled files for the given revision.
5107 Print a list of version controlled files for the given revision.
5111 If no revision is given, the first parent of the working directory
5108 If no revision is given, the first parent of the working directory
5112 is used, or the null revision if no revision is checked out.
5109 is used, or the null revision if no revision is checked out.
5113
5110
5114 With -v, print file permissions, symlink and executable bits.
5111 With -v, print file permissions, symlink and executable bits.
5115 With --debug, print file revision hashes.
5112 With --debug, print file revision hashes.
5116
5113
5117 If option --all is specified, the list of all files from all revisions
5114 If option --all is specified, the list of all files from all revisions
5118 is printed. This includes deleted and renamed files.
5115 is printed. This includes deleted and renamed files.
5119
5116
5120 Returns 0 on success.
5117 Returns 0 on success.
5121 """
5118 """
5122
5119
5123 fm = ui.formatter('manifest', opts)
5120 fm = ui.formatter('manifest', opts)
5124
5121
5125 if opts.get('all'):
5122 if opts.get('all'):
5126 if rev or node:
5123 if rev or node:
5127 raise error.Abort(_("can't specify a revision with --all"))
5124 raise error.Abort(_("can't specify a revision with --all"))
5128
5125
5129 res = []
5126 res = []
5130 prefix = "data/"
5127 prefix = "data/"
5131 suffix = ".i"
5128 suffix = ".i"
5132 plen = len(prefix)
5129 plen = len(prefix)
5133 slen = len(suffix)
5130 slen = len(suffix)
5134 lock = repo.lock()
5131 lock = repo.lock()
5135 try:
5132 try:
5136 for fn, b, size in repo.store.datafiles():
5133 for fn, b, size in repo.store.datafiles():
5137 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5134 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
5138 res.append(fn[plen:-slen])
5135 res.append(fn[plen:-slen])
5139 finally:
5136 finally:
5140 lock.release()
5137 lock.release()
5141 for f in res:
5138 for f in res:
5142 fm.startitem()
5139 fm.startitem()
5143 fm.write("path", '%s\n', f)
5140 fm.write("path", '%s\n', f)
5144 fm.end()
5141 fm.end()
5145 return
5142 return
5146
5143
5147 if rev and node:
5144 if rev and node:
5148 raise error.Abort(_("please specify just one revision"))
5145 raise error.Abort(_("please specify just one revision"))
5149
5146
5150 if not node:
5147 if not node:
5151 node = rev
5148 node = rev
5152
5149
5153 char = {'l': '@', 'x': '*', '': ''}
5150 char = {'l': '@', 'x': '*', '': ''}
5154 mode = {'l': '644', 'x': '755', '': '644'}
5151 mode = {'l': '644', 'x': '755', '': '644'}
5155 ctx = scmutil.revsingle(repo, node)
5152 ctx = scmutil.revsingle(repo, node)
5156 mf = ctx.manifest()
5153 mf = ctx.manifest()
5157 for f in ctx:
5154 for f in ctx:
5158 fm.startitem()
5155 fm.startitem()
5159 fl = ctx[f].flags()
5156 fl = ctx[f].flags()
5160 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5157 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
5161 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5158 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
5162 fm.write('path', '%s\n', f)
5159 fm.write('path', '%s\n', f)
5163 fm.end()
5160 fm.end()
5164
5161
5165 @command('^merge',
5162 @command('^merge',
5166 [('f', 'force', None,
5163 [('f', 'force', None,
5167 _('force a merge including outstanding changes (DEPRECATED)')),
5164 _('force a merge including outstanding changes (DEPRECATED)')),
5168 ('r', 'rev', '', _('revision to merge'), _('REV')),
5165 ('r', 'rev', '', _('revision to merge'), _('REV')),
5169 ('P', 'preview', None,
5166 ('P', 'preview', None,
5170 _('review revisions to merge (no merge is performed)'))
5167 _('review revisions to merge (no merge is performed)'))
5171 ] + mergetoolopts,
5168 ] + mergetoolopts,
5172 _('[-P] [-f] [[-r] REV]'))
5169 _('[-P] [-f] [[-r] REV]'))
5173 def merge(ui, repo, node=None, **opts):
5170 def merge(ui, repo, node=None, **opts):
5174 """merge another revision into working directory
5171 """merge another revision into working directory
5175
5172
5176 The current working directory is updated with all changes made in
5173 The current working directory is updated with all changes made in
5177 the requested revision since the last common predecessor revision.
5174 the requested revision since the last common predecessor revision.
5178
5175
5179 Files that changed between either parent are marked as changed for
5176 Files that changed between either parent are marked as changed for
5180 the next commit and a commit must be performed before any further
5177 the next commit and a commit must be performed before any further
5181 updates to the repository are allowed. The next commit will have
5178 updates to the repository are allowed. The next commit will have
5182 two parents.
5179 two parents.
5183
5180
5184 ``--tool`` can be used to specify the merge tool used for file
5181 ``--tool`` can be used to specify the merge tool used for file
5185 merges. It overrides the HGMERGE environment variable and your
5182 merges. It overrides the HGMERGE environment variable and your
5186 configuration files. See :hg:`help merge-tools` for options.
5183 configuration files. See :hg:`help merge-tools` for options.
5187
5184
5188 If no revision is specified, the working directory's parent is a
5185 If no revision is specified, the working directory's parent is a
5189 head revision, and the current branch contains exactly one other
5186 head revision, and the current branch contains exactly one other
5190 head, the other head is merged with by default. Otherwise, an
5187 head, the other head is merged with by default. Otherwise, an
5191 explicit revision with which to merge with must be provided.
5188 explicit revision with which to merge with must be provided.
5192
5189
5193 See :hg:`help resolve` for information on handling file conflicts.
5190 See :hg:`help resolve` for information on handling file conflicts.
5194
5191
5195 To undo an uncommitted merge, use :hg:`update --clean .` which
5192 To undo an uncommitted merge, use :hg:`update --clean .` which
5196 will check out a clean copy of the original merge parent, losing
5193 will check out a clean copy of the original merge parent, losing
5197 all changes.
5194 all changes.
5198
5195
5199 Returns 0 on success, 1 if there are unresolved files.
5196 Returns 0 on success, 1 if there are unresolved files.
5200 """
5197 """
5201
5198
5202 if opts.get('rev') and node:
5199 if opts.get('rev') and node:
5203 raise error.Abort(_("please specify just one revision"))
5200 raise error.Abort(_("please specify just one revision"))
5204 if not node:
5201 if not node:
5205 node = opts.get('rev')
5202 node = opts.get('rev')
5206
5203
5207 if node:
5204 if node:
5208 node = scmutil.revsingle(repo, node).node()
5205 node = scmutil.revsingle(repo, node).node()
5209
5206
5210 if not node:
5207 if not node:
5211 node = repo[destutil.destmerge(repo)].node()
5208 node = repo[destutil.destmerge(repo)].node()
5212
5209
5213 if opts.get('preview'):
5210 if opts.get('preview'):
5214 # find nodes that are ancestors of p2 but not of p1
5211 # find nodes that are ancestors of p2 but not of p1
5215 p1 = repo.lookup('.')
5212 p1 = repo.lookup('.')
5216 p2 = repo.lookup(node)
5213 p2 = repo.lookup(node)
5217 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5214 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
5218
5215
5219 displayer = cmdutil.show_changeset(ui, repo, opts)
5216 displayer = cmdutil.show_changeset(ui, repo, opts)
5220 for node in nodes:
5217 for node in nodes:
5221 displayer.show(repo[node])
5218 displayer.show(repo[node])
5222 displayer.close()
5219 displayer.close()
5223 return 0
5220 return 0
5224
5221
5225 try:
5222 try:
5226 # ui.forcemerge is an internal variable, do not document
5223 # ui.forcemerge is an internal variable, do not document
5227 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5224 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
5228 return hg.merge(repo, node, force=opts.get('force'))
5225 return hg.merge(repo, node, force=opts.get('force'))
5229 finally:
5226 finally:
5230 ui.setconfig('ui', 'forcemerge', '', 'merge')
5227 ui.setconfig('ui', 'forcemerge', '', 'merge')
5231
5228
5232 @command('outgoing|out',
5229 @command('outgoing|out',
5233 [('f', 'force', None, _('run even when the destination is unrelated')),
5230 [('f', 'force', None, _('run even when the destination is unrelated')),
5234 ('r', 'rev', [],
5231 ('r', 'rev', [],
5235 _('a changeset intended to be included in the destination'), _('REV')),
5232 _('a changeset intended to be included in the destination'), _('REV')),
5236 ('n', 'newest-first', None, _('show newest record first')),
5233 ('n', 'newest-first', None, _('show newest record first')),
5237 ('B', 'bookmarks', False, _('compare bookmarks')),
5234 ('B', 'bookmarks', False, _('compare bookmarks')),
5238 ('b', 'branch', [], _('a specific branch you would like to push'),
5235 ('b', 'branch', [], _('a specific branch you would like to push'),
5239 _('BRANCH')),
5236 _('BRANCH')),
5240 ] + logopts + remoteopts + subrepoopts,
5237 ] + logopts + remoteopts + subrepoopts,
5241 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5238 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
5242 def outgoing(ui, repo, dest=None, **opts):
5239 def outgoing(ui, repo, dest=None, **opts):
5243 """show changesets not found in the destination
5240 """show changesets not found in the destination
5244
5241
5245 Show changesets not found in the specified destination repository
5242 Show changesets not found in the specified destination repository
5246 or the default push location. These are the changesets that would
5243 or the default push location. These are the changesets that would
5247 be pushed if a push was requested.
5244 be pushed if a push was requested.
5248
5245
5249 See pull for details of valid destination formats.
5246 See pull for details of valid destination formats.
5250
5247
5251 .. container:: verbose
5248 .. container:: verbose
5252
5249
5253 With -B/--bookmarks, the result of bookmark comparison between
5250 With -B/--bookmarks, the result of bookmark comparison between
5254 local and remote repositories is displayed. With -v/--verbose,
5251 local and remote repositories is displayed. With -v/--verbose,
5255 status is also displayed for each bookmark like below::
5252 status is also displayed for each bookmark like below::
5256
5253
5257 BM1 01234567890a added
5254 BM1 01234567890a added
5258 BM2 deleted
5255 BM2 deleted
5259 BM3 234567890abc advanced
5256 BM3 234567890abc advanced
5260 BM4 34567890abcd diverged
5257 BM4 34567890abcd diverged
5261 BM5 4567890abcde changed
5258 BM5 4567890abcde changed
5262
5259
5263 The action taken when pushing depends on the
5260 The action taken when pushing depends on the
5264 status of each bookmark:
5261 status of each bookmark:
5265
5262
5266 :``added``: push with ``-B`` will create it
5263 :``added``: push with ``-B`` will create it
5267 :``deleted``: push with ``-B`` will delete it
5264 :``deleted``: push with ``-B`` will delete it
5268 :``advanced``: push will update it
5265 :``advanced``: push will update it
5269 :``diverged``: push with ``-B`` will update it
5266 :``diverged``: push with ``-B`` will update it
5270 :``changed``: push with ``-B`` will update it
5267 :``changed``: push with ``-B`` will update it
5271
5268
5272 From the point of view of pushing behavior, bookmarks
5269 From the point of view of pushing behavior, bookmarks
5273 existing only in the remote repository are treated as
5270 existing only in the remote repository are treated as
5274 ``deleted``, even if it is in fact added remotely.
5271 ``deleted``, even if it is in fact added remotely.
5275
5272
5276 Returns 0 if there are outgoing changes, 1 otherwise.
5273 Returns 0 if there are outgoing changes, 1 otherwise.
5277 """
5274 """
5278 if opts.get('graph'):
5275 if opts.get('graph'):
5279 cmdutil.checkunsupportedgraphflags([], opts)
5276 cmdutil.checkunsupportedgraphflags([], opts)
5280 o, other = hg._outgoing(ui, repo, dest, opts)
5277 o, other = hg._outgoing(ui, repo, dest, opts)
5281 if not o:
5278 if not o:
5282 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5279 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5283 return
5280 return
5284
5281
5285 revdag = cmdutil.graphrevs(repo, o, opts)
5282 revdag = cmdutil.graphrevs(repo, o, opts)
5286 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5283 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5287 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5284 cmdutil.displaygraph(ui, repo, revdag, displayer, graphmod.asciiedges)
5288 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5285 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5289 return 0
5286 return 0
5290
5287
5291 if opts.get('bookmarks'):
5288 if opts.get('bookmarks'):
5292 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5289 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5293 dest, branches = hg.parseurl(dest, opts.get('branch'))
5290 dest, branches = hg.parseurl(dest, opts.get('branch'))
5294 other = hg.peer(repo, opts, dest)
5291 other = hg.peer(repo, opts, dest)
5295 if 'bookmarks' not in other.listkeys('namespaces'):
5292 if 'bookmarks' not in other.listkeys('namespaces'):
5296 ui.warn(_("remote doesn't support bookmarks\n"))
5293 ui.warn(_("remote doesn't support bookmarks\n"))
5297 return 0
5294 return 0
5298 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5295 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5299 return bookmarks.outgoing(ui, repo, other)
5296 return bookmarks.outgoing(ui, repo, other)
5300
5297
5301 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5298 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5302 try:
5299 try:
5303 return hg.outgoing(ui, repo, dest, opts)
5300 return hg.outgoing(ui, repo, dest, opts)
5304 finally:
5301 finally:
5305 del repo._subtoppath
5302 del repo._subtoppath
5306
5303
5307 @command('parents',
5304 @command('parents',
5308 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5305 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5309 ] + templateopts,
5306 ] + templateopts,
5310 _('[-r REV] [FILE]'),
5307 _('[-r REV] [FILE]'),
5311 inferrepo=True)
5308 inferrepo=True)
5312 def parents(ui, repo, file_=None, **opts):
5309 def parents(ui, repo, file_=None, **opts):
5313 """show the parents of the working directory or revision (DEPRECATED)
5310 """show the parents of the working directory or revision (DEPRECATED)
5314
5311
5315 Print the working directory's parent revisions. If a revision is
5312 Print the working directory's parent revisions. If a revision is
5316 given via -r/--rev, the parent of that revision will be printed.
5313 given via -r/--rev, the parent of that revision will be printed.
5317 If a file argument is given, the revision in which the file was
5314 If a file argument is given, the revision in which the file was
5318 last changed (before the working directory revision or the
5315 last changed (before the working directory revision or the
5319 argument to --rev if given) is printed.
5316 argument to --rev if given) is printed.
5320
5317
5321 This command is equivalent to::
5318 This command is equivalent to::
5322
5319
5323 hg log -r "p1()+p2()" or
5320 hg log -r "p1()+p2()" or
5324 hg log -r "p1(REV)+p2(REV)" or
5321 hg log -r "p1(REV)+p2(REV)" or
5325 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5322 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5326 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5323 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5327
5324
5328 See :hg:`summary` and :hg:`help revsets` for related information.
5325 See :hg:`summary` and :hg:`help revsets` for related information.
5329
5326
5330 Returns 0 on success.
5327 Returns 0 on success.
5331 """
5328 """
5332
5329
5333 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5330 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5334
5331
5335 if file_:
5332 if file_:
5336 m = scmutil.match(ctx, (file_,), opts)
5333 m = scmutil.match(ctx, (file_,), opts)
5337 if m.anypats() or len(m.files()) != 1:
5334 if m.anypats() or len(m.files()) != 1:
5338 raise error.Abort(_('can only specify an explicit filename'))
5335 raise error.Abort(_('can only specify an explicit filename'))
5339 file_ = m.files()[0]
5336 file_ = m.files()[0]
5340 filenodes = []
5337 filenodes = []
5341 for cp in ctx.parents():
5338 for cp in ctx.parents():
5342 if not cp:
5339 if not cp:
5343 continue
5340 continue
5344 try:
5341 try:
5345 filenodes.append(cp.filenode(file_))
5342 filenodes.append(cp.filenode(file_))
5346 except error.LookupError:
5343 except error.LookupError:
5347 pass
5344 pass
5348 if not filenodes:
5345 if not filenodes:
5349 raise error.Abort(_("'%s' not found in manifest!") % file_)
5346 raise error.Abort(_("'%s' not found in manifest!") % file_)
5350 p = []
5347 p = []
5351 for fn in filenodes:
5348 for fn in filenodes:
5352 fctx = repo.filectx(file_, fileid=fn)
5349 fctx = repo.filectx(file_, fileid=fn)
5353 p.append(fctx.node())
5350 p.append(fctx.node())
5354 else:
5351 else:
5355 p = [cp.node() for cp in ctx.parents()]
5352 p = [cp.node() for cp in ctx.parents()]
5356
5353
5357 displayer = cmdutil.show_changeset(ui, repo, opts)
5354 displayer = cmdutil.show_changeset(ui, repo, opts)
5358 for n in p:
5355 for n in p:
5359 if n != nullid:
5356 if n != nullid:
5360 displayer.show(repo[n])
5357 displayer.show(repo[n])
5361 displayer.close()
5358 displayer.close()
5362
5359
5363 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5360 @command('paths', formatteropts, _('[NAME]'), optionalrepo=True)
5364 def paths(ui, repo, search=None, **opts):
5361 def paths(ui, repo, search=None, **opts):
5365 """show aliases for remote repositories
5362 """show aliases for remote repositories
5366
5363
5367 Show definition of symbolic path name NAME. If no name is given,
5364 Show definition of symbolic path name NAME. If no name is given,
5368 show definition of all available names.
5365 show definition of all available names.
5369
5366
5370 Option -q/--quiet suppresses all output when searching for NAME
5367 Option -q/--quiet suppresses all output when searching for NAME
5371 and shows only the path names when listing all definitions.
5368 and shows only the path names when listing all definitions.
5372
5369
5373 Path names are defined in the [paths] section of your
5370 Path names are defined in the [paths] section of your
5374 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5371 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5375 repository, ``.hg/hgrc`` is used, too.
5372 repository, ``.hg/hgrc`` is used, too.
5376
5373
5377 The path names ``default`` and ``default-push`` have a special
5374 The path names ``default`` and ``default-push`` have a special
5378 meaning. When performing a push or pull operation, they are used
5375 meaning. When performing a push or pull operation, they are used
5379 as fallbacks if no location is specified on the command-line.
5376 as fallbacks if no location is specified on the command-line.
5380 When ``default-push`` is set, it will be used for push and
5377 When ``default-push`` is set, it will be used for push and
5381 ``default`` will be used for pull; otherwise ``default`` is used
5378 ``default`` will be used for pull; otherwise ``default`` is used
5382 as the fallback for both. When cloning a repository, the clone
5379 as the fallback for both. When cloning a repository, the clone
5383 source is written as ``default`` in ``.hg/hgrc``.
5380 source is written as ``default`` in ``.hg/hgrc``.
5384
5381
5385 .. note::
5382 .. note::
5386
5383
5387 ``default`` and ``default-push`` apply to all inbound (e.g.
5384 ``default`` and ``default-push`` apply to all inbound (e.g.
5388 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5385 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5389 and :hg:`bundle`) operations.
5386 and :hg:`bundle`) operations.
5390
5387
5391 See :hg:`help urls` for more information.
5388 See :hg:`help urls` for more information.
5392
5389
5393 Returns 0 on success.
5390 Returns 0 on success.
5394 """
5391 """
5395 if search:
5392 if search:
5396 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5393 pathitems = [(name, path) for name, path in ui.paths.iteritems()
5397 if name == search]
5394 if name == search]
5398 else:
5395 else:
5399 pathitems = sorted(ui.paths.iteritems())
5396 pathitems = sorted(ui.paths.iteritems())
5400
5397
5401 fm = ui.formatter('paths', opts)
5398 fm = ui.formatter('paths', opts)
5402 if fm:
5399 if fm:
5403 hidepassword = str
5400 hidepassword = str
5404 else:
5401 else:
5405 hidepassword = util.hidepassword
5402 hidepassword = util.hidepassword
5406 if ui.quiet:
5403 if ui.quiet:
5407 namefmt = '%s\n'
5404 namefmt = '%s\n'
5408 else:
5405 else:
5409 namefmt = '%s = '
5406 namefmt = '%s = '
5410 showsubopts = not search and not ui.quiet
5407 showsubopts = not search and not ui.quiet
5411
5408
5412 for name, path in pathitems:
5409 for name, path in pathitems:
5413 fm.startitem()
5410 fm.startitem()
5414 fm.condwrite(not search, 'name', namefmt, name)
5411 fm.condwrite(not search, 'name', namefmt, name)
5415 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5412 fm.condwrite(not ui.quiet, 'url', '%s\n', hidepassword(path.rawloc))
5416 for subopt, value in sorted(path.suboptions.items()):
5413 for subopt, value in sorted(path.suboptions.items()):
5417 assert subopt not in ('name', 'url')
5414 assert subopt not in ('name', 'url')
5418 if showsubopts:
5415 if showsubopts:
5419 fm.plain('%s:%s = ' % (name, subopt))
5416 fm.plain('%s:%s = ' % (name, subopt))
5420 fm.condwrite(showsubopts, subopt, '%s\n', value)
5417 fm.condwrite(showsubopts, subopt, '%s\n', value)
5421
5418
5422 fm.end()
5419 fm.end()
5423
5420
5424 if search and not pathitems:
5421 if search and not pathitems:
5425 if not ui.quiet:
5422 if not ui.quiet:
5426 ui.warn(_("not found!\n"))
5423 ui.warn(_("not found!\n"))
5427 return 1
5424 return 1
5428 else:
5425 else:
5429 return 0
5426 return 0
5430
5427
5431 @command('phase',
5428 @command('phase',
5432 [('p', 'public', False, _('set changeset phase to public')),
5429 [('p', 'public', False, _('set changeset phase to public')),
5433 ('d', 'draft', False, _('set changeset phase to draft')),
5430 ('d', 'draft', False, _('set changeset phase to draft')),
5434 ('s', 'secret', False, _('set changeset phase to secret')),
5431 ('s', 'secret', False, _('set changeset phase to secret')),
5435 ('f', 'force', False, _('allow to move boundary backward')),
5432 ('f', 'force', False, _('allow to move boundary backward')),
5436 ('r', 'rev', [], _('target revision'), _('REV')),
5433 ('r', 'rev', [], _('target revision'), _('REV')),
5437 ],
5434 ],
5438 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5435 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5439 def phase(ui, repo, *revs, **opts):
5436 def phase(ui, repo, *revs, **opts):
5440 """set or show the current phase name
5437 """set or show the current phase name
5441
5438
5442 With no argument, show the phase name of the current revision(s).
5439 With no argument, show the phase name of the current revision(s).
5443
5440
5444 With one of -p/--public, -d/--draft or -s/--secret, change the
5441 With one of -p/--public, -d/--draft or -s/--secret, change the
5445 phase value of the specified revisions.
5442 phase value of the specified revisions.
5446
5443
5447 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5444 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5448 lower phase to an higher phase. Phases are ordered as follows::
5445 lower phase to an higher phase. Phases are ordered as follows::
5449
5446
5450 public < draft < secret
5447 public < draft < secret
5451
5448
5452 Returns 0 on success, 1 if some phases could not be changed.
5449 Returns 0 on success, 1 if some phases could not be changed.
5453
5450
5454 (For more information about the phases concept, see :hg:`help phases`.)
5451 (For more information about the phases concept, see :hg:`help phases`.)
5455 """
5452 """
5456 # search for a unique phase argument
5453 # search for a unique phase argument
5457 targetphase = None
5454 targetphase = None
5458 for idx, name in enumerate(phases.phasenames):
5455 for idx, name in enumerate(phases.phasenames):
5459 if opts[name]:
5456 if opts[name]:
5460 if targetphase is not None:
5457 if targetphase is not None:
5461 raise error.Abort(_('only one phase can be specified'))
5458 raise error.Abort(_('only one phase can be specified'))
5462 targetphase = idx
5459 targetphase = idx
5463
5460
5464 # look for specified revision
5461 # look for specified revision
5465 revs = list(revs)
5462 revs = list(revs)
5466 revs.extend(opts['rev'])
5463 revs.extend(opts['rev'])
5467 if not revs:
5464 if not revs:
5468 # display both parents as the second parent phase can influence
5465 # display both parents as the second parent phase can influence
5469 # the phase of a merge commit
5466 # the phase of a merge commit
5470 revs = [c.rev() for c in repo[None].parents()]
5467 revs = [c.rev() for c in repo[None].parents()]
5471
5468
5472 revs = scmutil.revrange(repo, revs)
5469 revs = scmutil.revrange(repo, revs)
5473
5470
5474 lock = None
5471 lock = None
5475 ret = 0
5472 ret = 0
5476 if targetphase is None:
5473 if targetphase is None:
5477 # display
5474 # display
5478 for r in revs:
5475 for r in revs:
5479 ctx = repo[r]
5476 ctx = repo[r]
5480 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5477 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5481 else:
5478 else:
5482 tr = None
5479 tr = None
5483 lock = repo.lock()
5480 lock = repo.lock()
5484 try:
5481 try:
5485 tr = repo.transaction("phase")
5482 tr = repo.transaction("phase")
5486 # set phase
5483 # set phase
5487 if not revs:
5484 if not revs:
5488 raise error.Abort(_('empty revision set'))
5485 raise error.Abort(_('empty revision set'))
5489 nodes = [repo[r].node() for r in revs]
5486 nodes = [repo[r].node() for r in revs]
5490 # moving revision from public to draft may hide them
5487 # moving revision from public to draft may hide them
5491 # We have to check result on an unfiltered repository
5488 # We have to check result on an unfiltered repository
5492 unfi = repo.unfiltered()
5489 unfi = repo.unfiltered()
5493 getphase = unfi._phasecache.phase
5490 getphase = unfi._phasecache.phase
5494 olddata = [getphase(unfi, r) for r in unfi]
5491 olddata = [getphase(unfi, r) for r in unfi]
5495 phases.advanceboundary(repo, tr, targetphase, nodes)
5492 phases.advanceboundary(repo, tr, targetphase, nodes)
5496 if opts['force']:
5493 if opts['force']:
5497 phases.retractboundary(repo, tr, targetphase, nodes)
5494 phases.retractboundary(repo, tr, targetphase, nodes)
5498 tr.close()
5495 tr.close()
5499 finally:
5496 finally:
5500 if tr is not None:
5497 if tr is not None:
5501 tr.release()
5498 tr.release()
5502 lock.release()
5499 lock.release()
5503 getphase = unfi._phasecache.phase
5500 getphase = unfi._phasecache.phase
5504 newdata = [getphase(unfi, r) for r in unfi]
5501 newdata = [getphase(unfi, r) for r in unfi]
5505 changes = sum(newdata[r] != olddata[r] for r in unfi)
5502 changes = sum(newdata[r] != olddata[r] for r in unfi)
5506 cl = unfi.changelog
5503 cl = unfi.changelog
5507 rejected = [n for n in nodes
5504 rejected = [n for n in nodes
5508 if newdata[cl.rev(n)] < targetphase]
5505 if newdata[cl.rev(n)] < targetphase]
5509 if rejected:
5506 if rejected:
5510 ui.warn(_('cannot move %i changesets to a higher '
5507 ui.warn(_('cannot move %i changesets to a higher '
5511 'phase, use --force\n') % len(rejected))
5508 'phase, use --force\n') % len(rejected))
5512 ret = 1
5509 ret = 1
5513 if changes:
5510 if changes:
5514 msg = _('phase changed for %i changesets\n') % changes
5511 msg = _('phase changed for %i changesets\n') % changes
5515 if ret:
5512 if ret:
5516 ui.status(msg)
5513 ui.status(msg)
5517 else:
5514 else:
5518 ui.note(msg)
5515 ui.note(msg)
5519 else:
5516 else:
5520 ui.warn(_('no phases changed\n'))
5517 ui.warn(_('no phases changed\n'))
5521 return ret
5518 return ret
5522
5519
5523 def postincoming(ui, repo, modheads, optupdate, checkout):
5520 def postincoming(ui, repo, modheads, optupdate, checkout):
5524 if modheads == 0:
5521 if modheads == 0:
5525 return
5522 return
5526 if optupdate:
5523 if optupdate:
5527 try:
5524 try:
5528 brev = checkout
5525 brev = checkout
5529 movemarkfrom = None
5526 movemarkfrom = None
5530 if not checkout:
5527 if not checkout:
5531 updata = destutil.destupdate(repo)
5528 updata = destutil.destupdate(repo)
5532 checkout, movemarkfrom, brev = updata
5529 checkout, movemarkfrom, brev = updata
5533 ret = hg.update(repo, checkout)
5530 ret = hg.update(repo, checkout)
5534 except error.UpdateAbort as inst:
5531 except error.UpdateAbort as inst:
5535 msg = _("not updating: %s") % str(inst)
5532 msg = _("not updating: %s") % str(inst)
5536 hint = inst.hint
5533 hint = inst.hint
5537 raise error.UpdateAbort(msg, hint=hint)
5534 raise error.UpdateAbort(msg, hint=hint)
5538 if not ret and not checkout:
5535 if not ret and not checkout:
5539 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5536 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5540 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5537 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5541 return ret
5538 return ret
5542 if modheads > 1:
5539 if modheads > 1:
5543 currentbranchheads = len(repo.branchheads())
5540 currentbranchheads = len(repo.branchheads())
5544 if currentbranchheads == modheads:
5541 if currentbranchheads == modheads:
5545 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5542 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5546 elif currentbranchheads > 1:
5543 elif currentbranchheads > 1:
5547 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5544 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5548 "merge)\n"))
5545 "merge)\n"))
5549 else:
5546 else:
5550 ui.status(_("(run 'hg heads' to see heads)\n"))
5547 ui.status(_("(run 'hg heads' to see heads)\n"))
5551 else:
5548 else:
5552 ui.status(_("(run 'hg update' to get a working copy)\n"))
5549 ui.status(_("(run 'hg update' to get a working copy)\n"))
5553
5550
5554 @command('^pull',
5551 @command('^pull',
5555 [('u', 'update', None,
5552 [('u', 'update', None,
5556 _('update to new branch head if changesets were pulled')),
5553 _('update to new branch head if changesets were pulled')),
5557 ('f', 'force', None, _('run even when remote repository is unrelated')),
5554 ('f', 'force', None, _('run even when remote repository is unrelated')),
5558 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5555 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5559 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5556 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5560 ('b', 'branch', [], _('a specific branch you would like to pull'),
5557 ('b', 'branch', [], _('a specific branch you would like to pull'),
5561 _('BRANCH')),
5558 _('BRANCH')),
5562 ] + remoteopts,
5559 ] + remoteopts,
5563 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5560 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5564 def pull(ui, repo, source="default", **opts):
5561 def pull(ui, repo, source="default", **opts):
5565 """pull changes from the specified source
5562 """pull changes from the specified source
5566
5563
5567 Pull changes from a remote repository to a local one.
5564 Pull changes from a remote repository to a local one.
5568
5565
5569 This finds all changes from the repository at the specified path
5566 This finds all changes from the repository at the specified path
5570 or URL and adds them to a local repository (the current one unless
5567 or URL and adds them to a local repository (the current one unless
5571 -R is specified). By default, this does not update the copy of the
5568 -R is specified). By default, this does not update the copy of the
5572 project in the working directory.
5569 project in the working directory.
5573
5570
5574 Use :hg:`incoming` if you want to see what would have been added
5571 Use :hg:`incoming` if you want to see what would have been added
5575 by a pull at the time you issued this command. If you then decide
5572 by a pull at the time you issued this command. If you then decide
5576 to add those changes to the repository, you should use :hg:`pull
5573 to add those changes to the repository, you should use :hg:`pull
5577 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5574 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5578
5575
5579 If SOURCE is omitted, the 'default' path will be used.
5576 If SOURCE is omitted, the 'default' path will be used.
5580 See :hg:`help urls` for more information.
5577 See :hg:`help urls` for more information.
5581
5578
5582 Returns 0 on success, 1 if an update had unresolved files.
5579 Returns 0 on success, 1 if an update had unresolved files.
5583 """
5580 """
5584 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5581 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5585 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5582 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5586 other = hg.peer(repo, opts, source)
5583 other = hg.peer(repo, opts, source)
5587 try:
5584 try:
5588 revs, checkout = hg.addbranchrevs(repo, other, branches,
5585 revs, checkout = hg.addbranchrevs(repo, other, branches,
5589 opts.get('rev'))
5586 opts.get('rev'))
5590
5587
5591
5588
5592 pullopargs = {}
5589 pullopargs = {}
5593 if opts.get('bookmark'):
5590 if opts.get('bookmark'):
5594 if not revs:
5591 if not revs:
5595 revs = []
5592 revs = []
5596 # The list of bookmark used here is not the one used to actually
5593 # The list of bookmark used here is not the one used to actually
5597 # update the bookmark name. This can result in the revision pulled
5594 # update the bookmark name. This can result in the revision pulled
5598 # not ending up with the name of the bookmark because of a race
5595 # not ending up with the name of the bookmark because of a race
5599 # condition on the server. (See issue 4689 for details)
5596 # condition on the server. (See issue 4689 for details)
5600 remotebookmarks = other.listkeys('bookmarks')
5597 remotebookmarks = other.listkeys('bookmarks')
5601 pullopargs['remotebookmarks'] = remotebookmarks
5598 pullopargs['remotebookmarks'] = remotebookmarks
5602 for b in opts['bookmark']:
5599 for b in opts['bookmark']:
5603 if b not in remotebookmarks:
5600 if b not in remotebookmarks:
5604 raise error.Abort(_('remote bookmark %s not found!') % b)
5601 raise error.Abort(_('remote bookmark %s not found!') % b)
5605 revs.append(remotebookmarks[b])
5602 revs.append(remotebookmarks[b])
5606
5603
5607 if revs:
5604 if revs:
5608 try:
5605 try:
5609 # When 'rev' is a bookmark name, we cannot guarantee that it
5606 # When 'rev' is a bookmark name, we cannot guarantee that it
5610 # will be updated with that name because of a race condition
5607 # will be updated with that name because of a race condition
5611 # server side. (See issue 4689 for details)
5608 # server side. (See issue 4689 for details)
5612 oldrevs = revs
5609 oldrevs = revs
5613 revs = [] # actually, nodes
5610 revs = [] # actually, nodes
5614 for r in oldrevs:
5611 for r in oldrevs:
5615 node = other.lookup(r)
5612 node = other.lookup(r)
5616 revs.append(node)
5613 revs.append(node)
5617 if r == checkout:
5614 if r == checkout:
5618 checkout = node
5615 checkout = node
5619 except error.CapabilityError:
5616 except error.CapabilityError:
5620 err = _("other repository doesn't support revision lookup, "
5617 err = _("other repository doesn't support revision lookup, "
5621 "so a rev cannot be specified.")
5618 "so a rev cannot be specified.")
5622 raise error.Abort(err)
5619 raise error.Abort(err)
5623
5620
5624 pullopargs.update(opts.get('opargs', {}))
5621 pullopargs.update(opts.get('opargs', {}))
5625 modheads = exchange.pull(repo, other, heads=revs,
5622 modheads = exchange.pull(repo, other, heads=revs,
5626 force=opts.get('force'),
5623 force=opts.get('force'),
5627 bookmarks=opts.get('bookmark', ()),
5624 bookmarks=opts.get('bookmark', ()),
5628 opargs=pullopargs).cgresult
5625 opargs=pullopargs).cgresult
5629 if checkout:
5626 if checkout:
5630 checkout = str(repo.changelog.rev(checkout))
5627 checkout = str(repo.changelog.rev(checkout))
5631 repo._subtoppath = source
5628 repo._subtoppath = source
5632 try:
5629 try:
5633 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5630 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5634
5631
5635 finally:
5632 finally:
5636 del repo._subtoppath
5633 del repo._subtoppath
5637
5634
5638 finally:
5635 finally:
5639 other.close()
5636 other.close()
5640 return ret
5637 return ret
5641
5638
5642 @command('^push',
5639 @command('^push',
5643 [('f', 'force', None, _('force push')),
5640 [('f', 'force', None, _('force push')),
5644 ('r', 'rev', [],
5641 ('r', 'rev', [],
5645 _('a changeset intended to be included in the destination'),
5642 _('a changeset intended to be included in the destination'),
5646 _('REV')),
5643 _('REV')),
5647 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5644 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5648 ('b', 'branch', [],
5645 ('b', 'branch', [],
5649 _('a specific branch you would like to push'), _('BRANCH')),
5646 _('a specific branch you would like to push'), _('BRANCH')),
5650 ('', 'new-branch', False, _('allow pushing a new branch')),
5647 ('', 'new-branch', False, _('allow pushing a new branch')),
5651 ] + remoteopts,
5648 ] + remoteopts,
5652 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5649 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5653 def push(ui, repo, dest=None, **opts):
5650 def push(ui, repo, dest=None, **opts):
5654 """push changes to the specified destination
5651 """push changes to the specified destination
5655
5652
5656 Push changesets from the local repository to the specified
5653 Push changesets from the local repository to the specified
5657 destination.
5654 destination.
5658
5655
5659 This operation is symmetrical to pull: it is identical to a pull
5656 This operation is symmetrical to pull: it is identical to a pull
5660 in the destination repository from the current one.
5657 in the destination repository from the current one.
5661
5658
5662 By default, push will not allow creation of new heads at the
5659 By default, push will not allow creation of new heads at the
5663 destination, since multiple heads would make it unclear which head
5660 destination, since multiple heads would make it unclear which head
5664 to use. In this situation, it is recommended to pull and merge
5661 to use. In this situation, it is recommended to pull and merge
5665 before pushing.
5662 before pushing.
5666
5663
5667 Use --new-branch if you want to allow push to create a new named
5664 Use --new-branch if you want to allow push to create a new named
5668 branch that is not present at the destination. This allows you to
5665 branch that is not present at the destination. This allows you to
5669 only create a new branch without forcing other changes.
5666 only create a new branch without forcing other changes.
5670
5667
5671 .. note::
5668 .. note::
5672
5669
5673 Extra care should be taken with the -f/--force option,
5670 Extra care should be taken with the -f/--force option,
5674 which will push all new heads on all branches, an action which will
5671 which will push all new heads on all branches, an action which will
5675 almost always cause confusion for collaborators.
5672 almost always cause confusion for collaborators.
5676
5673
5677 If -r/--rev is used, the specified revision and all its ancestors
5674 If -r/--rev is used, the specified revision and all its ancestors
5678 will be pushed to the remote repository.
5675 will be pushed to the remote repository.
5679
5676
5680 If -B/--bookmark is used, the specified bookmarked revision, its
5677 If -B/--bookmark is used, the specified bookmarked revision, its
5681 ancestors, and the bookmark will be pushed to the remote
5678 ancestors, and the bookmark will be pushed to the remote
5682 repository.
5679 repository.
5683
5680
5684 Please see :hg:`help urls` for important details about ``ssh://``
5681 Please see :hg:`help urls` for important details about ``ssh://``
5685 URLs. If DESTINATION is omitted, a default path will be used.
5682 URLs. If DESTINATION is omitted, a default path will be used.
5686
5683
5687 Returns 0 if push was successful, 1 if nothing to push.
5684 Returns 0 if push was successful, 1 if nothing to push.
5688 """
5685 """
5689
5686
5690 if opts.get('bookmark'):
5687 if opts.get('bookmark'):
5691 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5688 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5692 for b in opts['bookmark']:
5689 for b in opts['bookmark']:
5693 # translate -B options to -r so changesets get pushed
5690 # translate -B options to -r so changesets get pushed
5694 if b in repo._bookmarks:
5691 if b in repo._bookmarks:
5695 opts.setdefault('rev', []).append(b)
5692 opts.setdefault('rev', []).append(b)
5696 else:
5693 else:
5697 # if we try to push a deleted bookmark, translate it to null
5694 # if we try to push a deleted bookmark, translate it to null
5698 # this lets simultaneous -r, -b options continue working
5695 # this lets simultaneous -r, -b options continue working
5699 opts.setdefault('rev', []).append("null")
5696 opts.setdefault('rev', []).append("null")
5700
5697
5701 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5698 path = ui.paths.getpath(dest, default=('default-push', 'default'))
5702 if not path:
5699 if not path:
5703 raise error.Abort(_('default repository not configured!'),
5700 raise error.Abort(_('default repository not configured!'),
5704 hint=_('see the "path" section in "hg help config"'))
5701 hint=_('see the "path" section in "hg help config"'))
5705 dest = path.pushloc or path.loc
5702 dest = path.pushloc or path.loc
5706 branches = (path.branch, opts.get('branch') or [])
5703 branches = (path.branch, opts.get('branch') or [])
5707 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5704 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5708 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5705 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5709 other = hg.peer(repo, opts, dest)
5706 other = hg.peer(repo, opts, dest)
5710
5707
5711 if revs:
5708 if revs:
5712 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5709 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5713 if not revs:
5710 if not revs:
5714 raise error.Abort(_("specified revisions evaluate to an empty set"),
5711 raise error.Abort(_("specified revisions evaluate to an empty set"),
5715 hint=_("use different revision arguments"))
5712 hint=_("use different revision arguments"))
5716
5713
5717 repo._subtoppath = dest
5714 repo._subtoppath = dest
5718 try:
5715 try:
5719 # push subrepos depth-first for coherent ordering
5716 # push subrepos depth-first for coherent ordering
5720 c = repo['']
5717 c = repo['']
5721 subs = c.substate # only repos that are committed
5718 subs = c.substate # only repos that are committed
5722 for s in sorted(subs):
5719 for s in sorted(subs):
5723 result = c.sub(s).push(opts)
5720 result = c.sub(s).push(opts)
5724 if result == 0:
5721 if result == 0:
5725 return not result
5722 return not result
5726 finally:
5723 finally:
5727 del repo._subtoppath
5724 del repo._subtoppath
5728 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5725 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5729 newbranch=opts.get('new_branch'),
5726 newbranch=opts.get('new_branch'),
5730 bookmarks=opts.get('bookmark', ()),
5727 bookmarks=opts.get('bookmark', ()),
5731 opargs=opts.get('opargs'))
5728 opargs=opts.get('opargs'))
5732
5729
5733 result = not pushop.cgresult
5730 result = not pushop.cgresult
5734
5731
5735 if pushop.bkresult is not None:
5732 if pushop.bkresult is not None:
5736 if pushop.bkresult == 2:
5733 if pushop.bkresult == 2:
5737 result = 2
5734 result = 2
5738 elif not result and pushop.bkresult:
5735 elif not result and pushop.bkresult:
5739 result = 2
5736 result = 2
5740
5737
5741 return result
5738 return result
5742
5739
5743 @command('recover', [])
5740 @command('recover', [])
5744 def recover(ui, repo):
5741 def recover(ui, repo):
5745 """roll back an interrupted transaction
5742 """roll back an interrupted transaction
5746
5743
5747 Recover from an interrupted commit or pull.
5744 Recover from an interrupted commit or pull.
5748
5745
5749 This command tries to fix the repository status after an
5746 This command tries to fix the repository status after an
5750 interrupted operation. It should only be necessary when Mercurial
5747 interrupted operation. It should only be necessary when Mercurial
5751 suggests it.
5748 suggests it.
5752
5749
5753 Returns 0 if successful, 1 if nothing to recover or verify fails.
5750 Returns 0 if successful, 1 if nothing to recover or verify fails.
5754 """
5751 """
5755 if repo.recover():
5752 if repo.recover():
5756 return hg.verify(repo)
5753 return hg.verify(repo)
5757 return 1
5754 return 1
5758
5755
5759 @command('^remove|rm',
5756 @command('^remove|rm',
5760 [('A', 'after', None, _('record delete for missing files')),
5757 [('A', 'after', None, _('record delete for missing files')),
5761 ('f', 'force', None,
5758 ('f', 'force', None,
5762 _('remove (and delete) file even if added or modified')),
5759 _('remove (and delete) file even if added or modified')),
5763 ] + subrepoopts + walkopts,
5760 ] + subrepoopts + walkopts,
5764 _('[OPTION]... FILE...'),
5761 _('[OPTION]... FILE...'),
5765 inferrepo=True)
5762 inferrepo=True)
5766 def remove(ui, repo, *pats, **opts):
5763 def remove(ui, repo, *pats, **opts):
5767 """remove the specified files on the next commit
5764 """remove the specified files on the next commit
5768
5765
5769 Schedule the indicated files for removal from the current branch.
5766 Schedule the indicated files for removal from the current branch.
5770
5767
5771 This command schedules the files to be removed at the next commit.
5768 This command schedules the files to be removed at the next commit.
5772 To undo a remove before that, see :hg:`revert`. To undo added
5769 To undo a remove before that, see :hg:`revert`. To undo added
5773 files, see :hg:`forget`.
5770 files, see :hg:`forget`.
5774
5771
5775 .. container:: verbose
5772 .. container:: verbose
5776
5773
5777 -A/--after can be used to remove only files that have already
5774 -A/--after can be used to remove only files that have already
5778 been deleted, -f/--force can be used to force deletion, and -Af
5775 been deleted, -f/--force can be used to force deletion, and -Af
5779 can be used to remove files from the next revision without
5776 can be used to remove files from the next revision without
5780 deleting them from the working directory.
5777 deleting them from the working directory.
5781
5778
5782 The following table details the behavior of remove for different
5779 The following table details the behavior of remove for different
5783 file states (columns) and option combinations (rows). The file
5780 file states (columns) and option combinations (rows). The file
5784 states are Added [A], Clean [C], Modified [M] and Missing [!]
5781 states are Added [A], Clean [C], Modified [M] and Missing [!]
5785 (as reported by :hg:`status`). The actions are Warn, Remove
5782 (as reported by :hg:`status`). The actions are Warn, Remove
5786 (from branch) and Delete (from disk):
5783 (from branch) and Delete (from disk):
5787
5784
5788 ========= == == == ==
5785 ========= == == == ==
5789 opt/state A C M !
5786 opt/state A C M !
5790 ========= == == == ==
5787 ========= == == == ==
5791 none W RD W R
5788 none W RD W R
5792 -f R RD RD R
5789 -f R RD RD R
5793 -A W W W R
5790 -A W W W R
5794 -Af R R R R
5791 -Af R R R R
5795 ========= == == == ==
5792 ========= == == == ==
5796
5793
5797 .. note::
5794 .. note::
5798
5795
5799 :hg:`remove` never deletes files in Added [A] state from the
5796 :hg:`remove` never deletes files in Added [A] state from the
5800 working directory, not even if ``--force`` is specified.
5797 working directory, not even if ``--force`` is specified.
5801
5798
5802 Returns 0 on success, 1 if any warnings encountered.
5799 Returns 0 on success, 1 if any warnings encountered.
5803 """
5800 """
5804
5801
5805 after, force = opts.get('after'), opts.get('force')
5802 after, force = opts.get('after'), opts.get('force')
5806 if not pats and not after:
5803 if not pats and not after:
5807 raise error.Abort(_('no files specified'))
5804 raise error.Abort(_('no files specified'))
5808
5805
5809 m = scmutil.match(repo[None], pats, opts)
5806 m = scmutil.match(repo[None], pats, opts)
5810 subrepos = opts.get('subrepos')
5807 subrepos = opts.get('subrepos')
5811 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5808 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5812
5809
5813 @command('rename|move|mv',
5810 @command('rename|move|mv',
5814 [('A', 'after', None, _('record a rename that has already occurred')),
5811 [('A', 'after', None, _('record a rename that has already occurred')),
5815 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5812 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5816 ] + walkopts + dryrunopts,
5813 ] + walkopts + dryrunopts,
5817 _('[OPTION]... SOURCE... DEST'))
5814 _('[OPTION]... SOURCE... DEST'))
5818 def rename(ui, repo, *pats, **opts):
5815 def rename(ui, repo, *pats, **opts):
5819 """rename files; equivalent of copy + remove
5816 """rename files; equivalent of copy + remove
5820
5817
5821 Mark dest as copies of sources; mark sources for deletion. If dest
5818 Mark dest as copies of sources; mark sources for deletion. If dest
5822 is a directory, copies are put in that directory. If dest is a
5819 is a directory, copies are put in that directory. If dest is a
5823 file, there can only be one source.
5820 file, there can only be one source.
5824
5821
5825 By default, this command copies the contents of files as they
5822 By default, this command copies the contents of files as they
5826 exist in the working directory. If invoked with -A/--after, the
5823 exist in the working directory. If invoked with -A/--after, the
5827 operation is recorded, but no copying is performed.
5824 operation is recorded, but no copying is performed.
5828
5825
5829 This command takes effect at the next commit. To undo a rename
5826 This command takes effect at the next commit. To undo a rename
5830 before that, see :hg:`revert`.
5827 before that, see :hg:`revert`.
5831
5828
5832 Returns 0 on success, 1 if errors are encountered.
5829 Returns 0 on success, 1 if errors are encountered.
5833 """
5830 """
5834 wlock = repo.wlock(False)
5831 wlock = repo.wlock(False)
5835 try:
5832 try:
5836 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5833 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5837 finally:
5834 finally:
5838 wlock.release()
5835 wlock.release()
5839
5836
5840 @command('resolve',
5837 @command('resolve',
5841 [('a', 'all', None, _('select all unresolved files')),
5838 [('a', 'all', None, _('select all unresolved files')),
5842 ('l', 'list', None, _('list state of files needing merge')),
5839 ('l', 'list', None, _('list state of files needing merge')),
5843 ('m', 'mark', None, _('mark files as resolved')),
5840 ('m', 'mark', None, _('mark files as resolved')),
5844 ('u', 'unmark', None, _('mark files as unresolved')),
5841 ('u', 'unmark', None, _('mark files as unresolved')),
5845 ('n', 'no-status', None, _('hide status prefix'))]
5842 ('n', 'no-status', None, _('hide status prefix'))]
5846 + mergetoolopts + walkopts + formatteropts,
5843 + mergetoolopts + walkopts + formatteropts,
5847 _('[OPTION]... [FILE]...'),
5844 _('[OPTION]... [FILE]...'),
5848 inferrepo=True)
5845 inferrepo=True)
5849 def resolve(ui, repo, *pats, **opts):
5846 def resolve(ui, repo, *pats, **opts):
5850 """redo merges or set/view the merge status of files
5847 """redo merges or set/view the merge status of files
5851
5848
5852 Merges with unresolved conflicts are often the result of
5849 Merges with unresolved conflicts are often the result of
5853 non-interactive merging using the ``internal:merge`` configuration
5850 non-interactive merging using the ``internal:merge`` configuration
5854 setting, or a command-line merge tool like ``diff3``. The resolve
5851 setting, or a command-line merge tool like ``diff3``. The resolve
5855 command is used to manage the files involved in a merge, after
5852 command is used to manage the files involved in a merge, after
5856 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5853 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5857 working directory must have two parents). See :hg:`help
5854 working directory must have two parents). See :hg:`help
5858 merge-tools` for information on configuring merge tools.
5855 merge-tools` for information on configuring merge tools.
5859
5856
5860 The resolve command can be used in the following ways:
5857 The resolve command can be used in the following ways:
5861
5858
5862 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5859 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5863 files, discarding any previous merge attempts. Re-merging is not
5860 files, discarding any previous merge attempts. Re-merging is not
5864 performed for files already marked as resolved. Use ``--all/-a``
5861 performed for files already marked as resolved. Use ``--all/-a``
5865 to select all unresolved files. ``--tool`` can be used to specify
5862 to select all unresolved files. ``--tool`` can be used to specify
5866 the merge tool used for the given files. It overrides the HGMERGE
5863 the merge tool used for the given files. It overrides the HGMERGE
5867 environment variable and your configuration files. Previous file
5864 environment variable and your configuration files. Previous file
5868 contents are saved with a ``.orig`` suffix.
5865 contents are saved with a ``.orig`` suffix.
5869
5866
5870 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5867 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5871 (e.g. after having manually fixed-up the files). The default is
5868 (e.g. after having manually fixed-up the files). The default is
5872 to mark all unresolved files.
5869 to mark all unresolved files.
5873
5870
5874 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5871 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5875 default is to mark all resolved files.
5872 default is to mark all resolved files.
5876
5873
5877 - :hg:`resolve -l`: list files which had or still have conflicts.
5874 - :hg:`resolve -l`: list files which had or still have conflicts.
5878 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5875 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5879
5876
5880 .. note::
5877 .. note::
5881
5878
5882 Mercurial will not let you commit files with unresolved merge
5879 Mercurial will not let you commit files with unresolved merge
5883 conflicts. You must use :hg:`resolve -m ...` before you can
5880 conflicts. You must use :hg:`resolve -m ...` before you can
5884 commit after a conflicting merge.
5881 commit after a conflicting merge.
5885
5882
5886 Returns 0 on success, 1 if any files fail a resolve attempt.
5883 Returns 0 on success, 1 if any files fail a resolve attempt.
5887 """
5884 """
5888
5885
5889 all, mark, unmark, show, nostatus = \
5886 all, mark, unmark, show, nostatus = \
5890 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5887 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5891
5888
5892 if (show and (mark or unmark)) or (mark and unmark):
5889 if (show and (mark or unmark)) or (mark and unmark):
5893 raise error.Abort(_("too many options specified"))
5890 raise error.Abort(_("too many options specified"))
5894 if pats and all:
5891 if pats and all:
5895 raise error.Abort(_("can't specify --all and patterns"))
5892 raise error.Abort(_("can't specify --all and patterns"))
5896 if not (all or pats or show or mark or unmark):
5893 if not (all or pats or show or mark or unmark):
5897 raise error.Abort(_('no files or directories specified'),
5894 raise error.Abort(_('no files or directories specified'),
5898 hint=('use --all to re-merge all unresolved files'))
5895 hint=('use --all to re-merge all unresolved files'))
5899
5896
5900 if show:
5897 if show:
5901 fm = ui.formatter('resolve', opts)
5898 fm = ui.formatter('resolve', opts)
5902 ms = mergemod.mergestate.read(repo)
5899 ms = mergemod.mergestate.read(repo)
5903 m = scmutil.match(repo[None], pats, opts)
5900 m = scmutil.match(repo[None], pats, opts)
5904 for f in ms:
5901 for f in ms:
5905 if not m(f):
5902 if not m(f):
5906 continue
5903 continue
5907 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5904 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5908 'd': 'driverresolved'}[ms[f]]
5905 'd': 'driverresolved'}[ms[f]]
5909 fm.startitem()
5906 fm.startitem()
5910 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5907 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5911 fm.write('path', '%s\n', f, label=l)
5908 fm.write('path', '%s\n', f, label=l)
5912 fm.end()
5909 fm.end()
5913 return 0
5910 return 0
5914
5911
5915 wlock = repo.wlock()
5912 wlock = repo.wlock()
5916 try:
5913 try:
5917 ms = mergemod.mergestate.read(repo)
5914 ms = mergemod.mergestate.read(repo)
5918
5915
5919 if not (ms.active() or repo.dirstate.p2() != nullid):
5916 if not (ms.active() or repo.dirstate.p2() != nullid):
5920 raise error.Abort(
5917 raise error.Abort(
5921 _('resolve command not applicable when not merging'))
5918 _('resolve command not applicable when not merging'))
5922
5919
5923 wctx = repo[None]
5920 wctx = repo[None]
5924
5921
5925 if ms.mergedriver and ms.mdstate() == 'u':
5922 if ms.mergedriver and ms.mdstate() == 'u':
5926 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5923 proceed = mergemod.driverpreprocess(repo, ms, wctx)
5927 ms.commit()
5924 ms.commit()
5928 # allow mark and unmark to go through
5925 # allow mark and unmark to go through
5929 if not mark and not unmark and not proceed:
5926 if not mark and not unmark and not proceed:
5930 return 1
5927 return 1
5931
5928
5932 m = scmutil.match(wctx, pats, opts)
5929 m = scmutil.match(wctx, pats, opts)
5933 ret = 0
5930 ret = 0
5934 didwork = False
5931 didwork = False
5935 runconclude = False
5932 runconclude = False
5936
5933
5937 tocomplete = []
5934 tocomplete = []
5938 for f in ms:
5935 for f in ms:
5939 if not m(f):
5936 if not m(f):
5940 continue
5937 continue
5941
5938
5942 didwork = True
5939 didwork = True
5943
5940
5944 # don't let driver-resolved files be marked, and run the conclude
5941 # don't let driver-resolved files be marked, and run the conclude
5945 # step if asked to resolve
5942 # step if asked to resolve
5946 if ms[f] == "d":
5943 if ms[f] == "d":
5947 exact = m.exact(f)
5944 exact = m.exact(f)
5948 if mark:
5945 if mark:
5949 if exact:
5946 if exact:
5950 ui.warn(_('not marking %s as it is driver-resolved\n')
5947 ui.warn(_('not marking %s as it is driver-resolved\n')
5951 % f)
5948 % f)
5952 elif unmark:
5949 elif unmark:
5953 if exact:
5950 if exact:
5954 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5951 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5955 % f)
5952 % f)
5956 else:
5953 else:
5957 runconclude = True
5954 runconclude = True
5958 continue
5955 continue
5959
5956
5960 if mark:
5957 if mark:
5961 ms.mark(f, "r")
5958 ms.mark(f, "r")
5962 elif unmark:
5959 elif unmark:
5963 ms.mark(f, "u")
5960 ms.mark(f, "u")
5964 else:
5961 else:
5965 # backup pre-resolve (merge uses .orig for its own purposes)
5962 # backup pre-resolve (merge uses .orig for its own purposes)
5966 a = repo.wjoin(f)
5963 a = repo.wjoin(f)
5967 try:
5964 try:
5968 util.copyfile(a, a + ".resolve")
5965 util.copyfile(a, a + ".resolve")
5969 except (IOError, OSError) as inst:
5966 except (IOError, OSError) as inst:
5970 if inst.errno != errno.ENOENT:
5967 if inst.errno != errno.ENOENT:
5971 raise
5968 raise
5972
5969
5973 try:
5970 try:
5974 # preresolve file
5971 # preresolve file
5975 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5972 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5976 'resolve')
5973 'resolve')
5977 complete, r = ms.preresolve(f, wctx)
5974 complete, r = ms.preresolve(f, wctx)
5978 if not complete:
5975 if not complete:
5979 tocomplete.append(f)
5976 tocomplete.append(f)
5980 elif r:
5977 elif r:
5981 ret = 1
5978 ret = 1
5982 finally:
5979 finally:
5983 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5980 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5984 ms.commit()
5981 ms.commit()
5985
5982
5986 # replace filemerge's .orig file with our resolve file, but only
5983 # replace filemerge's .orig file with our resolve file, but only
5987 # for merges that are complete
5984 # for merges that are complete
5988 if complete:
5985 if complete:
5989 try:
5986 try:
5990 util.rename(a + ".resolve",
5987 util.rename(a + ".resolve",
5991 scmutil.origpath(ui, repo, a))
5988 scmutil.origpath(ui, repo, a))
5992 except OSError as inst:
5989 except OSError as inst:
5993 if inst.errno != errno.ENOENT:
5990 if inst.errno != errno.ENOENT:
5994 raise
5991 raise
5995
5992
5996 for f in tocomplete:
5993 for f in tocomplete:
5997 try:
5994 try:
5998 # resolve file
5995 # resolve file
5999 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5996 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
6000 'resolve')
5997 'resolve')
6001 r = ms.resolve(f, wctx)
5998 r = ms.resolve(f, wctx)
6002 if r:
5999 if r:
6003 ret = 1
6000 ret = 1
6004 finally:
6001 finally:
6005 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6002 ui.setconfig('ui', 'forcemerge', '', 'resolve')
6006 ms.commit()
6003 ms.commit()
6007
6004
6008 # replace filemerge's .orig file with our resolve file
6005 # replace filemerge's .orig file with our resolve file
6009 a = repo.wjoin(f)
6006 a = repo.wjoin(f)
6010 try:
6007 try:
6011 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6008 util.rename(a + ".resolve", scmutil.origpath(ui, repo, a))
6012 except OSError as inst:
6009 except OSError as inst:
6013 if inst.errno != errno.ENOENT:
6010 if inst.errno != errno.ENOENT:
6014 raise
6011 raise
6015
6012
6016 ms.commit()
6013 ms.commit()
6017 ms.recordactions()
6014 ms.recordactions()
6018
6015
6019 if not didwork and pats:
6016 if not didwork and pats:
6020 ui.warn(_("arguments do not match paths that need resolving\n"))
6017 ui.warn(_("arguments do not match paths that need resolving\n"))
6021 elif ms.mergedriver and ms.mdstate() != 's':
6018 elif ms.mergedriver and ms.mdstate() != 's':
6022 # run conclude step when either a driver-resolved file is requested
6019 # run conclude step when either a driver-resolved file is requested
6023 # or there are no driver-resolved files
6020 # or there are no driver-resolved files
6024 # we can't use 'ret' to determine whether any files are unresolved
6021 # we can't use 'ret' to determine whether any files are unresolved
6025 # because we might not have tried to resolve some
6022 # because we might not have tried to resolve some
6026 if ((runconclude or not list(ms.driverresolved()))
6023 if ((runconclude or not list(ms.driverresolved()))
6027 and not list(ms.unresolved())):
6024 and not list(ms.unresolved())):
6028 proceed = mergemod.driverconclude(repo, ms, wctx)
6025 proceed = mergemod.driverconclude(repo, ms, wctx)
6029 ms.commit()
6026 ms.commit()
6030 if not proceed:
6027 if not proceed:
6031 return 1
6028 return 1
6032
6029
6033 finally:
6030 finally:
6034 wlock.release()
6031 wlock.release()
6035
6032
6036 # Nudge users into finishing an unfinished operation
6033 # Nudge users into finishing an unfinished operation
6037 unresolvedf = list(ms.unresolved())
6034 unresolvedf = list(ms.unresolved())
6038 driverresolvedf = list(ms.driverresolved())
6035 driverresolvedf = list(ms.driverresolved())
6039 if not unresolvedf and not driverresolvedf:
6036 if not unresolvedf and not driverresolvedf:
6040 ui.status(_('(no more unresolved files)\n'))
6037 ui.status(_('(no more unresolved files)\n'))
6041 cmdutil.checkafterresolved(repo)
6038 cmdutil.checkafterresolved(repo)
6042 elif not unresolvedf:
6039 elif not unresolvedf:
6043 ui.status(_('(no more unresolved files -- '
6040 ui.status(_('(no more unresolved files -- '
6044 'run "hg resolve --all" to conclude)\n'))
6041 'run "hg resolve --all" to conclude)\n'))
6045
6042
6046 return ret
6043 return ret
6047
6044
6048 @command('revert',
6045 @command('revert',
6049 [('a', 'all', None, _('revert all changes when no arguments given')),
6046 [('a', 'all', None, _('revert all changes when no arguments given')),
6050 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6047 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6051 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6048 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
6052 ('C', 'no-backup', None, _('do not save backup copies of files')),
6049 ('C', 'no-backup', None, _('do not save backup copies of files')),
6053 ('i', 'interactive', None,
6050 ('i', 'interactive', None,
6054 _('interactively select the changes (EXPERIMENTAL)')),
6051 _('interactively select the changes (EXPERIMENTAL)')),
6055 ] + walkopts + dryrunopts,
6052 ] + walkopts + dryrunopts,
6056 _('[OPTION]... [-r REV] [NAME]...'))
6053 _('[OPTION]... [-r REV] [NAME]...'))
6057 def revert(ui, repo, *pats, **opts):
6054 def revert(ui, repo, *pats, **opts):
6058 """restore files to their checkout state
6055 """restore files to their checkout state
6059
6056
6060 .. note::
6057 .. note::
6061
6058
6062 To check out earlier revisions, you should use :hg:`update REV`.
6059 To check out earlier revisions, you should use :hg:`update REV`.
6063 To cancel an uncommitted merge (and lose your changes),
6060 To cancel an uncommitted merge (and lose your changes),
6064 use :hg:`update --clean .`.
6061 use :hg:`update --clean .`.
6065
6062
6066 With no revision specified, revert the specified files or directories
6063 With no revision specified, revert the specified files or directories
6067 to the contents they had in the parent of the working directory.
6064 to the contents they had in the parent of the working directory.
6068 This restores the contents of files to an unmodified
6065 This restores the contents of files to an unmodified
6069 state and unschedules adds, removes, copies, and renames. If the
6066 state and unschedules adds, removes, copies, and renames. If the
6070 working directory has two parents, you must explicitly specify a
6067 working directory has two parents, you must explicitly specify a
6071 revision.
6068 revision.
6072
6069
6073 Using the -r/--rev or -d/--date options, revert the given files or
6070 Using the -r/--rev or -d/--date options, revert the given files or
6074 directories to their states as of a specific revision. Because
6071 directories to their states as of a specific revision. Because
6075 revert does not change the working directory parents, this will
6072 revert does not change the working directory parents, this will
6076 cause these files to appear modified. This can be helpful to "back
6073 cause these files to appear modified. This can be helpful to "back
6077 out" some or all of an earlier change. See :hg:`backout` for a
6074 out" some or all of an earlier change. See :hg:`backout` for a
6078 related method.
6075 related method.
6079
6076
6080 Modified files are saved with a .orig suffix before reverting.
6077 Modified files are saved with a .orig suffix before reverting.
6081 To disable these backups, use --no-backup.
6078 To disable these backups, use --no-backup.
6082
6079
6083 See :hg:`help dates` for a list of formats valid for -d/--date.
6080 See :hg:`help dates` for a list of formats valid for -d/--date.
6084
6081
6085 See :hg:`help backout` for a way to reverse the effect of an
6082 See :hg:`help backout` for a way to reverse the effect of an
6086 earlier changeset.
6083 earlier changeset.
6087
6084
6088 Returns 0 on success.
6085 Returns 0 on success.
6089 """
6086 """
6090
6087
6091 if opts.get("date"):
6088 if opts.get("date"):
6092 if opts.get("rev"):
6089 if opts.get("rev"):
6093 raise error.Abort(_("you can't specify a revision and a date"))
6090 raise error.Abort(_("you can't specify a revision and a date"))
6094 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6091 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
6095
6092
6096 parent, p2 = repo.dirstate.parents()
6093 parent, p2 = repo.dirstate.parents()
6097 if not opts.get('rev') and p2 != nullid:
6094 if not opts.get('rev') and p2 != nullid:
6098 # revert after merge is a trap for new users (issue2915)
6095 # revert after merge is a trap for new users (issue2915)
6099 raise error.Abort(_('uncommitted merge with no revision specified'),
6096 raise error.Abort(_('uncommitted merge with no revision specified'),
6100 hint=_('use "hg update" or see "hg help revert"'))
6097 hint=_('use "hg update" or see "hg help revert"'))
6101
6098
6102 ctx = scmutil.revsingle(repo, opts.get('rev'))
6099 ctx = scmutil.revsingle(repo, opts.get('rev'))
6103
6100
6104 if (not (pats or opts.get('include') or opts.get('exclude') or
6101 if (not (pats or opts.get('include') or opts.get('exclude') or
6105 opts.get('all') or opts.get('interactive'))):
6102 opts.get('all') or opts.get('interactive'))):
6106 msg = _("no files or directories specified")
6103 msg = _("no files or directories specified")
6107 if p2 != nullid:
6104 if p2 != nullid:
6108 hint = _("uncommitted merge, use --all to discard all changes,"
6105 hint = _("uncommitted merge, use --all to discard all changes,"
6109 " or 'hg update -C .' to abort the merge")
6106 " or 'hg update -C .' to abort the merge")
6110 raise error.Abort(msg, hint=hint)
6107 raise error.Abort(msg, hint=hint)
6111 dirty = any(repo.status())
6108 dirty = any(repo.status())
6112 node = ctx.node()
6109 node = ctx.node()
6113 if node != parent:
6110 if node != parent:
6114 if dirty:
6111 if dirty:
6115 hint = _("uncommitted changes, use --all to discard all"
6112 hint = _("uncommitted changes, use --all to discard all"
6116 " changes, or 'hg update %s' to update") % ctx.rev()
6113 " changes, or 'hg update %s' to update") % ctx.rev()
6117 else:
6114 else:
6118 hint = _("use --all to revert all files,"
6115 hint = _("use --all to revert all files,"
6119 " or 'hg update %s' to update") % ctx.rev()
6116 " or 'hg update %s' to update") % ctx.rev()
6120 elif dirty:
6117 elif dirty:
6121 hint = _("uncommitted changes, use --all to discard all changes")
6118 hint = _("uncommitted changes, use --all to discard all changes")
6122 else:
6119 else:
6123 hint = _("use --all to revert all files")
6120 hint = _("use --all to revert all files")
6124 raise error.Abort(msg, hint=hint)
6121 raise error.Abort(msg, hint=hint)
6125
6122
6126 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6123 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
6127
6124
6128 @command('rollback', dryrunopts +
6125 @command('rollback', dryrunopts +
6129 [('f', 'force', False, _('ignore safety measures'))])
6126 [('f', 'force', False, _('ignore safety measures'))])
6130 def rollback(ui, repo, **opts):
6127 def rollback(ui, repo, **opts):
6131 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6128 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6132
6129
6133 Please use :hg:`commit --amend` instead of rollback to correct
6130 Please use :hg:`commit --amend` instead of rollback to correct
6134 mistakes in the last commit.
6131 mistakes in the last commit.
6135
6132
6136 This command should be used with care. There is only one level of
6133 This command should be used with care. There is only one level of
6137 rollback, and there is no way to undo a rollback. It will also
6134 rollback, and there is no way to undo a rollback. It will also
6138 restore the dirstate at the time of the last transaction, losing
6135 restore the dirstate at the time of the last transaction, losing
6139 any dirstate changes since that time. This command does not alter
6136 any dirstate changes since that time. This command does not alter
6140 the working directory.
6137 the working directory.
6141
6138
6142 Transactions are used to encapsulate the effects of all commands
6139 Transactions are used to encapsulate the effects of all commands
6143 that create new changesets or propagate existing changesets into a
6140 that create new changesets or propagate existing changesets into a
6144 repository.
6141 repository.
6145
6142
6146 .. container:: verbose
6143 .. container:: verbose
6147
6144
6148 For example, the following commands are transactional, and their
6145 For example, the following commands are transactional, and their
6149 effects can be rolled back:
6146 effects can be rolled back:
6150
6147
6151 - commit
6148 - commit
6152 - import
6149 - import
6153 - pull
6150 - pull
6154 - push (with this repository as the destination)
6151 - push (with this repository as the destination)
6155 - unbundle
6152 - unbundle
6156
6153
6157 To avoid permanent data loss, rollback will refuse to rollback a
6154 To avoid permanent data loss, rollback will refuse to rollback a
6158 commit transaction if it isn't checked out. Use --force to
6155 commit transaction if it isn't checked out. Use --force to
6159 override this protection.
6156 override this protection.
6160
6157
6161 This command is not intended for use on public repositories. Once
6158 This command is not intended for use on public repositories. Once
6162 changes are visible for pull by other users, rolling a transaction
6159 changes are visible for pull by other users, rolling a transaction
6163 back locally is ineffective (someone else may already have pulled
6160 back locally is ineffective (someone else may already have pulled
6164 the changes). Furthermore, a race is possible with readers of the
6161 the changes). Furthermore, a race is possible with readers of the
6165 repository; for example an in-progress pull from the repository
6162 repository; for example an in-progress pull from the repository
6166 may fail if a rollback is performed.
6163 may fail if a rollback is performed.
6167
6164
6168 Returns 0 on success, 1 if no rollback data is available.
6165 Returns 0 on success, 1 if no rollback data is available.
6169 """
6166 """
6170 return repo.rollback(dryrun=opts.get('dry_run'),
6167 return repo.rollback(dryrun=opts.get('dry_run'),
6171 force=opts.get('force'))
6168 force=opts.get('force'))
6172
6169
6173 @command('root', [])
6170 @command('root', [])
6174 def root(ui, repo):
6171 def root(ui, repo):
6175 """print the root (top) of the current working directory
6172 """print the root (top) of the current working directory
6176
6173
6177 Print the root directory of the current repository.
6174 Print the root directory of the current repository.
6178
6175
6179 Returns 0 on success.
6176 Returns 0 on success.
6180 """
6177 """
6181 ui.write(repo.root + "\n")
6178 ui.write(repo.root + "\n")
6182
6179
6183 @command('^serve',
6180 @command('^serve',
6184 [('A', 'accesslog', '', _('name of access log file to write to'),
6181 [('A', 'accesslog', '', _('name of access log file to write to'),
6185 _('FILE')),
6182 _('FILE')),
6186 ('d', 'daemon', None, _('run server in background')),
6183 ('d', 'daemon', None, _('run server in background')),
6187 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6184 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
6188 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6185 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
6189 # use string type, then we can check if something was passed
6186 # use string type, then we can check if something was passed
6190 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6187 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
6191 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6188 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
6192 _('ADDR')),
6189 _('ADDR')),
6193 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6190 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
6194 _('PREFIX')),
6191 _('PREFIX')),
6195 ('n', 'name', '',
6192 ('n', 'name', '',
6196 _('name to show in web pages (default: working directory)'), _('NAME')),
6193 _('name to show in web pages (default: working directory)'), _('NAME')),
6197 ('', 'web-conf', '',
6194 ('', 'web-conf', '',
6198 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6195 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
6199 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6196 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
6200 _('FILE')),
6197 _('FILE')),
6201 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6198 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
6202 ('', 'stdio', None, _('for remote clients')),
6199 ('', 'stdio', None, _('for remote clients')),
6203 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6200 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
6204 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6201 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
6205 ('', 'style', '', _('template style to use'), _('STYLE')),
6202 ('', 'style', '', _('template style to use'), _('STYLE')),
6206 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6203 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
6207 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6204 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
6208 _('[OPTION]...'),
6205 _('[OPTION]...'),
6209 optionalrepo=True)
6206 optionalrepo=True)
6210 def serve(ui, repo, **opts):
6207 def serve(ui, repo, **opts):
6211 """start stand-alone webserver
6208 """start stand-alone webserver
6212
6209
6213 Start a local HTTP repository browser and pull server. You can use
6210 Start a local HTTP repository browser and pull server. You can use
6214 this for ad-hoc sharing and browsing of repositories. It is
6211 this for ad-hoc sharing and browsing of repositories. It is
6215 recommended to use a real web server to serve a repository for
6212 recommended to use a real web server to serve a repository for
6216 longer periods of time.
6213 longer periods of time.
6217
6214
6218 Please note that the server does not implement access control.
6215 Please note that the server does not implement access control.
6219 This means that, by default, anybody can read from the server and
6216 This means that, by default, anybody can read from the server and
6220 nobody can write to it by default. Set the ``web.allow_push``
6217 nobody can write to it by default. Set the ``web.allow_push``
6221 option to ``*`` to allow everybody to push to the server. You
6218 option to ``*`` to allow everybody to push to the server. You
6222 should use a real web server if you need to authenticate users.
6219 should use a real web server if you need to authenticate users.
6223
6220
6224 By default, the server logs accesses to stdout and errors to
6221 By default, the server logs accesses to stdout and errors to
6225 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6222 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6226 files.
6223 files.
6227
6224
6228 To have the server choose a free port number to listen on, specify
6225 To have the server choose a free port number to listen on, specify
6229 a port number of 0; in this case, the server will print the port
6226 a port number of 0; in this case, the server will print the port
6230 number it uses.
6227 number it uses.
6231
6228
6232 Returns 0 on success.
6229 Returns 0 on success.
6233 """
6230 """
6234
6231
6235 if opts["stdio"] and opts["cmdserver"]:
6232 if opts["stdio"] and opts["cmdserver"]:
6236 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6233 raise error.Abort(_("cannot use --stdio with --cmdserver"))
6237
6234
6238 if opts["stdio"]:
6235 if opts["stdio"]:
6239 if repo is None:
6236 if repo is None:
6240 raise error.RepoError(_("there is no Mercurial repository here"
6237 raise error.RepoError(_("there is no Mercurial repository here"
6241 " (.hg not found)"))
6238 " (.hg not found)"))
6242 s = sshserver.sshserver(ui, repo)
6239 s = sshserver.sshserver(ui, repo)
6243 s.serve_forever()
6240 s.serve_forever()
6244
6241
6245 if opts["cmdserver"]:
6242 if opts["cmdserver"]:
6246 service = commandserver.createservice(ui, repo, opts)
6243 service = commandserver.createservice(ui, repo, opts)
6247 else:
6244 else:
6248 service = hgweb.createservice(ui, repo, opts)
6245 service = hgweb.createservice(ui, repo, opts)
6249 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6246 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
6250
6247
6251 @command('^status|st',
6248 @command('^status|st',
6252 [('A', 'all', None, _('show status of all files')),
6249 [('A', 'all', None, _('show status of all files')),
6253 ('m', 'modified', None, _('show only modified files')),
6250 ('m', 'modified', None, _('show only modified files')),
6254 ('a', 'added', None, _('show only added files')),
6251 ('a', 'added', None, _('show only added files')),
6255 ('r', 'removed', None, _('show only removed files')),
6252 ('r', 'removed', None, _('show only removed files')),
6256 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6253 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
6257 ('c', 'clean', None, _('show only files without changes')),
6254 ('c', 'clean', None, _('show only files without changes')),
6258 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6255 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
6259 ('i', 'ignored', None, _('show only ignored files')),
6256 ('i', 'ignored', None, _('show only ignored files')),
6260 ('n', 'no-status', None, _('hide status prefix')),
6257 ('n', 'no-status', None, _('hide status prefix')),
6261 ('C', 'copies', None, _('show source of copied files')),
6258 ('C', 'copies', None, _('show source of copied files')),
6262 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6259 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
6263 ('', 'rev', [], _('show difference from revision'), _('REV')),
6260 ('', 'rev', [], _('show difference from revision'), _('REV')),
6264 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6261 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
6265 ] + walkopts + subrepoopts + formatteropts,
6262 ] + walkopts + subrepoopts + formatteropts,
6266 _('[OPTION]... [FILE]...'),
6263 _('[OPTION]... [FILE]...'),
6267 inferrepo=True)
6264 inferrepo=True)
6268 def status(ui, repo, *pats, **opts):
6265 def status(ui, repo, *pats, **opts):
6269 """show changed files in the working directory
6266 """show changed files in the working directory
6270
6267
6271 Show status of files in the repository. If names are given, only
6268 Show status of files in the repository. If names are given, only
6272 files that match are shown. Files that are clean or ignored or
6269 files that match are shown. Files that are clean or ignored or
6273 the source of a copy/move operation, are not listed unless
6270 the source of a copy/move operation, are not listed unless
6274 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6271 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6275 Unless options described with "show only ..." are given, the
6272 Unless options described with "show only ..." are given, the
6276 options -mardu are used.
6273 options -mardu are used.
6277
6274
6278 Option -q/--quiet hides untracked (unknown and ignored) files
6275 Option -q/--quiet hides untracked (unknown and ignored) files
6279 unless explicitly requested with -u/--unknown or -i/--ignored.
6276 unless explicitly requested with -u/--unknown or -i/--ignored.
6280
6277
6281 .. note::
6278 .. note::
6282
6279
6283 :hg:`status` may appear to disagree with diff if permissions have
6280 :hg:`status` may appear to disagree with diff if permissions have
6284 changed or a merge has occurred. The standard diff format does
6281 changed or a merge has occurred. The standard diff format does
6285 not report permission changes and diff only reports changes
6282 not report permission changes and diff only reports changes
6286 relative to one merge parent.
6283 relative to one merge parent.
6287
6284
6288 If one revision is given, it is used as the base revision.
6285 If one revision is given, it is used as the base revision.
6289 If two revisions are given, the differences between them are
6286 If two revisions are given, the differences between them are
6290 shown. The --change option can also be used as a shortcut to list
6287 shown. The --change option can also be used as a shortcut to list
6291 the changed files of a revision from its first parent.
6288 the changed files of a revision from its first parent.
6292
6289
6293 The codes used to show the status of files are::
6290 The codes used to show the status of files are::
6294
6291
6295 M = modified
6292 M = modified
6296 A = added
6293 A = added
6297 R = removed
6294 R = removed
6298 C = clean
6295 C = clean
6299 ! = missing (deleted by non-hg command, but still tracked)
6296 ! = missing (deleted by non-hg command, but still tracked)
6300 ? = not tracked
6297 ? = not tracked
6301 I = ignored
6298 I = ignored
6302 = origin of the previous file (with --copies)
6299 = origin of the previous file (with --copies)
6303
6300
6304 .. container:: verbose
6301 .. container:: verbose
6305
6302
6306 Examples:
6303 Examples:
6307
6304
6308 - show changes in the working directory relative to a
6305 - show changes in the working directory relative to a
6309 changeset::
6306 changeset::
6310
6307
6311 hg status --rev 9353
6308 hg status --rev 9353
6312
6309
6313 - show changes in the working directory relative to the
6310 - show changes in the working directory relative to the
6314 current directory (see :hg:`help patterns` for more information)::
6311 current directory (see :hg:`help patterns` for more information)::
6315
6312
6316 hg status re:
6313 hg status re:
6317
6314
6318 - show all changes including copies in an existing changeset::
6315 - show all changes including copies in an existing changeset::
6319
6316
6320 hg status --copies --change 9353
6317 hg status --copies --change 9353
6321
6318
6322 - get a NUL separated list of added files, suitable for xargs::
6319 - get a NUL separated list of added files, suitable for xargs::
6323
6320
6324 hg status -an0
6321 hg status -an0
6325
6322
6326 Returns 0 on success.
6323 Returns 0 on success.
6327 """
6324 """
6328
6325
6329 revs = opts.get('rev')
6326 revs = opts.get('rev')
6330 change = opts.get('change')
6327 change = opts.get('change')
6331
6328
6332 if revs and change:
6329 if revs and change:
6333 msg = _('cannot specify --rev and --change at the same time')
6330 msg = _('cannot specify --rev and --change at the same time')
6334 raise error.Abort(msg)
6331 raise error.Abort(msg)
6335 elif change:
6332 elif change:
6336 node2 = scmutil.revsingle(repo, change, None).node()
6333 node2 = scmutil.revsingle(repo, change, None).node()
6337 node1 = repo[node2].p1().node()
6334 node1 = repo[node2].p1().node()
6338 else:
6335 else:
6339 node1, node2 = scmutil.revpair(repo, revs)
6336 node1, node2 = scmutil.revpair(repo, revs)
6340
6337
6341 if pats:
6338 if pats:
6342 cwd = repo.getcwd()
6339 cwd = repo.getcwd()
6343 else:
6340 else:
6344 cwd = ''
6341 cwd = ''
6345
6342
6346 if opts.get('print0'):
6343 if opts.get('print0'):
6347 end = '\0'
6344 end = '\0'
6348 else:
6345 else:
6349 end = '\n'
6346 end = '\n'
6350 copy = {}
6347 copy = {}
6351 states = 'modified added removed deleted unknown ignored clean'.split()
6348 states = 'modified added removed deleted unknown ignored clean'.split()
6352 show = [k for k in states if opts.get(k)]
6349 show = [k for k in states if opts.get(k)]
6353 if opts.get('all'):
6350 if opts.get('all'):
6354 show += ui.quiet and (states[:4] + ['clean']) or states
6351 show += ui.quiet and (states[:4] + ['clean']) or states
6355 if not show:
6352 if not show:
6356 if ui.quiet:
6353 if ui.quiet:
6357 show = states[:4]
6354 show = states[:4]
6358 else:
6355 else:
6359 show = states[:5]
6356 show = states[:5]
6360
6357
6361 m = scmutil.match(repo[node2], pats, opts)
6358 m = scmutil.match(repo[node2], pats, opts)
6362 stat = repo.status(node1, node2, m,
6359 stat = repo.status(node1, node2, m,
6363 'ignored' in show, 'clean' in show, 'unknown' in show,
6360 'ignored' in show, 'clean' in show, 'unknown' in show,
6364 opts.get('subrepos'))
6361 opts.get('subrepos'))
6365 changestates = zip(states, 'MAR!?IC', stat)
6362 changestates = zip(states, 'MAR!?IC', stat)
6366
6363
6367 if (opts.get('all') or opts.get('copies')
6364 if (opts.get('all') or opts.get('copies')
6368 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6365 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6369 copy = copies.pathcopies(repo[node1], repo[node2], m)
6366 copy = copies.pathcopies(repo[node1], repo[node2], m)
6370
6367
6371 fm = ui.formatter('status', opts)
6368 fm = ui.formatter('status', opts)
6372 fmt = '%s' + end
6369 fmt = '%s' + end
6373 showchar = not opts.get('no_status')
6370 showchar = not opts.get('no_status')
6374
6371
6375 for state, char, files in changestates:
6372 for state, char, files in changestates:
6376 if state in show:
6373 if state in show:
6377 label = 'status.' + state
6374 label = 'status.' + state
6378 for f in files:
6375 for f in files:
6379 fm.startitem()
6376 fm.startitem()
6380 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6377 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6381 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6378 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6382 if f in copy:
6379 if f in copy:
6383 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6380 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6384 label='status.copied')
6381 label='status.copied')
6385 fm.end()
6382 fm.end()
6386
6383
6387 @command('^summary|sum',
6384 @command('^summary|sum',
6388 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6385 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6389 def summary(ui, repo, **opts):
6386 def summary(ui, repo, **opts):
6390 """summarize working directory state
6387 """summarize working directory state
6391
6388
6392 This generates a brief summary of the working directory state,
6389 This generates a brief summary of the working directory state,
6393 including parents, branch, commit status, phase and available updates.
6390 including parents, branch, commit status, phase and available updates.
6394
6391
6395 With the --remote option, this will check the default paths for
6392 With the --remote option, this will check the default paths for
6396 incoming and outgoing changes. This can be time-consuming.
6393 incoming and outgoing changes. This can be time-consuming.
6397
6394
6398 Returns 0 on success.
6395 Returns 0 on success.
6399 """
6396 """
6400
6397
6401 ctx = repo[None]
6398 ctx = repo[None]
6402 parents = ctx.parents()
6399 parents = ctx.parents()
6403 pnode = parents[0].node()
6400 pnode = parents[0].node()
6404 marks = []
6401 marks = []
6405
6402
6406 for p in parents:
6403 for p in parents:
6407 # label with log.changeset (instead of log.parent) since this
6404 # label with log.changeset (instead of log.parent) since this
6408 # shows a working directory parent *changeset*:
6405 # shows a working directory parent *changeset*:
6409 # i18n: column positioning for "hg summary"
6406 # i18n: column positioning for "hg summary"
6410 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6407 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6411 label='log.changeset changeset.%s' % p.phasestr())
6408 label='log.changeset changeset.%s' % p.phasestr())
6412 ui.write(' '.join(p.tags()), label='log.tag')
6409 ui.write(' '.join(p.tags()), label='log.tag')
6413 if p.bookmarks():
6410 if p.bookmarks():
6414 marks.extend(p.bookmarks())
6411 marks.extend(p.bookmarks())
6415 if p.rev() == -1:
6412 if p.rev() == -1:
6416 if not len(repo):
6413 if not len(repo):
6417 ui.write(_(' (empty repository)'))
6414 ui.write(_(' (empty repository)'))
6418 else:
6415 else:
6419 ui.write(_(' (no revision checked out)'))
6416 ui.write(_(' (no revision checked out)'))
6420 ui.write('\n')
6417 ui.write('\n')
6421 if p.description():
6418 if p.description():
6422 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6419 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6423 label='log.summary')
6420 label='log.summary')
6424
6421
6425 branch = ctx.branch()
6422 branch = ctx.branch()
6426 bheads = repo.branchheads(branch)
6423 bheads = repo.branchheads(branch)
6427 # i18n: column positioning for "hg summary"
6424 # i18n: column positioning for "hg summary"
6428 m = _('branch: %s\n') % branch
6425 m = _('branch: %s\n') % branch
6429 if branch != 'default':
6426 if branch != 'default':
6430 ui.write(m, label='log.branch')
6427 ui.write(m, label='log.branch')
6431 else:
6428 else:
6432 ui.status(m, label='log.branch')
6429 ui.status(m, label='log.branch')
6433
6430
6434 if marks:
6431 if marks:
6435 active = repo._activebookmark
6432 active = repo._activebookmark
6436 # i18n: column positioning for "hg summary"
6433 # i18n: column positioning for "hg summary"
6437 ui.write(_('bookmarks:'), label='log.bookmark')
6434 ui.write(_('bookmarks:'), label='log.bookmark')
6438 if active is not None:
6435 if active is not None:
6439 if active in marks:
6436 if active in marks:
6440 ui.write(' *' + active, label=activebookmarklabel)
6437 ui.write(' *' + active, label=activebookmarklabel)
6441 marks.remove(active)
6438 marks.remove(active)
6442 else:
6439 else:
6443 ui.write(' [%s]' % active, label=activebookmarklabel)
6440 ui.write(' [%s]' % active, label=activebookmarklabel)
6444 for m in marks:
6441 for m in marks:
6445 ui.write(' ' + m, label='log.bookmark')
6442 ui.write(' ' + m, label='log.bookmark')
6446 ui.write('\n', label='log.bookmark')
6443 ui.write('\n', label='log.bookmark')
6447
6444
6448 status = repo.status(unknown=True)
6445 status = repo.status(unknown=True)
6449
6446
6450 c = repo.dirstate.copies()
6447 c = repo.dirstate.copies()
6451 copied, renamed = [], []
6448 copied, renamed = [], []
6452 for d, s in c.iteritems():
6449 for d, s in c.iteritems():
6453 if s in status.removed:
6450 if s in status.removed:
6454 status.removed.remove(s)
6451 status.removed.remove(s)
6455 renamed.append(d)
6452 renamed.append(d)
6456 else:
6453 else:
6457 copied.append(d)
6454 copied.append(d)
6458 if d in status.added:
6455 if d in status.added:
6459 status.added.remove(d)
6456 status.added.remove(d)
6460
6457
6461 try:
6458 try:
6462 ms = mergemod.mergestate.read(repo)
6459 ms = mergemod.mergestate.read(repo)
6463 except error.UnsupportedMergeRecords as e:
6460 except error.UnsupportedMergeRecords as e:
6464 s = ' '.join(e.recordtypes)
6461 s = ' '.join(e.recordtypes)
6465 ui.warn(
6462 ui.warn(
6466 _('warning: merge state has unsupported record types: %s\n') % s)
6463 _('warning: merge state has unsupported record types: %s\n') % s)
6467 unresolved = 0
6464 unresolved = 0
6468 else:
6465 else:
6469 unresolved = [f for f in ms if ms[f] == 'u']
6466 unresolved = [f for f in ms if ms[f] == 'u']
6470
6467
6471 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6468 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6472
6469
6473 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6470 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6474 (ui.label(_('%d added'), 'status.added'), status.added),
6471 (ui.label(_('%d added'), 'status.added'), status.added),
6475 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6472 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6476 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6473 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6477 (ui.label(_('%d copied'), 'status.copied'), copied),
6474 (ui.label(_('%d copied'), 'status.copied'), copied),
6478 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6475 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6479 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6476 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6480 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6477 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6481 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6478 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6482 t = []
6479 t = []
6483 for l, s in labels:
6480 for l, s in labels:
6484 if s:
6481 if s:
6485 t.append(l % len(s))
6482 t.append(l % len(s))
6486
6483
6487 t = ', '.join(t)
6484 t = ', '.join(t)
6488 cleanworkdir = False
6485 cleanworkdir = False
6489
6486
6490 if repo.vfs.exists('graftstate'):
6487 if repo.vfs.exists('graftstate'):
6491 t += _(' (graft in progress)')
6488 t += _(' (graft in progress)')
6492 if repo.vfs.exists('updatestate'):
6489 if repo.vfs.exists('updatestate'):
6493 t += _(' (interrupted update)')
6490 t += _(' (interrupted update)')
6494 elif len(parents) > 1:
6491 elif len(parents) > 1:
6495 t += _(' (merge)')
6492 t += _(' (merge)')
6496 elif branch != parents[0].branch():
6493 elif branch != parents[0].branch():
6497 t += _(' (new branch)')
6494 t += _(' (new branch)')
6498 elif (parents[0].closesbranch() and
6495 elif (parents[0].closesbranch() and
6499 pnode in repo.branchheads(branch, closed=True)):
6496 pnode in repo.branchheads(branch, closed=True)):
6500 t += _(' (head closed)')
6497 t += _(' (head closed)')
6501 elif not (status.modified or status.added or status.removed or renamed or
6498 elif not (status.modified or status.added or status.removed or renamed or
6502 copied or subs):
6499 copied or subs):
6503 t += _(' (clean)')
6500 t += _(' (clean)')
6504 cleanworkdir = True
6501 cleanworkdir = True
6505 elif pnode not in bheads:
6502 elif pnode not in bheads:
6506 t += _(' (new branch head)')
6503 t += _(' (new branch head)')
6507
6504
6508 if parents:
6505 if parents:
6509 pendingphase = max(p.phase() for p in parents)
6506 pendingphase = max(p.phase() for p in parents)
6510 else:
6507 else:
6511 pendingphase = phases.public
6508 pendingphase = phases.public
6512
6509
6513 if pendingphase > phases.newcommitphase(ui):
6510 if pendingphase > phases.newcommitphase(ui):
6514 t += ' (%s)' % phases.phasenames[pendingphase]
6511 t += ' (%s)' % phases.phasenames[pendingphase]
6515
6512
6516 if cleanworkdir:
6513 if cleanworkdir:
6517 # i18n: column positioning for "hg summary"
6514 # i18n: column positioning for "hg summary"
6518 ui.status(_('commit: %s\n') % t.strip())
6515 ui.status(_('commit: %s\n') % t.strip())
6519 else:
6516 else:
6520 # i18n: column positioning for "hg summary"
6517 # i18n: column positioning for "hg summary"
6521 ui.write(_('commit: %s\n') % t.strip())
6518 ui.write(_('commit: %s\n') % t.strip())
6522
6519
6523 # all ancestors of branch heads - all ancestors of parent = new csets
6520 # all ancestors of branch heads - all ancestors of parent = new csets
6524 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6521 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6525 bheads))
6522 bheads))
6526
6523
6527 if new == 0:
6524 if new == 0:
6528 # i18n: column positioning for "hg summary"
6525 # i18n: column positioning for "hg summary"
6529 ui.status(_('update: (current)\n'))
6526 ui.status(_('update: (current)\n'))
6530 elif pnode not in bheads:
6527 elif pnode not in bheads:
6531 # i18n: column positioning for "hg summary"
6528 # i18n: column positioning for "hg summary"
6532 ui.write(_('update: %d new changesets (update)\n') % new)
6529 ui.write(_('update: %d new changesets (update)\n') % new)
6533 else:
6530 else:
6534 # i18n: column positioning for "hg summary"
6531 # i18n: column positioning for "hg summary"
6535 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6532 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6536 (new, len(bheads)))
6533 (new, len(bheads)))
6537
6534
6538 t = []
6535 t = []
6539 draft = len(repo.revs('draft()'))
6536 draft = len(repo.revs('draft()'))
6540 if draft:
6537 if draft:
6541 t.append(_('%d draft') % draft)
6538 t.append(_('%d draft') % draft)
6542 secret = len(repo.revs('secret()'))
6539 secret = len(repo.revs('secret()'))
6543 if secret:
6540 if secret:
6544 t.append(_('%d secret') % secret)
6541 t.append(_('%d secret') % secret)
6545
6542
6546 if draft or secret:
6543 if draft or secret:
6547 ui.status(_('phases: %s\n') % ', '.join(t))
6544 ui.status(_('phases: %s\n') % ', '.join(t))
6548
6545
6549 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6546 if obsolete.isenabled(repo, obsolete.createmarkersopt):
6550 for trouble in ("unstable", "divergent", "bumped"):
6547 for trouble in ("unstable", "divergent", "bumped"):
6551 numtrouble = len(repo.revs(trouble + "()"))
6548 numtrouble = len(repo.revs(trouble + "()"))
6552 # We write all the possibilities to ease translation
6549 # We write all the possibilities to ease translation
6553 troublemsg = {
6550 troublemsg = {
6554 "unstable": _("unstable: %d changesets"),
6551 "unstable": _("unstable: %d changesets"),
6555 "divergent": _("divergent: %d changesets"),
6552 "divergent": _("divergent: %d changesets"),
6556 "bumped": _("bumped: %d changesets"),
6553 "bumped": _("bumped: %d changesets"),
6557 }
6554 }
6558 if numtrouble > 0:
6555 if numtrouble > 0:
6559 ui.status(troublemsg[trouble] % numtrouble + "\n")
6556 ui.status(troublemsg[trouble] % numtrouble + "\n")
6560
6557
6561 cmdutil.summaryhooks(ui, repo)
6558 cmdutil.summaryhooks(ui, repo)
6562
6559
6563 if opts.get('remote'):
6560 if opts.get('remote'):
6564 needsincoming, needsoutgoing = True, True
6561 needsincoming, needsoutgoing = True, True
6565 else:
6562 else:
6566 needsincoming, needsoutgoing = False, False
6563 needsincoming, needsoutgoing = False, False
6567 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6564 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6568 if i:
6565 if i:
6569 needsincoming = True
6566 needsincoming = True
6570 if o:
6567 if o:
6571 needsoutgoing = True
6568 needsoutgoing = True
6572 if not needsincoming and not needsoutgoing:
6569 if not needsincoming and not needsoutgoing:
6573 return
6570 return
6574
6571
6575 def getincoming():
6572 def getincoming():
6576 source, branches = hg.parseurl(ui.expandpath('default'))
6573 source, branches = hg.parseurl(ui.expandpath('default'))
6577 sbranch = branches[0]
6574 sbranch = branches[0]
6578 try:
6575 try:
6579 other = hg.peer(repo, {}, source)
6576 other = hg.peer(repo, {}, source)
6580 except error.RepoError:
6577 except error.RepoError:
6581 if opts.get('remote'):
6578 if opts.get('remote'):
6582 raise
6579 raise
6583 return source, sbranch, None, None, None
6580 return source, sbranch, None, None, None
6584 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6581 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6585 if revs:
6582 if revs:
6586 revs = [other.lookup(rev) for rev in revs]
6583 revs = [other.lookup(rev) for rev in revs]
6587 ui.debug('comparing with %s\n' % util.hidepassword(source))
6584 ui.debug('comparing with %s\n' % util.hidepassword(source))
6588 repo.ui.pushbuffer()
6585 repo.ui.pushbuffer()
6589 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6586 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6590 repo.ui.popbuffer()
6587 repo.ui.popbuffer()
6591 return source, sbranch, other, commoninc, commoninc[1]
6588 return source, sbranch, other, commoninc, commoninc[1]
6592
6589
6593 if needsincoming:
6590 if needsincoming:
6594 source, sbranch, sother, commoninc, incoming = getincoming()
6591 source, sbranch, sother, commoninc, incoming = getincoming()
6595 else:
6592 else:
6596 source = sbranch = sother = commoninc = incoming = None
6593 source = sbranch = sother = commoninc = incoming = None
6597
6594
6598 def getoutgoing():
6595 def getoutgoing():
6599 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6596 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6600 dbranch = branches[0]
6597 dbranch = branches[0]
6601 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6598 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6602 if source != dest:
6599 if source != dest:
6603 try:
6600 try:
6604 dother = hg.peer(repo, {}, dest)
6601 dother = hg.peer(repo, {}, dest)
6605 except error.RepoError:
6602 except error.RepoError:
6606 if opts.get('remote'):
6603 if opts.get('remote'):
6607 raise
6604 raise
6608 return dest, dbranch, None, None
6605 return dest, dbranch, None, None
6609 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6606 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6610 elif sother is None:
6607 elif sother is None:
6611 # there is no explicit destination peer, but source one is invalid
6608 # there is no explicit destination peer, but source one is invalid
6612 return dest, dbranch, None, None
6609 return dest, dbranch, None, None
6613 else:
6610 else:
6614 dother = sother
6611 dother = sother
6615 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6612 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6616 common = None
6613 common = None
6617 else:
6614 else:
6618 common = commoninc
6615 common = commoninc
6619 if revs:
6616 if revs:
6620 revs = [repo.lookup(rev) for rev in revs]
6617 revs = [repo.lookup(rev) for rev in revs]
6621 repo.ui.pushbuffer()
6618 repo.ui.pushbuffer()
6622 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6619 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6623 commoninc=common)
6620 commoninc=common)
6624 repo.ui.popbuffer()
6621 repo.ui.popbuffer()
6625 return dest, dbranch, dother, outgoing
6622 return dest, dbranch, dother, outgoing
6626
6623
6627 if needsoutgoing:
6624 if needsoutgoing:
6628 dest, dbranch, dother, outgoing = getoutgoing()
6625 dest, dbranch, dother, outgoing = getoutgoing()
6629 else:
6626 else:
6630 dest = dbranch = dother = outgoing = None
6627 dest = dbranch = dother = outgoing = None
6631
6628
6632 if opts.get('remote'):
6629 if opts.get('remote'):
6633 t = []
6630 t = []
6634 if incoming:
6631 if incoming:
6635 t.append(_('1 or more incoming'))
6632 t.append(_('1 or more incoming'))
6636 o = outgoing.missing
6633 o = outgoing.missing
6637 if o:
6634 if o:
6638 t.append(_('%d outgoing') % len(o))
6635 t.append(_('%d outgoing') % len(o))
6639 other = dother or sother
6636 other = dother or sother
6640 if 'bookmarks' in other.listkeys('namespaces'):
6637 if 'bookmarks' in other.listkeys('namespaces'):
6641 counts = bookmarks.summary(repo, other)
6638 counts = bookmarks.summary(repo, other)
6642 if counts[0] > 0:
6639 if counts[0] > 0:
6643 t.append(_('%d incoming bookmarks') % counts[0])
6640 t.append(_('%d incoming bookmarks') % counts[0])
6644 if counts[1] > 0:
6641 if counts[1] > 0:
6645 t.append(_('%d outgoing bookmarks') % counts[1])
6642 t.append(_('%d outgoing bookmarks') % counts[1])
6646
6643
6647 if t:
6644 if t:
6648 # i18n: column positioning for "hg summary"
6645 # i18n: column positioning for "hg summary"
6649 ui.write(_('remote: %s\n') % (', '.join(t)))
6646 ui.write(_('remote: %s\n') % (', '.join(t)))
6650 else:
6647 else:
6651 # i18n: column positioning for "hg summary"
6648 # i18n: column positioning for "hg summary"
6652 ui.status(_('remote: (synced)\n'))
6649 ui.status(_('remote: (synced)\n'))
6653
6650
6654 cmdutil.summaryremotehooks(ui, repo, opts,
6651 cmdutil.summaryremotehooks(ui, repo, opts,
6655 ((source, sbranch, sother, commoninc),
6652 ((source, sbranch, sother, commoninc),
6656 (dest, dbranch, dother, outgoing)))
6653 (dest, dbranch, dother, outgoing)))
6657
6654
6658 @command('tag',
6655 @command('tag',
6659 [('f', 'force', None, _('force tag')),
6656 [('f', 'force', None, _('force tag')),
6660 ('l', 'local', None, _('make the tag local')),
6657 ('l', 'local', None, _('make the tag local')),
6661 ('r', 'rev', '', _('revision to tag'), _('REV')),
6658 ('r', 'rev', '', _('revision to tag'), _('REV')),
6662 ('', 'remove', None, _('remove a tag')),
6659 ('', 'remove', None, _('remove a tag')),
6663 # -l/--local is already there, commitopts cannot be used
6660 # -l/--local is already there, commitopts cannot be used
6664 ('e', 'edit', None, _('invoke editor on commit messages')),
6661 ('e', 'edit', None, _('invoke editor on commit messages')),
6665 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6662 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6666 ] + commitopts2,
6663 ] + commitopts2,
6667 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6664 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6668 def tag(ui, repo, name1, *names, **opts):
6665 def tag(ui, repo, name1, *names, **opts):
6669 """add one or more tags for the current or given revision
6666 """add one or more tags for the current or given revision
6670
6667
6671 Name a particular revision using <name>.
6668 Name a particular revision using <name>.
6672
6669
6673 Tags are used to name particular revisions of the repository and are
6670 Tags are used to name particular revisions of the repository and are
6674 very useful to compare different revisions, to go back to significant
6671 very useful to compare different revisions, to go back to significant
6675 earlier versions or to mark branch points as releases, etc. Changing
6672 earlier versions or to mark branch points as releases, etc. Changing
6676 an existing tag is normally disallowed; use -f/--force to override.
6673 an existing tag is normally disallowed; use -f/--force to override.
6677
6674
6678 If no revision is given, the parent of the working directory is
6675 If no revision is given, the parent of the working directory is
6679 used.
6676 used.
6680
6677
6681 To facilitate version control, distribution, and merging of tags,
6678 To facilitate version control, distribution, and merging of tags,
6682 they are stored as a file named ".hgtags" which is managed similarly
6679 they are stored as a file named ".hgtags" which is managed similarly
6683 to other project files and can be hand-edited if necessary. This
6680 to other project files and can be hand-edited if necessary. This
6684 also means that tagging creates a new commit. The file
6681 also means that tagging creates a new commit. The file
6685 ".hg/localtags" is used for local tags (not shared among
6682 ".hg/localtags" is used for local tags (not shared among
6686 repositories).
6683 repositories).
6687
6684
6688 Tag commits are usually made at the head of a branch. If the parent
6685 Tag commits are usually made at the head of a branch. If the parent
6689 of the working directory is not a branch head, :hg:`tag` aborts; use
6686 of the working directory is not a branch head, :hg:`tag` aborts; use
6690 -f/--force to force the tag commit to be based on a non-head
6687 -f/--force to force the tag commit to be based on a non-head
6691 changeset.
6688 changeset.
6692
6689
6693 See :hg:`help dates` for a list of formats valid for -d/--date.
6690 See :hg:`help dates` for a list of formats valid for -d/--date.
6694
6691
6695 Since tag names have priority over branch names during revision
6692 Since tag names have priority over branch names during revision
6696 lookup, using an existing branch name as a tag name is discouraged.
6693 lookup, using an existing branch name as a tag name is discouraged.
6697
6694
6698 Returns 0 on success.
6695 Returns 0 on success.
6699 """
6696 """
6700 wlock = lock = None
6697 wlock = lock = None
6701 try:
6698 try:
6702 wlock = repo.wlock()
6699 wlock = repo.wlock()
6703 lock = repo.lock()
6700 lock = repo.lock()
6704 rev_ = "."
6701 rev_ = "."
6705 names = [t.strip() for t in (name1,) + names]
6702 names = [t.strip() for t in (name1,) + names]
6706 if len(names) != len(set(names)):
6703 if len(names) != len(set(names)):
6707 raise error.Abort(_('tag names must be unique'))
6704 raise error.Abort(_('tag names must be unique'))
6708 for n in names:
6705 for n in names:
6709 scmutil.checknewlabel(repo, n, 'tag')
6706 scmutil.checknewlabel(repo, n, 'tag')
6710 if not n:
6707 if not n:
6711 raise error.Abort(_('tag names cannot consist entirely of '
6708 raise error.Abort(_('tag names cannot consist entirely of '
6712 'whitespace'))
6709 'whitespace'))
6713 if opts.get('rev') and opts.get('remove'):
6710 if opts.get('rev') and opts.get('remove'):
6714 raise error.Abort(_("--rev and --remove are incompatible"))
6711 raise error.Abort(_("--rev and --remove are incompatible"))
6715 if opts.get('rev'):
6712 if opts.get('rev'):
6716 rev_ = opts['rev']
6713 rev_ = opts['rev']
6717 message = opts.get('message')
6714 message = opts.get('message')
6718 if opts.get('remove'):
6715 if opts.get('remove'):
6719 if opts.get('local'):
6716 if opts.get('local'):
6720 expectedtype = 'local'
6717 expectedtype = 'local'
6721 else:
6718 else:
6722 expectedtype = 'global'
6719 expectedtype = 'global'
6723
6720
6724 for n in names:
6721 for n in names:
6725 if not repo.tagtype(n):
6722 if not repo.tagtype(n):
6726 raise error.Abort(_("tag '%s' does not exist") % n)
6723 raise error.Abort(_("tag '%s' does not exist") % n)
6727 if repo.tagtype(n) != expectedtype:
6724 if repo.tagtype(n) != expectedtype:
6728 if expectedtype == 'global':
6725 if expectedtype == 'global':
6729 raise error.Abort(_("tag '%s' is not a global tag") % n)
6726 raise error.Abort(_("tag '%s' is not a global tag") % n)
6730 else:
6727 else:
6731 raise error.Abort(_("tag '%s' is not a local tag") % n)
6728 raise error.Abort(_("tag '%s' is not a local tag") % n)
6732 rev_ = 'null'
6729 rev_ = 'null'
6733 if not message:
6730 if not message:
6734 # we don't translate commit messages
6731 # we don't translate commit messages
6735 message = 'Removed tag %s' % ', '.join(names)
6732 message = 'Removed tag %s' % ', '.join(names)
6736 elif not opts.get('force'):
6733 elif not opts.get('force'):
6737 for n in names:
6734 for n in names:
6738 if n in repo.tags():
6735 if n in repo.tags():
6739 raise error.Abort(_("tag '%s' already exists "
6736 raise error.Abort(_("tag '%s' already exists "
6740 "(use -f to force)") % n)
6737 "(use -f to force)") % n)
6741 if not opts.get('local'):
6738 if not opts.get('local'):
6742 p1, p2 = repo.dirstate.parents()
6739 p1, p2 = repo.dirstate.parents()
6743 if p2 != nullid:
6740 if p2 != nullid:
6744 raise error.Abort(_('uncommitted merge'))
6741 raise error.Abort(_('uncommitted merge'))
6745 bheads = repo.branchheads()
6742 bheads = repo.branchheads()
6746 if not opts.get('force') and bheads and p1 not in bheads:
6743 if not opts.get('force') and bheads and p1 not in bheads:
6747 raise error.Abort(_('not at a branch head (use -f to force)'))
6744 raise error.Abort(_('not at a branch head (use -f to force)'))
6748 r = scmutil.revsingle(repo, rev_).node()
6745 r = scmutil.revsingle(repo, rev_).node()
6749
6746
6750 if not message:
6747 if not message:
6751 # we don't translate commit messages
6748 # we don't translate commit messages
6752 message = ('Added tag %s for changeset %s' %
6749 message = ('Added tag %s for changeset %s' %
6753 (', '.join(names), short(r)))
6750 (', '.join(names), short(r)))
6754
6751
6755 date = opts.get('date')
6752 date = opts.get('date')
6756 if date:
6753 if date:
6757 date = util.parsedate(date)
6754 date = util.parsedate(date)
6758
6755
6759 if opts.get('remove'):
6756 if opts.get('remove'):
6760 editform = 'tag.remove'
6757 editform = 'tag.remove'
6761 else:
6758 else:
6762 editform = 'tag.add'
6759 editform = 'tag.add'
6763 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6760 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6764
6761
6765 # don't allow tagging the null rev
6762 # don't allow tagging the null rev
6766 if (not opts.get('remove') and
6763 if (not opts.get('remove') and
6767 scmutil.revsingle(repo, rev_).rev() == nullrev):
6764 scmutil.revsingle(repo, rev_).rev() == nullrev):
6768 raise error.Abort(_("cannot tag null revision"))
6765 raise error.Abort(_("cannot tag null revision"))
6769
6766
6770 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6767 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6771 editor=editor)
6768 editor=editor)
6772 finally:
6769 finally:
6773 release(lock, wlock)
6770 release(lock, wlock)
6774
6771
6775 @command('tags', formatteropts, '')
6772 @command('tags', formatteropts, '')
6776 def tags(ui, repo, **opts):
6773 def tags(ui, repo, **opts):
6777 """list repository tags
6774 """list repository tags
6778
6775
6779 This lists both regular and local tags. When the -v/--verbose
6776 This lists both regular and local tags. When the -v/--verbose
6780 switch is used, a third column "local" is printed for local tags.
6777 switch is used, a third column "local" is printed for local tags.
6781 When the -q/--quiet switch is used, only the tag name is printed.
6778 When the -q/--quiet switch is used, only the tag name is printed.
6782
6779
6783 Returns 0 on success.
6780 Returns 0 on success.
6784 """
6781 """
6785
6782
6786 fm = ui.formatter('tags', opts)
6783 fm = ui.formatter('tags', opts)
6787 hexfunc = fm.hexfunc
6784 hexfunc = fm.hexfunc
6788 tagtype = ""
6785 tagtype = ""
6789
6786
6790 for t, n in reversed(repo.tagslist()):
6787 for t, n in reversed(repo.tagslist()):
6791 hn = hexfunc(n)
6788 hn = hexfunc(n)
6792 label = 'tags.normal'
6789 label = 'tags.normal'
6793 tagtype = ''
6790 tagtype = ''
6794 if repo.tagtype(t) == 'local':
6791 if repo.tagtype(t) == 'local':
6795 label = 'tags.local'
6792 label = 'tags.local'
6796 tagtype = 'local'
6793 tagtype = 'local'
6797
6794
6798 fm.startitem()
6795 fm.startitem()
6799 fm.write('tag', '%s', t, label=label)
6796 fm.write('tag', '%s', t, label=label)
6800 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6797 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6801 fm.condwrite(not ui.quiet, 'rev node', fmt,
6798 fm.condwrite(not ui.quiet, 'rev node', fmt,
6802 repo.changelog.rev(n), hn, label=label)
6799 repo.changelog.rev(n), hn, label=label)
6803 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6800 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6804 tagtype, label=label)
6801 tagtype, label=label)
6805 fm.plain('\n')
6802 fm.plain('\n')
6806 fm.end()
6803 fm.end()
6807
6804
6808 @command('tip',
6805 @command('tip',
6809 [('p', 'patch', None, _('show patch')),
6806 [('p', 'patch', None, _('show patch')),
6810 ('g', 'git', None, _('use git extended diff format')),
6807 ('g', 'git', None, _('use git extended diff format')),
6811 ] + templateopts,
6808 ] + templateopts,
6812 _('[-p] [-g]'))
6809 _('[-p] [-g]'))
6813 def tip(ui, repo, **opts):
6810 def tip(ui, repo, **opts):
6814 """show the tip revision (DEPRECATED)
6811 """show the tip revision (DEPRECATED)
6815
6812
6816 The tip revision (usually just called the tip) is the changeset
6813 The tip revision (usually just called the tip) is the changeset
6817 most recently added to the repository (and therefore the most
6814 most recently added to the repository (and therefore the most
6818 recently changed head).
6815 recently changed head).
6819
6816
6820 If you have just made a commit, that commit will be the tip. If
6817 If you have just made a commit, that commit will be the tip. If
6821 you have just pulled changes from another repository, the tip of
6818 you have just pulled changes from another repository, the tip of
6822 that repository becomes the current tip. The "tip" tag is special
6819 that repository becomes the current tip. The "tip" tag is special
6823 and cannot be renamed or assigned to a different changeset.
6820 and cannot be renamed or assigned to a different changeset.
6824
6821
6825 This command is deprecated, please use :hg:`heads` instead.
6822 This command is deprecated, please use :hg:`heads` instead.
6826
6823
6827 Returns 0 on success.
6824 Returns 0 on success.
6828 """
6825 """
6829 displayer = cmdutil.show_changeset(ui, repo, opts)
6826 displayer = cmdutil.show_changeset(ui, repo, opts)
6830 displayer.show(repo['tip'])
6827 displayer.show(repo['tip'])
6831 displayer.close()
6828 displayer.close()
6832
6829
6833 @command('unbundle',
6830 @command('unbundle',
6834 [('u', 'update', None,
6831 [('u', 'update', None,
6835 _('update to new branch head if changesets were unbundled'))],
6832 _('update to new branch head if changesets were unbundled'))],
6836 _('[-u] FILE...'))
6833 _('[-u] FILE...'))
6837 def unbundle(ui, repo, fname1, *fnames, **opts):
6834 def unbundle(ui, repo, fname1, *fnames, **opts):
6838 """apply one or more changegroup files
6835 """apply one or more changegroup files
6839
6836
6840 Apply one or more compressed changegroup files generated by the
6837 Apply one or more compressed changegroup files generated by the
6841 bundle command.
6838 bundle command.
6842
6839
6843 Returns 0 on success, 1 if an update has unresolved files.
6840 Returns 0 on success, 1 if an update has unresolved files.
6844 """
6841 """
6845 fnames = (fname1,) + fnames
6842 fnames = (fname1,) + fnames
6846
6843
6847 lock = repo.lock()
6844 lock = repo.lock()
6848 try:
6845 try:
6849 for fname in fnames:
6846 for fname in fnames:
6850 f = hg.openpath(ui, fname)
6847 f = hg.openpath(ui, fname)
6851 gen = exchange.readbundle(ui, f, fname)
6848 gen = exchange.readbundle(ui, f, fname)
6852 if isinstance(gen, bundle2.unbundle20):
6849 if isinstance(gen, bundle2.unbundle20):
6853 tr = repo.transaction('unbundle')
6850 tr = repo.transaction('unbundle')
6854 try:
6851 try:
6855 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6852 op = bundle2.applybundle(repo, gen, tr, source='unbundle',
6856 url='bundle:' + fname)
6853 url='bundle:' + fname)
6857 tr.close()
6854 tr.close()
6858 except error.BundleUnknownFeatureError as exc:
6855 except error.BundleUnknownFeatureError as exc:
6859 raise error.Abort(_('%s: unknown bundle feature, %s')
6856 raise error.Abort(_('%s: unknown bundle feature, %s')
6860 % (fname, exc),
6857 % (fname, exc),
6861 hint=_("see https://mercurial-scm.org/"
6858 hint=_("see https://mercurial-scm.org/"
6862 "wiki/BundleFeature for more "
6859 "wiki/BundleFeature for more "
6863 "information"))
6860 "information"))
6864 finally:
6861 finally:
6865 if tr:
6862 if tr:
6866 tr.release()
6863 tr.release()
6867 changes = [r.get('return', 0)
6864 changes = [r.get('return', 0)
6868 for r in op.records['changegroup']]
6865 for r in op.records['changegroup']]
6869 modheads = changegroup.combineresults(changes)
6866 modheads = changegroup.combineresults(changes)
6870 elif isinstance(gen, streamclone.streamcloneapplier):
6867 elif isinstance(gen, streamclone.streamcloneapplier):
6871 raise error.Abort(
6868 raise error.Abort(
6872 _('packed bundles cannot be applied with '
6869 _('packed bundles cannot be applied with '
6873 '"hg unbundle"'),
6870 '"hg unbundle"'),
6874 hint=_('use "hg debugapplystreamclonebundle"'))
6871 hint=_('use "hg debugapplystreamclonebundle"'))
6875 else:
6872 else:
6876 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6873 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6877 finally:
6874 finally:
6878 lock.release()
6875 lock.release()
6879
6876
6880 return postincoming(ui, repo, modheads, opts.get('update'), None)
6877 return postincoming(ui, repo, modheads, opts.get('update'), None)
6881
6878
6882 @command('^update|up|checkout|co',
6879 @command('^update|up|checkout|co',
6883 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6880 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6884 ('c', 'check', None,
6881 ('c', 'check', None,
6885 _('update across branches if no uncommitted changes')),
6882 _('update across branches if no uncommitted changes')),
6886 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6883 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6887 ('r', 'rev', '', _('revision'), _('REV'))
6884 ('r', 'rev', '', _('revision'), _('REV'))
6888 ] + mergetoolopts,
6885 ] + mergetoolopts,
6889 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6886 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6890 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6887 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6891 tool=None):
6888 tool=None):
6892 """update working directory (or switch revisions)
6889 """update working directory (or switch revisions)
6893
6890
6894 Update the repository's working directory to the specified
6891 Update the repository's working directory to the specified
6895 changeset. If no changeset is specified, update to the tip of the
6892 changeset. If no changeset is specified, update to the tip of the
6896 current named branch and move the active bookmark (see :hg:`help
6893 current named branch and move the active bookmark (see :hg:`help
6897 bookmarks`).
6894 bookmarks`).
6898
6895
6899 Update sets the working directory's parent revision to the specified
6896 Update sets the working directory's parent revision to the specified
6900 changeset (see :hg:`help parents`).
6897 changeset (see :hg:`help parents`).
6901
6898
6902 If the changeset is not a descendant or ancestor of the working
6899 If the changeset is not a descendant or ancestor of the working
6903 directory's parent, the update is aborted. With the -c/--check
6900 directory's parent, the update is aborted. With the -c/--check
6904 option, the working directory is checked for uncommitted changes; if
6901 option, the working directory is checked for uncommitted changes; if
6905 none are found, the working directory is updated to the specified
6902 none are found, the working directory is updated to the specified
6906 changeset.
6903 changeset.
6907
6904
6908 .. container:: verbose
6905 .. container:: verbose
6909
6906
6910 The following rules apply when the working directory contains
6907 The following rules apply when the working directory contains
6911 uncommitted changes:
6908 uncommitted changes:
6912
6909
6913 1. If neither -c/--check nor -C/--clean is specified, and if
6910 1. If neither -c/--check nor -C/--clean is specified, and if
6914 the requested changeset is an ancestor or descendant of
6911 the requested changeset is an ancestor or descendant of
6915 the working directory's parent, the uncommitted changes
6912 the working directory's parent, the uncommitted changes
6916 are merged into the requested changeset and the merged
6913 are merged into the requested changeset and the merged
6917 result is left uncommitted. If the requested changeset is
6914 result is left uncommitted. If the requested changeset is
6918 not an ancestor or descendant (that is, it is on another
6915 not an ancestor or descendant (that is, it is on another
6919 branch), the update is aborted and the uncommitted changes
6916 branch), the update is aborted and the uncommitted changes
6920 are preserved.
6917 are preserved.
6921
6918
6922 2. With the -c/--check option, the update is aborted and the
6919 2. With the -c/--check option, the update is aborted and the
6923 uncommitted changes are preserved.
6920 uncommitted changes are preserved.
6924
6921
6925 3. With the -C/--clean option, uncommitted changes are discarded and
6922 3. With the -C/--clean option, uncommitted changes are discarded and
6926 the working directory is updated to the requested changeset.
6923 the working directory is updated to the requested changeset.
6927
6924
6928 To cancel an uncommitted merge (and lose your changes), use
6925 To cancel an uncommitted merge (and lose your changes), use
6929 :hg:`update --clean .`.
6926 :hg:`update --clean .`.
6930
6927
6931 Use null as the changeset to remove the working directory (like
6928 Use null as the changeset to remove the working directory (like
6932 :hg:`clone -U`).
6929 :hg:`clone -U`).
6933
6930
6934 If you want to revert just one file to an older revision, use
6931 If you want to revert just one file to an older revision, use
6935 :hg:`revert [-r REV] NAME`.
6932 :hg:`revert [-r REV] NAME`.
6936
6933
6937 See :hg:`help dates` for a list of formats valid for -d/--date.
6934 See :hg:`help dates` for a list of formats valid for -d/--date.
6938
6935
6939 Returns 0 on success, 1 if there are unresolved files.
6936 Returns 0 on success, 1 if there are unresolved files.
6940 """
6937 """
6941 movemarkfrom = None
6938 movemarkfrom = None
6942 if rev and node:
6939 if rev and node:
6943 raise error.Abort(_("please specify just one revision"))
6940 raise error.Abort(_("please specify just one revision"))
6944
6941
6945 if rev is None or rev == '':
6942 if rev is None or rev == '':
6946 rev = node
6943 rev = node
6947
6944
6948 wlock = repo.wlock()
6945 wlock = repo.wlock()
6949 try:
6946 try:
6950 cmdutil.clearunfinished(repo)
6947 cmdutil.clearunfinished(repo)
6951
6948
6952 if date:
6949 if date:
6953 if rev is not None:
6950 if rev is not None:
6954 raise error.Abort(_("you can't specify a revision and a date"))
6951 raise error.Abort(_("you can't specify a revision and a date"))
6955 rev = cmdutil.finddate(ui, repo, date)
6952 rev = cmdutil.finddate(ui, repo, date)
6956
6953
6957 # if we defined a bookmark, we have to remember the original name
6954 # if we defined a bookmark, we have to remember the original name
6958 brev = rev
6955 brev = rev
6959 rev = scmutil.revsingle(repo, rev, rev).rev()
6956 rev = scmutil.revsingle(repo, rev, rev).rev()
6960
6957
6961 if check and clean:
6958 if check and clean:
6962 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6959 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6963 )
6960 )
6964
6961
6965 if check:
6962 if check:
6966 cmdutil.bailifchanged(repo, merge=False)
6963 cmdutil.bailifchanged(repo, merge=False)
6967 if rev is None:
6964 if rev is None:
6968 updata = destutil.destupdate(repo, clean=clean, check=check)
6965 updata = destutil.destupdate(repo, clean=clean, check=check)
6969 rev, movemarkfrom, brev = updata
6966 rev, movemarkfrom, brev = updata
6970
6967
6971 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6968 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6972
6969
6973 if clean:
6970 if clean:
6974 ret = hg.clean(repo, rev)
6971 ret = hg.clean(repo, rev)
6975 else:
6972 else:
6976 ret = hg.update(repo, rev)
6973 ret = hg.update(repo, rev)
6977
6974
6978 if not ret and movemarkfrom:
6975 if not ret and movemarkfrom:
6979 if movemarkfrom == repo['.'].node():
6976 if movemarkfrom == repo['.'].node():
6980 pass # no-op update
6977 pass # no-op update
6981 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6978 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6982 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6979 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6983 else:
6980 else:
6984 # this can happen with a non-linear update
6981 # this can happen with a non-linear update
6985 ui.status(_("(leaving bookmark %s)\n") %
6982 ui.status(_("(leaving bookmark %s)\n") %
6986 repo._activebookmark)
6983 repo._activebookmark)
6987 bookmarks.deactivate(repo)
6984 bookmarks.deactivate(repo)
6988 elif brev in repo._bookmarks:
6985 elif brev in repo._bookmarks:
6989 bookmarks.activate(repo, brev)
6986 bookmarks.activate(repo, brev)
6990 ui.status(_("(activating bookmark %s)\n") % brev)
6987 ui.status(_("(activating bookmark %s)\n") % brev)
6991 elif brev:
6988 elif brev:
6992 if repo._activebookmark:
6989 if repo._activebookmark:
6993 ui.status(_("(leaving bookmark %s)\n") %
6990 ui.status(_("(leaving bookmark %s)\n") %
6994 repo._activebookmark)
6991 repo._activebookmark)
6995 bookmarks.deactivate(repo)
6992 bookmarks.deactivate(repo)
6996 finally:
6993 finally:
6997 wlock.release()
6994 wlock.release()
6998
6995
6999 return ret
6996 return ret
7000
6997
7001 @command('verify', [])
6998 @command('verify', [])
7002 def verify(ui, repo):
6999 def verify(ui, repo):
7003 """verify the integrity of the repository
7000 """verify the integrity of the repository
7004
7001
7005 Verify the integrity of the current repository.
7002 Verify the integrity of the current repository.
7006
7003
7007 This will perform an extensive check of the repository's
7004 This will perform an extensive check of the repository's
7008 integrity, validating the hashes and checksums of each entry in
7005 integrity, validating the hashes and checksums of each entry in
7009 the changelog, manifest, and tracked files, as well as the
7006 the changelog, manifest, and tracked files, as well as the
7010 integrity of their crosslinks and indices.
7007 integrity of their crosslinks and indices.
7011
7008
7012 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7009 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7013 for more information about recovery from corruption of the
7010 for more information about recovery from corruption of the
7014 repository.
7011 repository.
7015
7012
7016 Returns 0 on success, 1 if errors are encountered.
7013 Returns 0 on success, 1 if errors are encountered.
7017 """
7014 """
7018 return hg.verify(repo)
7015 return hg.verify(repo)
7019
7016
7020 @command('version', [], norepo=True)
7017 @command('version', [], norepo=True)
7021 def version_(ui):
7018 def version_(ui):
7022 """output version and copyright information"""
7019 """output version and copyright information"""
7023 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7020 ui.write(_("Mercurial Distributed SCM (version %s)\n")
7024 % util.version())
7021 % util.version())
7025 ui.status(_(
7022 ui.status(_(
7026 "(see https://mercurial-scm.org for more information)\n"
7023 "(see https://mercurial-scm.org for more information)\n"
7027 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
7024 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
7028 "This is free software; see the source for copying conditions. "
7025 "This is free software; see the source for copying conditions. "
7029 "There is NO\nwarranty; "
7026 "There is NO\nwarranty; "
7030 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7027 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7031 ))
7028 ))
7032
7029
7033 ui.note(_("\nEnabled extensions:\n\n"))
7030 ui.note(_("\nEnabled extensions:\n\n"))
7034 if ui.verbose:
7031 if ui.verbose:
7035 # format names and versions into columns
7032 # format names and versions into columns
7036 names = []
7033 names = []
7037 vers = []
7034 vers = []
7038 for name, module in extensions.extensions():
7035 for name, module in extensions.extensions():
7039 names.append(name)
7036 names.append(name)
7040 vers.append(extensions.moduleversion(module))
7037 vers.append(extensions.moduleversion(module))
7041 if names:
7038 if names:
7042 maxnamelen = max(len(n) for n in names)
7039 maxnamelen = max(len(n) for n in names)
7043 for i, name in enumerate(names):
7040 for i, name in enumerate(names):
7044 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
7041 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
General Comments 0
You need to be logged in to leave comments. Login now