##// END OF EJS Templates
bookmarks: don't deactivate on no-op update (issue4901)
Matt Mackall -
r26676:71a48513 default
parent child Browse files
Show More
@@ -1,6685 +1,6687 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, 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 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random, operator
22 import random, operator
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo, destutil
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
24 import phases, obsolete, exchange, bundle2, repair, lock as lockmod
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # label constants
43 # label constants
44 # until 3.5, bookmarks.current was the advertised name, not
44 # until 3.5, bookmarks.current was the advertised name, not
45 # bookmarks.active, so we must use both to avoid breaking old
45 # bookmarks.active, so we must use both to avoid breaking old
46 # custom styles
46 # custom styles
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
47 activebookmarklabel = 'bookmarks.active bookmarks.current'
48
48
49 # common command options
49 # common command options
50
50
51 globalopts = [
51 globalopts = [
52 ('R', 'repository', '',
52 ('R', 'repository', '',
53 _('repository root directory or name of overlay bundle file'),
53 _('repository root directory or name of overlay bundle file'),
54 _('REPO')),
54 _('REPO')),
55 ('', 'cwd', '',
55 ('', 'cwd', '',
56 _('change working directory'), _('DIR')),
56 _('change working directory'), _('DIR')),
57 ('y', 'noninteractive', None,
57 ('y', 'noninteractive', None,
58 _('do not prompt, automatically pick the first choice for all prompts')),
58 _('do not prompt, automatically pick the first choice for all prompts')),
59 ('q', 'quiet', None, _('suppress output')),
59 ('q', 'quiet', None, _('suppress output')),
60 ('v', 'verbose', None, _('enable additional output')),
60 ('v', 'verbose', None, _('enable additional output')),
61 ('', 'config', [],
61 ('', 'config', [],
62 _('set/override config option (use \'section.name=value\')'),
62 _('set/override config option (use \'section.name=value\')'),
63 _('CONFIG')),
63 _('CONFIG')),
64 ('', 'debug', None, _('enable debugging output')),
64 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debugger', None, _('start debugger')),
65 ('', 'debugger', None, _('start debugger')),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
66 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 _('ENCODE')),
67 _('ENCODE')),
68 ('', 'encodingmode', encoding.encodingmode,
68 ('', 'encodingmode', encoding.encodingmode,
69 _('set the charset encoding mode'), _('MODE')),
69 _('set the charset encoding mode'), _('MODE')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
70 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'time', None, _('time how long the command takes')),
71 ('', 'time', None, _('time how long the command takes')),
72 ('', 'profile', None, _('print command execution profile')),
72 ('', 'profile', None, _('print command execution profile')),
73 ('', 'version', None, _('output version information and exit')),
73 ('', 'version', None, _('output version information and exit')),
74 ('h', 'help', None, _('display help and exit')),
74 ('h', 'help', None, _('display help and exit')),
75 ('', 'hidden', False, _('consider hidden changesets')),
75 ('', 'hidden', False, _('consider hidden changesets')),
76 ]
76 ]
77
77
78 dryrunopts = [('n', 'dry-run', None,
78 dryrunopts = [('n', 'dry-run', None,
79 _('do not perform actions, just print output'))]
79 _('do not perform actions, just print output'))]
80
80
81 remoteopts = [
81 remoteopts = [
82 ('e', 'ssh', '',
82 ('e', 'ssh', '',
83 _('specify ssh command to use'), _('CMD')),
83 _('specify ssh command to use'), _('CMD')),
84 ('', 'remotecmd', '',
84 ('', 'remotecmd', '',
85 _('specify hg command to run on the remote side'), _('CMD')),
85 _('specify hg command to run on the remote side'), _('CMD')),
86 ('', 'insecure', None,
86 ('', 'insecure', None,
87 _('do not verify server certificate (ignoring web.cacerts config)')),
87 _('do not verify server certificate (ignoring web.cacerts config)')),
88 ]
88 ]
89
89
90 walkopts = [
90 walkopts = [
91 ('I', 'include', [],
91 ('I', 'include', [],
92 _('include names matching the given patterns'), _('PATTERN')),
92 _('include names matching the given patterns'), _('PATTERN')),
93 ('X', 'exclude', [],
93 ('X', 'exclude', [],
94 _('exclude names matching the given patterns'), _('PATTERN')),
94 _('exclude names matching the given patterns'), _('PATTERN')),
95 ]
95 ]
96
96
97 commitopts = [
97 commitopts = [
98 ('m', 'message', '',
98 ('m', 'message', '',
99 _('use text as commit message'), _('TEXT')),
99 _('use text as commit message'), _('TEXT')),
100 ('l', 'logfile', '',
100 ('l', 'logfile', '',
101 _('read commit message from file'), _('FILE')),
101 _('read commit message from file'), _('FILE')),
102 ]
102 ]
103
103
104 commitopts2 = [
104 commitopts2 = [
105 ('d', 'date', '',
105 ('d', 'date', '',
106 _('record the specified date as commit date'), _('DATE')),
106 _('record the specified date as commit date'), _('DATE')),
107 ('u', 'user', '',
107 ('u', 'user', '',
108 _('record the specified user as committer'), _('USER')),
108 _('record the specified user as committer'), _('USER')),
109 ]
109 ]
110
110
111 # hidden for now
111 # hidden for now
112 formatteropts = [
112 formatteropts = [
113 ('T', 'template', '',
113 ('T', 'template', '',
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
114 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 ]
115 ]
116
116
117 templateopts = [
117 templateopts = [
118 ('', 'style', '',
118 ('', 'style', '',
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
119 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 ('T', 'template', '',
120 ('T', 'template', '',
121 _('display with template'), _('TEMPLATE')),
121 _('display with template'), _('TEMPLATE')),
122 ]
122 ]
123
123
124 logopts = [
124 logopts = [
125 ('p', 'patch', None, _('show patch')),
125 ('p', 'patch', None, _('show patch')),
126 ('g', 'git', None, _('use git extended diff format')),
126 ('g', 'git', None, _('use git extended diff format')),
127 ('l', 'limit', '',
127 ('l', 'limit', '',
128 _('limit number of changes displayed'), _('NUM')),
128 _('limit number of changes displayed'), _('NUM')),
129 ('M', 'no-merges', None, _('do not show merges')),
129 ('M', 'no-merges', None, _('do not show merges')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
130 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('G', 'graph', None, _("show the revision DAG")),
131 ('G', 'graph', None, _("show the revision DAG")),
132 ] + templateopts
132 ] + templateopts
133
133
134 diffopts = [
134 diffopts = [
135 ('a', 'text', None, _('treat all files as text')),
135 ('a', 'text', None, _('treat all files as text')),
136 ('g', 'git', None, _('use git extended diff format')),
136 ('g', 'git', None, _('use git extended diff format')),
137 ('', 'nodates', None, _('omit dates from diff headers'))
137 ('', 'nodates', None, _('omit dates from diff headers'))
138 ]
138 ]
139
139
140 diffwsopts = [
140 diffwsopts = [
141 ('w', 'ignore-all-space', None,
141 ('w', 'ignore-all-space', None,
142 _('ignore white space when comparing lines')),
142 _('ignore white space when comparing lines')),
143 ('b', 'ignore-space-change', None,
143 ('b', 'ignore-space-change', None,
144 _('ignore changes in the amount of white space')),
144 _('ignore changes in the amount of white space')),
145 ('B', 'ignore-blank-lines', None,
145 ('B', 'ignore-blank-lines', None,
146 _('ignore changes whose lines are all blank')),
146 _('ignore changes whose lines are all blank')),
147 ]
147 ]
148
148
149 diffopts2 = [
149 diffopts2 = [
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
150 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('p', 'show-function', None, _('show which function each change is in')),
151 ('p', 'show-function', None, _('show which function each change is in')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
152 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ] + diffwsopts + [
153 ] + diffwsopts + [
154 ('U', 'unified', '',
154 ('U', 'unified', '',
155 _('number of lines of context to show'), _('NUM')),
155 _('number of lines of context to show'), _('NUM')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
156 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
157 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ]
158 ]
159
159
160 mergetoolopts = [
160 mergetoolopts = [
161 ('t', 'tool', '', _('specify merge tool')),
161 ('t', 'tool', '', _('specify merge tool')),
162 ]
162 ]
163
163
164 similarityopts = [
164 similarityopts = [
165 ('s', 'similarity', '',
165 ('s', 'similarity', '',
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
166 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 ]
167 ]
168
168
169 subrepoopts = [
169 subrepoopts = [
170 ('S', 'subrepos', None,
170 ('S', 'subrepos', None,
171 _('recurse into subrepositories'))
171 _('recurse into subrepositories'))
172 ]
172 ]
173
173
174 # Commands start here, listed alphabetically
174 # Commands start here, listed alphabetically
175
175
176 @command('^add',
176 @command('^add',
177 walkopts + subrepoopts + dryrunopts,
177 walkopts + subrepoopts + dryrunopts,
178 _('[OPTION]... [FILE]...'),
178 _('[OPTION]... [FILE]...'),
179 inferrepo=True)
179 inferrepo=True)
180 def add(ui, repo, *pats, **opts):
180 def add(ui, repo, *pats, **opts):
181 """add the specified files on the next commit
181 """add the specified files on the next commit
182
182
183 Schedule files to be version controlled and added to the
183 Schedule files to be version controlled and added to the
184 repository.
184 repository.
185
185
186 The files will be added to the repository at the next commit. To
186 The files will be added to the repository at the next commit. To
187 undo an add before that, see :hg:`forget`.
187 undo an add before that, see :hg:`forget`.
188
188
189 If no names are given, add all files to the repository.
189 If no names are given, add all files to the repository.
190
190
191 .. container:: verbose
191 .. container:: verbose
192
192
193 An example showing how new (unknown) files are added
193 An example showing how new (unknown) files are added
194 automatically by :hg:`add`::
194 automatically by :hg:`add`::
195
195
196 $ ls
196 $ ls
197 foo.c
197 foo.c
198 $ hg status
198 $ hg status
199 ? foo.c
199 ? foo.c
200 $ hg add
200 $ hg add
201 adding foo.c
201 adding foo.c
202 $ hg status
202 $ hg status
203 A foo.c
203 A foo.c
204
204
205 Returns 0 if all files are successfully added.
205 Returns 0 if all files are successfully added.
206 """
206 """
207
207
208 m = scmutil.match(repo[None], pats, opts)
208 m = scmutil.match(repo[None], pats, opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
209 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
210 return rejected and 1 or 0
210 return rejected and 1 or 0
211
211
212 @command('addremove',
212 @command('addremove',
213 similarityopts + subrepoopts + walkopts + dryrunopts,
213 similarityopts + subrepoopts + walkopts + dryrunopts,
214 _('[OPTION]... [FILE]...'),
214 _('[OPTION]... [FILE]...'),
215 inferrepo=True)
215 inferrepo=True)
216 def addremove(ui, repo, *pats, **opts):
216 def addremove(ui, repo, *pats, **opts):
217 """add all new files, delete all missing files
217 """add all new files, delete all missing files
218
218
219 Add all new files and remove all missing files from the
219 Add all new files and remove all missing files from the
220 repository.
220 repository.
221
221
222 New files are ignored if they match any of the patterns in
222 New files are ignored if they match any of the patterns in
223 ``.hgignore``. As with add, these changes take effect at the next
223 ``.hgignore``. As with add, these changes take effect at the next
224 commit.
224 commit.
225
225
226 Use the -s/--similarity option to detect renamed files. This
226 Use the -s/--similarity option to detect renamed files. This
227 option takes a percentage between 0 (disabled) and 100 (files must
227 option takes a percentage between 0 (disabled) and 100 (files must
228 be identical) as its parameter. With a parameter greater than 0,
228 be identical) as its parameter. With a parameter greater than 0,
229 this compares every removed file with every added file and records
229 this compares every removed file with every added file and records
230 those similar enough as renames. Detecting renamed files this way
230 those similar enough as renames. Detecting renamed files this way
231 can be expensive. After using this option, :hg:`status -C` can be
231 can be expensive. After using this option, :hg:`status -C` can be
232 used to check which files were identified as moved or renamed. If
232 used to check which files were identified as moved or renamed. If
233 not specified, -s/--similarity defaults to 100 and only renames of
233 not specified, -s/--similarity defaults to 100 and only renames of
234 identical files are detected.
234 identical files are detected.
235
235
236 Returns 0 if all files are successfully added.
236 Returns 0 if all files are successfully added.
237 """
237 """
238 try:
238 try:
239 sim = float(opts.get('similarity') or 100)
239 sim = float(opts.get('similarity') or 100)
240 except ValueError:
240 except ValueError:
241 raise error.Abort(_('similarity must be a number'))
241 raise error.Abort(_('similarity must be a number'))
242 if sim < 0 or sim > 100:
242 if sim < 0 or sim > 100:
243 raise error.Abort(_('similarity must be between 0 and 100'))
243 raise error.Abort(_('similarity must be between 0 and 100'))
244 matcher = scmutil.match(repo[None], pats, opts)
244 matcher = scmutil.match(repo[None], pats, opts)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
245 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
246
246
247 @command('^annotate|blame',
247 @command('^annotate|blame',
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
248 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
249 ('', 'follow', None,
249 ('', 'follow', None,
250 _('follow copies/renames and list the filename (DEPRECATED)')),
250 _('follow copies/renames and list the filename (DEPRECATED)')),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
251 ('', 'no-follow', None, _("don't follow copies and renames")),
252 ('a', 'text', None, _('treat all files as text')),
252 ('a', 'text', None, _('treat all files as text')),
253 ('u', 'user', None, _('list the author (long with -v)')),
253 ('u', 'user', None, _('list the author (long with -v)')),
254 ('f', 'file', None, _('list the filename')),
254 ('f', 'file', None, _('list the filename')),
255 ('d', 'date', None, _('list the date (short with -q)')),
255 ('d', 'date', None, _('list the date (short with -q)')),
256 ('n', 'number', None, _('list the revision number (default)')),
256 ('n', 'number', None, _('list the revision number (default)')),
257 ('c', 'changeset', None, _('list the changeset')),
257 ('c', 'changeset', None, _('list the changeset')),
258 ('l', 'line-number', None, _('show line number at the first appearance'))
258 ('l', 'line-number', None, _('show line number at the first appearance'))
259 ] + diffwsopts + walkopts + formatteropts,
259 ] + diffwsopts + walkopts + formatteropts,
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
260 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
261 inferrepo=True)
261 inferrepo=True)
262 def annotate(ui, repo, *pats, **opts):
262 def annotate(ui, repo, *pats, **opts):
263 """show changeset information by line for each file
263 """show changeset information by line for each file
264
264
265 List changes in files, showing the revision id responsible for
265 List changes in files, showing the revision id responsible for
266 each line
266 each line
267
267
268 This command is useful for discovering when a change was made and
268 This command is useful for discovering when a change was made and
269 by whom.
269 by whom.
270
270
271 Without the -a/--text option, annotate will avoid processing files
271 Without the -a/--text option, annotate will avoid processing files
272 it detects as binary. With -a, annotate will annotate the file
272 it detects as binary. With -a, annotate will annotate the file
273 anyway, although the results will probably be neither useful
273 anyway, although the results will probably be neither useful
274 nor desirable.
274 nor desirable.
275
275
276 Returns 0 on success.
276 Returns 0 on success.
277 """
277 """
278 if not pats:
278 if not pats:
279 raise error.Abort(_('at least one filename or pattern is required'))
279 raise error.Abort(_('at least one filename or pattern is required'))
280
280
281 if opts.get('follow'):
281 if opts.get('follow'):
282 # --follow is deprecated and now just an alias for -f/--file
282 # --follow is deprecated and now just an alias for -f/--file
283 # to mimic the behavior of Mercurial before version 1.5
283 # to mimic the behavior of Mercurial before version 1.5
284 opts['file'] = True
284 opts['file'] = True
285
285
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
286 ctx = scmutil.revsingle(repo, opts.get('rev'))
287
287
288 fm = ui.formatter('annotate', opts)
288 fm = ui.formatter('annotate', opts)
289 if ui.quiet:
289 if ui.quiet:
290 datefunc = util.shortdate
290 datefunc = util.shortdate
291 else:
291 else:
292 datefunc = util.datestr
292 datefunc = util.datestr
293 if ctx.rev() is None:
293 if ctx.rev() is None:
294 def hexfn(node):
294 def hexfn(node):
295 if node is None:
295 if node is None:
296 return None
296 return None
297 else:
297 else:
298 return fm.hexfunc(node)
298 return fm.hexfunc(node)
299 if opts.get('changeset'):
299 if opts.get('changeset'):
300 # omit "+" suffix which is appended to node hex
300 # omit "+" suffix which is appended to node hex
301 def formatrev(rev):
301 def formatrev(rev):
302 if rev is None:
302 if rev is None:
303 return '%d' % ctx.p1().rev()
303 return '%d' % ctx.p1().rev()
304 else:
304 else:
305 return '%d' % rev
305 return '%d' % rev
306 else:
306 else:
307 def formatrev(rev):
307 def formatrev(rev):
308 if rev is None:
308 if rev is None:
309 return '%d+' % ctx.p1().rev()
309 return '%d+' % ctx.p1().rev()
310 else:
310 else:
311 return '%d ' % rev
311 return '%d ' % rev
312 def formathex(hex):
312 def formathex(hex):
313 if hex is None:
313 if hex is None:
314 return '%s+' % fm.hexfunc(ctx.p1().node())
314 return '%s+' % fm.hexfunc(ctx.p1().node())
315 else:
315 else:
316 return '%s ' % hex
316 return '%s ' % hex
317 else:
317 else:
318 hexfn = fm.hexfunc
318 hexfn = fm.hexfunc
319 formatrev = formathex = str
319 formatrev = formathex = str
320
320
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
321 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
322 ('number', ' ', lambda x: x[0].rev(), formatrev),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
323 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
324 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
325 ('file', ' ', lambda x: x[0].path(), str),
325 ('file', ' ', lambda x: x[0].path(), str),
326 ('line_number', ':', lambda x: x[1], str),
326 ('line_number', ':', lambda x: x[1], str),
327 ]
327 ]
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
328 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
329
329
330 if (not opts.get('user') and not opts.get('changeset')
330 if (not opts.get('user') and not opts.get('changeset')
331 and not opts.get('date') and not opts.get('file')):
331 and not opts.get('date') and not opts.get('file')):
332 opts['number'] = True
332 opts['number'] = True
333
333
334 linenumber = opts.get('line_number') is not None
334 linenumber = opts.get('line_number') is not None
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
335 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
336 raise error.Abort(_('at least one of -n/-c is required for -l'))
336 raise error.Abort(_('at least one of -n/-c is required for -l'))
337
337
338 if fm:
338 if fm:
339 def makefunc(get, fmt):
339 def makefunc(get, fmt):
340 return get
340 return get
341 else:
341 else:
342 def makefunc(get, fmt):
342 def makefunc(get, fmt):
343 return lambda x: fmt(get(x))
343 return lambda x: fmt(get(x))
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
344 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
345 if opts.get(op)]
345 if opts.get(op)]
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
346 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
347 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
348 if opts.get(op))
348 if opts.get(op))
349
349
350 def bad(x, y):
350 def bad(x, y):
351 raise error.Abort("%s: %s" % (x, y))
351 raise error.Abort("%s: %s" % (x, y))
352
352
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
353 m = scmutil.match(ctx, pats, opts, badfn=bad)
354
354
355 follow = not opts.get('no_follow')
355 follow = not opts.get('no_follow')
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
356 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
357 whitespace=True)
357 whitespace=True)
358 for abs in ctx.walk(m):
358 for abs in ctx.walk(m):
359 fctx = ctx[abs]
359 fctx = ctx[abs]
360 if not opts.get('text') and util.binary(fctx.data()):
360 if not opts.get('text') and util.binary(fctx.data()):
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
361 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
362 continue
362 continue
363
363
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
364 lines = fctx.annotate(follow=follow, linenumber=linenumber,
365 diffopts=diffopts)
365 diffopts=diffopts)
366 formats = []
366 formats = []
367 pieces = []
367 pieces = []
368
368
369 for f, sep in funcmap:
369 for f, sep in funcmap:
370 l = [f(n) for n, dummy in lines]
370 l = [f(n) for n, dummy in lines]
371 if l:
371 if l:
372 if fm:
372 if fm:
373 formats.append(['%s' for x in l])
373 formats.append(['%s' for x in l])
374 else:
374 else:
375 sizes = [encoding.colwidth(x) for x in l]
375 sizes = [encoding.colwidth(x) for x in l]
376 ml = max(sizes)
376 ml = max(sizes)
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
377 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
378 pieces.append(l)
378 pieces.append(l)
379
379
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
380 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
381 fm.startitem()
381 fm.startitem()
382 fm.write(fields, "".join(f), *p)
382 fm.write(fields, "".join(f), *p)
383 fm.write('line', ": %s", l[1])
383 fm.write('line', ": %s", l[1])
384
384
385 if lines and not lines[-1][1].endswith('\n'):
385 if lines and not lines[-1][1].endswith('\n'):
386 fm.plain('\n')
386 fm.plain('\n')
387
387
388 fm.end()
388 fm.end()
389
389
390 @command('archive',
390 @command('archive',
391 [('', 'no-decode', None, _('do not pass files through decoders')),
391 [('', 'no-decode', None, _('do not pass files through decoders')),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
392 ('p', 'prefix', '', _('directory prefix for files in archive'),
393 _('PREFIX')),
393 _('PREFIX')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
394 ('r', 'rev', '', _('revision to distribute'), _('REV')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
395 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
396 ] + subrepoopts + walkopts,
396 ] + subrepoopts + walkopts,
397 _('[OPTION]... DEST'))
397 _('[OPTION]... DEST'))
398 def archive(ui, repo, dest, **opts):
398 def archive(ui, repo, dest, **opts):
399 '''create an unversioned archive of a repository revision
399 '''create an unversioned archive of a repository revision
400
400
401 By default, the revision used is the parent of the working
401 By default, the revision used is the parent of the working
402 directory; use -r/--rev to specify a different revision.
402 directory; use -r/--rev to specify a different revision.
403
403
404 The archive type is automatically detected based on file
404 The archive type is automatically detected based on file
405 extension (or override using -t/--type).
405 extension (or override using -t/--type).
406
406
407 .. container:: verbose
407 .. container:: verbose
408
408
409 Examples:
409 Examples:
410
410
411 - create a zip file containing the 1.0 release::
411 - create a zip file containing the 1.0 release::
412
412
413 hg archive -r 1.0 project-1.0.zip
413 hg archive -r 1.0 project-1.0.zip
414
414
415 - create a tarball excluding .hg files::
415 - create a tarball excluding .hg files::
416
416
417 hg archive project.tar.gz -X ".hg*"
417 hg archive project.tar.gz -X ".hg*"
418
418
419 Valid types are:
419 Valid types are:
420
420
421 :``files``: a directory full of files (default)
421 :``files``: a directory full of files (default)
422 :``tar``: tar archive, uncompressed
422 :``tar``: tar archive, uncompressed
423 :``tbz2``: tar archive, compressed using bzip2
423 :``tbz2``: tar archive, compressed using bzip2
424 :``tgz``: tar archive, compressed using gzip
424 :``tgz``: tar archive, compressed using gzip
425 :``uzip``: zip archive, uncompressed
425 :``uzip``: zip archive, uncompressed
426 :``zip``: zip archive, compressed using deflate
426 :``zip``: zip archive, compressed using deflate
427
427
428 The exact name of the destination archive or directory is given
428 The exact name of the destination archive or directory is given
429 using a format string; see :hg:`help export` for details.
429 using a format string; see :hg:`help export` for details.
430
430
431 Each member added to an archive file has a directory prefix
431 Each member added to an archive file has a directory prefix
432 prepended. Use -p/--prefix to specify a format string for the
432 prepended. Use -p/--prefix to specify a format string for the
433 prefix. The default is the basename of the archive, with suffixes
433 prefix. The default is the basename of the archive, with suffixes
434 removed.
434 removed.
435
435
436 Returns 0 on success.
436 Returns 0 on success.
437 '''
437 '''
438
438
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
439 ctx = scmutil.revsingle(repo, opts.get('rev'))
440 if not ctx:
440 if not ctx:
441 raise error.Abort(_('no working directory: please specify a revision'))
441 raise error.Abort(_('no working directory: please specify a revision'))
442 node = ctx.node()
442 node = ctx.node()
443 dest = cmdutil.makefilename(repo, dest, node)
443 dest = cmdutil.makefilename(repo, dest, node)
444 if os.path.realpath(dest) == repo.root:
444 if os.path.realpath(dest) == repo.root:
445 raise error.Abort(_('repository root cannot be destination'))
445 raise error.Abort(_('repository root cannot be destination'))
446
446
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
447 kind = opts.get('type') or archival.guesskind(dest) or 'files'
448 prefix = opts.get('prefix')
448 prefix = opts.get('prefix')
449
449
450 if dest == '-':
450 if dest == '-':
451 if kind == 'files':
451 if kind == 'files':
452 raise error.Abort(_('cannot archive plain files to stdout'))
452 raise error.Abort(_('cannot archive plain files to stdout'))
453 dest = cmdutil.makefileobj(repo, dest)
453 dest = cmdutil.makefileobj(repo, dest)
454 if not prefix:
454 if not prefix:
455 prefix = os.path.basename(repo.root) + '-%h'
455 prefix = os.path.basename(repo.root) + '-%h'
456
456
457 prefix = cmdutil.makefilename(repo, prefix, node)
457 prefix = cmdutil.makefilename(repo, prefix, node)
458 matchfn = scmutil.match(ctx, [], opts)
458 matchfn = scmutil.match(ctx, [], opts)
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
459 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
460 matchfn, prefix, subrepos=opts.get('subrepos'))
460 matchfn, prefix, subrepos=opts.get('subrepos'))
461
461
462 @command('backout',
462 @command('backout',
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
463 [('', 'merge', None, _('merge with old dirstate parent after backout')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
464 ('', 'commit', None, _('commit if no conflicts were encountered')),
465 ('', 'parent', '',
465 ('', 'parent', '',
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
466 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
467 ('r', 'rev', '', _('revision to backout'), _('REV')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
468 ('e', 'edit', False, _('invoke editor on commit messages')),
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
469 ] + mergetoolopts + walkopts + commitopts + commitopts2,
470 _('[OPTION]... [-r] REV'))
470 _('[OPTION]... [-r] REV'))
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
471 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
472 '''reverse effect of earlier changeset
472 '''reverse effect of earlier changeset
473
473
474 Prepare a new changeset with the effect of REV undone in the
474 Prepare a new changeset with the effect of REV undone in the
475 current working directory.
475 current working directory.
476
476
477 If REV is the parent of the working directory, then this new changeset
477 If REV is the parent of the working directory, then this new changeset
478 is committed automatically. Otherwise, hg needs to merge the
478 is committed automatically. Otherwise, hg needs to merge the
479 changes and the merged result is left uncommitted.
479 changes and the merged result is left uncommitted.
480
480
481 .. note::
481 .. note::
482
482
483 backout cannot be used to fix either an unwanted or
483 backout cannot be used to fix either an unwanted or
484 incorrect merge.
484 incorrect merge.
485
485
486 .. container:: verbose
486 .. container:: verbose
487
487
488 By default, the pending changeset will have one parent,
488 By default, the pending changeset will have one parent,
489 maintaining a linear history. With --merge, the pending
489 maintaining a linear history. With --merge, the pending
490 changeset will instead have two parents: the old parent of the
490 changeset will instead have two parents: the old parent of the
491 working directory and a new child of REV that simply undoes REV.
491 working directory and a new child of REV that simply undoes REV.
492
492
493 Before version 1.7, the behavior without --merge was equivalent
493 Before version 1.7, the behavior without --merge was equivalent
494 to specifying --merge followed by :hg:`update --clean .` to
494 to specifying --merge followed by :hg:`update --clean .` to
495 cancel the merge and leave the child of REV as a head to be
495 cancel the merge and leave the child of REV as a head to be
496 merged separately.
496 merged separately.
497
497
498 See :hg:`help dates` for a list of formats valid for -d/--date.
498 See :hg:`help dates` for a list of formats valid for -d/--date.
499
499
500 See :hg:`help revert` for a way to restore files to the state
500 See :hg:`help revert` for a way to restore files to the state
501 of another revision.
501 of another revision.
502
502
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
503 Returns 0 on success, 1 if nothing to backout or there are unresolved
504 files.
504 files.
505 '''
505 '''
506 if rev and node:
506 if rev and node:
507 raise error.Abort(_("please specify just one revision"))
507 raise error.Abort(_("please specify just one revision"))
508
508
509 if not rev:
509 if not rev:
510 rev = node
510 rev = node
511
511
512 if not rev:
512 if not rev:
513 raise error.Abort(_("please specify a revision to backout"))
513 raise error.Abort(_("please specify a revision to backout"))
514
514
515 date = opts.get('date')
515 date = opts.get('date')
516 if date:
516 if date:
517 opts['date'] = util.parsedate(date)
517 opts['date'] = util.parsedate(date)
518
518
519 cmdutil.checkunfinished(repo)
519 cmdutil.checkunfinished(repo)
520 cmdutil.bailifchanged(repo)
520 cmdutil.bailifchanged(repo)
521 node = scmutil.revsingle(repo, rev).node()
521 node = scmutil.revsingle(repo, rev).node()
522
522
523 op1, op2 = repo.dirstate.parents()
523 op1, op2 = repo.dirstate.parents()
524 if not repo.changelog.isancestor(node, op1):
524 if not repo.changelog.isancestor(node, op1):
525 raise error.Abort(_('cannot backout change that is not an ancestor'))
525 raise error.Abort(_('cannot backout change that is not an ancestor'))
526
526
527 p1, p2 = repo.changelog.parents(node)
527 p1, p2 = repo.changelog.parents(node)
528 if p1 == nullid:
528 if p1 == nullid:
529 raise error.Abort(_('cannot backout a change with no parents'))
529 raise error.Abort(_('cannot backout a change with no parents'))
530 if p2 != nullid:
530 if p2 != nullid:
531 if not opts.get('parent'):
531 if not opts.get('parent'):
532 raise error.Abort(_('cannot backout a merge changeset'))
532 raise error.Abort(_('cannot backout a merge changeset'))
533 p = repo.lookup(opts['parent'])
533 p = repo.lookup(opts['parent'])
534 if p not in (p1, p2):
534 if p not in (p1, p2):
535 raise error.Abort(_('%s is not a parent of %s') %
535 raise error.Abort(_('%s is not a parent of %s') %
536 (short(p), short(node)))
536 (short(p), short(node)))
537 parent = p
537 parent = p
538 else:
538 else:
539 if opts.get('parent'):
539 if opts.get('parent'):
540 raise error.Abort(_('cannot use --parent on non-merge changeset'))
540 raise error.Abort(_('cannot use --parent on non-merge changeset'))
541 parent = p1
541 parent = p1
542
542
543 # the backout should appear on the same branch
543 # the backout should appear on the same branch
544 wlock = repo.wlock()
544 wlock = repo.wlock()
545 try:
545 try:
546 branch = repo.dirstate.branch()
546 branch = repo.dirstate.branch()
547 bheads = repo.branchheads(branch)
547 bheads = repo.branchheads(branch)
548 rctx = scmutil.revsingle(repo, hex(parent))
548 rctx = scmutil.revsingle(repo, hex(parent))
549 if not opts.get('merge') and op1 != node:
549 if not opts.get('merge') and op1 != node:
550 dsguard = cmdutil.dirstateguard(repo, 'backout')
550 dsguard = cmdutil.dirstateguard(repo, 'backout')
551 try:
551 try:
552 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
552 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
553 'backout')
553 'backout')
554 stats = mergemod.update(repo, parent, True, True, False,
554 stats = mergemod.update(repo, parent, True, True, False,
555 node, False)
555 node, False)
556 repo.setparents(op1, op2)
556 repo.setparents(op1, op2)
557 dsguard.close()
557 dsguard.close()
558 hg._showstats(repo, stats)
558 hg._showstats(repo, stats)
559 if stats[3]:
559 if stats[3]:
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
560 repo.ui.status(_("use 'hg resolve' to retry unresolved "
561 "file merges\n"))
561 "file merges\n"))
562 return 1
562 return 1
563 elif not commit:
563 elif not commit:
564 msg = _("changeset %s backed out, "
564 msg = _("changeset %s backed out, "
565 "don't forget to commit.\n")
565 "don't forget to commit.\n")
566 ui.status(msg % short(node))
566 ui.status(msg % short(node))
567 return 0
567 return 0
568 finally:
568 finally:
569 ui.setconfig('ui', 'forcemerge', '', '')
569 ui.setconfig('ui', 'forcemerge', '', '')
570 lockmod.release(dsguard)
570 lockmod.release(dsguard)
571 else:
571 else:
572 hg.clean(repo, node, show_stats=False)
572 hg.clean(repo, node, show_stats=False)
573 repo.dirstate.setbranch(branch)
573 repo.dirstate.setbranch(branch)
574 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
574 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
575
575
576
576
577 def commitfunc(ui, repo, message, match, opts):
577 def commitfunc(ui, repo, message, match, opts):
578 editform = 'backout'
578 editform = 'backout'
579 e = cmdutil.getcommiteditor(editform=editform, **opts)
579 e = cmdutil.getcommiteditor(editform=editform, **opts)
580 if not message:
580 if not message:
581 # we don't translate commit messages
581 # we don't translate commit messages
582 message = "Backed out changeset %s" % short(node)
582 message = "Backed out changeset %s" % short(node)
583 e = cmdutil.getcommiteditor(edit=True, editform=editform)
583 e = cmdutil.getcommiteditor(edit=True, editform=editform)
584 return repo.commit(message, opts.get('user'), opts.get('date'),
584 return repo.commit(message, opts.get('user'), opts.get('date'),
585 match, editor=e)
585 match, editor=e)
586 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
586 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
587 if not newnode:
587 if not newnode:
588 ui.status(_("nothing changed\n"))
588 ui.status(_("nothing changed\n"))
589 return 1
589 return 1
590 cmdutil.commitstatus(repo, newnode, branch, bheads)
590 cmdutil.commitstatus(repo, newnode, branch, bheads)
591
591
592 def nice(node):
592 def nice(node):
593 return '%d:%s' % (repo.changelog.rev(node), short(node))
593 return '%d:%s' % (repo.changelog.rev(node), short(node))
594 ui.status(_('changeset %s backs out changeset %s\n') %
594 ui.status(_('changeset %s backs out changeset %s\n') %
595 (nice(repo.changelog.tip()), nice(node)))
595 (nice(repo.changelog.tip()), nice(node)))
596 if opts.get('merge') and op1 != node:
596 if opts.get('merge') and op1 != node:
597 hg.clean(repo, op1, show_stats=False)
597 hg.clean(repo, op1, show_stats=False)
598 ui.status(_('merging with changeset %s\n')
598 ui.status(_('merging with changeset %s\n')
599 % nice(repo.changelog.tip()))
599 % nice(repo.changelog.tip()))
600 try:
600 try:
601 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
601 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
602 'backout')
602 'backout')
603 return hg.merge(repo, hex(repo.changelog.tip()))
603 return hg.merge(repo, hex(repo.changelog.tip()))
604 finally:
604 finally:
605 ui.setconfig('ui', 'forcemerge', '', '')
605 ui.setconfig('ui', 'forcemerge', '', '')
606 finally:
606 finally:
607 wlock.release()
607 wlock.release()
608 return 0
608 return 0
609
609
610 @command('bisect',
610 @command('bisect',
611 [('r', 'reset', False, _('reset bisect state')),
611 [('r', 'reset', False, _('reset bisect state')),
612 ('g', 'good', False, _('mark changeset good')),
612 ('g', 'good', False, _('mark changeset good')),
613 ('b', 'bad', False, _('mark changeset bad')),
613 ('b', 'bad', False, _('mark changeset bad')),
614 ('s', 'skip', False, _('skip testing changeset')),
614 ('s', 'skip', False, _('skip testing changeset')),
615 ('e', 'extend', False, _('extend the bisect range')),
615 ('e', 'extend', False, _('extend the bisect range')),
616 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
616 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
617 ('U', 'noupdate', False, _('do not update to target'))],
617 ('U', 'noupdate', False, _('do not update to target'))],
618 _("[-gbsr] [-U] [-c CMD] [REV]"))
618 _("[-gbsr] [-U] [-c CMD] [REV]"))
619 def bisect(ui, repo, rev=None, extra=None, command=None,
619 def bisect(ui, repo, rev=None, extra=None, command=None,
620 reset=None, good=None, bad=None, skip=None, extend=None,
620 reset=None, good=None, bad=None, skip=None, extend=None,
621 noupdate=None):
621 noupdate=None):
622 """subdivision search of changesets
622 """subdivision search of changesets
623
623
624 This command helps to find changesets which introduce problems. To
624 This command helps to find changesets which introduce problems. To
625 use, mark the earliest changeset you know exhibits the problem as
625 use, mark the earliest changeset you know exhibits the problem as
626 bad, then mark the latest changeset which is free from the problem
626 bad, then mark the latest changeset which is free from the problem
627 as good. Bisect will update your working directory to a revision
627 as good. Bisect will update your working directory to a revision
628 for testing (unless the -U/--noupdate option is specified). Once
628 for testing (unless the -U/--noupdate option is specified). Once
629 you have performed tests, mark the working directory as good or
629 you have performed tests, mark the working directory as good or
630 bad, and bisect will either update to another candidate changeset
630 bad, and bisect will either update to another candidate changeset
631 or announce that it has found the bad revision.
631 or announce that it has found the bad revision.
632
632
633 As a shortcut, you can also use the revision argument to mark a
633 As a shortcut, you can also use the revision argument to mark a
634 revision as good or bad without checking it out first.
634 revision as good or bad without checking it out first.
635
635
636 If you supply a command, it will be used for automatic bisection.
636 If you supply a command, it will be used for automatic bisection.
637 The environment variable HG_NODE will contain the ID of the
637 The environment variable HG_NODE will contain the ID of the
638 changeset being tested. The exit status of the command will be
638 changeset being tested. The exit status of the command will be
639 used to mark revisions as good or bad: status 0 means good, 125
639 used to mark revisions as good or bad: status 0 means good, 125
640 means to skip the revision, 127 (command not found) will abort the
640 means to skip the revision, 127 (command not found) will abort the
641 bisection, and any other non-zero exit status means the revision
641 bisection, and any other non-zero exit status means the revision
642 is bad.
642 is bad.
643
643
644 .. container:: verbose
644 .. container:: verbose
645
645
646 Some examples:
646 Some examples:
647
647
648 - start a bisection with known bad revision 34, and good revision 12::
648 - start a bisection with known bad revision 34, and good revision 12::
649
649
650 hg bisect --bad 34
650 hg bisect --bad 34
651 hg bisect --good 12
651 hg bisect --good 12
652
652
653 - advance the current bisection by marking current revision as good or
653 - advance the current bisection by marking current revision as good or
654 bad::
654 bad::
655
655
656 hg bisect --good
656 hg bisect --good
657 hg bisect --bad
657 hg bisect --bad
658
658
659 - mark the current revision, or a known revision, to be skipped (e.g. if
659 - mark the current revision, or a known revision, to be skipped (e.g. if
660 that revision is not usable because of another issue)::
660 that revision is not usable because of another issue)::
661
661
662 hg bisect --skip
662 hg bisect --skip
663 hg bisect --skip 23
663 hg bisect --skip 23
664
664
665 - skip all revisions that do not touch directories ``foo`` or ``bar``::
665 - skip all revisions that do not touch directories ``foo`` or ``bar``::
666
666
667 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
667 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
668
668
669 - forget the current bisection::
669 - forget the current bisection::
670
670
671 hg bisect --reset
671 hg bisect --reset
672
672
673 - use 'make && make tests' to automatically find the first broken
673 - use 'make && make tests' to automatically find the first broken
674 revision::
674 revision::
675
675
676 hg bisect --reset
676 hg bisect --reset
677 hg bisect --bad 34
677 hg bisect --bad 34
678 hg bisect --good 12
678 hg bisect --good 12
679 hg bisect --command "make && make tests"
679 hg bisect --command "make && make tests"
680
680
681 - see all changesets whose states are already known in the current
681 - see all changesets whose states are already known in the current
682 bisection::
682 bisection::
683
683
684 hg log -r "bisect(pruned)"
684 hg log -r "bisect(pruned)"
685
685
686 - see the changeset currently being bisected (especially useful
686 - see the changeset currently being bisected (especially useful
687 if running with -U/--noupdate)::
687 if running with -U/--noupdate)::
688
688
689 hg log -r "bisect(current)"
689 hg log -r "bisect(current)"
690
690
691 - see all changesets that took part in the current bisection::
691 - see all changesets that took part in the current bisection::
692
692
693 hg log -r "bisect(range)"
693 hg log -r "bisect(range)"
694
694
695 - you can even get a nice graph::
695 - you can even get a nice graph::
696
696
697 hg log --graph -r "bisect(range)"
697 hg log --graph -r "bisect(range)"
698
698
699 See :hg:`help revsets` for more about the `bisect()` keyword.
699 See :hg:`help revsets` for more about the `bisect()` keyword.
700
700
701 Returns 0 on success.
701 Returns 0 on success.
702 """
702 """
703 def extendbisectrange(nodes, good):
703 def extendbisectrange(nodes, good):
704 # bisect is incomplete when it ends on a merge node and
704 # bisect is incomplete when it ends on a merge node and
705 # one of the parent was not checked.
705 # one of the parent was not checked.
706 parents = repo[nodes[0]].parents()
706 parents = repo[nodes[0]].parents()
707 if len(parents) > 1:
707 if len(parents) > 1:
708 if good:
708 if good:
709 side = state['bad']
709 side = state['bad']
710 else:
710 else:
711 side = state['good']
711 side = state['good']
712 num = len(set(i.node() for i in parents) & set(side))
712 num = len(set(i.node() for i in parents) & set(side))
713 if num == 1:
713 if num == 1:
714 return parents[0].ancestor(parents[1])
714 return parents[0].ancestor(parents[1])
715 return None
715 return None
716
716
717 def print_result(nodes, good):
717 def print_result(nodes, good):
718 displayer = cmdutil.show_changeset(ui, repo, {})
718 displayer = cmdutil.show_changeset(ui, repo, {})
719 if len(nodes) == 1:
719 if len(nodes) == 1:
720 # narrowed it down to a single revision
720 # narrowed it down to a single revision
721 if good:
721 if good:
722 ui.write(_("The first good revision is:\n"))
722 ui.write(_("The first good revision is:\n"))
723 else:
723 else:
724 ui.write(_("The first bad revision is:\n"))
724 ui.write(_("The first bad revision is:\n"))
725 displayer.show(repo[nodes[0]])
725 displayer.show(repo[nodes[0]])
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_('Not all ancestors of this changeset have been'
728 ui.write(_('Not all ancestors of this changeset have been'
729 ' checked.\nUse bisect --extend to continue the '
729 ' checked.\nUse bisect --extend to continue the '
730 'bisection from\nthe common ancestor, %s.\n')
730 'bisection from\nthe common ancestor, %s.\n')
731 % extendnode)
731 % extendnode)
732 else:
732 else:
733 # multiple possible revisions
733 # multiple possible revisions
734 if good:
734 if good:
735 ui.write(_("Due to skipped revisions, the first "
735 ui.write(_("Due to skipped revisions, the first "
736 "good revision could be any of:\n"))
736 "good revision could be any of:\n"))
737 else:
737 else:
738 ui.write(_("Due to skipped revisions, the first "
738 ui.write(_("Due to skipped revisions, the first "
739 "bad revision could be any of:\n"))
739 "bad revision could be any of:\n"))
740 for n in nodes:
740 for n in nodes:
741 displayer.show(repo[n])
741 displayer.show(repo[n])
742 displayer.close()
742 displayer.close()
743
743
744 def check_state(state, interactive=True):
744 def check_state(state, interactive=True):
745 if not state['good'] or not state['bad']:
745 if not state['good'] or not state['bad']:
746 if (good or bad or skip or reset) and interactive:
746 if (good or bad or skip or reset) and interactive:
747 return
747 return
748 if not state['good']:
748 if not state['good']:
749 raise error.Abort(_('cannot bisect (no known good revisions)'))
749 raise error.Abort(_('cannot bisect (no known good revisions)'))
750 else:
750 else:
751 raise error.Abort(_('cannot bisect (no known bad revisions)'))
751 raise error.Abort(_('cannot bisect (no known bad revisions)'))
752 return True
752 return True
753
753
754 # backward compatibility
754 # backward compatibility
755 if rev in "good bad reset init".split():
755 if rev in "good bad reset init".split():
756 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
756 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
757 cmd, rev, extra = rev, extra, None
757 cmd, rev, extra = rev, extra, None
758 if cmd == "good":
758 if cmd == "good":
759 good = True
759 good = True
760 elif cmd == "bad":
760 elif cmd == "bad":
761 bad = True
761 bad = True
762 else:
762 else:
763 reset = True
763 reset = True
764 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
764 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
765 raise error.Abort(_('incompatible arguments'))
765 raise error.Abort(_('incompatible arguments'))
766
766
767 cmdutil.checkunfinished(repo)
767 cmdutil.checkunfinished(repo)
768
768
769 if reset:
769 if reset:
770 p = repo.join("bisect.state")
770 p = repo.join("bisect.state")
771 if os.path.exists(p):
771 if os.path.exists(p):
772 os.unlink(p)
772 os.unlink(p)
773 return
773 return
774
774
775 state = hbisect.load_state(repo)
775 state = hbisect.load_state(repo)
776
776
777 if command:
777 if command:
778 changesets = 1
778 changesets = 1
779 if noupdate:
779 if noupdate:
780 try:
780 try:
781 node = state['current'][0]
781 node = state['current'][0]
782 except LookupError:
782 except LookupError:
783 raise error.Abort(_('current bisect revision is unknown - '
783 raise error.Abort(_('current bisect revision is unknown - '
784 'start a new bisect to fix'))
784 'start a new bisect to fix'))
785 else:
785 else:
786 node, p2 = repo.dirstate.parents()
786 node, p2 = repo.dirstate.parents()
787 if p2 != nullid:
787 if p2 != nullid:
788 raise error.Abort(_('current bisect revision is a merge'))
788 raise error.Abort(_('current bisect revision is a merge'))
789 try:
789 try:
790 while changesets:
790 while changesets:
791 # update state
791 # update state
792 state['current'] = [node]
792 state['current'] = [node]
793 hbisect.save_state(repo, state)
793 hbisect.save_state(repo, state)
794 status = ui.system(command, environ={'HG_NODE': hex(node)})
794 status = ui.system(command, environ={'HG_NODE': hex(node)})
795 if status == 125:
795 if status == 125:
796 transition = "skip"
796 transition = "skip"
797 elif status == 0:
797 elif status == 0:
798 transition = "good"
798 transition = "good"
799 # status < 0 means process was killed
799 # status < 0 means process was killed
800 elif status == 127:
800 elif status == 127:
801 raise error.Abort(_("failed to execute %s") % command)
801 raise error.Abort(_("failed to execute %s") % command)
802 elif status < 0:
802 elif status < 0:
803 raise error.Abort(_("%s killed") % command)
803 raise error.Abort(_("%s killed") % command)
804 else:
804 else:
805 transition = "bad"
805 transition = "bad"
806 ctx = scmutil.revsingle(repo, rev, node)
806 ctx = scmutil.revsingle(repo, rev, node)
807 rev = None # clear for future iterations
807 rev = None # clear for future iterations
808 state[transition].append(ctx.node())
808 state[transition].append(ctx.node())
809 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
809 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
810 check_state(state, interactive=False)
810 check_state(state, interactive=False)
811 # bisect
811 # bisect
812 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
812 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
813 # update to next check
813 # update to next check
814 node = nodes[0]
814 node = nodes[0]
815 if not noupdate:
815 if not noupdate:
816 cmdutil.bailifchanged(repo)
816 cmdutil.bailifchanged(repo)
817 hg.clean(repo, node, show_stats=False)
817 hg.clean(repo, node, show_stats=False)
818 finally:
818 finally:
819 state['current'] = [node]
819 state['current'] = [node]
820 hbisect.save_state(repo, state)
820 hbisect.save_state(repo, state)
821 print_result(nodes, bgood)
821 print_result(nodes, bgood)
822 return
822 return
823
823
824 # update state
824 # update state
825
825
826 if rev:
826 if rev:
827 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
827 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
828 else:
828 else:
829 nodes = [repo.lookup('.')]
829 nodes = [repo.lookup('.')]
830
830
831 if good or bad or skip:
831 if good or bad or skip:
832 if good:
832 if good:
833 state['good'] += nodes
833 state['good'] += nodes
834 elif bad:
834 elif bad:
835 state['bad'] += nodes
835 state['bad'] += nodes
836 elif skip:
836 elif skip:
837 state['skip'] += nodes
837 state['skip'] += nodes
838 hbisect.save_state(repo, state)
838 hbisect.save_state(repo, state)
839
839
840 if not check_state(state):
840 if not check_state(state):
841 return
841 return
842
842
843 # actually bisect
843 # actually bisect
844 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
844 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
845 if extend:
845 if extend:
846 if not changesets:
846 if not changesets:
847 extendnode = extendbisectrange(nodes, good)
847 extendnode = extendbisectrange(nodes, good)
848 if extendnode is not None:
848 if extendnode is not None:
849 ui.write(_("Extending search to changeset %d:%s\n")
849 ui.write(_("Extending search to changeset %d:%s\n")
850 % (extendnode.rev(), extendnode))
850 % (extendnode.rev(), extendnode))
851 state['current'] = [extendnode.node()]
851 state['current'] = [extendnode.node()]
852 hbisect.save_state(repo, state)
852 hbisect.save_state(repo, state)
853 if noupdate:
853 if noupdate:
854 return
854 return
855 cmdutil.bailifchanged(repo)
855 cmdutil.bailifchanged(repo)
856 return hg.clean(repo, extendnode.node())
856 return hg.clean(repo, extendnode.node())
857 raise error.Abort(_("nothing to extend"))
857 raise error.Abort(_("nothing to extend"))
858
858
859 if changesets == 0:
859 if changesets == 0:
860 print_result(nodes, good)
860 print_result(nodes, good)
861 else:
861 else:
862 assert len(nodes) == 1 # only a single node can be tested next
862 assert len(nodes) == 1 # only a single node can be tested next
863 node = nodes[0]
863 node = nodes[0]
864 # compute the approximate number of remaining tests
864 # compute the approximate number of remaining tests
865 tests, size = 0, 2
865 tests, size = 0, 2
866 while size <= changesets:
866 while size <= changesets:
867 tests, size = tests + 1, size * 2
867 tests, size = tests + 1, size * 2
868 rev = repo.changelog.rev(node)
868 rev = repo.changelog.rev(node)
869 ui.write(_("Testing changeset %d:%s "
869 ui.write(_("Testing changeset %d:%s "
870 "(%d changesets remaining, ~%d tests)\n")
870 "(%d changesets remaining, ~%d tests)\n")
871 % (rev, short(node), changesets, tests))
871 % (rev, short(node), changesets, tests))
872 state['current'] = [node]
872 state['current'] = [node]
873 hbisect.save_state(repo, state)
873 hbisect.save_state(repo, state)
874 if not noupdate:
874 if not noupdate:
875 cmdutil.bailifchanged(repo)
875 cmdutil.bailifchanged(repo)
876 return hg.clean(repo, node)
876 return hg.clean(repo, node)
877
877
878 @command('bookmarks|bookmark',
878 @command('bookmarks|bookmark',
879 [('f', 'force', False, _('force')),
879 [('f', 'force', False, _('force')),
880 ('r', 'rev', '', _('revision'), _('REV')),
880 ('r', 'rev', '', _('revision'), _('REV')),
881 ('d', 'delete', False, _('delete a given bookmark')),
881 ('d', 'delete', False, _('delete a given bookmark')),
882 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
882 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
883 ('i', 'inactive', False, _('mark a bookmark inactive')),
883 ('i', 'inactive', False, _('mark a bookmark inactive')),
884 ] + formatteropts,
884 ] + formatteropts,
885 _('hg bookmarks [OPTIONS]... [NAME]...'))
885 _('hg bookmarks [OPTIONS]... [NAME]...'))
886 def bookmark(ui, repo, *names, **opts):
886 def bookmark(ui, repo, *names, **opts):
887 '''create a new bookmark or list existing bookmarks
887 '''create a new bookmark or list existing bookmarks
888
888
889 Bookmarks are labels on changesets to help track lines of development.
889 Bookmarks are labels on changesets to help track lines of development.
890 Bookmarks are unversioned and can be moved, renamed and deleted.
890 Bookmarks are unversioned and can be moved, renamed and deleted.
891 Deleting or moving a bookmark has no effect on the associated changesets.
891 Deleting or moving a bookmark has no effect on the associated changesets.
892
892
893 Creating or updating to a bookmark causes it to be marked as 'active'.
893 Creating or updating to a bookmark causes it to be marked as 'active'.
894 The active bookmark is indicated with a '*'.
894 The active bookmark is indicated with a '*'.
895 When a commit is made, the active bookmark will advance to the new commit.
895 When a commit is made, the active bookmark will advance to the new commit.
896 A plain :hg:`update` will also advance an active bookmark, if possible.
896 A plain :hg:`update` will also advance an active bookmark, if possible.
897 Updating away from a bookmark will cause it to be deactivated.
897 Updating away from a bookmark will cause it to be deactivated.
898
898
899 Bookmarks can be pushed and pulled between repositories (see
899 Bookmarks can be pushed and pulled between repositories (see
900 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
900 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
901 diverged, a new 'divergent bookmark' of the form 'name@path' will
901 diverged, a new 'divergent bookmark' of the form 'name@path' will
902 be created. Using :hg:`merge` will resolve the divergence.
902 be created. Using :hg:`merge` will resolve the divergence.
903
903
904 A bookmark named '@' has the special property that :hg:`clone` will
904 A bookmark named '@' has the special property that :hg:`clone` will
905 check it out by default if it exists.
905 check it out by default if it exists.
906
906
907 .. container:: verbose
907 .. container:: verbose
908
908
909 Examples:
909 Examples:
910
910
911 - create an active bookmark for a new line of development::
911 - create an active bookmark for a new line of development::
912
912
913 hg book new-feature
913 hg book new-feature
914
914
915 - create an inactive bookmark as a place marker::
915 - create an inactive bookmark as a place marker::
916
916
917 hg book -i reviewed
917 hg book -i reviewed
918
918
919 - create an inactive bookmark on another changeset::
919 - create an inactive bookmark on another changeset::
920
920
921 hg book -r .^ tested
921 hg book -r .^ tested
922
922
923 - rename bookmark turkey to dinner::
923 - rename bookmark turkey to dinner::
924
924
925 hg book -m turkey dinner
925 hg book -m turkey dinner
926
926
927 - move the '@' bookmark from another branch::
927 - move the '@' bookmark from another branch::
928
928
929 hg book -f @
929 hg book -f @
930 '''
930 '''
931 force = opts.get('force')
931 force = opts.get('force')
932 rev = opts.get('rev')
932 rev = opts.get('rev')
933 delete = opts.get('delete')
933 delete = opts.get('delete')
934 rename = opts.get('rename')
934 rename = opts.get('rename')
935 inactive = opts.get('inactive')
935 inactive = opts.get('inactive')
936
936
937 def checkformat(mark):
937 def checkformat(mark):
938 mark = mark.strip()
938 mark = mark.strip()
939 if not mark:
939 if not mark:
940 raise error.Abort(_("bookmark names cannot consist entirely of "
940 raise error.Abort(_("bookmark names cannot consist entirely of "
941 "whitespace"))
941 "whitespace"))
942 scmutil.checknewlabel(repo, mark, 'bookmark')
942 scmutil.checknewlabel(repo, mark, 'bookmark')
943 return mark
943 return mark
944
944
945 def checkconflict(repo, mark, cur, force=False, target=None):
945 def checkconflict(repo, mark, cur, force=False, target=None):
946 if mark in marks and not force:
946 if mark in marks and not force:
947 if target:
947 if target:
948 if marks[mark] == target and target == cur:
948 if marks[mark] == target and target == cur:
949 # re-activating a bookmark
949 # re-activating a bookmark
950 return
950 return
951 anc = repo.changelog.ancestors([repo[target].rev()])
951 anc = repo.changelog.ancestors([repo[target].rev()])
952 bmctx = repo[marks[mark]]
952 bmctx = repo[marks[mark]]
953 divs = [repo[b].node() for b in marks
953 divs = [repo[b].node() for b in marks
954 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
954 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
955
955
956 # allow resolving a single divergent bookmark even if moving
956 # allow resolving a single divergent bookmark even if moving
957 # the bookmark across branches when a revision is specified
957 # the bookmark across branches when a revision is specified
958 # that contains a divergent bookmark
958 # that contains a divergent bookmark
959 if bmctx.rev() not in anc and target in divs:
959 if bmctx.rev() not in anc and target in divs:
960 bookmarks.deletedivergent(repo, [target], mark)
960 bookmarks.deletedivergent(repo, [target], mark)
961 return
961 return
962
962
963 deletefrom = [b for b in divs
963 deletefrom = [b for b in divs
964 if repo[b].rev() in anc or b == target]
964 if repo[b].rev() in anc or b == target]
965 bookmarks.deletedivergent(repo, deletefrom, mark)
965 bookmarks.deletedivergent(repo, deletefrom, mark)
966 if bookmarks.validdest(repo, bmctx, repo[target]):
966 if bookmarks.validdest(repo, bmctx, repo[target]):
967 ui.status(_("moving bookmark '%s' forward from %s\n") %
967 ui.status(_("moving bookmark '%s' forward from %s\n") %
968 (mark, short(bmctx.node())))
968 (mark, short(bmctx.node())))
969 return
969 return
970 raise error.Abort(_("bookmark '%s' already exists "
970 raise error.Abort(_("bookmark '%s' already exists "
971 "(use -f to force)") % mark)
971 "(use -f to force)") % mark)
972 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
972 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
973 and not force):
973 and not force):
974 raise error.Abort(
974 raise error.Abort(
975 _("a bookmark cannot have the name of an existing branch"))
975 _("a bookmark cannot have the name of an existing branch"))
976
976
977 if delete and rename:
977 if delete and rename:
978 raise error.Abort(_("--delete and --rename are incompatible"))
978 raise error.Abort(_("--delete and --rename are incompatible"))
979 if delete and rev:
979 if delete and rev:
980 raise error.Abort(_("--rev is incompatible with --delete"))
980 raise error.Abort(_("--rev is incompatible with --delete"))
981 if rename and rev:
981 if rename and rev:
982 raise error.Abort(_("--rev is incompatible with --rename"))
982 raise error.Abort(_("--rev is incompatible with --rename"))
983 if not names and (delete or rev):
983 if not names and (delete or rev):
984 raise error.Abort(_("bookmark name required"))
984 raise error.Abort(_("bookmark name required"))
985
985
986 if delete or rename or names or inactive:
986 if delete or rename or names or inactive:
987 wlock = lock = tr = None
987 wlock = lock = tr = None
988 try:
988 try:
989 wlock = repo.wlock()
989 wlock = repo.wlock()
990 lock = repo.lock()
990 lock = repo.lock()
991 cur = repo.changectx('.').node()
991 cur = repo.changectx('.').node()
992 marks = repo._bookmarks
992 marks = repo._bookmarks
993 if delete:
993 if delete:
994 tr = repo.transaction('bookmark')
994 tr = repo.transaction('bookmark')
995 for mark in names:
995 for mark in names:
996 if mark not in marks:
996 if mark not in marks:
997 raise error.Abort(_("bookmark '%s' does not exist") %
997 raise error.Abort(_("bookmark '%s' does not exist") %
998 mark)
998 mark)
999 if mark == repo._activebookmark:
999 if mark == repo._activebookmark:
1000 bookmarks.deactivate(repo)
1000 bookmarks.deactivate(repo)
1001 del marks[mark]
1001 del marks[mark]
1002
1002
1003 elif rename:
1003 elif rename:
1004 tr = repo.transaction('bookmark')
1004 tr = repo.transaction('bookmark')
1005 if not names:
1005 if not names:
1006 raise error.Abort(_("new bookmark name required"))
1006 raise error.Abort(_("new bookmark name required"))
1007 elif len(names) > 1:
1007 elif len(names) > 1:
1008 raise error.Abort(_("only one new bookmark name allowed"))
1008 raise error.Abort(_("only one new bookmark name allowed"))
1009 mark = checkformat(names[0])
1009 mark = checkformat(names[0])
1010 if rename not in marks:
1010 if rename not in marks:
1011 raise error.Abort(_("bookmark '%s' does not exist")
1011 raise error.Abort(_("bookmark '%s' does not exist")
1012 % rename)
1012 % rename)
1013 checkconflict(repo, mark, cur, force)
1013 checkconflict(repo, mark, cur, force)
1014 marks[mark] = marks[rename]
1014 marks[mark] = marks[rename]
1015 if repo._activebookmark == rename and not inactive:
1015 if repo._activebookmark == rename and not inactive:
1016 bookmarks.activate(repo, mark)
1016 bookmarks.activate(repo, mark)
1017 del marks[rename]
1017 del marks[rename]
1018 elif names:
1018 elif names:
1019 tr = repo.transaction('bookmark')
1019 tr = repo.transaction('bookmark')
1020 newact = None
1020 newact = None
1021 for mark in names:
1021 for mark in names:
1022 mark = checkformat(mark)
1022 mark = checkformat(mark)
1023 if newact is None:
1023 if newact is None:
1024 newact = mark
1024 newact = mark
1025 if inactive and mark == repo._activebookmark:
1025 if inactive and mark == repo._activebookmark:
1026 bookmarks.deactivate(repo)
1026 bookmarks.deactivate(repo)
1027 return
1027 return
1028 tgt = cur
1028 tgt = cur
1029 if rev:
1029 if rev:
1030 tgt = scmutil.revsingle(repo, rev).node()
1030 tgt = scmutil.revsingle(repo, rev).node()
1031 checkconflict(repo, mark, cur, force, tgt)
1031 checkconflict(repo, mark, cur, force, tgt)
1032 marks[mark] = tgt
1032 marks[mark] = tgt
1033 if not inactive and cur == marks[newact] and not rev:
1033 if not inactive and cur == marks[newact] and not rev:
1034 bookmarks.activate(repo, newact)
1034 bookmarks.activate(repo, newact)
1035 elif cur != tgt and newact == repo._activebookmark:
1035 elif cur != tgt and newact == repo._activebookmark:
1036 bookmarks.deactivate(repo)
1036 bookmarks.deactivate(repo)
1037 elif inactive:
1037 elif inactive:
1038 if len(marks) == 0:
1038 if len(marks) == 0:
1039 ui.status(_("no bookmarks set\n"))
1039 ui.status(_("no bookmarks set\n"))
1040 elif not repo._activebookmark:
1040 elif not repo._activebookmark:
1041 ui.status(_("no active bookmark\n"))
1041 ui.status(_("no active bookmark\n"))
1042 else:
1042 else:
1043 bookmarks.deactivate(repo)
1043 bookmarks.deactivate(repo)
1044 if tr is not None:
1044 if tr is not None:
1045 marks.recordchange(tr)
1045 marks.recordchange(tr)
1046 tr.close()
1046 tr.close()
1047 finally:
1047 finally:
1048 lockmod.release(tr, lock, wlock)
1048 lockmod.release(tr, lock, wlock)
1049 else: # show bookmarks
1049 else: # show bookmarks
1050 fm = ui.formatter('bookmarks', opts)
1050 fm = ui.formatter('bookmarks', opts)
1051 hexfn = fm.hexfunc
1051 hexfn = fm.hexfunc
1052 marks = repo._bookmarks
1052 marks = repo._bookmarks
1053 if len(marks) == 0 and not fm:
1053 if len(marks) == 0 and not fm:
1054 ui.status(_("no bookmarks set\n"))
1054 ui.status(_("no bookmarks set\n"))
1055 for bmark, n in sorted(marks.iteritems()):
1055 for bmark, n in sorted(marks.iteritems()):
1056 active = repo._activebookmark
1056 active = repo._activebookmark
1057 if bmark == active:
1057 if bmark == active:
1058 prefix, label = '*', activebookmarklabel
1058 prefix, label = '*', activebookmarklabel
1059 else:
1059 else:
1060 prefix, label = ' ', ''
1060 prefix, label = ' ', ''
1061
1061
1062 fm.startitem()
1062 fm.startitem()
1063 if not ui.quiet:
1063 if not ui.quiet:
1064 fm.plain(' %s ' % prefix, label=label)
1064 fm.plain(' %s ' % prefix, label=label)
1065 fm.write('bookmark', '%s', bmark, label=label)
1065 fm.write('bookmark', '%s', bmark, label=label)
1066 pad = " " * (25 - encoding.colwidth(bmark))
1066 pad = " " * (25 - encoding.colwidth(bmark))
1067 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1067 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1068 repo.changelog.rev(n), hexfn(n), label=label)
1068 repo.changelog.rev(n), hexfn(n), label=label)
1069 fm.data(active=(bmark == active))
1069 fm.data(active=(bmark == active))
1070 fm.plain('\n')
1070 fm.plain('\n')
1071 fm.end()
1071 fm.end()
1072
1072
1073 @command('branch',
1073 @command('branch',
1074 [('f', 'force', None,
1074 [('f', 'force', None,
1075 _('set branch name even if it shadows an existing branch')),
1075 _('set branch name even if it shadows an existing branch')),
1076 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1076 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1077 _('[-fC] [NAME]'))
1077 _('[-fC] [NAME]'))
1078 def branch(ui, repo, label=None, **opts):
1078 def branch(ui, repo, label=None, **opts):
1079 """set or show the current branch name
1079 """set or show the current branch name
1080
1080
1081 .. note::
1081 .. note::
1082
1082
1083 Branch names are permanent and global. Use :hg:`bookmark` to create a
1083 Branch names are permanent and global. Use :hg:`bookmark` to create a
1084 light-weight bookmark instead. See :hg:`help glossary` for more
1084 light-weight bookmark instead. See :hg:`help glossary` for more
1085 information about named branches and bookmarks.
1085 information about named branches and bookmarks.
1086
1086
1087 With no argument, show the current branch name. With one argument,
1087 With no argument, show the current branch name. With one argument,
1088 set the working directory branch name (the branch will not exist
1088 set the working directory branch name (the branch will not exist
1089 in the repository until the next commit). Standard practice
1089 in the repository until the next commit). Standard practice
1090 recommends that primary development take place on the 'default'
1090 recommends that primary development take place on the 'default'
1091 branch.
1091 branch.
1092
1092
1093 Unless -f/--force is specified, branch will not let you set a
1093 Unless -f/--force is specified, branch will not let you set a
1094 branch name that already exists.
1094 branch name that already exists.
1095
1095
1096 Use -C/--clean to reset the working directory branch to that of
1096 Use -C/--clean to reset the working directory branch to that of
1097 the parent of the working directory, negating a previous branch
1097 the parent of the working directory, negating a previous branch
1098 change.
1098 change.
1099
1099
1100 Use the command :hg:`update` to switch to an existing branch. Use
1100 Use the command :hg:`update` to switch to an existing branch. Use
1101 :hg:`commit --close-branch` to mark this branch head as closed.
1101 :hg:`commit --close-branch` to mark this branch head as closed.
1102 When all heads of the branch are closed, the branch will be
1102 When all heads of the branch are closed, the branch will be
1103 considered closed.
1103 considered closed.
1104
1104
1105 Returns 0 on success.
1105 Returns 0 on success.
1106 """
1106 """
1107 if label:
1107 if label:
1108 label = label.strip()
1108 label = label.strip()
1109
1109
1110 if not opts.get('clean') and not label:
1110 if not opts.get('clean') and not label:
1111 ui.write("%s\n" % repo.dirstate.branch())
1111 ui.write("%s\n" % repo.dirstate.branch())
1112 return
1112 return
1113
1113
1114 wlock = repo.wlock()
1114 wlock = repo.wlock()
1115 try:
1115 try:
1116 if opts.get('clean'):
1116 if opts.get('clean'):
1117 label = repo[None].p1().branch()
1117 label = repo[None].p1().branch()
1118 repo.dirstate.setbranch(label)
1118 repo.dirstate.setbranch(label)
1119 ui.status(_('reset working directory to branch %s\n') % label)
1119 ui.status(_('reset working directory to branch %s\n') % label)
1120 elif label:
1120 elif label:
1121 if not opts.get('force') and label in repo.branchmap():
1121 if not opts.get('force') and label in repo.branchmap():
1122 if label not in [p.branch() for p in repo.parents()]:
1122 if label not in [p.branch() for p in repo.parents()]:
1123 raise error.Abort(_('a branch of the same name already'
1123 raise error.Abort(_('a branch of the same name already'
1124 ' exists'),
1124 ' exists'),
1125 # i18n: "it" refers to an existing branch
1125 # i18n: "it" refers to an existing branch
1126 hint=_("use 'hg update' to switch to it"))
1126 hint=_("use 'hg update' to switch to it"))
1127 scmutil.checknewlabel(repo, label, 'branch')
1127 scmutil.checknewlabel(repo, label, 'branch')
1128 repo.dirstate.setbranch(label)
1128 repo.dirstate.setbranch(label)
1129 ui.status(_('marked working directory as branch %s\n') % label)
1129 ui.status(_('marked working directory as branch %s\n') % label)
1130
1130
1131 # find any open named branches aside from default
1131 # find any open named branches aside from default
1132 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1132 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1133 if n != "default" and not c]
1133 if n != "default" and not c]
1134 if not others:
1134 if not others:
1135 ui.status(_('(branches are permanent and global, '
1135 ui.status(_('(branches are permanent and global, '
1136 'did you want a bookmark?)\n'))
1136 'did you want a bookmark?)\n'))
1137 finally:
1137 finally:
1138 wlock.release()
1138 wlock.release()
1139
1139
1140 @command('branches',
1140 @command('branches',
1141 [('a', 'active', False,
1141 [('a', 'active', False,
1142 _('show only branches that have unmerged heads (DEPRECATED)')),
1142 _('show only branches that have unmerged heads (DEPRECATED)')),
1143 ('c', 'closed', False, _('show normal and closed branches')),
1143 ('c', 'closed', False, _('show normal and closed branches')),
1144 ] + formatteropts,
1144 ] + formatteropts,
1145 _('[-ac]'))
1145 _('[-ac]'))
1146 def branches(ui, repo, active=False, closed=False, **opts):
1146 def branches(ui, repo, active=False, closed=False, **opts):
1147 """list repository named branches
1147 """list repository named branches
1148
1148
1149 List the repository's named branches, indicating which ones are
1149 List the repository's named branches, indicating which ones are
1150 inactive. If -c/--closed is specified, also list branches which have
1150 inactive. If -c/--closed is specified, also list branches which have
1151 been marked closed (see :hg:`commit --close-branch`).
1151 been marked closed (see :hg:`commit --close-branch`).
1152
1152
1153 Use the command :hg:`update` to switch to an existing branch.
1153 Use the command :hg:`update` to switch to an existing branch.
1154
1154
1155 Returns 0.
1155 Returns 0.
1156 """
1156 """
1157
1157
1158 fm = ui.formatter('branches', opts)
1158 fm = ui.formatter('branches', opts)
1159 hexfunc = fm.hexfunc
1159 hexfunc = fm.hexfunc
1160
1160
1161 allheads = set(repo.heads())
1161 allheads = set(repo.heads())
1162 branches = []
1162 branches = []
1163 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1163 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1164 isactive = not isclosed and bool(set(heads) & allheads)
1164 isactive = not isclosed and bool(set(heads) & allheads)
1165 branches.append((tag, repo[tip], isactive, not isclosed))
1165 branches.append((tag, repo[tip], isactive, not isclosed))
1166 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1166 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1167 reverse=True)
1167 reverse=True)
1168
1168
1169 for tag, ctx, isactive, isopen in branches:
1169 for tag, ctx, isactive, isopen in branches:
1170 if active and not isactive:
1170 if active and not isactive:
1171 continue
1171 continue
1172 if isactive:
1172 if isactive:
1173 label = 'branches.active'
1173 label = 'branches.active'
1174 notice = ''
1174 notice = ''
1175 elif not isopen:
1175 elif not isopen:
1176 if not closed:
1176 if not closed:
1177 continue
1177 continue
1178 label = 'branches.closed'
1178 label = 'branches.closed'
1179 notice = _(' (closed)')
1179 notice = _(' (closed)')
1180 else:
1180 else:
1181 label = 'branches.inactive'
1181 label = 'branches.inactive'
1182 notice = _(' (inactive)')
1182 notice = _(' (inactive)')
1183 current = (tag == repo.dirstate.branch())
1183 current = (tag == repo.dirstate.branch())
1184 if current:
1184 if current:
1185 label = 'branches.current'
1185 label = 'branches.current'
1186
1186
1187 fm.startitem()
1187 fm.startitem()
1188 fm.write('branch', '%s', tag, label=label)
1188 fm.write('branch', '%s', tag, label=label)
1189 rev = ctx.rev()
1189 rev = ctx.rev()
1190 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1190 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1191 fmt = ' ' * padsize + ' %d:%s'
1191 fmt = ' ' * padsize + ' %d:%s'
1192 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1192 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1193 label='log.changeset changeset.%s' % ctx.phasestr())
1193 label='log.changeset changeset.%s' % ctx.phasestr())
1194 fm.data(active=isactive, closed=not isopen, current=current)
1194 fm.data(active=isactive, closed=not isopen, current=current)
1195 if not ui.quiet:
1195 if not ui.quiet:
1196 fm.plain(notice)
1196 fm.plain(notice)
1197 fm.plain('\n')
1197 fm.plain('\n')
1198 fm.end()
1198 fm.end()
1199
1199
1200 @command('bundle',
1200 @command('bundle',
1201 [('f', 'force', None, _('run even when the destination is unrelated')),
1201 [('f', 'force', None, _('run even when the destination is unrelated')),
1202 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1202 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1203 _('REV')),
1203 _('REV')),
1204 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1204 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1205 _('BRANCH')),
1205 _('BRANCH')),
1206 ('', 'base', [],
1206 ('', 'base', [],
1207 _('a base changeset assumed to be available at the destination'),
1207 _('a base changeset assumed to be available at the destination'),
1208 _('REV')),
1208 _('REV')),
1209 ('a', 'all', None, _('bundle all changesets in the repository')),
1209 ('a', 'all', None, _('bundle all changesets in the repository')),
1210 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1210 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1211 ] + remoteopts,
1211 ] + remoteopts,
1212 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1212 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1213 def bundle(ui, repo, fname, dest=None, **opts):
1213 def bundle(ui, repo, fname, dest=None, **opts):
1214 """create a changegroup file
1214 """create a changegroup file
1215
1215
1216 Generate a compressed changegroup file collecting changesets not
1216 Generate a compressed changegroup file collecting changesets not
1217 known to be in another repository.
1217 known to be in another repository.
1218
1218
1219 If you omit the destination repository, then hg assumes the
1219 If you omit the destination repository, then hg assumes the
1220 destination will have all the nodes you specify with --base
1220 destination will have all the nodes you specify with --base
1221 parameters. To create a bundle containing all changesets, use
1221 parameters. To create a bundle containing all changesets, use
1222 -a/--all (or --base null).
1222 -a/--all (or --base null).
1223
1223
1224 You can change bundle format with the -t/--type option. You can
1224 You can change bundle format with the -t/--type option. You can
1225 specify a compression, a bundle version or both using a dash
1225 specify a compression, a bundle version or both using a dash
1226 (comp-version). The available compression methods are: none, bzip2,
1226 (comp-version). The available compression methods are: none, bzip2,
1227 and gzip (by default, bundles are compressed using bzip2). The
1227 and gzip (by default, bundles are compressed using bzip2). The
1228 available format are: v1, v2 (default to most suitable).
1228 available format are: v1, v2 (default to most suitable).
1229
1229
1230 The bundle file can then be transferred using conventional means
1230 The bundle file can then be transferred using conventional means
1231 and applied to another repository with the unbundle or pull
1231 and applied to another repository with the unbundle or pull
1232 command. This is useful when direct push and pull are not
1232 command. This is useful when direct push and pull are not
1233 available or when exporting an entire repository is undesirable.
1233 available or when exporting an entire repository is undesirable.
1234
1234
1235 Applying bundles preserves all changeset contents including
1235 Applying bundles preserves all changeset contents including
1236 permissions, copy/rename information, and revision history.
1236 permissions, copy/rename information, and revision history.
1237
1237
1238 Returns 0 on success, 1 if no changes found.
1238 Returns 0 on success, 1 if no changes found.
1239 """
1239 """
1240 revs = None
1240 revs = None
1241 if 'rev' in opts:
1241 if 'rev' in opts:
1242 revs = scmutil.revrange(repo, opts['rev'])
1242 revs = scmutil.revrange(repo, opts['rev'])
1243
1243
1244 bundletype = opts.get('type', 'bzip2').lower()
1244 bundletype = opts.get('type', 'bzip2').lower()
1245 try:
1245 try:
1246 bcompression, cgversion = exchange.parsebundlespec(
1246 bcompression, cgversion = exchange.parsebundlespec(
1247 repo, bundletype, strict=False)
1247 repo, bundletype, strict=False)
1248 except error.UnsupportedBundleSpecification as e:
1248 except error.UnsupportedBundleSpecification as e:
1249 raise error.Abort(str(e),
1249 raise error.Abort(str(e),
1250 hint=_('see "hg help bundle" for supported '
1250 hint=_('see "hg help bundle" for supported '
1251 'values for --type'))
1251 'values for --type'))
1252
1252
1253 if opts.get('all'):
1253 if opts.get('all'):
1254 base = ['null']
1254 base = ['null']
1255 else:
1255 else:
1256 base = scmutil.revrange(repo, opts.get('base'))
1256 base = scmutil.revrange(repo, opts.get('base'))
1257 # TODO: get desired bundlecaps from command line.
1257 # TODO: get desired bundlecaps from command line.
1258 bundlecaps = None
1258 bundlecaps = None
1259 if base:
1259 if base:
1260 if dest:
1260 if dest:
1261 raise error.Abort(_("--base is incompatible with specifying "
1261 raise error.Abort(_("--base is incompatible with specifying "
1262 "a destination"))
1262 "a destination"))
1263 common = [repo.lookup(rev) for rev in base]
1263 common = [repo.lookup(rev) for rev in base]
1264 heads = revs and map(repo.lookup, revs) or revs
1264 heads = revs and map(repo.lookup, revs) or revs
1265 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1265 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1266 common=common, bundlecaps=bundlecaps,
1266 common=common, bundlecaps=bundlecaps,
1267 version=cgversion)
1267 version=cgversion)
1268 outgoing = None
1268 outgoing = None
1269 else:
1269 else:
1270 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1270 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1271 dest, branches = hg.parseurl(dest, opts.get('branch'))
1271 dest, branches = hg.parseurl(dest, opts.get('branch'))
1272 other = hg.peer(repo, opts, dest)
1272 other = hg.peer(repo, opts, dest)
1273 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1273 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1274 heads = revs and map(repo.lookup, revs) or revs
1274 heads = revs and map(repo.lookup, revs) or revs
1275 outgoing = discovery.findcommonoutgoing(repo, other,
1275 outgoing = discovery.findcommonoutgoing(repo, other,
1276 onlyheads=heads,
1276 onlyheads=heads,
1277 force=opts.get('force'),
1277 force=opts.get('force'),
1278 portable=True)
1278 portable=True)
1279 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1279 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1280 bundlecaps, version=cgversion)
1280 bundlecaps, version=cgversion)
1281 if not cg:
1281 if not cg:
1282 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1282 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1283 return 1
1283 return 1
1284
1284
1285 if cgversion == '01': #bundle1
1285 if cgversion == '01': #bundle1
1286 if bcompression is None:
1286 if bcompression is None:
1287 bcompression = 'UN'
1287 bcompression = 'UN'
1288 bversion = 'HG10' + bcompression
1288 bversion = 'HG10' + bcompression
1289 bcompression = None
1289 bcompression = None
1290 else:
1290 else:
1291 assert cgversion == '02'
1291 assert cgversion == '02'
1292 bversion = 'HG20'
1292 bversion = 'HG20'
1293
1293
1294
1294
1295 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1295 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1296
1296
1297 @command('cat',
1297 @command('cat',
1298 [('o', 'output', '',
1298 [('o', 'output', '',
1299 _('print output to file with formatted name'), _('FORMAT')),
1299 _('print output to file with formatted name'), _('FORMAT')),
1300 ('r', 'rev', '', _('print the given revision'), _('REV')),
1300 ('r', 'rev', '', _('print the given revision'), _('REV')),
1301 ('', 'decode', None, _('apply any matching decode filter')),
1301 ('', 'decode', None, _('apply any matching decode filter')),
1302 ] + walkopts,
1302 ] + walkopts,
1303 _('[OPTION]... FILE...'),
1303 _('[OPTION]... FILE...'),
1304 inferrepo=True)
1304 inferrepo=True)
1305 def cat(ui, repo, file1, *pats, **opts):
1305 def cat(ui, repo, file1, *pats, **opts):
1306 """output the current or given revision of files
1306 """output the current or given revision of files
1307
1307
1308 Print the specified files as they were at the given revision. If
1308 Print the specified files as they were at the given revision. If
1309 no revision is given, the parent of the working directory is used.
1309 no revision is given, the parent of the working directory is used.
1310
1310
1311 Output may be to a file, in which case the name of the file is
1311 Output may be to a file, in which case the name of the file is
1312 given using a format string. The formatting rules as follows:
1312 given using a format string. The formatting rules as follows:
1313
1313
1314 :``%%``: literal "%" character
1314 :``%%``: literal "%" character
1315 :``%s``: basename of file being printed
1315 :``%s``: basename of file being printed
1316 :``%d``: dirname of file being printed, or '.' if in repository root
1316 :``%d``: dirname of file being printed, or '.' if in repository root
1317 :``%p``: root-relative path name of file being printed
1317 :``%p``: root-relative path name of file being printed
1318 :``%H``: changeset hash (40 hexadecimal digits)
1318 :``%H``: changeset hash (40 hexadecimal digits)
1319 :``%R``: changeset revision number
1319 :``%R``: changeset revision number
1320 :``%h``: short-form changeset hash (12 hexadecimal digits)
1320 :``%h``: short-form changeset hash (12 hexadecimal digits)
1321 :``%r``: zero-padded changeset revision number
1321 :``%r``: zero-padded changeset revision number
1322 :``%b``: basename of the exporting repository
1322 :``%b``: basename of the exporting repository
1323
1323
1324 Returns 0 on success.
1324 Returns 0 on success.
1325 """
1325 """
1326 ctx = scmutil.revsingle(repo, opts.get('rev'))
1326 ctx = scmutil.revsingle(repo, opts.get('rev'))
1327 m = scmutil.match(ctx, (file1,) + pats, opts)
1327 m = scmutil.match(ctx, (file1,) + pats, opts)
1328
1328
1329 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1329 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1330
1330
1331 @command('^clone',
1331 @command('^clone',
1332 [('U', 'noupdate', None, _('the clone will include an empty working '
1332 [('U', 'noupdate', None, _('the clone will include an empty working '
1333 'directory (only a repository)')),
1333 'directory (only a repository)')),
1334 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1334 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1335 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1335 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1336 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1336 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1337 ('', 'pull', None, _('use pull protocol to copy metadata')),
1337 ('', 'pull', None, _('use pull protocol to copy metadata')),
1338 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1338 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1339 ] + remoteopts,
1339 ] + remoteopts,
1340 _('[OPTION]... SOURCE [DEST]'),
1340 _('[OPTION]... SOURCE [DEST]'),
1341 norepo=True)
1341 norepo=True)
1342 def clone(ui, source, dest=None, **opts):
1342 def clone(ui, source, dest=None, **opts):
1343 """make a copy of an existing repository
1343 """make a copy of an existing repository
1344
1344
1345 Create a copy of an existing repository in a new directory.
1345 Create a copy of an existing repository in a new directory.
1346
1346
1347 If no destination directory name is specified, it defaults to the
1347 If no destination directory name is specified, it defaults to the
1348 basename of the source.
1348 basename of the source.
1349
1349
1350 The location of the source is added to the new repository's
1350 The location of the source is added to the new repository's
1351 ``.hg/hgrc`` file, as the default to be used for future pulls.
1351 ``.hg/hgrc`` file, as the default to be used for future pulls.
1352
1352
1353 Only local paths and ``ssh://`` URLs are supported as
1353 Only local paths and ``ssh://`` URLs are supported as
1354 destinations. For ``ssh://`` destinations, no working directory or
1354 destinations. For ``ssh://`` destinations, no working directory or
1355 ``.hg/hgrc`` will be created on the remote side.
1355 ``.hg/hgrc`` will be created on the remote side.
1356
1356
1357 To pull only a subset of changesets, specify one or more revisions
1357 To pull only a subset of changesets, specify one or more revisions
1358 identifiers with -r/--rev or branches with -b/--branch. The
1358 identifiers with -r/--rev or branches with -b/--branch. The
1359 resulting clone will contain only the specified changesets and
1359 resulting clone will contain only the specified changesets and
1360 their ancestors. These options (or 'clone src#rev dest') imply
1360 their ancestors. These options (or 'clone src#rev dest') imply
1361 --pull, even for local source repositories. Note that specifying a
1361 --pull, even for local source repositories. Note that specifying a
1362 tag will include the tagged changeset but not the changeset
1362 tag will include the tagged changeset but not the changeset
1363 containing the tag.
1363 containing the tag.
1364
1364
1365 If the source repository has a bookmark called '@' set, that
1365 If the source repository has a bookmark called '@' set, that
1366 revision will be checked out in the new repository by default.
1366 revision will be checked out in the new repository by default.
1367
1367
1368 To check out a particular version, use -u/--update, or
1368 To check out a particular version, use -u/--update, or
1369 -U/--noupdate to create a clone with no working directory.
1369 -U/--noupdate to create a clone with no working directory.
1370
1370
1371 .. container:: verbose
1371 .. container:: verbose
1372
1372
1373 For efficiency, hardlinks are used for cloning whenever the
1373 For efficiency, hardlinks are used for cloning whenever the
1374 source and destination are on the same filesystem (note this
1374 source and destination are on the same filesystem (note this
1375 applies only to the repository data, not to the working
1375 applies only to the repository data, not to the working
1376 directory). Some filesystems, such as AFS, implement hardlinking
1376 directory). Some filesystems, such as AFS, implement hardlinking
1377 incorrectly, but do not report errors. In these cases, use the
1377 incorrectly, but do not report errors. In these cases, use the
1378 --pull option to avoid hardlinking.
1378 --pull option to avoid hardlinking.
1379
1379
1380 In some cases, you can clone repositories and the working
1380 In some cases, you can clone repositories and the working
1381 directory using full hardlinks with ::
1381 directory using full hardlinks with ::
1382
1382
1383 $ cp -al REPO REPOCLONE
1383 $ cp -al REPO REPOCLONE
1384
1384
1385 This is the fastest way to clone, but it is not always safe. The
1385 This is the fastest way to clone, but it is not always safe. The
1386 operation is not atomic (making sure REPO is not modified during
1386 operation is not atomic (making sure REPO is not modified during
1387 the operation is up to you) and you have to make sure your
1387 the operation is up to you) and you have to make sure your
1388 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1388 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1389 so). Also, this is not compatible with certain extensions that
1389 so). Also, this is not compatible with certain extensions that
1390 place their metadata under the .hg directory, such as mq.
1390 place their metadata under the .hg directory, such as mq.
1391
1391
1392 Mercurial will update the working directory to the first applicable
1392 Mercurial will update the working directory to the first applicable
1393 revision from this list:
1393 revision from this list:
1394
1394
1395 a) null if -U or the source repository has no changesets
1395 a) null if -U or the source repository has no changesets
1396 b) if -u . and the source repository is local, the first parent of
1396 b) if -u . and the source repository is local, the first parent of
1397 the source repository's working directory
1397 the source repository's working directory
1398 c) the changeset specified with -u (if a branch name, this means the
1398 c) the changeset specified with -u (if a branch name, this means the
1399 latest head of that branch)
1399 latest head of that branch)
1400 d) the changeset specified with -r
1400 d) the changeset specified with -r
1401 e) the tipmost head specified with -b
1401 e) the tipmost head specified with -b
1402 f) the tipmost head specified with the url#branch source syntax
1402 f) the tipmost head specified with the url#branch source syntax
1403 g) the revision marked with the '@' bookmark, if present
1403 g) the revision marked with the '@' bookmark, if present
1404 h) the tipmost head of the default branch
1404 h) the tipmost head of the default branch
1405 i) tip
1405 i) tip
1406
1406
1407 Examples:
1407 Examples:
1408
1408
1409 - clone a remote repository to a new directory named hg/::
1409 - clone a remote repository to a new directory named hg/::
1410
1410
1411 hg clone http://selenic.com/hg
1411 hg clone http://selenic.com/hg
1412
1412
1413 - create a lightweight local clone::
1413 - create a lightweight local clone::
1414
1414
1415 hg clone project/ project-feature/
1415 hg clone project/ project-feature/
1416
1416
1417 - clone from an absolute path on an ssh server (note double-slash)::
1417 - clone from an absolute path on an ssh server (note double-slash)::
1418
1418
1419 hg clone ssh://user@server//home/projects/alpha/
1419 hg clone ssh://user@server//home/projects/alpha/
1420
1420
1421 - do a high-speed clone over a LAN while checking out a
1421 - do a high-speed clone over a LAN while checking out a
1422 specified version::
1422 specified version::
1423
1423
1424 hg clone --uncompressed http://server/repo -u 1.5
1424 hg clone --uncompressed http://server/repo -u 1.5
1425
1425
1426 - create a repository without changesets after a particular revision::
1426 - create a repository without changesets after a particular revision::
1427
1427
1428 hg clone -r 04e544 experimental/ good/
1428 hg clone -r 04e544 experimental/ good/
1429
1429
1430 - clone (and track) a particular named branch::
1430 - clone (and track) a particular named branch::
1431
1431
1432 hg clone http://selenic.com/hg#stable
1432 hg clone http://selenic.com/hg#stable
1433
1433
1434 See :hg:`help urls` for details on specifying URLs.
1434 See :hg:`help urls` for details on specifying URLs.
1435
1435
1436 Returns 0 on success.
1436 Returns 0 on success.
1437 """
1437 """
1438 if opts.get('noupdate') and opts.get('updaterev'):
1438 if opts.get('noupdate') and opts.get('updaterev'):
1439 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1439 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1440
1440
1441 r = hg.clone(ui, opts, source, dest,
1441 r = hg.clone(ui, opts, source, dest,
1442 pull=opts.get('pull'),
1442 pull=opts.get('pull'),
1443 stream=opts.get('uncompressed'),
1443 stream=opts.get('uncompressed'),
1444 rev=opts.get('rev'),
1444 rev=opts.get('rev'),
1445 update=opts.get('updaterev') or not opts.get('noupdate'),
1445 update=opts.get('updaterev') or not opts.get('noupdate'),
1446 branch=opts.get('branch'),
1446 branch=opts.get('branch'),
1447 shareopts=opts.get('shareopts'))
1447 shareopts=opts.get('shareopts'))
1448
1448
1449 return r is None
1449 return r is None
1450
1450
1451 @command('^commit|ci',
1451 @command('^commit|ci',
1452 [('A', 'addremove', None,
1452 [('A', 'addremove', None,
1453 _('mark new/missing files as added/removed before committing')),
1453 _('mark new/missing files as added/removed before committing')),
1454 ('', 'close-branch', None,
1454 ('', 'close-branch', None,
1455 _('mark a branch head as closed')),
1455 _('mark a branch head as closed')),
1456 ('', 'amend', None, _('amend the parent of the working directory')),
1456 ('', 'amend', None, _('amend the parent of the working directory')),
1457 ('s', 'secret', None, _('use the secret phase for committing')),
1457 ('s', 'secret', None, _('use the secret phase for committing')),
1458 ('e', 'edit', None, _('invoke editor on commit messages')),
1458 ('e', 'edit', None, _('invoke editor on commit messages')),
1459 ('i', 'interactive', None, _('use interactive mode')),
1459 ('i', 'interactive', None, _('use interactive mode')),
1460 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1460 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1461 _('[OPTION]... [FILE]...'),
1461 _('[OPTION]... [FILE]...'),
1462 inferrepo=True)
1462 inferrepo=True)
1463 def commit(ui, repo, *pats, **opts):
1463 def commit(ui, repo, *pats, **opts):
1464 """commit the specified files or all outstanding changes
1464 """commit the specified files or all outstanding changes
1465
1465
1466 Commit changes to the given files into the repository. Unlike a
1466 Commit changes to the given files into the repository. Unlike a
1467 centralized SCM, this operation is a local operation. See
1467 centralized SCM, this operation is a local operation. See
1468 :hg:`push` for a way to actively distribute your changes.
1468 :hg:`push` for a way to actively distribute your changes.
1469
1469
1470 If a list of files is omitted, all changes reported by :hg:`status`
1470 If a list of files is omitted, all changes reported by :hg:`status`
1471 will be committed.
1471 will be committed.
1472
1472
1473 If you are committing the result of a merge, do not provide any
1473 If you are committing the result of a merge, do not provide any
1474 filenames or -I/-X filters.
1474 filenames or -I/-X filters.
1475
1475
1476 If no commit message is specified, Mercurial starts your
1476 If no commit message is specified, Mercurial starts your
1477 configured editor where you can enter a message. In case your
1477 configured editor where you can enter a message. In case your
1478 commit fails, you will find a backup of your message in
1478 commit fails, you will find a backup of your message in
1479 ``.hg/last-message.txt``.
1479 ``.hg/last-message.txt``.
1480
1480
1481 The --close-branch flag can be used to mark the current branch
1481 The --close-branch flag can be used to mark the current branch
1482 head closed. When all heads of a branch are closed, the branch
1482 head closed. When all heads of a branch are closed, the branch
1483 will be considered closed and no longer listed.
1483 will be considered closed and no longer listed.
1484
1484
1485 The --amend flag can be used to amend the parent of the
1485 The --amend flag can be used to amend the parent of the
1486 working directory with a new commit that contains the changes
1486 working directory with a new commit that contains the changes
1487 in the parent in addition to those currently reported by :hg:`status`,
1487 in the parent in addition to those currently reported by :hg:`status`,
1488 if there are any. The old commit is stored in a backup bundle in
1488 if there are any. The old commit is stored in a backup bundle in
1489 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1489 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1490 on how to restore it).
1490 on how to restore it).
1491
1491
1492 Message, user and date are taken from the amended commit unless
1492 Message, user and date are taken from the amended commit unless
1493 specified. When a message isn't specified on the command line,
1493 specified. When a message isn't specified on the command line,
1494 the editor will open with the message of the amended commit.
1494 the editor will open with the message of the amended commit.
1495
1495
1496 It is not possible to amend public changesets (see :hg:`help phases`)
1496 It is not possible to amend public changesets (see :hg:`help phases`)
1497 or changesets that have children.
1497 or changesets that have children.
1498
1498
1499 See :hg:`help dates` for a list of formats valid for -d/--date.
1499 See :hg:`help dates` for a list of formats valid for -d/--date.
1500
1500
1501 Returns 0 on success, 1 if nothing changed.
1501 Returns 0 on success, 1 if nothing changed.
1502 """
1502 """
1503 if opts.get('interactive'):
1503 if opts.get('interactive'):
1504 opts.pop('interactive')
1504 opts.pop('interactive')
1505 cmdutil.dorecord(ui, repo, commit, None, False,
1505 cmdutil.dorecord(ui, repo, commit, None, False,
1506 cmdutil.recordfilter, *pats, **opts)
1506 cmdutil.recordfilter, *pats, **opts)
1507 return
1507 return
1508
1508
1509 if opts.get('subrepos'):
1509 if opts.get('subrepos'):
1510 if opts.get('amend'):
1510 if opts.get('amend'):
1511 raise error.Abort(_('cannot amend with --subrepos'))
1511 raise error.Abort(_('cannot amend with --subrepos'))
1512 # Let --subrepos on the command line override config setting.
1512 # Let --subrepos on the command line override config setting.
1513 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1513 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1514
1514
1515 cmdutil.checkunfinished(repo, commit=True)
1515 cmdutil.checkunfinished(repo, commit=True)
1516
1516
1517 branch = repo[None].branch()
1517 branch = repo[None].branch()
1518 bheads = repo.branchheads(branch)
1518 bheads = repo.branchheads(branch)
1519
1519
1520 extra = {}
1520 extra = {}
1521 if opts.get('close_branch'):
1521 if opts.get('close_branch'):
1522 extra['close'] = 1
1522 extra['close'] = 1
1523
1523
1524 if not bheads:
1524 if not bheads:
1525 raise error.Abort(_('can only close branch heads'))
1525 raise error.Abort(_('can only close branch heads'))
1526 elif opts.get('amend'):
1526 elif opts.get('amend'):
1527 if repo.parents()[0].p1().branch() != branch and \
1527 if repo.parents()[0].p1().branch() != branch and \
1528 repo.parents()[0].p2().branch() != branch:
1528 repo.parents()[0].p2().branch() != branch:
1529 raise error.Abort(_('can only close branch heads'))
1529 raise error.Abort(_('can only close branch heads'))
1530
1530
1531 if opts.get('amend'):
1531 if opts.get('amend'):
1532 if ui.configbool('ui', 'commitsubrepos'):
1532 if ui.configbool('ui', 'commitsubrepos'):
1533 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1533 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1534
1534
1535 old = repo['.']
1535 old = repo['.']
1536 if not old.mutable():
1536 if not old.mutable():
1537 raise error.Abort(_('cannot amend public changesets'))
1537 raise error.Abort(_('cannot amend public changesets'))
1538 if len(repo[None].parents()) > 1:
1538 if len(repo[None].parents()) > 1:
1539 raise error.Abort(_('cannot amend while merging'))
1539 raise error.Abort(_('cannot amend while merging'))
1540 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1540 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1541 if not allowunstable and old.children():
1541 if not allowunstable and old.children():
1542 raise error.Abort(_('cannot amend changeset with children'))
1542 raise error.Abort(_('cannot amend changeset with children'))
1543
1543
1544 # commitfunc is used only for temporary amend commit by cmdutil.amend
1544 # commitfunc is used only for temporary amend commit by cmdutil.amend
1545 def commitfunc(ui, repo, message, match, opts):
1545 def commitfunc(ui, repo, message, match, opts):
1546 return repo.commit(message,
1546 return repo.commit(message,
1547 opts.get('user') or old.user(),
1547 opts.get('user') or old.user(),
1548 opts.get('date') or old.date(),
1548 opts.get('date') or old.date(),
1549 match,
1549 match,
1550 extra=extra)
1550 extra=extra)
1551
1551
1552 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1552 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1553 if node == old.node():
1553 if node == old.node():
1554 ui.status(_("nothing changed\n"))
1554 ui.status(_("nothing changed\n"))
1555 return 1
1555 return 1
1556 else:
1556 else:
1557 def commitfunc(ui, repo, message, match, opts):
1557 def commitfunc(ui, repo, message, match, opts):
1558 backup = ui.backupconfig('phases', 'new-commit')
1558 backup = ui.backupconfig('phases', 'new-commit')
1559 baseui = repo.baseui
1559 baseui = repo.baseui
1560 basebackup = baseui.backupconfig('phases', 'new-commit')
1560 basebackup = baseui.backupconfig('phases', 'new-commit')
1561 try:
1561 try:
1562 if opts.get('secret'):
1562 if opts.get('secret'):
1563 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1563 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1564 # Propagate to subrepos
1564 # Propagate to subrepos
1565 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1565 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1566
1566
1567 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1567 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1568 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1568 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1569 return repo.commit(message, opts.get('user'), opts.get('date'),
1569 return repo.commit(message, opts.get('user'), opts.get('date'),
1570 match,
1570 match,
1571 editor=editor,
1571 editor=editor,
1572 extra=extra)
1572 extra=extra)
1573 finally:
1573 finally:
1574 ui.restoreconfig(backup)
1574 ui.restoreconfig(backup)
1575 repo.baseui.restoreconfig(basebackup)
1575 repo.baseui.restoreconfig(basebackup)
1576
1576
1577
1577
1578 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1578 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1579
1579
1580 if not node:
1580 if not node:
1581 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1581 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1582 if stat[3]:
1582 if stat[3]:
1583 ui.status(_("nothing changed (%d missing files, see "
1583 ui.status(_("nothing changed (%d missing files, see "
1584 "'hg status')\n") % len(stat[3]))
1584 "'hg status')\n") % len(stat[3]))
1585 else:
1585 else:
1586 ui.status(_("nothing changed\n"))
1586 ui.status(_("nothing changed\n"))
1587 return 1
1587 return 1
1588
1588
1589 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1589 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1590
1590
1591 @command('config|showconfig|debugconfig',
1591 @command('config|showconfig|debugconfig',
1592 [('u', 'untrusted', None, _('show untrusted configuration options')),
1592 [('u', 'untrusted', None, _('show untrusted configuration options')),
1593 ('e', 'edit', None, _('edit user config')),
1593 ('e', 'edit', None, _('edit user config')),
1594 ('l', 'local', None, _('edit repository config')),
1594 ('l', 'local', None, _('edit repository config')),
1595 ('g', 'global', None, _('edit global config'))],
1595 ('g', 'global', None, _('edit global config'))],
1596 _('[-u] [NAME]...'),
1596 _('[-u] [NAME]...'),
1597 optionalrepo=True)
1597 optionalrepo=True)
1598 def config(ui, repo, *values, **opts):
1598 def config(ui, repo, *values, **opts):
1599 """show combined config settings from all hgrc files
1599 """show combined config settings from all hgrc files
1600
1600
1601 With no arguments, print names and values of all config items.
1601 With no arguments, print names and values of all config items.
1602
1602
1603 With one argument of the form section.name, print just the value
1603 With one argument of the form section.name, print just the value
1604 of that config item.
1604 of that config item.
1605
1605
1606 With multiple arguments, print names and values of all config
1606 With multiple arguments, print names and values of all config
1607 items with matching section names.
1607 items with matching section names.
1608
1608
1609 With --edit, start an editor on the user-level config file. With
1609 With --edit, start an editor on the user-level config file. With
1610 --global, edit the system-wide config file. With --local, edit the
1610 --global, edit the system-wide config file. With --local, edit the
1611 repository-level config file.
1611 repository-level config file.
1612
1612
1613 With --debug, the source (filename and line number) is printed
1613 With --debug, the source (filename and line number) is printed
1614 for each config item.
1614 for each config item.
1615
1615
1616 See :hg:`help config` for more information about config files.
1616 See :hg:`help config` for more information about config files.
1617
1617
1618 Returns 0 on success, 1 if NAME does not exist.
1618 Returns 0 on success, 1 if NAME does not exist.
1619
1619
1620 """
1620 """
1621
1621
1622 if opts.get('edit') or opts.get('local') or opts.get('global'):
1622 if opts.get('edit') or opts.get('local') or opts.get('global'):
1623 if opts.get('local') and opts.get('global'):
1623 if opts.get('local') and opts.get('global'):
1624 raise error.Abort(_("can't use --local and --global together"))
1624 raise error.Abort(_("can't use --local and --global together"))
1625
1625
1626 if opts.get('local'):
1626 if opts.get('local'):
1627 if not repo:
1627 if not repo:
1628 raise error.Abort(_("can't use --local outside a repository"))
1628 raise error.Abort(_("can't use --local outside a repository"))
1629 paths = [repo.join('hgrc')]
1629 paths = [repo.join('hgrc')]
1630 elif opts.get('global'):
1630 elif opts.get('global'):
1631 paths = scmutil.systemrcpath()
1631 paths = scmutil.systemrcpath()
1632 else:
1632 else:
1633 paths = scmutil.userrcpath()
1633 paths = scmutil.userrcpath()
1634
1634
1635 for f in paths:
1635 for f in paths:
1636 if os.path.exists(f):
1636 if os.path.exists(f):
1637 break
1637 break
1638 else:
1638 else:
1639 if opts.get('global'):
1639 if opts.get('global'):
1640 samplehgrc = uimod.samplehgrcs['global']
1640 samplehgrc = uimod.samplehgrcs['global']
1641 elif opts.get('local'):
1641 elif opts.get('local'):
1642 samplehgrc = uimod.samplehgrcs['local']
1642 samplehgrc = uimod.samplehgrcs['local']
1643 else:
1643 else:
1644 samplehgrc = uimod.samplehgrcs['user']
1644 samplehgrc = uimod.samplehgrcs['user']
1645
1645
1646 f = paths[0]
1646 f = paths[0]
1647 fp = open(f, "w")
1647 fp = open(f, "w")
1648 fp.write(samplehgrc)
1648 fp.write(samplehgrc)
1649 fp.close()
1649 fp.close()
1650
1650
1651 editor = ui.geteditor()
1651 editor = ui.geteditor()
1652 ui.system("%s \"%s\"" % (editor, f),
1652 ui.system("%s \"%s\"" % (editor, f),
1653 onerr=error.Abort, errprefix=_("edit failed"))
1653 onerr=error.Abort, errprefix=_("edit failed"))
1654 return
1654 return
1655
1655
1656 for f in scmutil.rcpath():
1656 for f in scmutil.rcpath():
1657 ui.debug('read config from: %s\n' % f)
1657 ui.debug('read config from: %s\n' % f)
1658 untrusted = bool(opts.get('untrusted'))
1658 untrusted = bool(opts.get('untrusted'))
1659 if values:
1659 if values:
1660 sections = [v for v in values if '.' not in v]
1660 sections = [v for v in values if '.' not in v]
1661 items = [v for v in values if '.' in v]
1661 items = [v for v in values if '.' in v]
1662 if len(items) > 1 or items and sections:
1662 if len(items) > 1 or items and sections:
1663 raise error.Abort(_('only one config item permitted'))
1663 raise error.Abort(_('only one config item permitted'))
1664 matched = False
1664 matched = False
1665 for section, name, value in ui.walkconfig(untrusted=untrusted):
1665 for section, name, value in ui.walkconfig(untrusted=untrusted):
1666 value = str(value).replace('\n', '\\n')
1666 value = str(value).replace('\n', '\\n')
1667 sectname = section + '.' + name
1667 sectname = section + '.' + name
1668 if values:
1668 if values:
1669 for v in values:
1669 for v in values:
1670 if v == section:
1670 if v == section:
1671 ui.debug('%s: ' %
1671 ui.debug('%s: ' %
1672 ui.configsource(section, name, untrusted))
1672 ui.configsource(section, name, untrusted))
1673 ui.write('%s=%s\n' % (sectname, value))
1673 ui.write('%s=%s\n' % (sectname, value))
1674 matched = True
1674 matched = True
1675 elif v == sectname:
1675 elif v == sectname:
1676 ui.debug('%s: ' %
1676 ui.debug('%s: ' %
1677 ui.configsource(section, name, untrusted))
1677 ui.configsource(section, name, untrusted))
1678 ui.write(value, '\n')
1678 ui.write(value, '\n')
1679 matched = True
1679 matched = True
1680 else:
1680 else:
1681 ui.debug('%s: ' %
1681 ui.debug('%s: ' %
1682 ui.configsource(section, name, untrusted))
1682 ui.configsource(section, name, untrusted))
1683 ui.write('%s=%s\n' % (sectname, value))
1683 ui.write('%s=%s\n' % (sectname, value))
1684 matched = True
1684 matched = True
1685 if matched:
1685 if matched:
1686 return 0
1686 return 0
1687 return 1
1687 return 1
1688
1688
1689 @command('copy|cp',
1689 @command('copy|cp',
1690 [('A', 'after', None, _('record a copy that has already occurred')),
1690 [('A', 'after', None, _('record a copy that has already occurred')),
1691 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1691 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1692 ] + walkopts + dryrunopts,
1692 ] + walkopts + dryrunopts,
1693 _('[OPTION]... [SOURCE]... DEST'))
1693 _('[OPTION]... [SOURCE]... DEST'))
1694 def copy(ui, repo, *pats, **opts):
1694 def copy(ui, repo, *pats, **opts):
1695 """mark files as copied for the next commit
1695 """mark files as copied for the next commit
1696
1696
1697 Mark dest as having copies of source files. If dest is a
1697 Mark dest as having copies of source files. If dest is a
1698 directory, copies are put in that directory. If dest is a file,
1698 directory, copies are put in that directory. If dest is a file,
1699 the source must be a single file.
1699 the source must be a single file.
1700
1700
1701 By default, this command copies the contents of files as they
1701 By default, this command copies the contents of files as they
1702 exist in the working directory. If invoked with -A/--after, the
1702 exist in the working directory. If invoked with -A/--after, the
1703 operation is recorded, but no copying is performed.
1703 operation is recorded, but no copying is performed.
1704
1704
1705 This command takes effect with the next commit. To undo a copy
1705 This command takes effect with the next commit. To undo a copy
1706 before that, see :hg:`revert`.
1706 before that, see :hg:`revert`.
1707
1707
1708 Returns 0 on success, 1 if errors are encountered.
1708 Returns 0 on success, 1 if errors are encountered.
1709 """
1709 """
1710 wlock = repo.wlock(False)
1710 wlock = repo.wlock(False)
1711 try:
1711 try:
1712 return cmdutil.copy(ui, repo, pats, opts)
1712 return cmdutil.copy(ui, repo, pats, opts)
1713 finally:
1713 finally:
1714 wlock.release()
1714 wlock.release()
1715
1715
1716 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1716 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1717 def debugancestor(ui, repo, *args):
1717 def debugancestor(ui, repo, *args):
1718 """find the ancestor revision of two revisions in a given index"""
1718 """find the ancestor revision of two revisions in a given index"""
1719 if len(args) == 3:
1719 if len(args) == 3:
1720 index, rev1, rev2 = args
1720 index, rev1, rev2 = args
1721 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1721 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1722 lookup = r.lookup
1722 lookup = r.lookup
1723 elif len(args) == 2:
1723 elif len(args) == 2:
1724 if not repo:
1724 if not repo:
1725 raise error.Abort(_("there is no Mercurial repository here "
1725 raise error.Abort(_("there is no Mercurial repository here "
1726 "(.hg not found)"))
1726 "(.hg not found)"))
1727 rev1, rev2 = args
1727 rev1, rev2 = args
1728 r = repo.changelog
1728 r = repo.changelog
1729 lookup = repo.lookup
1729 lookup = repo.lookup
1730 else:
1730 else:
1731 raise error.Abort(_('either two or three arguments required'))
1731 raise error.Abort(_('either two or three arguments required'))
1732 a = r.ancestor(lookup(rev1), lookup(rev2))
1732 a = r.ancestor(lookup(rev1), lookup(rev2))
1733 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1733 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1734
1734
1735 @command('debugbuilddag',
1735 @command('debugbuilddag',
1736 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1736 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1737 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1737 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1738 ('n', 'new-file', None, _('add new file at each rev'))],
1738 ('n', 'new-file', None, _('add new file at each rev'))],
1739 _('[OPTION]... [TEXT]'))
1739 _('[OPTION]... [TEXT]'))
1740 def debugbuilddag(ui, repo, text=None,
1740 def debugbuilddag(ui, repo, text=None,
1741 mergeable_file=False,
1741 mergeable_file=False,
1742 overwritten_file=False,
1742 overwritten_file=False,
1743 new_file=False):
1743 new_file=False):
1744 """builds a repo with a given DAG from scratch in the current empty repo
1744 """builds a repo with a given DAG from scratch in the current empty repo
1745
1745
1746 The description of the DAG is read from stdin if not given on the
1746 The description of the DAG is read from stdin if not given on the
1747 command line.
1747 command line.
1748
1748
1749 Elements:
1749 Elements:
1750
1750
1751 - "+n" is a linear run of n nodes based on the current default parent
1751 - "+n" is a linear run of n nodes based on the current default parent
1752 - "." is a single node based on the current default parent
1752 - "." is a single node based on the current default parent
1753 - "$" resets the default parent to null (implied at the start);
1753 - "$" resets the default parent to null (implied at the start);
1754 otherwise the default parent is always the last node created
1754 otherwise the default parent is always the last node created
1755 - "<p" sets the default parent to the backref p
1755 - "<p" sets the default parent to the backref p
1756 - "*p" is a fork at parent p, which is a backref
1756 - "*p" is a fork at parent p, which is a backref
1757 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1757 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1758 - "/p2" is a merge of the preceding node and p2
1758 - "/p2" is a merge of the preceding node and p2
1759 - ":tag" defines a local tag for the preceding node
1759 - ":tag" defines a local tag for the preceding node
1760 - "@branch" sets the named branch for subsequent nodes
1760 - "@branch" sets the named branch for subsequent nodes
1761 - "#...\\n" is a comment up to the end of the line
1761 - "#...\\n" is a comment up to the end of the line
1762
1762
1763 Whitespace between the above elements is ignored.
1763 Whitespace between the above elements is ignored.
1764
1764
1765 A backref is either
1765 A backref is either
1766
1766
1767 - a number n, which references the node curr-n, where curr is the current
1767 - a number n, which references the node curr-n, where curr is the current
1768 node, or
1768 node, or
1769 - the name of a local tag you placed earlier using ":tag", or
1769 - the name of a local tag you placed earlier using ":tag", or
1770 - empty to denote the default parent.
1770 - empty to denote the default parent.
1771
1771
1772 All string valued-elements are either strictly alphanumeric, or must
1772 All string valued-elements are either strictly alphanumeric, or must
1773 be enclosed in double quotes ("..."), with "\\" as escape character.
1773 be enclosed in double quotes ("..."), with "\\" as escape character.
1774 """
1774 """
1775
1775
1776 if text is None:
1776 if text is None:
1777 ui.status(_("reading DAG from stdin\n"))
1777 ui.status(_("reading DAG from stdin\n"))
1778 text = ui.fin.read()
1778 text = ui.fin.read()
1779
1779
1780 cl = repo.changelog
1780 cl = repo.changelog
1781 if len(cl) > 0:
1781 if len(cl) > 0:
1782 raise error.Abort(_('repository is not empty'))
1782 raise error.Abort(_('repository is not empty'))
1783
1783
1784 # determine number of revs in DAG
1784 # determine number of revs in DAG
1785 total = 0
1785 total = 0
1786 for type, data in dagparser.parsedag(text):
1786 for type, data in dagparser.parsedag(text):
1787 if type == 'n':
1787 if type == 'n':
1788 total += 1
1788 total += 1
1789
1789
1790 if mergeable_file:
1790 if mergeable_file:
1791 linesperrev = 2
1791 linesperrev = 2
1792 # make a file with k lines per rev
1792 # make a file with k lines per rev
1793 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1793 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1794 initialmergedlines.append("")
1794 initialmergedlines.append("")
1795
1795
1796 tags = []
1796 tags = []
1797
1797
1798 lock = tr = None
1798 lock = tr = None
1799 try:
1799 try:
1800 lock = repo.lock()
1800 lock = repo.lock()
1801 tr = repo.transaction("builddag")
1801 tr = repo.transaction("builddag")
1802
1802
1803 at = -1
1803 at = -1
1804 atbranch = 'default'
1804 atbranch = 'default'
1805 nodeids = []
1805 nodeids = []
1806 id = 0
1806 id = 0
1807 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1807 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1808 for type, data in dagparser.parsedag(text):
1808 for type, data in dagparser.parsedag(text):
1809 if type == 'n':
1809 if type == 'n':
1810 ui.note(('node %s\n' % str(data)))
1810 ui.note(('node %s\n' % str(data)))
1811 id, ps = data
1811 id, ps = data
1812
1812
1813 files = []
1813 files = []
1814 fctxs = {}
1814 fctxs = {}
1815
1815
1816 p2 = None
1816 p2 = None
1817 if mergeable_file:
1817 if mergeable_file:
1818 fn = "mf"
1818 fn = "mf"
1819 p1 = repo[ps[0]]
1819 p1 = repo[ps[0]]
1820 if len(ps) > 1:
1820 if len(ps) > 1:
1821 p2 = repo[ps[1]]
1821 p2 = repo[ps[1]]
1822 pa = p1.ancestor(p2)
1822 pa = p1.ancestor(p2)
1823 base, local, other = [x[fn].data() for x in (pa, p1,
1823 base, local, other = [x[fn].data() for x in (pa, p1,
1824 p2)]
1824 p2)]
1825 m3 = simplemerge.Merge3Text(base, local, other)
1825 m3 = simplemerge.Merge3Text(base, local, other)
1826 ml = [l.strip() for l in m3.merge_lines()]
1826 ml = [l.strip() for l in m3.merge_lines()]
1827 ml.append("")
1827 ml.append("")
1828 elif at > 0:
1828 elif at > 0:
1829 ml = p1[fn].data().split("\n")
1829 ml = p1[fn].data().split("\n")
1830 else:
1830 else:
1831 ml = initialmergedlines
1831 ml = initialmergedlines
1832 ml[id * linesperrev] += " r%i" % id
1832 ml[id * linesperrev] += " r%i" % id
1833 mergedtext = "\n".join(ml)
1833 mergedtext = "\n".join(ml)
1834 files.append(fn)
1834 files.append(fn)
1835 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1835 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1836
1836
1837 if overwritten_file:
1837 if overwritten_file:
1838 fn = "of"
1838 fn = "of"
1839 files.append(fn)
1839 files.append(fn)
1840 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1840 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1841
1841
1842 if new_file:
1842 if new_file:
1843 fn = "nf%i" % id
1843 fn = "nf%i" % id
1844 files.append(fn)
1844 files.append(fn)
1845 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1845 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1846 if len(ps) > 1:
1846 if len(ps) > 1:
1847 if not p2:
1847 if not p2:
1848 p2 = repo[ps[1]]
1848 p2 = repo[ps[1]]
1849 for fn in p2:
1849 for fn in p2:
1850 if fn.startswith("nf"):
1850 if fn.startswith("nf"):
1851 files.append(fn)
1851 files.append(fn)
1852 fctxs[fn] = p2[fn]
1852 fctxs[fn] = p2[fn]
1853
1853
1854 def fctxfn(repo, cx, path):
1854 def fctxfn(repo, cx, path):
1855 return fctxs.get(path)
1855 return fctxs.get(path)
1856
1856
1857 if len(ps) == 0 or ps[0] < 0:
1857 if len(ps) == 0 or ps[0] < 0:
1858 pars = [None, None]
1858 pars = [None, None]
1859 elif len(ps) == 1:
1859 elif len(ps) == 1:
1860 pars = [nodeids[ps[0]], None]
1860 pars = [nodeids[ps[0]], None]
1861 else:
1861 else:
1862 pars = [nodeids[p] for p in ps]
1862 pars = [nodeids[p] for p in ps]
1863 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1863 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1864 date=(id, 0),
1864 date=(id, 0),
1865 user="debugbuilddag",
1865 user="debugbuilddag",
1866 extra={'branch': atbranch})
1866 extra={'branch': atbranch})
1867 nodeid = repo.commitctx(cx)
1867 nodeid = repo.commitctx(cx)
1868 nodeids.append(nodeid)
1868 nodeids.append(nodeid)
1869 at = id
1869 at = id
1870 elif type == 'l':
1870 elif type == 'l':
1871 id, name = data
1871 id, name = data
1872 ui.note(('tag %s\n' % name))
1872 ui.note(('tag %s\n' % name))
1873 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1873 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1874 elif type == 'a':
1874 elif type == 'a':
1875 ui.note(('branch %s\n' % data))
1875 ui.note(('branch %s\n' % data))
1876 atbranch = data
1876 atbranch = data
1877 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1877 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1878 tr.close()
1878 tr.close()
1879
1879
1880 if tags:
1880 if tags:
1881 repo.vfs.write("localtags", "".join(tags))
1881 repo.vfs.write("localtags", "".join(tags))
1882 finally:
1882 finally:
1883 ui.progress(_('building'), None)
1883 ui.progress(_('building'), None)
1884 release(tr, lock)
1884 release(tr, lock)
1885
1885
1886 @command('debugbundle',
1886 @command('debugbundle',
1887 [('a', 'all', None, _('show all details'))],
1887 [('a', 'all', None, _('show all details'))],
1888 _('FILE'),
1888 _('FILE'),
1889 norepo=True)
1889 norepo=True)
1890 def debugbundle(ui, bundlepath, all=None, **opts):
1890 def debugbundle(ui, bundlepath, all=None, **opts):
1891 """lists the contents of a bundle"""
1891 """lists the contents of a bundle"""
1892 f = hg.openpath(ui, bundlepath)
1892 f = hg.openpath(ui, bundlepath)
1893 try:
1893 try:
1894 gen = exchange.readbundle(ui, f, bundlepath)
1894 gen = exchange.readbundle(ui, f, bundlepath)
1895 if isinstance(gen, bundle2.unbundle20):
1895 if isinstance(gen, bundle2.unbundle20):
1896 return _debugbundle2(ui, gen, all=all, **opts)
1896 return _debugbundle2(ui, gen, all=all, **opts)
1897 if all:
1897 if all:
1898 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1898 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1899
1899
1900 def showchunks(named):
1900 def showchunks(named):
1901 ui.write("\n%s\n" % named)
1901 ui.write("\n%s\n" % named)
1902 chain = None
1902 chain = None
1903 while True:
1903 while True:
1904 chunkdata = gen.deltachunk(chain)
1904 chunkdata = gen.deltachunk(chain)
1905 if not chunkdata:
1905 if not chunkdata:
1906 break
1906 break
1907 node = chunkdata['node']
1907 node = chunkdata['node']
1908 p1 = chunkdata['p1']
1908 p1 = chunkdata['p1']
1909 p2 = chunkdata['p2']
1909 p2 = chunkdata['p2']
1910 cs = chunkdata['cs']
1910 cs = chunkdata['cs']
1911 deltabase = chunkdata['deltabase']
1911 deltabase = chunkdata['deltabase']
1912 delta = chunkdata['delta']
1912 delta = chunkdata['delta']
1913 ui.write("%s %s %s %s %s %s\n" %
1913 ui.write("%s %s %s %s %s %s\n" %
1914 (hex(node), hex(p1), hex(p2),
1914 (hex(node), hex(p1), hex(p2),
1915 hex(cs), hex(deltabase), len(delta)))
1915 hex(cs), hex(deltabase), len(delta)))
1916 chain = node
1916 chain = node
1917
1917
1918 chunkdata = gen.changelogheader()
1918 chunkdata = gen.changelogheader()
1919 showchunks("changelog")
1919 showchunks("changelog")
1920 chunkdata = gen.manifestheader()
1920 chunkdata = gen.manifestheader()
1921 showchunks("manifest")
1921 showchunks("manifest")
1922 while True:
1922 while True:
1923 chunkdata = gen.filelogheader()
1923 chunkdata = gen.filelogheader()
1924 if not chunkdata:
1924 if not chunkdata:
1925 break
1925 break
1926 fname = chunkdata['filename']
1926 fname = chunkdata['filename']
1927 showchunks(fname)
1927 showchunks(fname)
1928 else:
1928 else:
1929 if isinstance(gen, bundle2.unbundle20):
1929 if isinstance(gen, bundle2.unbundle20):
1930 raise error.Abort(_('use debugbundle2 for this file'))
1930 raise error.Abort(_('use debugbundle2 for this file'))
1931 chunkdata = gen.changelogheader()
1931 chunkdata = gen.changelogheader()
1932 chain = None
1932 chain = None
1933 while True:
1933 while True:
1934 chunkdata = gen.deltachunk(chain)
1934 chunkdata = gen.deltachunk(chain)
1935 if not chunkdata:
1935 if not chunkdata:
1936 break
1936 break
1937 node = chunkdata['node']
1937 node = chunkdata['node']
1938 ui.write("%s\n" % hex(node))
1938 ui.write("%s\n" % hex(node))
1939 chain = node
1939 chain = node
1940 finally:
1940 finally:
1941 f.close()
1941 f.close()
1942
1942
1943 def _debugbundle2(ui, gen, **opts):
1943 def _debugbundle2(ui, gen, **opts):
1944 """lists the contents of a bundle2"""
1944 """lists the contents of a bundle2"""
1945 if not isinstance(gen, bundle2.unbundle20):
1945 if not isinstance(gen, bundle2.unbundle20):
1946 raise error.Abort(_('not a bundle2 file'))
1946 raise error.Abort(_('not a bundle2 file'))
1947 ui.write(('Stream params: %s\n' % repr(gen.params)))
1947 ui.write(('Stream params: %s\n' % repr(gen.params)))
1948 for part in gen.iterparts():
1948 for part in gen.iterparts():
1949 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1949 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1950 if part.type == 'changegroup':
1950 if part.type == 'changegroup':
1951 version = part.params.get('version', '01')
1951 version = part.params.get('version', '01')
1952 cg = changegroup.packermap[version][1](part, 'UN')
1952 cg = changegroup.packermap[version][1](part, 'UN')
1953 chunkdata = cg.changelogheader()
1953 chunkdata = cg.changelogheader()
1954 chain = None
1954 chain = None
1955 while True:
1955 while True:
1956 chunkdata = cg.deltachunk(chain)
1956 chunkdata = cg.deltachunk(chain)
1957 if not chunkdata:
1957 if not chunkdata:
1958 break
1958 break
1959 node = chunkdata['node']
1959 node = chunkdata['node']
1960 ui.write(" %s\n" % hex(node))
1960 ui.write(" %s\n" % hex(node))
1961 chain = node
1961 chain = node
1962
1962
1963 @command('debugcheckstate', [], '')
1963 @command('debugcheckstate', [], '')
1964 def debugcheckstate(ui, repo):
1964 def debugcheckstate(ui, repo):
1965 """validate the correctness of the current dirstate"""
1965 """validate the correctness of the current dirstate"""
1966 parent1, parent2 = repo.dirstate.parents()
1966 parent1, parent2 = repo.dirstate.parents()
1967 m1 = repo[parent1].manifest()
1967 m1 = repo[parent1].manifest()
1968 m2 = repo[parent2].manifest()
1968 m2 = repo[parent2].manifest()
1969 errors = 0
1969 errors = 0
1970 for f in repo.dirstate:
1970 for f in repo.dirstate:
1971 state = repo.dirstate[f]
1971 state = repo.dirstate[f]
1972 if state in "nr" and f not in m1:
1972 if state in "nr" and f not in m1:
1973 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1973 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1974 errors += 1
1974 errors += 1
1975 if state in "a" and f in m1:
1975 if state in "a" and f in m1:
1976 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1976 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1977 errors += 1
1977 errors += 1
1978 if state in "m" and f not in m1 and f not in m2:
1978 if state in "m" and f not in m1 and f not in m2:
1979 ui.warn(_("%s in state %s, but not in either manifest\n") %
1979 ui.warn(_("%s in state %s, but not in either manifest\n") %
1980 (f, state))
1980 (f, state))
1981 errors += 1
1981 errors += 1
1982 for f in m1:
1982 for f in m1:
1983 state = repo.dirstate[f]
1983 state = repo.dirstate[f]
1984 if state not in "nrm":
1984 if state not in "nrm":
1985 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1985 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1986 errors += 1
1986 errors += 1
1987 if errors:
1987 if errors:
1988 error = _(".hg/dirstate inconsistent with current parent's manifest")
1988 error = _(".hg/dirstate inconsistent with current parent's manifest")
1989 raise error.Abort(error)
1989 raise error.Abort(error)
1990
1990
1991 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1991 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1992 def debugcommands(ui, cmd='', *args):
1992 def debugcommands(ui, cmd='', *args):
1993 """list all available commands and options"""
1993 """list all available commands and options"""
1994 for cmd, vals in sorted(table.iteritems()):
1994 for cmd, vals in sorted(table.iteritems()):
1995 cmd = cmd.split('|')[0].strip('^')
1995 cmd = cmd.split('|')[0].strip('^')
1996 opts = ', '.join([i[1] for i in vals[1]])
1996 opts = ', '.join([i[1] for i in vals[1]])
1997 ui.write('%s: %s\n' % (cmd, opts))
1997 ui.write('%s: %s\n' % (cmd, opts))
1998
1998
1999 @command('debugcomplete',
1999 @command('debugcomplete',
2000 [('o', 'options', None, _('show the command options'))],
2000 [('o', 'options', None, _('show the command options'))],
2001 _('[-o] CMD'),
2001 _('[-o] CMD'),
2002 norepo=True)
2002 norepo=True)
2003 def debugcomplete(ui, cmd='', **opts):
2003 def debugcomplete(ui, cmd='', **opts):
2004 """returns the completion list associated with the given command"""
2004 """returns the completion list associated with the given command"""
2005
2005
2006 if opts.get('options'):
2006 if opts.get('options'):
2007 options = []
2007 options = []
2008 otables = [globalopts]
2008 otables = [globalopts]
2009 if cmd:
2009 if cmd:
2010 aliases, entry = cmdutil.findcmd(cmd, table, False)
2010 aliases, entry = cmdutil.findcmd(cmd, table, False)
2011 otables.append(entry[1])
2011 otables.append(entry[1])
2012 for t in otables:
2012 for t in otables:
2013 for o in t:
2013 for o in t:
2014 if "(DEPRECATED)" in o[3]:
2014 if "(DEPRECATED)" in o[3]:
2015 continue
2015 continue
2016 if o[0]:
2016 if o[0]:
2017 options.append('-%s' % o[0])
2017 options.append('-%s' % o[0])
2018 options.append('--%s' % o[1])
2018 options.append('--%s' % o[1])
2019 ui.write("%s\n" % "\n".join(options))
2019 ui.write("%s\n" % "\n".join(options))
2020 return
2020 return
2021
2021
2022 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2022 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2023 if ui.verbose:
2023 if ui.verbose:
2024 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2024 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2025 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2025 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2026
2026
2027 @command('debugdag',
2027 @command('debugdag',
2028 [('t', 'tags', None, _('use tags as labels')),
2028 [('t', 'tags', None, _('use tags as labels')),
2029 ('b', 'branches', None, _('annotate with branch names')),
2029 ('b', 'branches', None, _('annotate with branch names')),
2030 ('', 'dots', None, _('use dots for runs')),
2030 ('', 'dots', None, _('use dots for runs')),
2031 ('s', 'spaces', None, _('separate elements by spaces'))],
2031 ('s', 'spaces', None, _('separate elements by spaces'))],
2032 _('[OPTION]... [FILE [REV]...]'),
2032 _('[OPTION]... [FILE [REV]...]'),
2033 optionalrepo=True)
2033 optionalrepo=True)
2034 def debugdag(ui, repo, file_=None, *revs, **opts):
2034 def debugdag(ui, repo, file_=None, *revs, **opts):
2035 """format the changelog or an index DAG as a concise textual description
2035 """format the changelog or an index DAG as a concise textual description
2036
2036
2037 If you pass a revlog index, the revlog's DAG is emitted. If you list
2037 If you pass a revlog index, the revlog's DAG is emitted. If you list
2038 revision numbers, they get labeled in the output as rN.
2038 revision numbers, they get labeled in the output as rN.
2039
2039
2040 Otherwise, the changelog DAG of the current repo is emitted.
2040 Otherwise, the changelog DAG of the current repo is emitted.
2041 """
2041 """
2042 spaces = opts.get('spaces')
2042 spaces = opts.get('spaces')
2043 dots = opts.get('dots')
2043 dots = opts.get('dots')
2044 if file_:
2044 if file_:
2045 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2045 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2046 revs = set((int(r) for r in revs))
2046 revs = set((int(r) for r in revs))
2047 def events():
2047 def events():
2048 for r in rlog:
2048 for r in rlog:
2049 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2049 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2050 if p != -1))
2050 if p != -1))
2051 if r in revs:
2051 if r in revs:
2052 yield 'l', (r, "r%i" % r)
2052 yield 'l', (r, "r%i" % r)
2053 elif repo:
2053 elif repo:
2054 cl = repo.changelog
2054 cl = repo.changelog
2055 tags = opts.get('tags')
2055 tags = opts.get('tags')
2056 branches = opts.get('branches')
2056 branches = opts.get('branches')
2057 if tags:
2057 if tags:
2058 labels = {}
2058 labels = {}
2059 for l, n in repo.tags().items():
2059 for l, n in repo.tags().items():
2060 labels.setdefault(cl.rev(n), []).append(l)
2060 labels.setdefault(cl.rev(n), []).append(l)
2061 def events():
2061 def events():
2062 b = "default"
2062 b = "default"
2063 for r in cl:
2063 for r in cl:
2064 if branches:
2064 if branches:
2065 newb = cl.read(cl.node(r))[5]['branch']
2065 newb = cl.read(cl.node(r))[5]['branch']
2066 if newb != b:
2066 if newb != b:
2067 yield 'a', newb
2067 yield 'a', newb
2068 b = newb
2068 b = newb
2069 yield 'n', (r, list(p for p in cl.parentrevs(r)
2069 yield 'n', (r, list(p for p in cl.parentrevs(r)
2070 if p != -1))
2070 if p != -1))
2071 if tags:
2071 if tags:
2072 ls = labels.get(r)
2072 ls = labels.get(r)
2073 if ls:
2073 if ls:
2074 for l in ls:
2074 for l in ls:
2075 yield 'l', (r, l)
2075 yield 'l', (r, l)
2076 else:
2076 else:
2077 raise error.Abort(_('need repo for changelog dag'))
2077 raise error.Abort(_('need repo for changelog dag'))
2078
2078
2079 for line in dagparser.dagtextlines(events(),
2079 for line in dagparser.dagtextlines(events(),
2080 addspaces=spaces,
2080 addspaces=spaces,
2081 wraplabels=True,
2081 wraplabels=True,
2082 wrapannotations=True,
2082 wrapannotations=True,
2083 wrapnonlinear=dots,
2083 wrapnonlinear=dots,
2084 usedots=dots,
2084 usedots=dots,
2085 maxlinewidth=70):
2085 maxlinewidth=70):
2086 ui.write(line)
2086 ui.write(line)
2087 ui.write("\n")
2087 ui.write("\n")
2088
2088
2089 @command('debugdata',
2089 @command('debugdata',
2090 [('c', 'changelog', False, _('open changelog')),
2090 [('c', 'changelog', False, _('open changelog')),
2091 ('m', 'manifest', False, _('open manifest')),
2091 ('m', 'manifest', False, _('open manifest')),
2092 ('', 'dir', False, _('open directory manifest'))],
2092 ('', 'dir', False, _('open directory manifest'))],
2093 _('-c|-m|FILE REV'))
2093 _('-c|-m|FILE REV'))
2094 def debugdata(ui, repo, file_, rev=None, **opts):
2094 def debugdata(ui, repo, file_, rev=None, **opts):
2095 """dump the contents of a data file revision"""
2095 """dump the contents of a data file revision"""
2096 if opts.get('changelog') or opts.get('manifest'):
2096 if opts.get('changelog') or opts.get('manifest'):
2097 file_, rev = None, file_
2097 file_, rev = None, file_
2098 elif rev is None:
2098 elif rev is None:
2099 raise error.CommandError('debugdata', _('invalid arguments'))
2099 raise error.CommandError('debugdata', _('invalid arguments'))
2100 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2100 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2101 try:
2101 try:
2102 ui.write(r.revision(r.lookup(rev)))
2102 ui.write(r.revision(r.lookup(rev)))
2103 except KeyError:
2103 except KeyError:
2104 raise error.Abort(_('invalid revision identifier %s') % rev)
2104 raise error.Abort(_('invalid revision identifier %s') % rev)
2105
2105
2106 @command('debugdate',
2106 @command('debugdate',
2107 [('e', 'extended', None, _('try extended date formats'))],
2107 [('e', 'extended', None, _('try extended date formats'))],
2108 _('[-e] DATE [RANGE]'),
2108 _('[-e] DATE [RANGE]'),
2109 norepo=True, optionalrepo=True)
2109 norepo=True, optionalrepo=True)
2110 def debugdate(ui, date, range=None, **opts):
2110 def debugdate(ui, date, range=None, **opts):
2111 """parse and display a date"""
2111 """parse and display a date"""
2112 if opts["extended"]:
2112 if opts["extended"]:
2113 d = util.parsedate(date, util.extendeddateformats)
2113 d = util.parsedate(date, util.extendeddateformats)
2114 else:
2114 else:
2115 d = util.parsedate(date)
2115 d = util.parsedate(date)
2116 ui.write(("internal: %s %s\n") % d)
2116 ui.write(("internal: %s %s\n") % d)
2117 ui.write(("standard: %s\n") % util.datestr(d))
2117 ui.write(("standard: %s\n") % util.datestr(d))
2118 if range:
2118 if range:
2119 m = util.matchdate(range)
2119 m = util.matchdate(range)
2120 ui.write(("match: %s\n") % m(d[0]))
2120 ui.write(("match: %s\n") % m(d[0]))
2121
2121
2122 @command('debugdiscovery',
2122 @command('debugdiscovery',
2123 [('', 'old', None, _('use old-style discovery')),
2123 [('', 'old', None, _('use old-style discovery')),
2124 ('', 'nonheads', None,
2124 ('', 'nonheads', None,
2125 _('use old-style discovery with non-heads included')),
2125 _('use old-style discovery with non-heads included')),
2126 ] + remoteopts,
2126 ] + remoteopts,
2127 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2127 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2128 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2128 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2129 """runs the changeset discovery protocol in isolation"""
2129 """runs the changeset discovery protocol in isolation"""
2130 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2130 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2131 opts.get('branch'))
2131 opts.get('branch'))
2132 remote = hg.peer(repo, opts, remoteurl)
2132 remote = hg.peer(repo, opts, remoteurl)
2133 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2133 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2134
2134
2135 # make sure tests are repeatable
2135 # make sure tests are repeatable
2136 random.seed(12323)
2136 random.seed(12323)
2137
2137
2138 def doit(localheads, remoteheads, remote=remote):
2138 def doit(localheads, remoteheads, remote=remote):
2139 if opts.get('old'):
2139 if opts.get('old'):
2140 if localheads:
2140 if localheads:
2141 raise error.Abort('cannot use localheads with old style '
2141 raise error.Abort('cannot use localheads with old style '
2142 'discovery')
2142 'discovery')
2143 if not util.safehasattr(remote, 'branches'):
2143 if not util.safehasattr(remote, 'branches'):
2144 # enable in-client legacy support
2144 # enable in-client legacy support
2145 remote = localrepo.locallegacypeer(remote.local())
2145 remote = localrepo.locallegacypeer(remote.local())
2146 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2146 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2147 force=True)
2147 force=True)
2148 common = set(common)
2148 common = set(common)
2149 if not opts.get('nonheads'):
2149 if not opts.get('nonheads'):
2150 ui.write(("unpruned common: %s\n") %
2150 ui.write(("unpruned common: %s\n") %
2151 " ".join(sorted(short(n) for n in common)))
2151 " ".join(sorted(short(n) for n in common)))
2152 dag = dagutil.revlogdag(repo.changelog)
2152 dag = dagutil.revlogdag(repo.changelog)
2153 all = dag.ancestorset(dag.internalizeall(common))
2153 all = dag.ancestorset(dag.internalizeall(common))
2154 common = dag.externalizeall(dag.headsetofconnecteds(all))
2154 common = dag.externalizeall(dag.headsetofconnecteds(all))
2155 else:
2155 else:
2156 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2156 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2157 common = set(common)
2157 common = set(common)
2158 rheads = set(hds)
2158 rheads = set(hds)
2159 lheads = set(repo.heads())
2159 lheads = set(repo.heads())
2160 ui.write(("common heads: %s\n") %
2160 ui.write(("common heads: %s\n") %
2161 " ".join(sorted(short(n) for n in common)))
2161 " ".join(sorted(short(n) for n in common)))
2162 if lheads <= common:
2162 if lheads <= common:
2163 ui.write(("local is subset\n"))
2163 ui.write(("local is subset\n"))
2164 elif rheads <= common:
2164 elif rheads <= common:
2165 ui.write(("remote is subset\n"))
2165 ui.write(("remote is subset\n"))
2166
2166
2167 serverlogs = opts.get('serverlog')
2167 serverlogs = opts.get('serverlog')
2168 if serverlogs:
2168 if serverlogs:
2169 for filename in serverlogs:
2169 for filename in serverlogs:
2170 logfile = open(filename, 'r')
2170 logfile = open(filename, 'r')
2171 try:
2171 try:
2172 line = logfile.readline()
2172 line = logfile.readline()
2173 while line:
2173 while line:
2174 parts = line.strip().split(';')
2174 parts = line.strip().split(';')
2175 op = parts[1]
2175 op = parts[1]
2176 if op == 'cg':
2176 if op == 'cg':
2177 pass
2177 pass
2178 elif op == 'cgss':
2178 elif op == 'cgss':
2179 doit(parts[2].split(' '), parts[3].split(' '))
2179 doit(parts[2].split(' '), parts[3].split(' '))
2180 elif op == 'unb':
2180 elif op == 'unb':
2181 doit(parts[3].split(' '), parts[2].split(' '))
2181 doit(parts[3].split(' '), parts[2].split(' '))
2182 line = logfile.readline()
2182 line = logfile.readline()
2183 finally:
2183 finally:
2184 logfile.close()
2184 logfile.close()
2185
2185
2186 else:
2186 else:
2187 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2187 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2188 opts.get('remote_head'))
2188 opts.get('remote_head'))
2189 localrevs = opts.get('local_head')
2189 localrevs = opts.get('local_head')
2190 doit(localrevs, remoterevs)
2190 doit(localrevs, remoterevs)
2191
2191
2192 @command('debugextensions', formatteropts, [], norepo=True)
2192 @command('debugextensions', formatteropts, [], norepo=True)
2193 def debugextensions(ui, **opts):
2193 def debugextensions(ui, **opts):
2194 '''show information about active extensions'''
2194 '''show information about active extensions'''
2195 exts = extensions.extensions(ui)
2195 exts = extensions.extensions(ui)
2196 fm = ui.formatter('debugextensions', opts)
2196 fm = ui.formatter('debugextensions', opts)
2197 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2197 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2198 extsource = extmod.__file__
2198 extsource = extmod.__file__
2199 exttestedwith = getattr(extmod, 'testedwith', None)
2199 exttestedwith = getattr(extmod, 'testedwith', None)
2200 if exttestedwith is not None:
2200 if exttestedwith is not None:
2201 exttestedwith = exttestedwith.split()
2201 exttestedwith = exttestedwith.split()
2202 extbuglink = getattr(extmod, 'buglink', None)
2202 extbuglink = getattr(extmod, 'buglink', None)
2203
2203
2204 fm.startitem()
2204 fm.startitem()
2205
2205
2206 if ui.quiet or ui.verbose:
2206 if ui.quiet or ui.verbose:
2207 fm.write('name', '%s\n', extname)
2207 fm.write('name', '%s\n', extname)
2208 else:
2208 else:
2209 fm.write('name', '%s', extname)
2209 fm.write('name', '%s', extname)
2210 if not exttestedwith:
2210 if not exttestedwith:
2211 fm.plain(_(' (untested!)\n'))
2211 fm.plain(_(' (untested!)\n'))
2212 else:
2212 else:
2213 if exttestedwith == ['internal'] or \
2213 if exttestedwith == ['internal'] or \
2214 util.version() in exttestedwith:
2214 util.version() in exttestedwith:
2215 fm.plain('\n')
2215 fm.plain('\n')
2216 else:
2216 else:
2217 lasttestedversion = exttestedwith[-1]
2217 lasttestedversion = exttestedwith[-1]
2218 fm.plain(' (%s!)\n' % lasttestedversion)
2218 fm.plain(' (%s!)\n' % lasttestedversion)
2219
2219
2220 fm.condwrite(ui.verbose and extsource, 'source',
2220 fm.condwrite(ui.verbose and extsource, 'source',
2221 _(' location: %s\n'), extsource or "")
2221 _(' location: %s\n'), extsource or "")
2222
2222
2223 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2223 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2224 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2224 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2225
2225
2226 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2226 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2227 _(' bug reporting: %s\n'), extbuglink or "")
2227 _(' bug reporting: %s\n'), extbuglink or "")
2228
2228
2229 fm.end()
2229 fm.end()
2230
2230
2231 @command('debugfileset',
2231 @command('debugfileset',
2232 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2232 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2233 _('[-r REV] FILESPEC'))
2233 _('[-r REV] FILESPEC'))
2234 def debugfileset(ui, repo, expr, **opts):
2234 def debugfileset(ui, repo, expr, **opts):
2235 '''parse and apply a fileset specification'''
2235 '''parse and apply a fileset specification'''
2236 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2236 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2237 if ui.verbose:
2237 if ui.verbose:
2238 tree = fileset.parse(expr)
2238 tree = fileset.parse(expr)
2239 ui.note(fileset.prettyformat(tree), "\n")
2239 ui.note(fileset.prettyformat(tree), "\n")
2240
2240
2241 for f in ctx.getfileset(expr):
2241 for f in ctx.getfileset(expr):
2242 ui.write("%s\n" % f)
2242 ui.write("%s\n" % f)
2243
2243
2244 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2244 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2245 def debugfsinfo(ui, path="."):
2245 def debugfsinfo(ui, path="."):
2246 """show information detected about current filesystem"""
2246 """show information detected about current filesystem"""
2247 util.writefile('.debugfsinfo', '')
2247 util.writefile('.debugfsinfo', '')
2248 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2248 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2249 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2249 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2250 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2250 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2251 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2251 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2252 and 'yes' or 'no'))
2252 and 'yes' or 'no'))
2253 os.unlink('.debugfsinfo')
2253 os.unlink('.debugfsinfo')
2254
2254
2255 @command('debuggetbundle',
2255 @command('debuggetbundle',
2256 [('H', 'head', [], _('id of head node'), _('ID')),
2256 [('H', 'head', [], _('id of head node'), _('ID')),
2257 ('C', 'common', [], _('id of common node'), _('ID')),
2257 ('C', 'common', [], _('id of common node'), _('ID')),
2258 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2258 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2259 _('REPO FILE [-H|-C ID]...'),
2259 _('REPO FILE [-H|-C ID]...'),
2260 norepo=True)
2260 norepo=True)
2261 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2261 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2262 """retrieves a bundle from a repo
2262 """retrieves a bundle from a repo
2263
2263
2264 Every ID must be a full-length hex node id string. Saves the bundle to the
2264 Every ID must be a full-length hex node id string. Saves the bundle to the
2265 given file.
2265 given file.
2266 """
2266 """
2267 repo = hg.peer(ui, opts, repopath)
2267 repo = hg.peer(ui, opts, repopath)
2268 if not repo.capable('getbundle'):
2268 if not repo.capable('getbundle'):
2269 raise error.Abort("getbundle() not supported by target repository")
2269 raise error.Abort("getbundle() not supported by target repository")
2270 args = {}
2270 args = {}
2271 if common:
2271 if common:
2272 args['common'] = [bin(s) for s in common]
2272 args['common'] = [bin(s) for s in common]
2273 if head:
2273 if head:
2274 args['heads'] = [bin(s) for s in head]
2274 args['heads'] = [bin(s) for s in head]
2275 # TODO: get desired bundlecaps from command line.
2275 # TODO: get desired bundlecaps from command line.
2276 args['bundlecaps'] = None
2276 args['bundlecaps'] = None
2277 bundle = repo.getbundle('debug', **args)
2277 bundle = repo.getbundle('debug', **args)
2278
2278
2279 bundletype = opts.get('type', 'bzip2').lower()
2279 bundletype = opts.get('type', 'bzip2').lower()
2280 btypes = {'none': 'HG10UN',
2280 btypes = {'none': 'HG10UN',
2281 'bzip2': 'HG10BZ',
2281 'bzip2': 'HG10BZ',
2282 'gzip': 'HG10GZ',
2282 'gzip': 'HG10GZ',
2283 'bundle2': 'HG20'}
2283 'bundle2': 'HG20'}
2284 bundletype = btypes.get(bundletype)
2284 bundletype = btypes.get(bundletype)
2285 if bundletype not in changegroup.bundletypes:
2285 if bundletype not in changegroup.bundletypes:
2286 raise error.Abort(_('unknown bundle type specified with --type'))
2286 raise error.Abort(_('unknown bundle type specified with --type'))
2287 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2287 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2288
2288
2289 @command('debugignore', [], '')
2289 @command('debugignore', [], '')
2290 def debugignore(ui, repo, *values, **opts):
2290 def debugignore(ui, repo, *values, **opts):
2291 """display the combined ignore pattern"""
2291 """display the combined ignore pattern"""
2292 ignore = repo.dirstate._ignore
2292 ignore = repo.dirstate._ignore
2293 includepat = getattr(ignore, 'includepat', None)
2293 includepat = getattr(ignore, 'includepat', None)
2294 if includepat is not None:
2294 if includepat is not None:
2295 ui.write("%s\n" % includepat)
2295 ui.write("%s\n" % includepat)
2296 else:
2296 else:
2297 raise error.Abort(_("no ignore patterns found"))
2297 raise error.Abort(_("no ignore patterns found"))
2298
2298
2299 @command('debugindex',
2299 @command('debugindex',
2300 [('c', 'changelog', False, _('open changelog')),
2300 [('c', 'changelog', False, _('open changelog')),
2301 ('m', 'manifest', False, _('open manifest')),
2301 ('m', 'manifest', False, _('open manifest')),
2302 ('', 'dir', False, _('open directory manifest')),
2302 ('', 'dir', False, _('open directory manifest')),
2303 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2303 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2304 _('[-f FORMAT] -c|-m|FILE'),
2304 _('[-f FORMAT] -c|-m|FILE'),
2305 optionalrepo=True)
2305 optionalrepo=True)
2306 def debugindex(ui, repo, file_=None, **opts):
2306 def debugindex(ui, repo, file_=None, **opts):
2307 """dump the contents of an index file"""
2307 """dump the contents of an index file"""
2308 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2308 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2309 format = opts.get('format', 0)
2309 format = opts.get('format', 0)
2310 if format not in (0, 1):
2310 if format not in (0, 1):
2311 raise error.Abort(_("unknown format %d") % format)
2311 raise error.Abort(_("unknown format %d") % format)
2312
2312
2313 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2313 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2314 if generaldelta:
2314 if generaldelta:
2315 basehdr = ' delta'
2315 basehdr = ' delta'
2316 else:
2316 else:
2317 basehdr = ' base'
2317 basehdr = ' base'
2318
2318
2319 if ui.debugflag:
2319 if ui.debugflag:
2320 shortfn = hex
2320 shortfn = hex
2321 else:
2321 else:
2322 shortfn = short
2322 shortfn = short
2323
2323
2324 # There might not be anything in r, so have a sane default
2324 # There might not be anything in r, so have a sane default
2325 idlen = 12
2325 idlen = 12
2326 for i in r:
2326 for i in r:
2327 idlen = len(shortfn(r.node(i)))
2327 idlen = len(shortfn(r.node(i)))
2328 break
2328 break
2329
2329
2330 if format == 0:
2330 if format == 0:
2331 ui.write(" rev offset length " + basehdr + " linkrev"
2331 ui.write(" rev offset length " + basehdr + " linkrev"
2332 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2332 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2333 elif format == 1:
2333 elif format == 1:
2334 ui.write(" rev flag offset length"
2334 ui.write(" rev flag offset length"
2335 " size " + basehdr + " link p1 p2"
2335 " size " + basehdr + " link p1 p2"
2336 " %s\n" % "nodeid".rjust(idlen))
2336 " %s\n" % "nodeid".rjust(idlen))
2337
2337
2338 for i in r:
2338 for i in r:
2339 node = r.node(i)
2339 node = r.node(i)
2340 if generaldelta:
2340 if generaldelta:
2341 base = r.deltaparent(i)
2341 base = r.deltaparent(i)
2342 else:
2342 else:
2343 base = r.chainbase(i)
2343 base = r.chainbase(i)
2344 if format == 0:
2344 if format == 0:
2345 try:
2345 try:
2346 pp = r.parents(node)
2346 pp = r.parents(node)
2347 except Exception:
2347 except Exception:
2348 pp = [nullid, nullid]
2348 pp = [nullid, nullid]
2349 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2349 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2350 i, r.start(i), r.length(i), base, r.linkrev(i),
2350 i, r.start(i), r.length(i), base, r.linkrev(i),
2351 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2351 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2352 elif format == 1:
2352 elif format == 1:
2353 pr = r.parentrevs(i)
2353 pr = r.parentrevs(i)
2354 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2354 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2355 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2355 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2356 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2356 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2357
2357
2358 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2358 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2359 def debugindexdot(ui, repo, file_):
2359 def debugindexdot(ui, repo, file_):
2360 """dump an index DAG as a graphviz dot file"""
2360 """dump an index DAG as a graphviz dot file"""
2361 r = None
2361 r = None
2362 if repo:
2362 if repo:
2363 filelog = repo.file(file_)
2363 filelog = repo.file(file_)
2364 if len(filelog):
2364 if len(filelog):
2365 r = filelog
2365 r = filelog
2366 if not r:
2366 if not r:
2367 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2367 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2368 ui.write(("digraph G {\n"))
2368 ui.write(("digraph G {\n"))
2369 for i in r:
2369 for i in r:
2370 node = r.node(i)
2370 node = r.node(i)
2371 pp = r.parents(node)
2371 pp = r.parents(node)
2372 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2372 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2373 if pp[1] != nullid:
2373 if pp[1] != nullid:
2374 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2374 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2375 ui.write("}\n")
2375 ui.write("}\n")
2376
2376
2377 @command('debuginstall', [], '', norepo=True)
2377 @command('debuginstall', [], '', norepo=True)
2378 def debuginstall(ui):
2378 def debuginstall(ui):
2379 '''test Mercurial installation
2379 '''test Mercurial installation
2380
2380
2381 Returns 0 on success.
2381 Returns 0 on success.
2382 '''
2382 '''
2383
2383
2384 def writetemp(contents):
2384 def writetemp(contents):
2385 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2385 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2386 f = os.fdopen(fd, "wb")
2386 f = os.fdopen(fd, "wb")
2387 f.write(contents)
2387 f.write(contents)
2388 f.close()
2388 f.close()
2389 return name
2389 return name
2390
2390
2391 problems = 0
2391 problems = 0
2392
2392
2393 # encoding
2393 # encoding
2394 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2394 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2395 try:
2395 try:
2396 encoding.fromlocal("test")
2396 encoding.fromlocal("test")
2397 except error.Abort as inst:
2397 except error.Abort as inst:
2398 ui.write(" %s\n" % inst)
2398 ui.write(" %s\n" % inst)
2399 ui.write(_(" (check that your locale is properly set)\n"))
2399 ui.write(_(" (check that your locale is properly set)\n"))
2400 problems += 1
2400 problems += 1
2401
2401
2402 # Python
2402 # Python
2403 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2403 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2404 ui.status(_("checking Python version (%s)\n")
2404 ui.status(_("checking Python version (%s)\n")
2405 % ("%s.%s.%s" % sys.version_info[:3]))
2405 % ("%s.%s.%s" % sys.version_info[:3]))
2406 ui.status(_("checking Python lib (%s)...\n")
2406 ui.status(_("checking Python lib (%s)...\n")
2407 % os.path.dirname(os.__file__))
2407 % os.path.dirname(os.__file__))
2408
2408
2409 # compiled modules
2409 # compiled modules
2410 ui.status(_("checking installed modules (%s)...\n")
2410 ui.status(_("checking installed modules (%s)...\n")
2411 % os.path.dirname(__file__))
2411 % os.path.dirname(__file__))
2412 try:
2412 try:
2413 import bdiff, mpatch, base85, osutil
2413 import bdiff, mpatch, base85, osutil
2414 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2414 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2415 except Exception as inst:
2415 except Exception as inst:
2416 ui.write(" %s\n" % inst)
2416 ui.write(" %s\n" % inst)
2417 ui.write(_(" One or more extensions could not be found"))
2417 ui.write(_(" One or more extensions could not be found"))
2418 ui.write(_(" (check that you compiled the extensions)\n"))
2418 ui.write(_(" (check that you compiled the extensions)\n"))
2419 problems += 1
2419 problems += 1
2420
2420
2421 # templates
2421 # templates
2422 import templater
2422 import templater
2423 p = templater.templatepaths()
2423 p = templater.templatepaths()
2424 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2424 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2425 if p:
2425 if p:
2426 m = templater.templatepath("map-cmdline.default")
2426 m = templater.templatepath("map-cmdline.default")
2427 if m:
2427 if m:
2428 # template found, check if it is working
2428 # template found, check if it is working
2429 try:
2429 try:
2430 templater.templater(m)
2430 templater.templater(m)
2431 except Exception as inst:
2431 except Exception as inst:
2432 ui.write(" %s\n" % inst)
2432 ui.write(" %s\n" % inst)
2433 p = None
2433 p = None
2434 else:
2434 else:
2435 ui.write(_(" template 'default' not found\n"))
2435 ui.write(_(" template 'default' not found\n"))
2436 p = None
2436 p = None
2437 else:
2437 else:
2438 ui.write(_(" no template directories found\n"))
2438 ui.write(_(" no template directories found\n"))
2439 if not p:
2439 if not p:
2440 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2440 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2441 problems += 1
2441 problems += 1
2442
2442
2443 # editor
2443 # editor
2444 ui.status(_("checking commit editor...\n"))
2444 ui.status(_("checking commit editor...\n"))
2445 editor = ui.geteditor()
2445 editor = ui.geteditor()
2446 editor = util.expandpath(editor)
2446 editor = util.expandpath(editor)
2447 cmdpath = util.findexe(shlex.split(editor)[0])
2447 cmdpath = util.findexe(shlex.split(editor)[0])
2448 if not cmdpath:
2448 if not cmdpath:
2449 if editor == 'vi':
2449 if editor == 'vi':
2450 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2450 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2451 ui.write(_(" (specify a commit editor in your configuration"
2451 ui.write(_(" (specify a commit editor in your configuration"
2452 " file)\n"))
2452 " file)\n"))
2453 else:
2453 else:
2454 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2454 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2455 ui.write(_(" (specify a commit editor in your configuration"
2455 ui.write(_(" (specify a commit editor in your configuration"
2456 " file)\n"))
2456 " file)\n"))
2457 problems += 1
2457 problems += 1
2458
2458
2459 # check username
2459 # check username
2460 ui.status(_("checking username...\n"))
2460 ui.status(_("checking username...\n"))
2461 try:
2461 try:
2462 ui.username()
2462 ui.username()
2463 except error.Abort as e:
2463 except error.Abort as e:
2464 ui.write(" %s\n" % e)
2464 ui.write(" %s\n" % e)
2465 ui.write(_(" (specify a username in your configuration file)\n"))
2465 ui.write(_(" (specify a username in your configuration file)\n"))
2466 problems += 1
2466 problems += 1
2467
2467
2468 if not problems:
2468 if not problems:
2469 ui.status(_("no problems detected\n"))
2469 ui.status(_("no problems detected\n"))
2470 else:
2470 else:
2471 ui.write(_("%s problems detected,"
2471 ui.write(_("%s problems detected,"
2472 " please check your install!\n") % problems)
2472 " please check your install!\n") % problems)
2473
2473
2474 return problems
2474 return problems
2475
2475
2476 @command('debugknown', [], _('REPO ID...'), norepo=True)
2476 @command('debugknown', [], _('REPO ID...'), norepo=True)
2477 def debugknown(ui, repopath, *ids, **opts):
2477 def debugknown(ui, repopath, *ids, **opts):
2478 """test whether node ids are known to a repo
2478 """test whether node ids are known to a repo
2479
2479
2480 Every ID must be a full-length hex node id string. Returns a list of 0s
2480 Every ID must be a full-length hex node id string. Returns a list of 0s
2481 and 1s indicating unknown/known.
2481 and 1s indicating unknown/known.
2482 """
2482 """
2483 repo = hg.peer(ui, opts, repopath)
2483 repo = hg.peer(ui, opts, repopath)
2484 if not repo.capable('known'):
2484 if not repo.capable('known'):
2485 raise error.Abort("known() not supported by target repository")
2485 raise error.Abort("known() not supported by target repository")
2486 flags = repo.known([bin(s) for s in ids])
2486 flags = repo.known([bin(s) for s in ids])
2487 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2487 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2488
2488
2489 @command('debuglabelcomplete', [], _('LABEL...'))
2489 @command('debuglabelcomplete', [], _('LABEL...'))
2490 def debuglabelcomplete(ui, repo, *args):
2490 def debuglabelcomplete(ui, repo, *args):
2491 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2491 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2492 debugnamecomplete(ui, repo, *args)
2492 debugnamecomplete(ui, repo, *args)
2493
2493
2494 @command('debugmergestate', [], '')
2494 @command('debugmergestate', [], '')
2495 def debugmergestate(ui, repo, *args):
2495 def debugmergestate(ui, repo, *args):
2496 """print merge state
2496 """print merge state
2497
2497
2498 Use --verbose to print out information about whether v1 or v2 merge state
2498 Use --verbose to print out information about whether v1 or v2 merge state
2499 was chosen."""
2499 was chosen."""
2500 def printrecords(version):
2500 def printrecords(version):
2501 ui.write(('* version %s records\n') % version)
2501 ui.write(('* version %s records\n') % version)
2502 if version == 1:
2502 if version == 1:
2503 records = v1records
2503 records = v1records
2504 else:
2504 else:
2505 records = v2records
2505 records = v2records
2506
2506
2507 for rtype, record in records:
2507 for rtype, record in records:
2508 # pretty print some record types
2508 # pretty print some record types
2509 if rtype == 'L':
2509 if rtype == 'L':
2510 ui.write(('local: %s\n') % record)
2510 ui.write(('local: %s\n') % record)
2511 elif rtype == 'O':
2511 elif rtype == 'O':
2512 ui.write(('other: %s\n') % record)
2512 ui.write(('other: %s\n') % record)
2513 elif rtype == 'm':
2513 elif rtype == 'm':
2514 driver, mdstate = record.split('\0', 1)
2514 driver, mdstate = record.split('\0', 1)
2515 ui.write(('merge driver: %s (state "%s")\n')
2515 ui.write(('merge driver: %s (state "%s")\n')
2516 % (driver, mdstate))
2516 % (driver, mdstate))
2517 elif rtype in 'FD':
2517 elif rtype in 'FD':
2518 r = record.split('\0')
2518 r = record.split('\0')
2519 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2519 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2520 if version == 1:
2520 if version == 1:
2521 onode = 'not stored in v1 format'
2521 onode = 'not stored in v1 format'
2522 flags = r[7]
2522 flags = r[7]
2523 else:
2523 else:
2524 onode, flags = r[7:9]
2524 onode, flags = r[7:9]
2525 ui.write(('file: %s (state "%s", hash %s)\n')
2525 ui.write(('file: %s (state "%s", hash %s)\n')
2526 % (f, state, hash))
2526 % (f, state, hash))
2527 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2527 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2528 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2528 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2529 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2529 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2530 else:
2530 else:
2531 ui.write(('unrecognized entry: %s\t%s\n')
2531 ui.write(('unrecognized entry: %s\t%s\n')
2532 % (rtype, record.replace('\0', '\t')))
2532 % (rtype, record.replace('\0', '\t')))
2533
2533
2534 ms = mergemod.mergestate(repo)
2534 ms = mergemod.mergestate(repo)
2535
2535
2536 # sort so that reasonable information is on top
2536 # sort so that reasonable information is on top
2537 v1records = ms._readrecordsv1()
2537 v1records = ms._readrecordsv1()
2538 v2records = ms._readrecordsv2()
2538 v2records = ms._readrecordsv2()
2539 order = 'LOm'
2539 order = 'LOm'
2540 def key(r):
2540 def key(r):
2541 idx = order.find(r[0])
2541 idx = order.find(r[0])
2542 if idx == -1:
2542 if idx == -1:
2543 return (1, r[1])
2543 return (1, r[1])
2544 else:
2544 else:
2545 return (0, idx)
2545 return (0, idx)
2546 v1records.sort(key=key)
2546 v1records.sort(key=key)
2547 v2records.sort(key=key)
2547 v2records.sort(key=key)
2548
2548
2549 if not v1records and not v2records:
2549 if not v1records and not v2records:
2550 ui.write(('no merge state found\n'))
2550 ui.write(('no merge state found\n'))
2551 elif not v2records:
2551 elif not v2records:
2552 ui.note(('no version 2 merge state\n'))
2552 ui.note(('no version 2 merge state\n'))
2553 printrecords(1)
2553 printrecords(1)
2554 elif ms._v1v2match(v1records, v2records):
2554 elif ms._v1v2match(v1records, v2records):
2555 ui.note(('v1 and v2 states match: using v2\n'))
2555 ui.note(('v1 and v2 states match: using v2\n'))
2556 printrecords(2)
2556 printrecords(2)
2557 else:
2557 else:
2558 ui.note(('v1 and v2 states mismatch: using v1\n'))
2558 ui.note(('v1 and v2 states mismatch: using v1\n'))
2559 printrecords(1)
2559 printrecords(1)
2560 if ui.verbose:
2560 if ui.verbose:
2561 printrecords(2)
2561 printrecords(2)
2562
2562
2563 @command('debugnamecomplete', [], _('NAME...'))
2563 @command('debugnamecomplete', [], _('NAME...'))
2564 def debugnamecomplete(ui, repo, *args):
2564 def debugnamecomplete(ui, repo, *args):
2565 '''complete "names" - tags, open branch names, bookmark names'''
2565 '''complete "names" - tags, open branch names, bookmark names'''
2566
2566
2567 names = set()
2567 names = set()
2568 # since we previously only listed open branches, we will handle that
2568 # since we previously only listed open branches, we will handle that
2569 # specially (after this for loop)
2569 # specially (after this for loop)
2570 for name, ns in repo.names.iteritems():
2570 for name, ns in repo.names.iteritems():
2571 if name != 'branches':
2571 if name != 'branches':
2572 names.update(ns.listnames(repo))
2572 names.update(ns.listnames(repo))
2573 names.update(tag for (tag, heads, tip, closed)
2573 names.update(tag for (tag, heads, tip, closed)
2574 in repo.branchmap().iterbranches() if not closed)
2574 in repo.branchmap().iterbranches() if not closed)
2575 completions = set()
2575 completions = set()
2576 if not args:
2576 if not args:
2577 args = ['']
2577 args = ['']
2578 for a in args:
2578 for a in args:
2579 completions.update(n for n in names if n.startswith(a))
2579 completions.update(n for n in names if n.startswith(a))
2580 ui.write('\n'.join(sorted(completions)))
2580 ui.write('\n'.join(sorted(completions)))
2581 ui.write('\n')
2581 ui.write('\n')
2582
2582
2583 @command('debuglocks',
2583 @command('debuglocks',
2584 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2584 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2585 ('W', 'force-wlock', None,
2585 ('W', 'force-wlock', None,
2586 _('free the working state lock (DANGEROUS)'))],
2586 _('free the working state lock (DANGEROUS)'))],
2587 _('[OPTION]...'))
2587 _('[OPTION]...'))
2588 def debuglocks(ui, repo, **opts):
2588 def debuglocks(ui, repo, **opts):
2589 """show or modify state of locks
2589 """show or modify state of locks
2590
2590
2591 By default, this command will show which locks are held. This
2591 By default, this command will show which locks are held. This
2592 includes the user and process holding the lock, the amount of time
2592 includes the user and process holding the lock, the amount of time
2593 the lock has been held, and the machine name where the process is
2593 the lock has been held, and the machine name where the process is
2594 running if it's not local.
2594 running if it's not local.
2595
2595
2596 Locks protect the integrity of Mercurial's data, so should be
2596 Locks protect the integrity of Mercurial's data, so should be
2597 treated with care. System crashes or other interruptions may cause
2597 treated with care. System crashes or other interruptions may cause
2598 locks to not be properly released, though Mercurial will usually
2598 locks to not be properly released, though Mercurial will usually
2599 detect and remove such stale locks automatically.
2599 detect and remove such stale locks automatically.
2600
2600
2601 However, detecting stale locks may not always be possible (for
2601 However, detecting stale locks may not always be possible (for
2602 instance, on a shared filesystem). Removing locks may also be
2602 instance, on a shared filesystem). Removing locks may also be
2603 blocked by filesystem permissions.
2603 blocked by filesystem permissions.
2604
2604
2605 Returns 0 if no locks are held.
2605 Returns 0 if no locks are held.
2606
2606
2607 """
2607 """
2608
2608
2609 if opts.get('force_lock'):
2609 if opts.get('force_lock'):
2610 repo.svfs.unlink('lock')
2610 repo.svfs.unlink('lock')
2611 if opts.get('force_wlock'):
2611 if opts.get('force_wlock'):
2612 repo.vfs.unlink('wlock')
2612 repo.vfs.unlink('wlock')
2613 if opts.get('force_lock') or opts.get('force_lock'):
2613 if opts.get('force_lock') or opts.get('force_lock'):
2614 return 0
2614 return 0
2615
2615
2616 now = time.time()
2616 now = time.time()
2617 held = 0
2617 held = 0
2618
2618
2619 def report(vfs, name, method):
2619 def report(vfs, name, method):
2620 # this causes stale locks to get reaped for more accurate reporting
2620 # this causes stale locks to get reaped for more accurate reporting
2621 try:
2621 try:
2622 l = method(False)
2622 l = method(False)
2623 except error.LockHeld:
2623 except error.LockHeld:
2624 l = None
2624 l = None
2625
2625
2626 if l:
2626 if l:
2627 l.release()
2627 l.release()
2628 else:
2628 else:
2629 try:
2629 try:
2630 stat = vfs.lstat(name)
2630 stat = vfs.lstat(name)
2631 age = now - stat.st_mtime
2631 age = now - stat.st_mtime
2632 user = util.username(stat.st_uid)
2632 user = util.username(stat.st_uid)
2633 locker = vfs.readlock(name)
2633 locker = vfs.readlock(name)
2634 if ":" in locker:
2634 if ":" in locker:
2635 host, pid = locker.split(':')
2635 host, pid = locker.split(':')
2636 if host == socket.gethostname():
2636 if host == socket.gethostname():
2637 locker = 'user %s, process %s' % (user, pid)
2637 locker = 'user %s, process %s' % (user, pid)
2638 else:
2638 else:
2639 locker = 'user %s, process %s, host %s' \
2639 locker = 'user %s, process %s, host %s' \
2640 % (user, pid, host)
2640 % (user, pid, host)
2641 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2641 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2642 return 1
2642 return 1
2643 except OSError as e:
2643 except OSError as e:
2644 if e.errno != errno.ENOENT:
2644 if e.errno != errno.ENOENT:
2645 raise
2645 raise
2646
2646
2647 ui.write("%-6s free\n" % (name + ":"))
2647 ui.write("%-6s free\n" % (name + ":"))
2648 return 0
2648 return 0
2649
2649
2650 held += report(repo.svfs, "lock", repo.lock)
2650 held += report(repo.svfs, "lock", repo.lock)
2651 held += report(repo.vfs, "wlock", repo.wlock)
2651 held += report(repo.vfs, "wlock", repo.wlock)
2652
2652
2653 return held
2653 return held
2654
2654
2655 @command('debugobsolete',
2655 @command('debugobsolete',
2656 [('', 'flags', 0, _('markers flag')),
2656 [('', 'flags', 0, _('markers flag')),
2657 ('', 'record-parents', False,
2657 ('', 'record-parents', False,
2658 _('record parent information for the precursor')),
2658 _('record parent information for the precursor')),
2659 ('r', 'rev', [], _('display markers relevant to REV')),
2659 ('r', 'rev', [], _('display markers relevant to REV')),
2660 ] + commitopts2,
2660 ] + commitopts2,
2661 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2661 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2662 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2662 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2663 """create arbitrary obsolete marker
2663 """create arbitrary obsolete marker
2664
2664
2665 With no arguments, displays the list of obsolescence markers."""
2665 With no arguments, displays the list of obsolescence markers."""
2666
2666
2667 def parsenodeid(s):
2667 def parsenodeid(s):
2668 try:
2668 try:
2669 # We do not use revsingle/revrange functions here to accept
2669 # We do not use revsingle/revrange functions here to accept
2670 # arbitrary node identifiers, possibly not present in the
2670 # arbitrary node identifiers, possibly not present in the
2671 # local repository.
2671 # local repository.
2672 n = bin(s)
2672 n = bin(s)
2673 if len(n) != len(nullid):
2673 if len(n) != len(nullid):
2674 raise TypeError()
2674 raise TypeError()
2675 return n
2675 return n
2676 except TypeError:
2676 except TypeError:
2677 raise error.Abort('changeset references must be full hexadecimal '
2677 raise error.Abort('changeset references must be full hexadecimal '
2678 'node identifiers')
2678 'node identifiers')
2679
2679
2680 if precursor is not None:
2680 if precursor is not None:
2681 if opts['rev']:
2681 if opts['rev']:
2682 raise error.Abort('cannot select revision when creating marker')
2682 raise error.Abort('cannot select revision when creating marker')
2683 metadata = {}
2683 metadata = {}
2684 metadata['user'] = opts['user'] or ui.username()
2684 metadata['user'] = opts['user'] or ui.username()
2685 succs = tuple(parsenodeid(succ) for succ in successors)
2685 succs = tuple(parsenodeid(succ) for succ in successors)
2686 l = repo.lock()
2686 l = repo.lock()
2687 try:
2687 try:
2688 tr = repo.transaction('debugobsolete')
2688 tr = repo.transaction('debugobsolete')
2689 try:
2689 try:
2690 date = opts.get('date')
2690 date = opts.get('date')
2691 if date:
2691 if date:
2692 date = util.parsedate(date)
2692 date = util.parsedate(date)
2693 else:
2693 else:
2694 date = None
2694 date = None
2695 prec = parsenodeid(precursor)
2695 prec = parsenodeid(precursor)
2696 parents = None
2696 parents = None
2697 if opts['record_parents']:
2697 if opts['record_parents']:
2698 if prec not in repo.unfiltered():
2698 if prec not in repo.unfiltered():
2699 raise error.Abort('cannot used --record-parents on '
2699 raise error.Abort('cannot used --record-parents on '
2700 'unknown changesets')
2700 'unknown changesets')
2701 parents = repo.unfiltered()[prec].parents()
2701 parents = repo.unfiltered()[prec].parents()
2702 parents = tuple(p.node() for p in parents)
2702 parents = tuple(p.node() for p in parents)
2703 repo.obsstore.create(tr, prec, succs, opts['flags'],
2703 repo.obsstore.create(tr, prec, succs, opts['flags'],
2704 parents=parents, date=date,
2704 parents=parents, date=date,
2705 metadata=metadata)
2705 metadata=metadata)
2706 tr.close()
2706 tr.close()
2707 except ValueError as exc:
2707 except ValueError as exc:
2708 raise error.Abort(_('bad obsmarker input: %s') % exc)
2708 raise error.Abort(_('bad obsmarker input: %s') % exc)
2709 finally:
2709 finally:
2710 tr.release()
2710 tr.release()
2711 finally:
2711 finally:
2712 l.release()
2712 l.release()
2713 else:
2713 else:
2714 if opts['rev']:
2714 if opts['rev']:
2715 revs = scmutil.revrange(repo, opts['rev'])
2715 revs = scmutil.revrange(repo, opts['rev'])
2716 nodes = [repo[r].node() for r in revs]
2716 nodes = [repo[r].node() for r in revs]
2717 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2717 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2718 markers.sort(key=lambda x: x._data)
2718 markers.sort(key=lambda x: x._data)
2719 else:
2719 else:
2720 markers = obsolete.getmarkers(repo)
2720 markers = obsolete.getmarkers(repo)
2721
2721
2722 for m in markers:
2722 for m in markers:
2723 cmdutil.showmarker(ui, m)
2723 cmdutil.showmarker(ui, m)
2724
2724
2725 @command('debugpathcomplete',
2725 @command('debugpathcomplete',
2726 [('f', 'full', None, _('complete an entire path')),
2726 [('f', 'full', None, _('complete an entire path')),
2727 ('n', 'normal', None, _('show only normal files')),
2727 ('n', 'normal', None, _('show only normal files')),
2728 ('a', 'added', None, _('show only added files')),
2728 ('a', 'added', None, _('show only added files')),
2729 ('r', 'removed', None, _('show only removed files'))],
2729 ('r', 'removed', None, _('show only removed files'))],
2730 _('FILESPEC...'))
2730 _('FILESPEC...'))
2731 def debugpathcomplete(ui, repo, *specs, **opts):
2731 def debugpathcomplete(ui, repo, *specs, **opts):
2732 '''complete part or all of a tracked path
2732 '''complete part or all of a tracked path
2733
2733
2734 This command supports shells that offer path name completion. It
2734 This command supports shells that offer path name completion. It
2735 currently completes only files already known to the dirstate.
2735 currently completes only files already known to the dirstate.
2736
2736
2737 Completion extends only to the next path segment unless
2737 Completion extends only to the next path segment unless
2738 --full is specified, in which case entire paths are used.'''
2738 --full is specified, in which case entire paths are used.'''
2739
2739
2740 def complete(path, acceptable):
2740 def complete(path, acceptable):
2741 dirstate = repo.dirstate
2741 dirstate = repo.dirstate
2742 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2742 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2743 rootdir = repo.root + os.sep
2743 rootdir = repo.root + os.sep
2744 if spec != repo.root and not spec.startswith(rootdir):
2744 if spec != repo.root and not spec.startswith(rootdir):
2745 return [], []
2745 return [], []
2746 if os.path.isdir(spec):
2746 if os.path.isdir(spec):
2747 spec += '/'
2747 spec += '/'
2748 spec = spec[len(rootdir):]
2748 spec = spec[len(rootdir):]
2749 fixpaths = os.sep != '/'
2749 fixpaths = os.sep != '/'
2750 if fixpaths:
2750 if fixpaths:
2751 spec = spec.replace(os.sep, '/')
2751 spec = spec.replace(os.sep, '/')
2752 speclen = len(spec)
2752 speclen = len(spec)
2753 fullpaths = opts['full']
2753 fullpaths = opts['full']
2754 files, dirs = set(), set()
2754 files, dirs = set(), set()
2755 adddir, addfile = dirs.add, files.add
2755 adddir, addfile = dirs.add, files.add
2756 for f, st in dirstate.iteritems():
2756 for f, st in dirstate.iteritems():
2757 if f.startswith(spec) and st[0] in acceptable:
2757 if f.startswith(spec) and st[0] in acceptable:
2758 if fixpaths:
2758 if fixpaths:
2759 f = f.replace('/', os.sep)
2759 f = f.replace('/', os.sep)
2760 if fullpaths:
2760 if fullpaths:
2761 addfile(f)
2761 addfile(f)
2762 continue
2762 continue
2763 s = f.find(os.sep, speclen)
2763 s = f.find(os.sep, speclen)
2764 if s >= 0:
2764 if s >= 0:
2765 adddir(f[:s])
2765 adddir(f[:s])
2766 else:
2766 else:
2767 addfile(f)
2767 addfile(f)
2768 return files, dirs
2768 return files, dirs
2769
2769
2770 acceptable = ''
2770 acceptable = ''
2771 if opts['normal']:
2771 if opts['normal']:
2772 acceptable += 'nm'
2772 acceptable += 'nm'
2773 if opts['added']:
2773 if opts['added']:
2774 acceptable += 'a'
2774 acceptable += 'a'
2775 if opts['removed']:
2775 if opts['removed']:
2776 acceptable += 'r'
2776 acceptable += 'r'
2777 cwd = repo.getcwd()
2777 cwd = repo.getcwd()
2778 if not specs:
2778 if not specs:
2779 specs = ['.']
2779 specs = ['.']
2780
2780
2781 files, dirs = set(), set()
2781 files, dirs = set(), set()
2782 for spec in specs:
2782 for spec in specs:
2783 f, d = complete(spec, acceptable or 'nmar')
2783 f, d = complete(spec, acceptable or 'nmar')
2784 files.update(f)
2784 files.update(f)
2785 dirs.update(d)
2785 dirs.update(d)
2786 files.update(dirs)
2786 files.update(dirs)
2787 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2787 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2788 ui.write('\n')
2788 ui.write('\n')
2789
2789
2790 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2790 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2791 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2791 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2792 '''access the pushkey key/value protocol
2792 '''access the pushkey key/value protocol
2793
2793
2794 With two args, list the keys in the given namespace.
2794 With two args, list the keys in the given namespace.
2795
2795
2796 With five args, set a key to new if it currently is set to old.
2796 With five args, set a key to new if it currently is set to old.
2797 Reports success or failure.
2797 Reports success or failure.
2798 '''
2798 '''
2799
2799
2800 target = hg.peer(ui, {}, repopath)
2800 target = hg.peer(ui, {}, repopath)
2801 if keyinfo:
2801 if keyinfo:
2802 key, old, new = keyinfo
2802 key, old, new = keyinfo
2803 r = target.pushkey(namespace, key, old, new)
2803 r = target.pushkey(namespace, key, old, new)
2804 ui.status(str(r) + '\n')
2804 ui.status(str(r) + '\n')
2805 return not r
2805 return not r
2806 else:
2806 else:
2807 for k, v in sorted(target.listkeys(namespace).iteritems()):
2807 for k, v in sorted(target.listkeys(namespace).iteritems()):
2808 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2808 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2809 v.encode('string-escape')))
2809 v.encode('string-escape')))
2810
2810
2811 @command('debugpvec', [], _('A B'))
2811 @command('debugpvec', [], _('A B'))
2812 def debugpvec(ui, repo, a, b=None):
2812 def debugpvec(ui, repo, a, b=None):
2813 ca = scmutil.revsingle(repo, a)
2813 ca = scmutil.revsingle(repo, a)
2814 cb = scmutil.revsingle(repo, b)
2814 cb = scmutil.revsingle(repo, b)
2815 pa = pvec.ctxpvec(ca)
2815 pa = pvec.ctxpvec(ca)
2816 pb = pvec.ctxpvec(cb)
2816 pb = pvec.ctxpvec(cb)
2817 if pa == pb:
2817 if pa == pb:
2818 rel = "="
2818 rel = "="
2819 elif pa > pb:
2819 elif pa > pb:
2820 rel = ">"
2820 rel = ">"
2821 elif pa < pb:
2821 elif pa < pb:
2822 rel = "<"
2822 rel = "<"
2823 elif pa | pb:
2823 elif pa | pb:
2824 rel = "|"
2824 rel = "|"
2825 ui.write(_("a: %s\n") % pa)
2825 ui.write(_("a: %s\n") % pa)
2826 ui.write(_("b: %s\n") % pb)
2826 ui.write(_("b: %s\n") % pb)
2827 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2827 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2828 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2828 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2829 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2829 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2830 pa.distance(pb), rel))
2830 pa.distance(pb), rel))
2831
2831
2832 @command('debugrebuilddirstate|debugrebuildstate',
2832 @command('debugrebuilddirstate|debugrebuildstate',
2833 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2833 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2834 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2834 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2835 'the working copy parent')),
2835 'the working copy parent')),
2836 ],
2836 ],
2837 _('[-r REV]'))
2837 _('[-r REV]'))
2838 def debugrebuilddirstate(ui, repo, rev, **opts):
2838 def debugrebuilddirstate(ui, repo, rev, **opts):
2839 """rebuild the dirstate as it would look like for the given revision
2839 """rebuild the dirstate as it would look like for the given revision
2840
2840
2841 If no revision is specified the first current parent will be used.
2841 If no revision is specified the first current parent will be used.
2842
2842
2843 The dirstate will be set to the files of the given revision.
2843 The dirstate will be set to the files of the given revision.
2844 The actual working directory content or existing dirstate
2844 The actual working directory content or existing dirstate
2845 information such as adds or removes is not considered.
2845 information such as adds or removes is not considered.
2846
2846
2847 ``minimal`` will only rebuild the dirstate status for files that claim to be
2847 ``minimal`` will only rebuild the dirstate status for files that claim to be
2848 tracked but are not in the parent manifest, or that exist in the parent
2848 tracked but are not in the parent manifest, or that exist in the parent
2849 manifest but are not in the dirstate. It will not change adds, removes, or
2849 manifest but are not in the dirstate. It will not change adds, removes, or
2850 modified files that are in the working copy parent.
2850 modified files that are in the working copy parent.
2851
2851
2852 One use of this command is to make the next :hg:`status` invocation
2852 One use of this command is to make the next :hg:`status` invocation
2853 check the actual file content.
2853 check the actual file content.
2854 """
2854 """
2855 ctx = scmutil.revsingle(repo, rev)
2855 ctx = scmutil.revsingle(repo, rev)
2856 wlock = repo.wlock()
2856 wlock = repo.wlock()
2857 try:
2857 try:
2858 dirstate = repo.dirstate
2858 dirstate = repo.dirstate
2859
2859
2860 # See command doc for what minimal does.
2860 # See command doc for what minimal does.
2861 if opts.get('minimal'):
2861 if opts.get('minimal'):
2862 dirstatefiles = set(dirstate)
2862 dirstatefiles = set(dirstate)
2863 ctxfiles = set(ctx.manifest().keys())
2863 ctxfiles = set(ctx.manifest().keys())
2864 for file in (dirstatefiles | ctxfiles):
2864 for file in (dirstatefiles | ctxfiles):
2865 indirstate = file in dirstatefiles
2865 indirstate = file in dirstatefiles
2866 inctx = file in ctxfiles
2866 inctx = file in ctxfiles
2867
2867
2868 if indirstate and not inctx and dirstate[file] != 'a':
2868 if indirstate and not inctx and dirstate[file] != 'a':
2869 dirstate.drop(file)
2869 dirstate.drop(file)
2870 elif inctx and not indirstate:
2870 elif inctx and not indirstate:
2871 dirstate.normallookup(file)
2871 dirstate.normallookup(file)
2872 else:
2872 else:
2873 dirstate.rebuild(ctx.node(), ctx.manifest())
2873 dirstate.rebuild(ctx.node(), ctx.manifest())
2874 finally:
2874 finally:
2875 wlock.release()
2875 wlock.release()
2876
2876
2877 @command('debugrebuildfncache', [], '')
2877 @command('debugrebuildfncache', [], '')
2878 def debugrebuildfncache(ui, repo):
2878 def debugrebuildfncache(ui, repo):
2879 """rebuild the fncache file"""
2879 """rebuild the fncache file"""
2880 repair.rebuildfncache(ui, repo)
2880 repair.rebuildfncache(ui, repo)
2881
2881
2882 @command('debugrename',
2882 @command('debugrename',
2883 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2883 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2884 _('[-r REV] FILE'))
2884 _('[-r REV] FILE'))
2885 def debugrename(ui, repo, file1, *pats, **opts):
2885 def debugrename(ui, repo, file1, *pats, **opts):
2886 """dump rename information"""
2886 """dump rename information"""
2887
2887
2888 ctx = scmutil.revsingle(repo, opts.get('rev'))
2888 ctx = scmutil.revsingle(repo, opts.get('rev'))
2889 m = scmutil.match(ctx, (file1,) + pats, opts)
2889 m = scmutil.match(ctx, (file1,) + pats, opts)
2890 for abs in ctx.walk(m):
2890 for abs in ctx.walk(m):
2891 fctx = ctx[abs]
2891 fctx = ctx[abs]
2892 o = fctx.filelog().renamed(fctx.filenode())
2892 o = fctx.filelog().renamed(fctx.filenode())
2893 rel = m.rel(abs)
2893 rel = m.rel(abs)
2894 if o:
2894 if o:
2895 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2895 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2896 else:
2896 else:
2897 ui.write(_("%s not renamed\n") % rel)
2897 ui.write(_("%s not renamed\n") % rel)
2898
2898
2899 @command('debugrevlog',
2899 @command('debugrevlog',
2900 [('c', 'changelog', False, _('open changelog')),
2900 [('c', 'changelog', False, _('open changelog')),
2901 ('m', 'manifest', False, _('open manifest')),
2901 ('m', 'manifest', False, _('open manifest')),
2902 ('', 'dir', False, _('open directory manifest')),
2902 ('', 'dir', False, _('open directory manifest')),
2903 ('d', 'dump', False, _('dump index data'))],
2903 ('d', 'dump', False, _('dump index data'))],
2904 _('-c|-m|FILE'),
2904 _('-c|-m|FILE'),
2905 optionalrepo=True)
2905 optionalrepo=True)
2906 def debugrevlog(ui, repo, file_=None, **opts):
2906 def debugrevlog(ui, repo, file_=None, **opts):
2907 """show data and statistics about a revlog"""
2907 """show data and statistics about a revlog"""
2908 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2908 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2909
2909
2910 if opts.get("dump"):
2910 if opts.get("dump"):
2911 numrevs = len(r)
2911 numrevs = len(r)
2912 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2912 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2913 " rawsize totalsize compression heads chainlen\n")
2913 " rawsize totalsize compression heads chainlen\n")
2914 ts = 0
2914 ts = 0
2915 heads = set()
2915 heads = set()
2916
2916
2917 for rev in xrange(numrevs):
2917 for rev in xrange(numrevs):
2918 dbase = r.deltaparent(rev)
2918 dbase = r.deltaparent(rev)
2919 if dbase == -1:
2919 if dbase == -1:
2920 dbase = rev
2920 dbase = rev
2921 cbase = r.chainbase(rev)
2921 cbase = r.chainbase(rev)
2922 clen = r.chainlen(rev)
2922 clen = r.chainlen(rev)
2923 p1, p2 = r.parentrevs(rev)
2923 p1, p2 = r.parentrevs(rev)
2924 rs = r.rawsize(rev)
2924 rs = r.rawsize(rev)
2925 ts = ts + rs
2925 ts = ts + rs
2926 heads -= set(r.parentrevs(rev))
2926 heads -= set(r.parentrevs(rev))
2927 heads.add(rev)
2927 heads.add(rev)
2928 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2928 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2929 "%11d %5d %8d\n" %
2929 "%11d %5d %8d\n" %
2930 (rev, p1, p2, r.start(rev), r.end(rev),
2930 (rev, p1, p2, r.start(rev), r.end(rev),
2931 r.start(dbase), r.start(cbase),
2931 r.start(dbase), r.start(cbase),
2932 r.start(p1), r.start(p2),
2932 r.start(p1), r.start(p2),
2933 rs, ts, ts / r.end(rev), len(heads), clen))
2933 rs, ts, ts / r.end(rev), len(heads), clen))
2934 return 0
2934 return 0
2935
2935
2936 v = r.version
2936 v = r.version
2937 format = v & 0xFFFF
2937 format = v & 0xFFFF
2938 flags = []
2938 flags = []
2939 gdelta = False
2939 gdelta = False
2940 if v & revlog.REVLOGNGINLINEDATA:
2940 if v & revlog.REVLOGNGINLINEDATA:
2941 flags.append('inline')
2941 flags.append('inline')
2942 if v & revlog.REVLOGGENERALDELTA:
2942 if v & revlog.REVLOGGENERALDELTA:
2943 gdelta = True
2943 gdelta = True
2944 flags.append('generaldelta')
2944 flags.append('generaldelta')
2945 if not flags:
2945 if not flags:
2946 flags = ['(none)']
2946 flags = ['(none)']
2947
2947
2948 nummerges = 0
2948 nummerges = 0
2949 numfull = 0
2949 numfull = 0
2950 numprev = 0
2950 numprev = 0
2951 nump1 = 0
2951 nump1 = 0
2952 nump2 = 0
2952 nump2 = 0
2953 numother = 0
2953 numother = 0
2954 nump1prev = 0
2954 nump1prev = 0
2955 nump2prev = 0
2955 nump2prev = 0
2956 chainlengths = []
2956 chainlengths = []
2957
2957
2958 datasize = [None, 0, 0L]
2958 datasize = [None, 0, 0L]
2959 fullsize = [None, 0, 0L]
2959 fullsize = [None, 0, 0L]
2960 deltasize = [None, 0, 0L]
2960 deltasize = [None, 0, 0L]
2961
2961
2962 def addsize(size, l):
2962 def addsize(size, l):
2963 if l[0] is None or size < l[0]:
2963 if l[0] is None or size < l[0]:
2964 l[0] = size
2964 l[0] = size
2965 if size > l[1]:
2965 if size > l[1]:
2966 l[1] = size
2966 l[1] = size
2967 l[2] += size
2967 l[2] += size
2968
2968
2969 numrevs = len(r)
2969 numrevs = len(r)
2970 for rev in xrange(numrevs):
2970 for rev in xrange(numrevs):
2971 p1, p2 = r.parentrevs(rev)
2971 p1, p2 = r.parentrevs(rev)
2972 delta = r.deltaparent(rev)
2972 delta = r.deltaparent(rev)
2973 if format > 0:
2973 if format > 0:
2974 addsize(r.rawsize(rev), datasize)
2974 addsize(r.rawsize(rev), datasize)
2975 if p2 != nullrev:
2975 if p2 != nullrev:
2976 nummerges += 1
2976 nummerges += 1
2977 size = r.length(rev)
2977 size = r.length(rev)
2978 if delta == nullrev:
2978 if delta == nullrev:
2979 chainlengths.append(0)
2979 chainlengths.append(0)
2980 numfull += 1
2980 numfull += 1
2981 addsize(size, fullsize)
2981 addsize(size, fullsize)
2982 else:
2982 else:
2983 chainlengths.append(chainlengths[delta] + 1)
2983 chainlengths.append(chainlengths[delta] + 1)
2984 addsize(size, deltasize)
2984 addsize(size, deltasize)
2985 if delta == rev - 1:
2985 if delta == rev - 1:
2986 numprev += 1
2986 numprev += 1
2987 if delta == p1:
2987 if delta == p1:
2988 nump1prev += 1
2988 nump1prev += 1
2989 elif delta == p2:
2989 elif delta == p2:
2990 nump2prev += 1
2990 nump2prev += 1
2991 elif delta == p1:
2991 elif delta == p1:
2992 nump1 += 1
2992 nump1 += 1
2993 elif delta == p2:
2993 elif delta == p2:
2994 nump2 += 1
2994 nump2 += 1
2995 elif delta != nullrev:
2995 elif delta != nullrev:
2996 numother += 1
2996 numother += 1
2997
2997
2998 # Adjust size min value for empty cases
2998 # Adjust size min value for empty cases
2999 for size in (datasize, fullsize, deltasize):
2999 for size in (datasize, fullsize, deltasize):
3000 if size[0] is None:
3000 if size[0] is None:
3001 size[0] = 0
3001 size[0] = 0
3002
3002
3003 numdeltas = numrevs - numfull
3003 numdeltas = numrevs - numfull
3004 numoprev = numprev - nump1prev - nump2prev
3004 numoprev = numprev - nump1prev - nump2prev
3005 totalrawsize = datasize[2]
3005 totalrawsize = datasize[2]
3006 datasize[2] /= numrevs
3006 datasize[2] /= numrevs
3007 fulltotal = fullsize[2]
3007 fulltotal = fullsize[2]
3008 fullsize[2] /= numfull
3008 fullsize[2] /= numfull
3009 deltatotal = deltasize[2]
3009 deltatotal = deltasize[2]
3010 if numrevs - numfull > 0:
3010 if numrevs - numfull > 0:
3011 deltasize[2] /= numrevs - numfull
3011 deltasize[2] /= numrevs - numfull
3012 totalsize = fulltotal + deltatotal
3012 totalsize = fulltotal + deltatotal
3013 avgchainlen = sum(chainlengths) / numrevs
3013 avgchainlen = sum(chainlengths) / numrevs
3014 maxchainlen = max(chainlengths)
3014 maxchainlen = max(chainlengths)
3015 compratio = totalrawsize / totalsize
3015 compratio = totalrawsize / totalsize
3016
3016
3017 basedfmtstr = '%%%dd\n'
3017 basedfmtstr = '%%%dd\n'
3018 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3018 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3019
3019
3020 def dfmtstr(max):
3020 def dfmtstr(max):
3021 return basedfmtstr % len(str(max))
3021 return basedfmtstr % len(str(max))
3022 def pcfmtstr(max, padding=0):
3022 def pcfmtstr(max, padding=0):
3023 return basepcfmtstr % (len(str(max)), ' ' * padding)
3023 return basepcfmtstr % (len(str(max)), ' ' * padding)
3024
3024
3025 def pcfmt(value, total):
3025 def pcfmt(value, total):
3026 return (value, 100 * float(value) / total)
3026 return (value, 100 * float(value) / total)
3027
3027
3028 ui.write(('format : %d\n') % format)
3028 ui.write(('format : %d\n') % format)
3029 ui.write(('flags : %s\n') % ', '.join(flags))
3029 ui.write(('flags : %s\n') % ', '.join(flags))
3030
3030
3031 ui.write('\n')
3031 ui.write('\n')
3032 fmt = pcfmtstr(totalsize)
3032 fmt = pcfmtstr(totalsize)
3033 fmt2 = dfmtstr(totalsize)
3033 fmt2 = dfmtstr(totalsize)
3034 ui.write(('revisions : ') + fmt2 % numrevs)
3034 ui.write(('revisions : ') + fmt2 % numrevs)
3035 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3035 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3036 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3036 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3037 ui.write(('revisions : ') + fmt2 % numrevs)
3037 ui.write(('revisions : ') + fmt2 % numrevs)
3038 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3038 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3039 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3039 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3040 ui.write(('revision size : ') + fmt2 % totalsize)
3040 ui.write(('revision size : ') + fmt2 % totalsize)
3041 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3041 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3042 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3042 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3043
3043
3044 ui.write('\n')
3044 ui.write('\n')
3045 fmt = dfmtstr(max(avgchainlen, compratio))
3045 fmt = dfmtstr(max(avgchainlen, compratio))
3046 ui.write(('avg chain length : ') + fmt % avgchainlen)
3046 ui.write(('avg chain length : ') + fmt % avgchainlen)
3047 ui.write(('max chain length : ') + fmt % maxchainlen)
3047 ui.write(('max chain length : ') + fmt % maxchainlen)
3048 ui.write(('compression ratio : ') + fmt % compratio)
3048 ui.write(('compression ratio : ') + fmt % compratio)
3049
3049
3050 if format > 0:
3050 if format > 0:
3051 ui.write('\n')
3051 ui.write('\n')
3052 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3052 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3053 % tuple(datasize))
3053 % tuple(datasize))
3054 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3054 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3055 % tuple(fullsize))
3055 % tuple(fullsize))
3056 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3056 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3057 % tuple(deltasize))
3057 % tuple(deltasize))
3058
3058
3059 if numdeltas > 0:
3059 if numdeltas > 0:
3060 ui.write('\n')
3060 ui.write('\n')
3061 fmt = pcfmtstr(numdeltas)
3061 fmt = pcfmtstr(numdeltas)
3062 fmt2 = pcfmtstr(numdeltas, 4)
3062 fmt2 = pcfmtstr(numdeltas, 4)
3063 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3063 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3064 if numprev > 0:
3064 if numprev > 0:
3065 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3065 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3066 numprev))
3066 numprev))
3067 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3067 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3068 numprev))
3068 numprev))
3069 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3069 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3070 numprev))
3070 numprev))
3071 if gdelta:
3071 if gdelta:
3072 ui.write(('deltas against p1 : ')
3072 ui.write(('deltas against p1 : ')
3073 + fmt % pcfmt(nump1, numdeltas))
3073 + fmt % pcfmt(nump1, numdeltas))
3074 ui.write(('deltas against p2 : ')
3074 ui.write(('deltas against p2 : ')
3075 + fmt % pcfmt(nump2, numdeltas))
3075 + fmt % pcfmt(nump2, numdeltas))
3076 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3076 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3077 numdeltas))
3077 numdeltas))
3078
3078
3079 @command('debugrevspec',
3079 @command('debugrevspec',
3080 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3080 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3081 ('REVSPEC'))
3081 ('REVSPEC'))
3082 def debugrevspec(ui, repo, expr, **opts):
3082 def debugrevspec(ui, repo, expr, **opts):
3083 """parse and apply a revision specification
3083 """parse and apply a revision specification
3084
3084
3085 Use --verbose to print the parsed tree before and after aliases
3085 Use --verbose to print the parsed tree before and after aliases
3086 expansion.
3086 expansion.
3087 """
3087 """
3088 if ui.verbose:
3088 if ui.verbose:
3089 tree = revset.parse(expr, lookup=repo.__contains__)
3089 tree = revset.parse(expr, lookup=repo.__contains__)
3090 ui.note(revset.prettyformat(tree), "\n")
3090 ui.note(revset.prettyformat(tree), "\n")
3091 newtree = revset.findaliases(ui, tree)
3091 newtree = revset.findaliases(ui, tree)
3092 if newtree != tree:
3092 if newtree != tree:
3093 ui.note(revset.prettyformat(newtree), "\n")
3093 ui.note(revset.prettyformat(newtree), "\n")
3094 tree = newtree
3094 tree = newtree
3095 newtree = revset.foldconcat(tree)
3095 newtree = revset.foldconcat(tree)
3096 if newtree != tree:
3096 if newtree != tree:
3097 ui.note(revset.prettyformat(newtree), "\n")
3097 ui.note(revset.prettyformat(newtree), "\n")
3098 if opts["optimize"]:
3098 if opts["optimize"]:
3099 weight, optimizedtree = revset.optimize(newtree, True)
3099 weight, optimizedtree = revset.optimize(newtree, True)
3100 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3100 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3101 func = revset.match(ui, expr, repo)
3101 func = revset.match(ui, expr, repo)
3102 revs = func(repo)
3102 revs = func(repo)
3103 if ui.verbose:
3103 if ui.verbose:
3104 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3104 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3105 for c in revs:
3105 for c in revs:
3106 ui.write("%s\n" % c)
3106 ui.write("%s\n" % c)
3107
3107
3108 @command('debugsetparents', [], _('REV1 [REV2]'))
3108 @command('debugsetparents', [], _('REV1 [REV2]'))
3109 def debugsetparents(ui, repo, rev1, rev2=None):
3109 def debugsetparents(ui, repo, rev1, rev2=None):
3110 """manually set the parents of the current working directory
3110 """manually set the parents of the current working directory
3111
3111
3112 This is useful for writing repository conversion tools, but should
3112 This is useful for writing repository conversion tools, but should
3113 be used with care. For example, neither the working directory nor the
3113 be used with care. For example, neither the working directory nor the
3114 dirstate is updated, so file status may be incorrect after running this
3114 dirstate is updated, so file status may be incorrect after running this
3115 command.
3115 command.
3116
3116
3117 Returns 0 on success.
3117 Returns 0 on success.
3118 """
3118 """
3119
3119
3120 r1 = scmutil.revsingle(repo, rev1).node()
3120 r1 = scmutil.revsingle(repo, rev1).node()
3121 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3121 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3122
3122
3123 wlock = repo.wlock()
3123 wlock = repo.wlock()
3124 try:
3124 try:
3125 repo.dirstate.beginparentchange()
3125 repo.dirstate.beginparentchange()
3126 repo.setparents(r1, r2)
3126 repo.setparents(r1, r2)
3127 repo.dirstate.endparentchange()
3127 repo.dirstate.endparentchange()
3128 finally:
3128 finally:
3129 wlock.release()
3129 wlock.release()
3130
3130
3131 @command('debugdirstate|debugstate',
3131 @command('debugdirstate|debugstate',
3132 [('', 'nodates', None, _('do not display the saved mtime')),
3132 [('', 'nodates', None, _('do not display the saved mtime')),
3133 ('', 'datesort', None, _('sort by saved mtime'))],
3133 ('', 'datesort', None, _('sort by saved mtime'))],
3134 _('[OPTION]...'))
3134 _('[OPTION]...'))
3135 def debugstate(ui, repo, nodates=None, datesort=None):
3135 def debugstate(ui, repo, nodates=None, datesort=None):
3136 """show the contents of the current dirstate"""
3136 """show the contents of the current dirstate"""
3137 timestr = ""
3137 timestr = ""
3138 if datesort:
3138 if datesort:
3139 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3139 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3140 else:
3140 else:
3141 keyfunc = None # sort by filename
3141 keyfunc = None # sort by filename
3142 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3142 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3143 if ent[3] == -1:
3143 if ent[3] == -1:
3144 timestr = 'unset '
3144 timestr = 'unset '
3145 elif nodates:
3145 elif nodates:
3146 timestr = 'set '
3146 timestr = 'set '
3147 else:
3147 else:
3148 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3148 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3149 time.localtime(ent[3]))
3149 time.localtime(ent[3]))
3150 if ent[1] & 0o20000:
3150 if ent[1] & 0o20000:
3151 mode = 'lnk'
3151 mode = 'lnk'
3152 else:
3152 else:
3153 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3153 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3154 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3154 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3155 for f in repo.dirstate.copies():
3155 for f in repo.dirstate.copies():
3156 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3156 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3157
3157
3158 @command('debugsub',
3158 @command('debugsub',
3159 [('r', 'rev', '',
3159 [('r', 'rev', '',
3160 _('revision to check'), _('REV'))],
3160 _('revision to check'), _('REV'))],
3161 _('[-r REV] [REV]'))
3161 _('[-r REV] [REV]'))
3162 def debugsub(ui, repo, rev=None):
3162 def debugsub(ui, repo, rev=None):
3163 ctx = scmutil.revsingle(repo, rev, None)
3163 ctx = scmutil.revsingle(repo, rev, None)
3164 for k, v in sorted(ctx.substate.items()):
3164 for k, v in sorted(ctx.substate.items()):
3165 ui.write(('path %s\n') % k)
3165 ui.write(('path %s\n') % k)
3166 ui.write((' source %s\n') % v[0])
3166 ui.write((' source %s\n') % v[0])
3167 ui.write((' revision %s\n') % v[1])
3167 ui.write((' revision %s\n') % v[1])
3168
3168
3169 @command('debugsuccessorssets',
3169 @command('debugsuccessorssets',
3170 [],
3170 [],
3171 _('[REV]'))
3171 _('[REV]'))
3172 def debugsuccessorssets(ui, repo, *revs):
3172 def debugsuccessorssets(ui, repo, *revs):
3173 """show set of successors for revision
3173 """show set of successors for revision
3174
3174
3175 A successors set of changeset A is a consistent group of revisions that
3175 A successors set of changeset A is a consistent group of revisions that
3176 succeed A. It contains non-obsolete changesets only.
3176 succeed A. It contains non-obsolete changesets only.
3177
3177
3178 In most cases a changeset A has a single successors set containing a single
3178 In most cases a changeset A has a single successors set containing a single
3179 successor (changeset A replaced by A').
3179 successor (changeset A replaced by A').
3180
3180
3181 A changeset that is made obsolete with no successors are called "pruned".
3181 A changeset that is made obsolete with no successors are called "pruned".
3182 Such changesets have no successors sets at all.
3182 Such changesets have no successors sets at all.
3183
3183
3184 A changeset that has been "split" will have a successors set containing
3184 A changeset that has been "split" will have a successors set containing
3185 more than one successor.
3185 more than one successor.
3186
3186
3187 A changeset that has been rewritten in multiple different ways is called
3187 A changeset that has been rewritten in multiple different ways is called
3188 "divergent". Such changesets have multiple successor sets (each of which
3188 "divergent". Such changesets have multiple successor sets (each of which
3189 may also be split, i.e. have multiple successors).
3189 may also be split, i.e. have multiple successors).
3190
3190
3191 Results are displayed as follows::
3191 Results are displayed as follows::
3192
3192
3193 <rev1>
3193 <rev1>
3194 <successors-1A>
3194 <successors-1A>
3195 <rev2>
3195 <rev2>
3196 <successors-2A>
3196 <successors-2A>
3197 <successors-2B1> <successors-2B2> <successors-2B3>
3197 <successors-2B1> <successors-2B2> <successors-2B3>
3198
3198
3199 Here rev2 has two possible (i.e. divergent) successors sets. The first
3199 Here rev2 has two possible (i.e. divergent) successors sets. The first
3200 holds one element, whereas the second holds three (i.e. the changeset has
3200 holds one element, whereas the second holds three (i.e. the changeset has
3201 been split).
3201 been split).
3202 """
3202 """
3203 # passed to successorssets caching computation from one call to another
3203 # passed to successorssets caching computation from one call to another
3204 cache = {}
3204 cache = {}
3205 ctx2str = str
3205 ctx2str = str
3206 node2str = short
3206 node2str = short
3207 if ui.debug():
3207 if ui.debug():
3208 def ctx2str(ctx):
3208 def ctx2str(ctx):
3209 return ctx.hex()
3209 return ctx.hex()
3210 node2str = hex
3210 node2str = hex
3211 for rev in scmutil.revrange(repo, revs):
3211 for rev in scmutil.revrange(repo, revs):
3212 ctx = repo[rev]
3212 ctx = repo[rev]
3213 ui.write('%s\n'% ctx2str(ctx))
3213 ui.write('%s\n'% ctx2str(ctx))
3214 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3214 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3215 if succsset:
3215 if succsset:
3216 ui.write(' ')
3216 ui.write(' ')
3217 ui.write(node2str(succsset[0]))
3217 ui.write(node2str(succsset[0]))
3218 for node in succsset[1:]:
3218 for node in succsset[1:]:
3219 ui.write(' ')
3219 ui.write(' ')
3220 ui.write(node2str(node))
3220 ui.write(node2str(node))
3221 ui.write('\n')
3221 ui.write('\n')
3222
3222
3223 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3223 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3224 def debugwalk(ui, repo, *pats, **opts):
3224 def debugwalk(ui, repo, *pats, **opts):
3225 """show how files match on given patterns"""
3225 """show how files match on given patterns"""
3226 m = scmutil.match(repo[None], pats, opts)
3226 m = scmutil.match(repo[None], pats, opts)
3227 items = list(repo.walk(m))
3227 items = list(repo.walk(m))
3228 if not items:
3228 if not items:
3229 return
3229 return
3230 f = lambda fn: fn
3230 f = lambda fn: fn
3231 if ui.configbool('ui', 'slash') and os.sep != '/':
3231 if ui.configbool('ui', 'slash') and os.sep != '/':
3232 f = lambda fn: util.normpath(fn)
3232 f = lambda fn: util.normpath(fn)
3233 fmt = 'f %%-%ds %%-%ds %%s' % (
3233 fmt = 'f %%-%ds %%-%ds %%s' % (
3234 max([len(abs) for abs in items]),
3234 max([len(abs) for abs in items]),
3235 max([len(m.rel(abs)) for abs in items]))
3235 max([len(m.rel(abs)) for abs in items]))
3236 for abs in items:
3236 for abs in items:
3237 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3237 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3238 ui.write("%s\n" % line.rstrip())
3238 ui.write("%s\n" % line.rstrip())
3239
3239
3240 @command('debugwireargs',
3240 @command('debugwireargs',
3241 [('', 'three', '', 'three'),
3241 [('', 'three', '', 'three'),
3242 ('', 'four', '', 'four'),
3242 ('', 'four', '', 'four'),
3243 ('', 'five', '', 'five'),
3243 ('', 'five', '', 'five'),
3244 ] + remoteopts,
3244 ] + remoteopts,
3245 _('REPO [OPTIONS]... [ONE [TWO]]'),
3245 _('REPO [OPTIONS]... [ONE [TWO]]'),
3246 norepo=True)
3246 norepo=True)
3247 def debugwireargs(ui, repopath, *vals, **opts):
3247 def debugwireargs(ui, repopath, *vals, **opts):
3248 repo = hg.peer(ui, opts, repopath)
3248 repo = hg.peer(ui, opts, repopath)
3249 for opt in remoteopts:
3249 for opt in remoteopts:
3250 del opts[opt[1]]
3250 del opts[opt[1]]
3251 args = {}
3251 args = {}
3252 for k, v in opts.iteritems():
3252 for k, v in opts.iteritems():
3253 if v:
3253 if v:
3254 args[k] = v
3254 args[k] = v
3255 # run twice to check that we don't mess up the stream for the next command
3255 # run twice to check that we don't mess up the stream for the next command
3256 res1 = repo.debugwireargs(*vals, **args)
3256 res1 = repo.debugwireargs(*vals, **args)
3257 res2 = repo.debugwireargs(*vals, **args)
3257 res2 = repo.debugwireargs(*vals, **args)
3258 ui.write("%s\n" % res1)
3258 ui.write("%s\n" % res1)
3259 if res1 != res2:
3259 if res1 != res2:
3260 ui.warn("%s\n" % res2)
3260 ui.warn("%s\n" % res2)
3261
3261
3262 @command('^diff',
3262 @command('^diff',
3263 [('r', 'rev', [], _('revision'), _('REV')),
3263 [('r', 'rev', [], _('revision'), _('REV')),
3264 ('c', 'change', '', _('change made by revision'), _('REV'))
3264 ('c', 'change', '', _('change made by revision'), _('REV'))
3265 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3265 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3266 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3266 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3267 inferrepo=True)
3267 inferrepo=True)
3268 def diff(ui, repo, *pats, **opts):
3268 def diff(ui, repo, *pats, **opts):
3269 """diff repository (or selected files)
3269 """diff repository (or selected files)
3270
3270
3271 Show differences between revisions for the specified files.
3271 Show differences between revisions for the specified files.
3272
3272
3273 Differences between files are shown using the unified diff format.
3273 Differences between files are shown using the unified diff format.
3274
3274
3275 .. note::
3275 .. note::
3276
3276
3277 diff may generate unexpected results for merges, as it will
3277 diff may generate unexpected results for merges, as it will
3278 default to comparing against the working directory's first
3278 default to comparing against the working directory's first
3279 parent changeset if no revisions are specified.
3279 parent changeset if no revisions are specified.
3280
3280
3281 When two revision arguments are given, then changes are shown
3281 When two revision arguments are given, then changes are shown
3282 between those revisions. If only one revision is specified then
3282 between those revisions. If only one revision is specified then
3283 that revision is compared to the working directory, and, when no
3283 that revision is compared to the working directory, and, when no
3284 revisions are specified, the working directory files are compared
3284 revisions are specified, the working directory files are compared
3285 to its parent.
3285 to its parent.
3286
3286
3287 Alternatively you can specify -c/--change with a revision to see
3287 Alternatively you can specify -c/--change with a revision to see
3288 the changes in that changeset relative to its first parent.
3288 the changes in that changeset relative to its first parent.
3289
3289
3290 Without the -a/--text option, diff will avoid generating diffs of
3290 Without the -a/--text option, diff will avoid generating diffs of
3291 files it detects as binary. With -a, diff will generate a diff
3291 files it detects as binary. With -a, diff will generate a diff
3292 anyway, probably with undesirable results.
3292 anyway, probably with undesirable results.
3293
3293
3294 Use the -g/--git option to generate diffs in the git extended diff
3294 Use the -g/--git option to generate diffs in the git extended diff
3295 format. For more information, read :hg:`help diffs`.
3295 format. For more information, read :hg:`help diffs`.
3296
3296
3297 .. container:: verbose
3297 .. container:: verbose
3298
3298
3299 Examples:
3299 Examples:
3300
3300
3301 - compare a file in the current working directory to its parent::
3301 - compare a file in the current working directory to its parent::
3302
3302
3303 hg diff foo.c
3303 hg diff foo.c
3304
3304
3305 - compare two historical versions of a directory, with rename info::
3305 - compare two historical versions of a directory, with rename info::
3306
3306
3307 hg diff --git -r 1.0:1.2 lib/
3307 hg diff --git -r 1.0:1.2 lib/
3308
3308
3309 - get change stats relative to the last change on some date::
3309 - get change stats relative to the last change on some date::
3310
3310
3311 hg diff --stat -r "date('may 2')"
3311 hg diff --stat -r "date('may 2')"
3312
3312
3313 - diff all newly-added files that contain a keyword::
3313 - diff all newly-added files that contain a keyword::
3314
3314
3315 hg diff "set:added() and grep(GNU)"
3315 hg diff "set:added() and grep(GNU)"
3316
3316
3317 - compare a revision and its parents::
3317 - compare a revision and its parents::
3318
3318
3319 hg diff -c 9353 # compare against first parent
3319 hg diff -c 9353 # compare against first parent
3320 hg diff -r 9353^:9353 # same using revset syntax
3320 hg diff -r 9353^:9353 # same using revset syntax
3321 hg diff -r 9353^2:9353 # compare against the second parent
3321 hg diff -r 9353^2:9353 # compare against the second parent
3322
3322
3323 Returns 0 on success.
3323 Returns 0 on success.
3324 """
3324 """
3325
3325
3326 revs = opts.get('rev')
3326 revs = opts.get('rev')
3327 change = opts.get('change')
3327 change = opts.get('change')
3328 stat = opts.get('stat')
3328 stat = opts.get('stat')
3329 reverse = opts.get('reverse')
3329 reverse = opts.get('reverse')
3330
3330
3331 if revs and change:
3331 if revs and change:
3332 msg = _('cannot specify --rev and --change at the same time')
3332 msg = _('cannot specify --rev and --change at the same time')
3333 raise error.Abort(msg)
3333 raise error.Abort(msg)
3334 elif change:
3334 elif change:
3335 node2 = scmutil.revsingle(repo, change, None).node()
3335 node2 = scmutil.revsingle(repo, change, None).node()
3336 node1 = repo[node2].p1().node()
3336 node1 = repo[node2].p1().node()
3337 else:
3337 else:
3338 node1, node2 = scmutil.revpair(repo, revs)
3338 node1, node2 = scmutil.revpair(repo, revs)
3339
3339
3340 if reverse:
3340 if reverse:
3341 node1, node2 = node2, node1
3341 node1, node2 = node2, node1
3342
3342
3343 diffopts = patch.diffallopts(ui, opts)
3343 diffopts = patch.diffallopts(ui, opts)
3344 m = scmutil.match(repo[node2], pats, opts)
3344 m = scmutil.match(repo[node2], pats, opts)
3345 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3345 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3346 listsubrepos=opts.get('subrepos'),
3346 listsubrepos=opts.get('subrepos'),
3347 root=opts.get('root'))
3347 root=opts.get('root'))
3348
3348
3349 @command('^export',
3349 @command('^export',
3350 [('o', 'output', '',
3350 [('o', 'output', '',
3351 _('print output to file with formatted name'), _('FORMAT')),
3351 _('print output to file with formatted name'), _('FORMAT')),
3352 ('', 'switch-parent', None, _('diff against the second parent')),
3352 ('', 'switch-parent', None, _('diff against the second parent')),
3353 ('r', 'rev', [], _('revisions to export'), _('REV')),
3353 ('r', 'rev', [], _('revisions to export'), _('REV')),
3354 ] + diffopts,
3354 ] + diffopts,
3355 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3355 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3356 def export(ui, repo, *changesets, **opts):
3356 def export(ui, repo, *changesets, **opts):
3357 """dump the header and diffs for one or more changesets
3357 """dump the header and diffs for one or more changesets
3358
3358
3359 Print the changeset header and diffs for one or more revisions.
3359 Print the changeset header and diffs for one or more revisions.
3360 If no revision is given, the parent of the working directory is used.
3360 If no revision is given, the parent of the working directory is used.
3361
3361
3362 The information shown in the changeset header is: author, date,
3362 The information shown in the changeset header is: author, date,
3363 branch name (if non-default), changeset hash, parent(s) and commit
3363 branch name (if non-default), changeset hash, parent(s) and commit
3364 comment.
3364 comment.
3365
3365
3366 .. note::
3366 .. note::
3367
3367
3368 export may generate unexpected diff output for merge
3368 export may generate unexpected diff output for merge
3369 changesets, as it will compare the merge changeset against its
3369 changesets, as it will compare the merge changeset against its
3370 first parent only.
3370 first parent only.
3371
3371
3372 Output may be to a file, in which case the name of the file is
3372 Output may be to a file, in which case the name of the file is
3373 given using a format string. The formatting rules are as follows:
3373 given using a format string. The formatting rules are as follows:
3374
3374
3375 :``%%``: literal "%" character
3375 :``%%``: literal "%" character
3376 :``%H``: changeset hash (40 hexadecimal digits)
3376 :``%H``: changeset hash (40 hexadecimal digits)
3377 :``%N``: number of patches being generated
3377 :``%N``: number of patches being generated
3378 :``%R``: changeset revision number
3378 :``%R``: changeset revision number
3379 :``%b``: basename of the exporting repository
3379 :``%b``: basename of the exporting repository
3380 :``%h``: short-form changeset hash (12 hexadecimal digits)
3380 :``%h``: short-form changeset hash (12 hexadecimal digits)
3381 :``%m``: first line of the commit message (only alphanumeric characters)
3381 :``%m``: first line of the commit message (only alphanumeric characters)
3382 :``%n``: zero-padded sequence number, starting at 1
3382 :``%n``: zero-padded sequence number, starting at 1
3383 :``%r``: zero-padded changeset revision number
3383 :``%r``: zero-padded changeset revision number
3384
3384
3385 Without the -a/--text option, export will avoid generating diffs
3385 Without the -a/--text option, export will avoid generating diffs
3386 of files it detects as binary. With -a, export will generate a
3386 of files it detects as binary. With -a, export will generate a
3387 diff anyway, probably with undesirable results.
3387 diff anyway, probably with undesirable results.
3388
3388
3389 Use the -g/--git option to generate diffs in the git extended diff
3389 Use the -g/--git option to generate diffs in the git extended diff
3390 format. See :hg:`help diffs` for more information.
3390 format. See :hg:`help diffs` for more information.
3391
3391
3392 With the --switch-parent option, the diff will be against the
3392 With the --switch-parent option, the diff will be against the
3393 second parent. It can be useful to review a merge.
3393 second parent. It can be useful to review a merge.
3394
3394
3395 .. container:: verbose
3395 .. container:: verbose
3396
3396
3397 Examples:
3397 Examples:
3398
3398
3399 - use export and import to transplant a bugfix to the current
3399 - use export and import to transplant a bugfix to the current
3400 branch::
3400 branch::
3401
3401
3402 hg export -r 9353 | hg import -
3402 hg export -r 9353 | hg import -
3403
3403
3404 - export all the changesets between two revisions to a file with
3404 - export all the changesets between two revisions to a file with
3405 rename information::
3405 rename information::
3406
3406
3407 hg export --git -r 123:150 > changes.txt
3407 hg export --git -r 123:150 > changes.txt
3408
3408
3409 - split outgoing changes into a series of patches with
3409 - split outgoing changes into a series of patches with
3410 descriptive names::
3410 descriptive names::
3411
3411
3412 hg export -r "outgoing()" -o "%n-%m.patch"
3412 hg export -r "outgoing()" -o "%n-%m.patch"
3413
3413
3414 Returns 0 on success.
3414 Returns 0 on success.
3415 """
3415 """
3416 changesets += tuple(opts.get('rev', []))
3416 changesets += tuple(opts.get('rev', []))
3417 if not changesets:
3417 if not changesets:
3418 changesets = ['.']
3418 changesets = ['.']
3419 revs = scmutil.revrange(repo, changesets)
3419 revs = scmutil.revrange(repo, changesets)
3420 if not revs:
3420 if not revs:
3421 raise error.Abort(_("export requires at least one changeset"))
3421 raise error.Abort(_("export requires at least one changeset"))
3422 if len(revs) > 1:
3422 if len(revs) > 1:
3423 ui.note(_('exporting patches:\n'))
3423 ui.note(_('exporting patches:\n'))
3424 else:
3424 else:
3425 ui.note(_('exporting patch:\n'))
3425 ui.note(_('exporting patch:\n'))
3426 cmdutil.export(repo, revs, template=opts.get('output'),
3426 cmdutil.export(repo, revs, template=opts.get('output'),
3427 switch_parent=opts.get('switch_parent'),
3427 switch_parent=opts.get('switch_parent'),
3428 opts=patch.diffallopts(ui, opts))
3428 opts=patch.diffallopts(ui, opts))
3429
3429
3430 @command('files',
3430 @command('files',
3431 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3431 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3432 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3432 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3433 ] + walkopts + formatteropts + subrepoopts,
3433 ] + walkopts + formatteropts + subrepoopts,
3434 _('[OPTION]... [PATTERN]...'))
3434 _('[OPTION]... [PATTERN]...'))
3435 def files(ui, repo, *pats, **opts):
3435 def files(ui, repo, *pats, **opts):
3436 """list tracked files
3436 """list tracked files
3437
3437
3438 Print files under Mercurial control in the working directory or
3438 Print files under Mercurial control in the working directory or
3439 specified revision whose names match the given patterns (excluding
3439 specified revision whose names match the given patterns (excluding
3440 removed files).
3440 removed files).
3441
3441
3442 If no patterns are given to match, this command prints the names
3442 If no patterns are given to match, this command prints the names
3443 of all files under Mercurial control in the working directory.
3443 of all files under Mercurial control in the working directory.
3444
3444
3445 .. container:: verbose
3445 .. container:: verbose
3446
3446
3447 Examples:
3447 Examples:
3448
3448
3449 - list all files under the current directory::
3449 - list all files under the current directory::
3450
3450
3451 hg files .
3451 hg files .
3452
3452
3453 - shows sizes and flags for current revision::
3453 - shows sizes and flags for current revision::
3454
3454
3455 hg files -vr .
3455 hg files -vr .
3456
3456
3457 - list all files named README::
3457 - list all files named README::
3458
3458
3459 hg files -I "**/README"
3459 hg files -I "**/README"
3460
3460
3461 - list all binary files::
3461 - list all binary files::
3462
3462
3463 hg files "set:binary()"
3463 hg files "set:binary()"
3464
3464
3465 - find files containing a regular expression::
3465 - find files containing a regular expression::
3466
3466
3467 hg files "set:grep('bob')"
3467 hg files "set:grep('bob')"
3468
3468
3469 - search tracked file contents with xargs and grep::
3469 - search tracked file contents with xargs and grep::
3470
3470
3471 hg files -0 | xargs -0 grep foo
3471 hg files -0 | xargs -0 grep foo
3472
3472
3473 See :hg:`help patterns` and :hg:`help filesets` for more information
3473 See :hg:`help patterns` and :hg:`help filesets` for more information
3474 on specifying file patterns.
3474 on specifying file patterns.
3475
3475
3476 Returns 0 if a match is found, 1 otherwise.
3476 Returns 0 if a match is found, 1 otherwise.
3477
3477
3478 """
3478 """
3479 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3479 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3480
3480
3481 end = '\n'
3481 end = '\n'
3482 if opts.get('print0'):
3482 if opts.get('print0'):
3483 end = '\0'
3483 end = '\0'
3484 fm = ui.formatter('files', opts)
3484 fm = ui.formatter('files', opts)
3485 fmt = '%s' + end
3485 fmt = '%s' + end
3486
3486
3487 m = scmutil.match(ctx, pats, opts)
3487 m = scmutil.match(ctx, pats, opts)
3488 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3488 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3489
3489
3490 fm.end()
3490 fm.end()
3491
3491
3492 return ret
3492 return ret
3493
3493
3494 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3494 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3495 def forget(ui, repo, *pats, **opts):
3495 def forget(ui, repo, *pats, **opts):
3496 """forget the specified files on the next commit
3496 """forget the specified files on the next commit
3497
3497
3498 Mark the specified files so they will no longer be tracked
3498 Mark the specified files so they will no longer be tracked
3499 after the next commit.
3499 after the next commit.
3500
3500
3501 This only removes files from the current branch, not from the
3501 This only removes files from the current branch, not from the
3502 entire project history, and it does not delete them from the
3502 entire project history, and it does not delete them from the
3503 working directory.
3503 working directory.
3504
3504
3505 To delete the file from the working directory, see :hg:`remove`.
3505 To delete the file from the working directory, see :hg:`remove`.
3506
3506
3507 To undo a forget before the next commit, see :hg:`add`.
3507 To undo a forget before the next commit, see :hg:`add`.
3508
3508
3509 .. container:: verbose
3509 .. container:: verbose
3510
3510
3511 Examples:
3511 Examples:
3512
3512
3513 - forget newly-added binary files::
3513 - forget newly-added binary files::
3514
3514
3515 hg forget "set:added() and binary()"
3515 hg forget "set:added() and binary()"
3516
3516
3517 - forget files that would be excluded by .hgignore::
3517 - forget files that would be excluded by .hgignore::
3518
3518
3519 hg forget "set:hgignore()"
3519 hg forget "set:hgignore()"
3520
3520
3521 Returns 0 on success.
3521 Returns 0 on success.
3522 """
3522 """
3523
3523
3524 if not pats:
3524 if not pats:
3525 raise error.Abort(_('no files specified'))
3525 raise error.Abort(_('no files specified'))
3526
3526
3527 m = scmutil.match(repo[None], pats, opts)
3527 m = scmutil.match(repo[None], pats, opts)
3528 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3528 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3529 return rejected and 1 or 0
3529 return rejected and 1 or 0
3530
3530
3531 @command(
3531 @command(
3532 'graft',
3532 'graft',
3533 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3533 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3534 ('c', 'continue', False, _('resume interrupted graft')),
3534 ('c', 'continue', False, _('resume interrupted graft')),
3535 ('e', 'edit', False, _('invoke editor on commit messages')),
3535 ('e', 'edit', False, _('invoke editor on commit messages')),
3536 ('', 'log', None, _('append graft info to log message')),
3536 ('', 'log', None, _('append graft info to log message')),
3537 ('f', 'force', False, _('force graft')),
3537 ('f', 'force', False, _('force graft')),
3538 ('D', 'currentdate', False,
3538 ('D', 'currentdate', False,
3539 _('record the current date as commit date')),
3539 _('record the current date as commit date')),
3540 ('U', 'currentuser', False,
3540 ('U', 'currentuser', False,
3541 _('record the current user as committer'), _('DATE'))]
3541 _('record the current user as committer'), _('DATE'))]
3542 + commitopts2 + mergetoolopts + dryrunopts,
3542 + commitopts2 + mergetoolopts + dryrunopts,
3543 _('[OPTION]... [-r] REV...'))
3543 _('[OPTION]... [-r] REV...'))
3544 def graft(ui, repo, *revs, **opts):
3544 def graft(ui, repo, *revs, **opts):
3545 '''copy changes from other branches onto the current branch
3545 '''copy changes from other branches onto the current branch
3546
3546
3547 This command uses Mercurial's merge logic to copy individual
3547 This command uses Mercurial's merge logic to copy individual
3548 changes from other branches without merging branches in the
3548 changes from other branches without merging branches in the
3549 history graph. This is sometimes known as 'backporting' or
3549 history graph. This is sometimes known as 'backporting' or
3550 'cherry-picking'. By default, graft will copy user, date, and
3550 'cherry-picking'. By default, graft will copy user, date, and
3551 description from the source changesets.
3551 description from the source changesets.
3552
3552
3553 Changesets that are ancestors of the current revision, that have
3553 Changesets that are ancestors of the current revision, that have
3554 already been grafted, or that are merges will be skipped.
3554 already been grafted, or that are merges will be skipped.
3555
3555
3556 If --log is specified, log messages will have a comment appended
3556 If --log is specified, log messages will have a comment appended
3557 of the form::
3557 of the form::
3558
3558
3559 (grafted from CHANGESETHASH)
3559 (grafted from CHANGESETHASH)
3560
3560
3561 If --force is specified, revisions will be grafted even if they
3561 If --force is specified, revisions will be grafted even if they
3562 are already ancestors of or have been grafted to the destination.
3562 are already ancestors of or have been grafted to the destination.
3563 This is useful when the revisions have since been backed out.
3563 This is useful when the revisions have since been backed out.
3564
3564
3565 If a graft merge results in conflicts, the graft process is
3565 If a graft merge results in conflicts, the graft process is
3566 interrupted so that the current merge can be manually resolved.
3566 interrupted so that the current merge can be manually resolved.
3567 Once all conflicts are addressed, the graft process can be
3567 Once all conflicts are addressed, the graft process can be
3568 continued with the -c/--continue option.
3568 continued with the -c/--continue option.
3569
3569
3570 .. note::
3570 .. note::
3571
3571
3572 The -c/--continue option does not reapply earlier options, except
3572 The -c/--continue option does not reapply earlier options, except
3573 for --force.
3573 for --force.
3574
3574
3575 .. container:: verbose
3575 .. container:: verbose
3576
3576
3577 Examples:
3577 Examples:
3578
3578
3579 - copy a single change to the stable branch and edit its description::
3579 - copy a single change to the stable branch and edit its description::
3580
3580
3581 hg update stable
3581 hg update stable
3582 hg graft --edit 9393
3582 hg graft --edit 9393
3583
3583
3584 - graft a range of changesets with one exception, updating dates::
3584 - graft a range of changesets with one exception, updating dates::
3585
3585
3586 hg graft -D "2085::2093 and not 2091"
3586 hg graft -D "2085::2093 and not 2091"
3587
3587
3588 - continue a graft after resolving conflicts::
3588 - continue a graft after resolving conflicts::
3589
3589
3590 hg graft -c
3590 hg graft -c
3591
3591
3592 - show the source of a grafted changeset::
3592 - show the source of a grafted changeset::
3593
3593
3594 hg log --debug -r .
3594 hg log --debug -r .
3595
3595
3596 See :hg:`help revisions` and :hg:`help revsets` for more about
3596 See :hg:`help revisions` and :hg:`help revsets` for more about
3597 specifying revisions.
3597 specifying revisions.
3598
3598
3599 Returns 0 on successful completion.
3599 Returns 0 on successful completion.
3600 '''
3600 '''
3601
3601
3602 revs = list(revs)
3602 revs = list(revs)
3603 revs.extend(opts['rev'])
3603 revs.extend(opts['rev'])
3604
3604
3605 if not opts.get('user') and opts.get('currentuser'):
3605 if not opts.get('user') and opts.get('currentuser'):
3606 opts['user'] = ui.username()
3606 opts['user'] = ui.username()
3607 if not opts.get('date') and opts.get('currentdate'):
3607 if not opts.get('date') and opts.get('currentdate'):
3608 opts['date'] = "%d %d" % util.makedate()
3608 opts['date'] = "%d %d" % util.makedate()
3609
3609
3610 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3610 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3611
3611
3612 cont = False
3612 cont = False
3613 if opts['continue']:
3613 if opts['continue']:
3614 cont = True
3614 cont = True
3615 if revs:
3615 if revs:
3616 raise error.Abort(_("can't specify --continue and revisions"))
3616 raise error.Abort(_("can't specify --continue and revisions"))
3617 # read in unfinished revisions
3617 # read in unfinished revisions
3618 try:
3618 try:
3619 nodes = repo.vfs.read('graftstate').splitlines()
3619 nodes = repo.vfs.read('graftstate').splitlines()
3620 revs = [repo[node].rev() for node in nodes]
3620 revs = [repo[node].rev() for node in nodes]
3621 except IOError as inst:
3621 except IOError as inst:
3622 if inst.errno != errno.ENOENT:
3622 if inst.errno != errno.ENOENT:
3623 raise
3623 raise
3624 raise error.Abort(_("no graft state found, can't continue"))
3624 raise error.Abort(_("no graft state found, can't continue"))
3625 else:
3625 else:
3626 cmdutil.checkunfinished(repo)
3626 cmdutil.checkunfinished(repo)
3627 cmdutil.bailifchanged(repo)
3627 cmdutil.bailifchanged(repo)
3628 if not revs:
3628 if not revs:
3629 raise error.Abort(_('no revisions specified'))
3629 raise error.Abort(_('no revisions specified'))
3630 revs = scmutil.revrange(repo, revs)
3630 revs = scmutil.revrange(repo, revs)
3631
3631
3632 skipped = set()
3632 skipped = set()
3633 # check for merges
3633 # check for merges
3634 for rev in repo.revs('%ld and merge()', revs):
3634 for rev in repo.revs('%ld and merge()', revs):
3635 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3635 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3636 skipped.add(rev)
3636 skipped.add(rev)
3637 revs = [r for r in revs if r not in skipped]
3637 revs = [r for r in revs if r not in skipped]
3638 if not revs:
3638 if not revs:
3639 return -1
3639 return -1
3640
3640
3641 # Don't check in the --continue case, in effect retaining --force across
3641 # Don't check in the --continue case, in effect retaining --force across
3642 # --continues. That's because without --force, any revisions we decided to
3642 # --continues. That's because without --force, any revisions we decided to
3643 # skip would have been filtered out here, so they wouldn't have made their
3643 # skip would have been filtered out here, so they wouldn't have made their
3644 # way to the graftstate. With --force, any revisions we would have otherwise
3644 # way to the graftstate. With --force, any revisions we would have otherwise
3645 # skipped would not have been filtered out, and if they hadn't been applied
3645 # skipped would not have been filtered out, and if they hadn't been applied
3646 # already, they'd have been in the graftstate.
3646 # already, they'd have been in the graftstate.
3647 if not (cont or opts.get('force')):
3647 if not (cont or opts.get('force')):
3648 # check for ancestors of dest branch
3648 # check for ancestors of dest branch
3649 crev = repo['.'].rev()
3649 crev = repo['.'].rev()
3650 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3650 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3651 # Cannot use x.remove(y) on smart set, this has to be a list.
3651 # Cannot use x.remove(y) on smart set, this has to be a list.
3652 # XXX make this lazy in the future
3652 # XXX make this lazy in the future
3653 revs = list(revs)
3653 revs = list(revs)
3654 # don't mutate while iterating, create a copy
3654 # don't mutate while iterating, create a copy
3655 for rev in list(revs):
3655 for rev in list(revs):
3656 if rev in ancestors:
3656 if rev in ancestors:
3657 ui.warn(_('skipping ancestor revision %d:%s\n') %
3657 ui.warn(_('skipping ancestor revision %d:%s\n') %
3658 (rev, repo[rev]))
3658 (rev, repo[rev]))
3659 # XXX remove on list is slow
3659 # XXX remove on list is slow
3660 revs.remove(rev)
3660 revs.remove(rev)
3661 if not revs:
3661 if not revs:
3662 return -1
3662 return -1
3663
3663
3664 # analyze revs for earlier grafts
3664 # analyze revs for earlier grafts
3665 ids = {}
3665 ids = {}
3666 for ctx in repo.set("%ld", revs):
3666 for ctx in repo.set("%ld", revs):
3667 ids[ctx.hex()] = ctx.rev()
3667 ids[ctx.hex()] = ctx.rev()
3668 n = ctx.extra().get('source')
3668 n = ctx.extra().get('source')
3669 if n:
3669 if n:
3670 ids[n] = ctx.rev()
3670 ids[n] = ctx.rev()
3671
3671
3672 # check ancestors for earlier grafts
3672 # check ancestors for earlier grafts
3673 ui.debug('scanning for duplicate grafts\n')
3673 ui.debug('scanning for duplicate grafts\n')
3674
3674
3675 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3675 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3676 ctx = repo[rev]
3676 ctx = repo[rev]
3677 n = ctx.extra().get('source')
3677 n = ctx.extra().get('source')
3678 if n in ids:
3678 if n in ids:
3679 try:
3679 try:
3680 r = repo[n].rev()
3680 r = repo[n].rev()
3681 except error.RepoLookupError:
3681 except error.RepoLookupError:
3682 r = None
3682 r = None
3683 if r in revs:
3683 if r in revs:
3684 ui.warn(_('skipping revision %d:%s '
3684 ui.warn(_('skipping revision %d:%s '
3685 '(already grafted to %d:%s)\n')
3685 '(already grafted to %d:%s)\n')
3686 % (r, repo[r], rev, ctx))
3686 % (r, repo[r], rev, ctx))
3687 revs.remove(r)
3687 revs.remove(r)
3688 elif ids[n] in revs:
3688 elif ids[n] in revs:
3689 if r is None:
3689 if r is None:
3690 ui.warn(_('skipping already grafted revision %d:%s '
3690 ui.warn(_('skipping already grafted revision %d:%s '
3691 '(%d:%s also has unknown origin %s)\n')
3691 '(%d:%s also has unknown origin %s)\n')
3692 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3692 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3693 else:
3693 else:
3694 ui.warn(_('skipping already grafted revision %d:%s '
3694 ui.warn(_('skipping already grafted revision %d:%s '
3695 '(%d:%s also has origin %d:%s)\n')
3695 '(%d:%s also has origin %d:%s)\n')
3696 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3696 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3697 revs.remove(ids[n])
3697 revs.remove(ids[n])
3698 elif ctx.hex() in ids:
3698 elif ctx.hex() in ids:
3699 r = ids[ctx.hex()]
3699 r = ids[ctx.hex()]
3700 ui.warn(_('skipping already grafted revision %d:%s '
3700 ui.warn(_('skipping already grafted revision %d:%s '
3701 '(was grafted from %d:%s)\n') %
3701 '(was grafted from %d:%s)\n') %
3702 (r, repo[r], rev, ctx))
3702 (r, repo[r], rev, ctx))
3703 revs.remove(r)
3703 revs.remove(r)
3704 if not revs:
3704 if not revs:
3705 return -1
3705 return -1
3706
3706
3707 wlock = repo.wlock()
3707 wlock = repo.wlock()
3708 try:
3708 try:
3709 for pos, ctx in enumerate(repo.set("%ld", revs)):
3709 for pos, ctx in enumerate(repo.set("%ld", revs)):
3710 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3710 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3711 ctx.description().split('\n', 1)[0])
3711 ctx.description().split('\n', 1)[0])
3712 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3712 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3713 if names:
3713 if names:
3714 desc += ' (%s)' % ' '.join(names)
3714 desc += ' (%s)' % ' '.join(names)
3715 ui.status(_('grafting %s\n') % desc)
3715 ui.status(_('grafting %s\n') % desc)
3716 if opts.get('dry_run'):
3716 if opts.get('dry_run'):
3717 continue
3717 continue
3718
3718
3719 source = ctx.extra().get('source')
3719 source = ctx.extra().get('source')
3720 extra = {}
3720 extra = {}
3721 if source:
3721 if source:
3722 extra['source'] = source
3722 extra['source'] = source
3723 extra['intermediate-source'] = ctx.hex()
3723 extra['intermediate-source'] = ctx.hex()
3724 else:
3724 else:
3725 extra['source'] = ctx.hex()
3725 extra['source'] = ctx.hex()
3726 user = ctx.user()
3726 user = ctx.user()
3727 if opts.get('user'):
3727 if opts.get('user'):
3728 user = opts['user']
3728 user = opts['user']
3729 date = ctx.date()
3729 date = ctx.date()
3730 if opts.get('date'):
3730 if opts.get('date'):
3731 date = opts['date']
3731 date = opts['date']
3732 message = ctx.description()
3732 message = ctx.description()
3733 if opts.get('log'):
3733 if opts.get('log'):
3734 message += '\n(grafted from %s)' % ctx.hex()
3734 message += '\n(grafted from %s)' % ctx.hex()
3735
3735
3736 # we don't merge the first commit when continuing
3736 # we don't merge the first commit when continuing
3737 if not cont:
3737 if not cont:
3738 # perform the graft merge with p1(rev) as 'ancestor'
3738 # perform the graft merge with p1(rev) as 'ancestor'
3739 try:
3739 try:
3740 # ui.forcemerge is an internal variable, do not document
3740 # ui.forcemerge is an internal variable, do not document
3741 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3741 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3742 'graft')
3742 'graft')
3743 stats = mergemod.graft(repo, ctx, ctx.p1(),
3743 stats = mergemod.graft(repo, ctx, ctx.p1(),
3744 ['local', 'graft'])
3744 ['local', 'graft'])
3745 finally:
3745 finally:
3746 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3746 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3747 # report any conflicts
3747 # report any conflicts
3748 if stats and stats[3] > 0:
3748 if stats and stats[3] > 0:
3749 # write out state for --continue
3749 # write out state for --continue
3750 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3750 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3751 repo.vfs.write('graftstate', ''.join(nodelines))
3751 repo.vfs.write('graftstate', ''.join(nodelines))
3752 raise error.Abort(
3752 raise error.Abort(
3753 _("unresolved conflicts, can't continue"),
3753 _("unresolved conflicts, can't continue"),
3754 hint=_('use hg resolve and hg graft --continue'))
3754 hint=_('use hg resolve and hg graft --continue'))
3755 else:
3755 else:
3756 cont = False
3756 cont = False
3757
3757
3758 # commit
3758 # commit
3759 node = repo.commit(text=message, user=user,
3759 node = repo.commit(text=message, user=user,
3760 date=date, extra=extra, editor=editor)
3760 date=date, extra=extra, editor=editor)
3761 if node is None:
3761 if node is None:
3762 ui.warn(
3762 ui.warn(
3763 _('note: graft of %d:%s created no changes to commit\n') %
3763 _('note: graft of %d:%s created no changes to commit\n') %
3764 (ctx.rev(), ctx))
3764 (ctx.rev(), ctx))
3765 finally:
3765 finally:
3766 wlock.release()
3766 wlock.release()
3767
3767
3768 # remove state when we complete successfully
3768 # remove state when we complete successfully
3769 if not opts.get('dry_run'):
3769 if not opts.get('dry_run'):
3770 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3770 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3771
3771
3772 return 0
3772 return 0
3773
3773
3774 @command('grep',
3774 @command('grep',
3775 [('0', 'print0', None, _('end fields with NUL')),
3775 [('0', 'print0', None, _('end fields with NUL')),
3776 ('', 'all', None, _('print all revisions that match')),
3776 ('', 'all', None, _('print all revisions that match')),
3777 ('a', 'text', None, _('treat all files as text')),
3777 ('a', 'text', None, _('treat all files as text')),
3778 ('f', 'follow', None,
3778 ('f', 'follow', None,
3779 _('follow changeset history,'
3779 _('follow changeset history,'
3780 ' or file history across copies and renames')),
3780 ' or file history across copies and renames')),
3781 ('i', 'ignore-case', None, _('ignore case when matching')),
3781 ('i', 'ignore-case', None, _('ignore case when matching')),
3782 ('l', 'files-with-matches', None,
3782 ('l', 'files-with-matches', None,
3783 _('print only filenames and revisions that match')),
3783 _('print only filenames and revisions that match')),
3784 ('n', 'line-number', None, _('print matching line numbers')),
3784 ('n', 'line-number', None, _('print matching line numbers')),
3785 ('r', 'rev', [],
3785 ('r', 'rev', [],
3786 _('only search files changed within revision range'), _('REV')),
3786 _('only search files changed within revision range'), _('REV')),
3787 ('u', 'user', None, _('list the author (long with -v)')),
3787 ('u', 'user', None, _('list the author (long with -v)')),
3788 ('d', 'date', None, _('list the date (short with -q)')),
3788 ('d', 'date', None, _('list the date (short with -q)')),
3789 ] + walkopts,
3789 ] + walkopts,
3790 _('[OPTION]... PATTERN [FILE]...'),
3790 _('[OPTION]... PATTERN [FILE]...'),
3791 inferrepo=True)
3791 inferrepo=True)
3792 def grep(ui, repo, pattern, *pats, **opts):
3792 def grep(ui, repo, pattern, *pats, **opts):
3793 """search for a pattern in specified files and revisions
3793 """search for a pattern in specified files and revisions
3794
3794
3795 Search revisions of files for a regular expression.
3795 Search revisions of files for a regular expression.
3796
3796
3797 This command behaves differently than Unix grep. It only accepts
3797 This command behaves differently than Unix grep. It only accepts
3798 Python/Perl regexps. It searches repository history, not the
3798 Python/Perl regexps. It searches repository history, not the
3799 working directory. It always prints the revision number in which a
3799 working directory. It always prints the revision number in which a
3800 match appears.
3800 match appears.
3801
3801
3802 By default, grep only prints output for the first revision of a
3802 By default, grep only prints output for the first revision of a
3803 file in which it finds a match. To get it to print every revision
3803 file in which it finds a match. To get it to print every revision
3804 that contains a change in match status ("-" for a match that
3804 that contains a change in match status ("-" for a match that
3805 becomes a non-match, or "+" for a non-match that becomes a match),
3805 becomes a non-match, or "+" for a non-match that becomes a match),
3806 use the --all flag.
3806 use the --all flag.
3807
3807
3808 Returns 0 if a match is found, 1 otherwise.
3808 Returns 0 if a match is found, 1 otherwise.
3809 """
3809 """
3810 reflags = re.M
3810 reflags = re.M
3811 if opts.get('ignore_case'):
3811 if opts.get('ignore_case'):
3812 reflags |= re.I
3812 reflags |= re.I
3813 try:
3813 try:
3814 regexp = util.re.compile(pattern, reflags)
3814 regexp = util.re.compile(pattern, reflags)
3815 except re.error as inst:
3815 except re.error as inst:
3816 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3816 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3817 return 1
3817 return 1
3818 sep, eol = ':', '\n'
3818 sep, eol = ':', '\n'
3819 if opts.get('print0'):
3819 if opts.get('print0'):
3820 sep = eol = '\0'
3820 sep = eol = '\0'
3821
3821
3822 getfile = util.lrucachefunc(repo.file)
3822 getfile = util.lrucachefunc(repo.file)
3823
3823
3824 def matchlines(body):
3824 def matchlines(body):
3825 begin = 0
3825 begin = 0
3826 linenum = 0
3826 linenum = 0
3827 while begin < len(body):
3827 while begin < len(body):
3828 match = regexp.search(body, begin)
3828 match = regexp.search(body, begin)
3829 if not match:
3829 if not match:
3830 break
3830 break
3831 mstart, mend = match.span()
3831 mstart, mend = match.span()
3832 linenum += body.count('\n', begin, mstart) + 1
3832 linenum += body.count('\n', begin, mstart) + 1
3833 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3833 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3834 begin = body.find('\n', mend) + 1 or len(body) + 1
3834 begin = body.find('\n', mend) + 1 or len(body) + 1
3835 lend = begin - 1
3835 lend = begin - 1
3836 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3836 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3837
3837
3838 class linestate(object):
3838 class linestate(object):
3839 def __init__(self, line, linenum, colstart, colend):
3839 def __init__(self, line, linenum, colstart, colend):
3840 self.line = line
3840 self.line = line
3841 self.linenum = linenum
3841 self.linenum = linenum
3842 self.colstart = colstart
3842 self.colstart = colstart
3843 self.colend = colend
3843 self.colend = colend
3844
3844
3845 def __hash__(self):
3845 def __hash__(self):
3846 return hash((self.linenum, self.line))
3846 return hash((self.linenum, self.line))
3847
3847
3848 def __eq__(self, other):
3848 def __eq__(self, other):
3849 return self.line == other.line
3849 return self.line == other.line
3850
3850
3851 def __iter__(self):
3851 def __iter__(self):
3852 yield (self.line[:self.colstart], '')
3852 yield (self.line[:self.colstart], '')
3853 yield (self.line[self.colstart:self.colend], 'grep.match')
3853 yield (self.line[self.colstart:self.colend], 'grep.match')
3854 rest = self.line[self.colend:]
3854 rest = self.line[self.colend:]
3855 while rest != '':
3855 while rest != '':
3856 match = regexp.search(rest)
3856 match = regexp.search(rest)
3857 if not match:
3857 if not match:
3858 yield (rest, '')
3858 yield (rest, '')
3859 break
3859 break
3860 mstart, mend = match.span()
3860 mstart, mend = match.span()
3861 yield (rest[:mstart], '')
3861 yield (rest[:mstart], '')
3862 yield (rest[mstart:mend], 'grep.match')
3862 yield (rest[mstart:mend], 'grep.match')
3863 rest = rest[mend:]
3863 rest = rest[mend:]
3864
3864
3865 matches = {}
3865 matches = {}
3866 copies = {}
3866 copies = {}
3867 def grepbody(fn, rev, body):
3867 def grepbody(fn, rev, body):
3868 matches[rev].setdefault(fn, [])
3868 matches[rev].setdefault(fn, [])
3869 m = matches[rev][fn]
3869 m = matches[rev][fn]
3870 for lnum, cstart, cend, line in matchlines(body):
3870 for lnum, cstart, cend, line in matchlines(body):
3871 s = linestate(line, lnum, cstart, cend)
3871 s = linestate(line, lnum, cstart, cend)
3872 m.append(s)
3872 m.append(s)
3873
3873
3874 def difflinestates(a, b):
3874 def difflinestates(a, b):
3875 sm = difflib.SequenceMatcher(None, a, b)
3875 sm = difflib.SequenceMatcher(None, a, b)
3876 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3876 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3877 if tag == 'insert':
3877 if tag == 'insert':
3878 for i in xrange(blo, bhi):
3878 for i in xrange(blo, bhi):
3879 yield ('+', b[i])
3879 yield ('+', b[i])
3880 elif tag == 'delete':
3880 elif tag == 'delete':
3881 for i in xrange(alo, ahi):
3881 for i in xrange(alo, ahi):
3882 yield ('-', a[i])
3882 yield ('-', a[i])
3883 elif tag == 'replace':
3883 elif tag == 'replace':
3884 for i in xrange(alo, ahi):
3884 for i in xrange(alo, ahi):
3885 yield ('-', a[i])
3885 yield ('-', a[i])
3886 for i in xrange(blo, bhi):
3886 for i in xrange(blo, bhi):
3887 yield ('+', b[i])
3887 yield ('+', b[i])
3888
3888
3889 def display(fn, ctx, pstates, states):
3889 def display(fn, ctx, pstates, states):
3890 rev = ctx.rev()
3890 rev = ctx.rev()
3891 if ui.quiet:
3891 if ui.quiet:
3892 datefunc = util.shortdate
3892 datefunc = util.shortdate
3893 else:
3893 else:
3894 datefunc = util.datestr
3894 datefunc = util.datestr
3895 found = False
3895 found = False
3896 @util.cachefunc
3896 @util.cachefunc
3897 def binary():
3897 def binary():
3898 flog = getfile(fn)
3898 flog = getfile(fn)
3899 return util.binary(flog.read(ctx.filenode(fn)))
3899 return util.binary(flog.read(ctx.filenode(fn)))
3900
3900
3901 if opts.get('all'):
3901 if opts.get('all'):
3902 iter = difflinestates(pstates, states)
3902 iter = difflinestates(pstates, states)
3903 else:
3903 else:
3904 iter = [('', l) for l in states]
3904 iter = [('', l) for l in states]
3905 for change, l in iter:
3905 for change, l in iter:
3906 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3906 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3907
3907
3908 if opts.get('line_number'):
3908 if opts.get('line_number'):
3909 cols.append((str(l.linenum), 'grep.linenumber'))
3909 cols.append((str(l.linenum), 'grep.linenumber'))
3910 if opts.get('all'):
3910 if opts.get('all'):
3911 cols.append((change, 'grep.change'))
3911 cols.append((change, 'grep.change'))
3912 if opts.get('user'):
3912 if opts.get('user'):
3913 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3913 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3914 if opts.get('date'):
3914 if opts.get('date'):
3915 cols.append((datefunc(ctx.date()), 'grep.date'))
3915 cols.append((datefunc(ctx.date()), 'grep.date'))
3916 for col, label in cols[:-1]:
3916 for col, label in cols[:-1]:
3917 ui.write(col, label=label)
3917 ui.write(col, label=label)
3918 ui.write(sep, label='grep.sep')
3918 ui.write(sep, label='grep.sep')
3919 ui.write(cols[-1][0], label=cols[-1][1])
3919 ui.write(cols[-1][0], label=cols[-1][1])
3920 if not opts.get('files_with_matches'):
3920 if not opts.get('files_with_matches'):
3921 ui.write(sep, label='grep.sep')
3921 ui.write(sep, label='grep.sep')
3922 if not opts.get('text') and binary():
3922 if not opts.get('text') and binary():
3923 ui.write(" Binary file matches")
3923 ui.write(" Binary file matches")
3924 else:
3924 else:
3925 for s, label in l:
3925 for s, label in l:
3926 ui.write(s, label=label)
3926 ui.write(s, label=label)
3927 ui.write(eol)
3927 ui.write(eol)
3928 found = True
3928 found = True
3929 if opts.get('files_with_matches'):
3929 if opts.get('files_with_matches'):
3930 break
3930 break
3931 return found
3931 return found
3932
3932
3933 skip = {}
3933 skip = {}
3934 revfiles = {}
3934 revfiles = {}
3935 matchfn = scmutil.match(repo[None], pats, opts)
3935 matchfn = scmutil.match(repo[None], pats, opts)
3936 found = False
3936 found = False
3937 follow = opts.get('follow')
3937 follow = opts.get('follow')
3938
3938
3939 def prep(ctx, fns):
3939 def prep(ctx, fns):
3940 rev = ctx.rev()
3940 rev = ctx.rev()
3941 pctx = ctx.p1()
3941 pctx = ctx.p1()
3942 parent = pctx.rev()
3942 parent = pctx.rev()
3943 matches.setdefault(rev, {})
3943 matches.setdefault(rev, {})
3944 matches.setdefault(parent, {})
3944 matches.setdefault(parent, {})
3945 files = revfiles.setdefault(rev, [])
3945 files = revfiles.setdefault(rev, [])
3946 for fn in fns:
3946 for fn in fns:
3947 flog = getfile(fn)
3947 flog = getfile(fn)
3948 try:
3948 try:
3949 fnode = ctx.filenode(fn)
3949 fnode = ctx.filenode(fn)
3950 except error.LookupError:
3950 except error.LookupError:
3951 continue
3951 continue
3952
3952
3953 copied = flog.renamed(fnode)
3953 copied = flog.renamed(fnode)
3954 copy = follow and copied and copied[0]
3954 copy = follow and copied and copied[0]
3955 if copy:
3955 if copy:
3956 copies.setdefault(rev, {})[fn] = copy
3956 copies.setdefault(rev, {})[fn] = copy
3957 if fn in skip:
3957 if fn in skip:
3958 if copy:
3958 if copy:
3959 skip[copy] = True
3959 skip[copy] = True
3960 continue
3960 continue
3961 files.append(fn)
3961 files.append(fn)
3962
3962
3963 if fn not in matches[rev]:
3963 if fn not in matches[rev]:
3964 grepbody(fn, rev, flog.read(fnode))
3964 grepbody(fn, rev, flog.read(fnode))
3965
3965
3966 pfn = copy or fn
3966 pfn = copy or fn
3967 if pfn not in matches[parent]:
3967 if pfn not in matches[parent]:
3968 try:
3968 try:
3969 fnode = pctx.filenode(pfn)
3969 fnode = pctx.filenode(pfn)
3970 grepbody(pfn, parent, flog.read(fnode))
3970 grepbody(pfn, parent, flog.read(fnode))
3971 except error.LookupError:
3971 except error.LookupError:
3972 pass
3972 pass
3973
3973
3974 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3974 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3975 rev = ctx.rev()
3975 rev = ctx.rev()
3976 parent = ctx.p1().rev()
3976 parent = ctx.p1().rev()
3977 for fn in sorted(revfiles.get(rev, [])):
3977 for fn in sorted(revfiles.get(rev, [])):
3978 states = matches[rev][fn]
3978 states = matches[rev][fn]
3979 copy = copies.get(rev, {}).get(fn)
3979 copy = copies.get(rev, {}).get(fn)
3980 if fn in skip:
3980 if fn in skip:
3981 if copy:
3981 if copy:
3982 skip[copy] = True
3982 skip[copy] = True
3983 continue
3983 continue
3984 pstates = matches.get(parent, {}).get(copy or fn, [])
3984 pstates = matches.get(parent, {}).get(copy or fn, [])
3985 if pstates or states:
3985 if pstates or states:
3986 r = display(fn, ctx, pstates, states)
3986 r = display(fn, ctx, pstates, states)
3987 found = found or r
3987 found = found or r
3988 if r and not opts.get('all'):
3988 if r and not opts.get('all'):
3989 skip[fn] = True
3989 skip[fn] = True
3990 if copy:
3990 if copy:
3991 skip[copy] = True
3991 skip[copy] = True
3992 del matches[rev]
3992 del matches[rev]
3993 del revfiles[rev]
3993 del revfiles[rev]
3994
3994
3995 return not found
3995 return not found
3996
3996
3997 @command('heads',
3997 @command('heads',
3998 [('r', 'rev', '',
3998 [('r', 'rev', '',
3999 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3999 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4000 ('t', 'topo', False, _('show topological heads only')),
4000 ('t', 'topo', False, _('show topological heads only')),
4001 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4001 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4002 ('c', 'closed', False, _('show normal and closed branch heads')),
4002 ('c', 'closed', False, _('show normal and closed branch heads')),
4003 ] + templateopts,
4003 ] + templateopts,
4004 _('[-ct] [-r STARTREV] [REV]...'))
4004 _('[-ct] [-r STARTREV] [REV]...'))
4005 def heads(ui, repo, *branchrevs, **opts):
4005 def heads(ui, repo, *branchrevs, **opts):
4006 """show branch heads
4006 """show branch heads
4007
4007
4008 With no arguments, show all open branch heads in the repository.
4008 With no arguments, show all open branch heads in the repository.
4009 Branch heads are changesets that have no descendants on the
4009 Branch heads are changesets that have no descendants on the
4010 same branch. They are where development generally takes place and
4010 same branch. They are where development generally takes place and
4011 are the usual targets for update and merge operations.
4011 are the usual targets for update and merge operations.
4012
4012
4013 If one or more REVs are given, only open branch heads on the
4013 If one or more REVs are given, only open branch heads on the
4014 branches associated with the specified changesets are shown. This
4014 branches associated with the specified changesets are shown. This
4015 means that you can use :hg:`heads .` to see the heads on the
4015 means that you can use :hg:`heads .` to see the heads on the
4016 currently checked-out branch.
4016 currently checked-out branch.
4017
4017
4018 If -c/--closed is specified, also show branch heads marked closed
4018 If -c/--closed is specified, also show branch heads marked closed
4019 (see :hg:`commit --close-branch`).
4019 (see :hg:`commit --close-branch`).
4020
4020
4021 If STARTREV is specified, only those heads that are descendants of
4021 If STARTREV is specified, only those heads that are descendants of
4022 STARTREV will be displayed.
4022 STARTREV will be displayed.
4023
4023
4024 If -t/--topo is specified, named branch mechanics will be ignored and only
4024 If -t/--topo is specified, named branch mechanics will be ignored and only
4025 topological heads (changesets with no children) will be shown.
4025 topological heads (changesets with no children) will be shown.
4026
4026
4027 Returns 0 if matching heads are found, 1 if not.
4027 Returns 0 if matching heads are found, 1 if not.
4028 """
4028 """
4029
4029
4030 start = None
4030 start = None
4031 if 'rev' in opts:
4031 if 'rev' in opts:
4032 start = scmutil.revsingle(repo, opts['rev'], None).node()
4032 start = scmutil.revsingle(repo, opts['rev'], None).node()
4033
4033
4034 if opts.get('topo'):
4034 if opts.get('topo'):
4035 heads = [repo[h] for h in repo.heads(start)]
4035 heads = [repo[h] for h in repo.heads(start)]
4036 else:
4036 else:
4037 heads = []
4037 heads = []
4038 for branch in repo.branchmap():
4038 for branch in repo.branchmap():
4039 heads += repo.branchheads(branch, start, opts.get('closed'))
4039 heads += repo.branchheads(branch, start, opts.get('closed'))
4040 heads = [repo[h] for h in heads]
4040 heads = [repo[h] for h in heads]
4041
4041
4042 if branchrevs:
4042 if branchrevs:
4043 branches = set(repo[br].branch() for br in branchrevs)
4043 branches = set(repo[br].branch() for br in branchrevs)
4044 heads = [h for h in heads if h.branch() in branches]
4044 heads = [h for h in heads if h.branch() in branches]
4045
4045
4046 if opts.get('active') and branchrevs:
4046 if opts.get('active') and branchrevs:
4047 dagheads = repo.heads(start)
4047 dagheads = repo.heads(start)
4048 heads = [h for h in heads if h.node() in dagheads]
4048 heads = [h for h in heads if h.node() in dagheads]
4049
4049
4050 if branchrevs:
4050 if branchrevs:
4051 haveheads = set(h.branch() for h in heads)
4051 haveheads = set(h.branch() for h in heads)
4052 if branches - haveheads:
4052 if branches - haveheads:
4053 headless = ', '.join(b for b in branches - haveheads)
4053 headless = ', '.join(b for b in branches - haveheads)
4054 msg = _('no open branch heads found on branches %s')
4054 msg = _('no open branch heads found on branches %s')
4055 if opts.get('rev'):
4055 if opts.get('rev'):
4056 msg += _(' (started at %s)') % opts['rev']
4056 msg += _(' (started at %s)') % opts['rev']
4057 ui.warn((msg + '\n') % headless)
4057 ui.warn((msg + '\n') % headless)
4058
4058
4059 if not heads:
4059 if not heads:
4060 return 1
4060 return 1
4061
4061
4062 heads = sorted(heads, key=lambda x: -x.rev())
4062 heads = sorted(heads, key=lambda x: -x.rev())
4063 displayer = cmdutil.show_changeset(ui, repo, opts)
4063 displayer = cmdutil.show_changeset(ui, repo, opts)
4064 for ctx in heads:
4064 for ctx in heads:
4065 displayer.show(ctx)
4065 displayer.show(ctx)
4066 displayer.close()
4066 displayer.close()
4067
4067
4068 @command('help',
4068 @command('help',
4069 [('e', 'extension', None, _('show only help for extensions')),
4069 [('e', 'extension', None, _('show only help for extensions')),
4070 ('c', 'command', None, _('show only help for commands')),
4070 ('c', 'command', None, _('show only help for commands')),
4071 ('k', 'keyword', None, _('show topics matching keyword')),
4071 ('k', 'keyword', None, _('show topics matching keyword')),
4072 ],
4072 ],
4073 _('[-eck] [TOPIC]'),
4073 _('[-eck] [TOPIC]'),
4074 norepo=True)
4074 norepo=True)
4075 def help_(ui, name=None, **opts):
4075 def help_(ui, name=None, **opts):
4076 """show help for a given topic or a help overview
4076 """show help for a given topic or a help overview
4077
4077
4078 With no arguments, print a list of commands with short help messages.
4078 With no arguments, print a list of commands with short help messages.
4079
4079
4080 Given a topic, extension, or command name, print help for that
4080 Given a topic, extension, or command name, print help for that
4081 topic.
4081 topic.
4082
4082
4083 Returns 0 if successful.
4083 Returns 0 if successful.
4084 """
4084 """
4085
4085
4086 textwidth = min(ui.termwidth(), 80) - 2
4086 textwidth = min(ui.termwidth(), 80) - 2
4087
4087
4088 keep = []
4088 keep = []
4089 if ui.verbose:
4089 if ui.verbose:
4090 keep.append('verbose')
4090 keep.append('verbose')
4091 if sys.platform.startswith('win'):
4091 if sys.platform.startswith('win'):
4092 keep.append('windows')
4092 keep.append('windows')
4093 elif sys.platform == 'OpenVMS':
4093 elif sys.platform == 'OpenVMS':
4094 keep.append('vms')
4094 keep.append('vms')
4095 elif sys.platform == 'plan9':
4095 elif sys.platform == 'plan9':
4096 keep.append('plan9')
4096 keep.append('plan9')
4097 else:
4097 else:
4098 keep.append('unix')
4098 keep.append('unix')
4099 keep.append(sys.platform.lower())
4099 keep.append(sys.platform.lower())
4100
4100
4101 section = None
4101 section = None
4102 if name and '.' in name:
4102 if name and '.' in name:
4103 name, section = name.split('.', 1)
4103 name, section = name.split('.', 1)
4104 section = section.lower()
4104 section = section.lower()
4105
4105
4106 text = help.help_(ui, name, **opts)
4106 text = help.help_(ui, name, **opts)
4107
4107
4108 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4108 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4109 section=section)
4109 section=section)
4110
4110
4111 # We could have been given a weird ".foo" section without a name
4111 # We could have been given a weird ".foo" section without a name
4112 # to look for, or we could have simply failed to found "foo.bar"
4112 # to look for, or we could have simply failed to found "foo.bar"
4113 # because bar isn't a section of foo
4113 # because bar isn't a section of foo
4114 if section and not (formatted and name):
4114 if section and not (formatted and name):
4115 raise error.Abort(_("help section not found"))
4115 raise error.Abort(_("help section not found"))
4116
4116
4117 if 'verbose' in pruned:
4117 if 'verbose' in pruned:
4118 keep.append('omitted')
4118 keep.append('omitted')
4119 else:
4119 else:
4120 keep.append('notomitted')
4120 keep.append('notomitted')
4121 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4121 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4122 section=section)
4122 section=section)
4123 ui.write(formatted)
4123 ui.write(formatted)
4124
4124
4125
4125
4126 @command('identify|id',
4126 @command('identify|id',
4127 [('r', 'rev', '',
4127 [('r', 'rev', '',
4128 _('identify the specified revision'), _('REV')),
4128 _('identify the specified revision'), _('REV')),
4129 ('n', 'num', None, _('show local revision number')),
4129 ('n', 'num', None, _('show local revision number')),
4130 ('i', 'id', None, _('show global revision id')),
4130 ('i', 'id', None, _('show global revision id')),
4131 ('b', 'branch', None, _('show branch')),
4131 ('b', 'branch', None, _('show branch')),
4132 ('t', 'tags', None, _('show tags')),
4132 ('t', 'tags', None, _('show tags')),
4133 ('B', 'bookmarks', None, _('show bookmarks')),
4133 ('B', 'bookmarks', None, _('show bookmarks')),
4134 ] + remoteopts,
4134 ] + remoteopts,
4135 _('[-nibtB] [-r REV] [SOURCE]'),
4135 _('[-nibtB] [-r REV] [SOURCE]'),
4136 optionalrepo=True)
4136 optionalrepo=True)
4137 def identify(ui, repo, source=None, rev=None,
4137 def identify(ui, repo, source=None, rev=None,
4138 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4138 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4139 """identify the working directory or specified revision
4139 """identify the working directory or specified revision
4140
4140
4141 Print a summary identifying the repository state at REV using one or
4141 Print a summary identifying the repository state at REV using one or
4142 two parent hash identifiers, followed by a "+" if the working
4142 two parent hash identifiers, followed by a "+" if the working
4143 directory has uncommitted changes, the branch name (if not default),
4143 directory has uncommitted changes, the branch name (if not default),
4144 a list of tags, and a list of bookmarks.
4144 a list of tags, and a list of bookmarks.
4145
4145
4146 When REV is not given, print a summary of the current state of the
4146 When REV is not given, print a summary of the current state of the
4147 repository.
4147 repository.
4148
4148
4149 Specifying a path to a repository root or Mercurial bundle will
4149 Specifying a path to a repository root or Mercurial bundle will
4150 cause lookup to operate on that repository/bundle.
4150 cause lookup to operate on that repository/bundle.
4151
4151
4152 .. container:: verbose
4152 .. container:: verbose
4153
4153
4154 Examples:
4154 Examples:
4155
4155
4156 - generate a build identifier for the working directory::
4156 - generate a build identifier for the working directory::
4157
4157
4158 hg id --id > build-id.dat
4158 hg id --id > build-id.dat
4159
4159
4160 - find the revision corresponding to a tag::
4160 - find the revision corresponding to a tag::
4161
4161
4162 hg id -n -r 1.3
4162 hg id -n -r 1.3
4163
4163
4164 - check the most recent revision of a remote repository::
4164 - check the most recent revision of a remote repository::
4165
4165
4166 hg id -r tip http://selenic.com/hg/
4166 hg id -r tip http://selenic.com/hg/
4167
4167
4168 Returns 0 if successful.
4168 Returns 0 if successful.
4169 """
4169 """
4170
4170
4171 if not repo and not source:
4171 if not repo and not source:
4172 raise error.Abort(_("there is no Mercurial repository here "
4172 raise error.Abort(_("there is no Mercurial repository here "
4173 "(.hg not found)"))
4173 "(.hg not found)"))
4174
4174
4175 if ui.debugflag:
4175 if ui.debugflag:
4176 hexfunc = hex
4176 hexfunc = hex
4177 else:
4177 else:
4178 hexfunc = short
4178 hexfunc = short
4179 default = not (num or id or branch or tags or bookmarks)
4179 default = not (num or id or branch or tags or bookmarks)
4180 output = []
4180 output = []
4181 revs = []
4181 revs = []
4182
4182
4183 if source:
4183 if source:
4184 source, branches = hg.parseurl(ui.expandpath(source))
4184 source, branches = hg.parseurl(ui.expandpath(source))
4185 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4185 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4186 repo = peer.local()
4186 repo = peer.local()
4187 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4187 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4188
4188
4189 if not repo:
4189 if not repo:
4190 if num or branch or tags:
4190 if num or branch or tags:
4191 raise error.Abort(
4191 raise error.Abort(
4192 _("can't query remote revision number, branch, or tags"))
4192 _("can't query remote revision number, branch, or tags"))
4193 if not rev and revs:
4193 if not rev and revs:
4194 rev = revs[0]
4194 rev = revs[0]
4195 if not rev:
4195 if not rev:
4196 rev = "tip"
4196 rev = "tip"
4197
4197
4198 remoterev = peer.lookup(rev)
4198 remoterev = peer.lookup(rev)
4199 if default or id:
4199 if default or id:
4200 output = [hexfunc(remoterev)]
4200 output = [hexfunc(remoterev)]
4201
4201
4202 def getbms():
4202 def getbms():
4203 bms = []
4203 bms = []
4204
4204
4205 if 'bookmarks' in peer.listkeys('namespaces'):
4205 if 'bookmarks' in peer.listkeys('namespaces'):
4206 hexremoterev = hex(remoterev)
4206 hexremoterev = hex(remoterev)
4207 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4207 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4208 if bmr == hexremoterev]
4208 if bmr == hexremoterev]
4209
4209
4210 return sorted(bms)
4210 return sorted(bms)
4211
4211
4212 if bookmarks:
4212 if bookmarks:
4213 output.extend(getbms())
4213 output.extend(getbms())
4214 elif default and not ui.quiet:
4214 elif default and not ui.quiet:
4215 # multiple bookmarks for a single parent separated by '/'
4215 # multiple bookmarks for a single parent separated by '/'
4216 bm = '/'.join(getbms())
4216 bm = '/'.join(getbms())
4217 if bm:
4217 if bm:
4218 output.append(bm)
4218 output.append(bm)
4219 else:
4219 else:
4220 ctx = scmutil.revsingle(repo, rev, None)
4220 ctx = scmutil.revsingle(repo, rev, None)
4221
4221
4222 if ctx.rev() is None:
4222 if ctx.rev() is None:
4223 ctx = repo[None]
4223 ctx = repo[None]
4224 parents = ctx.parents()
4224 parents = ctx.parents()
4225 taglist = []
4225 taglist = []
4226 for p in parents:
4226 for p in parents:
4227 taglist.extend(p.tags())
4227 taglist.extend(p.tags())
4228
4228
4229 changed = ""
4229 changed = ""
4230 if default or id or num:
4230 if default or id or num:
4231 if (any(repo.status())
4231 if (any(repo.status())
4232 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4232 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4233 changed = '+'
4233 changed = '+'
4234 if default or id:
4234 if default or id:
4235 output = ["%s%s" %
4235 output = ["%s%s" %
4236 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4236 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4237 if num:
4237 if num:
4238 output.append("%s%s" %
4238 output.append("%s%s" %
4239 ('+'.join([str(p.rev()) for p in parents]), changed))
4239 ('+'.join([str(p.rev()) for p in parents]), changed))
4240 else:
4240 else:
4241 if default or id:
4241 if default or id:
4242 output = [hexfunc(ctx.node())]
4242 output = [hexfunc(ctx.node())]
4243 if num:
4243 if num:
4244 output.append(str(ctx.rev()))
4244 output.append(str(ctx.rev()))
4245 taglist = ctx.tags()
4245 taglist = ctx.tags()
4246
4246
4247 if default and not ui.quiet:
4247 if default and not ui.quiet:
4248 b = ctx.branch()
4248 b = ctx.branch()
4249 if b != 'default':
4249 if b != 'default':
4250 output.append("(%s)" % b)
4250 output.append("(%s)" % b)
4251
4251
4252 # multiple tags for a single parent separated by '/'
4252 # multiple tags for a single parent separated by '/'
4253 t = '/'.join(taglist)
4253 t = '/'.join(taglist)
4254 if t:
4254 if t:
4255 output.append(t)
4255 output.append(t)
4256
4256
4257 # multiple bookmarks for a single parent separated by '/'
4257 # multiple bookmarks for a single parent separated by '/'
4258 bm = '/'.join(ctx.bookmarks())
4258 bm = '/'.join(ctx.bookmarks())
4259 if bm:
4259 if bm:
4260 output.append(bm)
4260 output.append(bm)
4261 else:
4261 else:
4262 if branch:
4262 if branch:
4263 output.append(ctx.branch())
4263 output.append(ctx.branch())
4264
4264
4265 if tags:
4265 if tags:
4266 output.extend(taglist)
4266 output.extend(taglist)
4267
4267
4268 if bookmarks:
4268 if bookmarks:
4269 output.extend(ctx.bookmarks())
4269 output.extend(ctx.bookmarks())
4270
4270
4271 ui.write("%s\n" % ' '.join(output))
4271 ui.write("%s\n" % ' '.join(output))
4272
4272
4273 @command('import|patch',
4273 @command('import|patch',
4274 [('p', 'strip', 1,
4274 [('p', 'strip', 1,
4275 _('directory strip option for patch. This has the same '
4275 _('directory strip option for patch. This has the same '
4276 'meaning as the corresponding patch option'), _('NUM')),
4276 'meaning as the corresponding patch option'), _('NUM')),
4277 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4277 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4278 ('e', 'edit', False, _('invoke editor on commit messages')),
4278 ('e', 'edit', False, _('invoke editor on commit messages')),
4279 ('f', 'force', None,
4279 ('f', 'force', None,
4280 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4280 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4281 ('', 'no-commit', None,
4281 ('', 'no-commit', None,
4282 _("don't commit, just update the working directory")),
4282 _("don't commit, just update the working directory")),
4283 ('', 'bypass', None,
4283 ('', 'bypass', None,
4284 _("apply patch without touching the working directory")),
4284 _("apply patch without touching the working directory")),
4285 ('', 'partial', None,
4285 ('', 'partial', None,
4286 _('commit even if some hunks fail')),
4286 _('commit even if some hunks fail')),
4287 ('', 'exact', None,
4287 ('', 'exact', None,
4288 _('apply patch to the nodes from which it was generated')),
4288 _('apply patch to the nodes from which it was generated')),
4289 ('', 'prefix', '',
4289 ('', 'prefix', '',
4290 _('apply patch to subdirectory'), _('DIR')),
4290 _('apply patch to subdirectory'), _('DIR')),
4291 ('', 'import-branch', None,
4291 ('', 'import-branch', None,
4292 _('use any branch information in patch (implied by --exact)'))] +
4292 _('use any branch information in patch (implied by --exact)'))] +
4293 commitopts + commitopts2 + similarityopts,
4293 commitopts + commitopts2 + similarityopts,
4294 _('[OPTION]... PATCH...'))
4294 _('[OPTION]... PATCH...'))
4295 def import_(ui, repo, patch1=None, *patches, **opts):
4295 def import_(ui, repo, patch1=None, *patches, **opts):
4296 """import an ordered set of patches
4296 """import an ordered set of patches
4297
4297
4298 Import a list of patches and commit them individually (unless
4298 Import a list of patches and commit them individually (unless
4299 --no-commit is specified).
4299 --no-commit is specified).
4300
4300
4301 Because import first applies changes to the working directory,
4301 Because import first applies changes to the working directory,
4302 import will abort if there are outstanding changes.
4302 import will abort if there are outstanding changes.
4303
4303
4304 You can import a patch straight from a mail message. Even patches
4304 You can import a patch straight from a mail message. Even patches
4305 as attachments work (to use the body part, it must have type
4305 as attachments work (to use the body part, it must have type
4306 text/plain or text/x-patch). From and Subject headers of email
4306 text/plain or text/x-patch). From and Subject headers of email
4307 message are used as default committer and commit message. All
4307 message are used as default committer and commit message. All
4308 text/plain body parts before first diff are added to commit
4308 text/plain body parts before first diff are added to commit
4309 message.
4309 message.
4310
4310
4311 If the imported patch was generated by :hg:`export`, user and
4311 If the imported patch was generated by :hg:`export`, user and
4312 description from patch override values from message headers and
4312 description from patch override values from message headers and
4313 body. Values given on command line with -m/--message and -u/--user
4313 body. Values given on command line with -m/--message and -u/--user
4314 override these.
4314 override these.
4315
4315
4316 If --exact is specified, import will set the working directory to
4316 If --exact is specified, import will set the working directory to
4317 the parent of each patch before applying it, and will abort if the
4317 the parent of each patch before applying it, and will abort if the
4318 resulting changeset has a different ID than the one recorded in
4318 resulting changeset has a different ID than the one recorded in
4319 the patch. This may happen due to character set problems or other
4319 the patch. This may happen due to character set problems or other
4320 deficiencies in the text patch format.
4320 deficiencies in the text patch format.
4321
4321
4322 Use --bypass to apply and commit patches directly to the
4322 Use --bypass to apply and commit patches directly to the
4323 repository, not touching the working directory. Without --exact,
4323 repository, not touching the working directory. Without --exact,
4324 patches will be applied on top of the working directory parent
4324 patches will be applied on top of the working directory parent
4325 revision.
4325 revision.
4326
4326
4327 With -s/--similarity, hg will attempt to discover renames and
4327 With -s/--similarity, hg will attempt to discover renames and
4328 copies in the patch in the same way as :hg:`addremove`.
4328 copies in the patch in the same way as :hg:`addremove`.
4329
4329
4330 Use --partial to ensure a changeset will be created from the patch
4330 Use --partial to ensure a changeset will be created from the patch
4331 even if some hunks fail to apply. Hunks that fail to apply will be
4331 even if some hunks fail to apply. Hunks that fail to apply will be
4332 written to a <target-file>.rej file. Conflicts can then be resolved
4332 written to a <target-file>.rej file. Conflicts can then be resolved
4333 by hand before :hg:`commit --amend` is run to update the created
4333 by hand before :hg:`commit --amend` is run to update the created
4334 changeset. This flag exists to let people import patches that
4334 changeset. This flag exists to let people import patches that
4335 partially apply without losing the associated metadata (author,
4335 partially apply without losing the associated metadata (author,
4336 date, description, ...). Note that when none of the hunk applies
4336 date, description, ...). Note that when none of the hunk applies
4337 cleanly, :hg:`import --partial` will create an empty changeset,
4337 cleanly, :hg:`import --partial` will create an empty changeset,
4338 importing only the patch metadata.
4338 importing only the patch metadata.
4339
4339
4340 It is possible to use external patch programs to perform the patch
4340 It is possible to use external patch programs to perform the patch
4341 by setting the ``ui.patch`` configuration option. For the default
4341 by setting the ``ui.patch`` configuration option. For the default
4342 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4342 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4343 See :hg:`help config` for more information about configuration
4343 See :hg:`help config` for more information about configuration
4344 files and how to use these options.
4344 files and how to use these options.
4345
4345
4346 To read a patch from standard input, use "-" as the patch name. If
4346 To read a patch from standard input, use "-" as the patch name. If
4347 a URL is specified, the patch will be downloaded from it.
4347 a URL is specified, the patch will be downloaded from it.
4348 See :hg:`help dates` for a list of formats valid for -d/--date.
4348 See :hg:`help dates` for a list of formats valid for -d/--date.
4349
4349
4350 .. container:: verbose
4350 .. container:: verbose
4351
4351
4352 Examples:
4352 Examples:
4353
4353
4354 - import a traditional patch from a website and detect renames::
4354 - import a traditional patch from a website and detect renames::
4355
4355
4356 hg import -s 80 http://example.com/bugfix.patch
4356 hg import -s 80 http://example.com/bugfix.patch
4357
4357
4358 - import a changeset from an hgweb server::
4358 - import a changeset from an hgweb server::
4359
4359
4360 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4360 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4361
4361
4362 - import all the patches in an Unix-style mbox::
4362 - import all the patches in an Unix-style mbox::
4363
4363
4364 hg import incoming-patches.mbox
4364 hg import incoming-patches.mbox
4365
4365
4366 - attempt to exactly restore an exported changeset (not always
4366 - attempt to exactly restore an exported changeset (not always
4367 possible)::
4367 possible)::
4368
4368
4369 hg import --exact proposed-fix.patch
4369 hg import --exact proposed-fix.patch
4370
4370
4371 - use an external tool to apply a patch which is too fuzzy for
4371 - use an external tool to apply a patch which is too fuzzy for
4372 the default internal tool.
4372 the default internal tool.
4373
4373
4374 hg import --config ui.patch="patch --merge" fuzzy.patch
4374 hg import --config ui.patch="patch --merge" fuzzy.patch
4375
4375
4376 - change the default fuzzing from 2 to a less strict 7
4376 - change the default fuzzing from 2 to a less strict 7
4377
4377
4378 hg import --config ui.fuzz=7 fuzz.patch
4378 hg import --config ui.fuzz=7 fuzz.patch
4379
4379
4380 Returns 0 on success, 1 on partial success (see --partial).
4380 Returns 0 on success, 1 on partial success (see --partial).
4381 """
4381 """
4382
4382
4383 if not patch1:
4383 if not patch1:
4384 raise error.Abort(_('need at least one patch to import'))
4384 raise error.Abort(_('need at least one patch to import'))
4385
4385
4386 patches = (patch1,) + patches
4386 patches = (patch1,) + patches
4387
4387
4388 date = opts.get('date')
4388 date = opts.get('date')
4389 if date:
4389 if date:
4390 opts['date'] = util.parsedate(date)
4390 opts['date'] = util.parsedate(date)
4391
4391
4392 update = not opts.get('bypass')
4392 update = not opts.get('bypass')
4393 if not update and opts.get('no_commit'):
4393 if not update and opts.get('no_commit'):
4394 raise error.Abort(_('cannot use --no-commit with --bypass'))
4394 raise error.Abort(_('cannot use --no-commit with --bypass'))
4395 try:
4395 try:
4396 sim = float(opts.get('similarity') or 0)
4396 sim = float(opts.get('similarity') or 0)
4397 except ValueError:
4397 except ValueError:
4398 raise error.Abort(_('similarity must be a number'))
4398 raise error.Abort(_('similarity must be a number'))
4399 if sim < 0 or sim > 100:
4399 if sim < 0 or sim > 100:
4400 raise error.Abort(_('similarity must be between 0 and 100'))
4400 raise error.Abort(_('similarity must be between 0 and 100'))
4401 if sim and not update:
4401 if sim and not update:
4402 raise error.Abort(_('cannot use --similarity with --bypass'))
4402 raise error.Abort(_('cannot use --similarity with --bypass'))
4403 if opts.get('exact') and opts.get('edit'):
4403 if opts.get('exact') and opts.get('edit'):
4404 raise error.Abort(_('cannot use --exact with --edit'))
4404 raise error.Abort(_('cannot use --exact with --edit'))
4405 if opts.get('exact') and opts.get('prefix'):
4405 if opts.get('exact') and opts.get('prefix'):
4406 raise error.Abort(_('cannot use --exact with --prefix'))
4406 raise error.Abort(_('cannot use --exact with --prefix'))
4407
4407
4408 if update:
4408 if update:
4409 cmdutil.checkunfinished(repo)
4409 cmdutil.checkunfinished(repo)
4410 if (opts.get('exact') or not opts.get('force')) and update:
4410 if (opts.get('exact') or not opts.get('force')) and update:
4411 cmdutil.bailifchanged(repo)
4411 cmdutil.bailifchanged(repo)
4412
4412
4413 base = opts["base"]
4413 base = opts["base"]
4414 wlock = dsguard = lock = tr = None
4414 wlock = dsguard = lock = tr = None
4415 msgs = []
4415 msgs = []
4416 ret = 0
4416 ret = 0
4417
4417
4418
4418
4419 try:
4419 try:
4420 try:
4420 try:
4421 wlock = repo.wlock()
4421 wlock = repo.wlock()
4422 if not opts.get('no_commit'):
4422 if not opts.get('no_commit'):
4423 lock = repo.lock()
4423 lock = repo.lock()
4424 tr = repo.transaction('import')
4424 tr = repo.transaction('import')
4425 else:
4425 else:
4426 dsguard = cmdutil.dirstateguard(repo, 'import')
4426 dsguard = cmdutil.dirstateguard(repo, 'import')
4427 parents = repo.parents()
4427 parents = repo.parents()
4428 for patchurl in patches:
4428 for patchurl in patches:
4429 if patchurl == '-':
4429 if patchurl == '-':
4430 ui.status(_('applying patch from stdin\n'))
4430 ui.status(_('applying patch from stdin\n'))
4431 patchfile = ui.fin
4431 patchfile = ui.fin
4432 patchurl = 'stdin' # for error message
4432 patchurl = 'stdin' # for error message
4433 else:
4433 else:
4434 patchurl = os.path.join(base, patchurl)
4434 patchurl = os.path.join(base, patchurl)
4435 ui.status(_('applying %s\n') % patchurl)
4435 ui.status(_('applying %s\n') % patchurl)
4436 patchfile = hg.openpath(ui, patchurl)
4436 patchfile = hg.openpath(ui, patchurl)
4437
4437
4438 haspatch = False
4438 haspatch = False
4439 for hunk in patch.split(patchfile):
4439 for hunk in patch.split(patchfile):
4440 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4440 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4441 parents, opts,
4441 parents, opts,
4442 msgs, hg.clean)
4442 msgs, hg.clean)
4443 if msg:
4443 if msg:
4444 haspatch = True
4444 haspatch = True
4445 ui.note(msg + '\n')
4445 ui.note(msg + '\n')
4446 if update or opts.get('exact'):
4446 if update or opts.get('exact'):
4447 parents = repo.parents()
4447 parents = repo.parents()
4448 else:
4448 else:
4449 parents = [repo[node]]
4449 parents = [repo[node]]
4450 if rej:
4450 if rej:
4451 ui.write_err(_("patch applied partially\n"))
4451 ui.write_err(_("patch applied partially\n"))
4452 ui.write_err(_("(fix the .rej files and run "
4452 ui.write_err(_("(fix the .rej files and run "
4453 "`hg commit --amend`)\n"))
4453 "`hg commit --amend`)\n"))
4454 ret = 1
4454 ret = 1
4455 break
4455 break
4456
4456
4457 if not haspatch:
4457 if not haspatch:
4458 raise error.Abort(_('%s: no diffs found') % patchurl)
4458 raise error.Abort(_('%s: no diffs found') % patchurl)
4459
4459
4460 if tr:
4460 if tr:
4461 tr.close()
4461 tr.close()
4462 if msgs:
4462 if msgs:
4463 repo.savecommitmessage('\n* * *\n'.join(msgs))
4463 repo.savecommitmessage('\n* * *\n'.join(msgs))
4464 if dsguard:
4464 if dsguard:
4465 dsguard.close()
4465 dsguard.close()
4466 return ret
4466 return ret
4467 finally:
4467 finally:
4468 # TODO: get rid of this meaningless try/finally enclosing.
4468 # TODO: get rid of this meaningless try/finally enclosing.
4469 # this is kept only to reduce changes in a patch.
4469 # this is kept only to reduce changes in a patch.
4470 pass
4470 pass
4471 finally:
4471 finally:
4472 if tr:
4472 if tr:
4473 tr.release()
4473 tr.release()
4474 release(lock, dsguard, wlock)
4474 release(lock, dsguard, wlock)
4475
4475
4476 @command('incoming|in',
4476 @command('incoming|in',
4477 [('f', 'force', None,
4477 [('f', 'force', None,
4478 _('run even if remote repository is unrelated')),
4478 _('run even if remote repository is unrelated')),
4479 ('n', 'newest-first', None, _('show newest record first')),
4479 ('n', 'newest-first', None, _('show newest record first')),
4480 ('', 'bundle', '',
4480 ('', 'bundle', '',
4481 _('file to store the bundles into'), _('FILE')),
4481 _('file to store the bundles into'), _('FILE')),
4482 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4482 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4483 ('B', 'bookmarks', False, _("compare bookmarks")),
4483 ('B', 'bookmarks', False, _("compare bookmarks")),
4484 ('b', 'branch', [],
4484 ('b', 'branch', [],
4485 _('a specific branch you would like to pull'), _('BRANCH')),
4485 _('a specific branch you would like to pull'), _('BRANCH')),
4486 ] + logopts + remoteopts + subrepoopts,
4486 ] + logopts + remoteopts + subrepoopts,
4487 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4487 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4488 def incoming(ui, repo, source="default", **opts):
4488 def incoming(ui, repo, source="default", **opts):
4489 """show new changesets found in source
4489 """show new changesets found in source
4490
4490
4491 Show new changesets found in the specified path/URL or the default
4491 Show new changesets found in the specified path/URL or the default
4492 pull location. These are the changesets that would have been pulled
4492 pull location. These are the changesets that would have been pulled
4493 if a pull at the time you issued this command.
4493 if a pull at the time you issued this command.
4494
4494
4495 See pull for valid source format details.
4495 See pull for valid source format details.
4496
4496
4497 .. container:: verbose
4497 .. container:: verbose
4498
4498
4499 With -B/--bookmarks, the result of bookmark comparison between
4499 With -B/--bookmarks, the result of bookmark comparison between
4500 local and remote repositories is displayed. With -v/--verbose,
4500 local and remote repositories is displayed. With -v/--verbose,
4501 status is also displayed for each bookmark like below::
4501 status is also displayed for each bookmark like below::
4502
4502
4503 BM1 01234567890a added
4503 BM1 01234567890a added
4504 BM2 1234567890ab advanced
4504 BM2 1234567890ab advanced
4505 BM3 234567890abc diverged
4505 BM3 234567890abc diverged
4506 BM4 34567890abcd changed
4506 BM4 34567890abcd changed
4507
4507
4508 The action taken locally when pulling depends on the
4508 The action taken locally when pulling depends on the
4509 status of each bookmark:
4509 status of each bookmark:
4510
4510
4511 :``added``: pull will create it
4511 :``added``: pull will create it
4512 :``advanced``: pull will update it
4512 :``advanced``: pull will update it
4513 :``diverged``: pull will create a divergent bookmark
4513 :``diverged``: pull will create a divergent bookmark
4514 :``changed``: result depends on remote changesets
4514 :``changed``: result depends on remote changesets
4515
4515
4516 From the point of view of pulling behavior, bookmark
4516 From the point of view of pulling behavior, bookmark
4517 existing only in the remote repository are treated as ``added``,
4517 existing only in the remote repository are treated as ``added``,
4518 even if it is in fact locally deleted.
4518 even if it is in fact locally deleted.
4519
4519
4520 .. container:: verbose
4520 .. container:: verbose
4521
4521
4522 For remote repository, using --bundle avoids downloading the
4522 For remote repository, using --bundle avoids downloading the
4523 changesets twice if the incoming is followed by a pull.
4523 changesets twice if the incoming is followed by a pull.
4524
4524
4525 Examples:
4525 Examples:
4526
4526
4527 - show incoming changes with patches and full description::
4527 - show incoming changes with patches and full description::
4528
4528
4529 hg incoming -vp
4529 hg incoming -vp
4530
4530
4531 - show incoming changes excluding merges, store a bundle::
4531 - show incoming changes excluding merges, store a bundle::
4532
4532
4533 hg in -vpM --bundle incoming.hg
4533 hg in -vpM --bundle incoming.hg
4534 hg pull incoming.hg
4534 hg pull incoming.hg
4535
4535
4536 - briefly list changes inside a bundle::
4536 - briefly list changes inside a bundle::
4537
4537
4538 hg in changes.hg -T "{desc|firstline}\\n"
4538 hg in changes.hg -T "{desc|firstline}\\n"
4539
4539
4540 Returns 0 if there are incoming changes, 1 otherwise.
4540 Returns 0 if there are incoming changes, 1 otherwise.
4541 """
4541 """
4542 if opts.get('graph'):
4542 if opts.get('graph'):
4543 cmdutil.checkunsupportedgraphflags([], opts)
4543 cmdutil.checkunsupportedgraphflags([], opts)
4544 def display(other, chlist, displayer):
4544 def display(other, chlist, displayer):
4545 revdag = cmdutil.graphrevs(other, chlist, opts)
4545 revdag = cmdutil.graphrevs(other, chlist, opts)
4546 showparents = [ctx.node() for ctx in repo[None].parents()]
4546 showparents = [ctx.node() for ctx in repo[None].parents()]
4547 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4547 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4548 graphmod.asciiedges)
4548 graphmod.asciiedges)
4549
4549
4550 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4550 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4551 return 0
4551 return 0
4552
4552
4553 if opts.get('bundle') and opts.get('subrepos'):
4553 if opts.get('bundle') and opts.get('subrepos'):
4554 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4554 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4555
4555
4556 if opts.get('bookmarks'):
4556 if opts.get('bookmarks'):
4557 source, branches = hg.parseurl(ui.expandpath(source),
4557 source, branches = hg.parseurl(ui.expandpath(source),
4558 opts.get('branch'))
4558 opts.get('branch'))
4559 other = hg.peer(repo, opts, source)
4559 other = hg.peer(repo, opts, source)
4560 if 'bookmarks' not in other.listkeys('namespaces'):
4560 if 'bookmarks' not in other.listkeys('namespaces'):
4561 ui.warn(_("remote doesn't support bookmarks\n"))
4561 ui.warn(_("remote doesn't support bookmarks\n"))
4562 return 0
4562 return 0
4563 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4563 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4564 return bookmarks.incoming(ui, repo, other)
4564 return bookmarks.incoming(ui, repo, other)
4565
4565
4566 repo._subtoppath = ui.expandpath(source)
4566 repo._subtoppath = ui.expandpath(source)
4567 try:
4567 try:
4568 return hg.incoming(ui, repo, source, opts)
4568 return hg.incoming(ui, repo, source, opts)
4569 finally:
4569 finally:
4570 del repo._subtoppath
4570 del repo._subtoppath
4571
4571
4572
4572
4573 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4573 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4574 norepo=True)
4574 norepo=True)
4575 def init(ui, dest=".", **opts):
4575 def init(ui, dest=".", **opts):
4576 """create a new repository in the given directory
4576 """create a new repository in the given directory
4577
4577
4578 Initialize a new repository in the given directory. If the given
4578 Initialize a new repository in the given directory. If the given
4579 directory does not exist, it will be created.
4579 directory does not exist, it will be created.
4580
4580
4581 If no directory is given, the current directory is used.
4581 If no directory is given, the current directory is used.
4582
4582
4583 It is possible to specify an ``ssh://`` URL as the destination.
4583 It is possible to specify an ``ssh://`` URL as the destination.
4584 See :hg:`help urls` for more information.
4584 See :hg:`help urls` for more information.
4585
4585
4586 Returns 0 on success.
4586 Returns 0 on success.
4587 """
4587 """
4588 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4588 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4589
4589
4590 @command('locate',
4590 @command('locate',
4591 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4591 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4592 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4592 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4593 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4593 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4594 ] + walkopts,
4594 ] + walkopts,
4595 _('[OPTION]... [PATTERN]...'))
4595 _('[OPTION]... [PATTERN]...'))
4596 def locate(ui, repo, *pats, **opts):
4596 def locate(ui, repo, *pats, **opts):
4597 """locate files matching specific patterns (DEPRECATED)
4597 """locate files matching specific patterns (DEPRECATED)
4598
4598
4599 Print files under Mercurial control in the working directory whose
4599 Print files under Mercurial control in the working directory whose
4600 names match the given patterns.
4600 names match the given patterns.
4601
4601
4602 By default, this command searches all directories in the working
4602 By default, this command searches all directories in the working
4603 directory. To search just the current directory and its
4603 directory. To search just the current directory and its
4604 subdirectories, use "--include .".
4604 subdirectories, use "--include .".
4605
4605
4606 If no patterns are given to match, this command prints the names
4606 If no patterns are given to match, this command prints the names
4607 of all files under Mercurial control in the working directory.
4607 of all files under Mercurial control in the working directory.
4608
4608
4609 If you want to feed the output of this command into the "xargs"
4609 If you want to feed the output of this command into the "xargs"
4610 command, use the -0 option to both this command and "xargs". This
4610 command, use the -0 option to both this command and "xargs". This
4611 will avoid the problem of "xargs" treating single filenames that
4611 will avoid the problem of "xargs" treating single filenames that
4612 contain whitespace as multiple filenames.
4612 contain whitespace as multiple filenames.
4613
4613
4614 See :hg:`help files` for a more versatile command.
4614 See :hg:`help files` for a more versatile command.
4615
4615
4616 Returns 0 if a match is found, 1 otherwise.
4616 Returns 0 if a match is found, 1 otherwise.
4617 """
4617 """
4618 if opts.get('print0'):
4618 if opts.get('print0'):
4619 end = '\0'
4619 end = '\0'
4620 else:
4620 else:
4621 end = '\n'
4621 end = '\n'
4622 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4622 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4623
4623
4624 ret = 1
4624 ret = 1
4625 ctx = repo[rev]
4625 ctx = repo[rev]
4626 m = scmutil.match(ctx, pats, opts, default='relglob',
4626 m = scmutil.match(ctx, pats, opts, default='relglob',
4627 badfn=lambda x, y: False)
4627 badfn=lambda x, y: False)
4628
4628
4629 for abs in ctx.matches(m):
4629 for abs in ctx.matches(m):
4630 if opts.get('fullpath'):
4630 if opts.get('fullpath'):
4631 ui.write(repo.wjoin(abs), end)
4631 ui.write(repo.wjoin(abs), end)
4632 else:
4632 else:
4633 ui.write(((pats and m.rel(abs)) or abs), end)
4633 ui.write(((pats and m.rel(abs)) or abs), end)
4634 ret = 0
4634 ret = 0
4635
4635
4636 return ret
4636 return ret
4637
4637
4638 @command('^log|history',
4638 @command('^log|history',
4639 [('f', 'follow', None,
4639 [('f', 'follow', None,
4640 _('follow changeset history, or file history across copies and renames')),
4640 _('follow changeset history, or file history across copies and renames')),
4641 ('', 'follow-first', None,
4641 ('', 'follow-first', None,
4642 _('only follow the first parent of merge changesets (DEPRECATED)')),
4642 _('only follow the first parent of merge changesets (DEPRECATED)')),
4643 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4643 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4644 ('C', 'copies', None, _('show copied files')),
4644 ('C', 'copies', None, _('show copied files')),
4645 ('k', 'keyword', [],
4645 ('k', 'keyword', [],
4646 _('do case-insensitive search for a given text'), _('TEXT')),
4646 _('do case-insensitive search for a given text'), _('TEXT')),
4647 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4647 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4648 ('', 'removed', None, _('include revisions where files were removed')),
4648 ('', 'removed', None, _('include revisions where files were removed')),
4649 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4649 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4650 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4650 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4651 ('', 'only-branch', [],
4651 ('', 'only-branch', [],
4652 _('show only changesets within the given named branch (DEPRECATED)'),
4652 _('show only changesets within the given named branch (DEPRECATED)'),
4653 _('BRANCH')),
4653 _('BRANCH')),
4654 ('b', 'branch', [],
4654 ('b', 'branch', [],
4655 _('show changesets within the given named branch'), _('BRANCH')),
4655 _('show changesets within the given named branch'), _('BRANCH')),
4656 ('P', 'prune', [],
4656 ('P', 'prune', [],
4657 _('do not display revision or any of its ancestors'), _('REV')),
4657 _('do not display revision or any of its ancestors'), _('REV')),
4658 ] + logopts + walkopts,
4658 ] + logopts + walkopts,
4659 _('[OPTION]... [FILE]'),
4659 _('[OPTION]... [FILE]'),
4660 inferrepo=True)
4660 inferrepo=True)
4661 def log(ui, repo, *pats, **opts):
4661 def log(ui, repo, *pats, **opts):
4662 """show revision history of entire repository or files
4662 """show revision history of entire repository or files
4663
4663
4664 Print the revision history of the specified files or the entire
4664 Print the revision history of the specified files or the entire
4665 project.
4665 project.
4666
4666
4667 If no revision range is specified, the default is ``tip:0`` unless
4667 If no revision range is specified, the default is ``tip:0`` unless
4668 --follow is set, in which case the working directory parent is
4668 --follow is set, in which case the working directory parent is
4669 used as the starting revision.
4669 used as the starting revision.
4670
4670
4671 File history is shown without following rename or copy history of
4671 File history is shown without following rename or copy history of
4672 files. Use -f/--follow with a filename to follow history across
4672 files. Use -f/--follow with a filename to follow history across
4673 renames and copies. --follow without a filename will only show
4673 renames and copies. --follow without a filename will only show
4674 ancestors or descendants of the starting revision.
4674 ancestors or descendants of the starting revision.
4675
4675
4676 By default this command prints revision number and changeset id,
4676 By default this command prints revision number and changeset id,
4677 tags, non-trivial parents, user, date and time, and a summary for
4677 tags, non-trivial parents, user, date and time, and a summary for
4678 each commit. When the -v/--verbose switch is used, the list of
4678 each commit. When the -v/--verbose switch is used, the list of
4679 changed files and full commit message are shown.
4679 changed files and full commit message are shown.
4680
4680
4681 With --graph the revisions are shown as an ASCII art DAG with the most
4681 With --graph the revisions are shown as an ASCII art DAG with the most
4682 recent changeset at the top.
4682 recent changeset at the top.
4683 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4683 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4684 and '+' represents a fork where the changeset from the lines below is a
4684 and '+' represents a fork where the changeset from the lines below is a
4685 parent of the 'o' merge on the same line.
4685 parent of the 'o' merge on the same line.
4686
4686
4687 .. note::
4687 .. note::
4688
4688
4689 log -p/--patch may generate unexpected diff output for merge
4689 log -p/--patch may generate unexpected diff output for merge
4690 changesets, as it will only compare the merge changeset against
4690 changesets, as it will only compare the merge changeset against
4691 its first parent. Also, only files different from BOTH parents
4691 its first parent. Also, only files different from BOTH parents
4692 will appear in files:.
4692 will appear in files:.
4693
4693
4694 .. note::
4694 .. note::
4695
4695
4696 for performance reasons, log FILE may omit duplicate changes
4696 for performance reasons, log FILE may omit duplicate changes
4697 made on branches and will not show removals or mode changes. To
4697 made on branches and will not show removals or mode changes. To
4698 see all such changes, use the --removed switch.
4698 see all such changes, use the --removed switch.
4699
4699
4700 .. container:: verbose
4700 .. container:: verbose
4701
4701
4702 Some examples:
4702 Some examples:
4703
4703
4704 - changesets with full descriptions and file lists::
4704 - changesets with full descriptions and file lists::
4705
4705
4706 hg log -v
4706 hg log -v
4707
4707
4708 - changesets ancestral to the working directory::
4708 - changesets ancestral to the working directory::
4709
4709
4710 hg log -f
4710 hg log -f
4711
4711
4712 - last 10 commits on the current branch::
4712 - last 10 commits on the current branch::
4713
4713
4714 hg log -l 10 -b .
4714 hg log -l 10 -b .
4715
4715
4716 - changesets showing all modifications of a file, including removals::
4716 - changesets showing all modifications of a file, including removals::
4717
4717
4718 hg log --removed file.c
4718 hg log --removed file.c
4719
4719
4720 - all changesets that touch a directory, with diffs, excluding merges::
4720 - all changesets that touch a directory, with diffs, excluding merges::
4721
4721
4722 hg log -Mp lib/
4722 hg log -Mp lib/
4723
4723
4724 - all revision numbers that match a keyword::
4724 - all revision numbers that match a keyword::
4725
4725
4726 hg log -k bug --template "{rev}\\n"
4726 hg log -k bug --template "{rev}\\n"
4727
4727
4728 - list available log templates::
4728 - list available log templates::
4729
4729
4730 hg log -T list
4730 hg log -T list
4731
4731
4732 - check if a given changeset is included in a tagged release::
4732 - check if a given changeset is included in a tagged release::
4733
4733
4734 hg log -r "a21ccf and ancestor(1.9)"
4734 hg log -r "a21ccf and ancestor(1.9)"
4735
4735
4736 - find all changesets by some user in a date range::
4736 - find all changesets by some user in a date range::
4737
4737
4738 hg log -k alice -d "may 2008 to jul 2008"
4738 hg log -k alice -d "may 2008 to jul 2008"
4739
4739
4740 - summary of all changesets after the last tag::
4740 - summary of all changesets after the last tag::
4741
4741
4742 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4742 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4743
4743
4744 See :hg:`help dates` for a list of formats valid for -d/--date.
4744 See :hg:`help dates` for a list of formats valid for -d/--date.
4745
4745
4746 See :hg:`help revisions` and :hg:`help revsets` for more about
4746 See :hg:`help revisions` and :hg:`help revsets` for more about
4747 specifying revisions.
4747 specifying revisions.
4748
4748
4749 See :hg:`help templates` for more about pre-packaged styles and
4749 See :hg:`help templates` for more about pre-packaged styles and
4750 specifying custom templates.
4750 specifying custom templates.
4751
4751
4752 Returns 0 on success.
4752 Returns 0 on success.
4753
4753
4754 """
4754 """
4755 if opts.get('follow') and opts.get('rev'):
4755 if opts.get('follow') and opts.get('rev'):
4756 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4756 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4757 del opts['follow']
4757 del opts['follow']
4758
4758
4759 if opts.get('graph'):
4759 if opts.get('graph'):
4760 return cmdutil.graphlog(ui, repo, *pats, **opts)
4760 return cmdutil.graphlog(ui, repo, *pats, **opts)
4761
4761
4762 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4762 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4763 limit = cmdutil.loglimit(opts)
4763 limit = cmdutil.loglimit(opts)
4764 count = 0
4764 count = 0
4765
4765
4766 getrenamed = None
4766 getrenamed = None
4767 if opts.get('copies'):
4767 if opts.get('copies'):
4768 endrev = None
4768 endrev = None
4769 if opts.get('rev'):
4769 if opts.get('rev'):
4770 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4770 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4771 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4771 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4772
4772
4773 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4773 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4774 for rev in revs:
4774 for rev in revs:
4775 if count == limit:
4775 if count == limit:
4776 break
4776 break
4777 ctx = repo[rev]
4777 ctx = repo[rev]
4778 copies = None
4778 copies = None
4779 if getrenamed is not None and rev:
4779 if getrenamed is not None and rev:
4780 copies = []
4780 copies = []
4781 for fn in ctx.files():
4781 for fn in ctx.files():
4782 rename = getrenamed(fn, rev)
4782 rename = getrenamed(fn, rev)
4783 if rename:
4783 if rename:
4784 copies.append((fn, rename[0]))
4784 copies.append((fn, rename[0]))
4785 if filematcher:
4785 if filematcher:
4786 revmatchfn = filematcher(ctx.rev())
4786 revmatchfn = filematcher(ctx.rev())
4787 else:
4787 else:
4788 revmatchfn = None
4788 revmatchfn = None
4789 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4789 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4790 if displayer.flush(ctx):
4790 if displayer.flush(ctx):
4791 count += 1
4791 count += 1
4792
4792
4793 displayer.close()
4793 displayer.close()
4794
4794
4795 @command('manifest',
4795 @command('manifest',
4796 [('r', 'rev', '', _('revision to display'), _('REV')),
4796 [('r', 'rev', '', _('revision to display'), _('REV')),
4797 ('', 'all', False, _("list files from all revisions"))]
4797 ('', 'all', False, _("list files from all revisions"))]
4798 + formatteropts,
4798 + formatteropts,
4799 _('[-r REV]'))
4799 _('[-r REV]'))
4800 def manifest(ui, repo, node=None, rev=None, **opts):
4800 def manifest(ui, repo, node=None, rev=None, **opts):
4801 """output the current or given revision of the project manifest
4801 """output the current or given revision of the project manifest
4802
4802
4803 Print a list of version controlled files for the given revision.
4803 Print a list of version controlled files for the given revision.
4804 If no revision is given, the first parent of the working directory
4804 If no revision is given, the first parent of the working directory
4805 is used, or the null revision if no revision is checked out.
4805 is used, or the null revision if no revision is checked out.
4806
4806
4807 With -v, print file permissions, symlink and executable bits.
4807 With -v, print file permissions, symlink and executable bits.
4808 With --debug, print file revision hashes.
4808 With --debug, print file revision hashes.
4809
4809
4810 If option --all is specified, the list of all files from all revisions
4810 If option --all is specified, the list of all files from all revisions
4811 is printed. This includes deleted and renamed files.
4811 is printed. This includes deleted and renamed files.
4812
4812
4813 Returns 0 on success.
4813 Returns 0 on success.
4814 """
4814 """
4815
4815
4816 fm = ui.formatter('manifest', opts)
4816 fm = ui.formatter('manifest', opts)
4817
4817
4818 if opts.get('all'):
4818 if opts.get('all'):
4819 if rev or node:
4819 if rev or node:
4820 raise error.Abort(_("can't specify a revision with --all"))
4820 raise error.Abort(_("can't specify a revision with --all"))
4821
4821
4822 res = []
4822 res = []
4823 prefix = "data/"
4823 prefix = "data/"
4824 suffix = ".i"
4824 suffix = ".i"
4825 plen = len(prefix)
4825 plen = len(prefix)
4826 slen = len(suffix)
4826 slen = len(suffix)
4827 lock = repo.lock()
4827 lock = repo.lock()
4828 try:
4828 try:
4829 for fn, b, size in repo.store.datafiles():
4829 for fn, b, size in repo.store.datafiles():
4830 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4830 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4831 res.append(fn[plen:-slen])
4831 res.append(fn[plen:-slen])
4832 finally:
4832 finally:
4833 lock.release()
4833 lock.release()
4834 for f in res:
4834 for f in res:
4835 fm.startitem()
4835 fm.startitem()
4836 fm.write("path", '%s\n', f)
4836 fm.write("path", '%s\n', f)
4837 fm.end()
4837 fm.end()
4838 return
4838 return
4839
4839
4840 if rev and node:
4840 if rev and node:
4841 raise error.Abort(_("please specify just one revision"))
4841 raise error.Abort(_("please specify just one revision"))
4842
4842
4843 if not node:
4843 if not node:
4844 node = rev
4844 node = rev
4845
4845
4846 char = {'l': '@', 'x': '*', '': ''}
4846 char = {'l': '@', 'x': '*', '': ''}
4847 mode = {'l': '644', 'x': '755', '': '644'}
4847 mode = {'l': '644', 'x': '755', '': '644'}
4848 ctx = scmutil.revsingle(repo, node)
4848 ctx = scmutil.revsingle(repo, node)
4849 mf = ctx.manifest()
4849 mf = ctx.manifest()
4850 for f in ctx:
4850 for f in ctx:
4851 fm.startitem()
4851 fm.startitem()
4852 fl = ctx[f].flags()
4852 fl = ctx[f].flags()
4853 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4853 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4854 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4854 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4855 fm.write('path', '%s\n', f)
4855 fm.write('path', '%s\n', f)
4856 fm.end()
4856 fm.end()
4857
4857
4858 @command('^merge',
4858 @command('^merge',
4859 [('f', 'force', None,
4859 [('f', 'force', None,
4860 _('force a merge including outstanding changes (DEPRECATED)')),
4860 _('force a merge including outstanding changes (DEPRECATED)')),
4861 ('r', 'rev', '', _('revision to merge'), _('REV')),
4861 ('r', 'rev', '', _('revision to merge'), _('REV')),
4862 ('P', 'preview', None,
4862 ('P', 'preview', None,
4863 _('review revisions to merge (no merge is performed)'))
4863 _('review revisions to merge (no merge is performed)'))
4864 ] + mergetoolopts,
4864 ] + mergetoolopts,
4865 _('[-P] [-f] [[-r] REV]'))
4865 _('[-P] [-f] [[-r] REV]'))
4866 def merge(ui, repo, node=None, **opts):
4866 def merge(ui, repo, node=None, **opts):
4867 """merge another revision into working directory
4867 """merge another revision into working directory
4868
4868
4869 The current working directory is updated with all changes made in
4869 The current working directory is updated with all changes made in
4870 the requested revision since the last common predecessor revision.
4870 the requested revision since the last common predecessor revision.
4871
4871
4872 Files that changed between either parent are marked as changed for
4872 Files that changed between either parent are marked as changed for
4873 the next commit and a commit must be performed before any further
4873 the next commit and a commit must be performed before any further
4874 updates to the repository are allowed. The next commit will have
4874 updates to the repository are allowed. The next commit will have
4875 two parents.
4875 two parents.
4876
4876
4877 ``--tool`` can be used to specify the merge tool used for file
4877 ``--tool`` can be used to specify the merge tool used for file
4878 merges. It overrides the HGMERGE environment variable and your
4878 merges. It overrides the HGMERGE environment variable and your
4879 configuration files. See :hg:`help merge-tools` for options.
4879 configuration files. See :hg:`help merge-tools` for options.
4880
4880
4881 If no revision is specified, the working directory's parent is a
4881 If no revision is specified, the working directory's parent is a
4882 head revision, and the current branch contains exactly one other
4882 head revision, and the current branch contains exactly one other
4883 head, the other head is merged with by default. Otherwise, an
4883 head, the other head is merged with by default. Otherwise, an
4884 explicit revision with which to merge with must be provided.
4884 explicit revision with which to merge with must be provided.
4885
4885
4886 :hg:`resolve` must be used to resolve unresolved files.
4886 :hg:`resolve` must be used to resolve unresolved files.
4887
4887
4888 To undo an uncommitted merge, use :hg:`update --clean .` which
4888 To undo an uncommitted merge, use :hg:`update --clean .` which
4889 will check out a clean copy of the original merge parent, losing
4889 will check out a clean copy of the original merge parent, losing
4890 all changes.
4890 all changes.
4891
4891
4892 Returns 0 on success, 1 if there are unresolved files.
4892 Returns 0 on success, 1 if there are unresolved files.
4893 """
4893 """
4894
4894
4895 if opts.get('rev') and node:
4895 if opts.get('rev') and node:
4896 raise error.Abort(_("please specify just one revision"))
4896 raise error.Abort(_("please specify just one revision"))
4897 if not node:
4897 if not node:
4898 node = opts.get('rev')
4898 node = opts.get('rev')
4899
4899
4900 if node:
4900 if node:
4901 node = scmutil.revsingle(repo, node).node()
4901 node = scmutil.revsingle(repo, node).node()
4902
4902
4903 if not node:
4903 if not node:
4904 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4904 node = scmutil.revsingle(repo, '_mergedefaultdest()').node()
4905
4905
4906 if opts.get('preview'):
4906 if opts.get('preview'):
4907 # find nodes that are ancestors of p2 but not of p1
4907 # find nodes that are ancestors of p2 but not of p1
4908 p1 = repo.lookup('.')
4908 p1 = repo.lookup('.')
4909 p2 = repo.lookup(node)
4909 p2 = repo.lookup(node)
4910 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4910 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4911
4911
4912 displayer = cmdutil.show_changeset(ui, repo, opts)
4912 displayer = cmdutil.show_changeset(ui, repo, opts)
4913 for node in nodes:
4913 for node in nodes:
4914 displayer.show(repo[node])
4914 displayer.show(repo[node])
4915 displayer.close()
4915 displayer.close()
4916 return 0
4916 return 0
4917
4917
4918 try:
4918 try:
4919 # ui.forcemerge is an internal variable, do not document
4919 # ui.forcemerge is an internal variable, do not document
4920 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4920 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4921 return hg.merge(repo, node, force=opts.get('force'))
4921 return hg.merge(repo, node, force=opts.get('force'))
4922 finally:
4922 finally:
4923 ui.setconfig('ui', 'forcemerge', '', 'merge')
4923 ui.setconfig('ui', 'forcemerge', '', 'merge')
4924
4924
4925 @command('outgoing|out',
4925 @command('outgoing|out',
4926 [('f', 'force', None, _('run even when the destination is unrelated')),
4926 [('f', 'force', None, _('run even when the destination is unrelated')),
4927 ('r', 'rev', [],
4927 ('r', 'rev', [],
4928 _('a changeset intended to be included in the destination'), _('REV')),
4928 _('a changeset intended to be included in the destination'), _('REV')),
4929 ('n', 'newest-first', None, _('show newest record first')),
4929 ('n', 'newest-first', None, _('show newest record first')),
4930 ('B', 'bookmarks', False, _('compare bookmarks')),
4930 ('B', 'bookmarks', False, _('compare bookmarks')),
4931 ('b', 'branch', [], _('a specific branch you would like to push'),
4931 ('b', 'branch', [], _('a specific branch you would like to push'),
4932 _('BRANCH')),
4932 _('BRANCH')),
4933 ] + logopts + remoteopts + subrepoopts,
4933 ] + logopts + remoteopts + subrepoopts,
4934 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4934 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4935 def outgoing(ui, repo, dest=None, **opts):
4935 def outgoing(ui, repo, dest=None, **opts):
4936 """show changesets not found in the destination
4936 """show changesets not found in the destination
4937
4937
4938 Show changesets not found in the specified destination repository
4938 Show changesets not found in the specified destination repository
4939 or the default push location. These are the changesets that would
4939 or the default push location. These are the changesets that would
4940 be pushed if a push was requested.
4940 be pushed if a push was requested.
4941
4941
4942 See pull for details of valid destination formats.
4942 See pull for details of valid destination formats.
4943
4943
4944 .. container:: verbose
4944 .. container:: verbose
4945
4945
4946 With -B/--bookmarks, the result of bookmark comparison between
4946 With -B/--bookmarks, the result of bookmark comparison between
4947 local and remote repositories is displayed. With -v/--verbose,
4947 local and remote repositories is displayed. With -v/--verbose,
4948 status is also displayed for each bookmark like below::
4948 status is also displayed for each bookmark like below::
4949
4949
4950 BM1 01234567890a added
4950 BM1 01234567890a added
4951 BM2 deleted
4951 BM2 deleted
4952 BM3 234567890abc advanced
4952 BM3 234567890abc advanced
4953 BM4 34567890abcd diverged
4953 BM4 34567890abcd diverged
4954 BM5 4567890abcde changed
4954 BM5 4567890abcde changed
4955
4955
4956 The action taken when pushing depends on the
4956 The action taken when pushing depends on the
4957 status of each bookmark:
4957 status of each bookmark:
4958
4958
4959 :``added``: push with ``-B`` will create it
4959 :``added``: push with ``-B`` will create it
4960 :``deleted``: push with ``-B`` will delete it
4960 :``deleted``: push with ``-B`` will delete it
4961 :``advanced``: push will update it
4961 :``advanced``: push will update it
4962 :``diverged``: push with ``-B`` will update it
4962 :``diverged``: push with ``-B`` will update it
4963 :``changed``: push with ``-B`` will update it
4963 :``changed``: push with ``-B`` will update it
4964
4964
4965 From the point of view of pushing behavior, bookmarks
4965 From the point of view of pushing behavior, bookmarks
4966 existing only in the remote repository are treated as
4966 existing only in the remote repository are treated as
4967 ``deleted``, even if it is in fact added remotely.
4967 ``deleted``, even if it is in fact added remotely.
4968
4968
4969 Returns 0 if there are outgoing changes, 1 otherwise.
4969 Returns 0 if there are outgoing changes, 1 otherwise.
4970 """
4970 """
4971 if opts.get('graph'):
4971 if opts.get('graph'):
4972 cmdutil.checkunsupportedgraphflags([], opts)
4972 cmdutil.checkunsupportedgraphflags([], opts)
4973 o, other = hg._outgoing(ui, repo, dest, opts)
4973 o, other = hg._outgoing(ui, repo, dest, opts)
4974 if not o:
4974 if not o:
4975 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4975 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4976 return
4976 return
4977
4977
4978 revdag = cmdutil.graphrevs(repo, o, opts)
4978 revdag = cmdutil.graphrevs(repo, o, opts)
4979 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4979 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4980 showparents = [ctx.node() for ctx in repo[None].parents()]
4980 showparents = [ctx.node() for ctx in repo[None].parents()]
4981 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4981 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4982 graphmod.asciiedges)
4982 graphmod.asciiedges)
4983 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4983 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4984 return 0
4984 return 0
4985
4985
4986 if opts.get('bookmarks'):
4986 if opts.get('bookmarks'):
4987 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4987 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4988 dest, branches = hg.parseurl(dest, opts.get('branch'))
4988 dest, branches = hg.parseurl(dest, opts.get('branch'))
4989 other = hg.peer(repo, opts, dest)
4989 other = hg.peer(repo, opts, dest)
4990 if 'bookmarks' not in other.listkeys('namespaces'):
4990 if 'bookmarks' not in other.listkeys('namespaces'):
4991 ui.warn(_("remote doesn't support bookmarks\n"))
4991 ui.warn(_("remote doesn't support bookmarks\n"))
4992 return 0
4992 return 0
4993 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4993 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4994 return bookmarks.outgoing(ui, repo, other)
4994 return bookmarks.outgoing(ui, repo, other)
4995
4995
4996 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4996 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4997 try:
4997 try:
4998 return hg.outgoing(ui, repo, dest, opts)
4998 return hg.outgoing(ui, repo, dest, opts)
4999 finally:
4999 finally:
5000 del repo._subtoppath
5000 del repo._subtoppath
5001
5001
5002 @command('parents',
5002 @command('parents',
5003 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5003 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5004 ] + templateopts,
5004 ] + templateopts,
5005 _('[-r REV] [FILE]'),
5005 _('[-r REV] [FILE]'),
5006 inferrepo=True)
5006 inferrepo=True)
5007 def parents(ui, repo, file_=None, **opts):
5007 def parents(ui, repo, file_=None, **opts):
5008 """show the parents of the working directory or revision (DEPRECATED)
5008 """show the parents of the working directory or revision (DEPRECATED)
5009
5009
5010 Print the working directory's parent revisions. If a revision is
5010 Print the working directory's parent revisions. If a revision is
5011 given via -r/--rev, the parent of that revision will be printed.
5011 given via -r/--rev, the parent of that revision will be printed.
5012 If a file argument is given, the revision in which the file was
5012 If a file argument is given, the revision in which the file was
5013 last changed (before the working directory revision or the
5013 last changed (before the working directory revision or the
5014 argument to --rev if given) is printed.
5014 argument to --rev if given) is printed.
5015
5015
5016 See :hg:`summary` and :hg:`help revsets` for related information.
5016 See :hg:`summary` and :hg:`help revsets` for related information.
5017
5017
5018 Returns 0 on success.
5018 Returns 0 on success.
5019 """
5019 """
5020
5020
5021 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5021 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5022
5022
5023 if file_:
5023 if file_:
5024 m = scmutil.match(ctx, (file_,), opts)
5024 m = scmutil.match(ctx, (file_,), opts)
5025 if m.anypats() or len(m.files()) != 1:
5025 if m.anypats() or len(m.files()) != 1:
5026 raise error.Abort(_('can only specify an explicit filename'))
5026 raise error.Abort(_('can only specify an explicit filename'))
5027 file_ = m.files()[0]
5027 file_ = m.files()[0]
5028 filenodes = []
5028 filenodes = []
5029 for cp in ctx.parents():
5029 for cp in ctx.parents():
5030 if not cp:
5030 if not cp:
5031 continue
5031 continue
5032 try:
5032 try:
5033 filenodes.append(cp.filenode(file_))
5033 filenodes.append(cp.filenode(file_))
5034 except error.LookupError:
5034 except error.LookupError:
5035 pass
5035 pass
5036 if not filenodes:
5036 if not filenodes:
5037 raise error.Abort(_("'%s' not found in manifest!") % file_)
5037 raise error.Abort(_("'%s' not found in manifest!") % file_)
5038 p = []
5038 p = []
5039 for fn in filenodes:
5039 for fn in filenodes:
5040 fctx = repo.filectx(file_, fileid=fn)
5040 fctx = repo.filectx(file_, fileid=fn)
5041 p.append(fctx.node())
5041 p.append(fctx.node())
5042 else:
5042 else:
5043 p = [cp.node() for cp in ctx.parents()]
5043 p = [cp.node() for cp in ctx.parents()]
5044
5044
5045 displayer = cmdutil.show_changeset(ui, repo, opts)
5045 displayer = cmdutil.show_changeset(ui, repo, opts)
5046 for n in p:
5046 for n in p:
5047 if n != nullid:
5047 if n != nullid:
5048 displayer.show(repo[n])
5048 displayer.show(repo[n])
5049 displayer.close()
5049 displayer.close()
5050
5050
5051 @command('paths', [], _('[NAME]'), optionalrepo=True)
5051 @command('paths', [], _('[NAME]'), optionalrepo=True)
5052 def paths(ui, repo, search=None):
5052 def paths(ui, repo, search=None):
5053 """show aliases for remote repositories
5053 """show aliases for remote repositories
5054
5054
5055 Show definition of symbolic path name NAME. If no name is given,
5055 Show definition of symbolic path name NAME. If no name is given,
5056 show definition of all available names.
5056 show definition of all available names.
5057
5057
5058 Option -q/--quiet suppresses all output when searching for NAME
5058 Option -q/--quiet suppresses all output when searching for NAME
5059 and shows only the path names when listing all definitions.
5059 and shows only the path names when listing all definitions.
5060
5060
5061 Path names are defined in the [paths] section of your
5061 Path names are defined in the [paths] section of your
5062 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5062 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5063 repository, ``.hg/hgrc`` is used, too.
5063 repository, ``.hg/hgrc`` is used, too.
5064
5064
5065 The path names ``default`` and ``default-push`` have a special
5065 The path names ``default`` and ``default-push`` have a special
5066 meaning. When performing a push or pull operation, they are used
5066 meaning. When performing a push or pull operation, they are used
5067 as fallbacks if no location is specified on the command-line.
5067 as fallbacks if no location is specified on the command-line.
5068 When ``default-push`` is set, it will be used for push and
5068 When ``default-push`` is set, it will be used for push and
5069 ``default`` will be used for pull; otherwise ``default`` is used
5069 ``default`` will be used for pull; otherwise ``default`` is used
5070 as the fallback for both. When cloning a repository, the clone
5070 as the fallback for both. When cloning a repository, the clone
5071 source is written as ``default`` in ``.hg/hgrc``. Note that
5071 source is written as ``default`` in ``.hg/hgrc``. Note that
5072 ``default`` and ``default-push`` apply to all inbound (e.g.
5072 ``default`` and ``default-push`` apply to all inbound (e.g.
5073 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5073 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5074 :hg:`bundle`) operations.
5074 :hg:`bundle`) operations.
5075
5075
5076 See :hg:`help urls` for more information.
5076 See :hg:`help urls` for more information.
5077
5077
5078 Returns 0 on success.
5078 Returns 0 on success.
5079 """
5079 """
5080 if search:
5080 if search:
5081 for name, path in sorted(ui.paths.iteritems()):
5081 for name, path in sorted(ui.paths.iteritems()):
5082 if name == search:
5082 if name == search:
5083 ui.status("%s\n" % util.hidepassword(path.loc))
5083 ui.status("%s\n" % util.hidepassword(path.loc))
5084 return
5084 return
5085 if not ui.quiet:
5085 if not ui.quiet:
5086 ui.warn(_("not found!\n"))
5086 ui.warn(_("not found!\n"))
5087 return 1
5087 return 1
5088 else:
5088 else:
5089 for name, path in sorted(ui.paths.iteritems()):
5089 for name, path in sorted(ui.paths.iteritems()):
5090 if ui.quiet:
5090 if ui.quiet:
5091 ui.write("%s\n" % name)
5091 ui.write("%s\n" % name)
5092 else:
5092 else:
5093 ui.write("%s = %s\n" % (name,
5093 ui.write("%s = %s\n" % (name,
5094 util.hidepassword(path.loc)))
5094 util.hidepassword(path.loc)))
5095
5095
5096 @command('phase',
5096 @command('phase',
5097 [('p', 'public', False, _('set changeset phase to public')),
5097 [('p', 'public', False, _('set changeset phase to public')),
5098 ('d', 'draft', False, _('set changeset phase to draft')),
5098 ('d', 'draft', False, _('set changeset phase to draft')),
5099 ('s', 'secret', False, _('set changeset phase to secret')),
5099 ('s', 'secret', False, _('set changeset phase to secret')),
5100 ('f', 'force', False, _('allow to move boundary backward')),
5100 ('f', 'force', False, _('allow to move boundary backward')),
5101 ('r', 'rev', [], _('target revision'), _('REV')),
5101 ('r', 'rev', [], _('target revision'), _('REV')),
5102 ],
5102 ],
5103 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5103 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5104 def phase(ui, repo, *revs, **opts):
5104 def phase(ui, repo, *revs, **opts):
5105 """set or show the current phase name
5105 """set or show the current phase name
5106
5106
5107 With no argument, show the phase name of the current revision(s).
5107 With no argument, show the phase name of the current revision(s).
5108
5108
5109 With one of -p/--public, -d/--draft or -s/--secret, change the
5109 With one of -p/--public, -d/--draft or -s/--secret, change the
5110 phase value of the specified revisions.
5110 phase value of the specified revisions.
5111
5111
5112 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5112 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5113 lower phase to an higher phase. Phases are ordered as follows::
5113 lower phase to an higher phase. Phases are ordered as follows::
5114
5114
5115 public < draft < secret
5115 public < draft < secret
5116
5116
5117 Returns 0 on success, 1 if some phases could not be changed.
5117 Returns 0 on success, 1 if some phases could not be changed.
5118
5118
5119 (For more information about the phases concept, see :hg:`help phases`.)
5119 (For more information about the phases concept, see :hg:`help phases`.)
5120 """
5120 """
5121 # search for a unique phase argument
5121 # search for a unique phase argument
5122 targetphase = None
5122 targetphase = None
5123 for idx, name in enumerate(phases.phasenames):
5123 for idx, name in enumerate(phases.phasenames):
5124 if opts[name]:
5124 if opts[name]:
5125 if targetphase is not None:
5125 if targetphase is not None:
5126 raise error.Abort(_('only one phase can be specified'))
5126 raise error.Abort(_('only one phase can be specified'))
5127 targetphase = idx
5127 targetphase = idx
5128
5128
5129 # look for specified revision
5129 # look for specified revision
5130 revs = list(revs)
5130 revs = list(revs)
5131 revs.extend(opts['rev'])
5131 revs.extend(opts['rev'])
5132 if not revs:
5132 if not revs:
5133 # display both parents as the second parent phase can influence
5133 # display both parents as the second parent phase can influence
5134 # the phase of a merge commit
5134 # the phase of a merge commit
5135 revs = [c.rev() for c in repo[None].parents()]
5135 revs = [c.rev() for c in repo[None].parents()]
5136
5136
5137 revs = scmutil.revrange(repo, revs)
5137 revs = scmutil.revrange(repo, revs)
5138
5138
5139 lock = None
5139 lock = None
5140 ret = 0
5140 ret = 0
5141 if targetphase is None:
5141 if targetphase is None:
5142 # display
5142 # display
5143 for r in revs:
5143 for r in revs:
5144 ctx = repo[r]
5144 ctx = repo[r]
5145 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5145 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5146 else:
5146 else:
5147 tr = None
5147 tr = None
5148 lock = repo.lock()
5148 lock = repo.lock()
5149 try:
5149 try:
5150 tr = repo.transaction("phase")
5150 tr = repo.transaction("phase")
5151 # set phase
5151 # set phase
5152 if not revs:
5152 if not revs:
5153 raise error.Abort(_('empty revision set'))
5153 raise error.Abort(_('empty revision set'))
5154 nodes = [repo[r].node() for r in revs]
5154 nodes = [repo[r].node() for r in revs]
5155 # moving revision from public to draft may hide them
5155 # moving revision from public to draft may hide them
5156 # We have to check result on an unfiltered repository
5156 # We have to check result on an unfiltered repository
5157 unfi = repo.unfiltered()
5157 unfi = repo.unfiltered()
5158 getphase = unfi._phasecache.phase
5158 getphase = unfi._phasecache.phase
5159 olddata = [getphase(unfi, r) for r in unfi]
5159 olddata = [getphase(unfi, r) for r in unfi]
5160 phases.advanceboundary(repo, tr, targetphase, nodes)
5160 phases.advanceboundary(repo, tr, targetphase, nodes)
5161 if opts['force']:
5161 if opts['force']:
5162 phases.retractboundary(repo, tr, targetphase, nodes)
5162 phases.retractboundary(repo, tr, targetphase, nodes)
5163 tr.close()
5163 tr.close()
5164 finally:
5164 finally:
5165 if tr is not None:
5165 if tr is not None:
5166 tr.release()
5166 tr.release()
5167 lock.release()
5167 lock.release()
5168 getphase = unfi._phasecache.phase
5168 getphase = unfi._phasecache.phase
5169 newdata = [getphase(unfi, r) for r in unfi]
5169 newdata = [getphase(unfi, r) for r in unfi]
5170 changes = sum(newdata[r] != olddata[r] for r in unfi)
5170 changes = sum(newdata[r] != olddata[r] for r in unfi)
5171 cl = unfi.changelog
5171 cl = unfi.changelog
5172 rejected = [n for n in nodes
5172 rejected = [n for n in nodes
5173 if newdata[cl.rev(n)] < targetphase]
5173 if newdata[cl.rev(n)] < targetphase]
5174 if rejected:
5174 if rejected:
5175 ui.warn(_('cannot move %i changesets to a higher '
5175 ui.warn(_('cannot move %i changesets to a higher '
5176 'phase, use --force\n') % len(rejected))
5176 'phase, use --force\n') % len(rejected))
5177 ret = 1
5177 ret = 1
5178 if changes:
5178 if changes:
5179 msg = _('phase changed for %i changesets\n') % changes
5179 msg = _('phase changed for %i changesets\n') % changes
5180 if ret:
5180 if ret:
5181 ui.status(msg)
5181 ui.status(msg)
5182 else:
5182 else:
5183 ui.note(msg)
5183 ui.note(msg)
5184 else:
5184 else:
5185 ui.warn(_('no phases changed\n'))
5185 ui.warn(_('no phases changed\n'))
5186 return ret
5186 return ret
5187
5187
5188 def postincoming(ui, repo, modheads, optupdate, checkout):
5188 def postincoming(ui, repo, modheads, optupdate, checkout):
5189 if modheads == 0:
5189 if modheads == 0:
5190 return
5190 return
5191 if optupdate:
5191 if optupdate:
5192 try:
5192 try:
5193 brev = checkout
5193 brev = checkout
5194 movemarkfrom = None
5194 movemarkfrom = None
5195 if not checkout:
5195 if not checkout:
5196 updata = destutil.destupdate(repo)
5196 updata = destutil.destupdate(repo)
5197 checkout, movemarkfrom, brev = updata
5197 checkout, movemarkfrom, brev = updata
5198 ret = hg.update(repo, checkout)
5198 ret = hg.update(repo, checkout)
5199 except error.Abort as inst:
5199 except error.Abort as inst:
5200 ui.warn(_("not updating: %s\n") % str(inst))
5200 ui.warn(_("not updating: %s\n") % str(inst))
5201 if inst.hint:
5201 if inst.hint:
5202 ui.warn(_("(%s)\n") % inst.hint)
5202 ui.warn(_("(%s)\n") % inst.hint)
5203 return 0
5203 return 0
5204 if not ret and not checkout:
5204 if not ret and not checkout:
5205 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5205 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5206 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5206 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5207 return ret
5207 return ret
5208 if modheads > 1:
5208 if modheads > 1:
5209 currentbranchheads = len(repo.branchheads())
5209 currentbranchheads = len(repo.branchheads())
5210 if currentbranchheads == modheads:
5210 if currentbranchheads == modheads:
5211 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5211 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5212 elif currentbranchheads > 1:
5212 elif currentbranchheads > 1:
5213 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5213 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5214 "merge)\n"))
5214 "merge)\n"))
5215 else:
5215 else:
5216 ui.status(_("(run 'hg heads' to see heads)\n"))
5216 ui.status(_("(run 'hg heads' to see heads)\n"))
5217 else:
5217 else:
5218 ui.status(_("(run 'hg update' to get a working copy)\n"))
5218 ui.status(_("(run 'hg update' to get a working copy)\n"))
5219
5219
5220 @command('^pull',
5220 @command('^pull',
5221 [('u', 'update', None,
5221 [('u', 'update', None,
5222 _('update to new branch head if changesets were pulled')),
5222 _('update to new branch head if changesets were pulled')),
5223 ('f', 'force', None, _('run even when remote repository is unrelated')),
5223 ('f', 'force', None, _('run even when remote repository is unrelated')),
5224 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5224 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5225 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5225 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5226 ('b', 'branch', [], _('a specific branch you would like to pull'),
5226 ('b', 'branch', [], _('a specific branch you would like to pull'),
5227 _('BRANCH')),
5227 _('BRANCH')),
5228 ] + remoteopts,
5228 ] + remoteopts,
5229 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5229 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5230 def pull(ui, repo, source="default", **opts):
5230 def pull(ui, repo, source="default", **opts):
5231 """pull changes from the specified source
5231 """pull changes from the specified source
5232
5232
5233 Pull changes from a remote repository to a local one.
5233 Pull changes from a remote repository to a local one.
5234
5234
5235 This finds all changes from the repository at the specified path
5235 This finds all changes from the repository at the specified path
5236 or URL and adds them to a local repository (the current one unless
5236 or URL and adds them to a local repository (the current one unless
5237 -R is specified). By default, this does not update the copy of the
5237 -R is specified). By default, this does not update the copy of the
5238 project in the working directory.
5238 project in the working directory.
5239
5239
5240 Use :hg:`incoming` if you want to see what would have been added
5240 Use :hg:`incoming` if you want to see what would have been added
5241 by a pull at the time you issued this command. If you then decide
5241 by a pull at the time you issued this command. If you then decide
5242 to add those changes to the repository, you should use :hg:`pull
5242 to add those changes to the repository, you should use :hg:`pull
5243 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5243 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5244
5244
5245 If SOURCE is omitted, the 'default' path will be used.
5245 If SOURCE is omitted, the 'default' path will be used.
5246 See :hg:`help urls` for more information.
5246 See :hg:`help urls` for more information.
5247
5247
5248 Returns 0 on success, 1 if an update had unresolved files.
5248 Returns 0 on success, 1 if an update had unresolved files.
5249 """
5249 """
5250 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5250 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5251 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5251 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5252 other = hg.peer(repo, opts, source)
5252 other = hg.peer(repo, opts, source)
5253 try:
5253 try:
5254 revs, checkout = hg.addbranchrevs(repo, other, branches,
5254 revs, checkout = hg.addbranchrevs(repo, other, branches,
5255 opts.get('rev'))
5255 opts.get('rev'))
5256
5256
5257
5257
5258 pullopargs = {}
5258 pullopargs = {}
5259 if opts.get('bookmark'):
5259 if opts.get('bookmark'):
5260 if not revs:
5260 if not revs:
5261 revs = []
5261 revs = []
5262 # The list of bookmark used here is not the one used to actually
5262 # The list of bookmark used here is not the one used to actually
5263 # update the bookmark name. This can result in the revision pulled
5263 # update the bookmark name. This can result in the revision pulled
5264 # not ending up with the name of the bookmark because of a race
5264 # not ending up with the name of the bookmark because of a race
5265 # condition on the server. (See issue 4689 for details)
5265 # condition on the server. (See issue 4689 for details)
5266 remotebookmarks = other.listkeys('bookmarks')
5266 remotebookmarks = other.listkeys('bookmarks')
5267 pullopargs['remotebookmarks'] = remotebookmarks
5267 pullopargs['remotebookmarks'] = remotebookmarks
5268 for b in opts['bookmark']:
5268 for b in opts['bookmark']:
5269 if b not in remotebookmarks:
5269 if b not in remotebookmarks:
5270 raise error.Abort(_('remote bookmark %s not found!') % b)
5270 raise error.Abort(_('remote bookmark %s not found!') % b)
5271 revs.append(remotebookmarks[b])
5271 revs.append(remotebookmarks[b])
5272
5272
5273 if revs:
5273 if revs:
5274 try:
5274 try:
5275 # When 'rev' is a bookmark name, we cannot guarantee that it
5275 # When 'rev' is a bookmark name, we cannot guarantee that it
5276 # will be updated with that name because of a race condition
5276 # will be updated with that name because of a race condition
5277 # server side. (See issue 4689 for details)
5277 # server side. (See issue 4689 for details)
5278 oldrevs = revs
5278 oldrevs = revs
5279 revs = [] # actually, nodes
5279 revs = [] # actually, nodes
5280 for r in oldrevs:
5280 for r in oldrevs:
5281 node = other.lookup(r)
5281 node = other.lookup(r)
5282 revs.append(node)
5282 revs.append(node)
5283 if r == checkout:
5283 if r == checkout:
5284 checkout = node
5284 checkout = node
5285 except error.CapabilityError:
5285 except error.CapabilityError:
5286 err = _("other repository doesn't support revision lookup, "
5286 err = _("other repository doesn't support revision lookup, "
5287 "so a rev cannot be specified.")
5287 "so a rev cannot be specified.")
5288 raise error.Abort(err)
5288 raise error.Abort(err)
5289
5289
5290 modheads = exchange.pull(repo, other, heads=revs,
5290 modheads = exchange.pull(repo, other, heads=revs,
5291 force=opts.get('force'),
5291 force=opts.get('force'),
5292 bookmarks=opts.get('bookmark', ()),
5292 bookmarks=opts.get('bookmark', ()),
5293 opargs=pullopargs).cgresult
5293 opargs=pullopargs).cgresult
5294 if checkout:
5294 if checkout:
5295 checkout = str(repo.changelog.rev(checkout))
5295 checkout = str(repo.changelog.rev(checkout))
5296 repo._subtoppath = source
5296 repo._subtoppath = source
5297 try:
5297 try:
5298 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5298 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5299
5299
5300 finally:
5300 finally:
5301 del repo._subtoppath
5301 del repo._subtoppath
5302
5302
5303 finally:
5303 finally:
5304 other.close()
5304 other.close()
5305 return ret
5305 return ret
5306
5306
5307 @command('^push',
5307 @command('^push',
5308 [('f', 'force', None, _('force push')),
5308 [('f', 'force', None, _('force push')),
5309 ('r', 'rev', [],
5309 ('r', 'rev', [],
5310 _('a changeset intended to be included in the destination'),
5310 _('a changeset intended to be included in the destination'),
5311 _('REV')),
5311 _('REV')),
5312 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5312 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5313 ('b', 'branch', [],
5313 ('b', 'branch', [],
5314 _('a specific branch you would like to push'), _('BRANCH')),
5314 _('a specific branch you would like to push'), _('BRANCH')),
5315 ('', 'new-branch', False, _('allow pushing a new branch')),
5315 ('', 'new-branch', False, _('allow pushing a new branch')),
5316 ] + remoteopts,
5316 ] + remoteopts,
5317 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5317 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5318 def push(ui, repo, dest=None, **opts):
5318 def push(ui, repo, dest=None, **opts):
5319 """push changes to the specified destination
5319 """push changes to the specified destination
5320
5320
5321 Push changesets from the local repository to the specified
5321 Push changesets from the local repository to the specified
5322 destination.
5322 destination.
5323
5323
5324 This operation is symmetrical to pull: it is identical to a pull
5324 This operation is symmetrical to pull: it is identical to a pull
5325 in the destination repository from the current one.
5325 in the destination repository from the current one.
5326
5326
5327 By default, push will not allow creation of new heads at the
5327 By default, push will not allow creation of new heads at the
5328 destination, since multiple heads would make it unclear which head
5328 destination, since multiple heads would make it unclear which head
5329 to use. In this situation, it is recommended to pull and merge
5329 to use. In this situation, it is recommended to pull and merge
5330 before pushing.
5330 before pushing.
5331
5331
5332 Use --new-branch if you want to allow push to create a new named
5332 Use --new-branch if you want to allow push to create a new named
5333 branch that is not present at the destination. This allows you to
5333 branch that is not present at the destination. This allows you to
5334 only create a new branch without forcing other changes.
5334 only create a new branch without forcing other changes.
5335
5335
5336 .. note::
5336 .. note::
5337
5337
5338 Extra care should be taken with the -f/--force option,
5338 Extra care should be taken with the -f/--force option,
5339 which will push all new heads on all branches, an action which will
5339 which will push all new heads on all branches, an action which will
5340 almost always cause confusion for collaborators.
5340 almost always cause confusion for collaborators.
5341
5341
5342 If -r/--rev is used, the specified revision and all its ancestors
5342 If -r/--rev is used, the specified revision and all its ancestors
5343 will be pushed to the remote repository.
5343 will be pushed to the remote repository.
5344
5344
5345 If -B/--bookmark is used, the specified bookmarked revision, its
5345 If -B/--bookmark is used, the specified bookmarked revision, its
5346 ancestors, and the bookmark will be pushed to the remote
5346 ancestors, and the bookmark will be pushed to the remote
5347 repository.
5347 repository.
5348
5348
5349 Please see :hg:`help urls` for important details about ``ssh://``
5349 Please see :hg:`help urls` for important details about ``ssh://``
5350 URLs. If DESTINATION is omitted, a default path will be used.
5350 URLs. If DESTINATION is omitted, a default path will be used.
5351
5351
5352 Returns 0 if push was successful, 1 if nothing to push.
5352 Returns 0 if push was successful, 1 if nothing to push.
5353 """
5353 """
5354
5354
5355 if opts.get('bookmark'):
5355 if opts.get('bookmark'):
5356 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5356 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5357 for b in opts['bookmark']:
5357 for b in opts['bookmark']:
5358 # translate -B options to -r so changesets get pushed
5358 # translate -B options to -r so changesets get pushed
5359 if b in repo._bookmarks:
5359 if b in repo._bookmarks:
5360 opts.setdefault('rev', []).append(b)
5360 opts.setdefault('rev', []).append(b)
5361 else:
5361 else:
5362 # if we try to push a deleted bookmark, translate it to null
5362 # if we try to push a deleted bookmark, translate it to null
5363 # this lets simultaneous -r, -b options continue working
5363 # this lets simultaneous -r, -b options continue working
5364 opts.setdefault('rev', []).append("null")
5364 opts.setdefault('rev', []).append("null")
5365
5365
5366 path = ui.paths.getpath(dest, default='default')
5366 path = ui.paths.getpath(dest, default='default')
5367 if not path:
5367 if not path:
5368 raise error.Abort(_('default repository not configured!'),
5368 raise error.Abort(_('default repository not configured!'),
5369 hint=_('see the "path" section in "hg help config"'))
5369 hint=_('see the "path" section in "hg help config"'))
5370 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5370 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5371 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5371 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5372 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5372 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5373 other = hg.peer(repo, opts, dest)
5373 other = hg.peer(repo, opts, dest)
5374
5374
5375 if revs:
5375 if revs:
5376 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5376 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5377 if not revs:
5377 if not revs:
5378 raise error.Abort(_("specified revisions evaluate to an empty set"),
5378 raise error.Abort(_("specified revisions evaluate to an empty set"),
5379 hint=_("use different revision arguments"))
5379 hint=_("use different revision arguments"))
5380
5380
5381 repo._subtoppath = dest
5381 repo._subtoppath = dest
5382 try:
5382 try:
5383 # push subrepos depth-first for coherent ordering
5383 # push subrepos depth-first for coherent ordering
5384 c = repo['']
5384 c = repo['']
5385 subs = c.substate # only repos that are committed
5385 subs = c.substate # only repos that are committed
5386 for s in sorted(subs):
5386 for s in sorted(subs):
5387 result = c.sub(s).push(opts)
5387 result = c.sub(s).push(opts)
5388 if result == 0:
5388 if result == 0:
5389 return not result
5389 return not result
5390 finally:
5390 finally:
5391 del repo._subtoppath
5391 del repo._subtoppath
5392 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5392 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5393 newbranch=opts.get('new_branch'),
5393 newbranch=opts.get('new_branch'),
5394 bookmarks=opts.get('bookmark', ()))
5394 bookmarks=opts.get('bookmark', ()))
5395
5395
5396 result = not pushop.cgresult
5396 result = not pushop.cgresult
5397
5397
5398 if pushop.bkresult is not None:
5398 if pushop.bkresult is not None:
5399 if pushop.bkresult == 2:
5399 if pushop.bkresult == 2:
5400 result = 2
5400 result = 2
5401 elif not result and pushop.bkresult:
5401 elif not result and pushop.bkresult:
5402 result = 2
5402 result = 2
5403
5403
5404 return result
5404 return result
5405
5405
5406 @command('recover', [])
5406 @command('recover', [])
5407 def recover(ui, repo):
5407 def recover(ui, repo):
5408 """roll back an interrupted transaction
5408 """roll back an interrupted transaction
5409
5409
5410 Recover from an interrupted commit or pull.
5410 Recover from an interrupted commit or pull.
5411
5411
5412 This command tries to fix the repository status after an
5412 This command tries to fix the repository status after an
5413 interrupted operation. It should only be necessary when Mercurial
5413 interrupted operation. It should only be necessary when Mercurial
5414 suggests it.
5414 suggests it.
5415
5415
5416 Returns 0 if successful, 1 if nothing to recover or verify fails.
5416 Returns 0 if successful, 1 if nothing to recover or verify fails.
5417 """
5417 """
5418 if repo.recover():
5418 if repo.recover():
5419 return hg.verify(repo)
5419 return hg.verify(repo)
5420 return 1
5420 return 1
5421
5421
5422 @command('^remove|rm',
5422 @command('^remove|rm',
5423 [('A', 'after', None, _('record delete for missing files')),
5423 [('A', 'after', None, _('record delete for missing files')),
5424 ('f', 'force', None,
5424 ('f', 'force', None,
5425 _('remove (and delete) file even if added or modified')),
5425 _('remove (and delete) file even if added or modified')),
5426 ] + subrepoopts + walkopts,
5426 ] + subrepoopts + walkopts,
5427 _('[OPTION]... FILE...'),
5427 _('[OPTION]... FILE...'),
5428 inferrepo=True)
5428 inferrepo=True)
5429 def remove(ui, repo, *pats, **opts):
5429 def remove(ui, repo, *pats, **opts):
5430 """remove the specified files on the next commit
5430 """remove the specified files on the next commit
5431
5431
5432 Schedule the indicated files for removal from the current branch.
5432 Schedule the indicated files for removal from the current branch.
5433
5433
5434 This command schedules the files to be removed at the next commit.
5434 This command schedules the files to be removed at the next commit.
5435 To undo a remove before that, see :hg:`revert`. To undo added
5435 To undo a remove before that, see :hg:`revert`. To undo added
5436 files, see :hg:`forget`.
5436 files, see :hg:`forget`.
5437
5437
5438 .. container:: verbose
5438 .. container:: verbose
5439
5439
5440 -A/--after can be used to remove only files that have already
5440 -A/--after can be used to remove only files that have already
5441 been deleted, -f/--force can be used to force deletion, and -Af
5441 been deleted, -f/--force can be used to force deletion, and -Af
5442 can be used to remove files from the next revision without
5442 can be used to remove files from the next revision without
5443 deleting them from the working directory.
5443 deleting them from the working directory.
5444
5444
5445 The following table details the behavior of remove for different
5445 The following table details the behavior of remove for different
5446 file states (columns) and option combinations (rows). The file
5446 file states (columns) and option combinations (rows). The file
5447 states are Added [A], Clean [C], Modified [M] and Missing [!]
5447 states are Added [A], Clean [C], Modified [M] and Missing [!]
5448 (as reported by :hg:`status`). The actions are Warn, Remove
5448 (as reported by :hg:`status`). The actions are Warn, Remove
5449 (from branch) and Delete (from disk):
5449 (from branch) and Delete (from disk):
5450
5450
5451 ========= == == == ==
5451 ========= == == == ==
5452 opt/state A C M !
5452 opt/state A C M !
5453 ========= == == == ==
5453 ========= == == == ==
5454 none W RD W R
5454 none W RD W R
5455 -f R RD RD R
5455 -f R RD RD R
5456 -A W W W R
5456 -A W W W R
5457 -Af R R R R
5457 -Af R R R R
5458 ========= == == == ==
5458 ========= == == == ==
5459
5459
5460 Note that remove never deletes files in Added [A] state from the
5460 Note that remove never deletes files in Added [A] state from the
5461 working directory, not even if option --force is specified.
5461 working directory, not even if option --force is specified.
5462
5462
5463 Returns 0 on success, 1 if any warnings encountered.
5463 Returns 0 on success, 1 if any warnings encountered.
5464 """
5464 """
5465
5465
5466 after, force = opts.get('after'), opts.get('force')
5466 after, force = opts.get('after'), opts.get('force')
5467 if not pats and not after:
5467 if not pats and not after:
5468 raise error.Abort(_('no files specified'))
5468 raise error.Abort(_('no files specified'))
5469
5469
5470 m = scmutil.match(repo[None], pats, opts)
5470 m = scmutil.match(repo[None], pats, opts)
5471 subrepos = opts.get('subrepos')
5471 subrepos = opts.get('subrepos')
5472 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5472 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5473
5473
5474 @command('rename|move|mv',
5474 @command('rename|move|mv',
5475 [('A', 'after', None, _('record a rename that has already occurred')),
5475 [('A', 'after', None, _('record a rename that has already occurred')),
5476 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5476 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5477 ] + walkopts + dryrunopts,
5477 ] + walkopts + dryrunopts,
5478 _('[OPTION]... SOURCE... DEST'))
5478 _('[OPTION]... SOURCE... DEST'))
5479 def rename(ui, repo, *pats, **opts):
5479 def rename(ui, repo, *pats, **opts):
5480 """rename files; equivalent of copy + remove
5480 """rename files; equivalent of copy + remove
5481
5481
5482 Mark dest as copies of sources; mark sources for deletion. If dest
5482 Mark dest as copies of sources; mark sources for deletion. If dest
5483 is a directory, copies are put in that directory. If dest is a
5483 is a directory, copies are put in that directory. If dest is a
5484 file, there can only be one source.
5484 file, there can only be one source.
5485
5485
5486 By default, this command copies the contents of files as they
5486 By default, this command copies the contents of files as they
5487 exist in the working directory. If invoked with -A/--after, the
5487 exist in the working directory. If invoked with -A/--after, the
5488 operation is recorded, but no copying is performed.
5488 operation is recorded, but no copying is performed.
5489
5489
5490 This command takes effect at the next commit. To undo a rename
5490 This command takes effect at the next commit. To undo a rename
5491 before that, see :hg:`revert`.
5491 before that, see :hg:`revert`.
5492
5492
5493 Returns 0 on success, 1 if errors are encountered.
5493 Returns 0 on success, 1 if errors are encountered.
5494 """
5494 """
5495 wlock = repo.wlock(False)
5495 wlock = repo.wlock(False)
5496 try:
5496 try:
5497 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5497 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5498 finally:
5498 finally:
5499 wlock.release()
5499 wlock.release()
5500
5500
5501 @command('resolve',
5501 @command('resolve',
5502 [('a', 'all', None, _('select all unresolved files')),
5502 [('a', 'all', None, _('select all unresolved files')),
5503 ('l', 'list', None, _('list state of files needing merge')),
5503 ('l', 'list', None, _('list state of files needing merge')),
5504 ('m', 'mark', None, _('mark files as resolved')),
5504 ('m', 'mark', None, _('mark files as resolved')),
5505 ('u', 'unmark', None, _('mark files as unresolved')),
5505 ('u', 'unmark', None, _('mark files as unresolved')),
5506 ('n', 'no-status', None, _('hide status prefix'))]
5506 ('n', 'no-status', None, _('hide status prefix'))]
5507 + mergetoolopts + walkopts + formatteropts,
5507 + mergetoolopts + walkopts + formatteropts,
5508 _('[OPTION]... [FILE]...'),
5508 _('[OPTION]... [FILE]...'),
5509 inferrepo=True)
5509 inferrepo=True)
5510 def resolve(ui, repo, *pats, **opts):
5510 def resolve(ui, repo, *pats, **opts):
5511 """redo merges or set/view the merge status of files
5511 """redo merges or set/view the merge status of files
5512
5512
5513 Merges with unresolved conflicts are often the result of
5513 Merges with unresolved conflicts are often the result of
5514 non-interactive merging using the ``internal:merge`` configuration
5514 non-interactive merging using the ``internal:merge`` configuration
5515 setting, or a command-line merge tool like ``diff3``. The resolve
5515 setting, or a command-line merge tool like ``diff3``. The resolve
5516 command is used to manage the files involved in a merge, after
5516 command is used to manage the files involved in a merge, after
5517 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5517 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5518 working directory must have two parents). See :hg:`help
5518 working directory must have two parents). See :hg:`help
5519 merge-tools` for information on configuring merge tools.
5519 merge-tools` for information on configuring merge tools.
5520
5520
5521 The resolve command can be used in the following ways:
5521 The resolve command can be used in the following ways:
5522
5522
5523 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5523 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5524 files, discarding any previous merge attempts. Re-merging is not
5524 files, discarding any previous merge attempts. Re-merging is not
5525 performed for files already marked as resolved. Use ``--all/-a``
5525 performed for files already marked as resolved. Use ``--all/-a``
5526 to select all unresolved files. ``--tool`` can be used to specify
5526 to select all unresolved files. ``--tool`` can be used to specify
5527 the merge tool used for the given files. It overrides the HGMERGE
5527 the merge tool used for the given files. It overrides the HGMERGE
5528 environment variable and your configuration files. Previous file
5528 environment variable and your configuration files. Previous file
5529 contents are saved with a ``.orig`` suffix.
5529 contents are saved with a ``.orig`` suffix.
5530
5530
5531 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5531 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5532 (e.g. after having manually fixed-up the files). The default is
5532 (e.g. after having manually fixed-up the files). The default is
5533 to mark all unresolved files.
5533 to mark all unresolved files.
5534
5534
5535 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5535 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5536 default is to mark all resolved files.
5536 default is to mark all resolved files.
5537
5537
5538 - :hg:`resolve -l`: list files which had or still have conflicts.
5538 - :hg:`resolve -l`: list files which had or still have conflicts.
5539 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5539 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5540
5540
5541 Note that Mercurial will not let you commit files with unresolved
5541 Note that Mercurial will not let you commit files with unresolved
5542 merge conflicts. You must use :hg:`resolve -m ...` before you can
5542 merge conflicts. You must use :hg:`resolve -m ...` before you can
5543 commit after a conflicting merge.
5543 commit after a conflicting merge.
5544
5544
5545 Returns 0 on success, 1 if any files fail a resolve attempt.
5545 Returns 0 on success, 1 if any files fail a resolve attempt.
5546 """
5546 """
5547
5547
5548 all, mark, unmark, show, nostatus = \
5548 all, mark, unmark, show, nostatus = \
5549 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5549 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5550
5550
5551 if (show and (mark or unmark)) or (mark and unmark):
5551 if (show and (mark or unmark)) or (mark and unmark):
5552 raise error.Abort(_("too many options specified"))
5552 raise error.Abort(_("too many options specified"))
5553 if pats and all:
5553 if pats and all:
5554 raise error.Abort(_("can't specify --all and patterns"))
5554 raise error.Abort(_("can't specify --all and patterns"))
5555 if not (all or pats or show or mark or unmark):
5555 if not (all or pats or show or mark or unmark):
5556 raise error.Abort(_('no files or directories specified'),
5556 raise error.Abort(_('no files or directories specified'),
5557 hint=('use --all to re-merge all unresolved files'))
5557 hint=('use --all to re-merge all unresolved files'))
5558
5558
5559 if show:
5559 if show:
5560 fm = ui.formatter('resolve', opts)
5560 fm = ui.formatter('resolve', opts)
5561 ms = mergemod.mergestate(repo)
5561 ms = mergemod.mergestate(repo)
5562 m = scmutil.match(repo[None], pats, opts)
5562 m = scmutil.match(repo[None], pats, opts)
5563 for f in ms:
5563 for f in ms:
5564 if not m(f):
5564 if not m(f):
5565 continue
5565 continue
5566 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5566 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5567 fm.startitem()
5567 fm.startitem()
5568 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5568 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5569 fm.write('path', '%s\n', f, label=l)
5569 fm.write('path', '%s\n', f, label=l)
5570 fm.end()
5570 fm.end()
5571 return 0
5571 return 0
5572
5572
5573 wlock = repo.wlock()
5573 wlock = repo.wlock()
5574 try:
5574 try:
5575 ms = mergemod.mergestate(repo)
5575 ms = mergemod.mergestate(repo)
5576
5576
5577 if not (ms.active() or repo.dirstate.p2() != nullid):
5577 if not (ms.active() or repo.dirstate.p2() != nullid):
5578 raise error.Abort(
5578 raise error.Abort(
5579 _('resolve command not applicable when not merging'))
5579 _('resolve command not applicable when not merging'))
5580
5580
5581 m = scmutil.match(repo[None], pats, opts)
5581 m = scmutil.match(repo[None], pats, opts)
5582 ret = 0
5582 ret = 0
5583 didwork = False
5583 didwork = False
5584
5584
5585 tocomplete = []
5585 tocomplete = []
5586 for f in ms:
5586 for f in ms:
5587 if not m(f):
5587 if not m(f):
5588 continue
5588 continue
5589
5589
5590 didwork = True
5590 didwork = True
5591
5591
5592 if mark:
5592 if mark:
5593 ms.mark(f, "r")
5593 ms.mark(f, "r")
5594 elif unmark:
5594 elif unmark:
5595 ms.mark(f, "u")
5595 ms.mark(f, "u")
5596 else:
5596 else:
5597 wctx = repo[None]
5597 wctx = repo[None]
5598
5598
5599 # backup pre-resolve (merge uses .orig for its own purposes)
5599 # backup pre-resolve (merge uses .orig for its own purposes)
5600 a = repo.wjoin(f)
5600 a = repo.wjoin(f)
5601 util.copyfile(a, a + ".resolve")
5601 util.copyfile(a, a + ".resolve")
5602
5602
5603 try:
5603 try:
5604 # preresolve file
5604 # preresolve file
5605 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5605 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5606 'resolve')
5606 'resolve')
5607 complete, r = ms.preresolve(f, wctx)
5607 complete, r = ms.preresolve(f, wctx)
5608 if not complete:
5608 if not complete:
5609 tocomplete.append(f)
5609 tocomplete.append(f)
5610 elif r:
5610 elif r:
5611 ret = 1
5611 ret = 1
5612 finally:
5612 finally:
5613 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5613 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5614 ms.commit()
5614 ms.commit()
5615
5615
5616 # replace filemerge's .orig file with our resolve file
5616 # replace filemerge's .orig file with our resolve file
5617 # for files in tocomplete, ms.resolve will not overwrite
5617 # for files in tocomplete, ms.resolve will not overwrite
5618 # .orig -- only preresolve does
5618 # .orig -- only preresolve does
5619 util.rename(a + ".resolve", a + ".orig")
5619 util.rename(a + ".resolve", a + ".orig")
5620
5620
5621 for f in tocomplete:
5621 for f in tocomplete:
5622 try:
5622 try:
5623 # resolve file
5623 # resolve file
5624 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5624 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5625 'resolve')
5625 'resolve')
5626 r = ms.resolve(f, wctx)
5626 r = ms.resolve(f, wctx)
5627 if r:
5627 if r:
5628 ret = 1
5628 ret = 1
5629 finally:
5629 finally:
5630 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5630 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5631 ms.commit()
5631 ms.commit()
5632
5632
5633 ms.commit()
5633 ms.commit()
5634
5634
5635 if not didwork and pats:
5635 if not didwork and pats:
5636 ui.warn(_("arguments do not match paths that need resolving\n"))
5636 ui.warn(_("arguments do not match paths that need resolving\n"))
5637
5637
5638 finally:
5638 finally:
5639 wlock.release()
5639 wlock.release()
5640
5640
5641 # Nudge users into finishing an unfinished operation
5641 # Nudge users into finishing an unfinished operation
5642 if not list(ms.unresolved()):
5642 if not list(ms.unresolved()):
5643 ui.status(_('(no more unresolved files)\n'))
5643 ui.status(_('(no more unresolved files)\n'))
5644
5644
5645 return ret
5645 return ret
5646
5646
5647 @command('revert',
5647 @command('revert',
5648 [('a', 'all', None, _('revert all changes when no arguments given')),
5648 [('a', 'all', None, _('revert all changes when no arguments given')),
5649 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5649 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5650 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5650 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5651 ('C', 'no-backup', None, _('do not save backup copies of files')),
5651 ('C', 'no-backup', None, _('do not save backup copies of files')),
5652 ('i', 'interactive', None,
5652 ('i', 'interactive', None,
5653 _('interactively select the changes (EXPERIMENTAL)')),
5653 _('interactively select the changes (EXPERIMENTAL)')),
5654 ] + walkopts + dryrunopts,
5654 ] + walkopts + dryrunopts,
5655 _('[OPTION]... [-r REV] [NAME]...'))
5655 _('[OPTION]... [-r REV] [NAME]...'))
5656 def revert(ui, repo, *pats, **opts):
5656 def revert(ui, repo, *pats, **opts):
5657 """restore files to their checkout state
5657 """restore files to their checkout state
5658
5658
5659 .. note::
5659 .. note::
5660
5660
5661 To check out earlier revisions, you should use :hg:`update REV`.
5661 To check out earlier revisions, you should use :hg:`update REV`.
5662 To cancel an uncommitted merge (and lose your changes),
5662 To cancel an uncommitted merge (and lose your changes),
5663 use :hg:`update --clean .`.
5663 use :hg:`update --clean .`.
5664
5664
5665 With no revision specified, revert the specified files or directories
5665 With no revision specified, revert the specified files or directories
5666 to the contents they had in the parent of the working directory.
5666 to the contents they had in the parent of the working directory.
5667 This restores the contents of files to an unmodified
5667 This restores the contents of files to an unmodified
5668 state and unschedules adds, removes, copies, and renames. If the
5668 state and unschedules adds, removes, copies, and renames. If the
5669 working directory has two parents, you must explicitly specify a
5669 working directory has two parents, you must explicitly specify a
5670 revision.
5670 revision.
5671
5671
5672 Using the -r/--rev or -d/--date options, revert the given files or
5672 Using the -r/--rev or -d/--date options, revert the given files or
5673 directories to their states as of a specific revision. Because
5673 directories to their states as of a specific revision. Because
5674 revert does not change the working directory parents, this will
5674 revert does not change the working directory parents, this will
5675 cause these files to appear modified. This can be helpful to "back
5675 cause these files to appear modified. This can be helpful to "back
5676 out" some or all of an earlier change. See :hg:`backout` for a
5676 out" some or all of an earlier change. See :hg:`backout` for a
5677 related method.
5677 related method.
5678
5678
5679 Modified files are saved with a .orig suffix before reverting.
5679 Modified files are saved with a .orig suffix before reverting.
5680 To disable these backups, use --no-backup.
5680 To disable these backups, use --no-backup.
5681
5681
5682 See :hg:`help dates` for a list of formats valid for -d/--date.
5682 See :hg:`help dates` for a list of formats valid for -d/--date.
5683
5683
5684 See :hg:`help backout` for a way to reverse the effect of an
5684 See :hg:`help backout` for a way to reverse the effect of an
5685 earlier changeset.
5685 earlier changeset.
5686
5686
5687 Returns 0 on success.
5687 Returns 0 on success.
5688 """
5688 """
5689
5689
5690 if opts.get("date"):
5690 if opts.get("date"):
5691 if opts.get("rev"):
5691 if opts.get("rev"):
5692 raise error.Abort(_("you can't specify a revision and a date"))
5692 raise error.Abort(_("you can't specify a revision and a date"))
5693 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5693 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5694
5694
5695 parent, p2 = repo.dirstate.parents()
5695 parent, p2 = repo.dirstate.parents()
5696 if not opts.get('rev') and p2 != nullid:
5696 if not opts.get('rev') and p2 != nullid:
5697 # revert after merge is a trap for new users (issue2915)
5697 # revert after merge is a trap for new users (issue2915)
5698 raise error.Abort(_('uncommitted merge with no revision specified'),
5698 raise error.Abort(_('uncommitted merge with no revision specified'),
5699 hint=_('use "hg update" or see "hg help revert"'))
5699 hint=_('use "hg update" or see "hg help revert"'))
5700
5700
5701 ctx = scmutil.revsingle(repo, opts.get('rev'))
5701 ctx = scmutil.revsingle(repo, opts.get('rev'))
5702
5702
5703 if (not (pats or opts.get('include') or opts.get('exclude') or
5703 if (not (pats or opts.get('include') or opts.get('exclude') or
5704 opts.get('all') or opts.get('interactive'))):
5704 opts.get('all') or opts.get('interactive'))):
5705 msg = _("no files or directories specified")
5705 msg = _("no files or directories specified")
5706 if p2 != nullid:
5706 if p2 != nullid:
5707 hint = _("uncommitted merge, use --all to discard all changes,"
5707 hint = _("uncommitted merge, use --all to discard all changes,"
5708 " or 'hg update -C .' to abort the merge")
5708 " or 'hg update -C .' to abort the merge")
5709 raise error.Abort(msg, hint=hint)
5709 raise error.Abort(msg, hint=hint)
5710 dirty = any(repo.status())
5710 dirty = any(repo.status())
5711 node = ctx.node()
5711 node = ctx.node()
5712 if node != parent:
5712 if node != parent:
5713 if dirty:
5713 if dirty:
5714 hint = _("uncommitted changes, use --all to discard all"
5714 hint = _("uncommitted changes, use --all to discard all"
5715 " changes, or 'hg update %s' to update") % ctx.rev()
5715 " changes, or 'hg update %s' to update") % ctx.rev()
5716 else:
5716 else:
5717 hint = _("use --all to revert all files,"
5717 hint = _("use --all to revert all files,"
5718 " or 'hg update %s' to update") % ctx.rev()
5718 " or 'hg update %s' to update") % ctx.rev()
5719 elif dirty:
5719 elif dirty:
5720 hint = _("uncommitted changes, use --all to discard all changes")
5720 hint = _("uncommitted changes, use --all to discard all changes")
5721 else:
5721 else:
5722 hint = _("use --all to revert all files")
5722 hint = _("use --all to revert all files")
5723 raise error.Abort(msg, hint=hint)
5723 raise error.Abort(msg, hint=hint)
5724
5724
5725 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5725 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5726
5726
5727 @command('rollback', dryrunopts +
5727 @command('rollback', dryrunopts +
5728 [('f', 'force', False, _('ignore safety measures'))])
5728 [('f', 'force', False, _('ignore safety measures'))])
5729 def rollback(ui, repo, **opts):
5729 def rollback(ui, repo, **opts):
5730 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5730 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5731
5731
5732 Please use :hg:`commit --amend` instead of rollback to correct
5732 Please use :hg:`commit --amend` instead of rollback to correct
5733 mistakes in the last commit.
5733 mistakes in the last commit.
5734
5734
5735 This command should be used with care. There is only one level of
5735 This command should be used with care. There is only one level of
5736 rollback, and there is no way to undo a rollback. It will also
5736 rollback, and there is no way to undo a rollback. It will also
5737 restore the dirstate at the time of the last transaction, losing
5737 restore the dirstate at the time of the last transaction, losing
5738 any dirstate changes since that time. This command does not alter
5738 any dirstate changes since that time. This command does not alter
5739 the working directory.
5739 the working directory.
5740
5740
5741 Transactions are used to encapsulate the effects of all commands
5741 Transactions are used to encapsulate the effects of all commands
5742 that create new changesets or propagate existing changesets into a
5742 that create new changesets or propagate existing changesets into a
5743 repository.
5743 repository.
5744
5744
5745 .. container:: verbose
5745 .. container:: verbose
5746
5746
5747 For example, the following commands are transactional, and their
5747 For example, the following commands are transactional, and their
5748 effects can be rolled back:
5748 effects can be rolled back:
5749
5749
5750 - commit
5750 - commit
5751 - import
5751 - import
5752 - pull
5752 - pull
5753 - push (with this repository as the destination)
5753 - push (with this repository as the destination)
5754 - unbundle
5754 - unbundle
5755
5755
5756 To avoid permanent data loss, rollback will refuse to rollback a
5756 To avoid permanent data loss, rollback will refuse to rollback a
5757 commit transaction if it isn't checked out. Use --force to
5757 commit transaction if it isn't checked out. Use --force to
5758 override this protection.
5758 override this protection.
5759
5759
5760 This command is not intended for use on public repositories. Once
5760 This command is not intended for use on public repositories. Once
5761 changes are visible for pull by other users, rolling a transaction
5761 changes are visible for pull by other users, rolling a transaction
5762 back locally is ineffective (someone else may already have pulled
5762 back locally is ineffective (someone else may already have pulled
5763 the changes). Furthermore, a race is possible with readers of the
5763 the changes). Furthermore, a race is possible with readers of the
5764 repository; for example an in-progress pull from the repository
5764 repository; for example an in-progress pull from the repository
5765 may fail if a rollback is performed.
5765 may fail if a rollback is performed.
5766
5766
5767 Returns 0 on success, 1 if no rollback data is available.
5767 Returns 0 on success, 1 if no rollback data is available.
5768 """
5768 """
5769 return repo.rollback(dryrun=opts.get('dry_run'),
5769 return repo.rollback(dryrun=opts.get('dry_run'),
5770 force=opts.get('force'))
5770 force=opts.get('force'))
5771
5771
5772 @command('root', [])
5772 @command('root', [])
5773 def root(ui, repo):
5773 def root(ui, repo):
5774 """print the root (top) of the current working directory
5774 """print the root (top) of the current working directory
5775
5775
5776 Print the root directory of the current repository.
5776 Print the root directory of the current repository.
5777
5777
5778 Returns 0 on success.
5778 Returns 0 on success.
5779 """
5779 """
5780 ui.write(repo.root + "\n")
5780 ui.write(repo.root + "\n")
5781
5781
5782 @command('^serve',
5782 @command('^serve',
5783 [('A', 'accesslog', '', _('name of access log file to write to'),
5783 [('A', 'accesslog', '', _('name of access log file to write to'),
5784 _('FILE')),
5784 _('FILE')),
5785 ('d', 'daemon', None, _('run server in background')),
5785 ('d', 'daemon', None, _('run server in background')),
5786 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5786 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5787 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5787 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5788 # use string type, then we can check if something was passed
5788 # use string type, then we can check if something was passed
5789 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5789 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5790 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5790 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5791 _('ADDR')),
5791 _('ADDR')),
5792 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5792 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5793 _('PREFIX')),
5793 _('PREFIX')),
5794 ('n', 'name', '',
5794 ('n', 'name', '',
5795 _('name to show in web pages (default: working directory)'), _('NAME')),
5795 _('name to show in web pages (default: working directory)'), _('NAME')),
5796 ('', 'web-conf', '',
5796 ('', 'web-conf', '',
5797 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5797 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5798 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5798 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5799 _('FILE')),
5799 _('FILE')),
5800 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5800 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5801 ('', 'stdio', None, _('for remote clients')),
5801 ('', 'stdio', None, _('for remote clients')),
5802 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5802 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5803 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5803 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5804 ('', 'style', '', _('template style to use'), _('STYLE')),
5804 ('', 'style', '', _('template style to use'), _('STYLE')),
5805 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5805 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5806 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5806 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5807 _('[OPTION]...'),
5807 _('[OPTION]...'),
5808 optionalrepo=True)
5808 optionalrepo=True)
5809 def serve(ui, repo, **opts):
5809 def serve(ui, repo, **opts):
5810 """start stand-alone webserver
5810 """start stand-alone webserver
5811
5811
5812 Start a local HTTP repository browser and pull server. You can use
5812 Start a local HTTP repository browser and pull server. You can use
5813 this for ad-hoc sharing and browsing of repositories. It is
5813 this for ad-hoc sharing and browsing of repositories. It is
5814 recommended to use a real web server to serve a repository for
5814 recommended to use a real web server to serve a repository for
5815 longer periods of time.
5815 longer periods of time.
5816
5816
5817 Please note that the server does not implement access control.
5817 Please note that the server does not implement access control.
5818 This means that, by default, anybody can read from the server and
5818 This means that, by default, anybody can read from the server and
5819 nobody can write to it by default. Set the ``web.allow_push``
5819 nobody can write to it by default. Set the ``web.allow_push``
5820 option to ``*`` to allow everybody to push to the server. You
5820 option to ``*`` to allow everybody to push to the server. You
5821 should use a real web server if you need to authenticate users.
5821 should use a real web server if you need to authenticate users.
5822
5822
5823 By default, the server logs accesses to stdout and errors to
5823 By default, the server logs accesses to stdout and errors to
5824 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5824 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5825 files.
5825 files.
5826
5826
5827 To have the server choose a free port number to listen on, specify
5827 To have the server choose a free port number to listen on, specify
5828 a port number of 0; in this case, the server will print the port
5828 a port number of 0; in this case, the server will print the port
5829 number it uses.
5829 number it uses.
5830
5830
5831 Returns 0 on success.
5831 Returns 0 on success.
5832 """
5832 """
5833
5833
5834 if opts["stdio"] and opts["cmdserver"]:
5834 if opts["stdio"] and opts["cmdserver"]:
5835 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5835 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5836
5836
5837 if opts["stdio"]:
5837 if opts["stdio"]:
5838 if repo is None:
5838 if repo is None:
5839 raise error.RepoError(_("there is no Mercurial repository here"
5839 raise error.RepoError(_("there is no Mercurial repository here"
5840 " (.hg not found)"))
5840 " (.hg not found)"))
5841 s = sshserver.sshserver(ui, repo)
5841 s = sshserver.sshserver(ui, repo)
5842 s.serve_forever()
5842 s.serve_forever()
5843
5843
5844 if opts["cmdserver"]:
5844 if opts["cmdserver"]:
5845 import commandserver
5845 import commandserver
5846 service = commandserver.createservice(ui, repo, opts)
5846 service = commandserver.createservice(ui, repo, opts)
5847 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5847 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5848
5848
5849 # this way we can check if something was given in the command-line
5849 # this way we can check if something was given in the command-line
5850 if opts.get('port'):
5850 if opts.get('port'):
5851 opts['port'] = util.getport(opts.get('port'))
5851 opts['port'] = util.getport(opts.get('port'))
5852
5852
5853 if repo:
5853 if repo:
5854 baseui = repo.baseui
5854 baseui = repo.baseui
5855 else:
5855 else:
5856 baseui = ui
5856 baseui = ui
5857 optlist = ("name templates style address port prefix ipv6"
5857 optlist = ("name templates style address port prefix ipv6"
5858 " accesslog errorlog certificate encoding")
5858 " accesslog errorlog certificate encoding")
5859 for o in optlist.split():
5859 for o in optlist.split():
5860 val = opts.get(o, '')
5860 val = opts.get(o, '')
5861 if val in (None, ''): # should check against default options instead
5861 if val in (None, ''): # should check against default options instead
5862 continue
5862 continue
5863 baseui.setconfig("web", o, val, 'serve')
5863 baseui.setconfig("web", o, val, 'serve')
5864 if repo and repo.ui != baseui:
5864 if repo and repo.ui != baseui:
5865 repo.ui.setconfig("web", o, val, 'serve')
5865 repo.ui.setconfig("web", o, val, 'serve')
5866
5866
5867 o = opts.get('web_conf') or opts.get('webdir_conf')
5867 o = opts.get('web_conf') or opts.get('webdir_conf')
5868 if not o:
5868 if not o:
5869 if not repo:
5869 if not repo:
5870 raise error.RepoError(_("there is no Mercurial repository"
5870 raise error.RepoError(_("there is no Mercurial repository"
5871 " here (.hg not found)"))
5871 " here (.hg not found)"))
5872 o = repo
5872 o = repo
5873
5873
5874 app = hgweb.hgweb(o, baseui=baseui)
5874 app = hgweb.hgweb(o, baseui=baseui)
5875 service = httpservice(ui, app, opts)
5875 service = httpservice(ui, app, opts)
5876 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5876 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5877
5877
5878 class httpservice(object):
5878 class httpservice(object):
5879 def __init__(self, ui, app, opts):
5879 def __init__(self, ui, app, opts):
5880 self.ui = ui
5880 self.ui = ui
5881 self.app = app
5881 self.app = app
5882 self.opts = opts
5882 self.opts = opts
5883
5883
5884 def init(self):
5884 def init(self):
5885 util.setsignalhandler()
5885 util.setsignalhandler()
5886 self.httpd = hgweb_server.create_server(self.ui, self.app)
5886 self.httpd = hgweb_server.create_server(self.ui, self.app)
5887
5887
5888 if self.opts['port'] and not self.ui.verbose:
5888 if self.opts['port'] and not self.ui.verbose:
5889 return
5889 return
5890
5890
5891 if self.httpd.prefix:
5891 if self.httpd.prefix:
5892 prefix = self.httpd.prefix.strip('/') + '/'
5892 prefix = self.httpd.prefix.strip('/') + '/'
5893 else:
5893 else:
5894 prefix = ''
5894 prefix = ''
5895
5895
5896 port = ':%d' % self.httpd.port
5896 port = ':%d' % self.httpd.port
5897 if port == ':80':
5897 if port == ':80':
5898 port = ''
5898 port = ''
5899
5899
5900 bindaddr = self.httpd.addr
5900 bindaddr = self.httpd.addr
5901 if bindaddr == '0.0.0.0':
5901 if bindaddr == '0.0.0.0':
5902 bindaddr = '*'
5902 bindaddr = '*'
5903 elif ':' in bindaddr: # IPv6
5903 elif ':' in bindaddr: # IPv6
5904 bindaddr = '[%s]' % bindaddr
5904 bindaddr = '[%s]' % bindaddr
5905
5905
5906 fqaddr = self.httpd.fqaddr
5906 fqaddr = self.httpd.fqaddr
5907 if ':' in fqaddr:
5907 if ':' in fqaddr:
5908 fqaddr = '[%s]' % fqaddr
5908 fqaddr = '[%s]' % fqaddr
5909 if self.opts['port']:
5909 if self.opts['port']:
5910 write = self.ui.status
5910 write = self.ui.status
5911 else:
5911 else:
5912 write = self.ui.write
5912 write = self.ui.write
5913 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5913 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5914 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5914 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5915 self.ui.flush() # avoid buffering of status message
5915 self.ui.flush() # avoid buffering of status message
5916
5916
5917 def run(self):
5917 def run(self):
5918 self.httpd.serve_forever()
5918 self.httpd.serve_forever()
5919
5919
5920
5920
5921 @command('^status|st',
5921 @command('^status|st',
5922 [('A', 'all', None, _('show status of all files')),
5922 [('A', 'all', None, _('show status of all files')),
5923 ('m', 'modified', None, _('show only modified files')),
5923 ('m', 'modified', None, _('show only modified files')),
5924 ('a', 'added', None, _('show only added files')),
5924 ('a', 'added', None, _('show only added files')),
5925 ('r', 'removed', None, _('show only removed files')),
5925 ('r', 'removed', None, _('show only removed files')),
5926 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5926 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5927 ('c', 'clean', None, _('show only files without changes')),
5927 ('c', 'clean', None, _('show only files without changes')),
5928 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5928 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5929 ('i', 'ignored', None, _('show only ignored files')),
5929 ('i', 'ignored', None, _('show only ignored files')),
5930 ('n', 'no-status', None, _('hide status prefix')),
5930 ('n', 'no-status', None, _('hide status prefix')),
5931 ('C', 'copies', None, _('show source of copied files')),
5931 ('C', 'copies', None, _('show source of copied files')),
5932 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5932 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5933 ('', 'rev', [], _('show difference from revision'), _('REV')),
5933 ('', 'rev', [], _('show difference from revision'), _('REV')),
5934 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5934 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5935 ] + walkopts + subrepoopts + formatteropts,
5935 ] + walkopts + subrepoopts + formatteropts,
5936 _('[OPTION]... [FILE]...'),
5936 _('[OPTION]... [FILE]...'),
5937 inferrepo=True)
5937 inferrepo=True)
5938 def status(ui, repo, *pats, **opts):
5938 def status(ui, repo, *pats, **opts):
5939 """show changed files in the working directory
5939 """show changed files in the working directory
5940
5940
5941 Show status of files in the repository. If names are given, only
5941 Show status of files in the repository. If names are given, only
5942 files that match are shown. Files that are clean or ignored or
5942 files that match are shown. Files that are clean or ignored or
5943 the source of a copy/move operation, are not listed unless
5943 the source of a copy/move operation, are not listed unless
5944 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5944 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5945 Unless options described with "show only ..." are given, the
5945 Unless options described with "show only ..." are given, the
5946 options -mardu are used.
5946 options -mardu are used.
5947
5947
5948 Option -q/--quiet hides untracked (unknown and ignored) files
5948 Option -q/--quiet hides untracked (unknown and ignored) files
5949 unless explicitly requested with -u/--unknown or -i/--ignored.
5949 unless explicitly requested with -u/--unknown or -i/--ignored.
5950
5950
5951 .. note::
5951 .. note::
5952
5952
5953 status may appear to disagree with diff if permissions have
5953 status may appear to disagree with diff if permissions have
5954 changed or a merge has occurred. The standard diff format does
5954 changed or a merge has occurred. The standard diff format does
5955 not report permission changes and diff only reports changes
5955 not report permission changes and diff only reports changes
5956 relative to one merge parent.
5956 relative to one merge parent.
5957
5957
5958 If one revision is given, it is used as the base revision.
5958 If one revision is given, it is used as the base revision.
5959 If two revisions are given, the differences between them are
5959 If two revisions are given, the differences between them are
5960 shown. The --change option can also be used as a shortcut to list
5960 shown. The --change option can also be used as a shortcut to list
5961 the changed files of a revision from its first parent.
5961 the changed files of a revision from its first parent.
5962
5962
5963 The codes used to show the status of files are::
5963 The codes used to show the status of files are::
5964
5964
5965 M = modified
5965 M = modified
5966 A = added
5966 A = added
5967 R = removed
5967 R = removed
5968 C = clean
5968 C = clean
5969 ! = missing (deleted by non-hg command, but still tracked)
5969 ! = missing (deleted by non-hg command, but still tracked)
5970 ? = not tracked
5970 ? = not tracked
5971 I = ignored
5971 I = ignored
5972 = origin of the previous file (with --copies)
5972 = origin of the previous file (with --copies)
5973
5973
5974 .. container:: verbose
5974 .. container:: verbose
5975
5975
5976 Examples:
5976 Examples:
5977
5977
5978 - show changes in the working directory relative to a
5978 - show changes in the working directory relative to a
5979 changeset::
5979 changeset::
5980
5980
5981 hg status --rev 9353
5981 hg status --rev 9353
5982
5982
5983 - show changes in the working directory relative to the
5983 - show changes in the working directory relative to the
5984 current directory (see :hg:`help patterns` for more information)::
5984 current directory (see :hg:`help patterns` for more information)::
5985
5985
5986 hg status re:
5986 hg status re:
5987
5987
5988 - show all changes including copies in an existing changeset::
5988 - show all changes including copies in an existing changeset::
5989
5989
5990 hg status --copies --change 9353
5990 hg status --copies --change 9353
5991
5991
5992 - get a NUL separated list of added files, suitable for xargs::
5992 - get a NUL separated list of added files, suitable for xargs::
5993
5993
5994 hg status -an0
5994 hg status -an0
5995
5995
5996 Returns 0 on success.
5996 Returns 0 on success.
5997 """
5997 """
5998
5998
5999 revs = opts.get('rev')
5999 revs = opts.get('rev')
6000 change = opts.get('change')
6000 change = opts.get('change')
6001
6001
6002 if revs and change:
6002 if revs and change:
6003 msg = _('cannot specify --rev and --change at the same time')
6003 msg = _('cannot specify --rev and --change at the same time')
6004 raise error.Abort(msg)
6004 raise error.Abort(msg)
6005 elif change:
6005 elif change:
6006 node2 = scmutil.revsingle(repo, change, None).node()
6006 node2 = scmutil.revsingle(repo, change, None).node()
6007 node1 = repo[node2].p1().node()
6007 node1 = repo[node2].p1().node()
6008 else:
6008 else:
6009 node1, node2 = scmutil.revpair(repo, revs)
6009 node1, node2 = scmutil.revpair(repo, revs)
6010
6010
6011 if pats:
6011 if pats:
6012 cwd = repo.getcwd()
6012 cwd = repo.getcwd()
6013 else:
6013 else:
6014 cwd = ''
6014 cwd = ''
6015
6015
6016 if opts.get('print0'):
6016 if opts.get('print0'):
6017 end = '\0'
6017 end = '\0'
6018 else:
6018 else:
6019 end = '\n'
6019 end = '\n'
6020 copy = {}
6020 copy = {}
6021 states = 'modified added removed deleted unknown ignored clean'.split()
6021 states = 'modified added removed deleted unknown ignored clean'.split()
6022 show = [k for k in states if opts.get(k)]
6022 show = [k for k in states if opts.get(k)]
6023 if opts.get('all'):
6023 if opts.get('all'):
6024 show += ui.quiet and (states[:4] + ['clean']) or states
6024 show += ui.quiet and (states[:4] + ['clean']) or states
6025 if not show:
6025 if not show:
6026 if ui.quiet:
6026 if ui.quiet:
6027 show = states[:4]
6027 show = states[:4]
6028 else:
6028 else:
6029 show = states[:5]
6029 show = states[:5]
6030
6030
6031 m = scmutil.match(repo[node2], pats, opts)
6031 m = scmutil.match(repo[node2], pats, opts)
6032 stat = repo.status(node1, node2, m,
6032 stat = repo.status(node1, node2, m,
6033 'ignored' in show, 'clean' in show, 'unknown' in show,
6033 'ignored' in show, 'clean' in show, 'unknown' in show,
6034 opts.get('subrepos'))
6034 opts.get('subrepos'))
6035 changestates = zip(states, 'MAR!?IC', stat)
6035 changestates = zip(states, 'MAR!?IC', stat)
6036
6036
6037 if (opts.get('all') or opts.get('copies')
6037 if (opts.get('all') or opts.get('copies')
6038 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6038 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6039 copy = copies.pathcopies(repo[node1], repo[node2], m)
6039 copy = copies.pathcopies(repo[node1], repo[node2], m)
6040
6040
6041 fm = ui.formatter('status', opts)
6041 fm = ui.formatter('status', opts)
6042 fmt = '%s' + end
6042 fmt = '%s' + end
6043 showchar = not opts.get('no_status')
6043 showchar = not opts.get('no_status')
6044
6044
6045 for state, char, files in changestates:
6045 for state, char, files in changestates:
6046 if state in show:
6046 if state in show:
6047 label = 'status.' + state
6047 label = 'status.' + state
6048 for f in files:
6048 for f in files:
6049 fm.startitem()
6049 fm.startitem()
6050 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6050 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6051 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6051 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6052 if f in copy:
6052 if f in copy:
6053 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6053 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6054 label='status.copied')
6054 label='status.copied')
6055 fm.end()
6055 fm.end()
6056
6056
6057 @command('^summary|sum',
6057 @command('^summary|sum',
6058 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6058 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6059 def summary(ui, repo, **opts):
6059 def summary(ui, repo, **opts):
6060 """summarize working directory state
6060 """summarize working directory state
6061
6061
6062 This generates a brief summary of the working directory state,
6062 This generates a brief summary of the working directory state,
6063 including parents, branch, commit status, phase and available updates.
6063 including parents, branch, commit status, phase and available updates.
6064
6064
6065 With the --remote option, this will check the default paths for
6065 With the --remote option, this will check the default paths for
6066 incoming and outgoing changes. This can be time-consuming.
6066 incoming and outgoing changes. This can be time-consuming.
6067
6067
6068 Returns 0 on success.
6068 Returns 0 on success.
6069 """
6069 """
6070
6070
6071 ctx = repo[None]
6071 ctx = repo[None]
6072 parents = ctx.parents()
6072 parents = ctx.parents()
6073 pnode = parents[0].node()
6073 pnode = parents[0].node()
6074 marks = []
6074 marks = []
6075
6075
6076 for p in parents:
6076 for p in parents:
6077 # label with log.changeset (instead of log.parent) since this
6077 # label with log.changeset (instead of log.parent) since this
6078 # shows a working directory parent *changeset*:
6078 # shows a working directory parent *changeset*:
6079 # i18n: column positioning for "hg summary"
6079 # i18n: column positioning for "hg summary"
6080 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6080 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6081 label='log.changeset changeset.%s' % p.phasestr())
6081 label='log.changeset changeset.%s' % p.phasestr())
6082 ui.write(' '.join(p.tags()), label='log.tag')
6082 ui.write(' '.join(p.tags()), label='log.tag')
6083 if p.bookmarks():
6083 if p.bookmarks():
6084 marks.extend(p.bookmarks())
6084 marks.extend(p.bookmarks())
6085 if p.rev() == -1:
6085 if p.rev() == -1:
6086 if not len(repo):
6086 if not len(repo):
6087 ui.write(_(' (empty repository)'))
6087 ui.write(_(' (empty repository)'))
6088 else:
6088 else:
6089 ui.write(_(' (no revision checked out)'))
6089 ui.write(_(' (no revision checked out)'))
6090 ui.write('\n')
6090 ui.write('\n')
6091 if p.description():
6091 if p.description():
6092 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6092 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6093 label='log.summary')
6093 label='log.summary')
6094
6094
6095 branch = ctx.branch()
6095 branch = ctx.branch()
6096 bheads = repo.branchheads(branch)
6096 bheads = repo.branchheads(branch)
6097 # i18n: column positioning for "hg summary"
6097 # i18n: column positioning for "hg summary"
6098 m = _('branch: %s\n') % branch
6098 m = _('branch: %s\n') % branch
6099 if branch != 'default':
6099 if branch != 'default':
6100 ui.write(m, label='log.branch')
6100 ui.write(m, label='log.branch')
6101 else:
6101 else:
6102 ui.status(m, label='log.branch')
6102 ui.status(m, label='log.branch')
6103
6103
6104 if marks:
6104 if marks:
6105 active = repo._activebookmark
6105 active = repo._activebookmark
6106 # i18n: column positioning for "hg summary"
6106 # i18n: column positioning for "hg summary"
6107 ui.write(_('bookmarks:'), label='log.bookmark')
6107 ui.write(_('bookmarks:'), label='log.bookmark')
6108 if active is not None:
6108 if active is not None:
6109 if active in marks:
6109 if active in marks:
6110 ui.write(' *' + active, label=activebookmarklabel)
6110 ui.write(' *' + active, label=activebookmarklabel)
6111 marks.remove(active)
6111 marks.remove(active)
6112 else:
6112 else:
6113 ui.write(' [%s]' % active, label=activebookmarklabel)
6113 ui.write(' [%s]' % active, label=activebookmarklabel)
6114 for m in marks:
6114 for m in marks:
6115 ui.write(' ' + m, label='log.bookmark')
6115 ui.write(' ' + m, label='log.bookmark')
6116 ui.write('\n', label='log.bookmark')
6116 ui.write('\n', label='log.bookmark')
6117
6117
6118 status = repo.status(unknown=True)
6118 status = repo.status(unknown=True)
6119
6119
6120 c = repo.dirstate.copies()
6120 c = repo.dirstate.copies()
6121 copied, renamed = [], []
6121 copied, renamed = [], []
6122 for d, s in c.iteritems():
6122 for d, s in c.iteritems():
6123 if s in status.removed:
6123 if s in status.removed:
6124 status.removed.remove(s)
6124 status.removed.remove(s)
6125 renamed.append(d)
6125 renamed.append(d)
6126 else:
6126 else:
6127 copied.append(d)
6127 copied.append(d)
6128 if d in status.added:
6128 if d in status.added:
6129 status.added.remove(d)
6129 status.added.remove(d)
6130
6130
6131 ms = mergemod.mergestate(repo)
6131 ms = mergemod.mergestate(repo)
6132 unresolved = [f for f in ms if ms[f] == 'u']
6132 unresolved = [f for f in ms if ms[f] == 'u']
6133
6133
6134 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6134 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6135
6135
6136 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6136 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6137 (ui.label(_('%d added'), 'status.added'), status.added),
6137 (ui.label(_('%d added'), 'status.added'), status.added),
6138 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6138 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6139 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6139 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6140 (ui.label(_('%d copied'), 'status.copied'), copied),
6140 (ui.label(_('%d copied'), 'status.copied'), copied),
6141 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6141 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6142 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6142 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6143 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6143 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6144 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6144 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6145 t = []
6145 t = []
6146 for l, s in labels:
6146 for l, s in labels:
6147 if s:
6147 if s:
6148 t.append(l % len(s))
6148 t.append(l % len(s))
6149
6149
6150 t = ', '.join(t)
6150 t = ', '.join(t)
6151 cleanworkdir = False
6151 cleanworkdir = False
6152
6152
6153 if repo.vfs.exists('updatestate'):
6153 if repo.vfs.exists('updatestate'):
6154 t += _(' (interrupted update)')
6154 t += _(' (interrupted update)')
6155 elif len(parents) > 1:
6155 elif len(parents) > 1:
6156 t += _(' (merge)')
6156 t += _(' (merge)')
6157 elif branch != parents[0].branch():
6157 elif branch != parents[0].branch():
6158 t += _(' (new branch)')
6158 t += _(' (new branch)')
6159 elif (parents[0].closesbranch() and
6159 elif (parents[0].closesbranch() and
6160 pnode in repo.branchheads(branch, closed=True)):
6160 pnode in repo.branchheads(branch, closed=True)):
6161 t += _(' (head closed)')
6161 t += _(' (head closed)')
6162 elif not (status.modified or status.added or status.removed or renamed or
6162 elif not (status.modified or status.added or status.removed or renamed or
6163 copied or subs):
6163 copied or subs):
6164 t += _(' (clean)')
6164 t += _(' (clean)')
6165 cleanworkdir = True
6165 cleanworkdir = True
6166 elif pnode not in bheads:
6166 elif pnode not in bheads:
6167 t += _(' (new branch head)')
6167 t += _(' (new branch head)')
6168
6168
6169 if parents:
6169 if parents:
6170 pendingphase = max(p.phase() for p in parents)
6170 pendingphase = max(p.phase() for p in parents)
6171 else:
6171 else:
6172 pendingphase = phases.public
6172 pendingphase = phases.public
6173
6173
6174 if pendingphase > phases.newcommitphase(ui):
6174 if pendingphase > phases.newcommitphase(ui):
6175 t += ' (%s)' % phases.phasenames[pendingphase]
6175 t += ' (%s)' % phases.phasenames[pendingphase]
6176
6176
6177 if cleanworkdir:
6177 if cleanworkdir:
6178 # i18n: column positioning for "hg summary"
6178 # i18n: column positioning for "hg summary"
6179 ui.status(_('commit: %s\n') % t.strip())
6179 ui.status(_('commit: %s\n') % t.strip())
6180 else:
6180 else:
6181 # i18n: column positioning for "hg summary"
6181 # i18n: column positioning for "hg summary"
6182 ui.write(_('commit: %s\n') % t.strip())
6182 ui.write(_('commit: %s\n') % t.strip())
6183
6183
6184 # all ancestors of branch heads - all ancestors of parent = new csets
6184 # all ancestors of branch heads - all ancestors of parent = new csets
6185 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6185 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6186 bheads))
6186 bheads))
6187
6187
6188 if new == 0:
6188 if new == 0:
6189 # i18n: column positioning for "hg summary"
6189 # i18n: column positioning for "hg summary"
6190 ui.status(_('update: (current)\n'))
6190 ui.status(_('update: (current)\n'))
6191 elif pnode not in bheads:
6191 elif pnode not in bheads:
6192 # i18n: column positioning for "hg summary"
6192 # i18n: column positioning for "hg summary"
6193 ui.write(_('update: %d new changesets (update)\n') % new)
6193 ui.write(_('update: %d new changesets (update)\n') % new)
6194 else:
6194 else:
6195 # i18n: column positioning for "hg summary"
6195 # i18n: column positioning for "hg summary"
6196 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6196 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6197 (new, len(bheads)))
6197 (new, len(bheads)))
6198
6198
6199 t = []
6199 t = []
6200 draft = len(repo.revs('draft()'))
6200 draft = len(repo.revs('draft()'))
6201 if draft:
6201 if draft:
6202 t.append(_('%d draft') % draft)
6202 t.append(_('%d draft') % draft)
6203 secret = len(repo.revs('secret()'))
6203 secret = len(repo.revs('secret()'))
6204 if secret:
6204 if secret:
6205 t.append(_('%d secret') % secret)
6205 t.append(_('%d secret') % secret)
6206
6206
6207 if draft or secret:
6207 if draft or secret:
6208 ui.status(_('phases: %s\n') % ', '.join(t))
6208 ui.status(_('phases: %s\n') % ', '.join(t))
6209
6209
6210 cmdutil.summaryhooks(ui, repo)
6210 cmdutil.summaryhooks(ui, repo)
6211
6211
6212 if opts.get('remote'):
6212 if opts.get('remote'):
6213 needsincoming, needsoutgoing = True, True
6213 needsincoming, needsoutgoing = True, True
6214 else:
6214 else:
6215 needsincoming, needsoutgoing = False, False
6215 needsincoming, needsoutgoing = False, False
6216 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6216 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6217 if i:
6217 if i:
6218 needsincoming = True
6218 needsincoming = True
6219 if o:
6219 if o:
6220 needsoutgoing = True
6220 needsoutgoing = True
6221 if not needsincoming and not needsoutgoing:
6221 if not needsincoming and not needsoutgoing:
6222 return
6222 return
6223
6223
6224 def getincoming():
6224 def getincoming():
6225 source, branches = hg.parseurl(ui.expandpath('default'))
6225 source, branches = hg.parseurl(ui.expandpath('default'))
6226 sbranch = branches[0]
6226 sbranch = branches[0]
6227 try:
6227 try:
6228 other = hg.peer(repo, {}, source)
6228 other = hg.peer(repo, {}, source)
6229 except error.RepoError:
6229 except error.RepoError:
6230 if opts.get('remote'):
6230 if opts.get('remote'):
6231 raise
6231 raise
6232 return source, sbranch, None, None, None
6232 return source, sbranch, None, None, None
6233 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6233 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6234 if revs:
6234 if revs:
6235 revs = [other.lookup(rev) for rev in revs]
6235 revs = [other.lookup(rev) for rev in revs]
6236 ui.debug('comparing with %s\n' % util.hidepassword(source))
6236 ui.debug('comparing with %s\n' % util.hidepassword(source))
6237 repo.ui.pushbuffer()
6237 repo.ui.pushbuffer()
6238 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6238 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6239 repo.ui.popbuffer()
6239 repo.ui.popbuffer()
6240 return source, sbranch, other, commoninc, commoninc[1]
6240 return source, sbranch, other, commoninc, commoninc[1]
6241
6241
6242 if needsincoming:
6242 if needsincoming:
6243 source, sbranch, sother, commoninc, incoming = getincoming()
6243 source, sbranch, sother, commoninc, incoming = getincoming()
6244 else:
6244 else:
6245 source = sbranch = sother = commoninc = incoming = None
6245 source = sbranch = sother = commoninc = incoming = None
6246
6246
6247 def getoutgoing():
6247 def getoutgoing():
6248 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6248 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6249 dbranch = branches[0]
6249 dbranch = branches[0]
6250 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6250 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6251 if source != dest:
6251 if source != dest:
6252 try:
6252 try:
6253 dother = hg.peer(repo, {}, dest)
6253 dother = hg.peer(repo, {}, dest)
6254 except error.RepoError:
6254 except error.RepoError:
6255 if opts.get('remote'):
6255 if opts.get('remote'):
6256 raise
6256 raise
6257 return dest, dbranch, None, None
6257 return dest, dbranch, None, None
6258 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6258 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6259 elif sother is None:
6259 elif sother is None:
6260 # there is no explicit destination peer, but source one is invalid
6260 # there is no explicit destination peer, but source one is invalid
6261 return dest, dbranch, None, None
6261 return dest, dbranch, None, None
6262 else:
6262 else:
6263 dother = sother
6263 dother = sother
6264 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6264 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6265 common = None
6265 common = None
6266 else:
6266 else:
6267 common = commoninc
6267 common = commoninc
6268 if revs:
6268 if revs:
6269 revs = [repo.lookup(rev) for rev in revs]
6269 revs = [repo.lookup(rev) for rev in revs]
6270 repo.ui.pushbuffer()
6270 repo.ui.pushbuffer()
6271 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6271 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6272 commoninc=common)
6272 commoninc=common)
6273 repo.ui.popbuffer()
6273 repo.ui.popbuffer()
6274 return dest, dbranch, dother, outgoing
6274 return dest, dbranch, dother, outgoing
6275
6275
6276 if needsoutgoing:
6276 if needsoutgoing:
6277 dest, dbranch, dother, outgoing = getoutgoing()
6277 dest, dbranch, dother, outgoing = getoutgoing()
6278 else:
6278 else:
6279 dest = dbranch = dother = outgoing = None
6279 dest = dbranch = dother = outgoing = None
6280
6280
6281 if opts.get('remote'):
6281 if opts.get('remote'):
6282 t = []
6282 t = []
6283 if incoming:
6283 if incoming:
6284 t.append(_('1 or more incoming'))
6284 t.append(_('1 or more incoming'))
6285 o = outgoing.missing
6285 o = outgoing.missing
6286 if o:
6286 if o:
6287 t.append(_('%d outgoing') % len(o))
6287 t.append(_('%d outgoing') % len(o))
6288 other = dother or sother
6288 other = dother or sother
6289 if 'bookmarks' in other.listkeys('namespaces'):
6289 if 'bookmarks' in other.listkeys('namespaces'):
6290 counts = bookmarks.summary(repo, other)
6290 counts = bookmarks.summary(repo, other)
6291 if counts[0] > 0:
6291 if counts[0] > 0:
6292 t.append(_('%d incoming bookmarks') % counts[0])
6292 t.append(_('%d incoming bookmarks') % counts[0])
6293 if counts[1] > 0:
6293 if counts[1] > 0:
6294 t.append(_('%d outgoing bookmarks') % counts[1])
6294 t.append(_('%d outgoing bookmarks') % counts[1])
6295
6295
6296 if t:
6296 if t:
6297 # i18n: column positioning for "hg summary"
6297 # i18n: column positioning for "hg summary"
6298 ui.write(_('remote: %s\n') % (', '.join(t)))
6298 ui.write(_('remote: %s\n') % (', '.join(t)))
6299 else:
6299 else:
6300 # i18n: column positioning for "hg summary"
6300 # i18n: column positioning for "hg summary"
6301 ui.status(_('remote: (synced)\n'))
6301 ui.status(_('remote: (synced)\n'))
6302
6302
6303 cmdutil.summaryremotehooks(ui, repo, opts,
6303 cmdutil.summaryremotehooks(ui, repo, opts,
6304 ((source, sbranch, sother, commoninc),
6304 ((source, sbranch, sother, commoninc),
6305 (dest, dbranch, dother, outgoing)))
6305 (dest, dbranch, dother, outgoing)))
6306
6306
6307 @command('tag',
6307 @command('tag',
6308 [('f', 'force', None, _('force tag')),
6308 [('f', 'force', None, _('force tag')),
6309 ('l', 'local', None, _('make the tag local')),
6309 ('l', 'local', None, _('make the tag local')),
6310 ('r', 'rev', '', _('revision to tag'), _('REV')),
6310 ('r', 'rev', '', _('revision to tag'), _('REV')),
6311 ('', 'remove', None, _('remove a tag')),
6311 ('', 'remove', None, _('remove a tag')),
6312 # -l/--local is already there, commitopts cannot be used
6312 # -l/--local is already there, commitopts cannot be used
6313 ('e', 'edit', None, _('invoke editor on commit messages')),
6313 ('e', 'edit', None, _('invoke editor on commit messages')),
6314 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6314 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6315 ] + commitopts2,
6315 ] + commitopts2,
6316 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6316 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6317 def tag(ui, repo, name1, *names, **opts):
6317 def tag(ui, repo, name1, *names, **opts):
6318 """add one or more tags for the current or given revision
6318 """add one or more tags for the current or given revision
6319
6319
6320 Name a particular revision using <name>.
6320 Name a particular revision using <name>.
6321
6321
6322 Tags are used to name particular revisions of the repository and are
6322 Tags are used to name particular revisions of the repository and are
6323 very useful to compare different revisions, to go back to significant
6323 very useful to compare different revisions, to go back to significant
6324 earlier versions or to mark branch points as releases, etc. Changing
6324 earlier versions or to mark branch points as releases, etc. Changing
6325 an existing tag is normally disallowed; use -f/--force to override.
6325 an existing tag is normally disallowed; use -f/--force to override.
6326
6326
6327 If no revision is given, the parent of the working directory is
6327 If no revision is given, the parent of the working directory is
6328 used.
6328 used.
6329
6329
6330 To facilitate version control, distribution, and merging of tags,
6330 To facilitate version control, distribution, and merging of tags,
6331 they are stored as a file named ".hgtags" which is managed similarly
6331 they are stored as a file named ".hgtags" which is managed similarly
6332 to other project files and can be hand-edited if necessary. This
6332 to other project files and can be hand-edited if necessary. This
6333 also means that tagging creates a new commit. The file
6333 also means that tagging creates a new commit. The file
6334 ".hg/localtags" is used for local tags (not shared among
6334 ".hg/localtags" is used for local tags (not shared among
6335 repositories).
6335 repositories).
6336
6336
6337 Tag commits are usually made at the head of a branch. If the parent
6337 Tag commits are usually made at the head of a branch. If the parent
6338 of the working directory is not a branch head, :hg:`tag` aborts; use
6338 of the working directory is not a branch head, :hg:`tag` aborts; use
6339 -f/--force to force the tag commit to be based on a non-head
6339 -f/--force to force the tag commit to be based on a non-head
6340 changeset.
6340 changeset.
6341
6341
6342 See :hg:`help dates` for a list of formats valid for -d/--date.
6342 See :hg:`help dates` for a list of formats valid for -d/--date.
6343
6343
6344 Since tag names have priority over branch names during revision
6344 Since tag names have priority over branch names during revision
6345 lookup, using an existing branch name as a tag name is discouraged.
6345 lookup, using an existing branch name as a tag name is discouraged.
6346
6346
6347 Returns 0 on success.
6347 Returns 0 on success.
6348 """
6348 """
6349 wlock = lock = None
6349 wlock = lock = None
6350 try:
6350 try:
6351 wlock = repo.wlock()
6351 wlock = repo.wlock()
6352 lock = repo.lock()
6352 lock = repo.lock()
6353 rev_ = "."
6353 rev_ = "."
6354 names = [t.strip() for t in (name1,) + names]
6354 names = [t.strip() for t in (name1,) + names]
6355 if len(names) != len(set(names)):
6355 if len(names) != len(set(names)):
6356 raise error.Abort(_('tag names must be unique'))
6356 raise error.Abort(_('tag names must be unique'))
6357 for n in names:
6357 for n in names:
6358 scmutil.checknewlabel(repo, n, 'tag')
6358 scmutil.checknewlabel(repo, n, 'tag')
6359 if not n:
6359 if not n:
6360 raise error.Abort(_('tag names cannot consist entirely of '
6360 raise error.Abort(_('tag names cannot consist entirely of '
6361 'whitespace'))
6361 'whitespace'))
6362 if opts.get('rev') and opts.get('remove'):
6362 if opts.get('rev') and opts.get('remove'):
6363 raise error.Abort(_("--rev and --remove are incompatible"))
6363 raise error.Abort(_("--rev and --remove are incompatible"))
6364 if opts.get('rev'):
6364 if opts.get('rev'):
6365 rev_ = opts['rev']
6365 rev_ = opts['rev']
6366 message = opts.get('message')
6366 message = opts.get('message')
6367 if opts.get('remove'):
6367 if opts.get('remove'):
6368 if opts.get('local'):
6368 if opts.get('local'):
6369 expectedtype = 'local'
6369 expectedtype = 'local'
6370 else:
6370 else:
6371 expectedtype = 'global'
6371 expectedtype = 'global'
6372
6372
6373 for n in names:
6373 for n in names:
6374 if not repo.tagtype(n):
6374 if not repo.tagtype(n):
6375 raise error.Abort(_("tag '%s' does not exist") % n)
6375 raise error.Abort(_("tag '%s' does not exist") % n)
6376 if repo.tagtype(n) != expectedtype:
6376 if repo.tagtype(n) != expectedtype:
6377 if expectedtype == 'global':
6377 if expectedtype == 'global':
6378 raise error.Abort(_("tag '%s' is not a global tag") % n)
6378 raise error.Abort(_("tag '%s' is not a global tag") % n)
6379 else:
6379 else:
6380 raise error.Abort(_("tag '%s' is not a local tag") % n)
6380 raise error.Abort(_("tag '%s' is not a local tag") % n)
6381 rev_ = 'null'
6381 rev_ = 'null'
6382 if not message:
6382 if not message:
6383 # we don't translate commit messages
6383 # we don't translate commit messages
6384 message = 'Removed tag %s' % ', '.join(names)
6384 message = 'Removed tag %s' % ', '.join(names)
6385 elif not opts.get('force'):
6385 elif not opts.get('force'):
6386 for n in names:
6386 for n in names:
6387 if n in repo.tags():
6387 if n in repo.tags():
6388 raise error.Abort(_("tag '%s' already exists "
6388 raise error.Abort(_("tag '%s' already exists "
6389 "(use -f to force)") % n)
6389 "(use -f to force)") % n)
6390 if not opts.get('local'):
6390 if not opts.get('local'):
6391 p1, p2 = repo.dirstate.parents()
6391 p1, p2 = repo.dirstate.parents()
6392 if p2 != nullid:
6392 if p2 != nullid:
6393 raise error.Abort(_('uncommitted merge'))
6393 raise error.Abort(_('uncommitted merge'))
6394 bheads = repo.branchheads()
6394 bheads = repo.branchheads()
6395 if not opts.get('force') and bheads and p1 not in bheads:
6395 if not opts.get('force') and bheads and p1 not in bheads:
6396 raise error.Abort(_('not at a branch head (use -f to force)'))
6396 raise error.Abort(_('not at a branch head (use -f to force)'))
6397 r = scmutil.revsingle(repo, rev_).node()
6397 r = scmutil.revsingle(repo, rev_).node()
6398
6398
6399 if not message:
6399 if not message:
6400 # we don't translate commit messages
6400 # we don't translate commit messages
6401 message = ('Added tag %s for changeset %s' %
6401 message = ('Added tag %s for changeset %s' %
6402 (', '.join(names), short(r)))
6402 (', '.join(names), short(r)))
6403
6403
6404 date = opts.get('date')
6404 date = opts.get('date')
6405 if date:
6405 if date:
6406 date = util.parsedate(date)
6406 date = util.parsedate(date)
6407
6407
6408 if opts.get('remove'):
6408 if opts.get('remove'):
6409 editform = 'tag.remove'
6409 editform = 'tag.remove'
6410 else:
6410 else:
6411 editform = 'tag.add'
6411 editform = 'tag.add'
6412 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6412 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6413
6413
6414 # don't allow tagging the null rev
6414 # don't allow tagging the null rev
6415 if (not opts.get('remove') and
6415 if (not opts.get('remove') and
6416 scmutil.revsingle(repo, rev_).rev() == nullrev):
6416 scmutil.revsingle(repo, rev_).rev() == nullrev):
6417 raise error.Abort(_("cannot tag null revision"))
6417 raise error.Abort(_("cannot tag null revision"))
6418
6418
6419 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6419 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6420 editor=editor)
6420 editor=editor)
6421 finally:
6421 finally:
6422 release(lock, wlock)
6422 release(lock, wlock)
6423
6423
6424 @command('tags', formatteropts, '')
6424 @command('tags', formatteropts, '')
6425 def tags(ui, repo, **opts):
6425 def tags(ui, repo, **opts):
6426 """list repository tags
6426 """list repository tags
6427
6427
6428 This lists both regular and local tags. When the -v/--verbose
6428 This lists both regular and local tags. When the -v/--verbose
6429 switch is used, a third column "local" is printed for local tags.
6429 switch is used, a third column "local" is printed for local tags.
6430
6430
6431 Returns 0 on success.
6431 Returns 0 on success.
6432 """
6432 """
6433
6433
6434 fm = ui.formatter('tags', opts)
6434 fm = ui.formatter('tags', opts)
6435 hexfunc = fm.hexfunc
6435 hexfunc = fm.hexfunc
6436 tagtype = ""
6436 tagtype = ""
6437
6437
6438 for t, n in reversed(repo.tagslist()):
6438 for t, n in reversed(repo.tagslist()):
6439 hn = hexfunc(n)
6439 hn = hexfunc(n)
6440 label = 'tags.normal'
6440 label = 'tags.normal'
6441 tagtype = ''
6441 tagtype = ''
6442 if repo.tagtype(t) == 'local':
6442 if repo.tagtype(t) == 'local':
6443 label = 'tags.local'
6443 label = 'tags.local'
6444 tagtype = 'local'
6444 tagtype = 'local'
6445
6445
6446 fm.startitem()
6446 fm.startitem()
6447 fm.write('tag', '%s', t, label=label)
6447 fm.write('tag', '%s', t, label=label)
6448 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6448 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6449 fm.condwrite(not ui.quiet, 'rev node', fmt,
6449 fm.condwrite(not ui.quiet, 'rev node', fmt,
6450 repo.changelog.rev(n), hn, label=label)
6450 repo.changelog.rev(n), hn, label=label)
6451 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6451 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6452 tagtype, label=label)
6452 tagtype, label=label)
6453 fm.plain('\n')
6453 fm.plain('\n')
6454 fm.end()
6454 fm.end()
6455
6455
6456 @command('tip',
6456 @command('tip',
6457 [('p', 'patch', None, _('show patch')),
6457 [('p', 'patch', None, _('show patch')),
6458 ('g', 'git', None, _('use git extended diff format')),
6458 ('g', 'git', None, _('use git extended diff format')),
6459 ] + templateopts,
6459 ] + templateopts,
6460 _('[-p] [-g]'))
6460 _('[-p] [-g]'))
6461 def tip(ui, repo, **opts):
6461 def tip(ui, repo, **opts):
6462 """show the tip revision (DEPRECATED)
6462 """show the tip revision (DEPRECATED)
6463
6463
6464 The tip revision (usually just called the tip) is the changeset
6464 The tip revision (usually just called the tip) is the changeset
6465 most recently added to the repository (and therefore the most
6465 most recently added to the repository (and therefore the most
6466 recently changed head).
6466 recently changed head).
6467
6467
6468 If you have just made a commit, that commit will be the tip. If
6468 If you have just made a commit, that commit will be the tip. If
6469 you have just pulled changes from another repository, the tip of
6469 you have just pulled changes from another repository, the tip of
6470 that repository becomes the current tip. The "tip" tag is special
6470 that repository becomes the current tip. The "tip" tag is special
6471 and cannot be renamed or assigned to a different changeset.
6471 and cannot be renamed or assigned to a different changeset.
6472
6472
6473 This command is deprecated, please use :hg:`heads` instead.
6473 This command is deprecated, please use :hg:`heads` instead.
6474
6474
6475 Returns 0 on success.
6475 Returns 0 on success.
6476 """
6476 """
6477 displayer = cmdutil.show_changeset(ui, repo, opts)
6477 displayer = cmdutil.show_changeset(ui, repo, opts)
6478 displayer.show(repo['tip'])
6478 displayer.show(repo['tip'])
6479 displayer.close()
6479 displayer.close()
6480
6480
6481 @command('unbundle',
6481 @command('unbundle',
6482 [('u', 'update', None,
6482 [('u', 'update', None,
6483 _('update to new branch head if changesets were unbundled'))],
6483 _('update to new branch head if changesets were unbundled'))],
6484 _('[-u] FILE...'))
6484 _('[-u] FILE...'))
6485 def unbundle(ui, repo, fname1, *fnames, **opts):
6485 def unbundle(ui, repo, fname1, *fnames, **opts):
6486 """apply one or more changegroup files
6486 """apply one or more changegroup files
6487
6487
6488 Apply one or more compressed changegroup files generated by the
6488 Apply one or more compressed changegroup files generated by the
6489 bundle command.
6489 bundle command.
6490
6490
6491 Returns 0 on success, 1 if an update has unresolved files.
6491 Returns 0 on success, 1 if an update has unresolved files.
6492 """
6492 """
6493 fnames = (fname1,) + fnames
6493 fnames = (fname1,) + fnames
6494
6494
6495 lock = repo.lock()
6495 lock = repo.lock()
6496 try:
6496 try:
6497 for fname in fnames:
6497 for fname in fnames:
6498 f = hg.openpath(ui, fname)
6498 f = hg.openpath(ui, fname)
6499 gen = exchange.readbundle(ui, f, fname)
6499 gen = exchange.readbundle(ui, f, fname)
6500 if isinstance(gen, bundle2.unbundle20):
6500 if isinstance(gen, bundle2.unbundle20):
6501 tr = repo.transaction('unbundle')
6501 tr = repo.transaction('unbundle')
6502 try:
6502 try:
6503 op = bundle2.processbundle(repo, gen, lambda: tr)
6503 op = bundle2.processbundle(repo, gen, lambda: tr)
6504 tr.close()
6504 tr.close()
6505 except error.BundleUnknownFeatureError as exc:
6505 except error.BundleUnknownFeatureError as exc:
6506 raise error.Abort(_('%s: unknown bundle feature, %s')
6506 raise error.Abort(_('%s: unknown bundle feature, %s')
6507 % (fname, exc),
6507 % (fname, exc),
6508 hint=_("see https://mercurial-scm.org/"
6508 hint=_("see https://mercurial-scm.org/"
6509 "wiki/BundleFeature for more "
6509 "wiki/BundleFeature for more "
6510 "information"))
6510 "information"))
6511 finally:
6511 finally:
6512 if tr:
6512 if tr:
6513 tr.release()
6513 tr.release()
6514 changes = [r.get('return', 0)
6514 changes = [r.get('return', 0)
6515 for r in op.records['changegroup']]
6515 for r in op.records['changegroup']]
6516 modheads = changegroup.combineresults(changes)
6516 modheads = changegroup.combineresults(changes)
6517 else:
6517 else:
6518 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6518 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6519 'bundle:' + fname)
6519 'bundle:' + fname)
6520 finally:
6520 finally:
6521 lock.release()
6521 lock.release()
6522
6522
6523 return postincoming(ui, repo, modheads, opts.get('update'), None)
6523 return postincoming(ui, repo, modheads, opts.get('update'), None)
6524
6524
6525 @command('^update|up|checkout|co',
6525 @command('^update|up|checkout|co',
6526 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6526 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6527 ('c', 'check', None,
6527 ('c', 'check', None,
6528 _('update across branches if no uncommitted changes')),
6528 _('update across branches if no uncommitted changes')),
6529 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6529 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6530 ('r', 'rev', '', _('revision'), _('REV'))
6530 ('r', 'rev', '', _('revision'), _('REV'))
6531 ] + mergetoolopts,
6531 ] + mergetoolopts,
6532 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6532 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6533 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6533 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6534 tool=None):
6534 tool=None):
6535 """update working directory (or switch revisions)
6535 """update working directory (or switch revisions)
6536
6536
6537 Update the repository's working directory to the specified
6537 Update the repository's working directory to the specified
6538 changeset. If no changeset is specified, update to the tip of the
6538 changeset. If no changeset is specified, update to the tip of the
6539 current named branch and move the active bookmark (see :hg:`help
6539 current named branch and move the active bookmark (see :hg:`help
6540 bookmarks`).
6540 bookmarks`).
6541
6541
6542 Update sets the working directory's parent revision to the specified
6542 Update sets the working directory's parent revision to the specified
6543 changeset (see :hg:`help parents`).
6543 changeset (see :hg:`help parents`).
6544
6544
6545 If the changeset is not a descendant or ancestor of the working
6545 If the changeset is not a descendant or ancestor of the working
6546 directory's parent, the update is aborted. With the -c/--check
6546 directory's parent, the update is aborted. With the -c/--check
6547 option, the working directory is checked for uncommitted changes; if
6547 option, the working directory is checked for uncommitted changes; if
6548 none are found, the working directory is updated to the specified
6548 none are found, the working directory is updated to the specified
6549 changeset.
6549 changeset.
6550
6550
6551 .. container:: verbose
6551 .. container:: verbose
6552
6552
6553 The following rules apply when the working directory contains
6553 The following rules apply when the working directory contains
6554 uncommitted changes:
6554 uncommitted changes:
6555
6555
6556 1. If neither -c/--check nor -C/--clean is specified, and if
6556 1. If neither -c/--check nor -C/--clean is specified, and if
6557 the requested changeset is an ancestor or descendant of
6557 the requested changeset is an ancestor or descendant of
6558 the working directory's parent, the uncommitted changes
6558 the working directory's parent, the uncommitted changes
6559 are merged into the requested changeset and the merged
6559 are merged into the requested changeset and the merged
6560 result is left uncommitted. If the requested changeset is
6560 result is left uncommitted. If the requested changeset is
6561 not an ancestor or descendant (that is, it is on another
6561 not an ancestor or descendant (that is, it is on another
6562 branch), the update is aborted and the uncommitted changes
6562 branch), the update is aborted and the uncommitted changes
6563 are preserved.
6563 are preserved.
6564
6564
6565 2. With the -c/--check option, the update is aborted and the
6565 2. With the -c/--check option, the update is aborted and the
6566 uncommitted changes are preserved.
6566 uncommitted changes are preserved.
6567
6567
6568 3. With the -C/--clean option, uncommitted changes are discarded and
6568 3. With the -C/--clean option, uncommitted changes are discarded and
6569 the working directory is updated to the requested changeset.
6569 the working directory is updated to the requested changeset.
6570
6570
6571 To cancel an uncommitted merge (and lose your changes), use
6571 To cancel an uncommitted merge (and lose your changes), use
6572 :hg:`update --clean .`.
6572 :hg:`update --clean .`.
6573
6573
6574 Use null as the changeset to remove the working directory (like
6574 Use null as the changeset to remove the working directory (like
6575 :hg:`clone -U`).
6575 :hg:`clone -U`).
6576
6576
6577 If you want to revert just one file to an older revision, use
6577 If you want to revert just one file to an older revision, use
6578 :hg:`revert [-r REV] NAME`.
6578 :hg:`revert [-r REV] NAME`.
6579
6579
6580 See :hg:`help dates` for a list of formats valid for -d/--date.
6580 See :hg:`help dates` for a list of formats valid for -d/--date.
6581
6581
6582 Returns 0 on success, 1 if there are unresolved files.
6582 Returns 0 on success, 1 if there are unresolved files.
6583 """
6583 """
6584 movemarkfrom = None
6584 movemarkfrom = None
6585 if rev and node:
6585 if rev and node:
6586 raise error.Abort(_("please specify just one revision"))
6586 raise error.Abort(_("please specify just one revision"))
6587
6587
6588 if rev is None or rev == '':
6588 if rev is None or rev == '':
6589 rev = node
6589 rev = node
6590
6590
6591 wlock = repo.wlock()
6591 wlock = repo.wlock()
6592 try:
6592 try:
6593 cmdutil.clearunfinished(repo)
6593 cmdutil.clearunfinished(repo)
6594
6594
6595 if date:
6595 if date:
6596 if rev is not None:
6596 if rev is not None:
6597 raise error.Abort(_("you can't specify a revision and a date"))
6597 raise error.Abort(_("you can't specify a revision and a date"))
6598 rev = cmdutil.finddate(ui, repo, date)
6598 rev = cmdutil.finddate(ui, repo, date)
6599
6599
6600 # if we defined a bookmark, we have to remember the original name
6600 # if we defined a bookmark, we have to remember the original name
6601 brev = rev
6601 brev = rev
6602 rev = scmutil.revsingle(repo, rev, rev).rev()
6602 rev = scmutil.revsingle(repo, rev, rev).rev()
6603
6603
6604 if check and clean:
6604 if check and clean:
6605 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6605 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6606 )
6606 )
6607
6607
6608 if check:
6608 if check:
6609 cmdutil.bailifchanged(repo, merge=False)
6609 cmdutil.bailifchanged(repo, merge=False)
6610 if rev is None:
6610 if rev is None:
6611 updata = destutil.destupdate(repo, clean=clean, check=check)
6611 updata = destutil.destupdate(repo, clean=clean, check=check)
6612 rev, movemarkfrom, brev = updata
6612 rev, movemarkfrom, brev = updata
6613
6613
6614 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6614 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6615
6615
6616 if clean:
6616 if clean:
6617 ret = hg.clean(repo, rev)
6617 ret = hg.clean(repo, rev)
6618 else:
6618 else:
6619 ret = hg.update(repo, rev)
6619 ret = hg.update(repo, rev)
6620
6620
6621 if not ret and movemarkfrom:
6621 if not ret and movemarkfrom:
6622 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6622 if movemarkfrom == repo['.'].node():
6623 pass # no-op update
6624 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6623 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6625 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6624 else:
6626 else:
6625 # this can happen with a non-linear update
6627 # this can happen with a non-linear update
6626 ui.status(_("(leaving bookmark %s)\n") %
6628 ui.status(_("(leaving bookmark %s)\n") %
6627 repo._activebookmark)
6629 repo._activebookmark)
6628 bookmarks.deactivate(repo)
6630 bookmarks.deactivate(repo)
6629 elif brev in repo._bookmarks:
6631 elif brev in repo._bookmarks:
6630 bookmarks.activate(repo, brev)
6632 bookmarks.activate(repo, brev)
6631 ui.status(_("(activating bookmark %s)\n") % brev)
6633 ui.status(_("(activating bookmark %s)\n") % brev)
6632 elif brev:
6634 elif brev:
6633 if repo._activebookmark:
6635 if repo._activebookmark:
6634 ui.status(_("(leaving bookmark %s)\n") %
6636 ui.status(_("(leaving bookmark %s)\n") %
6635 repo._activebookmark)
6637 repo._activebookmark)
6636 bookmarks.deactivate(repo)
6638 bookmarks.deactivate(repo)
6637 finally:
6639 finally:
6638 wlock.release()
6640 wlock.release()
6639
6641
6640 return ret
6642 return ret
6641
6643
6642 @command('verify', [])
6644 @command('verify', [])
6643 def verify(ui, repo):
6645 def verify(ui, repo):
6644 """verify the integrity of the repository
6646 """verify the integrity of the repository
6645
6647
6646 Verify the integrity of the current repository.
6648 Verify the integrity of the current repository.
6647
6649
6648 This will perform an extensive check of the repository's
6650 This will perform an extensive check of the repository's
6649 integrity, validating the hashes and checksums of each entry in
6651 integrity, validating the hashes and checksums of each entry in
6650 the changelog, manifest, and tracked files, as well as the
6652 the changelog, manifest, and tracked files, as well as the
6651 integrity of their crosslinks and indices.
6653 integrity of their crosslinks and indices.
6652
6654
6653 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6655 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6654 for more information about recovery from corruption of the
6656 for more information about recovery from corruption of the
6655 repository.
6657 repository.
6656
6658
6657 Returns 0 on success, 1 if errors are encountered.
6659 Returns 0 on success, 1 if errors are encountered.
6658 """
6660 """
6659 return hg.verify(repo)
6661 return hg.verify(repo)
6660
6662
6661 @command('version', [], norepo=True)
6663 @command('version', [], norepo=True)
6662 def version_(ui):
6664 def version_(ui):
6663 """output version and copyright information"""
6665 """output version and copyright information"""
6664 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6666 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6665 % util.version())
6667 % util.version())
6666 ui.status(_(
6668 ui.status(_(
6667 "(see https://mercurial-scm.org for more information)\n"
6669 "(see https://mercurial-scm.org for more information)\n"
6668 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6670 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6669 "This is free software; see the source for copying conditions. "
6671 "This is free software; see the source for copying conditions. "
6670 "There is NO\nwarranty; "
6672 "There is NO\nwarranty; "
6671 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6673 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6672 ))
6674 ))
6673
6675
6674 ui.note(_("\nEnabled extensions:\n\n"))
6676 ui.note(_("\nEnabled extensions:\n\n"))
6675 if ui.verbose:
6677 if ui.verbose:
6676 # format names and versions into columns
6678 # format names and versions into columns
6677 names = []
6679 names = []
6678 vers = []
6680 vers = []
6679 for name, module in extensions.extensions():
6681 for name, module in extensions.extensions():
6680 names.append(name)
6682 names.append(name)
6681 vers.append(extensions.moduleversion(module))
6683 vers.append(extensions.moduleversion(module))
6682 if names:
6684 if names:
6683 maxnamelen = max(len(n) for n in names)
6685 maxnamelen = max(len(n) for n in names)
6684 for i, name in enumerate(names):
6686 for i, name in enumerate(names):
6685 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6687 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,770 +1,783 b''
1 $ hg init
1 $ hg init
2
2
3 no bookmarks
3 no bookmarks
4
4
5 $ hg bookmarks
5 $ hg bookmarks
6 no bookmarks set
6 no bookmarks set
7
7
8 $ hg bookmarks -Tjson
8 $ hg bookmarks -Tjson
9 [
9 [
10 ]
10 ]
11
11
12 bookmark rev -1
12 bookmark rev -1
13
13
14 $ hg bookmark X
14 $ hg bookmark X
15
15
16 list bookmarks
16 list bookmarks
17
17
18 $ hg bookmarks
18 $ hg bookmarks
19 * X -1:000000000000
19 * X -1:000000000000
20
20
21 list bookmarks with color
21 list bookmarks with color
22
22
23 $ hg --config extensions.color= --config color.mode=ansi \
23 $ hg --config extensions.color= --config color.mode=ansi \
24 > bookmarks --color=always
24 > bookmarks --color=always
25 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
25 \x1b[0;32m * \x1b[0m\x1b[0;32mX\x1b[0m\x1b[0;32m -1:000000000000\x1b[0m (esc)
26
26
27 $ echo a > a
27 $ echo a > a
28 $ hg add a
28 $ hg add a
29 $ hg commit -m 0
29 $ hg commit -m 0
30
30
31 bookmark X moved to rev 0
31 bookmark X moved to rev 0
32
32
33 $ hg bookmarks
33 $ hg bookmarks
34 * X 0:f7b1eb17ad24
34 * X 0:f7b1eb17ad24
35
35
36 look up bookmark
36 look up bookmark
37
37
38 $ hg log -r X
38 $ hg log -r X
39 changeset: 0:f7b1eb17ad24
39 changeset: 0:f7b1eb17ad24
40 bookmark: X
40 bookmark: X
41 tag: tip
41 tag: tip
42 user: test
42 user: test
43 date: Thu Jan 01 00:00:00 1970 +0000
43 date: Thu Jan 01 00:00:00 1970 +0000
44 summary: 0
44 summary: 0
45
45
46
46
47 second bookmark for rev 0, command should work even with ui.strict on
47 second bookmark for rev 0, command should work even with ui.strict on
48
48
49 $ hg --config ui.strict=1 bookmark X2
49 $ hg --config ui.strict=1 bookmark X2
50
50
51 bookmark rev -1 again
51 bookmark rev -1 again
52
52
53 $ hg bookmark -r null Y
53 $ hg bookmark -r null Y
54
54
55 list bookmarks
55 list bookmarks
56
56
57 $ hg bookmarks
57 $ hg bookmarks
58 X 0:f7b1eb17ad24
58 X 0:f7b1eb17ad24
59 * X2 0:f7b1eb17ad24
59 * X2 0:f7b1eb17ad24
60 Y -1:000000000000
60 Y -1:000000000000
61
61
62 $ echo b > b
62 $ echo b > b
63 $ hg add b
63 $ hg add b
64 $ hg commit -m 1
64 $ hg commit -m 1
65
65
66 $ hg bookmarks -Tjson
66 $ hg bookmarks -Tjson
67 [
67 [
68 {
68 {
69 "active": false,
69 "active": false,
70 "bookmark": "X",
70 "bookmark": "X",
71 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
71 "node": "f7b1eb17ad24730a1651fccd46c43826d1bbc2ac",
72 "rev": 0
72 "rev": 0
73 },
73 },
74 {
74 {
75 "active": true,
75 "active": true,
76 "bookmark": "X2",
76 "bookmark": "X2",
77 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
77 "node": "925d80f479bb026b0fb3deb27503780b13f74123",
78 "rev": 1
78 "rev": 1
79 },
79 },
80 {
80 {
81 "active": false,
81 "active": false,
82 "bookmark": "Y",
82 "bookmark": "Y",
83 "node": "0000000000000000000000000000000000000000",
83 "node": "0000000000000000000000000000000000000000",
84 "rev": -1
84 "rev": -1
85 }
85 }
86 ]
86 ]
87
87
88 bookmarks revset
88 bookmarks revset
89
89
90 $ hg log -r 'bookmark()'
90 $ hg log -r 'bookmark()'
91 changeset: 0:f7b1eb17ad24
91 changeset: 0:f7b1eb17ad24
92 bookmark: X
92 bookmark: X
93 user: test
93 user: test
94 date: Thu Jan 01 00:00:00 1970 +0000
94 date: Thu Jan 01 00:00:00 1970 +0000
95 summary: 0
95 summary: 0
96
96
97 changeset: 1:925d80f479bb
97 changeset: 1:925d80f479bb
98 bookmark: X2
98 bookmark: X2
99 tag: tip
99 tag: tip
100 user: test
100 user: test
101 date: Thu Jan 01 00:00:00 1970 +0000
101 date: Thu Jan 01 00:00:00 1970 +0000
102 summary: 1
102 summary: 1
103
103
104 $ hg log -r 'bookmark(Y)'
104 $ hg log -r 'bookmark(Y)'
105 $ hg log -r 'bookmark(X2)'
105 $ hg log -r 'bookmark(X2)'
106 changeset: 1:925d80f479bb
106 changeset: 1:925d80f479bb
107 bookmark: X2
107 bookmark: X2
108 tag: tip
108 tag: tip
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:00 1970 +0000
110 date: Thu Jan 01 00:00:00 1970 +0000
111 summary: 1
111 summary: 1
112
112
113 $ hg log -r 'bookmark("re:X")'
113 $ hg log -r 'bookmark("re:X")'
114 changeset: 0:f7b1eb17ad24
114 changeset: 0:f7b1eb17ad24
115 bookmark: X
115 bookmark: X
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
117 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: 0
118 summary: 0
119
119
120 changeset: 1:925d80f479bb
120 changeset: 1:925d80f479bb
121 bookmark: X2
121 bookmark: X2
122 tag: tip
122 tag: tip
123 user: test
123 user: test
124 date: Thu Jan 01 00:00:00 1970 +0000
124 date: Thu Jan 01 00:00:00 1970 +0000
125 summary: 1
125 summary: 1
126
126
127 $ hg log -r 'bookmark("literal:X")'
127 $ hg log -r 'bookmark("literal:X")'
128 changeset: 0:f7b1eb17ad24
128 changeset: 0:f7b1eb17ad24
129 bookmark: X
129 bookmark: X
130 user: test
130 user: test
131 date: Thu Jan 01 00:00:00 1970 +0000
131 date: Thu Jan 01 00:00:00 1970 +0000
132 summary: 0
132 summary: 0
133
133
134
134
135 $ hg log -r 'bookmark(unknown)'
135 $ hg log -r 'bookmark(unknown)'
136 abort: bookmark 'unknown' does not exist!
136 abort: bookmark 'unknown' does not exist!
137 [255]
137 [255]
138 $ hg log -r 'bookmark("literal:unknown")'
138 $ hg log -r 'bookmark("literal:unknown")'
139 abort: bookmark 'unknown' does not exist!
139 abort: bookmark 'unknown' does not exist!
140 [255]
140 [255]
141 $ hg log -r 'bookmark("re:unknown")'
141 $ hg log -r 'bookmark("re:unknown")'
142 abort: no bookmarks exist that match 'unknown'!
142 abort: no bookmarks exist that match 'unknown'!
143 [255]
143 [255]
144 $ hg log -r 'present(bookmark("literal:unknown"))'
144 $ hg log -r 'present(bookmark("literal:unknown"))'
145 $ hg log -r 'present(bookmark("re:unknown"))'
145 $ hg log -r 'present(bookmark("re:unknown"))'
146
146
147 $ hg help revsets | grep 'bookmark('
147 $ hg help revsets | grep 'bookmark('
148 "bookmark([name])"
148 "bookmark([name])"
149
149
150 bookmarks X and X2 moved to rev 1, Y at rev -1
150 bookmarks X and X2 moved to rev 1, Y at rev -1
151
151
152 $ hg bookmarks
152 $ hg bookmarks
153 X 0:f7b1eb17ad24
153 X 0:f7b1eb17ad24
154 * X2 1:925d80f479bb
154 * X2 1:925d80f479bb
155 Y -1:000000000000
155 Y -1:000000000000
156
156
157 bookmark rev 0 again
157 bookmark rev 0 again
158
158
159 $ hg bookmark -r 0 Z
159 $ hg bookmark -r 0 Z
160
160
161 $ hg update X
161 $ hg update X
162 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
162 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
163 (activating bookmark X)
163 (activating bookmark X)
164 $ echo c > c
164 $ echo c > c
165 $ hg add c
165 $ hg add c
166 $ hg commit -m 2
166 $ hg commit -m 2
167 created new head
167 created new head
168
168
169 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
169 bookmarks X moved to rev 2, Y at rev -1, Z at rev 0
170
170
171 $ hg bookmarks
171 $ hg bookmarks
172 * X 2:db815d6d32e6
172 * X 2:db815d6d32e6
173 X2 1:925d80f479bb
173 X2 1:925d80f479bb
174 Y -1:000000000000
174 Y -1:000000000000
175 Z 0:f7b1eb17ad24
175 Z 0:f7b1eb17ad24
176
176
177 rename nonexistent bookmark
177 rename nonexistent bookmark
178
178
179 $ hg bookmark -m A B
179 $ hg bookmark -m A B
180 abort: bookmark 'A' does not exist
180 abort: bookmark 'A' does not exist
181 [255]
181 [255]
182
182
183 rename to existent bookmark
183 rename to existent bookmark
184
184
185 $ hg bookmark -m X Y
185 $ hg bookmark -m X Y
186 abort: bookmark 'Y' already exists (use -f to force)
186 abort: bookmark 'Y' already exists (use -f to force)
187 [255]
187 [255]
188
188
189 force rename to existent bookmark
189 force rename to existent bookmark
190
190
191 $ hg bookmark -f -m X Y
191 $ hg bookmark -f -m X Y
192
192
193 list bookmarks
193 list bookmarks
194
194
195 $ hg bookmark
195 $ hg bookmark
196 X2 1:925d80f479bb
196 X2 1:925d80f479bb
197 * Y 2:db815d6d32e6
197 * Y 2:db815d6d32e6
198 Z 0:f7b1eb17ad24
198 Z 0:f7b1eb17ad24
199
199
200 bookmarks from a revset
200 bookmarks from a revset
201 $ hg bookmark -r '.^1' REVSET
201 $ hg bookmark -r '.^1' REVSET
202 $ hg bookmark -r ':tip' TIP
202 $ hg bookmark -r ':tip' TIP
203 $ hg up -q TIP
203 $ hg up -q TIP
204 $ hg bookmarks
204 $ hg bookmarks
205 REVSET 0:f7b1eb17ad24
205 REVSET 0:f7b1eb17ad24
206 * TIP 2:db815d6d32e6
206 * TIP 2:db815d6d32e6
207 X2 1:925d80f479bb
207 X2 1:925d80f479bb
208 Y 2:db815d6d32e6
208 Y 2:db815d6d32e6
209 Z 0:f7b1eb17ad24
209 Z 0:f7b1eb17ad24
210
210
211 $ hg bookmark -d REVSET
211 $ hg bookmark -d REVSET
212 $ hg bookmark -d TIP
212 $ hg bookmark -d TIP
213
213
214 rename without new name or multiple names
214 rename without new name or multiple names
215
215
216 $ hg bookmark -m Y
216 $ hg bookmark -m Y
217 abort: new bookmark name required
217 abort: new bookmark name required
218 [255]
218 [255]
219 $ hg bookmark -m Y Y2 Y3
219 $ hg bookmark -m Y Y2 Y3
220 abort: only one new bookmark name allowed
220 abort: only one new bookmark name allowed
221 [255]
221 [255]
222
222
223 delete without name
223 delete without name
224
224
225 $ hg bookmark -d
225 $ hg bookmark -d
226 abort: bookmark name required
226 abort: bookmark name required
227 [255]
227 [255]
228
228
229 delete nonexistent bookmark
229 delete nonexistent bookmark
230
230
231 $ hg bookmark -d A
231 $ hg bookmark -d A
232 abort: bookmark 'A' does not exist
232 abort: bookmark 'A' does not exist
233 [255]
233 [255]
234
234
235 bookmark name with spaces should be stripped
235 bookmark name with spaces should be stripped
236
236
237 $ hg bookmark ' x y '
237 $ hg bookmark ' x y '
238
238
239 list bookmarks
239 list bookmarks
240
240
241 $ hg bookmarks
241 $ hg bookmarks
242 X2 1:925d80f479bb
242 X2 1:925d80f479bb
243 Y 2:db815d6d32e6
243 Y 2:db815d6d32e6
244 Z 0:f7b1eb17ad24
244 Z 0:f7b1eb17ad24
245 * x y 2:db815d6d32e6
245 * x y 2:db815d6d32e6
246
246
247 look up stripped bookmark name
247 look up stripped bookmark name
248
248
249 $ hg log -r '"x y"'
249 $ hg log -r '"x y"'
250 changeset: 2:db815d6d32e6
250 changeset: 2:db815d6d32e6
251 bookmark: Y
251 bookmark: Y
252 bookmark: x y
252 bookmark: x y
253 tag: tip
253 tag: tip
254 parent: 0:f7b1eb17ad24
254 parent: 0:f7b1eb17ad24
255 user: test
255 user: test
256 date: Thu Jan 01 00:00:00 1970 +0000
256 date: Thu Jan 01 00:00:00 1970 +0000
257 summary: 2
257 summary: 2
258
258
259
259
260 reject bookmark name with newline
260 reject bookmark name with newline
261
261
262 $ hg bookmark '
262 $ hg bookmark '
263 > '
263 > '
264 abort: bookmark names cannot consist entirely of whitespace
264 abort: bookmark names cannot consist entirely of whitespace
265 [255]
265 [255]
266
266
267 $ hg bookmark -m Z '
267 $ hg bookmark -m Z '
268 > '
268 > '
269 abort: bookmark names cannot consist entirely of whitespace
269 abort: bookmark names cannot consist entirely of whitespace
270 [255]
270 [255]
271
271
272 bookmark with reserved name
272 bookmark with reserved name
273
273
274 $ hg bookmark tip
274 $ hg bookmark tip
275 abort: the name 'tip' is reserved
275 abort: the name 'tip' is reserved
276 [255]
276 [255]
277
277
278 $ hg bookmark .
278 $ hg bookmark .
279 abort: the name '.' is reserved
279 abort: the name '.' is reserved
280 [255]
280 [255]
281
281
282 $ hg bookmark null
282 $ hg bookmark null
283 abort: the name 'null' is reserved
283 abort: the name 'null' is reserved
284 [255]
284 [255]
285
285
286
286
287 bookmark with existing name
287 bookmark with existing name
288
288
289 $ hg bookmark X2
289 $ hg bookmark X2
290 abort: bookmark 'X2' already exists (use -f to force)
290 abort: bookmark 'X2' already exists (use -f to force)
291 [255]
291 [255]
292
292
293 $ hg bookmark -m Y Z
293 $ hg bookmark -m Y Z
294 abort: bookmark 'Z' already exists (use -f to force)
294 abort: bookmark 'Z' already exists (use -f to force)
295 [255]
295 [255]
296
296
297 bookmark with name of branch
297 bookmark with name of branch
298
298
299 $ hg bookmark default
299 $ hg bookmark default
300 abort: a bookmark cannot have the name of an existing branch
300 abort: a bookmark cannot have the name of an existing branch
301 [255]
301 [255]
302
302
303 $ hg bookmark -m Y default
303 $ hg bookmark -m Y default
304 abort: a bookmark cannot have the name of an existing branch
304 abort: a bookmark cannot have the name of an existing branch
305 [255]
305 [255]
306
306
307 bookmark with integer name
307 bookmark with integer name
308
308
309 $ hg bookmark 10
309 $ hg bookmark 10
310 abort: cannot use an integer as a name
310 abort: cannot use an integer as a name
311 [255]
311 [255]
312
312
313 incompatible options
313 incompatible options
314
314
315 $ hg bookmark -m Y -d Z
315 $ hg bookmark -m Y -d Z
316 abort: --delete and --rename are incompatible
316 abort: --delete and --rename are incompatible
317 [255]
317 [255]
318
318
319 $ hg bookmark -r 1 -d Z
319 $ hg bookmark -r 1 -d Z
320 abort: --rev is incompatible with --delete
320 abort: --rev is incompatible with --delete
321 [255]
321 [255]
322
322
323 $ hg bookmark -r 1 -m Z Y
323 $ hg bookmark -r 1 -m Z Y
324 abort: --rev is incompatible with --rename
324 abort: --rev is incompatible with --rename
325 [255]
325 [255]
326
326
327 force bookmark with existing name
327 force bookmark with existing name
328
328
329 $ hg bookmark -f X2
329 $ hg bookmark -f X2
330
330
331 force bookmark back to where it was, should deactivate it
331 force bookmark back to where it was, should deactivate it
332
332
333 $ hg bookmark -fr1 X2
333 $ hg bookmark -fr1 X2
334 $ hg bookmarks
334 $ hg bookmarks
335 X2 1:925d80f479bb
335 X2 1:925d80f479bb
336 Y 2:db815d6d32e6
336 Y 2:db815d6d32e6
337 Z 0:f7b1eb17ad24
337 Z 0:f7b1eb17ad24
338 x y 2:db815d6d32e6
338 x y 2:db815d6d32e6
339
339
340 forward bookmark to descendant without --force
340 forward bookmark to descendant without --force
341
341
342 $ hg bookmark Z
342 $ hg bookmark Z
343 moving bookmark 'Z' forward from f7b1eb17ad24
343 moving bookmark 'Z' forward from f7b1eb17ad24
344
344
345 list bookmarks
345 list bookmarks
346
346
347 $ hg bookmark
347 $ hg bookmark
348 X2 1:925d80f479bb
348 X2 1:925d80f479bb
349 Y 2:db815d6d32e6
349 Y 2:db815d6d32e6
350 * Z 2:db815d6d32e6
350 * Z 2:db815d6d32e6
351 x y 2:db815d6d32e6
351 x y 2:db815d6d32e6
352
352
353 revision but no bookmark name
353 revision but no bookmark name
354
354
355 $ hg bookmark -r .
355 $ hg bookmark -r .
356 abort: bookmark name required
356 abort: bookmark name required
357 [255]
357 [255]
358
358
359 bookmark name with whitespace only
359 bookmark name with whitespace only
360
360
361 $ hg bookmark ' '
361 $ hg bookmark ' '
362 abort: bookmark names cannot consist entirely of whitespace
362 abort: bookmark names cannot consist entirely of whitespace
363 [255]
363 [255]
364
364
365 $ hg bookmark -m Y ' '
365 $ hg bookmark -m Y ' '
366 abort: bookmark names cannot consist entirely of whitespace
366 abort: bookmark names cannot consist entirely of whitespace
367 [255]
367 [255]
368
368
369 invalid bookmark
369 invalid bookmark
370
370
371 $ hg bookmark 'foo:bar'
371 $ hg bookmark 'foo:bar'
372 abort: ':' cannot be used in a name
372 abort: ':' cannot be used in a name
373 [255]
373 [255]
374
374
375 $ hg bookmark 'foo
375 $ hg bookmark 'foo
376 > bar'
376 > bar'
377 abort: '\n' cannot be used in a name
377 abort: '\n' cannot be used in a name
378 [255]
378 [255]
379
379
380 the bookmark extension should be ignored now that it is part of core
380 the bookmark extension should be ignored now that it is part of core
381
381
382 $ echo "[extensions]" >> $HGRCPATH
382 $ echo "[extensions]" >> $HGRCPATH
383 $ echo "bookmarks=" >> $HGRCPATH
383 $ echo "bookmarks=" >> $HGRCPATH
384 $ hg bookmarks
384 $ hg bookmarks
385 X2 1:925d80f479bb
385 X2 1:925d80f479bb
386 Y 2:db815d6d32e6
386 Y 2:db815d6d32e6
387 * Z 2:db815d6d32e6
387 * Z 2:db815d6d32e6
388 x y 2:db815d6d32e6
388 x y 2:db815d6d32e6
389
389
390 test summary
390 test summary
391
391
392 $ hg summary
392 $ hg summary
393 parent: 2:db815d6d32e6 tip
393 parent: 2:db815d6d32e6 tip
394 2
394 2
395 branch: default
395 branch: default
396 bookmarks: *Z Y x y
396 bookmarks: *Z Y x y
397 commit: (clean)
397 commit: (clean)
398 update: 1 new changesets, 2 branch heads (merge)
398 update: 1 new changesets, 2 branch heads (merge)
399 phases: 3 draft
399 phases: 3 draft
400
400
401 test id
401 test id
402
402
403 $ hg id
403 $ hg id
404 db815d6d32e6 tip Y/Z/x y
404 db815d6d32e6 tip Y/Z/x y
405
405
406 test rollback
406 test rollback
407
407
408 $ echo foo > f1
408 $ echo foo > f1
409 $ hg bookmark tmp-rollback
409 $ hg bookmark tmp-rollback
410 $ hg ci -Amr
410 $ hg ci -Amr
411 adding f1
411 adding f1
412 $ hg bookmarks
412 $ hg bookmarks
413 X2 1:925d80f479bb
413 X2 1:925d80f479bb
414 Y 2:db815d6d32e6
414 Y 2:db815d6d32e6
415 Z 2:db815d6d32e6
415 Z 2:db815d6d32e6
416 * tmp-rollback 3:2bf5cfec5864
416 * tmp-rollback 3:2bf5cfec5864
417 x y 2:db815d6d32e6
417 x y 2:db815d6d32e6
418 $ hg rollback
418 $ hg rollback
419 repository tip rolled back to revision 2 (undo commit)
419 repository tip rolled back to revision 2 (undo commit)
420 working directory now based on revision 2
420 working directory now based on revision 2
421 $ hg bookmarks
421 $ hg bookmarks
422 X2 1:925d80f479bb
422 X2 1:925d80f479bb
423 Y 2:db815d6d32e6
423 Y 2:db815d6d32e6
424 Z 2:db815d6d32e6
424 Z 2:db815d6d32e6
425 * tmp-rollback 2:db815d6d32e6
425 * tmp-rollback 2:db815d6d32e6
426 x y 2:db815d6d32e6
426 x y 2:db815d6d32e6
427 $ hg bookmark -f Z -r 1
427 $ hg bookmark -f Z -r 1
428 $ hg rollback
428 $ hg rollback
429 repository tip rolled back to revision 2 (undo bookmark)
429 repository tip rolled back to revision 2 (undo bookmark)
430 $ hg bookmarks
430 $ hg bookmarks
431 X2 1:925d80f479bb
431 X2 1:925d80f479bb
432 Y 2:db815d6d32e6
432 Y 2:db815d6d32e6
433 Z 2:db815d6d32e6
433 Z 2:db815d6d32e6
434 * tmp-rollback 2:db815d6d32e6
434 * tmp-rollback 2:db815d6d32e6
435 x y 2:db815d6d32e6
435 x y 2:db815d6d32e6
436 $ hg bookmark -d tmp-rollback
436 $ hg bookmark -d tmp-rollback
437
437
438 activate bookmark on working dir parent without --force
438 activate bookmark on working dir parent without --force
439
439
440 $ hg bookmark --inactive Z
440 $ hg bookmark --inactive Z
441 $ hg bookmark Z
441 $ hg bookmark Z
442
442
443 test clone
443 test clone
444
444
445 $ hg bookmark -r 2 -i @
445 $ hg bookmark -r 2 -i @
446 $ hg bookmark -r 2 -i a@
446 $ hg bookmark -r 2 -i a@
447 $ hg bookmarks
447 $ hg bookmarks
448 @ 2:db815d6d32e6
448 @ 2:db815d6d32e6
449 X2 1:925d80f479bb
449 X2 1:925d80f479bb
450 Y 2:db815d6d32e6
450 Y 2:db815d6d32e6
451 * Z 2:db815d6d32e6
451 * Z 2:db815d6d32e6
452 a@ 2:db815d6d32e6
452 a@ 2:db815d6d32e6
453 x y 2:db815d6d32e6
453 x y 2:db815d6d32e6
454 $ hg clone . cloned-bookmarks
454 $ hg clone . cloned-bookmarks
455 updating to bookmark @
455 updating to bookmark @
456 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
456 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 $ hg -R cloned-bookmarks bookmarks
457 $ hg -R cloned-bookmarks bookmarks
458 * @ 2:db815d6d32e6
458 * @ 2:db815d6d32e6
459 X2 1:925d80f479bb
459 X2 1:925d80f479bb
460 Y 2:db815d6d32e6
460 Y 2:db815d6d32e6
461 Z 2:db815d6d32e6
461 Z 2:db815d6d32e6
462 a@ 2:db815d6d32e6
462 a@ 2:db815d6d32e6
463 x y 2:db815d6d32e6
463 x y 2:db815d6d32e6
464
464
465 test clone with pull protocol
465 test clone with pull protocol
466
466
467 $ hg clone --pull . cloned-bookmarks-pull
467 $ hg clone --pull . cloned-bookmarks-pull
468 requesting all changes
468 requesting all changes
469 adding changesets
469 adding changesets
470 adding manifests
470 adding manifests
471 adding file changes
471 adding file changes
472 added 3 changesets with 3 changes to 3 files (+1 heads)
472 added 3 changesets with 3 changes to 3 files (+1 heads)
473 updating to bookmark @
473 updating to bookmark @
474 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
475 $ hg -R cloned-bookmarks-pull bookmarks
475 $ hg -R cloned-bookmarks-pull bookmarks
476 * @ 2:db815d6d32e6
476 * @ 2:db815d6d32e6
477 X2 1:925d80f479bb
477 X2 1:925d80f479bb
478 Y 2:db815d6d32e6
478 Y 2:db815d6d32e6
479 Z 2:db815d6d32e6
479 Z 2:db815d6d32e6
480 a@ 2:db815d6d32e6
480 a@ 2:db815d6d32e6
481 x y 2:db815d6d32e6
481 x y 2:db815d6d32e6
482
482
483 delete multiple bookmarks at once
483 delete multiple bookmarks at once
484
484
485 $ hg bookmark -d @ a@
485 $ hg bookmark -d @ a@
486
486
487 test clone with a bookmark named "default" (issue3677)
487 test clone with a bookmark named "default" (issue3677)
488
488
489 $ hg bookmark -r 1 -f -i default
489 $ hg bookmark -r 1 -f -i default
490 $ hg clone . cloned-bookmark-default
490 $ hg clone . cloned-bookmark-default
491 updating to branch default
491 updating to branch default
492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
492 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
493 $ hg -R cloned-bookmark-default bookmarks
493 $ hg -R cloned-bookmark-default bookmarks
494 X2 1:925d80f479bb
494 X2 1:925d80f479bb
495 Y 2:db815d6d32e6
495 Y 2:db815d6d32e6
496 Z 2:db815d6d32e6
496 Z 2:db815d6d32e6
497 default 1:925d80f479bb
497 default 1:925d80f479bb
498 x y 2:db815d6d32e6
498 x y 2:db815d6d32e6
499 $ hg -R cloned-bookmark-default parents -q
499 $ hg -R cloned-bookmark-default parents -q
500 2:db815d6d32e6
500 2:db815d6d32e6
501 $ hg bookmark -d default
501 $ hg bookmark -d default
502
502
503 test clone with a specific revision
503 test clone with a specific revision
504
504
505 $ hg clone -r 925d80 . cloned-bookmarks-rev
505 $ hg clone -r 925d80 . cloned-bookmarks-rev
506 adding changesets
506 adding changesets
507 adding manifests
507 adding manifests
508 adding file changes
508 adding file changes
509 added 2 changesets with 2 changes to 2 files
509 added 2 changesets with 2 changes to 2 files
510 updating to branch default
510 updating to branch default
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
511 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
512 $ hg -R cloned-bookmarks-rev bookmarks
512 $ hg -R cloned-bookmarks-rev bookmarks
513 X2 1:925d80f479bb
513 X2 1:925d80f479bb
514
514
515 test clone with update to a bookmark
515 test clone with update to a bookmark
516
516
517 $ hg clone -u Z . ../cloned-bookmarks-update
517 $ hg clone -u Z . ../cloned-bookmarks-update
518 updating to branch default
518 updating to branch default
519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
519 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
520 $ hg -R ../cloned-bookmarks-update bookmarks
520 $ hg -R ../cloned-bookmarks-update bookmarks
521 X2 1:925d80f479bb
521 X2 1:925d80f479bb
522 Y 2:db815d6d32e6
522 Y 2:db815d6d32e6
523 * Z 2:db815d6d32e6
523 * Z 2:db815d6d32e6
524 x y 2:db815d6d32e6
524 x y 2:db815d6d32e6
525
525
526 create bundle with two heads
526 create bundle with two heads
527
527
528 $ hg clone . tobundle
528 $ hg clone . tobundle
529 updating to branch default
529 updating to branch default
530 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 $ echo x > tobundle/x
531 $ echo x > tobundle/x
532 $ hg -R tobundle add tobundle/x
532 $ hg -R tobundle add tobundle/x
533 $ hg -R tobundle commit -m'x'
533 $ hg -R tobundle commit -m'x'
534 $ hg -R tobundle update -r -2
534 $ hg -R tobundle update -r -2
535 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
535 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
536 $ echo y > tobundle/y
536 $ echo y > tobundle/y
537 $ hg -R tobundle branch test
537 $ hg -R tobundle branch test
538 marked working directory as branch test
538 marked working directory as branch test
539 (branches are permanent and global, did you want a bookmark?)
539 (branches are permanent and global, did you want a bookmark?)
540 $ hg -R tobundle add tobundle/y
540 $ hg -R tobundle add tobundle/y
541 $ hg -R tobundle commit -m'y'
541 $ hg -R tobundle commit -m'y'
542 $ hg -R tobundle bundle tobundle.hg
542 $ hg -R tobundle bundle tobundle.hg
543 searching for changes
543 searching for changes
544 2 changesets found
544 2 changesets found
545 $ hg unbundle tobundle.hg
545 $ hg unbundle tobundle.hg
546 adding changesets
546 adding changesets
547 adding manifests
547 adding manifests
548 adding file changes
548 adding file changes
549 added 2 changesets with 2 changes to 2 files (+1 heads)
549 added 2 changesets with 2 changes to 2 files (+1 heads)
550 (run 'hg heads' to see heads, 'hg merge' to merge)
550 (run 'hg heads' to see heads, 'hg merge' to merge)
551
551
552 update to active bookmark if it's not the parent
552 update to active bookmark if it's not the parent
553
553
554 $ hg summary
554 $ hg summary
555 parent: 2:db815d6d32e6
555 parent: 2:db815d6d32e6
556 2
556 2
557 branch: default
557 branch: default
558 bookmarks: *Z Y x y
558 bookmarks: *Z Y x y
559 commit: 1 added, 1 unknown (new branch head)
559 commit: 1 added, 1 unknown (new branch head)
560 update: 2 new changesets (update)
560 update: 2 new changesets (update)
561 phases: 5 draft
561 phases: 5 draft
562 $ hg update
562 $ hg update
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 updating bookmark Z
564 updating bookmark Z
565 $ hg bookmarks
565 $ hg bookmarks
566 X2 1:925d80f479bb
566 X2 1:925d80f479bb
567 Y 2:db815d6d32e6
567 Y 2:db815d6d32e6
568 * Z 3:125c9a1d6df6
568 * Z 3:125c9a1d6df6
569 x y 2:db815d6d32e6
569 x y 2:db815d6d32e6
570
570
571 pull --update works the same as pull && update
571 pull --update works the same as pull && update
572
572
573 $ hg bookmark -r3 Y
573 $ hg bookmark -r3 Y
574 moving bookmark 'Y' forward from db815d6d32e6
574 moving bookmark 'Y' forward from db815d6d32e6
575 $ cp -r ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
575 $ cp -r ../cloned-bookmarks-update ../cloned-bookmarks-manual-update
576
576
577 (manual version)
577 (manual version)
578
578
579 $ hg -R ../cloned-bookmarks-manual-update update Y
579 $ hg -R ../cloned-bookmarks-manual-update update Y
580 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
580 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
581 (activating bookmark Y)
581 (activating bookmark Y)
582 $ hg -R ../cloned-bookmarks-manual-update pull .
582 $ hg -R ../cloned-bookmarks-manual-update pull .
583 pulling from .
583 pulling from .
584 searching for changes
584 searching for changes
585 adding changesets
585 adding changesets
586 adding manifests
586 adding manifests
587 adding file changes
587 adding file changes
588 added 2 changesets with 2 changes to 2 files (+1 heads)
588 added 2 changesets with 2 changes to 2 files (+1 heads)
589 updating bookmark Y
589 updating bookmark Y
590 updating bookmark Z
590 updating bookmark Z
591 (run 'hg heads' to see heads, 'hg merge' to merge)
591 (run 'hg heads' to see heads, 'hg merge' to merge)
592
592
593 (# tests strange but with --date crashing when bookmark have to move)
593 (# tests strange but with --date crashing when bookmark have to move)
594
594
595 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
595 $ hg -R ../cloned-bookmarks-manual-update update -d 1986
596 abort: revision matching date not found
596 abort: revision matching date not found
597 [255]
597 [255]
598 $ hg -R ../cloned-bookmarks-manual-update update
598 $ hg -R ../cloned-bookmarks-manual-update update
599 updating to active bookmark Y
599 updating to active bookmark Y
600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
600 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
601 (activating bookmark Y)
601 (activating bookmark Y)
602
602
603 (all in one version)
603 (all in one version)
604
604
605 $ hg -R ../cloned-bookmarks-update update Y
605 $ hg -R ../cloned-bookmarks-update update Y
606 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
606 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
607 (activating bookmark Y)
607 (activating bookmark Y)
608 $ hg -R ../cloned-bookmarks-update pull --update .
608 $ hg -R ../cloned-bookmarks-update pull --update .
609 pulling from .
609 pulling from .
610 searching for changes
610 searching for changes
611 adding changesets
611 adding changesets
612 adding manifests
612 adding manifests
613 adding file changes
613 adding file changes
614 added 2 changesets with 2 changes to 2 files (+1 heads)
614 added 2 changesets with 2 changes to 2 files (+1 heads)
615 updating bookmark Y
615 updating bookmark Y
616 updating bookmark Z
616 updating bookmark Z
617 updating to active bookmark Y
617 updating to active bookmark Y
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
618 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
619
619
620 test wrongly formated bookmark
620 test wrongly formated bookmark
621
621
622 $ echo '' >> .hg/bookmarks
622 $ echo '' >> .hg/bookmarks
623 $ hg bookmarks
623 $ hg bookmarks
624 X2 1:925d80f479bb
624 X2 1:925d80f479bb
625 Y 3:125c9a1d6df6
625 Y 3:125c9a1d6df6
626 * Z 3:125c9a1d6df6
626 * Z 3:125c9a1d6df6
627 x y 2:db815d6d32e6
627 x y 2:db815d6d32e6
628 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
628 $ echo "Ican'thasformatedlines" >> .hg/bookmarks
629 $ hg bookmarks
629 $ hg bookmarks
630 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
630 malformed line in .hg/bookmarks: "Ican'thasformatedlines"
631 X2 1:925d80f479bb
631 X2 1:925d80f479bb
632 Y 3:125c9a1d6df6
632 Y 3:125c9a1d6df6
633 * Z 3:125c9a1d6df6
633 * Z 3:125c9a1d6df6
634 x y 2:db815d6d32e6
634 x y 2:db815d6d32e6
635
635
636 test missing revisions
636 test missing revisions
637
637
638 $ echo "925d80f479bc z" > .hg/bookmarks
638 $ echo "925d80f479bc z" > .hg/bookmarks
639 $ hg book
639 $ hg book
640 no bookmarks set
640 no bookmarks set
641
641
642 test stripping a non-checked-out but bookmarked revision
642 test stripping a non-checked-out but bookmarked revision
643
643
644 $ hg log --graph
644 $ hg log --graph
645 o changeset: 4:9ba5f110a0b3
645 o changeset: 4:9ba5f110a0b3
646 | branch: test
646 | branch: test
647 | tag: tip
647 | tag: tip
648 | parent: 2:db815d6d32e6
648 | parent: 2:db815d6d32e6
649 | user: test
649 | user: test
650 | date: Thu Jan 01 00:00:00 1970 +0000
650 | date: Thu Jan 01 00:00:00 1970 +0000
651 | summary: y
651 | summary: y
652 |
652 |
653 | @ changeset: 3:125c9a1d6df6
653 | @ changeset: 3:125c9a1d6df6
654 |/ user: test
654 |/ user: test
655 | date: Thu Jan 01 00:00:00 1970 +0000
655 | date: Thu Jan 01 00:00:00 1970 +0000
656 | summary: x
656 | summary: x
657 |
657 |
658 o changeset: 2:db815d6d32e6
658 o changeset: 2:db815d6d32e6
659 | parent: 0:f7b1eb17ad24
659 | parent: 0:f7b1eb17ad24
660 | user: test
660 | user: test
661 | date: Thu Jan 01 00:00:00 1970 +0000
661 | date: Thu Jan 01 00:00:00 1970 +0000
662 | summary: 2
662 | summary: 2
663 |
663 |
664 | o changeset: 1:925d80f479bb
664 | o changeset: 1:925d80f479bb
665 |/ user: test
665 |/ user: test
666 | date: Thu Jan 01 00:00:00 1970 +0000
666 | date: Thu Jan 01 00:00:00 1970 +0000
667 | summary: 1
667 | summary: 1
668 |
668 |
669 o changeset: 0:f7b1eb17ad24
669 o changeset: 0:f7b1eb17ad24
670 user: test
670 user: test
671 date: Thu Jan 01 00:00:00 1970 +0000
671 date: Thu Jan 01 00:00:00 1970 +0000
672 summary: 0
672 summary: 0
673
673
674 $ hg book should-end-on-two
674 $ hg book should-end-on-two
675 $ hg co --clean 4
675 $ hg co --clean 4
676 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
676 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 (leaving bookmark should-end-on-two)
677 (leaving bookmark should-end-on-two)
678 $ hg book four
678 $ hg book four
679 $ hg --config extensions.mq= strip 3
679 $ hg --config extensions.mq= strip 3
680 saved backup bundle to * (glob)
680 saved backup bundle to * (glob)
681 should-end-on-two should end up pointing to revision 2, as that's the
681 should-end-on-two should end up pointing to revision 2, as that's the
682 tipmost surviving ancestor of the stripped revision.
682 tipmost surviving ancestor of the stripped revision.
683 $ hg log --graph
683 $ hg log --graph
684 @ changeset: 3:9ba5f110a0b3
684 @ changeset: 3:9ba5f110a0b3
685 | branch: test
685 | branch: test
686 | bookmark: four
686 | bookmark: four
687 | tag: tip
687 | tag: tip
688 | user: test
688 | user: test
689 | date: Thu Jan 01 00:00:00 1970 +0000
689 | date: Thu Jan 01 00:00:00 1970 +0000
690 | summary: y
690 | summary: y
691 |
691 |
692 o changeset: 2:db815d6d32e6
692 o changeset: 2:db815d6d32e6
693 | bookmark: should-end-on-two
693 | bookmark: should-end-on-two
694 | parent: 0:f7b1eb17ad24
694 | parent: 0:f7b1eb17ad24
695 | user: test
695 | user: test
696 | date: Thu Jan 01 00:00:00 1970 +0000
696 | date: Thu Jan 01 00:00:00 1970 +0000
697 | summary: 2
697 | summary: 2
698 |
698 |
699 | o changeset: 1:925d80f479bb
699 | o changeset: 1:925d80f479bb
700 |/ user: test
700 |/ user: test
701 | date: Thu Jan 01 00:00:00 1970 +0000
701 | date: Thu Jan 01 00:00:00 1970 +0000
702 | summary: 1
702 | summary: 1
703 |
703 |
704 o changeset: 0:f7b1eb17ad24
704 o changeset: 0:f7b1eb17ad24
705 user: test
705 user: test
706 date: Thu Jan 01 00:00:00 1970 +0000
706 date: Thu Jan 01 00:00:00 1970 +0000
707 summary: 0
707 summary: 0
708
708
709 test non-linear update not clearing active bookmark
709 test non-linear update not clearing active bookmark
710
710
711 $ hg up 1
711 $ hg up 1
712 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
712 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
713 (leaving bookmark four)
713 (leaving bookmark four)
714 $ hg book drop
714 $ hg book drop
715 $ hg up -C
715 $ hg up -C
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
717 (leaving bookmark drop)
717 (leaving bookmark drop)
718 $ hg sum
718 $ hg sum
719 parent: 2:db815d6d32e6
719 parent: 2:db815d6d32e6
720 2
720 2
721 branch: default
721 branch: default
722 bookmarks: should-end-on-two
722 bookmarks: should-end-on-two
723 commit: 2 unknown (clean)
723 commit: 2 unknown (clean)
724 update: 1 new changesets, 2 branch heads (merge)
724 update: 1 new changesets, 2 branch heads (merge)
725 phases: 4 draft
725 phases: 4 draft
726 $ hg book
726 $ hg book
727 drop 1:925d80f479bb
727 drop 1:925d80f479bb
728 four 3:9ba5f110a0b3
728 four 3:9ba5f110a0b3
729 should-end-on-two 2:db815d6d32e6
729 should-end-on-two 2:db815d6d32e6
730 $ hg book -d drop
730 $ hg book -d drop
731 $ hg up four
731 $ hg up four
732 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
732 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 (activating bookmark four)
733 (activating bookmark four)
734
734
735 no-op update doesn't deactive bookmarks
736
737 $ hg up
738 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
739 $ hg sum
740 parent: 3:9ba5f110a0b3 tip
741 y
742 branch: test
743 bookmarks: *four
744 commit: 2 unknown (clean)
745 update: (current)
746 phases: 4 draft
747
735 test clearing divergent bookmarks of linear ancestors
748 test clearing divergent bookmarks of linear ancestors
736
749
737 $ hg bookmark Z -r 0
750 $ hg bookmark Z -r 0
738 $ hg bookmark Z@1 -r 1
751 $ hg bookmark Z@1 -r 1
739 $ hg bookmark Z@2 -r 2
752 $ hg bookmark Z@2 -r 2
740 $ hg bookmark Z@3 -r 3
753 $ hg bookmark Z@3 -r 3
741 $ hg book
754 $ hg book
742 Z 0:f7b1eb17ad24
755 Z 0:f7b1eb17ad24
743 Z@1 1:925d80f479bb
756 Z@1 1:925d80f479bb
744 Z@2 2:db815d6d32e6
757 Z@2 2:db815d6d32e6
745 Z@3 3:9ba5f110a0b3
758 Z@3 3:9ba5f110a0b3
746 * four 3:9ba5f110a0b3
759 * four 3:9ba5f110a0b3
747 should-end-on-two 2:db815d6d32e6
760 should-end-on-two 2:db815d6d32e6
748 $ hg bookmark Z
761 $ hg bookmark Z
749 moving bookmark 'Z' forward from f7b1eb17ad24
762 moving bookmark 'Z' forward from f7b1eb17ad24
750 $ hg book
763 $ hg book
751 * Z 3:9ba5f110a0b3
764 * Z 3:9ba5f110a0b3
752 Z@1 1:925d80f479bb
765 Z@1 1:925d80f479bb
753 four 3:9ba5f110a0b3
766 four 3:9ba5f110a0b3
754 should-end-on-two 2:db815d6d32e6
767 should-end-on-two 2:db815d6d32e6
755
768
756 test clearing only a single divergent bookmark across branches
769 test clearing only a single divergent bookmark across branches
757
770
758 $ hg book foo -r 1
771 $ hg book foo -r 1
759 $ hg book foo@1 -r 0
772 $ hg book foo@1 -r 0
760 $ hg book foo@2 -r 2
773 $ hg book foo@2 -r 2
761 $ hg book foo@3 -r 3
774 $ hg book foo@3 -r 3
762 $ hg book foo -r foo@3
775 $ hg book foo -r foo@3
763 $ hg book
776 $ hg book
764 * Z 3:9ba5f110a0b3
777 * Z 3:9ba5f110a0b3
765 Z@1 1:925d80f479bb
778 Z@1 1:925d80f479bb
766 foo 3:9ba5f110a0b3
779 foo 3:9ba5f110a0b3
767 foo@1 0:f7b1eb17ad24
780 foo@1 0:f7b1eb17ad24
768 foo@2 2:db815d6d32e6
781 foo@2 2:db815d6d32e6
769 four 3:9ba5f110a0b3
782 four 3:9ba5f110a0b3
770 should-end-on-two 2:db815d6d32e6
783 should-end-on-two 2:db815d6d32e6
General Comments 0
You need to be logged in to leave comments. Login now